//------------------------------------------------------------------------------ // // 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 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; }