X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Flib%2Fdecoder.cc;h=045c1b818270052d58a93249377a7e2a6f5c6e27;hb=44b57d623dec97a3f9955082f0b8a7a8d27b7518;hp=6bebe800c753b615e4a486769746979b4031fa69;hpb=f0488edf2b3bc2874deb077879523becba7d0d10;p=dcpomatic.git diff --git a/src/lib/decoder.cc b/src/lib/decoder.cc index 6bebe800c..045c1b818 100644 --- a/src/lib/decoder.cc +++ b/src/lib/decoder.cc @@ -23,16 +23,18 @@ #include #include +#include extern "C" { #include #include -#ifndef DVDOMATIC_FFMPEG_0_8_3 +#if (LIBAVFILTER_VERSION_MAJOR == 2 && LIBAVFILTER_VERSION_MINOR >= 53 && LIBAVFILTER_VERSION_MINOR <= 77) || LIBAVFILTER_VERSION_MAJOR == 3 #include #include +#elif LIBAVFILTER_VERSION_MAJOR == 2 && LIBAVFILTER_VERSION_MINOR == 15 +#include #endif #include } -#include #include "film.h" #include "format.h" #include "job.h" @@ -46,6 +48,7 @@ extern "C" { #include "filter.h" #include "delay_line.h" #include "ffmpeg_compatibility.h" +#include "subtitle.h" using namespace std; using namespace boost; @@ -68,13 +71,12 @@ Decoder::Decoder (boost::shared_ptr s, boost::shared_ptrdecode_video_frequency != 0 && _fs->length == 0) { + if (_opt->decode_video_frequency != 0 && _fs->length() == 0) { throw DecodeError ("cannot do a partial decode if length == 0"); } } @@ -84,88 +86,62 @@ Decoder::~Decoder () delete _delay_line; } +/** Start off a decode processing run */ void Decoder::process_begin () { - if (_fs->audio_sample_rate != dcp_audio_sample_rate (_fs->audio_sample_rate)) { - _swr_context = swr_alloc_set_opts ( - 0, - audio_channel_layout(), - audio_sample_format(), - dcp_audio_sample_rate (_fs->audio_sample_rate), - audio_channel_layout(), - audio_sample_format(), - _fs->audio_sample_rate, - 0, 0 - ); - - swr_init (_swr_context); - } else { - _swr_context = 0; - } - - _delay_in_bytes = _fs->audio_delay * _fs->audio_sample_rate * _fs->audio_channels * _fs->bytes_per_sample() / 1000; + _delay_in_bytes = _fs->audio_delay() * _fs->audio_sample_rate() * _fs->audio_channels() * bytes_per_audio_sample() / 1000; delete _delay_line; _delay_line = new DelayLine (_delay_in_bytes); _audio_frames_processed = 0; } +/** Finish off a decode processing run */ void Decoder::process_end () { - if (_swr_context) { - - int mop = 0; - while (1) { - uint8_t buffer[256 * _fs->bytes_per_sample() * _fs->audio_channels]; - uint8_t* out[1] = { - buffer - }; - - int const frames = swr_convert (_swr_context, out, 256, 0, 0); - - if (frames < 0) { - throw DecodeError ("could not run sample-rate converter"); - } - - if (frames == 0) { - break; - } - - mop += frames; - int available = _delay_line->feed (buffer, frames * _fs->audio_channels * _fs->bytes_per_sample()); - Audio (buffer, available); - } - - cout << "mopped up " << mop << "\n"; - - swr_free (&_swr_context); - } - if (_delay_in_bytes < 0) { uint8_t remainder[-_delay_in_bytes]; _delay_line->get_remaining (remainder); - _audio_frames_processed += _delay_in_bytes / (audio_channels() * _fs->bytes_per_sample()); - Audio (remainder, _delay_in_bytes); + _audio_frames_processed += _delay_in_bytes / (_fs->audio_channels() * bytes_per_audio_sample()); + emit_audio (remainder, -_delay_in_bytes); } /* If we cut the decode off, the audio may be short; push some silence in to get it to the right length. */ - int const audio_short_by_frames = (decoding_frames() * dcp_audio_sample_rate (_fs->audio_sample_rate) / _fs->frames_per_second) - _audio_frames_processed; + int64_t const video_length_in_audio_frames = ((int64_t) _fs->dcp_length() * _fs->audio_sample_rate() / _fs->frames_per_second()); + int64_t const audio_short_by_frames = video_length_in_audio_frames - _audio_frames_processed; + + _log->log ( + String::compose ("DCP length is %1 (%2 audio frames); %3 frames of audio processed.", + _fs->dcp_length(), + video_length_in_audio_frames, + _audio_frames_processed) + ); + + if (audio_short_by_frames >= 0 && _opt->decode_audio) { - int bytes = audio_short_by_frames * audio_channels() * _fs->bytes_per_sample(); + _log->log (String::compose ("DCP length is %1; %2 frames of audio processed.", _fs->dcp_length(), _audio_frames_processed)); + _log->log (String::compose ("Adding %1 frames of silence to the end.", audio_short_by_frames)); - int const silence_size = 64 * 1024; - uint8_t silence[silence_size]; - memset (silence, 0, silence_size); + /* XXX: this is slightly questionable; does memset () give silence with all + sample formats? + */ - while (bytes) { - int const t = min (bytes, silence_size); - Audio (silence, t); - bytes -= t; + int64_t bytes = audio_short_by_frames * _fs->audio_channels() * bytes_per_audio_sample(); + + int64_t const silence_size = 16 * 1024 * _fs->audio_channels() * bytes_per_audio_sample(); + uint8_t silence[silence_size]; + memset (silence, 0, silence_size); + + while (bytes) { + int64_t const t = min (bytes, silence_size); + emit_audio (silence, t); + bytes -= t; + } } } @@ -181,24 +157,13 @@ Decoder::go () while (pass () == false) { if (_job && !_ignore_length) { - _job->set_progress (float (_video_frame) / decoding_frames ()); + _job->set_progress (float (_video_frame) / _fs->dcp_length()); } } process_end (); } -/** @return Number of frames that we will be decoding */ -int -Decoder::decoding_frames () const -{ - if (_opt->num_frames > 0) { - return _opt->num_frames; - } - - return _fs->length; -} - /** Run one pass. This may or may not generate any actual video / audio data; * some decoders may require several passes to generate a single frame. * @return true if we have finished processing all data; otherwise false. @@ -211,75 +176,99 @@ Decoder::pass () _have_setup_video_filters = true; } - if (_opt->num_frames != 0 && _video_frame >= _opt->num_frames) { + if (!_ignore_length && _video_frame >= _fs->dcp_length()) { return true; } return do_pass (); } -/** Called by subclasses to tell the world that some audio data is ready */ +/** Called by subclasses to tell the world that some audio data is ready + * @param data Audio data, in FilmState::audio_sample_format. + * @param size Number of bytes of data. + */ void Decoder::process_audio (uint8_t* data, int size) { - int const samples = size / _fs->bytes_per_sample(); - int const frames = samples / _fs->audio_channels; - - if (_fs->audio_gain != 0) { - float const linear_gain = pow (10, _fs->audio_gain / 20); - uint8_t* p = data; - switch (_fs->audio_sample_format) { - case AV_SAMPLE_FMT_S16: - for (int i = 0; i < samples; ++i) { - /* XXX: assumes little-endian; also we should probably be dithering here */ - int const ou = p[0] | (p[1] << 8); - int const os = ou >= 0x8000 ? (- 0x10000 + ou) : ou; - int const gs = int (os * linear_gain); - int const gu = gs > 0 ? gs : (0x10000 + gs); - p[0] = gu & 0xff; - p[1] = (gu & 0xff00) >> 8; - p += 2; + /* Push into the delay line */ + size = _delay_line->feed (data, size); + + emit_audio (data, size); +} + +void +Decoder::emit_audio (uint8_t* data, int size) +{ + /* Deinterleave and convert to float */ + + assert ((size % (bytes_per_audio_sample() * _fs->audio_channels())) == 0); + + int const total_samples = size / bytes_per_audio_sample(); + int const frames = total_samples / _fs->audio_channels(); + shared_ptr audio (new AudioBuffers (_fs->audio_channels(), frames)); + + switch (audio_sample_format()) { + case AV_SAMPLE_FMT_S16: + { + int16_t* p = (int16_t *) data; + int sample = 0; + int channel = 0; + for (int i = 0; i < total_samples; ++i) { + audio->data(channel)[sample] = float(*p++) / (1 << 15); + + ++channel; + if (channel == _fs->audio_channels()) { + channel = 0; + ++sample; + } + } + } + break; + + case AV_SAMPLE_FMT_S32: + { + int32_t* p = (int32_t *) data; + int sample = 0; + int channel = 0; + for (int i = 0; i < total_samples; ++i) { + audio->data(channel)[sample] = float(*p++) / (1 << 31); + + ++channel; + if (channel == _fs->audio_channels()) { + channel = 0; + ++sample; } - break; - default: - assert (false); } } - uint8_t* out_buffer = 0; - - if (_swr_context) { - - uint8_t const * in[2] = { - data, - 0 - }; + case AV_SAMPLE_FMT_FLTP: + { + float* p = reinterpret_cast (data); + for (int i = 0; i < _fs->audio_channels(); ++i) { + memcpy (audio->data(i), p, frames * sizeof(float)); + p += frames; + } + } + break; - int const out_buffer_size_frames = ceil (frames * float (dcp_audio_sample_rate (_fs->audio_sample_rate)) / _fs->audio_sample_rate) + 32; - int const out_buffer_size_bytes = out_buffer_size_frames * _fs->audio_channels * _fs->bytes_per_sample(); - out_buffer = new uint8_t[out_buffer_size_bytes]; + default: + assert (false); + } - uint8_t* out[2] = { - out_buffer, - 0 - }; - - int out_frames = swr_convert (_swr_context, out, out_buffer_size_frames, in, frames); - if (out_frames < 0) { - throw DecodeError ("could not run sample-rate converter"); + /* Maybe apply gain */ + if (_fs->audio_gain() != 0) { + float const linear_gain = pow (10, _fs->audio_gain() / 20); + for (int i = 0; i < _fs->audio_channels(); ++i) { + for (int j = 0; j < frames; ++j) { + audio->data(i)[j] *= linear_gain; + } } - - data = out_buffer; - size = out_frames * _fs->audio_channels * _fs->bytes_per_sample(); } - + /* Update the number of audio frames we've pushed to the encoder */ - _audio_frames_processed += size / (_fs->audio_channels * _fs->bytes_per_sample ()); - - int available = _delay_line->feed (data, size); - Audio (data, available); + _audio_frames_processed += audio->frames (); - delete[] out_buffer; + Audio (audio); } /** Called by subclasses to tell the world that some video data is ready. @@ -298,7 +287,7 @@ Decoder::process_video (AVFrame* frame) int gap = 0; if (_opt->decode_video_frequency != 0) { - gap = _fs->length / _opt->decode_video_frequency; + gap = _fs->length() / _opt->decode_video_frequency; } if (_opt->decode_video_frequency != 0 && gap != 0 && (_video_frame % gap) != 0) { @@ -306,8 +295,14 @@ Decoder::process_video (AVFrame* frame) return; } -#ifdef DVDOMATIC_FFMPEG_0_8_3 - +#if LIBAVFILTER_VERSION_MAJOR == 2 && LIBAVFILTER_VERSION_MINOR >= 53 && LIBAVFILTER_VERSION_MINOR <= 61 + + if (av_vsrc_buffer_add_frame (_buffer_src_context, frame, 0) < 0) { + throw DecodeError ("could not push buffer into filter chain."); + } + +#elif LIBAVFILTER_VERSION_MAJOR == 2 && LIBAVFILTER_VERSION_MINOR == 15 + AVRational par; par.num = sample_aspect_ratio_numerator (); par.den = sample_aspect_ratio_denominator (); @@ -324,13 +319,13 @@ Decoder::process_video (AVFrame* frame) #endif -#ifdef DVDOMATIC_FFMPEG_0_8_3 +#if LIBAVFILTER_VERSION_MAJOR == 2 && LIBAVFILTER_VERSION_MINOR >= 15 && LIBAVFILTER_VERSION_MINOR <= 61 while (avfilter_poll_frame (_buffer_sink_context->inputs[0])) { #else while (av_buffersink_read (_buffer_sink_context, 0)) { #endif -#ifdef DVDOMATIC_FFMPEG_0_8_3 +#if LIBAVFILTER_VERSION_MAJOR == 2 && LIBAVFILTER_VERSION_MINOR >= 15 int r = avfilter_request_frame (_buffer_sink_context->inputs[0]); if (r < 0) { @@ -356,12 +351,22 @@ Decoder::process_video (AVFrame* frame) image->make_black (); } - Video (image, _video_frame); + shared_ptr sub; + if (_timed_subtitle && _timed_subtitle->displayed_at (double (last_video_frame()) / _fs->frames_per_second())) { + sub = _timed_subtitle->subtitle (); + } + + TIMING ("Decoder emits %1", _video_frame); + Video (image, _video_frame, sub); ++_video_frame; } } } + +/** Set up a video filtering chain to include cropping and any filters that are specified + * by the Film. + */ void Decoder::setup_video_filters () { @@ -370,13 +375,13 @@ Decoder::setup_video_filters () if (_opt->apply_crop) { size_after_crop = _fs->cropped_size (native_size ()); - fs << crop_string (Position (_fs->left_crop, _fs->top_crop), size_after_crop); + fs << crop_string (Position (_fs->crop().left, _fs->crop().top), size_after_crop); } else { size_after_crop = native_size (); fs << crop_string (Position (0, 0), size_after_crop); } - string filters = Filter::ffmpeg_strings (_fs->filters).first; + string filters = Filter::ffmpeg_strings (_fs->filters()).first; if (!filters.empty ()) { filters += ","; } @@ -407,12 +412,18 @@ Decoder::setup_video_filters () << sample_aspect_ratio_denominator(); int r; + if ((r = avfilter_graph_create_filter (&_buffer_src_context, buffer_src, "in", a.str().c_str(), 0, graph)) < 0) { throw DecodeError ("could not create buffer source"); } - enum PixelFormat pixel_formats[] = { pixel_format(), PIX_FMT_NONE }; - if (avfilter_graph_create_filter (&_buffer_sink_context, buffer_sink, "out", 0, pixel_formats, graph) < 0) { + AVBufferSinkParams* sink_params = av_buffersink_params_alloc (); + PixelFormat* pixel_fmts = new PixelFormat[2]; + pixel_fmts[0] = pixel_format (); + pixel_fmts[1] = PIX_FMT_NONE; + sink_params->pixel_fmts = pixel_fmts; + + if (avfilter_graph_create_filter (&_buffer_sink_context, buffer_sink, "out", 0, sink_params, graph) < 0) { throw DecodeError ("could not create buffer sink."); } @@ -429,15 +440,17 @@ Decoder::setup_video_filters () inputs->next = 0; _log->log ("Using filter chain `" + filters + "'"); -#ifdef DVDOMATIC_FFMPEG_0_8_3 + +#if LIBAVFILTER_VERSION_MAJOR == 2 && LIBAVFILTER_VERSION_MINOR == 15 if (avfilter_graph_parse (graph, filters.c_str(), inputs, outputs, 0) < 0) { -#else + throw DecodeError ("could not set up filter graph."); + } +#else if (avfilter_graph_parse (graph, filters.c_str(), &inputs, &outputs, 0) < 0) { -#endif - throw DecodeError ("could not set up filter graph."); } - +#endif + if (avfilter_graph_config (graph, 0) < 0) { throw DecodeError ("could not configure filter graph."); } @@ -445,3 +458,20 @@ Decoder::setup_video_filters () /* XXX: leaking `inputs' / `outputs' ? */ } +void +Decoder::process_subtitle (shared_ptr s) +{ + _timed_subtitle = s; + + if (_timed_subtitle && _opt->apply_crop) { + Position const p = _timed_subtitle->subtitle()->position (); + _timed_subtitle->subtitle()->set_position (Position (p.x - _fs->crop().left, p.y - _fs->crop().top)); + } +} + + +int +Decoder::bytes_per_audio_sample () const +{ + return av_get_bytes_per_sample (audio_sample_format ()); +}