Commit 98518e99 authored by Philippe Gorley's avatar Philippe Gorley Committed by Adrien Béraud

filter: add automatic reinitialization

If one of the inputs has changed, the filter will reinitialize itself.

Change-Id: I884195b6fdf19ad72329364eeeefd33e3b3bbfff
parent 2c64e35a
...@@ -155,19 +155,27 @@ MediaFilter::getOutputParams() const ...@@ -155,19 +155,27 @@ MediaFilter::getOutputParams() const
} }
int int
MediaFilter::feedInput(AVFrame* frame, std::string inputName) MediaFilter::feedInput(AVFrame* frame, const std::string& inputName)
{ {
int ret = 0; int ret = 0;
if (!initialized_) if (!initialized_)
return fail("Filter not initialized", -1); return fail("Filter not initialized", -1);
for (size_t i = 0; i < inputs_.size(); ++i) { for (size_t i = 0; i < inputs_.size(); ++i) {
auto filterCtx = inputs_[i]; auto& ms = inputParams_[i];
if (inputParams_[i].name != inputName) if (ms.name != inputName)
continue; continue;
if (ms.format != frame->format
|| (ms.isVideo && (ms.width != frame->width || ms.height != frame->height))
|| (!ms.isVideo && (ms.sampleRate != frame->sample_rate || ms.nbChannels != frame->channels))) {
ms.update(frame);
if ((ret = reinitialize()) < 0)
return fail("Failed to reinitialize filter with new input parameters", ret);
}
int flags = AV_BUFFERSRC_FLAG_PUSH | AV_BUFFERSRC_FLAG_KEEP_REF; int flags = AV_BUFFERSRC_FLAG_PUSH | AV_BUFFERSRC_FLAG_KEEP_REF;
if ((ret = av_buffersrc_add_frame_flags(filterCtx, frame, flags)) < 0) if ((ret = av_buffersrc_add_frame_flags(inputs_[i], frame, flags)) < 0)
return fail("Could not pass frame to filters", ret); return fail("Could not pass frame to filters", ret);
else else
return 0; return 0;
...@@ -281,6 +289,19 @@ MediaFilter::initInputFilter(AVFilterInOut* in, MediaStream msp) ...@@ -281,6 +289,19 @@ MediaFilter::initInputFilter(AVFilterInOut* in, MediaStream msp)
return ret; return ret;
} }
int
MediaFilter::reinitialize()
{
// keep parameters needed for initialization before clearing filter
auto params = std::move(inputParams_);
auto desc = std::move(desc_);
clean();
auto ret = initialize(desc, params);
if (ret >= 0)
RING_DBG() << "Filter graph reinitialized";
return ret;
}
int int
MediaFilter::fail(std::string msg, int err) const MediaFilter::fail(std::string msg, int err) const
{ {
...@@ -292,8 +313,12 @@ MediaFilter::fail(std::string msg, int err) const ...@@ -292,8 +313,12 @@ MediaFilter::fail(std::string msg, int err) const
void void
MediaFilter::clean() MediaFilter::clean()
{ {
avfilter_graph_free(&graph_);
initialized_ = false; initialized_ = false;
avfilter_graph_free(&graph_); // frees inputs_ and output_
desc_.clear();
inputs_.clear(); // don't point to freed memory
output_ = nullptr; // don't point to freed memory
inputParams_.clear();
} }
} // namespace ring } // namespace ring
...@@ -88,7 +88,7 @@ class MediaFilter { ...@@ -88,7 +88,7 @@ class MediaFilter {
* *
* NOTE Will fail if @inputName is not found in the graph. * NOTE Will fail if @inputName is not found in the graph.
*/ */
int feedInput(AVFrame* frame, std::string inputName); int feedInput(AVFrame* frame, const std::string& inputName);
/** /**
* Pull a frame from the filter graph. Caller owns the frame reference. * Pull a frame from the filter graph. Caller owns the frame reference.
...@@ -112,6 +112,11 @@ class MediaFilter { ...@@ -112,6 +112,11 @@ class MediaFilter {
*/ */
int initInputFilter(AVFilterInOut* in, MediaStream msp); int initInputFilter(AVFilterInOut* in, MediaStream msp);
/**
* Reinitializes the filter graph with @inputParams_, which should be updated beforehand.
*/
int reinitialize();
/** /**
* Convenience method that prints @msg and returns err. * Convenience method that prints @msg and returns err.
* *
......
...@@ -41,11 +41,13 @@ private: ...@@ -41,11 +41,13 @@ private:
void testAudioFilter(); void testAudioFilter();
void testVideoFilter(); void testVideoFilter();
void testFilterParams(); void testFilterParams();
void testReinit();
CPPUNIT_TEST_SUITE(MediaFilterTest); CPPUNIT_TEST_SUITE(MediaFilterTest);
CPPUNIT_TEST(testAudioFilter); CPPUNIT_TEST(testAudioFilter);
CPPUNIT_TEST(testVideoFilter); CPPUNIT_TEST(testVideoFilter);
CPPUNIT_TEST(testFilterParams); CPPUNIT_TEST(testFilterParams);
CPPUNIT_TEST(testReinit);
CPPUNIT_TEST_SUITE_END(); CPPUNIT_TEST_SUITE_END();
std::unique_ptr<MediaFilter> filter_; std::unique_ptr<MediaFilter> filter_;
...@@ -240,6 +242,36 @@ MediaFilterTest::testFilterParams() ...@@ -240,6 +242,36 @@ MediaFilterTest::testFilterParams()
CPPUNIT_ASSERT(ms.format >= 0 && ms.width == width1 && ms.height == height1); CPPUNIT_ASSERT(ms.format >= 0 && ms.width == width1 && ms.height == height1);
} }
void
MediaFilterTest::testReinit()
{
std::string filterSpec = "[in1] aresample=48000";
// prepare audio frame
frame_ = av_frame_alloc();
frame_->format = AV_SAMPLE_FMT_S16;
frame_->channel_layout = AV_CH_LAYOUT_STEREO;
frame_->nb_samples = 100;
frame_->sample_rate = 44100;
frame_->channels = 2;
// construct the filter parameters with different sample rate
auto params = MediaStream("in1", frame_->format, rational<int>(1, 16000), 16000, frame_->channels);
// allocate and fill frame buffers
CPPUNIT_ASSERT(av_frame_get_buffer(frame_, 0) >= 0);
fill_samples(reinterpret_cast<uint16_t*>(frame_->data[0]), frame_->sample_rate, frame_->nb_samples, frame_->channels, 440.0);
// prepare filter
std::vector<MediaStream> vec;
vec.push_back(params);
CPPUNIT_ASSERT(filter_->initialize(filterSpec, vec) >= 0);
// filter should reinitialize on feedInput
CPPUNIT_ASSERT(filter_->feedInput(frame_, "in1") >= 0);
av_frame_free(&frame_);
}
}} // namespace ring::test }} // namespace ring::test
RING_TEST_RUNNER(ring::test::MediaFilterTest::name()); RING_TEST_RUNNER(ring::test::MediaFilterTest::name());
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment