diff options
| author | Carl Hetherington <cth@carlh.net> | 2021-09-15 23:36:21 +0200 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2021-09-27 13:41:46 +0200 |
| commit | 3799e91d126d243d41c44dcb0ca1bfa66b53a57e (patch) | |
| tree | 74348b18d5ac0ef81bbebb27fe32862b22baa0b2 /src/lib | |
| parent | 9bfa07293928c371d59db2091ba2b7e715ce5994 (diff) | |
Replace aligned bool with enum Alignment.
Diffstat (limited to 'src/lib')
| -rw-r--r-- | src/lib/butler.cc | 8 | ||||
| -rw-r--r-- | src/lib/butler.h | 4 | ||||
| -rw-r--r-- | src/lib/dcp_video.cc | 6 | ||||
| -rw-r--r-- | src/lib/encoder.cc | 2 | ||||
| -rw-r--r-- | src/lib/ffmpeg_decoder.cc | 56 | ||||
| -rw-r--r-- | src/lib/ffmpeg_encoder.cc | 16 | ||||
| -rw-r--r-- | src/lib/ffmpeg_file_encoder.cc | 14 | ||||
| -rw-r--r-- | src/lib/ffmpeg_image_proxy.cc | 4 | ||||
| -rw-r--r-- | src/lib/ffmpeg_image_proxy.h | 2 | ||||
| -rw-r--r-- | src/lib/hints.cc | 5 | ||||
| -rw-r--r-- | src/lib/image.cc | 73 | ||||
| -rw-r--r-- | src/lib/image.h | 25 | ||||
| -rw-r--r-- | src/lib/image_examiner.cc | 2 | ||||
| -rw-r--r-- | src/lib/image_proxy.h | 14 | ||||
| -rw-r--r-- | src/lib/j2k_image_proxy.cc | 12 | ||||
| -rw-r--r-- | src/lib/j2k_image_proxy.h | 4 | ||||
| -rw-r--r-- | src/lib/player.cc | 10 | ||||
| -rw-r--r-- | src/lib/player.h | 7 | ||||
| -rw-r--r-- | src/lib/player_video.cc | 24 | ||||
| -rw-r--r-- | src/lib/player_video.h | 13 | ||||
| -rw-r--r-- | src/lib/raw_image_proxy.cc | 10 | ||||
| -rw-r--r-- | src/lib/raw_image_proxy.h | 2 | ||||
| -rw-r--r-- | src/lib/render_text.cc | 2 | ||||
| -rw-r--r-- | src/lib/util.cc | 63 | ||||
| -rw-r--r-- | src/lib/video_filter_graph.cc | 5 |
25 files changed, 194 insertions, 189 deletions
diff --git a/src/lib/butler.cc b/src/lib/butler.cc index ca0887a4c..5a5cc4912 100644 --- a/src/lib/butler.cc +++ b/src/lib/butler.cc @@ -57,7 +57,7 @@ using namespace boost::placeholders; /** @param pixel_format Pixel format functor that will be used when calling ::image on PlayerVideos coming out of this * butler. This will be used (where possible) to prepare the PlayerVideos so that calling image() on them is quick. - * @param aligned Same as above for the `aligned' flag. + * @param alignment Same as above for the `alignment' value. * @param fast Same as above for the `fast' flag. */ Butler::Butler ( @@ -67,7 +67,7 @@ Butler::Butler ( int audio_channels, function<AVPixelFormat (AVPixelFormat)> pixel_format, VideoRange video_range, - bool aligned, + Image::Alignment alignment, bool fast, bool prepare_only_proxy ) @@ -84,7 +84,7 @@ Butler::Butler ( , _disable_audio (false) , _pixel_format (pixel_format) , _video_range (video_range) - , _aligned (aligned) + , _alignment (alignment) , _fast (fast) , _prepare_only_proxy (prepare_only_proxy) { @@ -325,7 +325,7 @@ try /* If the weak_ptr cannot be locked the video obviously no longer requires any work */ if (video) { LOG_TIMING("start-prepare in %1", thread_id()); - video->prepare (_pixel_format, _video_range, _aligned, _fast, _prepare_only_proxy); + video->prepare (_pixel_format, _video_range, _alignment, _fast, _prepare_only_proxy); LOG_TIMING("finish-prepare in %1", thread_id()); } } diff --git a/src/lib/butler.h b/src/lib/butler.h index 320e56bf9..cd3891754 100644 --- a/src/lib/butler.h +++ b/src/lib/butler.h @@ -45,7 +45,7 @@ public: int audio_channels, std::function<AVPixelFormat (AVPixelFormat)> pixel_format, VideoRange video_range, - bool aligned, + Image::Alignment alignment, bool fast, bool prepare_only_proxy ); @@ -125,7 +125,7 @@ private: std::function<AVPixelFormat (AVPixelFormat)> _pixel_format; VideoRange _video_range; - bool _aligned; + Image::Alignment _alignment; bool _fast; /** true to ask PlayerVideo::prepare to only prepare the ImageProxy and not also diff --git a/src/lib/dcp_video.cc b/src/lib/dcp_video.cc index 4a505a7e1..9daeb45c8 100644 --- a/src/lib/dcp_video.cc +++ b/src/lib/dcp_video.cc @@ -59,19 +59,21 @@ DCPOMATIC_ENABLE_WARNINGS #include "i18n.h" + using std::cout; using std::make_shared; using std::shared_ptr; using std::string; -using dcp::Size; using dcp::ArrayData; using dcp::raw_convert; #if BOOST_VERSION >= 106100 using namespace boost::placeholders; #endif + #define DCI_COEFFICENT (48.0 / 52.37) + /** Construct a DCP video frame. * @param frame Input frame. * @param index Index of the frame within the DCP. @@ -103,7 +105,7 @@ DCPVideo::convert_to_xyz (shared_ptr<const PlayerVideo> frame, dcp::NoteHandler { shared_ptr<dcp::OpenJPEGImage> xyz; - auto image = frame->image (bind(&PlayerVideo::keep_xyz_or_rgb, _1), VideoRange::FULL, true, false); + auto image = frame->image (bind(&PlayerVideo::keep_xyz_or_rgb, _1), VideoRange::FULL, Image::Alignment::PADDED, false); if (frame->colour_conversion()) { xyz = dcp::rgb_to_xyz ( image->data()[0], diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index 0b7c241d8..1d688c318 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -41,7 +41,7 @@ Encoder::Encoder (std::shared_ptr<const Film> film, std::weak_ptr<Job> job) : _film (film) , _job (job) - , _player (new Player(film, true)) + , _player (new Player(film, Image::Alignment::PADDED)) { } diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc index 70f9b0545..2baa99876 100644 --- a/src/lib/ffmpeg_decoder.cc +++ b/src/lib/ffmpeg_decoder.cc @@ -18,31 +18,33 @@ */ + /** @file src/ffmpeg_decoder.cc * @brief A decoder using FFmpeg to decode content. */ -#include "filter.h" -#include "exceptions.h" -#include "image.h" -#include "util.h" -#include "log.h" + +#include "audio_buffers.h" +#include "audio_content.h" +#include "audio_decoder.h" +#include "compose.hpp" #include "dcpomatic_log.h" -#include "ffmpeg_decoder.h" -#include "text_decoder.h" +#include "exceptions.h" #include "ffmpeg_audio_stream.h" -#include "ffmpeg_subtitle_stream.h" -#include "video_filter_graph.h" -#include "audio_buffers.h" #include "ffmpeg_content.h" -#include "raw_image_proxy.h" -#include "video_decoder.h" +#include "ffmpeg_decoder.h" +#include "ffmpeg_subtitle_stream.h" #include "film.h" -#include "audio_decoder.h" -#include "compose.hpp" -#include "text_content.h" -#include "audio_content.h" +#include "filter.h" #include "frame_interval_checker.h" +#include "image.h" +#include "log.h" +#include "raw_image_proxy.h" +#include "text_content.h" +#include "text_decoder.h" +#include "util.h" +#include "video_decoder.h" +#include "video_filter_graph.h" #include <dcp/subtitle_string.h> #include <sub/ssa_reader.h> #include <sub/subtitle.h> @@ -52,28 +54,22 @@ extern "C" { #include <libavformat/avformat.h> } #include <boost/algorithm/string.hpp> -#include <vector> #include <iomanip> #include <iostream> +#include <vector> #include <stdint.h> #include "i18n.h" + using std::cout; -using std::string; -using std::vector; -using std::list; +using std::dynamic_pointer_cast; +using std::make_shared; using std::min; -using std::pair; -using std::max; -using std::map; using std::shared_ptr; -using std::make_shared; -using std::make_pair; -using boost::is_any_of; -using boost::split; +using std::string; +using std::vector; using boost::optional; -using std::dynamic_pointer_cast; using dcp::Size; using namespace dcpomatic; @@ -86,7 +82,7 @@ FFmpegDecoder::FFmpegDecoder (shared_ptr<const Film> film, shared_ptr<const FFmp video = make_shared<VideoDecoder>(this, c); _pts_offset = pts_offset (c->ffmpeg_audio_streams(), c->first_video(), c->active_video_frame_rate(film)); /* It doesn't matter what size or pixel format this is, it just needs to be black */ - _black_image = make_shared<Image>(AV_PIX_FMT_RGB24, dcp::Size (128, 128), true); + _black_image = make_shared<Image>(AV_PIX_FMT_RGB24, dcp::Size (128, 128), Image::Alignment::PADDED); _black_image->make_black (); } else { _pts_offset = {}; @@ -684,7 +680,7 @@ FFmpegDecoder::process_bitmap_subtitle (AVSubtitleRect const * rect, ContentTime /* Note BGRA is expressed little-endian, so the first byte in the word is B, second G, third R, fourth A. */ - auto image = make_shared<Image>(AV_PIX_FMT_BGRA, dcp::Size (rect->w, rect->h), true); + auto image = make_shared<Image>(AV_PIX_FMT_BGRA, dcp::Size (rect->w, rect->h), Image::Alignment::PADDED); #ifdef DCPOMATIC_HAVE_AVSUBTITLERECT_PICT /* Start of the first line in the subtitle */ diff --git a/src/lib/ffmpeg_encoder.cc b/src/lib/ffmpeg_encoder.cc index 77f27d519..dd773168a 100644 --- a/src/lib/ffmpeg_encoder.cc +++ b/src/lib/ffmpeg_encoder.cc @@ -18,26 +18,25 @@ */ + +#include "butler.h" +#include "cross.h" #include "ffmpeg_encoder.h" #include "film.h" +#include "image.h" #include "job.h" +#include "log.h" #include "player.h" #include "player_video.h" -#include "log.h" -#include "image.h" -#include "cross.h" -#include "butler.h" #include "compose.hpp" #include <iostream> #include "i18n.h" + using std::cout; using std::list; using std::make_shared; -using std::map; -using std::pair; -using std::runtime_error; using std::shared_ptr; using std::string; using std::weak_ptr; @@ -48,6 +47,7 @@ using namespace dcpomatic; using namespace boost::placeholders; #endif + /** @param key Key to use to encrypt MP4 outputs */ FFmpegEncoder::FFmpegEncoder ( shared_ptr<const Film> film, @@ -108,7 +108,7 @@ FFmpegEncoder::FFmpegEncoder ( } _butler = std::make_shared<Butler>( - _film, _player, map, _output_audio_channels, bind(&PlayerVideo::force, _1, FFmpegFileEncoder::pixel_format(format)), VideoRange::VIDEO, true, false, false + _film, _player, map, _output_audio_channels, bind(&PlayerVideo::force, _1, FFmpegFileEncoder::pixel_format(format)), VideoRange::VIDEO, Image::Alignment::PADDED, false, false ); } diff --git a/src/lib/ffmpeg_file_encoder.cc b/src/lib/ffmpeg_file_encoder.cc index 533fd151c..ef02f30c8 100644 --- a/src/lib/ffmpeg_file_encoder.cc +++ b/src/lib/ffmpeg_file_encoder.cc @@ -19,16 +19,16 @@ */ +#include "compose.hpp" +#include "cross.h" #include "ffmpeg_encoder.h" #include "ffmpeg_wrapper.h" #include "film.h" +#include "image.h" #include "job.h" +#include "log.h" #include "player.h" #include "player_video.h" -#include "log.h" -#include "image.h" -#include "cross.h" -#include "compose.hpp" extern "C" { #include <libavutil/channel_layout.h> } @@ -39,13 +39,9 @@ extern "C" { using std::cout; using std::make_shared; -using std::pair; -using std::runtime_error; using std::shared_ptr; using std::string; -using std::weak_ptr; using boost::bind; -using boost::optional; using namespace dcpomatic; #if BOOST_VERSION >= 106100 using namespace boost::placeholders; @@ -406,7 +402,7 @@ FFmpegFileEncoder::video (shared_ptr<PlayerVideo> video, DCPTime time) auto image = video->image ( bind (&PlayerVideo::force, _1, _pixel_format), VideoRange::VIDEO, - true, + Image::Alignment::PADDED, false ); diff --git a/src/lib/ffmpeg_image_proxy.cc b/src/lib/ffmpeg_image_proxy.cc index dd2f80e0e..4b3c3084c 100644 --- a/src/lib/ffmpeg_image_proxy.cc +++ b/src/lib/ffmpeg_image_proxy.cc @@ -122,7 +122,7 @@ FFmpegImageProxy::avio_seek (int64_t const pos, int whence) ImageProxy::Result -FFmpegImageProxy::image (bool aligned, optional<dcp::Size>) const +FFmpegImageProxy::image (Image::Alignment alignment, optional<dcp::Size>) const { auto constexpr name_for_errors = "FFmpegImageProxy::image"; @@ -205,7 +205,7 @@ FFmpegImageProxy::image (bool aligned, optional<dcp::Size>) const throw DecodeError (N_("avcodec_receive_frame"), name_for_errors, r, *_path); } - _image = make_shared<Image>(frame, aligned); + _image = make_shared<Image>(frame, alignment); av_packet_unref (&packet); av_frame_free (&frame); diff --git a/src/lib/ffmpeg_image_proxy.h b/src/lib/ffmpeg_image_proxy.h index f4e5bf66c..48317ed75 100644 --- a/src/lib/ffmpeg_image_proxy.h +++ b/src/lib/ffmpeg_image_proxy.h @@ -32,7 +32,7 @@ public: FFmpegImageProxy (std::shared_ptr<Socket> socket); Result image ( - bool aligned, + Image::Alignment alignment, boost::optional<dcp::Size> size = boost::optional<dcp::Size> () ) const; diff --git a/src/lib/hints.cc b/src/lib/hints.cc index f21c51db9..46704ebf8 100644 --- a/src/lib/hints.cc +++ b/src/lib/hints.cc @@ -51,11 +51,8 @@ using std::cout; using std::make_shared; using std::max; -using std::min; -using std::pair; using std::shared_ptr; using std::string; -using std::vector; using std::weak_ptr; using boost::optional; using boost::bind; @@ -408,7 +405,7 @@ try emit (bind(boost::ref(Progress), _("Examining audio, subtitles and closed captions"))); } - auto player = make_shared<Player>(film, false); + auto player = make_shared<Player>(film, Image::Alignment::COMPACT); player->set_ignore_video (); if (check_loudness_done) { /* We don't need to analyse audio because we already loaded a suitable analysis */ diff --git a/src/lib/image.cc b/src/lib/image.cc index ce3f5817d..30589ef9c 100644 --- a/src/lib/image.cc +++ b/src/lib/image.cc @@ -64,8 +64,8 @@ using std::string; using dcp::Size; -/** The memory alignment, in bytes, used for each row of an image if aligment is requested */ -#define ALIGNMENT 64 +/** The memory alignment, in bytes, used for each row of an image if Alignment::PADDED is requested */ +int constexpr ALIGNMENT = 64; /* U/V black value for 8-bit colour */ static uint8_t const eight_bit_uv = (1 << 7) - 1; @@ -177,19 +177,19 @@ Image::crop_scale_window ( VideoRange video_range, AVPixelFormat out_format, VideoRange out_video_range, - bool out_aligned, + Alignment out_alignment, bool fast ) const { /* Empirical testing suggests that sws_scale() will crash if - the input image is not aligned. + the input image is not padded. */ - DCPOMATIC_ASSERT (aligned ()); + DCPOMATIC_ASSERT (alignment() == Alignment::PADDED); DCPOMATIC_ASSERT (out_size.width >= inter_size.width); DCPOMATIC_ASSERT (out_size.height >= inter_size.height); - auto out = make_shared<Image>(out_format, out_size, out_aligned); + auto out = make_shared<Image>(out_format, out_size, out_alignment); out->make_black (); auto in_desc = av_pix_fmt_desc_get (_pixel_format); @@ -310,27 +310,27 @@ Image::crop_scale_window ( } shared_ptr<Image> -Image::convert_pixel_format (dcp::YUVToRGB yuv_to_rgb, AVPixelFormat out_format, bool out_aligned, bool fast) const +Image::convert_pixel_format (dcp::YUVToRGB yuv_to_rgb, AVPixelFormat out_format, Alignment out_alignment, bool fast) const { - return scale(size(), yuv_to_rgb, out_format, out_aligned, fast); + return scale(size(), yuv_to_rgb, out_format, out_alignment, fast); } /** @param out_size Size to scale to. * @param yuv_to_rgb YUVToRGB transform transform to use, if required. * @param out_format Output pixel format. - * @param out_aligned true to make an aligned output image. + * @param out_aligment Output alignment. * @param fast Try to be fast at the possible expense of quality; at present this means using * fast bilinear rather than bicubic scaling. */ shared_ptr<Image> -Image::scale (dcp::Size out_size, dcp::YUVToRGB yuv_to_rgb, AVPixelFormat out_format, bool out_aligned, bool fast) const +Image::scale (dcp::Size out_size, dcp::YUVToRGB yuv_to_rgb, AVPixelFormat out_format, Alignment out_alignment, bool fast) const { /* Empirical testing suggests that sws_scale() will crash if - the input image is not aligned. + the input image alignment is not PADDED. */ - DCPOMATIC_ASSERT (aligned ()); + DCPOMATIC_ASSERT (alignment() == Alignment::PADDED); - auto scaled = make_shared<Image>(out_format, out_size, out_aligned); + auto scaled = make_shared<Image>(out_format, out_size, out_alignment); auto scale_context = sws_getContext ( size().width, size().height, pixel_format(), out_size.width, out_size.height, out_format, @@ -736,7 +736,7 @@ Image::alpha_blend (shared_ptr<const Image> other, Position<int> position) } case AV_PIX_FMT_YUV420P: { - auto yuv = other->convert_pixel_format (dcp::YUVToRGB::REC709, _pixel_format, false, false); + auto yuv = other->convert_pixel_format (dcp::YUVToRGB::REC709, _pixel_format, Alignment::COMPACT, false); dcp::Size const ts = size(); dcp::Size const os = yuv->size(); for (int ty = start_ty, oy = start_oy; ty < ts.height && oy < os.height; ++ty, ++oy) { @@ -771,7 +771,7 @@ Image::alpha_blend (shared_ptr<const Image> other, Position<int> position) } case AV_PIX_FMT_YUV420P10: { - auto yuv = other->convert_pixel_format (dcp::YUVToRGB::REC709, _pixel_format, false, false); + auto yuv = other->convert_pixel_format (dcp::YUVToRGB::REC709, _pixel_format, Alignment::COMPACT, false); dcp::Size const ts = size(); dcp::Size const os = yuv->size(); for (int ty = start_ty, oy = start_oy; ty < ts.height && oy < os.height; ++ty, ++oy) { @@ -806,7 +806,7 @@ Image::alpha_blend (shared_ptr<const Image> other, Position<int> position) } case AV_PIX_FMT_YUV422P10LE: { - auto yuv = other->convert_pixel_format (dcp::YUVToRGB::REC709, _pixel_format, false, false); + auto yuv = other->convert_pixel_format (dcp::YUVToRGB::REC709, _pixel_format, Alignment::COMPACT, false); dcp::Size const ts = size(); dcp::Size const os = yuv->size(); for (int ty = start_ty, oy = start_oy; ty < ts.height && oy < os.height; ++ty, ++oy) { @@ -934,16 +934,17 @@ Image::bytes_per_pixel (int c) const * * @param p Pixel format. * @param s Size in pixels. - * @param aligned true to make each row of this image aligned to a ALIGNMENT-byte boundary. + * @param alignment PADDED to make each row of this image aligned to a ALIGNMENT-byte boundary, otherwise COMPACT. */ -Image::Image (AVPixelFormat p, dcp::Size s, bool aligned) +Image::Image (AVPixelFormat p, dcp::Size s, Alignment alignment) : _size (s) , _pixel_format (p) - , _aligned (aligned) + , _alignment (alignment) { allocate (); } + void Image::allocate () { @@ -958,7 +959,7 @@ Image::allocate () for (int i = 0; i < planes(); ++i) { _line_size[i] = ceil (_size.width * bytes_per_pixel(i)); - _stride[i] = stride_round_up (i, _line_size, _aligned ? ALIGNMENT : 1); + _stride[i] = stride_round_up (i, _line_size, _alignment == Alignment::PADDED ? ALIGNMENT : 1); /* The assembler function ff_rgb24ToY_avx (in libswscale/x86/input.asm) uses a 16-byte fetch to read three bytes (R/G/B) of image data. @@ -1011,7 +1012,7 @@ Image::Image (Image const & other) : std::enable_shared_from_this<Image>(other) , _size (other._size) , _pixel_format (other._pixel_format) - , _aligned (other._aligned) + , _alignment (other._alignment) { allocate (); @@ -1027,10 +1028,10 @@ Image::Image (Image const & other) } } -Image::Image (AVFrame const * frame, bool aligned) +Image::Image (AVFrame const * frame, Alignment alignment) : _size (frame->width, frame->height) , _pixel_format (static_cast<AVPixelFormat>(frame->format)) - , _aligned (aligned) + , _alignment (alignment) { DCPOMATIC_ASSERT (_pixel_format != AV_PIX_FMT_NONE); @@ -1049,10 +1050,10 @@ Image::Image (AVFrame const * frame, bool aligned) } } -Image::Image (shared_ptr<const Image> other, bool aligned) +Image::Image (shared_ptr<const Image> other, Alignment alignment) : _size (other->_size) , _pixel_format (other->_pixel_format) - , _aligned (aligned) + , _alignment (alignment) { allocate (); @@ -1093,7 +1094,7 @@ Image::swap (Image & other) std::swap (_stride[i], other._stride[i]); } - std::swap (_aligned, other._aligned); + std::swap (_alignment, other._alignment); } Image::~Image () @@ -1131,15 +1132,15 @@ Image::size () const return _size; } -bool -Image::aligned () const +Image::Alignment +Image::alignment () const { - return _aligned; + return _alignment; } PositionImage -merge (list<PositionImage> images, bool aligned) +merge (list<PositionImage> images, Image::Alignment alignment) { if (images.empty ()) { return {}; @@ -1154,7 +1155,7 @@ merge (list<PositionImage> images, bool aligned) all.extend (dcpomatic::Rect<int>(i.position, i.image->size().width, i.image->size().height)); } - auto merged = make_shared<Image>(images.front().image->pixel_format(), dcp::Size(all.width, all.height), aligned); + auto merged = make_shared<Image>(images.front().image->pixel_format(), dcp::Size(all.width, all.height), alignment); merged->make_transparent (); for (auto const& i: images) { merged->alpha_blend (i.image, i.position - all.position()); @@ -1167,7 +1168,7 @@ merge (list<PositionImage> images, bool aligned) bool operator== (Image const & a, Image const & b) { - if (a.planes() != b.planes() || a.pixel_format() != b.pixel_format() || a.aligned() != b.aligned()) { + if (a.planes() != b.planes() || a.pixel_format() != b.pixel_format() || a.alignment() != b.alignment()) { return false; } @@ -1314,13 +1315,13 @@ Image::fade (float f) shared_ptr<const Image> -Image::ensure_aligned (shared_ptr<const Image> image, bool aligned) +Image::ensure_alignment (shared_ptr<const Image> image, Image::Alignment alignment) { - if (image->aligned() == aligned) { + if (image->alignment() == alignment) { return image; } - return make_shared<Image>(image, aligned); + return make_shared<Image>(image, alignment); } @@ -1395,7 +1396,7 @@ Image::as_png () const DCPOMATIC_ASSERT (bytes_per_pixel(0) == 4); DCPOMATIC_ASSERT (planes() == 1); if (pixel_format() != AV_PIX_FMT_RGBA) { - return convert_pixel_format(dcp::YUVToRGB::REC709, AV_PIX_FMT_RGBA, true, false)->as_png(); + return convert_pixel_format(dcp::YUVToRGB::REC709, AV_PIX_FMT_RGBA, Image::Alignment::PADDED, false)->as_png(); } /* error handling? */ diff --git a/src/lib/image.h b/src/lib/image.h index 3cba8f7e5..128b546b5 100644 --- a/src/lib/image.h +++ b/src/lib/image.h @@ -40,10 +40,15 @@ class Socket; class Image : public std::enable_shared_from_this<Image> { public: - Image (AVPixelFormat p, dcp::Size s, bool aligned); - explicit Image (AVFrame const *, bool aligned); + enum class Alignment { + COMPACT, + PADDED + }; + + Image (AVPixelFormat p, dcp::Size s, Alignment alignment); + explicit Image (AVFrame const *, Alignment alignment); explicit Image (Image const &); - Image (std::shared_ptr<const Image>, bool); + Image (std::shared_ptr<const Image>, Alignment alignment); Image& operator= (Image const &); ~Image (); @@ -53,7 +58,7 @@ public: /** @return array of sizes of the data in each line, in bytes (including any alignment padding) */ int const * stride () const; dcp::Size size () const; - bool aligned () const; + Alignment alignment () const; int planes () const; int vertical_factor (int) const; @@ -61,8 +66,8 @@ public: dcp::Size sample_size (int) const; float bytes_per_pixel (int) const; - std::shared_ptr<Image> convert_pixel_format (dcp::YUVToRGB yuv_to_rgb, AVPixelFormat out_format, bool aligned, bool fast) const; - std::shared_ptr<Image> scale (dcp::Size out_size, dcp::YUVToRGB yuv_to_rgb, AVPixelFormat out_format, bool aligned, bool fast) const; + std::shared_ptr<Image> convert_pixel_format (dcp::YUVToRGB yuv_to_rgb, AVPixelFormat out_format, Alignment alignment, bool fast) const; + std::shared_ptr<Image> scale (dcp::Size out_size, dcp::YUVToRGB yuv_to_rgb, AVPixelFormat out_format, Alignment alignment, bool fast) const; std::shared_ptr<Image> crop_scale_window ( Crop crop, dcp::Size inter_size, @@ -71,7 +76,7 @@ public: VideoRange video_range, AVPixelFormat out_format, VideoRange out_video_range, - bool aligned, + Alignment alignment, bool fast ) const; @@ -94,7 +99,7 @@ public: void png_error (char const * message); - static std::shared_ptr<const Image> ensure_aligned (std::shared_ptr<const Image> image, bool aligned); + static std::shared_ptr<const Image> ensure_alignment (std::shared_ptr<const Image> image, Alignment alignment); private: friend struct pixel_formats_test; @@ -112,10 +117,10 @@ private: uint8_t** _data; ///< array of pointers to components int* _line_size; ///< array of sizes of the data in each line, in bytes (without any alignment padding bytes) int* _stride; ///< array of strides for each line, in bytes (including any alignment padding bytes) - bool _aligned; + Alignment _alignment; }; -extern PositionImage merge (std::list<PositionImage> images, bool aligned); +extern PositionImage merge (std::list<PositionImage> images, Image::Alignment alignment); extern bool operator== (Image const & a, Image const & b); #endif diff --git a/src/lib/image_examiner.cc b/src/lib/image_examiner.cc index 8b2096214..ae12d7adb 100644 --- a/src/lib/image_examiner.cc +++ b/src/lib/image_examiner.cc @@ -67,7 +67,7 @@ ImageExaminer::ImageExaminer (shared_ptr<const Film> film, shared_ptr<const Imag delete[] buffer; } else { FFmpegImageProxy proxy(content->path(0)); - _video_size = proxy.image(false).image->size(); + _video_size = proxy.image(Image::Alignment::COMPACT).image->size(); } if (content->still ()) { diff --git a/src/lib/image_proxy.h b/src/lib/image_proxy.h index 8817845d9..a37be580f 100644 --- a/src/lib/image_proxy.h +++ b/src/lib/image_proxy.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2014 Carl Hetherington <cth@carlh.net> + Copyright (C) 2014-2021 Carl Hetherington <cth@carlh.net> This file is part of DCP-o-matic. @@ -18,13 +18,17 @@ */ + #ifndef DCPOMATIC_IMAGE_PROXY_H #define DCPOMATIC_IMAGE_PROXY_H + /** @file src/lib/image_proxy.h * @brief ImageProxy and subclasses. */ + +#include "image.h" extern "C" { #include <libavutil/pixfmt.h> } @@ -32,6 +36,7 @@ extern "C" { #include <boost/optional.hpp> #include <boost/utility.hpp> + class Image; class Socket; @@ -43,6 +48,7 @@ namespace cxml { class Node; } + /** @class ImageProxy * @brief A class which holds an Image, and can produce it on request. * @@ -91,7 +97,7 @@ public: * can be used as an optimisation. */ virtual Result image ( - bool aligned, + Image::Alignment alignment, boost::optional<dcp::Size> size = boost::optional<dcp::Size> () ) const = 0; @@ -103,10 +109,12 @@ public: * This method may be called in a different thread to image(). * @return log2 of any scaling down that will be applied to the image. */ - virtual int prepare (bool, boost::optional<dcp::Size> = boost::optional<dcp::Size>()) const { return 0; } + virtual int prepare (Image::Alignment, boost::optional<dcp::Size> = boost::optional<dcp::Size>()) const { return 0; } virtual size_t memory_used () const = 0; }; + std::shared_ptr<ImageProxy> image_proxy_factory (std::shared_ptr<cxml::Node> xml, std::shared_ptr<Socket> socket); + #endif diff --git a/src/lib/j2k_image_proxy.cc b/src/lib/j2k_image_proxy.cc index 21507ca15..00d3cf2ef 100644 --- a/src/lib/j2k_image_proxy.cc +++ b/src/lib/j2k_image_proxy.cc @@ -42,10 +42,8 @@ DCPOMATIC_ENABLE_WARNINGS using std::cout; using std::dynamic_pointer_cast; -using std::make_pair; using std::make_shared; using std::max; -using std::pair; using std::shared_ptr; using std::string; using boost::optional; @@ -120,7 +118,7 @@ J2KImageProxy::J2KImageProxy (shared_ptr<cxml::Node> xml, shared_ptr<Socket> soc int -J2KImageProxy::prepare (bool aligned, optional<dcp::Size> target_size) const +J2KImageProxy::prepare (Image::Alignment alignment, optional<dcp::Size> target_size) const { boost::mutex::scoped_lock lm (_mutex); @@ -145,7 +143,7 @@ J2KImageProxy::prepare (bool aligned, optional<dcp::Size> target_size) const try { /* XXX: should check that potentially trashing _data here doesn't matter */ auto decompressed = dcp::decompress_j2k (const_cast<uint8_t*>(_data->data()), _data->size(), reduce); - _image = make_shared<Image>(_pixel_format, decompressed->size(), aligned); + _image = make_shared<Image>(_pixel_format, decompressed->size(), alignment); int const shift = 16 - decompressed->precision (0); @@ -169,7 +167,7 @@ J2KImageProxy::prepare (bool aligned, optional<dcp::Size> target_size) const } } } catch (dcp::J2KDecompressionError& e) { - _image = make_shared<Image>(_pixel_format, _size, aligned); + _image = make_shared<Image>(_pixel_format, _size, alignment); _image->make_black (); _error = true; } @@ -182,9 +180,9 @@ J2KImageProxy::prepare (bool aligned, optional<dcp::Size> target_size) const ImageProxy::Result -J2KImageProxy::image (bool aligned, optional<dcp::Size> target_size) const +J2KImageProxy::image (Image::Alignment alignment, optional<dcp::Size> target_size) const { - int const r = prepare (aligned, target_size); + int const r = prepare (alignment, target_size); /* I think this is safe without a lock on mutex. _image is guaranteed to be set up when prepare() has happened. diff --git a/src/lib/j2k_image_proxy.h b/src/lib/j2k_image_proxy.h index a23ec6d98..d925bef86 100644 --- a/src/lib/j2k_image_proxy.h +++ b/src/lib/j2k_image_proxy.h @@ -57,7 +57,7 @@ public: J2KImageProxy (dcp::ArrayData data, dcp::Size size, AVPixelFormat pixel_format); Result image ( - bool aligned, + Image::Alignment alignment, boost::optional<dcp::Size> size = boost::optional<dcp::Size> () ) const; @@ -65,7 +65,7 @@ public: void write_to_socket (std::shared_ptr<Socket>) const; /** @return true if our image is definitely the same as another, false if it is probably not */ bool same (std::shared_ptr<const ImageProxy>) const; - int prepare (bool aligned, boost::optional<dcp::Size> = boost::optional<dcp::Size>()) const; + int prepare (Image::Alignment alignment, boost::optional<dcp::Size> = boost::optional<dcp::Size>()) const; std::shared_ptr<const dcp::Data> j2k () const { return _data; diff --git a/src/lib/player.cc b/src/lib/player.cc index 810d949d9..7c1a57aa9 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -95,12 +95,12 @@ int const PlayerProperty::DCP_DECODE_REDUCTION = 704; int const PlayerProperty::PLAYBACK_LENGTH = 705; -Player::Player (shared_ptr<const Film> film, bool aligned) +Player::Player (shared_ptr<const Film> film, Image::Alignment subtitle_alignment) : _film (film) , _suspended (0) , _tolerant (film->tolerant()) , _audio_merger (_film->audio_frame_rate()) - , _aligned_subtitles (aligned) + , _subtitle_alignment (subtitle_alignment) { construct (); } @@ -332,7 +332,7 @@ Player::set_video_container_size (dcp::Size s) _video_container_size = s; - _black_image.reset (new Image (AV_PIX_FMT_RGB24, _video_container_size, true)); + _black_image = make_shared<Image>(AV_PIX_FMT_RGB24, _video_container_size, Image::Alignment::PADDED); _black_image->make_black (); } @@ -828,7 +828,7 @@ Player::open_subtitles_for_frame (DCPTime time) const return {}; } - return merge (captions, _aligned_subtitles); + return merge (captions, _subtitle_alignment); } @@ -1056,7 +1056,7 @@ Player::bitmap_text_start (weak_ptr<Piece> wp, weak_ptr<const TextContent> wc, C } dcp::Size scaled_size (width, height); - ps.bitmap.push_back (BitmapText(image->scale(scaled_size, dcp::YUVToRGB::REC601, image->pixel_format(), true, _fast), subtitle.sub.rectangle)); + ps.bitmap.push_back (BitmapText(image->scale(scaled_size, dcp::YUVToRGB::REC601, image->pixel_format(), Image::Alignment::PADDED, _fast), subtitle.sub.rectangle)); DCPTime from (content_time_to_dcp (piece, subtitle.from())); _active_texts[static_cast<int>(text->type())].add_from (wc, ps, from); diff --git a/src/lib/player.h b/src/lib/player.h index 767218379..b74aeeefd 100644 --- a/src/lib/player.h +++ b/src/lib/player.h @@ -34,6 +34,7 @@ #include "content_video.h" #include "empty.h" #include "film.h" +#include "image.h" #include "piece.h" #include "player_text.h" #include "position_image.h" @@ -76,7 +77,7 @@ public: class Player : public std::enable_shared_from_this<Player> { public: - Player (std::shared_ptr<const Film>, bool aligned_subtitles); + Player (std::shared_ptr<const Film>, Image::Alignment subtitle_alignment); Player (std::shared_ptr<const Film>, std::shared_ptr<const Playlist> playlist); Player (Player const& Player) = delete; @@ -233,8 +234,8 @@ private: dcpomatic::DCPTime _playback_length; - /** aligned flag for subtitle images that we create */ - bool _aligned_subtitles = true; + /** Alignment for subtitle images that we create */ + Image::Alignment _subtitle_alignment = Image::Alignment::PADDED; boost::signals2::scoped_connection _film_changed_connection; boost::signals2::scoped_connection _playlist_change_connection; diff --git a/src/lib/player_video.cc b/src/lib/player_video.cc index a687e7ea5..2d60efe10 100644 --- a/src/lib/player_video.cc +++ b/src/lib/player_video.cc @@ -94,7 +94,7 @@ PlayerVideo::PlayerVideo (shared_ptr<cxml::Node> node, shared_ptr<Socket> socket if (node->optional_number_child<int>("SubtitleX")) { auto image = make_shared<Image> ( - AV_PIX_FMT_BGRA, dcp::Size(node->number_child<int>("SubtitleWidth"), node->number_child<int>("SubtitleHeight")), true + AV_PIX_FMT_BGRA, dcp::Size(node->number_child<int>("SubtitleWidth"), node->number_child<int>("SubtitleHeight")), Image::Alignment::PADDED ); image->read_from_socket (socket); @@ -110,13 +110,13 @@ PlayerVideo::set_text (PositionImage image) } shared_ptr<Image> -PlayerVideo::image (function<AVPixelFormat (AVPixelFormat)> pixel_format, VideoRange video_range, bool aligned, bool fast) const +PlayerVideo::image (function<AVPixelFormat (AVPixelFormat)> pixel_format, VideoRange video_range, Image::Alignment alignment, bool fast) const { /* XXX: this assumes that image() and prepare() are only ever called with the same parameters (except crop, inter size, out size, fade) */ boost::mutex::scoped_lock lm (_mutex); if (!_image || _crop != _image_crop || _inter_size != _image_inter_size || _out_size != _image_out_size || _fade != _image_fade) { - make_image (pixel_format, video_range, aligned, fast); + make_image (pixel_format, video_range, alignment, fast); } return _image; } @@ -125,7 +125,7 @@ PlayerVideo::image (function<AVPixelFormat (AVPixelFormat)> pixel_format, VideoR shared_ptr<const Image> PlayerVideo::raw_image () const { - return _in->image(false, _inter_size).image; + return _in->image(Image::Alignment::COMPACT, _inter_size).image; } @@ -133,18 +133,18 @@ PlayerVideo::raw_image () const * @param pixel_format Function which is called to decide what pixel format the output image should be; * it is passed the pixel format of the input image from the ImageProxy, and should return the desired * output pixel format. Two functions force and keep_xyz_or_rgb are provided for use here. - * @param aligned true if the output image should be aligned to 32-byte boundaries. + * @param alignment PADDED if the output image should be aligned to 32-byte boundaries, otherwise COMPACT. * @param fast true to be fast at the expense of quality. */ void -PlayerVideo::make_image (function<AVPixelFormat (AVPixelFormat)> pixel_format, VideoRange video_range, bool aligned, bool fast) const +PlayerVideo::make_image (function<AVPixelFormat (AVPixelFormat)> pixel_format, VideoRange video_range, Image::Alignment alignment, bool fast) const { _image_crop = _crop; _image_inter_size = _inter_size; _image_out_size = _out_size; _image_fade = _fade; - auto prox = _in->image (true, _inter_size); + auto prox = _in->image (Image::Alignment::PADDED, _inter_size); _error = prox.error; auto total_crop = _crop; @@ -180,11 +180,11 @@ PlayerVideo::make_image (function<AVPixelFormat (AVPixelFormat)> pixel_format, V } _image = prox.image->crop_scale_window ( - total_crop, _inter_size, _out_size, yuv_to_rgb, _video_range, pixel_format (prox.image->pixel_format()), video_range, aligned, fast + total_crop, _inter_size, _out_size, yuv_to_rgb, _video_range, pixel_format (prox.image->pixel_format()), video_range, alignment, fast ); if (_text) { - _image->alpha_blend (Image::ensure_aligned(_text->image, true), _text->position); + _image->alpha_blend (Image::ensure_alignment(_text->image, Image::Alignment::PADDED), _text->position); } if (_fade) { @@ -298,12 +298,12 @@ PlayerVideo::keep_xyz_or_rgb (AVPixelFormat p) } void -PlayerVideo::prepare (function<AVPixelFormat (AVPixelFormat)> pixel_format, VideoRange video_range, bool aligned, bool fast, bool proxy_only) +PlayerVideo::prepare (function<AVPixelFormat (AVPixelFormat)> pixel_format, VideoRange video_range, Image::Alignment alignment, bool fast, bool proxy_only) { - _in->prepare (aligned, _inter_size); + _in->prepare (alignment, _inter_size); boost::mutex::scoped_lock lm (_mutex); if (!_image && !proxy_only) { - make_image (pixel_format, video_range, aligned, fast); + make_image (pixel_format, video_range, alignment, fast); } } diff --git a/src/lib/player_video.h b/src/lib/player_video.h index 872bc9864..d24620c7e 100644 --- a/src/lib/player_video.h +++ b/src/lib/player_video.h @@ -23,11 +23,12 @@ #define DCPOMATIC_PLAYER_VIDEO_H -#include "types.h" -#include "position.h" -#include "dcpomatic_time.h" #include "colour_conversion.h" +#include "dcpomatic_time.h" +#include "image.h" +#include "position.h" #include "position_image.h" +#include "types.h" extern "C" { #include <libavutil/pixfmt.h> } @@ -74,8 +75,8 @@ public: return _text; } - void prepare (std::function<AVPixelFormat (AVPixelFormat)> pixel_format, VideoRange video_range, bool aligned, bool fast, bool proxy_only); - std::shared_ptr<Image> image (std::function<AVPixelFormat (AVPixelFormat)> pixel_format, VideoRange video_range, bool aligned, bool fast) const; + void prepare (std::function<AVPixelFormat (AVPixelFormat)> pixel_format, VideoRange video_range, Image::Alignment alignment, bool fast, bool proxy_only); + std::shared_ptr<Image> image (std::function<AVPixelFormat (AVPixelFormat)> pixel_format, VideoRange video_range, Image::Alignment alignment, bool fast) const; std::shared_ptr<const Image> raw_image () const; static AVPixelFormat force (AVPixelFormat, AVPixelFormat); @@ -126,7 +127,7 @@ public: } private: - void make_image (std::function<AVPixelFormat (AVPixelFormat)> pixel_format, VideoRange video_range, bool aligned, bool fast) const; + void make_image (std::function<AVPixelFormat (AVPixelFormat)> pixel_format, VideoRange video_range, Image::Alignment alignment, bool fast) const; std::shared_ptr<const ImageProxy> _in; Crop _crop; diff --git a/src/lib/raw_image_proxy.cc b/src/lib/raw_image_proxy.cc index ac8ff0763..fb0d16df8 100644 --- a/src/lib/raw_image_proxy.cc +++ b/src/lib/raw_image_proxy.cc @@ -58,16 +58,16 @@ RawImageProxy::RawImageProxy (shared_ptr<cxml::Node> xml, shared_ptr<Socket> soc xml->number_child<int>("Width"), xml->number_child<int>("Height") ); - _image = make_shared<Image>(static_cast<AVPixelFormat>(xml->number_child<int>("PixelFormat")), size, true); + _image = make_shared<Image>(static_cast<AVPixelFormat>(xml->number_child<int>("PixelFormat")), size, Image::Alignment::PADDED); _image->read_from_socket (socket); } ImageProxy::Result -RawImageProxy::image (bool aligned, optional<dcp::Size>) const +RawImageProxy::image (Image::Alignment alignment, optional<dcp::Size>) const { - /* This ensure_aligned could be wasteful */ - return Result (Image::ensure_aligned(_image, aligned), 0); + /* This ensure_alignment could be wasteful */ + return Result (Image::ensure_alignment(_image, alignment), 0); } @@ -96,7 +96,7 @@ RawImageProxy::same (shared_ptr<const ImageProxy> other) const return false; } - return (*_image.get()) == (*rp->image(_image->aligned()).image.get()); + return (*_image.get()) == (*rp->image(_image->alignment()).image.get()); } diff --git a/src/lib/raw_image_proxy.h b/src/lib/raw_image_proxy.h index 7e0861104..c9885654b 100644 --- a/src/lib/raw_image_proxy.h +++ b/src/lib/raw_image_proxy.h @@ -33,7 +33,7 @@ public: RawImageProxy (std::shared_ptr<cxml::Node> xml, std::shared_ptr<Socket> socket); Result image ( - bool aligned, + Image::Alignment alignment, boost::optional<dcp::Size> size = boost::optional<dcp::Size> () ) const; diff --git a/src/lib/render_text.cc b/src/lib/render_text.cc index 7bb7d6b45..96b832c57 100644 --- a/src/lib/render_text.cc +++ b/src/lib/render_text.cc @@ -96,7 +96,7 @@ static shared_ptr<Image> create_image (dcp::Size size) { /* FFmpeg BGRA means first byte blue, second byte green, third byte red, fourth byte alpha */ - auto image = make_shared<Image>(AV_PIX_FMT_BGRA, size, false); + auto image = make_shared<Image>(AV_PIX_FMT_BGRA, size, Image::Alignment::COMPACT); image->make_black (); return image; } diff --git a/src/lib/util.cc b/src/lib/util.cc index c65b2bc85..981cfa521 100644 --- a/src/lib/util.cc +++ b/src/lib/util.cc @@ -22,31 +22,33 @@ * @brief Some utility functions and classes. */ + #define UNICODE 1 -#include "util.h" -#include "exceptions.h" -#include "dcp_content_type.h" -#include "filter.h" + +#include "audio_buffers.h" +#include "audio_processor.h" #include "cinema_sound_processor.h" +#include "compose.hpp" #include "config.h" -#include "ratio.h" -#include "job.h" #include "cross.h" -#include "video_content.h" -#include "rect.h" -#include "digester.h" -#include "audio_processor.h" #include "crypto.h" -#include "compose.hpp" -#include "audio_buffers.h" -#include "string_text.h" -#include "font.h" -#include "render_text.h" +#include "dcp_content_type.h" +#include "digester.h" +#include "exceptions.h" #include "ffmpeg_image_proxy.h" +#include "filter.h" +#include "font.h" #include "image.h" -#include "text_decoder.h" +#include "job.h" #include "job_manager.h" +#include "ratio.h" +#include "rect.h" +#include "render_text.h" +#include "string_text.h" +#include "text_decoder.h" +#include "util.h" +#include "video_content.h" #include "warnings.h" #include <dcp/decrypted_kdm.h> #include <dcp/locale_convert.h> @@ -93,25 +95,23 @@ DCPOMATIC_ENABLE_WARNINGS #include "i18n.h" -using std::string; -using std::wstring; -using std::setfill; -using std::ostream; + +using std::bad_alloc; +using std::cout; using std::endl; -using std::vector; -using std::min; -using std::max; -using std::map; -using std::list; -using std::multimap; using std::istream; +using std::list; +using std::make_pair; +using std::make_shared; +using std::map; +using std::min; +using std::ostream; using std::pair; -using std::cout; -using std::bad_alloc; using std::set_terminate; -using std::make_pair; using std::shared_ptr; -using std::make_shared; +using std::string; +using std::vector; +using std::wstring; using boost::thread; using boost::optional; using boost::lexical_cast; @@ -122,6 +122,7 @@ using dcp::raw_convert; using dcp::locale_convert; using namespace dcpomatic; + /** Path to our executable, required by the stacktrace stuff and filled * in during App::onInit(). */ @@ -956,7 +957,7 @@ emit_subtitle_image (ContentTimePeriod period, dcp::SubtitleImage sub, dcp::Size { /* XXX: this is rather inefficient; decoding the image just to get its size */ FFmpegImageProxy proxy (sub.png_image()); - auto image = proxy.image(false).image; + auto image = proxy.image(Image::Alignment::COMPACT).image; /* set up rect with height and width */ dcpomatic::Rect<double> rect(0, 0, image->size().width / double(size.width), image->size().height / double(size.height)); diff --git a/src/lib/video_filter_graph.cc b/src/lib/video_filter_graph.cc index b4198da72..0c7e23b05 100644 --- a/src/lib/video_filter_graph.cc +++ b/src/lib/video_filter_graph.cc @@ -38,7 +38,6 @@ using std::make_shared; using std::pair; using std::shared_ptr; using std::string; -using std::vector; VideoFilterGraph::VideoFilterGraph (dcp::Size s, AVPixelFormat p, dcp::Fraction r) @@ -59,7 +58,7 @@ VideoFilterGraph::process (AVFrame* frame) list<pair<shared_ptr<Image>, int64_t>> images; if (_copy) { - images.push_back (make_pair(make_shared<Image>(frame, true), frame->best_effort_timestamp)); + images.push_back (make_pair(make_shared<Image>(frame, Image::Alignment::PADDED), frame->best_effort_timestamp)); } else { int r = av_buffersrc_write_frame (_buffer_src_context, frame); if (r < 0) { @@ -71,7 +70,7 @@ VideoFilterGraph::process (AVFrame* frame) break; } - images.push_back (make_pair(make_shared<Image>(_frame, true), frame->best_effort_timestamp)); + images.push_back (make_pair(make_shared<Image>(_frame, Image::Alignment::PADDED), frame->best_effort_timestamp)); av_frame_unref (_frame); } } |
