X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Flib%2Fffmpeg_decoder.cc;h=9ae5f0485246d2f88b42432adcfcf479a1eb711a;hb=bb0a36c3a6bea9cd1ebdde7b8a3a04765e317569;hp=dc2a5590b450f2226ef55ef0ffab005022aa899c;hpb=cab9a1d569396065a6e9eb39386736908564d6b4;p=dcpomatic.git diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc index dc2a5590b..9ae5f0485 100644 --- a/src/lib/ffmpeg_decoder.cc +++ b/src/lib/ffmpeg_decoder.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2012 Carl Hetherington + Copyright (C) 2012-2014 Carl Hetherington This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -27,7 +27,6 @@ #include #include #include -#include #include extern "C" { #include @@ -57,17 +56,13 @@ using boost::optional; using boost::dynamic_pointer_cast; using dcp::Size; -FFmpegDecoder::FFmpegDecoder (shared_ptr c, shared_ptr log, bool video, bool audio, bool subtitles) +FFmpegDecoder::FFmpegDecoder (shared_ptr c, shared_ptr log) : VideoDecoder (c) , AudioDecoder (c) , FFmpeg (c) , _log (log) , _subtitle_codec_context (0) , _subtitle_codec (0) - , _decode_video (video) - , _decode_audio (audio) - , _decode_subtitles (subtitles) - , _pts_offset (0) { setup_subtitle (); @@ -83,8 +78,8 @@ FFmpegDecoder::FFmpegDecoder (shared_ptr c, shared_ptr We will do pts_to_use = pts_from_ffmpeg + pts_offset; */ - bool const have_video = video && c->first_video(); - bool const have_audio = _decode_audio && c->audio_stream () && c->audio_stream()->first_audio; + bool const have_video = c->first_video(); + bool const have_audio = c->audio_stream () && c->audio_stream()->first_audio; /* First, make one of them start at 0 */ @@ -123,11 +118,9 @@ FFmpegDecoder::flush () /* XXX: should we reset _packet.data and size after each *_decode_* call? */ - if (_decode_video) { - while (decode_video_packet ()) {} - } + while (decode_video_packet ()) {} - if (_ffmpeg_content->audio_stream() && _decode_audio) { + if (_ffmpeg_content->audio_stream()) { decode_audio_packet (); AudioDecoder::flush (); } @@ -152,11 +145,11 @@ FFmpegDecoder::pass () int const si = _packet.stream_index; - if (si == _video_stream && _decode_video) { + if (si == _video_stream) { decode_video_packet (); - } else if (_ffmpeg_content->audio_stream() && _ffmpeg_content->audio_stream()->uses_index (_format_context, si) && _decode_audio) { + } else if (_ffmpeg_content->audio_stream() && _ffmpeg_content->audio_stream()->uses_index (_format_context, si)) { decode_audio_packet (); - } else if (_ffmpeg_content->subtitle_stream() && _ffmpeg_content->subtitle_stream()->uses_index (_format_context, si) && _decode_subtitles) { + } else if (_ffmpeg_content->subtitle_stream() && _ffmpeg_content->subtitle_stream()->uses_index (_format_context, si)) { decode_subtitle_packet (); } @@ -182,6 +175,23 @@ FFmpegDecoder::deinterleave_audio (uint8_t** data, int size) shared_ptr audio (new AudioBuffers (_ffmpeg_content->audio_channels(), frames)); switch (audio_sample_format()) { + case AV_SAMPLE_FMT_U8: + { + uint8_t* p = reinterpret_cast (data[0]); + int sample = 0; + int channel = 0; + for (int i = 0; i < total_samples; ++i) { + audio->data(channel)[sample] = float(*p++) / (1 << 23); + + ++channel; + if (channel == _ffmpeg_content->audio_channels()) { + channel = 0; + ++sample; + } + } + } + break; + case AV_SAMPLE_FMT_S16: { int16_t* p = reinterpret_cast (data[0]); @@ -302,9 +312,9 @@ FFmpegDecoder::minimal_run (boost::function, optiona avcodec_get_frame_defaults (_frame); - int finished = 0; - r = avcodec_decode_video2 (video_codec_context(), _frame, &finished, &_packet); - if (r >= 0 && finished) { + int got_picture = 0; + r = avcodec_decode_video2 (video_codec_context(), _frame, &got_picture, &_packet); + if (r >= 0 && got_picture) { last_video = ContentTime::from_seconds (av_frame_get_best_effort_timestamp (_frame) * time_base) + _pts_offset; } @@ -312,9 +322,9 @@ FFmpegDecoder::minimal_run (boost::function, optiona AVPacket copy_packet = _packet; while (copy_packet.size > 0) { - int finished; - r = avcodec_decode_audio4 (audio_codec_context(), _frame, &finished, &_packet); - if (r >= 0 && finished) { + int got_frame; + r = avcodec_decode_audio4 (audio_codec_context(), _frame, &got_frame, &_packet); + if (r >= 0 && got_frame) { last_audio = ContentTime::from_seconds (av_frame_get_best_effort_timestamp (_frame) * time_base) + _pts_offset; } @@ -373,17 +383,15 @@ FFmpegDecoder::seek_and_flush (ContentTime t) void FFmpegDecoder::seek (ContentTime time, bool accurate) { - Decoder::seek (time, accurate); - if (_decode_audio) { - AudioDecoder::seek (time, accurate); - } + VideoDecoder::seek (time, accurate); + AudioDecoder::seek (time, accurate); - /* If we are doing an accurate seek, our initial shot will be 200ms (200 being + /* If we are doing an accurate seek, our initial shot will be 2s (2 being a number plucked from the air) earlier than we want to end up. The loop below will hopefully then step through to where we want to be. */ - ContentTime pre_roll = accurate ? ContentTime::from_seconds (0.2) : ContentTime (0); + ContentTime pre_roll = accurate ? ContentTime::from_seconds (2) : ContentTime (0); ContentTime initial_seek = time - pre_roll; if (initial_seek < ContentTime (0)) { initial_seek = ContentTime (0); @@ -470,17 +478,13 @@ FFmpegDecoder::decode_video_packet () list, int64_t> > images = graph->process (_frame); - string post_process = Filter::ffmpeg_strings (_ffmpeg_content->filters()).second; - for (list, int64_t> >::iterator i = images.begin(); i != images.end(); ++i) { shared_ptr image = i->first; - if (!post_process.empty ()) { - image = image->post_process (post_process, true); - } if (i->second != AV_NOPTS_VALUE) { - video (image, false, ContentTime::from_seconds (i->second * av_q2d (_format_context->streams[_video_stream]->time_base)) + _pts_offset); + double const pts = i->second * av_q2d (_format_context->streams[_video_stream]->time_base) + _pts_offset.seconds (); + video (image, rint (pts * _ffmpeg_content->video_frame_rate ())); } else { _log->log ("Dropping frame without PTS"); } @@ -528,7 +532,7 @@ FFmpegDecoder::decode_subtitle_packet () indicate that the previous subtitle should stop. */ if (sub.num_rects <= 0) { - image_subtitle (shared_ptr (), dcpomatic::Rect (), ContentTime (), ContentTime ()); + image_subtitle (ContentTime (), ContentTime (), shared_ptr (), dcpomatic::Rect ()); return; } else if (sub.num_rects > 1) { throw DecodeError (_("multi-part subtitles not yet supported")); @@ -546,7 +550,9 @@ FFmpegDecoder::decode_subtitle_packet () AVSubtitleRect const * rect = sub.rects[0]; if (rect->type != SUBTITLE_BITMAP) { - throw DecodeError (_("non-bitmap subtitles not yet supported")); + /* XXX */ + // throw DecodeError (_("non-bitmap subtitles not yet supported")); + return; } /* Note RGBA is expressed little-endian, so the first byte in the word is R, second @@ -577,17 +583,16 @@ FFmpegDecoder::decode_subtitle_packet () dcp::Size const vs = _ffmpeg_content->video_size (); image_subtitle ( + from, + to, image, dcpomatic::Rect ( static_cast (rect->x) / vs.width, static_cast (rect->y) / vs.height, static_cast (rect->w) / vs.width, static_cast (rect->h) / vs.height - ), - from, - to + ) ); - avsubtitle_free (&sub); }