Extract audio_stream_from_index.
[dcpomatic.git] / src / lib / ffmpeg_decoder.cc
1 /*
2     Copyright (C) 2012-2018 Carl Hetherington <cth@carlh.net>
3
4     This file is part of DCP-o-matic.
5
6     DCP-o-matic is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     DCP-o-matic is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
18
19 */
20
21 /** @file  src/ffmpeg_decoder.cc
22  *  @brief A decoder using FFmpeg to decode content.
23  */
24
25 #include "filter.h"
26 #include "exceptions.h"
27 #include "image.h"
28 #include "util.h"
29 #include "log.h"
30 #include "dcpomatic_log.h"
31 #include "ffmpeg_decoder.h"
32 #include "text_decoder.h"
33 #include "ffmpeg_audio_stream.h"
34 #include "ffmpeg_subtitle_stream.h"
35 #include "video_filter_graph.h"
36 #include "audio_buffers.h"
37 #include "ffmpeg_content.h"
38 #include "raw_image_proxy.h"
39 #include "video_decoder.h"
40 #include "film.h"
41 #include "audio_decoder.h"
42 #include "compose.hpp"
43 #include "text_content.h"
44 #include "audio_content.h"
45 #include "frame_interval_checker.h"
46 #include <dcp/subtitle_string.h>
47 #include <sub/ssa_reader.h>
48 #include <sub/subtitle.h>
49 #include <sub/collect.h>
50 extern "C" {
51 #include <libavcodec/avcodec.h>
52 #include <libavformat/avformat.h>
53 }
54 #include <boost/algorithm/string.hpp>
55 #include <vector>
56 #include <iomanip>
57 #include <iostream>
58 #include <stdint.h>
59
60 #include "i18n.h"
61
62 using std::cout;
63 using std::string;
64 using std::vector;
65 using std::list;
66 using std::min;
67 using std::pair;
68 using std::max;
69 using std::map;
70 using std::shared_ptr;
71 using std::make_shared;
72 using boost::is_any_of;
73 using boost::split;
74 using boost::optional;
75 using std::dynamic_pointer_cast;
76 using dcp::Size;
77 using namespace dcpomatic;
78
79
80 FFmpegDecoder::FFmpegDecoder (shared_ptr<const Film> film, shared_ptr<const FFmpegContent> c, bool fast)
81         : FFmpeg (c)
82         , Decoder (film)
83         , _have_current_subtitle (false)
84 {
85         if (c->video && c->video->use()) {
86                 video = make_shared<VideoDecoder>(this, c);
87                 _pts_offset = pts_offset (c->ffmpeg_audio_streams(), c->first_video(), c->active_video_frame_rate(film));
88                 /* It doesn't matter what size or pixel format this is, it just needs to be black */
89                 _black_image.reset (new Image (AV_PIX_FMT_RGB24, dcp::Size (128, 128), true));
90                 _black_image->make_black ();
91         } else {
92                 _pts_offset = {};
93         }
94
95         if (c->audio) {
96                 audio = make_shared<AudioDecoder>(this, c->audio, fast);
97         }
98
99         if (c->only_text()) {
100                 /* XXX: this time here should be the time of the first subtitle, not 0 */
101                 text.push_back (make_shared<TextDecoder>(this, c->only_text(), ContentTime()));
102         }
103
104         _next_time.resize (_format_context->nb_streams);
105 }
106
107
108 void
109 FFmpegDecoder::flush ()
110 {
111         /* Get any remaining frames */
112
113         _packet.data = 0;
114         _packet.size = 0;
115
116         /* XXX: should we reset _packet.data and size after each *_decode_* call? */
117
118         while (video && decode_video_packet()) {}
119
120         if (audio) {
121                 decode_audio_packet ();
122         }
123
124         /* Make sure all streams are the same length and round up to the next video frame */
125
126         auto const frc = film()->active_frame_rate_change(_ffmpeg_content->position());
127         ContentTime full_length (_ffmpeg_content->full_length(film()), frc);
128         full_length = full_length.ceil (frc.source);
129         if (video) {
130                 double const vfr = _ffmpeg_content->video_frame_rate().get();
131                 auto const f = full_length.frames_round (vfr);
132                 auto v = video->position(film()).get_value_or(ContentTime()).frames_round(vfr) + 1;
133                 while (v < f) {
134                         video->emit (film(), shared_ptr<const ImageProxy> (new RawImageProxy (_black_image)), v);
135                         ++v;
136                 }
137         }
138
139         for (auto i: _ffmpeg_content->ffmpeg_audio_streams ()) {
140                 auto a = audio->stream_position(film(), i);
141                 /* Unfortunately if a is 0 that really means that we don't know the stream position since
142                    there has been no data on it since the last seek.  In this case we'll just do nothing
143                    here.  I'm not sure if that's the right idea.
144                 */
145                 if (a > ContentTime()) {
146                         while (a < full_length) {
147                                 auto to_do = min (full_length - a, ContentTime::from_seconds (0.1));
148                                 auto silence = make_shared<AudioBuffers>(i->channels(), to_do.frames_ceil (i->frame_rate()));
149                                 silence->make_silent ();
150                                 audio->emit (film(), i, silence, a, true);
151                                 a += to_do;
152                         }
153                 }
154         }
155
156         if (audio) {
157                 audio->flush ();
158         }
159 }
160
161
162 bool
163 FFmpegDecoder::pass ()
164 {
165         int r = av_read_frame (_format_context, &_packet);
166
167         /* AVERROR_INVALIDDATA can apparently be returned sometimes even when av_read_frame
168            has pretty-much succeeded (and hence generated data which should be processed).
169            Hence it makes sense to continue here in that case.
170         */
171         if (r < 0 && r != AVERROR_INVALIDDATA) {
172                 if (r != AVERROR_EOF) {
173                         /* Maybe we should fail here, but for now we'll just finish off instead */
174                         char buf[256];
175                         av_strerror (r, buf, sizeof(buf));
176                         LOG_ERROR (N_("error on av_read_frame (%1) (%2)"), &buf[0], r);
177                 }
178
179                 flush ();
180                 return true;
181         }
182
183         int const si = _packet.stream_index;
184         auto fc = _ffmpeg_content;
185
186         if (_video_stream && si == _video_stream.get() && video && !video->ignore()) {
187                 decode_video_packet ();
188         } else if (fc->subtitle_stream() && fc->subtitle_stream()->uses_index(_format_context, si) && !only_text()->ignore()) {
189                 decode_subtitle_packet ();
190         } else {
191                 decode_audio_packet ();
192         }
193
194         av_packet_unref (&_packet);
195         return false;
196 }
197
198
199 /** @param data pointer to array of pointers to buffers.
200  *  Only the first buffer will be used for non-planar data, otherwise there will be one per channel.
201  */
202 shared_ptr<AudioBuffers>
203 FFmpegDecoder::deinterleave_audio (shared_ptr<FFmpegAudioStream> stream) const
204 {
205         DCPOMATIC_ASSERT (bytes_per_audio_sample (stream));
206
207 DCPOMATIC_DISABLE_WARNINGS
208         int const size = av_samples_get_buffer_size (
209                 0, stream->stream(_format_context)->codec->channels, _frame->nb_samples, audio_sample_format (stream), 1
210                 );
211 DCPOMATIC_ENABLE_WARNINGS
212
213         /* XXX: can't we just use _frame->nb_samples directly here? */
214         /* XXX: can't we use swr_convert() to do the format conversion? */
215
216         /* Deinterleave and convert to float */
217
218         /* total_samples and frames will be rounded down here, so if there are stray samples at the end
219            of the block that do not form a complete sample or frame they will be dropped.
220         */
221         int const total_samples = size / bytes_per_audio_sample (stream);
222         int const channels = stream->channels();
223         int const frames = total_samples / channels;
224         auto audio = make_shared<AudioBuffers>(channels, frames);
225         auto data = audio->data();
226
227         switch (audio_sample_format (stream)) {
228         case AV_SAMPLE_FMT_U8:
229         {
230                 uint8_t* p = reinterpret_cast<uint8_t *> (_frame->data[0]);
231                 int sample = 0;
232                 int channel = 0;
233                 for (int i = 0; i < total_samples; ++i) {
234                         data[channel][sample] = float(*p++) / (1 << 23);
235
236                         ++channel;
237                         if (channel == channels) {
238                                 channel = 0;
239                                 ++sample;
240                         }
241                 }
242         }
243         break;
244
245         case AV_SAMPLE_FMT_S16:
246         {
247                 int16_t* p = reinterpret_cast<int16_t *> (_frame->data[0]);
248                 int sample = 0;
249                 int channel = 0;
250                 for (int i = 0; i < total_samples; ++i) {
251                         data[channel][sample] = float(*p++) / (1 << 15);
252
253                         ++channel;
254                         if (channel == channels) {
255                                 channel = 0;
256                                 ++sample;
257                         }
258                 }
259         }
260         break;
261
262         case AV_SAMPLE_FMT_S16P:
263         {
264                 int16_t** p = reinterpret_cast<int16_t **> (_frame->data);
265                 for (int i = 0; i < channels; ++i) {
266                         for (int j = 0; j < frames; ++j) {
267                                 data[i][j] = static_cast<float>(p[i][j]) / (1 << 15);
268                         }
269                 }
270         }
271         break;
272
273         case AV_SAMPLE_FMT_S32:
274         {
275                 int32_t* p = reinterpret_cast<int32_t *> (_frame->data[0]);
276                 int sample = 0;
277                 int channel = 0;
278                 for (int i = 0; i < total_samples; ++i) {
279                         data[channel][sample] = static_cast<float>(*p++) / 2147483648;
280
281                         ++channel;
282                         if (channel == channels) {
283                                 channel = 0;
284                                 ++sample;
285                         }
286                 }
287         }
288         break;
289
290         case AV_SAMPLE_FMT_S32P:
291         {
292                 int32_t** p = reinterpret_cast<int32_t **> (_frame->data);
293                 for (int i = 0; i < channels; ++i) {
294                         for (int j = 0; j < frames; ++j) {
295                                 data[i][j] = static_cast<float>(p[i][j]) / 2147483648;
296                         }
297                 }
298         }
299         break;
300
301         case AV_SAMPLE_FMT_FLT:
302         {
303                 float* p = reinterpret_cast<float*> (_frame->data[0]);
304                 int sample = 0;
305                 int channel = 0;
306                 for (int i = 0; i < total_samples; ++i) {
307                         data[channel][sample] = *p++;
308
309                         ++channel;
310                         if (channel == channels) {
311                                 channel = 0;
312                                 ++sample;
313                         }
314                 }
315         }
316         break;
317
318         case AV_SAMPLE_FMT_FLTP:
319         {
320                 float** p = reinterpret_cast<float**> (_frame->data);
321                 DCPOMATIC_ASSERT (_frame->channels <= channels);
322                 /* Sometimes there aren't as many channels in the _frame as in the stream */
323                 for (int i = 0; i < _frame->channels; ++i) {
324                         memcpy (data[i], p[i], frames * sizeof(float));
325                 }
326                 for (int i = _frame->channels; i < channels; ++i) {
327                         audio->make_silent (i);
328                 }
329         }
330         break;
331
332         default:
333                 throw DecodeError (String::compose (_("Unrecognised audio sample format (%1)"), static_cast<int> (audio_sample_format (stream))));
334         }
335
336         return audio;
337 }
338
339
340 AVSampleFormat
341 FFmpegDecoder::audio_sample_format (shared_ptr<FFmpegAudioStream> stream) const
342 {
343 DCPOMATIC_DISABLE_WARNINGS
344         return stream->stream (_format_context)->codec->sample_fmt;
345 DCPOMATIC_ENABLE_WARNINGS
346 }
347
348
349 int
350 FFmpegDecoder::bytes_per_audio_sample (shared_ptr<FFmpegAudioStream> stream) const
351 {
352         return av_get_bytes_per_sample (audio_sample_format (stream));
353 }
354
355
356 void
357 FFmpegDecoder::seek (ContentTime time, bool accurate)
358 {
359         Decoder::seek (time, accurate);
360
361         /* If we are doing an `accurate' seek, we need to use pre-roll, as
362            we don't really know what the seek will give us.
363         */
364
365         auto pre_roll = accurate ? ContentTime::from_seconds (2) : ContentTime (0);
366         time -= pre_roll;
367
368         /* XXX: it seems debatable whether PTS should be used here...
369            http://www.mjbshaw.com/2012/04/seeking-in-ffmpeg-know-your-timestamp.html
370         */
371
372         optional<int> stream;
373
374         if (_video_stream) {
375                 stream = _video_stream;
376         } else {
377                 DCPOMATIC_ASSERT (_ffmpeg_content->audio);
378                 auto s = dynamic_pointer_cast<FFmpegAudioStream>(_ffmpeg_content->audio->stream());
379                 if (s) {
380                         stream = s->index (_format_context);
381                 }
382         }
383
384         DCPOMATIC_ASSERT (stream);
385
386         auto u = time - _pts_offset;
387         if (u < ContentTime ()) {
388                 u = ContentTime ();
389         }
390         av_seek_frame (
391                 _format_context,
392                 stream.get(),
393                 u.seconds() / av_q2d (_format_context->streams[stream.get()]->time_base),
394                 AVSEEK_FLAG_BACKWARD
395                 );
396
397         {
398                 /* Force re-creation of filter graphs to reset them and hence to make sure
399                    they don't have any pre-seek frames knocking about.
400                 */
401                 boost::mutex::scoped_lock lm (_filter_graphs_mutex);
402                 _filter_graphs.clear ();
403         }
404
405         if (video_codec_context ()) {
406                 avcodec_flush_buffers (video_codec_context());
407         }
408
409 DCPOMATIC_DISABLE_WARNINGS
410         for (auto i: ffmpeg_content()->ffmpeg_audio_streams()) {
411                 avcodec_flush_buffers (i->stream(_format_context)->codec);
412         }
413 DCPOMATIC_ENABLE_WARNINGS
414
415         if (subtitle_codec_context ()) {
416                 avcodec_flush_buffers (subtitle_codec_context ());
417         }
418
419         _have_current_subtitle = false;
420
421         for (auto& i: _next_time) {
422                 i = optional<ContentTime>();
423         }
424 }
425
426
427 shared_ptr<FFmpegAudioStream>
428 FFmpegDecoder::audio_stream_from_index (int index) const
429 {
430         /* XXX: inefficient */
431         auto streams = ffmpeg_content()->ffmpeg_audio_streams();
432         auto stream = streams.begin();
433         while (stream != streams.end() && !(*stream)->uses_index(_format_context, index)) {
434                 ++stream;
435         }
436
437         if (stream == streams.end ()) {
438                 return {};
439         }
440
441         return *stream;
442 }
443
444
445 void
446 FFmpegDecoder::decode_audio_packet ()
447 {
448         /* Audio packets can contain multiple frames, so we may have to call avcodec_decode_audio4
449            several times.
450         */
451
452         AVPacket copy_packet = _packet;
453         int const stream_index = copy_packet.stream_index;
454
455         auto stream = audio_stream_from_index (stream_index);
456         if (!stream) {
457                 /* The packet's stream may not be an audio one; just ignore it in this method if so */
458                 return;
459         }
460
461 DCPOMATIC_DISABLE_WARNINGS
462         while (copy_packet.size > 0) {
463
464                 int frame_finished;
465                 int decode_result = avcodec_decode_audio4 (stream->stream(_format_context)->codec, _frame, &frame_finished, &copy_packet);
466                 if (decode_result < 0) {
467                         /* avcodec_decode_audio4 can sometimes return an error even though it has decoded
468                            some valid data; for example dca_subframe_footer can return AVERROR_INVALIDDATA
469                            if it overreads the auxiliary data.  ffplay carries on if frame_finished is true,
470                            even in the face of such an error, so I think we should too.
471
472                            Returning from the method here caused mantis #352.
473                         */
474                         LOG_WARNING ("avcodec_decode_audio4 failed (%1)", decode_result);
475
476                         /* Fudge decode_result so that we come out of the while loop when
477                            we've processed this data.
478                         */
479                         decode_result = copy_packet.size;
480                 }
481
482                 if (frame_finished) {
483                         auto data = deinterleave_audio (stream);
484
485                         ContentTime ct;
486                         if (_frame->pts == AV_NOPTS_VALUE) {
487                                 /* In some streams we see not every frame coming through with a timestamp; for those
488                                    that have AV_NOPTS_VALUE we need to work out the timestamp ourselves.  This is
489                                    particularly noticeable with TrueHD streams (see #1111).
490                                 */
491                                 if (_next_time[stream_index]) {
492                                         ct = *_next_time[stream_index];
493                                 }
494                         } else {
495                                 ct = ContentTime::from_seconds (
496                                         av_frame_get_best_effort_timestamp (_frame) *
497                                         av_q2d (stream->stream(_format_context)->time_base))
498                                         + _pts_offset;
499                         }
500
501                         _next_time[stream_index] = ct + ContentTime::from_frames(data->frames(), stream->frame_rate());
502
503                         if (ct < ContentTime()) {
504                                 /* Discard audio data that comes before time 0 */
505                                 auto const remove = min (int64_t(data->frames()), (-ct).frames_ceil(double(stream->frame_rate())));
506                                 data->move (data->frames() - remove, remove, 0);
507                                 data->set_frames (data->frames() - remove);
508                                 ct += ContentTime::from_frames (remove, stream->frame_rate());
509                         }
510
511                         if (ct < ContentTime()) {
512                                 LOG_WARNING (
513                                         "Crazy timestamp %1 for %2 samples in stream %3 packet pts %4 (ts=%5 tb=%6, off=%7)",
514                                         to_string(ct),
515                                         data->frames(),
516                                         copy_packet.stream_index,
517                                         copy_packet.pts,
518                                         av_frame_get_best_effort_timestamp(_frame),
519                                         av_q2d(stream->stream(_format_context)->time_base),
520                                         to_string(_pts_offset)
521                                         );
522                         }
523 DCPOMATIC_ENABLE_WARNINGS
524
525                         /* Give this data provided there is some, and its time is sane */
526                         if (ct >= ContentTime() && data->frames() > 0) {
527                                 audio->emit (film(), stream, data, ct);
528                         }
529                 }
530
531                 copy_packet.data += decode_result;
532                 copy_packet.size -= decode_result;
533         }
534 }
535
536
537 bool
538 FFmpegDecoder::decode_video_packet ()
539 {
540         DCPOMATIC_ASSERT (_video_stream);
541
542         int frame_finished;
543 DCPOMATIC_DISABLE_WARNINGS
544         if (avcodec_decode_video2 (video_codec_context(), _frame, &frame_finished, &_packet) < 0 || !frame_finished) {
545                 return false;
546         }
547 DCPOMATIC_ENABLE_WARNINGS
548
549         boost::mutex::scoped_lock lm (_filter_graphs_mutex);
550
551         shared_ptr<VideoFilterGraph> graph;
552
553         auto i = _filter_graphs.begin();
554         while (i != _filter_graphs.end() && !(*i)->can_process (dcp::Size (_frame->width, _frame->height), (AVPixelFormat) _frame->format)) {
555                 ++i;
556         }
557
558         if (i == _filter_graphs.end ()) {
559                 dcp::Fraction vfr (lrint(_ffmpeg_content->video_frame_rate().get() * 1000), 1000);
560                 graph = make_shared<VideoFilterGraph>(dcp::Size (_frame->width, _frame->height), (AVPixelFormat) _frame->format, vfr);
561                 graph->setup (_ffmpeg_content->filters ());
562                 _filter_graphs.push_back (graph);
563                 LOG_GENERAL (N_("New graph for %1x%2, pixel format %3"), _frame->width, _frame->height, _frame->format);
564         } else {
565                 graph = *i;
566         }
567
568         auto images = graph->process (_frame);
569
570         for (auto const& i: images) {
571
572                 auto image = i.first;
573
574                 if (i.second != AV_NOPTS_VALUE) {
575                         double const pts = i.second * av_q2d(_format_context->streams[_video_stream.get()]->time_base) + _pts_offset.seconds();
576
577                         video->emit (
578                                 film(),
579                                 make_shared<RawImageProxy>(image),
580                                 llrint(pts * _ffmpeg_content->active_video_frame_rate(film()))
581                                 );
582                 } else {
583                         LOG_WARNING_NC ("Dropping frame without PTS");
584                 }
585         }
586
587         return true;
588 }
589
590
591 void
592 FFmpegDecoder::decode_subtitle_packet ()
593 {
594         int got_subtitle;
595         AVSubtitle sub;
596         if (avcodec_decode_subtitle2 (subtitle_codec_context(), &sub, &got_subtitle, &_packet) < 0 || !got_subtitle) {
597                 return;
598         }
599
600         /* Stop any current subtitle, either at the time it was supposed to stop, or now if now is sooner */
601         if (_have_current_subtitle) {
602                 if (_current_subtitle_to) {
603                         only_text()->emit_stop (min(*_current_subtitle_to, subtitle_period(sub).from + _pts_offset));
604                 } else {
605                         only_text()->emit_stop (subtitle_period(sub).from + _pts_offset);
606                 }
607                 _have_current_subtitle = false;
608         }
609
610         if (sub.num_rects <= 0) {
611                 /* Nothing new in this subtitle */
612                 return;
613         }
614
615         /* Subtitle PTS (within the source, not taking into account any of the
616            source that we may have chopped off for the DCP).
617         */
618         auto sub_period = subtitle_period (sub);
619         ContentTime from;
620         from = sub_period.from + _pts_offset;
621         if (sub_period.to) {
622                 _current_subtitle_to = *sub_period.to + _pts_offset;
623         } else {
624                 _current_subtitle_to = optional<ContentTime>();
625                 _have_current_subtitle = true;
626         }
627
628         for (unsigned int i = 0; i < sub.num_rects; ++i) {
629                 auto const rect = sub.rects[i];
630
631                 switch (rect->type) {
632                 case SUBTITLE_NONE:
633                         break;
634                 case SUBTITLE_BITMAP:
635                         decode_bitmap_subtitle (rect, from);
636                         break;
637                 case SUBTITLE_TEXT:
638                         cout << "XXX: SUBTITLE_TEXT " << rect->text << "\n";
639                         break;
640                 case SUBTITLE_ASS:
641                         decode_ass_subtitle (rect->ass, from);
642                         break;
643                 }
644         }
645
646         if (_current_subtitle_to) {
647                 only_text()->emit_stop (*_current_subtitle_to);
648         }
649
650         avsubtitle_free (&sub);
651 }
652
653
654 void
655 FFmpegDecoder::decode_bitmap_subtitle (AVSubtitleRect const * rect, ContentTime from)
656 {
657         /* Note BGRA is expressed little-endian, so the first byte in the word is B, second
658            G, third R, fourth A.
659         */
660         auto image = make_shared<Image>(AV_PIX_FMT_BGRA, dcp::Size (rect->w, rect->h), true);
661
662 #ifdef DCPOMATIC_HAVE_AVSUBTITLERECT_PICT
663         /* Start of the first line in the subtitle */
664         auto sub_p = rect->pict.data[0];
665         /* sub_p looks up into a BGRA palette which is at rect->pict.data[1];
666            (i.e. first byte B, second G, third R, fourth A)
667         */
668         auto const palette = rect->pict.data[1];
669 #else
670         /* Start of the first line in the subtitle */
671         auto sub_p = rect->data[0];
672         /* sub_p looks up into a BGRA palette which is at rect->data[1].
673            (first byte B, second G, third R, fourth A)
674         */
675         auto const* palette = rect->data[1];
676 #endif
677         /* And the stream has a map of those palette colours to colours
678            chosen by the user; created a `mapped' palette from those settings.
679         */
680         auto colour_map = ffmpeg_content()->subtitle_stream()->colours();
681         vector<RGBA> mapped_palette (rect->nb_colors);
682         for (int i = 0; i < rect->nb_colors; ++i) {
683                 RGBA c (palette[2], palette[1], palette[0], palette[3]);
684                 auto j = colour_map.find (c);
685                 if (j != colour_map.end ()) {
686                         mapped_palette[i] = j->second;
687                 } else {
688                         /* This colour was not found in the FFmpegSubtitleStream's colour map; probably because
689                            it is from a project that was created before this stuff was added.  Just use the
690                            colour straight from the original palette.
691                         */
692                         mapped_palette[i] = c;
693                 }
694                 palette += 4;
695         }
696
697         /* Start of the output data */
698         auto out_p = image->data()[0];
699
700         for (int y = 0; y < rect->h; ++y) {
701                 auto sub_line_p = sub_p;
702                 auto out_line_p = out_p;
703                 for (int x = 0; x < rect->w; ++x) {
704                         auto const p = mapped_palette[*sub_line_p++];
705                         *out_line_p++ = p.b;
706                         *out_line_p++ = p.g;
707                         *out_line_p++ = p.r;
708                         *out_line_p++ = p.a;
709                 }
710 #ifdef DCPOMATIC_HAVE_AVSUBTITLERECT_PICT
711                 sub_p += rect->pict.linesize[0];
712 #else
713                 sub_p += rect->linesize[0];
714 #endif
715                 out_p += image->stride()[0];
716         }
717
718         int target_width = subtitle_codec_context()->width;
719         if (target_width == 0 && video_codec_context()) {
720                 /* subtitle_codec_context()->width == 0 has been seen in the wild but I don't
721                    know if it's supposed to mean something from FFmpeg's point of view.
722                 */
723                 target_width = video_codec_context()->width;
724         }
725         int target_height = subtitle_codec_context()->height;
726         if (target_height == 0 && video_codec_context()) {
727                 target_height = video_codec_context()->height;
728         }
729         DCPOMATIC_ASSERT (target_width);
730         DCPOMATIC_ASSERT (target_height);
731         dcpomatic::Rect<double> const scaled_rect (
732                 static_cast<double>(rect->x) / target_width,
733                 static_cast<double>(rect->y) / target_height,
734                 static_cast<double>(rect->w) / target_width,
735                 static_cast<double>(rect->h) / target_height
736                 );
737
738         only_text()->emit_bitmap_start (from, image, scaled_rect);
739 }
740
741
742 void
743 FFmpegDecoder::decode_ass_subtitle (string ass, ContentTime from)
744 {
745         /* We have no styles and no Format: line, so I'm assuming that FFmpeg
746            produces a single format of Dialogue: lines...
747         */
748
749         int commas = 0;
750         string text;
751         for (size_t i = 0; i < ass.length(); ++i) {
752                 if (commas < 9 && ass[i] == ',') {
753                         ++commas;
754                 } else if (commas == 9) {
755                         text += ass[i];
756                 }
757         }
758
759         if (text.empty ()) {
760                 return;
761         }
762
763         sub::RawSubtitle base;
764         auto raw = sub::SSAReader::parse_line (
765                 base,
766                 text,
767                 _ffmpeg_content->video->size().width,
768                 _ffmpeg_content->video->size().height
769                 );
770
771         for (auto const& i: sub::collect<vector<sub::Subtitle>>(raw)) {
772                 only_text()->emit_plain_start (from, i);
773         }
774 }