blob: 4a2a85f0ad53f5eb88822d75f43dc0b716d5c81d [file] [log] [blame]
agsantosd09cc6d2020-11-06 17:34:46 -05001/**
Sébastien Blincb783e32021-02-12 11:34:10 -05002 * Copyright (C) 2020-2021 Savoir-faire Linux Inc.
agsantosd09cc6d2020-11-06 17:34:46 -05003 *
4 * Author: Aline Gondim Santos <aline.gondimsantos@savoirfairelinux.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21#include "CoinCircleVideoSubscriber.h"
22
23extern "C" {
24#include <libavutil/display.h>
25}
26#include <accel.h>
agsantosc9181b42020-11-26 12:03:04 -050027#include <frameUtils.h>
agsantosd09cc6d2020-11-06 17:34:46 -050028#include <pluglog.h>
agsantosd09cc6d2020-11-06 17:34:46 -050029#include <stdio.h>
30#include <opencv2/imgproc.hpp>
31
32const std::string TAG = "CoinCircle";
33const char sep = separator();
34
35namespace jami {
36
37CoinCircleVideoSubscriber::CoinCircleVideoSubscriber(const std::string& dataPath)
38 : path_ {dataPath}
39{}
40
41CoinCircleVideoSubscriber::~CoinCircleVideoSubscriber()
42{
43 std::ostringstream oss;
44 oss << "~CoinCircleMediaProcessor" << std::endl;
45 Plog::log(Plog::LogPriority::INFO, TAG, oss.str());
46}
47
48void
agsantosc9181b42020-11-26 12:03:04 -050049CoinCircleVideoSubscriber::update(jami::Observable<AVFrame*>*, AVFrame* const& pluginFrame)
agsantosd09cc6d2020-11-06 17:34:46 -050050{
agsantosc9181b42020-11-26 12:03:04 -050051 if (!pluginFrame)
agsantosd09cc6d2020-11-06 17:34:46 -050052 return;
agsantosd09cc6d2020-11-06 17:34:46 -050053
54 //======================================================================================
55 // GET FRAME ROTATION
agsantosc9181b42020-11-26 12:03:04 -050056 AVFrameSideData* side_data = av_frame_get_side_data(pluginFrame, AV_FRAME_DATA_DISPLAYMATRIX);
agsantosd09cc6d2020-11-06 17:34:46 -050057
58 int angle {0};
59 if (side_data) {
60 auto matrix_rotation = reinterpret_cast<int32_t*>(side_data->data);
61 angle = static_cast<int>(av_display_rotation_get(matrix_rotation));
62 }
63
64 //======================================================================================
65 // GET RAW FRAME
66 // Use a non-const Frame
67 // Convert input frame to RGB
68 int inputHeight = pluginFrame->height;
69 int inputWidth = pluginFrame->width;
agsantosc9181b42020-11-26 12:03:04 -050070 AVFrame* temp = transferToMainMemory(pluginFrame, AV_PIX_FMT_NV12);
71 AVFrame* bgrFrame = scaler.convertFormat(temp, AV_PIX_FMT_RGB24);
72 av_frame_unref(temp);
73 av_frame_free(&temp);
74 if (!bgrFrame)
75 return;
agsantosd09cc6d2020-11-06 17:34:46 -050076 resultFrame = cv::Mat {bgrFrame->height,
77 bgrFrame->width,
78 CV_8UC3,
79 bgrFrame->data[0],
80 static_cast<size_t>(bgrFrame->linesize[0])};
81
82 // First clone the frame as the original one is unusable because of
83 // linespace
84 processingFrame = resultFrame.clone();
85
86 if (firstRun) {
87 // we set were the circle will be draw.
88 int w = resultFrame.size().width;
89 int h = resultFrame.size().height;
90 radius = std::min(w, h) / 8;
91 circlePos.y = static_cast<int>(radius);
92 circlePos.x = static_cast<int>(radius);
93 firstRun = false;
94 }
95
96 drawCoinCircle(angle);
97 copyByLine(bgrFrame->linesize[0]);
98
99 //======================================================================================
100 // REPLACE AVFRAME DATA WITH FRAME DATA
agsantosc9181b42020-11-26 12:03:04 -0500101 if (bgrFrame->data[0]) {
agsantosd09cc6d2020-11-06 17:34:46 -0500102 uint8_t* frameData = bgrFrame->data[0];
103 if (angle == 90 || angle == -90) {
104 std::memmove(frameData,
105 resultFrame.data,
106 static_cast<size_t>(pluginFrame->width * pluginFrame->height * 3)
107 * sizeof(uint8_t));
108 }
agsantosd09cc6d2020-11-06 17:34:46 -0500109
agsantosc9181b42020-11-26 12:03:04 -0500110 av_frame_copy_props(bgrFrame, pluginFrame);
111 moveFrom(pluginFrame, bgrFrame);
112 }
113 av_frame_unref(bgrFrame);
114 av_frame_free(&bgrFrame);
agsantosd09cc6d2020-11-06 17:34:46 -0500115}
116
117void
118CoinCircleVideoSubscriber::drawCoinCircle(const int angle)
119{
120 if (!processingFrame.empty()) {
121 rotateFrame(angle, processingFrame);
122 cv::circle(processingFrame, circlePos, radius, baseColor, cv::FILLED);
123 rotateFrame(-angle, processingFrame);
124 }
125}
126
127void
128CoinCircleVideoSubscriber::rotateFrame(const int angle, cv::Mat& frame)
129{
130 if (angle == -90)
131 cv::rotate(frame, frame, cv::ROTATE_90_COUNTERCLOCKWISE);
132 else if (std::abs(angle) == 180)
133 cv::rotate(frame, frame, cv::ROTATE_180);
134 else if (angle == 90)
135 cv::rotate(frame, frame, cv::ROTATE_90_CLOCKWISE);
136}
137
138void
139CoinCircleVideoSubscriber::setColor(const std::string& color)
140{
141 int r, g, b = 0;
142 std::sscanf(color.c_str(), "#%02x%02x%02x", &r, &g, &b);
143 baseColor = cv::Scalar(r, g, b);
144 Plog::log(Plog::LogPriority::INFO, TAG, "Color set to: " + color);
145}
146
147void
148CoinCircleVideoSubscriber::copyByLine(const int lineSize)
149{
150 if (3 * processingFrame.cols == lineSize) {
151 std::memcpy(resultFrame.data,
152 processingFrame.data,
153 processingFrame.rows * processingFrame.cols * 3);
154 } else {
155 int rows = processingFrame.rows;
156 int offset = 0;
157 int frameOffset = 0;
158 for (int i = 0; i < rows; i++) {
159 std::memcpy(resultFrame.data + offset, processingFrame.data + frameOffset, lineSize);
160 offset += lineSize;
161 frameOffset += 3 * processingFrame.cols;
162 }
163 }
164}
165
166void
167CoinCircleVideoSubscriber::attached(jami::Observable<AVFrame*>* observable)
168{
169 std::ostringstream oss;
170 oss << "::Attached ! " << std::endl;
171 Plog::log(Plog::LogPriority::INFO, TAG, oss.str());
172 observable_ = observable;
173}
174
175void
176CoinCircleVideoSubscriber::detached(jami::Observable<AVFrame*>*)
177{
178 firstRun = true;
179 observable_ = nullptr;
180 std::ostringstream oss;
181 oss << "::Detached()" << std::endl;
182 Plog::log(Plog::LogPriority::INFO, TAG, oss.str());
183}
184
185void
186CoinCircleVideoSubscriber::detach()
187{
188 if (observable_) {
189 firstRun = true;
190 std::ostringstream oss;
191 oss << "::Calling detach()" << std::endl;
192 Plog::log(Plog::LogPriority::INFO, TAG, oss.str());
193 observable_->detach(this);
194 }
195}
196} // namespace jami