You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

267 lines
6.8 KiB

//------------------------------------------------------------------------------
//
// Project: Anonymizer
//
// Brno University of Technology
// Faculty of Information Technology
//
//------------------------------------------------------------------------------
//
// This project was financially supported by project VG20102015006 funds
// provided by Ministry of the Interior of the Czech republic.
//
//------------------------------------------------------------------------------
/*!
@file videoframe.cpp
@brief Implementation of methods ...
@details Details
@authors Martin Borek (mborekcz@gmail.com)
@authors Filip Orsag (orsag@fit.vutbr.cz)
@date 2014-2015
@note This project was supported by MV CR project VG20102015006.
@copyright BUT OPEN SOURCE LICENCE (see License.txt)
*/
#include "videoframe.h"
#include <QDebug>
VideoFrame::VideoFrame():
scalingMethod(VIDEOTRACKING_DEFAULT_SCALING_METHOD)
{
matFrame = nullptr;
avFrame = nullptr;
width = 0;
height = 0;
}
VideoFrame::VideoFrame(unsigned int width, unsigned int height):
scalingMethod(VIDEOTRACKING_DEFAULT_SCALING_METHOD),
width(width),
height(height)
{
matFrame = nullptr;
avFrame = nullptr;
}
//VideoFrame::VideoFrame(cv::Mat const &newFrame, int64_t timestamp, unsigned long timePosition):
// Does not copy avFrame because it is not needed and would make it slower
VideoFrame::VideoFrame(VideoFrame const &obj):
scalingMethod(VIDEOTRACKING_DEFAULT_SCALING_METHOD)
{
avFrame = nullptr;
if (obj.matFrame)
matFrame = new cv::Mat(*(obj.matFrame));
else
matFrame = nullptr;
height = obj.height;
width = obj.width;
timestamp = obj.timestamp;
timePosition = obj.timePosition;
}
VideoFrame::~VideoFrame()
{
if (matFrame)
{
delete matFrame;
matFrame = nullptr;
}
if (avFrame)
{
av_free(avFrame->data[0]);
av_frame_free(&avFrame);
avFrame = nullptr;
}
}
bool VideoFrame::set_frame(AVFrame const *newFrame)
{
if (!matFrame) // matFrame is nullptr and was not allocated yet
{
if (!width || !height) // equals one of them zero?
return false;
else
matFrame = new cv::Mat(height, width, CV_8UC3); // CV_8UC3->3 channels of unsigned 8-bit int
}
return AVFrame2Mat(newFrame, matFrame);
}
unsigned long VideoFrame::get_time_position() const
{
return timePosition;
}
int64_t VideoFrame::get_timestamp() const
{
return timestamp;
}
unsigned long VideoFrame::get_frame_number() const
{
return frameNumber;
}
unsigned int VideoFrame::get_width() const
{
return width;
}
unsigned int VideoFrame::get_height() const
{
return height;
}
void VideoFrame::set_size(unsigned int newWidth, unsigned int newHeight)
{
width = newWidth;
height = newHeight;
// size changed -> allocated memory incorrect; free memory; it will be allocated when needed
if (matFrame)
{
delete matFrame;
matFrame = nullptr;
}
}
void VideoFrame::set_timestamp(int64_t newTimestamp)
{
timestamp = newTimestamp;
}
void VideoFrame::set_time_position(unsigned long newTimePosition)
{
timePosition = newTimePosition;
}
void VideoFrame::set_frame_number(unsigned long newFrameNumber)
{
frameNumber = newFrameNumber;
}
AVFrame const *VideoFrame::get_av_frame()
//AVFrame *VideoFrame::get_av_frame()
{
if (matFrame == nullptr) // There is not a valid frame that could be converted to AVFrame
return nullptr;
if (!avFrame)
{
avFrame = av_frame_alloc();
if (avFrame == nullptr)
{
qDebug() << "Not allocated";
exit(1);
}
int numBytes = avpicture_get_size((enum AVPixelFormat)outputFormat, width, height);
if (numBytes < 0)
{
qDebug() << "Error: avpicture_get_size()";
exit(1);
}
uint8_t *buffer = (uint8_t *)av_malloc(numBytes * sizeof(uint8_t));
if (buffer == nullptr)
{
qDebug() << "Not allocated";
exit(1);
}
if (avpicture_fill((AVPicture *)avFrame, buffer, (enum AVPixelFormat)outputFormat, width, height) < 0)
{
qDebug() << "Error: avpicture_fill()";
exit(1);
}
}
Mat2AVFrame(*matFrame, avFrame, outputFormat);
avFrame->pts = timestamp;
return avFrame;
}
cv::Mat const *VideoFrame::get_mat_frame() const
{
return matFrame;
}
// dstMat must be allocated before
bool VideoFrame::AVFrame2Mat(AVFrame const *src, cv::Mat *dstMat) const
{
assert(src != nullptr);
//assert(dstMat != nullptr);
AVFrame *dst = nullptr;
dst = av_frame_alloc(); // Calls also memset, xal
dst->data[0] = (uint8_t *)dstMat->data; //dstMat->data is used as a buffer
// note: avpicture_fill does not perform a deep copy
if (avpicture_fill((AVPicture *)dst, dst->data[0], AV_PIX_FMT_BGR24, src->width, src->height) < 0)
{
qDebug() << "Error - AVFrame2Mat: avpicture_fill";
av_frame_free(&dst);
dst = nullptr;
return false;
}
SwsContext *conversionContext = nullptr; // Context is needed for sws_scale
conversionContext = sws_getContext(src->width, src->height, (enum AVPixelFormat)src->format,
src->width, src->height, AV_PIX_FMT_BGR24,
scalingMethod, NULL, NULL, NULL); // xal
sws_scale(conversionContext, src->data, src->linesize, 0, src->height,
dst->data, dst->linesize);
// free allocated memories
sws_freeContext(conversionContext);
conversionContext = nullptr;
av_frame_free(&dst);
dst = nullptr;
return true;
}
bool VideoFrame::Mat2AVFrame(cv::Mat const &src, AVFrame *dstAVFrame, const int dstFormat) const
{
//assert(src != nullptr);
assert(dstAVFrame != nullptr);
static const int width = src.cols;
static const int height = src.rows;
AVFrame *srcAV = av_frame_alloc(); // Calls also memset, xal
if (srcAV == nullptr)
{
qDebug() << "Not allocated";
return false;
}
avpicture_fill((AVPicture *)srcAV, (uint8_t *)src.data, AV_PIX_FMT_BGR24, width, height);
// all frames have same width, height, format ...
SwsContext *conversionContext = sws_getContext(width, height, AV_PIX_FMT_BGR24,
width, height, (enum AVPixelFormat)dstFormat,
scalingMethod, NULL, NULL, NULL); // xal
sws_scale(conversionContext, srcAV->data, srcAV->linesize, 0, height,
dstAVFrame->data, dstAVFrame->linesize);
// free allocated memories
sws_freeContext(conversionContext);
conversionContext = nullptr;
av_frame_free(&srcAV);
srcAV = nullptr;
return true;
}