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