X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Flib%2Fffmpeg_decoder.cc;h=0c9225a6abc2f6485ab7fe31b6e0cb376ea4671d;hb=e60bb3e51bd1508b149e6b8f6608f09b5196ae26;hp=f8152b56e7629021d1a197b633cbe3d1559eaaff;hpb=2651ef8c2fd486332457630d459c1e620e626c1b;p=dcpomatic.git diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc index f8152b56e..0c9225a6a 100644 --- a/src/lib/ffmpeg_decoder.cc +++ b/src/lib/ffmpeg_decoder.cc @@ -124,14 +124,14 @@ void FFmpegDecoder::flush () { /* Get any remaining frames */ - + _packet.data = 0; _packet.size = 0; - + /* XXX: should we reset _packet.data and size after each *_decode_* call? */ - + while (decode_video_packet ()) {} - + decode_audio_packet (); AudioDecoder::flush (); } @@ -152,7 +152,7 @@ FFmpegDecoder::pass () av_strerror (r, buf, sizeof(buf)); LOG_ERROR (N_("error on av_read_frame (%1) (%2)"), buf, r); } - + flush (); return true; } @@ -206,7 +206,7 @@ FFmpegDecoder::deinterleave_audio (shared_ptr stream, uint8_t } } break; - + case AV_SAMPLE_FMT_S16: { int16_t* p = reinterpret_cast (data[0]); @@ -234,7 +234,7 @@ FFmpegDecoder::deinterleave_audio (shared_ptr stream, uint8_t } } break; - + case AV_SAMPLE_FMT_S32: { int32_t* p = reinterpret_cast (data[0]); @@ -268,7 +268,7 @@ FFmpegDecoder::deinterleave_audio (shared_ptr stream, uint8_t } } break; - + case AV_SAMPLE_FMT_FLTP: { float** p = reinterpret_cast (data); @@ -314,14 +314,17 @@ FFmpegDecoder::seek (ContentTime time, bool accurate) /* XXX: it seems debatable whether PTS should be used here... http://www.mjbshaw.com/2012/04/seeking-in-ffmpeg-know-your-timestamp.html */ - - ContentTime const u = time - _pts_offset; + + ContentTime u = time - _pts_offset; + if (u < ContentTime ()) { + u = ContentTime (); + } av_seek_frame (_format_context, _video_stream, u.seconds() / av_q2d (_format_context->streams[_video_stream]->time_base), AVSEEK_FLAG_BACKWARD); avcodec_flush_buffers (video_codec_context()); /* XXX: should be flushing audio buffers? */ - + if (subtitle_codec_context ()) { avcodec_flush_buffers (subtitle_codec_context ()); } @@ -333,7 +336,7 @@ FFmpegDecoder::decode_audio_packet () /* Audio packets can contain multiple frames, so we may have to call avcodec_decode_audio4 several times. */ - + AVPacket copy_packet = _packet; /* XXX: inefficient */ @@ -347,7 +350,7 @@ FFmpegDecoder::decode_audio_packet () /* The packet's stream may not be an audio one; just ignore it in this method if so */ return; } - + while (copy_packet.size > 0) { int frame_finished; @@ -373,14 +376,14 @@ FFmpegDecoder::decode_audio_packet () av_frame_get_best_effort_timestamp (_frame) * av_q2d ((*stream)->stream (_format_context)->time_base)) + _pts_offset; - + int const data_size = av_samples_get_buffer_size ( 0, (*stream)->stream(_format_context)->codec->channels, _frame->nb_samples, audio_sample_format (*stream), 1 ); audio (*stream, deinterleave_audio (*stream, _frame->data, data_size), ct); } - + copy_packet.data += decode_result; copy_packet.size -= decode_result; } @@ -397,7 +400,7 @@ FFmpegDecoder::decode_video_packet () boost::mutex::scoped_lock lm (_filter_graphs_mutex); shared_ptr graph; - + list >::iterator i = _filter_graphs.begin(); while (i != _filter_graphs.end() && !(*i)->can_process (dcp::Size (_frame->width, _frame->height), (AVPixelFormat) _frame->format)) { ++i; @@ -416,7 +419,7 @@ FFmpegDecoder::decode_video_packet () for (list, int64_t> >::iterator i = images.begin(); i != images.end(); ++i) { shared_ptr image = i->first; - + if (i->second != AV_NOPTS_VALUE) { double const pts = i->second * av_q2d (_format_context->streams[_video_stream]->time_base) + _pts_offset.seconds (); video ( @@ -430,7 +433,7 @@ FFmpegDecoder::decode_video_packet () return true; } - + void FFmpegDecoder::decode_subtitle_packet () { @@ -439,7 +442,7 @@ FFmpegDecoder::decode_subtitle_packet () if (avcodec_decode_subtitle2 (subtitle_codec_context(), &sub, &got_subtitle, &_packet) < 0 || !got_subtitle) { return; } - + if (sub.num_rects <= 0) { /* Sometimes we get an empty AVSubtitle, which is used by some codecs to indicate that the previous subtitle should stop. We can ignore it here. @@ -462,7 +465,7 @@ FFmpegDecoder::decode_subtitle_packet () /* We have to look up the `to' time in the stream's records */ period.to = ffmpeg_content()->subtitle_stream()->find_subtitle_to (sub_period.from); } - + AVSubtitleRect const * rect = sub.rects[0]; switch (rect->type) { @@ -478,7 +481,7 @@ FFmpegDecoder::decode_subtitle_packet () cout << "XXX: SUBTITLE_ASS " << rect->ass << "\n"; break; } - + avsubtitle_free (&sub); } @@ -501,7 +504,7 @@ FFmpegDecoder::decode_bitmap_subtitle (AVSubtitleRect const * rect, ContentTimeP G, third B, fourth A. */ shared_ptr image (new Image (PIX_FMT_RGBA, dcp::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 BGRA palette which is here @@ -510,7 +513,7 @@ FFmpegDecoder::decode_bitmap_subtitle (AVSubtitleRect const * rect, ContentTimeP 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; @@ -521,7 +524,7 @@ FFmpegDecoder::decode_bitmap_subtitle (AVSubtitleRect const * rect, ContentTimeP sub_p += rect->pict.linesize[0]; out_p += image->stride()[0] / sizeof (uint32_t); } - + dcp::Size const vs = _ffmpeg_content->video_size (); dcpomatic::Rect const scaled_rect ( static_cast (rect->x) / vs.width, @@ -529,7 +532,7 @@ FFmpegDecoder::decode_bitmap_subtitle (AVSubtitleRect const * rect, ContentTimeP static_cast (rect->w) / vs.width, static_cast (rect->h) / vs.height ); - + image_subtitle (period, image, scaled_rect); }