| /** |
| * 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> |
| #include <frameUtils.h> |
| #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& pluginFrame) |
| { |
| if (!pluginFrame) |
| return; |
| |
| //====================================================================================== |
| // GET FRAME ROTATION |
| AVFrameSideData* side_data = av_frame_get_side_data(pluginFrame, 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)); |
| } |
| delete side_data; |
| |
| //====================================================================================== |
| // GET RAW FRAME |
| // Use a non-const Frame |
| // Convert input frame to RGB |
| int inputHeight = pluginFrame->height; |
| int inputWidth = pluginFrame->width; |
| AVFrame* temp = transferToMainMemory(pluginFrame, AV_PIX_FMT_NV12); |
| AVFrame* bgrFrame = scaler.convertFormat(temp, AV_PIX_FMT_RGB24); |
| av_frame_unref(temp); |
| av_frame_free(&temp); |
| if (!bgrFrame) |
| return; |
| 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->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)); |
| } |
| |
| av_frame_copy_props(bgrFrame, pluginFrame); |
| moveFrom(pluginFrame, bgrFrame); |
| } |
| av_frame_unref(bgrFrame); |
| av_frame_free(&bgrFrame); |
| } |
| |
| 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 |