RetroShare/plugins/VOIP/gui/VideoProcessor.h
2026-02-17 18:56:41 +01:00

197 lines
6.9 KiB
C++

/*******************************************************************************
* plugins/VOIP/gui/VideoProcessor.h *
* *
* Copyright (C) 2012 by Retroshare Team <retroshare.project@gmail.com> *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Affero 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 Affero General Public License for more details. *
* *
* You should have received a copy of the GNU Affero General Public License *
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
* *
*******************************************************************************/
#pragma once
#include <stdint.h>
#include <QImage>
#include "interface/rsVOIP.h"
extern "C" {
#include <libavcodec/avcodec.h>
}
class QVideoOutputDevice ;
template<typename T>
class NetQueue {
std::vector<T> arr;
const unsigned int mask;
std::atomic<unsigned int> mhead;
std::atomic<unsigned int> mtail;
public:
NetQueue(unsigned int size) : arr(size), mask(size - 1), mhead(0), mtail(0) {
if(size & mask) throw std::invalid_argument("size must be a power of 2");
}
bool full() const { return mhead - mtail == arr.size(); }
T& head() { return arr[mhead & mask]; }
void push() { mhead++; }
bool push(const T& e) { return !full() && ((arr[mhead++ & mask] = e), true); }
bool empty() const { return mhead == mtail; }
T& tail() { return arr[mtail & mask]; }
void pop() { mtail++; }
bool pop(T& e) { return !empty() && ((e = arr[mtail++ & mask]), true); }
};
class VideoCodec
{
public:
virtual bool encodeData(const QImage& Image, uint32_t size_hint, NetQueue<RsVOIPDataChunk>& dst) = 0;
virtual bool decodeData(const RsVOIPDataChunk& chunk,QImage& image) = 0;
protected:
static const uint32_t HEADER_SIZE = 0x04 ;
};
// Now derive various image encoding/decoding algorithms.
//
class JPEGVideo: public VideoCodec
{
public:
JPEGVideo() ;
protected:
virtual bool encodeData(const QImage& Image, uint32_t target_encoding_bitrate, NetQueue<RsVOIPDataChunk>& dst) ;
virtual bool decodeData(const RsVOIPDataChunk& chunk, QImage& image) ;
static const uint32_t JPEG_VIDEO_FLAGS_DIFFERENTIAL_FRAME = 0x0001 ;
private:
QImage _decoded_reference_frame ;
QImage _encoded_reference_frame ;
uint32_t _encoded_ref_frame_max_distance ; // max distance between two reference frames.
uint32_t _encoded_ref_frame_count ;
};
struct AVCodec ;
struct AVCodecContext ;
struct AVFrame ;
struct AVPacket ;
class FFmpegVideo: public VideoCodec
{
public:
FFmpegVideo() ;
~FFmpegVideo() ;
protected:
virtual bool encodeData(const QImage& Image, uint32_t target_encoding_bitrate, NetQueue<RsVOIPDataChunk>& dst) ;
virtual bool decodeData(const RsVOIPDataChunk& chunk,QImage& image) ;
private:
const AVCodec *encoding_codec;
const AVCodec *decoding_codec;
AVCodecContext *encoding_context;
AVCodecContext *decoding_context;
AVFrame *encoding_frame_buffer ;
AVFrame *decoding_frame_buffer ;
AVPacket decoding_buffer;
uint64_t encoding_frame_count ;
#ifdef DEBUG_MPEG_VIDEO
FILE *encoding_debug_file ;
#endif
};
// This class decodes video from a stream. It keeps a queue of
// decoded frame that needs to be retrieved using the getNextImage() method.
//
class VideoProcessor
{
public:
VideoProcessor() ;
virtual ~VideoProcessor() ;
enum CodecId {
VIDEO_PROCESSOR_CODEC_ID_UNKNOWN = 0x0000,
VIDEO_PROCESSOR_CODEC_ID_JPEG_VIDEO = 0x0001,
VIDEO_PROCESSOR_CODEC_ID_DDWT_VIDEO = 0x0002,
VIDEO_PROCESSOR_CODEC_ID_MPEG_VIDEO = 0x0003
};
// =====================================================================================
// =------------------------------------ DECODING -------------------------------------=
// =====================================================================================
// Gets the next image to be displayed. Once returned, the image should
// be cleared from the incoming queue.
//
void setDisplayTarget(QVideoOutputDevice *odev) { _decoded_output_device = odev ; }
virtual void receiveEncodedData(const RsVOIPDataChunk& chunk) ;
// returns the current (measured) frame rate in bytes per second.
//
uint32_t currentBandwidthIn() const { return _estimated_bandwidth_in ; }
private:
QVideoOutputDevice *_decoded_output_device ;
std::list<QImage> _decoded_image_queue ;
//time_t _lastTimeToShowFrame ;
// =====================================================================================
// =------------------------------------ ENCODING -------------------------------------=
// =====================================================================================
public:
// Takes the next image to be encoded.
//
bool processImage(const QImage& Image) ;
bool encodedPacketReady() const { return !_encoded_out_queue.empty() ; }
bool nextEncodedPacket(RsVOIPDataChunk& ) ;
// Used to tweak the compression ratio so that the video can stream ok.
//
void setMaximumBandwidth(uint32_t bytes_per_second) ;
void setInternalFrameSize(QSize) ;
// returns the current encoding frame rate in bytes per second.
//
uint32_t currentBandwidthOut() const { return _estimated_bandwidth_out ; }
protected:
NetQueue<RsVOIPDataChunk> _encoded_out_queue;
QSize _encoded_frame_size ;
// =====================================================================================
// =------------------------------------- Codecs --------------------------------------=
// =====================================================================================
JPEGVideo _jpeg_video_codec ;
FFmpegVideo _mpeg_video_codec ;
uint16_t _encoding_current_codec ;
time_t _last_bw_estimate_in_TS;
time_t _last_bw_estimate_out_TS;
uint32_t _total_encoded_size_in ;
uint32_t _total_encoded_size_out ;
float _estimated_bandwidth_in ;
float _estimated_bandwidth_out ;
float _target_bandwidth_out ;
};