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