X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Flib%2Fffmpeg_decoder.cc;h=c3a42545a6ed695a97a06257971e9bd71fae6059;hb=5b3e3df6c9352e31dd932a5af215eabbf2cf27c8;hp=ae44ff5220d04a2730087b89ea4b7f49a24e1be3;hpb=43494601da412259814fdb1345950329cc4aa849;p=dcpomatic.git diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc index ae44ff522..c3a42545a 100644 --- a/src/lib/ffmpeg_decoder.cc +++ b/src/lib/ffmpeg_decoder.cc @@ -47,10 +47,10 @@ extern "C" { #include "i18n.h" -#define LOG_GENERAL(...) _video_content->film()->log()->log (String::compose (__VA_ARGS__), Log::TYPE_GENERAL); -#define LOG_ERROR(...) _video_content->film()->log()->log (String::compose (__VA_ARGS__), Log::TYPE_ERROR); -#define LOG_WARNING_NC(...) _video_content->film()->log()->log (__VA_ARGS__, Log::TYPE_WARNING); -#define LOG_WARNING(...) _video_content->film()->log()->log (String::compose (__VA_ARGS__), Log::TYPE_WARNING); +#define LOG_GENERAL(...) _log->log (String::compose (__VA_ARGS__), LogEntry::TYPE_GENERAL); +#define LOG_ERROR(...) _log->log (String::compose (__VA_ARGS__), LogEntry::TYPE_ERROR); +#define LOG_WARNING_NC(...) _log->log (__VA_ARGS__, LogEntry::TYPE_WARNING); +#define LOG_WARNING(...) _log->log (String::compose (__VA_ARGS__), LogEntry::TYPE_WARNING); using std::cout; using std::vector; @@ -67,51 +67,9 @@ FFmpegDecoder::FFmpegDecoder (shared_ptr c, shared_ptr , SubtitleDecoder (c) , FFmpeg (c) , _log (log) + , _pts_offset (pts_offset (c->ffmpeg_audio_streams(), c->first_video(), c->video_frame_rate())) { - /* Audio and video frame PTS values may not start with 0. We want - to fiddle them so that: - 1. One of them starts at time 0. - 2. The first video PTS value ends up on a frame boundary. - - Then we remove big initial gaps in PTS and we allow our - insertion of black frames to work. - - We will do: - audio_pts_to_use = audio_pts_from_ffmpeg + pts_offset; - video_pts_to_use = video_pts_from_ffmpeg + pts_offset; - */ - - /* First, make one of them start at 0 */ - - vector > streams = c->ffmpeg_audio_streams (); - - _pts_offset = ContentTime::min (); - - if (c->first_video ()) { - _pts_offset = - c->first_video().get (); - } - - BOOST_FOREACH (shared_ptr i, streams) { - if (i->first_audio) { - _pts_offset = max (_pts_offset, - i->first_audio.get ()); - } - } - - /* If _pts_offset is positive we would be pushing things from a -ve PTS to be played. - I don't think we ever want to do that, as it seems things at -ve PTS are not meant - to be seen (use for alignment bars etc.); see mantis #418. - */ - if (_pts_offset > ContentTime ()) { - _pts_offset = ContentTime (); - } - - /* Now adjust so that the video pts starts on a frame */ - if (c->first_video ()) { - ContentTime first_video = c->first_video().get() + _pts_offset; - ContentTime const old_first_video = first_video; - _pts_offset += first_video.round_up (c->video_frame_rate ()) - old_first_video; - } } void @@ -131,7 +89,7 @@ FFmpegDecoder::flush () } bool -FFmpegDecoder::pass () +FFmpegDecoder::pass (PassReason reason, bool accurate) { int r = av_read_frame (_format_context, &_packet); @@ -154,11 +112,11 @@ FFmpegDecoder::pass () int const si = _packet.stream_index; shared_ptr fc = _ffmpeg_content; - if (si == _video_stream && !_ignore_video) { + if (si == _video_stream && !_ignore_video && (accurate || reason != PASS_REASON_SUBTITLE)) { decode_video_packet (); } else if (fc->subtitle_stream() && fc->subtitle_stream()->uses_index (_format_context, si)) { decode_subtitle_packet (); - } else { + } else if (accurate || reason != PASS_REASON_SUBTITLE) { decode_audio_packet (); } @@ -366,7 +324,7 @@ FFmpegDecoder::decode_audio_packet () } if (frame_finished) { - ContentTime const ct = ContentTime::from_seconds ( + ContentTime ct = ContentTime::from_seconds ( av_frame_get_best_effort_timestamp (_frame) * av_q2d ((*stream)->stream (_format_context)->time_base)) + _pts_offset; @@ -375,7 +333,19 @@ FFmpegDecoder::decode_audio_packet () 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); + shared_ptr data = deinterleave_audio (*stream, _frame->data, data_size); + + if (ct < ContentTime ()) { + /* Discard audio data that comes before time 0 */ + Frame const remove = min (int64_t (data->frames()), (-ct).frames_ceil(double((*stream)->frame_rate ()))); + data->move (remove, 0, data->frames() - remove); + data->set_frames (data->frames() - remove); + ct += ContentTime::from_frames (remove, (*stream)->frame_rate ()); + } + + if (data->frames() > 0) { + audio (*stream, data, ct); + } } copy_packet.data += decode_result; @@ -442,8 +412,6 @@ FFmpegDecoder::decode_subtitle_packet () indicate that the previous subtitle should stop. We can ignore it here. */ return; - } else if (sub.num_rects > 1) { - throw DecodeError (_("multi-part subtitles not yet supported")); } /* Subtitle PTS (within the source, not taking into account any of the @@ -457,23 +425,25 @@ FFmpegDecoder::decode_subtitle_packet () period.to = sub_period.to.get() + _pts_offset; } else { /* 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); + period.to = ffmpeg_content()->subtitle_stream()->find_subtitle_to (period.from); } - AVSubtitleRect const * rect = sub.rects[0]; - - switch (rect->type) { - case SUBTITLE_NONE: - break; - case SUBTITLE_BITMAP: - decode_bitmap_subtitle (rect, period); - break; - case SUBTITLE_TEXT: - cout << "XXX: SUBTITLE_TEXT " << rect->text << "\n"; - break; - case SUBTITLE_ASS: - cout << "XXX: SUBTITLE_ASS " << rect->ass << "\n"; - break; + for (unsigned int i = 0; i < sub.num_rects; ++i) { + AVSubtitleRect const * rect = sub.rects[i]; + + switch (rect->type) { + case SUBTITLE_NONE: + break; + case SUBTITLE_BITMAP: + decode_bitmap_subtitle (rect, period); + break; + case SUBTITLE_TEXT: + cout << "XXX: SUBTITLE_TEXT " << rect->text << "\n"; + break; + case SUBTITLE_ASS: + cout << "XXX: SUBTITLE_ASS " << rect->ass << "\n"; + break; + } } avsubtitle_free (&sub); @@ -497,7 +467,7 @@ FFmpegDecoder::decode_bitmap_subtitle (AVSubtitleRect const * rect, ContentTimeP /* Note RGBA is expressed little-endian, so the first byte in the word is R, second G, third B, fourth A. */ - shared_ptr image (new Image (PIX_FMT_RGBA, dcp::Size (rect->w, rect->h), true)); + shared_ptr image (new Image (AV_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];