From fdd63a4c9925f0339089dce3a52f0d6ed0d97880 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Thu, 2 May 2013 22:15:32 +0100 Subject: [PATCH] Use newer format to specify filter graphs; don't filter unless necessary; fix tiny memory leak. --- src/lib/ffmpeg_decoder.cc | 45 +++++++++++++++++++++++--------------- src/lib/filter_graph.cc | 19 ++++++++-------- src/lib/image.cc | 8 +++++-- src/lib/image.h | 3 ++- test/pixel_formats_test.cc | 2 +- 5 files changed, 45 insertions(+), 32 deletions(-) diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc index 8e09810cb..cd68e5294 100644 --- a/src/lib/ffmpeg_decoder.cc +++ b/src/lib/ffmpeg_decoder.cc @@ -500,32 +500,41 @@ FFmpegDecoder::set_subtitle_stream (shared_ptr s) void FFmpegDecoder::filter_and_emit_video () { - boost::mutex::scoped_lock lm (_filter_graphs_mutex); + int64_t const bet = av_frame_get_best_effort_timestamp (_frame); + if (bet == AV_NOPTS_VALUE) { + _film->log()->log ("Dropping frame without PTS"); + return; + } - shared_ptr graph; - - list >::iterator i = _filter_graphs.begin(); - while (i != _filter_graphs.end() && !(*i)->can_process (libdcp::Size (_frame->width, _frame->height), (AVPixelFormat) _frame->format)) { - ++i; + if (_film->crop() == Crop() && _film->filters().empty()) { + /* No filter graph needed; just emit */ + emit_video (shared_ptr (new FrameImage (_frame, false)), false, bet * av_q2d (_format_context->streams[_video_stream]->time_base)); + return; } + + shared_ptr graph; - if (i == _filter_graphs.end ()) { - graph.reset (new FilterGraph (_film, this, libdcp::Size (_frame->width, _frame->height), (AVPixelFormat) _frame->format)); - _filter_graphs.push_back (graph); - _film->log()->log (String::compose (N_("New graph for %1x%2, pixel format %3"), _frame->width, _frame->height, _frame->format)); - } else { - graph = *i; + { + boost::mutex::scoped_lock lm (_filter_graphs_mutex); + + list >::iterator i = _filter_graphs.begin(); + while (i != _filter_graphs.end() && !(*i)->can_process (libdcp::Size (_frame->width, _frame->height), (AVPixelFormat) _frame->format)) { + ++i; + } + + if (i == _filter_graphs.end ()) { + graph.reset (new FilterGraph (_film, this, libdcp::Size (_frame->width, _frame->height), (AVPixelFormat) _frame->format)); + _filter_graphs.push_back (graph); + _film->log()->log (String::compose (N_("New graph for %1x%2, pixel format %3"), _frame->width, _frame->height, _frame->format)); + } else { + graph = *i; + } } list > images = graph->process (_frame); for (list >::iterator i = images.begin(); i != images.end(); ++i) { - int64_t const bet = av_frame_get_best_effort_timestamp (_frame); - if (bet != AV_NOPTS_VALUE) { - emit_video (*i, false, bet * av_q2d (_format_context->streams[_video_stream]->time_base)); - } else { - _film->log()->log ("Dropping frame without PTS"); - } + emit_video (*i, false, bet * av_q2d (_format_context->streams[_video_stream]->time_base)); } } diff --git a/src/lib/filter_graph.cc b/src/lib/filter_graph.cc index f0c49b37c..2624bc4d7 100644 --- a/src/lib/filter_graph.cc +++ b/src/lib/filter_graph.cc @@ -79,17 +79,14 @@ FilterGraph::FilterGraph (shared_ptr film, FFmpegDecoder* decoder, libdcp: } stringstream a; - a << _size.width << N_(":") - << _size.height << N_(":") - << _pixel_format << N_(":") - << decoder->time_base_numerator() << N_(":") - << decoder->time_base_denominator() << N_(":") - << decoder->sample_aspect_ratio_numerator() << N_(":") - << decoder->sample_aspect_ratio_denominator(); + a << "video_size=" << _size.width << "x" << _size.height << ":" + << "pix_fmt=" << _pixel_format << ":" + << "time_base=" << decoder->time_base_numerator() << "/" << decoder->time_base_denominator() << ":" + << "pixel_aspect=" << decoder->sample_aspect_ratio_numerator() << "/" << decoder->sample_aspect_ratio_denominator(); int r; - if ((r = avfilter_graph_create_filter (&_buffer_src_context, buffer_src, N_("in"), a.str().c_str(), 0, graph)) < 0) { + if ((r = avfilter_graph_create_filter (&_buffer_src_context, buffer_src, "in", a.str().c_str(), 0, graph)) < 0) { throw DecodeError (N_("could not create buffer source")); } @@ -103,6 +100,8 @@ FilterGraph::FilterGraph (shared_ptr film, FFmpegDecoder* decoder, libdcp: throw DecodeError (N_("could not create buffer sink.")); } + av_free (sink_params); + AVFilterInOut* outputs = avfilter_inout_alloc (); outputs->name = av_strdup(N_("in")); outputs->filter_ctx = _buffer_src_context; @@ -133,7 +132,7 @@ list > FilterGraph::process (AVFrame* frame) { list > images; - + if (av_buffersrc_write_frame (_buffer_src_context, frame) < 0) { throw DecodeError (N_("could not push buffer into filter chain.")); } @@ -146,7 +145,7 @@ FilterGraph::process (AVFrame* frame) } /* This takes ownership of the AVFrame */ - images.push_back (shared_ptr (new FrameImage (frame))); + images.push_back (shared_ptr (new FrameImage (frame, true))); } return images; diff --git a/src/lib/image.cc b/src/lib/image.cc index b97291585..1768be924 100644 --- a/src/lib/image.cc +++ b/src/lib/image.cc @@ -576,9 +576,10 @@ SimpleImage::aligned () const return _aligned; } -FrameImage::FrameImage (AVFrame* frame) +FrameImage::FrameImage (AVFrame* frame, bool own) : Image (static_cast (frame->format)) , _frame (frame) + , _own (own) { _line_size = (int *) av_malloc (4 * sizeof (int)); _line_size[0] = _line_size[1] = _line_size[2] = _line_size[3] = 0; @@ -590,7 +591,10 @@ FrameImage::FrameImage (AVFrame* frame) FrameImage::~FrameImage () { - av_frame_free (&_frame); + if (_own) { + av_frame_free (&_frame); + } + av_free (_line_size); } diff --git a/src/lib/image.h b/src/lib/image.h index 39d84fcd4..16fbd28c2 100644 --- a/src/lib/image.h +++ b/src/lib/image.h @@ -106,7 +106,7 @@ private: class FrameImage : public Image { public: - FrameImage (AVFrame *); + FrameImage (AVFrame *, bool); ~FrameImage (); uint8_t ** data () const; @@ -121,6 +121,7 @@ private: FrameImage& operator= (FrameImage const &); AVFrame* _frame; + bool _own; int* _line_size; }; diff --git a/test/pixel_formats_test.cc b/test/pixel_formats_test.cc index e0f6c4373..e8ad725ff 100644 --- a/test/pixel_formats_test.cc +++ b/test/pixel_formats_test.cc @@ -65,7 +65,7 @@ BOOST_AUTO_TEST_CASE (pixel_formats_test) f->width = 640; f->height = 480; f->format = static_cast (i->format); - FrameImage t (f); + FrameImage t (f, true); BOOST_CHECK_EQUAL(t.components(), i->components); BOOST_CHECK_EQUAL(t.lines(0), i->lines[0]); BOOST_CHECK_EQUAL(t.lines(1), i->lines[1]); -- 2.30.2