tutorial: HelloWorld
Change-Id: Ie19a7749ba028ceda16a2479398645daeb08f277
diff --git a/HelloWorld/CenterCircleVideoSubscriber.cpp b/HelloWorld/CenterCircleVideoSubscriber.cpp
new file mode 100644
index 0000000..b1e1377
--- /dev/null
+++ b/HelloWorld/CenterCircleVideoSubscriber.cpp
@@ -0,0 +1,187 @@
+/**
+ * Copyright (C) 2020 Savoir-faire Linux Inc.
+ *
+ * Author: Aline Gondim Santos <aline.gondimsantos@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 "CenterCircleVideoSubscriber.h"
+
+extern "C" {
+#include <libavutil/display.h>
+}
+#include <accel.h>
+
+// LOGGING
+#include <pluglog.h>
+
+#include <stdio.h>
+#include <opencv2/imgproc.hpp>
+
+const std::string TAG = "CenterCircle";
+const char sep = separator();
+
+namespace jami {
+
+CenterCircleVideoSubscriber::CenterCircleVideoSubscriber(const std::string& dataPath)
+ : path_ {dataPath}
+{}
+
+CenterCircleVideoSubscriber::~CenterCircleVideoSubscriber()
+{
+ std::ostringstream oss;
+ oss << "~CenterCircleMediaProcessor" << std::endl;
+ Plog::log(Plog::LogPriority::INFO, TAG, oss.str());
+}
+
+void
+CenterCircleVideoSubscriber::update(jami::Observable<AVFrame*>*, AVFrame* const& iFrame)
+{
+ if (!iFrame)
+ return;
+ AVFrame* pluginFrame = const_cast<AVFrame*>(iFrame);
+
+ //======================================================================================
+ // GET FRAME ROTATION
+ AVFrameSideData* side_data = av_frame_get_side_data(iFrame, AV_FRAME_DATA_DISPLAYMATRIX);
+
+ int angle {0};
+ if (side_data) {
+ auto matrix_rotation = reinterpret_cast<int32_t*>(side_data->data);
+ angle = static_cast<int>(av_display_rotation_get(matrix_rotation));
+ }
+
+ //======================================================================================
+ // GET RAW FRAME
+ // Use a non-const Frame
+ // Convert input frame to RGB
+ int inputHeight = pluginFrame->height;
+ int inputWidth = pluginFrame->width;
+
+ FrameUniquePtr bgrFrame = scaler.convertFormat(transferToMainMemory(pluginFrame,
+ AV_PIX_FMT_NV12),
+ AV_PIX_FMT_RGB24);
+ resultFrame = cv::Mat {bgrFrame->height,
+ bgrFrame->width,
+ CV_8UC3,
+ bgrFrame->data[0],
+ static_cast<size_t>(bgrFrame->linesize[0])};
+
+ // First clone the frame as the original one is unusable because of
+ // linespace
+ processingFrame = resultFrame.clone();
+
+ if (firstRun) {
+ // we set were the circle will be draw.
+ circlePos.y = static_cast<int>(inputHeight / 2);
+ circlePos.x = static_cast<int>(inputWidth / 2);
+ int w = resultFrame.size().width;
+ int h = resultFrame.size().height;
+ radius = std::min(w, h) / 8;
+ firstRun = false;
+ }
+
+ drawCenterCircle();
+ copyByLine(bgrFrame->linesize[0]);
+
+ //======================================================================================
+ // REPLACE AVFRAME DATA WITH FRAME DATA
+ if (bgrFrame && bgrFrame->data[0]) {
+ uint8_t* frameData = bgrFrame->data[0];
+ if (angle == 90 || angle == -90) {
+ std::memmove(frameData,
+ resultFrame.data,
+ static_cast<size_t>(pluginFrame->width * pluginFrame->height * 3)
+ * sizeof(uint8_t));
+ }
+ }
+ // Copy Frame meta data
+ if (bgrFrame && pluginFrame) {
+ av_frame_copy_props(bgrFrame.get(), pluginFrame);
+ scaler.moveFrom(pluginFrame, bgrFrame.get());
+ }
+
+ // Remove the pointer
+ pluginFrame = nullptr;
+}
+
+void
+CenterCircleVideoSubscriber::setColor(const std::string& color)
+{
+ int r, g, b = 0;
+ std::sscanf(color.c_str(), "#%02x%02x%02x", &r, &g, &b);
+ baseColor = cv::Scalar(r, g, b);
+ Plog::log(Plog::LogPriority::INFO, TAG, "Color set to: " + color);
+}
+
+void
+CenterCircleVideoSubscriber::copyByLine(const int lineSize)
+{
+ if (3 * processingFrame.cols == lineSize) {
+ std::memcpy(resultFrame.data,
+ processingFrame.data,
+ processingFrame.rows * processingFrame.cols * 3);
+ } else {
+ int rows = processingFrame.rows;
+ int offset = 0;
+ int frameOffset = 0;
+ for (int i = 0; i < rows; i++) {
+ std::memcpy(resultFrame.data + offset, processingFrame.data + frameOffset, lineSize);
+ offset += lineSize;
+ frameOffset += 3 * processingFrame.cols;
+ }
+ }
+}
+
+void
+CenterCircleVideoSubscriber::drawCenterCircle()
+{
+ if (!processingFrame.empty()) {
+ cv::circle(processingFrame, circlePos, radius, baseColor, cv::FILLED);
+ }
+}
+
+void
+CenterCircleVideoSubscriber::attached(jami::Observable<AVFrame*>* observable)
+{
+ std::ostringstream oss;
+ oss << "::Attached ! " << std::endl;
+ Plog::log(Plog::LogPriority::INFO, TAG, oss.str());
+ observable_ = observable;
+}
+
+void
+CenterCircleVideoSubscriber::detached(jami::Observable<AVFrame*>*)
+{
+ firstRun = true;
+ observable_ = nullptr;
+ std::ostringstream oss;
+ oss << "::Detached()" << std::endl;
+ Plog::log(Plog::LogPriority::INFO, TAG, oss.str());
+}
+
+void
+CenterCircleVideoSubscriber::detach()
+{
+ if (observable_) {
+ firstRun = true;
+ std::ostringstream oss;
+ oss << "::Calling detach()" << std::endl;
+ Plog::log(Plog::LogPriority::INFO, TAG, oss.str());
+ observable_->detach(this);
+ }
+}
+} // namespace jami