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

dring: expose frame wrappers in abi

Makes use of AVFrame's reference counting if possible instead of copying
the data.

Only bumps minor version because MediaFrame et al weren't in the ABI
until now.

Change-Id: I692e76230ed057c1ad4e46ab59ea5cfd163fb98d
parent 65b75a3a
......@@ -2,7 +2,7 @@ dnl Ring - configure.ac for automake 1.9 and autoconf 2.59
dnl Process this file with autoconf to produce a configure script.
AC_PREREQ([2.65])
AC_INIT([Ring Daemon],[6.0.0],[ring@gnu.org],[ring])
AC_INIT([Ring Daemon],[6.1.0],[ring@gnu.org],[ring])
AC_COPYRIGHT([[Copyright (c) Savoir-faire Linux 2004-2018]])
AC_REVISION([$Revision$])
......
......@@ -31,7 +31,7 @@ PROJECT_NAME = "Ring Daemon"
# This could be handy for archiving the generated documentation or
# if some version control system is used.
PROJECT_NUMBER = 6.0.0
PROJECT_NUMBER = 6.1.0
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer
......
......@@ -52,6 +52,13 @@ MediaFrame::MediaFrame()
throw std::bad_alloc();
}
void
MediaFrame::copyFrom(MediaFrame& o)
{
reset();
av_frame_ref(frame_.get(), o.frame_.get());
}
void
MediaFrame::reset() noexcept
{
......@@ -72,6 +79,14 @@ VideoFrame::reset() noexcept
releaseBufferCb_ = {};
}
void
VideoFrame::copyFrom(VideoFrame& o)
{
MediaFrame::copyFrom(o);
ptr_ = o.ptr_;
allocated_ = o.allocated_;
}
size_t
VideoFrame::size() const noexcept
{
......@@ -154,7 +169,6 @@ VideoFrame::setReleaseCb(std::function<void(uint8_t*)> cb) noexcept
}
}
void
VideoFrame::noise()
{
......@@ -166,17 +180,6 @@ VideoFrame::noise()
}
}
VideoFrame&
VideoFrame::operator =(const VideoFrame& src)
{
reserve(src.format(), src.width(), src.height());
auto source = src.pointer();
av_image_copy(frame_->data, frame_->linesize, (const uint8_t **)source->data,
source->linesize, (AVPixelFormat)frame_->format,
frame_->width, frame_->height);
return *this;
}
VideoFrame* getNewFrame()
{
if (auto input = ring::Manager::instance().getVideoManager().videoInput.lock())
......
......@@ -64,16 +64,23 @@ struct DRING_PUBLIC SinkTarget {
std::function<void(FrameBufferPtr)> push;
};
class MediaFrame {
class DRING_PUBLIC MediaFrame {
public:
// Construct an empty MediaFrame
MediaFrame();
MediaFrame(const MediaFrame&) = delete;
MediaFrame& operator =(const MediaFrame& o) = delete;
MediaFrame(MediaFrame&& o) = delete;
MediaFrame& operator =(MediaFrame&& o) = delete;
virtual ~MediaFrame() = default;
// Return a pointer on underlaying buffer
AVFrame* pointer() const noexcept { return frame_.get(); }
// Fill this MediaFrame with data from o
void copyFrom(MediaFrame& o);
// Reset internal buffers (return to an empty MediaFrame)
virtual void reset() noexcept;
......@@ -81,17 +88,20 @@ protected:
std::unique_ptr<AVFrame, void(*)(AVFrame*)> frame_;
};
struct AudioFrame: MediaFrame {};
class DRING_PUBLIC AudioFrame : public MediaFrame {};
class VideoFrame: public MediaFrame {
class DRING_PUBLIC VideoFrame : public MediaFrame {
public:
// Construct an empty VideoFrame
VideoFrame() = default;
VideoFrame() : MediaFrame() {}
~VideoFrame();
// Reset internal buffers (return to an empty VideoFrame)
void reset() noexcept override;
// Fill this VideoFrame with data from o
void copyFrom(VideoFrame& o);
// Return frame size in bytes
std::size_t size() const noexcept;
......@@ -115,9 +125,6 @@ public:
void noise();
// Copy-Assignement
VideoFrame& operator =(const VideoFrame& src);
private:
std::function<void(uint8_t*)> releaseBufferCb_ {};
uint8_t* ptr_ {nullptr};
......
......@@ -111,7 +111,7 @@ VideoMixer::update(Observable<std::shared_ptr<VideoFrame>>* ob,
x->update_frame.reset(new VideoFrame);
else
x->update_frame->reset();
*x->update_frame = *frame_p; // copy frame content, it will be destroyed after return
x->update_frame->copyFrom(*frame_p); // copy frame content, it will be destroyed after return
x->atomic_swap_render(x->update_frame);
return;
}
......
......@@ -92,4 +92,10 @@ ut_media_filter_SOURCES = media/test_media_filter.cpp
check_PROGRAMS += ut_resampler
ut_resampler_SOURCES = media/audio/test_resampler.cpp
#
# media_frame
#
check_PROGRAMS += ut_media_frame
ut_media_frame_SOURCES = media/test_media_frame.cpp
TESTS = $(check_PROGRAMS)
/*
* Copyright (C) 2018 Savoir-faire Linux Inc.
*
* Author: Philippe Gorley <philippe.gorley@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <cppunit/TestAssert.h>
#include <cppunit/TestFixture.h>
#include <cppunit/extensions/HelperMacros.h>
extern "C" {
#include <libavutil/frame.h>
#include <libavutil/pixfmt.h>
}
#include "dring.h"
#include "videomanager_interface.h"
#include "../../test_runner.h"
namespace ring { namespace test {
class MediaFrameTest : public CppUnit::TestFixture {
public:
static std::string name() { return "media_frame"; }
void setUp();
void tearDown();
private:
void testCopy();
CPPUNIT_TEST_SUITE(MediaFrameTest);
CPPUNIT_TEST(testCopy);
CPPUNIT_TEST_SUITE_END();
};
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(MediaFrameTest, MediaFrameTest::name());
void
MediaFrameTest::setUp()
{
DRing::init(DRing::InitFlag(DRing::DRING_FLAG_DEBUG | DRing::DRING_FLAG_CONSOLE_LOG));
}
void
MediaFrameTest::tearDown()
{
DRing::fini();
}
void
MediaFrameTest::testCopy()
{
// test allocation
DRing::VideoFrame v1;
v1.reserve(AV_PIX_FMT_YUV420P, 100, 100);
v1.pointer()->data[0][0] = 42;
CPPUNIT_ASSERT(v1.pointer());
// test frame referencing (different pointers, but same data)
DRing::VideoFrame v2;
v2.copyFrom(v1);
CPPUNIT_ASSERT(v1.format() == v2.format());
CPPUNIT_ASSERT(v1.width() == v2.width());
CPPUNIT_ASSERT(v1.height() == v2.height());
CPPUNIT_ASSERT(v1.pointer() != v2.pointer());
CPPUNIT_ASSERT(v1.pointer()->data[0][0] == 42);
CPPUNIT_ASSERT(v2.pointer()->data[0][0] == 42);
}
}} // namespace ring::test
RING_TEST_RUNNER(ring::test::MediaFrameTest::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