From 454cb1717fbd4b909dc88480e86d28d246993938 Mon Sep 17 00:00:00 2001
From: philippegorley <philippe.gorley@savoirfairelinux.com>
Date: Tue, 29 May 2018 10:11:23 -0400
Subject: [PATCH] filter: get output stream properties

Change-Id: I6f1ebfc9d967452fe7d7c7e72e32cf795ae2d85a
Reviewed-by: Sebastien Blin <sebastien.blin@savoirfairelinux.com>
---
 src/media/media_filter.cpp                | 35 +++++++++++++
 src/media/media_filter.h                  | 11 +++-
 test/unitTest/media/test_media_filter.cpp | 62 +++++++++++++++++++++++
 3 files changed, 107 insertions(+), 1 deletion(-)

diff --git a/src/media/media_filter.cpp b/src/media/media_filter.cpp
index 9d49018a94..57c3b734a5 100644
--- a/src/media/media_filter.cpp
+++ b/src/media/media_filter.cpp
@@ -121,6 +121,41 @@ MediaFilter::initialize(const std::string& filterDesc, std::vector<MediaStream>
     return 0;
 }
 
+MediaStream
+MediaFilter::getOutputParams()
+{
+    MediaStream output;
+    if (!output_ || !initialized_) {
+        fail("Filter not initialized", -1);
+        return output;
+    }
+
+    switch (av_buffersink_get_type(output_)) {
+    case AVMEDIA_TYPE_VIDEO:
+        output.name = "videoOutput";
+        output.format = av_buffersink_get_format(output_);
+        output.isVideo = true;
+        output.timeBase = av_buffersink_get_time_base(output_);
+        output.width = av_buffersink_get_w(output_);
+        output.height = av_buffersink_get_h(output_);
+        output.aspectRatio = av_buffersink_get_sample_aspect_ratio(output_);
+        output.frameRate = av_buffersink_get_frame_rate(output_);
+        break;
+    case AVMEDIA_TYPE_AUDIO:
+        output.name = "audioOutput";
+        output.format = av_buffersink_get_format(output_);
+        output.isVideo = false;
+        output.timeBase = av_buffersink_get_time_base(output_);
+        output.sampleRate = av_buffersink_get_sample_rate(output_);
+        output.nbChannels = av_buffersink_get_channels(output_);
+        break;
+    default:
+        output.format = -1;
+        break;
+    }
+    return output;
+}
+
 int
 MediaFilter::feedInput(AVFrame* frame)
 {
diff --git a/src/media/media_filter.h b/src/media/media_filter.h
index aa51a43fed..518a791224 100644
--- a/src/media/media_filter.h
+++ b/src/media/media_filter.h
@@ -78,6 +78,13 @@ class MediaFilter {
          */
         int initialize(const std::string& filterDesc, std::vector<MediaStream> msps);
 
+        /**
+         * Returns a MediaStream struct describing the frames that will be output.
+         *
+         * When called in an invalid state, the returned format will be invalid (less than 0).
+         */
+        MediaStream getOutputParams();
+
         /**
          * Give the filter graph an input frame. Caller is responsible for freeing the frame.
          *
@@ -97,8 +104,10 @@ class MediaFilter {
          * Pull a frame from the filter graph. Caller owns the frame reference.
          *
          * Returns AVERROR(EAGAIN) if filter graph requires more input.
+         *
+         * NOTE Frame reference belongs to the caller
          */
-        AVFrame* readOutput(); // frame reference belongs to caller
+        AVFrame* readOutput();
 
     private:
         NON_COPYABLE(MediaFilter);
diff --git a/test/unitTest/media/test_media_filter.cpp b/test/unitTest/media/test_media_filter.cpp
index 82d5f87f19..a7a42592be 100644
--- a/test/unitTest/media/test_media_filter.cpp
+++ b/test/unitTest/media/test_media_filter.cpp
@@ -41,11 +41,15 @@ private:
     void testSimpleVideoFilter();
     void testSimpleAudioFilter();
     void testComplexVideoFilter();
+    void testSimpleFilterParams();
+    void testComplexFilterParams();
 
     CPPUNIT_TEST_SUITE(MediaFilterTest);
     CPPUNIT_TEST(testSimpleVideoFilter);
     CPPUNIT_TEST(testSimpleAudioFilter);
     CPPUNIT_TEST(testComplexVideoFilter);
+    CPPUNIT_TEST(testSimpleFilterParams);
+    CPPUNIT_TEST(testComplexFilterParams);
     CPPUNIT_TEST_SUITE_END();
 
     std::unique_ptr<MediaFilter> filter_;
@@ -235,6 +239,64 @@ MediaFilterTest::testComplexVideoFilter()
     CPPUNIT_ASSERT(frame_->width == width1 && frame_->height == height1);
 }
 
+void
+MediaFilterTest::testSimpleFilterParams()
+{
+    std::string filterSpec = "scale=200x100";
+
+    // constants
+    const constexpr int width = 320;
+    const constexpr int height = 240;
+    const constexpr AVPixelFormat format = AV_PIX_FMT_YUV420P;
+
+    // construct the filter parameters
+    rational<int> one = rational<int>(1);
+    auto params = MediaStream("vf", format, one, width, height, one, one);
+
+    // returned params should be invalid
+    CPPUNIT_ASSERT(filter_->getOutputParams().format < 0);
+
+    // prepare filter
+    CPPUNIT_ASSERT(filter_->initialize(filterSpec, params) >= 0);
+
+    // output params should now be valid
+    auto ms = filter_->getOutputParams();
+    CPPUNIT_ASSERT(ms.format >= 0 && ms.width > 0 && ms.height > 0);
+}
+
+void
+MediaFilterTest::testComplexFilterParams()
+{
+    std::string filterSpec = "[main] [top] overlay=main_w-overlay_w-10:main_h-overlay_h-10";
+    std::string main = "main";
+    std::string top = "top";
+
+    // constants
+    const constexpr int width1 = 320;
+    const constexpr int height1 = 240;
+    const constexpr int width2 = 30;
+    const constexpr int height2 = 30;
+    const constexpr AVPixelFormat format = AV_PIX_FMT_YUV420P;
+
+    // construct the filter parameters
+    rational<int> one = rational<int>(1);
+    auto params1 = MediaStream("main", format, one, width1, height1, one, one);
+    auto params2 = MediaStream("top", format, one, width2, height2, one, one);
+
+    // returned params should be invalid
+    CPPUNIT_ASSERT(filter_->getOutputParams().format < 0);
+
+    // prepare filter
+    auto vec = std::vector<MediaStream>();
+    vec.push_back(params2); // order does not matter, as long as names match
+    vec.push_back(params1);
+    CPPUNIT_ASSERT(filter_->initialize(filterSpec, vec) >= 0);
+
+    // output params should now be valid
+    auto ms = filter_->getOutputParams();
+    CPPUNIT_ASSERT(ms.format >= 0 && ms.width == width1 && ms.height == height1);
+}
+
 }} // namespace ring::test
 
 RING_TEST_RUNNER(ring::test::MediaFilterTest::name());
-- 
GitLab