X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;ds=sidebyside;f=src%2Flib%2Fffmpeg_encoder.cc;h=71063c12371d3c4765e42c5120089bca1b051af7;hb=ec97893127a2d59871d92c9e658b6b1ab3100b40;hp=5d06616ee79e9122a14efc8e76ad9bc4c6de34dd;hpb=3458d0ec34f08a8eeef9b158f26a476a18548353;p=dcpomatic.git diff --git a/src/lib/ffmpeg_encoder.cc b/src/lib/ffmpeg_encoder.cc index 5d06616ee..71063c123 100644 --- a/src/lib/ffmpeg_encoder.cc +++ b/src/lib/ffmpeg_encoder.cc @@ -26,6 +26,7 @@ #include "log.h" #include "image.h" #include "cross.h" +#include "butler.h" #include "compose.hpp" #include @@ -34,6 +35,7 @@ using std::string; using std::runtime_error; using std::cout; +using std::pair; using boost::shared_ptr; using boost::bind; using boost::weak_ptr; @@ -70,29 +72,34 @@ FFmpegEncoder::FFmpegEncoder (shared_ptr film, weak_ptr job, bo break; } - _player->set_always_burn_subtitles (true); + _player->set_always_burn_open_subtitles (); _player->set_play_referenced (); int const ch = film->audio_channels (); + AudioMapping map; if (mixdown_to_stereo) { - _audio_mapping = AudioMapping (ch, 2); + _output_audio_channels = 2; + map = AudioMapping (ch, 2); float const overall_gain = 2 / (4 + sqrt(2)); float const minus_3dB = 1 / sqrt(2); - _audio_mapping.set (dcp::LEFT, 0, overall_gain); - _audio_mapping.set (dcp::RIGHT, 1, overall_gain); - _audio_mapping.set (dcp::CENTRE, 0, overall_gain * minus_3dB); - _audio_mapping.set (dcp::CENTRE, 1, overall_gain * minus_3dB); - _audio_mapping.set (dcp::LS, 0, overall_gain); - _audio_mapping.set (dcp::RS, 0, overall_gain); + map.set (dcp::LEFT, 0, overall_gain); + map.set (dcp::RIGHT, 1, overall_gain); + map.set (dcp::CENTRE, 0, overall_gain * minus_3dB); + map.set (dcp::CENTRE, 1, overall_gain * minus_3dB); + map.set (dcp::LS, 0, overall_gain); + map.set (dcp::RS, 1, overall_gain); _pending_audio.reset (new AudioBuffers (2, 0)); } else { - _audio_mapping = AudioMapping (ch, ch); + _output_audio_channels = ch; + map = AudioMapping (ch, ch); _pending_audio.reset (new AudioBuffers (ch, 0)); for (int i = 0; i < ch; ++i) { - _audio_mapping.set (i, i, 1); + map.set (i, i, 1); } } + + _butler.reset (new Butler (_player, film->log(), map, _output_audio_channels)); } void @@ -116,7 +123,7 @@ FFmpegEncoder::setup_video () _video_codec_context->height = _film->frame_size().height; _video_codec_context->time_base = (AVRational) { 1, _film->video_frame_rate() }; _video_codec_context->pix_fmt = _pixel_format; - _video_codec_context->flags |= CODEC_FLAG_QSCALE | CODEC_FLAG_GLOBAL_HEADER; + _video_codec_context->flags |= AV_CODEC_FLAG_QSCALE | AV_CODEC_FLAG_GLOBAL_HEADER; } void @@ -138,8 +145,8 @@ FFmpegEncoder::setup_audio () _audio_codec_context->bit_rate = 256 * 1024; _audio_codec_context->sample_fmt = _sample_format; _audio_codec_context->sample_rate = _film->audio_frame_rate (); - _audio_codec_context->channel_layout = av_get_default_channel_layout (_audio_mapping.output_channels ()); - _audio_codec_context->channels = _audio_mapping.output_channels (); + _audio_codec_context->channel_layout = av_get_default_channel_layout (_output_audio_channels); + _audio_codec_context->channels = _output_audio_channels; } void @@ -194,7 +201,24 @@ FFmpegEncoder::go () job->sub (_("Encoding")); } - while (!_player->pass ()) {} + DCPTime const video_frame = DCPTime::from_frames (1, _film->video_frame_rate ()); + int const audio_frames = video_frame.frames_round(_film->audio_frame_rate()); + float* interleaved = new float[_output_audio_channels * audio_frames]; + shared_ptr deinterleaved (new AudioBuffers (_output_audio_channels, audio_frames)); + for (DCPTime i; i < _film->length(); i += video_frame) { + pair, DCPTime> v = _butler->get_video (); + video (v.first, v.second); + _butler->get_audio (interleaved, audio_frames); + /* XXX: inefficient; butler interleaves and we deinterleave again */ + float* p = interleaved; + for (int j = 0; j < audio_frames; ++j) { + for (int k = 0; k < _output_audio_channels; ++k) { + deinterleaved->data(k)[j] = *p++; + } + } + audio (deinterleaved); + } + delete[] interleaved; if (_pending_audio->frames() > 0) { audio_frame (_pending_audio->frames ()); @@ -256,12 +280,9 @@ FFmpegEncoder::video (shared_ptr video, DCPTime time) AVFrame* frame = av_frame_alloc (); DCPOMATIC_ASSERT (frame); + _pending_images[image->data()[0]] = image; for (int i = 0; i < 3; ++i) { - size_t const size = image->stride()[i] * image->sample_size(i).height; - AVBufferRef* buffer = av_buffer_alloc (size); - DCPOMATIC_ASSERT (buffer); - /* XXX: inefficient */ - memcpy (buffer->data, image->data()[i], size); + AVBufferRef* buffer = av_buffer_create(image->data()[i], image->stride()[i] * image->size().height, &buffer_free, this, 0); frame->buf[i] = av_buffer_ref (buffer); frame->data[i] = buffer->data; frame->linesize[i] = image->stride()[i]; @@ -306,14 +327,14 @@ FFmpegEncoder::video (shared_ptr video, DCPTime time) /** Called when the player gives us some audio */ void -FFmpegEncoder::audio (shared_ptr audio, DCPTime) +FFmpegEncoder::audio (shared_ptr audio) { - _pending_audio->append (remap (audio, _audio_mapping.output_channels(), _audio_mapping)); + _pending_audio->append (audio); int frame_size = _audio_codec_context->frame_size; if (frame_size == 0) { /* codec has AV_CODEC_CAP_VARIABLE_FRAME_SIZE */ - frame_size = 2000; + frame_size = _film->audio_frame_rate() / _film->video_frame_rate(); } while (_pending_audio->frames() >= frame_size) { @@ -390,7 +411,7 @@ FFmpegEncoder::audio_frame (int size) } void -FFmpegEncoder::subtitle (PlayerSubtitles, DCPTimePeriod) +FFmpegEncoder::subtitle (PlayerText, DCPTimePeriod) { } @@ -407,3 +428,15 @@ FFmpegEncoder::frames_done () const boost::mutex::scoped_lock lm (_mutex); return _last_time.frames_round (_film->video_frame_rate ()); } + +void +FFmpegEncoder::buffer_free (void* opaque, uint8_t* data) +{ + reinterpret_cast(opaque)->buffer_free2(data); +} + +void +FFmpegEncoder::buffer_free2 (uint8_t* data) +{ + _pending_images.erase (data); +}