Fix subtitle colouring (#152).
[dcpomatic.git] / src / lib / ffmpeg_decoder.cc
index ede724b5f26e9d03fdb85223a8a05985c89ceeb8..d9b7796599b8c7cdf7687454fd6dc668db5195ef 100644 (file)
@@ -61,7 +61,7 @@ using libdcp::Size;
 FFmpegDecoder::FFmpegDecoder (shared_ptr<const Film> f, shared_ptr<const FFmpegContent> c, bool video, bool audio)
        : Decoder (f)
        , VideoDecoder (f, c)
-       , AudioDecoder (f)
+       , AudioDecoder (f, c)
        , SubtitleDecoder (f)
        , FFmpeg (c)
        , _subtitle_codec_context (0)
@@ -97,6 +97,8 @@ FFmpegDecoder::FFmpegDecoder (shared_ptr<const Film> f, shared_ptr<const FFmpegC
                _video_pts_offset = _audio_pts_offset = - min (c->first_video().get(), c->audio_stream()->first_audio.get());
        } else if (have_video) {
                _video_pts_offset = - c->first_video().get();
+       } else if (have_audio) {
+               _audio_pts_offset = - c->audio_stream()->first_audio.get();
        }
 
        /* Now adjust both so that the video pts starts on a frame */
@@ -169,12 +171,14 @@ FFmpegDecoder::pass ()
 
        shared_ptr<const Film> film = _film.lock ();
        assert (film);
+
+       int const si = _packet.stream_index;
        
-       if (_packet.stream_index == _video_stream && _decode_video) {
+       if (si == _video_stream && _decode_video) {
                decode_video_packet ();
-       } else if (_ffmpeg_content->audio_stream() && _packet.stream_index == _ffmpeg_content->audio_stream()->id && _decode_audio) {
+       } else if (_ffmpeg_content->audio_stream() && si == _ffmpeg_content->audio_stream()->index (_format_context) && _decode_audio) {
                decode_audio_packet ();
-       } else if (_ffmpeg_content->subtitle_stream() && _packet.stream_index == _ffmpeg_content->subtitle_stream()->id && film->with_subtitles ()) {
+       } else if (_ffmpeg_content->subtitle_stream() && si == _ffmpeg_content->subtitle_stream()->index (_format_context) && film->with_subtitles ()) {
                decode_subtitle_packet ();
        }
 
@@ -337,6 +341,7 @@ FFmpegDecoder::seek (VideoContent::Frame frame, bool accurate)
                }
 
                if (_packet.stream_index != _video_stream) {
+                       av_free_packet (&_packet);
                        continue;
                }
                
@@ -385,7 +390,7 @@ FFmpegDecoder::decode_audio_packet ()
                                /* Where we are in the source, in seconds */
                                double const pts = av_q2d (_format_context->streams[copy_packet.stream_index]->time_base)
                                        * av_frame_get_best_effort_timestamp(_frame) + _audio_pts_offset;
-                               
+
                                if (pts > 0) {
                                        /* Emit some silence */
                                        shared_ptr<AudioBuffers> silence (
@@ -508,11 +513,11 @@ FFmpegDecoder::setup_subtitle ()
 {
        boost::mutex::scoped_lock lm (_mutex);
        
-       if (!_ffmpeg_content->subtitle_stream() || _ffmpeg_content->subtitle_stream()->id >= int (_format_context->nb_streams)) {
+       if (!_ffmpeg_content->subtitle_stream() || _ffmpeg_content->subtitle_stream()->index (_format_context) >= int (_format_context->nb_streams)) {
                return;
        }
 
-       _subtitle_codec_context = _format_context->streams[_ffmpeg_content->subtitle_stream()->id]->codec;
+       _subtitle_codec_context = _ffmpeg_content->subtitle_stream()->stream(_format_context)->codec;
        _subtitle_codec = avcodec_find_decoder (_subtitle_codec_context->codec_id);
 
        if (_subtitle_codec == 0) {
@@ -554,7 +559,7 @@ FFmpegDecoder::decode_subtitle_packet ()
        /* Subtitle PTS in seconds (within the source, not taking into account any of the
           source that we may have chopped off for the DCP)
        */
-       double const packet_time = static_cast<double> (sub.pts) / AV_TIME_BASE;
+       double const packet_time = (static_cast<double> (sub.pts ) / AV_TIME_BASE) + _video_pts_offset;
        
        /* hence start time for this sub */
        Time const from = (packet_time + (double (sub.start_display_time) / 1e3)) * TIME_HZ;
@@ -565,21 +570,27 @@ FFmpegDecoder::decode_subtitle_packet ()
        if (rect->type != SUBTITLE_BITMAP) {
                throw DecodeError (_("non-bitmap subtitles not yet supported"));
        }
-       
+
+       /* Note RGBA is expressed little-endian, so the first byte in the word is R, second
+          G, third B, fourth A.
+       */
        shared_ptr<Image> image (new Image (PIX_FMT_RGBA, libdcp::Size (rect->w, rect->h), true));
 
        /* Start of the first line in the subtitle */
        uint8_t* sub_p = rect->pict.data[0];
-       /* sub_p looks up into a RGB palette which is here */
+       /* sub_p looks up into a BGRA palette which is here
+          (i.e. first byte B, second G, third R, fourth A)
+       */
        uint32_t const * palette = (uint32_t *) rect->pict.data[1];
        /* Start of the output data */
        uint32_t* out_p = (uint32_t *) image->data()[0];
-       
+
        for (int y = 0; y < rect->h; ++y) {
                uint8_t* sub_line_p = sub_p;
                uint32_t* out_line_p = out_p;
                for (int x = 0; x < rect->w; ++x) {
-                       *out_line_p++ = palette[*sub_line_p++];
+                       uint32_t const p = palette[*sub_line_p++];
+                       *out_line_p++ = ((p & 0xff) << 16) | (p & 0xff00) | ((p & 0xff0000) >> 16) | (p & 0xff000000);
                }
                sub_p += rect->pict.linesize[0];
                out_p += image->stride()[0] / sizeof (uint32_t);