X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Flib%2Fffmpeg_image_proxy.cc;h=00d2a6a59515a60519a6a0e12854016ddaea0ab4;hb=130b03ddabdd5abd5052651aae86ad1955e39ad3;hp=7b23221011474a246675977f9f7b260b29199484;hpb=1516214cdc7970797b79bca06b46a2eed16a1da3;p=dcpomatic.git diff --git a/src/lib/ffmpeg_image_proxy.cc b/src/lib/ffmpeg_image_proxy.cc index 7b2322101..00d2a6a59 100644 --- a/src/lib/ffmpeg_image_proxy.cc +++ b/src/lib/ffmpeg_image_proxy.cc @@ -21,21 +21,23 @@ #include "compose.hpp" #include "cross.h" +#include "dcpomatic_assert.h" #include "dcpomatic_socket.h" #include "exceptions.h" #include "ffmpeg_image_proxy.h" #include "image.h" -#include "util.h" -#include "warnings.h" +#include "memory_util.h" +#include "video_filter_graph.h" #include +#include +LIBDCP_DISABLE_WARNINGS extern "C" { #include #include #include } -DCPOMATIC_DISABLE_WARNINGS #include -DCPOMATIC_ENABLE_WARNINGS +LIBDCP_ENABLE_WARNINGS #include #include "i18n.h" @@ -53,26 +55,23 @@ using std::dynamic_pointer_cast; using dcp::raw_convert; -FFmpegImageProxy::FFmpegImageProxy (boost::filesystem::path path, VideoRange video_range) +FFmpegImageProxy::FFmpegImageProxy (boost::filesystem::path path) : _data (path) - , _video_range (video_range) , _pos (0) , _path (path) { } -FFmpegImageProxy::FFmpegImageProxy (dcp::ArrayData data, VideoRange video_range) +FFmpegImageProxy::FFmpegImageProxy (dcp::ArrayData data) : _data (data) - , _video_range (video_range) , _pos (0) { } -FFmpegImageProxy::FFmpegImageProxy (shared_ptr node, shared_ptr socket) - : _video_range (string_to_video_range(node->string_child("VideoRange"))) - , _pos (0) +FFmpegImageProxy::FFmpegImageProxy (shared_ptr socket) + : _pos (0) { uint32_t const size = socket->read_uint32 (); _data = dcp::ArrayData (size); @@ -125,7 +124,7 @@ FFmpegImageProxy::avio_seek (int64_t const pos, int whence) ImageProxy::Result -FFmpegImageProxy::image (optional) const +FFmpegImageProxy::image (Image::Alignment alignment, optional) const { auto constexpr name_for_errors = "FFmpegImageProxy::image"; @@ -136,11 +135,11 @@ FFmpegImageProxy::image (optional) const } uint8_t* avio_buffer = static_cast (wrapped_av_malloc(4096)); - AVIOContext* avio_context = avio_alloc_context (avio_buffer, 4096, 0, const_cast(this), avio_read_wrapper, 0, avio_seek_wrapper); + auto avio_context = avio_alloc_context (avio_buffer, 4096, 0, const_cast(this), avio_read_wrapper, 0, avio_seek_wrapper); AVFormatContext* format_context = avformat_alloc_context (); format_context->pb = avio_context; - AVDictionary* options = 0; + AVDictionary* options = nullptr; /* These durations are in microseconds, and represent how far into the content file we will look for streams. */ @@ -153,7 +152,7 @@ FFmpegImageProxy::image (optional) const directly from the file). This code just does enough to allow the probe code to take a hint from "foo.tga" and so try targa format. */ - AVInputFormat* f = av_find_input_format ("image2"); + auto f = av_find_input_format ("image2"); format_context = avformat_alloc_context (); format_context->pb = avio_context; format_context->iformat = f; @@ -169,12 +168,18 @@ FFmpegImageProxy::image (optional) const int r = avformat_find_stream_info(format_context, 0); if (r < 0) { - throw DecodeError (N_("avcodec_find_stream_info"), name_for_errors, r); + throw DecodeError (N_("avcodec_find_stream_info"), name_for_errors, r, *_path); } - DCPOMATIC_ASSERT (format_context->nb_streams == 1); + if (format_context->nb_streams != 1) { + if (_path) { + throw DecodeError("FFmpegProxy::image", String::compose("stream count %1", format_context->nb_streams), *_path); + } else { + throw DecodeError("FFmpegProxy::image", String::compose("stream count %1", format_context->nb_streams)); + } + } - AVFrame* frame = av_frame_alloc (); + auto frame = av_frame_alloc (); if (!frame) { std::bad_alloc (); } @@ -184,39 +189,43 @@ FFmpegImageProxy::image (optional) const auto context = avcodec_alloc_context3 (codec); if (!context) { - throw DecodeError (N_("avcodec_alloc_context3"), name_for_errors); + throw DecodeError (N_("avcodec_alloc_context3"), name_for_errors, *_path); } r = avcodec_open2 (context, codec, 0); if (r < 0) { - throw DecodeError (N_("avcodec_open2"), name_for_errors, r); + throw DecodeError (N_("avcodec_open2"), name_for_errors, r, *_path); } AVPacket packet; r = av_read_frame (format_context, &packet); if (r < 0) { - throw DecodeError (N_("av_read_frame"), name_for_errors, r); + throw DecodeError (N_("av_read_frame"), name_for_errors, r, *_path); } r = avcodec_send_packet (context, &packet); if (r < 0) { - throw DecodeError (N_("avcodec_send_packet"), name_for_errors, r); + throw DecodeError (N_("avcodec_send_packet"), name_for_errors, r, *_path); } r = avcodec_receive_frame (context, frame); if (r < 0) { - throw DecodeError (N_("avcodec_receive_frame"), name_for_errors, r); + throw DecodeError (N_("avcodec_receive_frame"), name_for_errors, r, *_path); } - auto const pix_fmt = static_cast(frame->format); - - _image = make_shared(frame); - if (_video_range == VideoRange::VIDEO && av_pix_fmt_desc_get(pix_fmt)->flags & AV_PIX_FMT_FLAG_RGB) { - /* Asking for the video range to be converted by libswscale (in Image) will not work for - * RGB sources since that method only processes video range in YUV and greyscale. So we have - * to do it ourselves here. + if (av_pix_fmt_desc_get(context->pix_fmt)->flags & AV_PIX_FMT_FLAG_ALPHA) { + /* XXX: this repeated setup of a the filter graph could be really slow + * (haven't measured it though). */ - _image->video_range_to_full_range(); + VideoFilterGraph graph(dcp::Size(frame->width, frame->height), context->pix_fmt, dcp::Fraction(24, 1)); + auto filter = Filter::from_id("premultiply"); + DCPOMATIC_ASSERT(filter); + graph.setup({*filter}); + auto images = graph.process(frame); + DCPOMATIC_ASSERT(images.size() == 1); + _image = images.front().first; + } else { + _image = make_shared(frame, alignment); } av_packet_unref (&packet); @@ -234,7 +243,6 @@ void FFmpegImageProxy::add_metadata (xmlpp::Node* node) const { node->add_child("Type")->add_child_text (N_("FFmpeg")); - node->add_child("VideoRange")->add_child_text(video_range_to_string(_video_range)); } void @@ -247,7 +255,7 @@ FFmpegImageProxy::write_to_socket (shared_ptr socket) const bool FFmpegImageProxy::same (shared_ptr other) const { - shared_ptr mp = dynamic_pointer_cast (other); + auto mp = dynamic_pointer_cast(other); if (!mp) { return false; }