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