29#include <libavcodec/avcodec.h>
30#include <libavformat/avformat.h>
31#include <libavutil/timestamp.h>
58 fd = fopen(file,
"r");
60 LOGERROR(
"videostream: %s: Can't open %s", __FUNCTION__, file);
64 character = getline(&buf, &size, fd);
83 txt_buf = (
char *) calloc(bufsize,
sizeof(
char));
84 int hardwareQuirks = 0;
86 read_size =
ReadLineFromFile(txt_buf, bufsize,
"/sys/firmware/devicetree/base/compatible");
88 free((
void *)txt_buf);
96 char *_txt_buf = (
char *) calloc(bufsize,
sizeof(
char));
97 char *_read_ptr = _txt_buf;
98 for (
size_t i = 0; i < bufsize; i++) {
99 if (memcmp(read_ptr,
"\0",
sizeof(
char))) {
100 memcpy(_read_ptr, read_ptr,
sizeof(
char));
107 LOGDEBUG2(
L_DRM,
"videostream: %s: found \"%s\", set hardware quirks", __FUNCTION__, _txt_buf);
110 if (strstr(read_ptr,
"bcm2836")) {
111 LOGDEBUG2(
L_DRM,
"videostream: %s: bcm2836 (Raspberry Pi 2 Model B) found", __FUNCTION__);
115 if (strstr(read_ptr,
"bcm2837")) {
116 LOGDEBUG2(
L_DRM,
"videostream: %s: bcm2837 (Raspberry Pi 2 Model B v1.2/ 3 Model B, Raspberry Pi 3 Compute Module 3) found", __FUNCTION__);
120 if (strstr(read_ptr,
"bcm2711")) {
121 LOGDEBUG2(
L_DRM,
"videostream: %s: bcm2711 (Raspberry Pi 4 Model B, Compute Module 4, Pi 400) found", __FUNCTION__);
125 if (strstr(read_ptr,
"bcm2712")) {
126 LOGDEBUG2(
L_DRM,
"videostream: %s: bcm2712 (Raspberry Pi 5, Compute Module 5, Pi 500) found", __FUNCTION__);
130 if (strstr(read_ptr,
"amlogic")) {
131 LOGDEBUG2(
L_DRM,
"videostream: %s: amlogic found, disable HW deinterlacer", __FUNCTION__);
138 read_size -= (strlen(read_ptr) + 1);
139 read_ptr = (
char *)&read_ptr[(strlen(read_ptr) + 1)];
141 free((
void *)_txt_buf);
142 free((
void *)txt_buf);
144 return hardwareQuirks;
158 m_identifier(isPipStream ?
"PIP" :
"main"),
159 m_frameOutput(frameOutput),
160 m_pDrmBufferQueue(drmBufferQueue),
161 m_userDisabledDeinterlacer(config->ConfigDisableDeint),
162 m_deinterlacerDeactivated(isPipStream ? true : false),
163 m_startDecodingWithIFrame(config->ConfigDecoderNeedsIFrame),
164 m_parseH264Dimensions(config->ConfigParseH264Dimensions)
181 LOGDEBUG(
"videostream %s:", __FUNCTION__);
248 av_packet_free(&avpkt);
291 LOGFATAL(
"videostream %s: %s: Could not reopen the decoder (flush)!",
m_identifier, __FUNCTION__);
334 if (needsParsing &&
m_codecId == AV_CODEC_ID_H264) {
341 av_packet_free(&avpkt);
366 AVFrame *frame =
nullptr;
380 if (ret != AVERROR(EAGAIN) && ret != AVERROR_EOF) {
382 av_packet_free(&avpkt);
392 }
else if (ret == AVERROR_EOF) {
406 LOGFATAL(
"videostream %s: %s: Could not reopen the decoder (sw fallback)!",
m_identifier, __FUNCTION__);
423 *width = videoCtx->coded_width;
424 *height = videoCtx->coded_height;
425 *aspect_ratio = *width / (double)*height;
442 m_trickpkts = codecId == AV_CODEC_ID_MPEG2VIDEO ? 1 : 2;
487 if (frame->decode_error_flags || frame->flags & AV_FRAME_FLAG_CORRUPT)
509 bool useDeinterlacer =
516 LOGDEBUG(
"videostream: %s: %s: deinterlacer disabled by user configuration",
m_identifier, __FUNCTION__);
522 if (frame->format == AV_PIX_FMT_YUV420P || (frame->format == AV_PIX_FMT_DRM_PRIME && useDeinterlacer))
void InitAndStart(const AVCodecContext *, AVFrame *, bool)
Init and start the video filter thread.
int GetNumFramesToFilter(void)
void PushFrame(AVFrame *)
Put a frame in the buffer to be filtered.
bool IsInputBufferFull(void)
cH264Parser - H264 Parser class
T * Pop(void)
Pop an element from the back of the queue.
bool IsEmpty(void)
Check if the queue is empty.
bool IsFull(void)
Check if the queue is full.
bool Push(T *element)
Push an element to the front of the queue.
size_t Size(void)
Get the current size of the queue.
T * Peek(void)
Get a reference to the back element.
int ConfigDecoderFallbackToSwNumPkts
maximum number of packets sent before fallback to sw decoder
void SetDecoderNeedsMaxPackets(int)
const char * CurrentDecoderType
const char * CurrentDecoderName
bool ConfigDecoderFallbackToSw
fallback to software decoder if the hardware decoder fails
int GetDecoderNeedsMaxPackets(void)
cVideoDecoder - VideoDecoder class
int ReopenCodec(enum AVCodecID, AVCodecParameters *, AVRational, int)
Reopen the video decoder.
AVCodecContext * GetContext(void)
int SendPacket(const AVPacket *)
Send a video packet to be decoded.
int Open(enum AVCodecID, AVCodecParameters *, AVRational, bool, int, int)
Open the video decoder.
bool IsHardwareDecoder(void)
int GetFramesReceived(void)
void FlushBuffers(void)
Flush the video decoder.
int ReceiveFrame(AVFrame **)
Receive a decoded a video frame.
void Close(void)
Close video decoder.
cVideoRender - Video render class
bool IsForwardTrickspeed(void)
cDecodingThread * m_pDecodingThread
pointer to decoding thread
bool m_interlaced
flag for interlaced stream
void GetVideoSize(int *, int *, double *)
Get video size and aspect ratio.
void OpenDecoder(void)
Open the decoder including an H.264 parsing if needed.
cFilterThread * m_pFilterThread
pointer to deinterlace filter thread
std::function< void(AVFrame *)> m_frameOutput
function to output the frame
const char * m_identifier
identifier string for logging
cSoftHdConfig * m_pConfig
plugin config
int64_t m_inputPts
PTS of the first packet in the input buffer.
bool m_deinterlacerDeactivated
set, if the deinterlacer should be disabled temporarily (trickspeed, stillpicture,...
int m_sentTrickPkts
how many avpkt have been sent to the decoder in trickspeed mode?
std::string m_decodingThreadName
decoding thread name string (persists for object lifetime)
void Flush(void)
Flushes the video stream by finalizing any pending data.
bool m_parseH264Dimensions
parse width and height when starting an h264 stream
void StartDecoder()
Start the decoder.
void CheckForcingFrameDecode(void)
Check, if we need to force the decoder to decode the frame (force a decoder drain)
bool m_startDecodingWithIFrame
wait for an I-Frame to start h264 decoding
void ClearVdrCoreToDecoderQueue(void)
Clears all video stream data, which is buffered to be decoded.
bool m_userDisabledDeinterlacer
set, if the user configured the deinterlace to be disabled
volatile bool m_newStream
flag for new stream
enum AVCodecID m_codecId
current codec id
bool m_checkFilterThreadNeeded
set, if we have to check, if filter thread is needed at start of playback
AVCodecParameters * m_pPar
current codec parameters
int m_decoderFallbackToSwNumPkts
fallback to sw decoder if hw decoder fails after the given number of packets sent
void DecodeInput(void)
Decodes a reassembled codec packet.
cQueue< cDrmBuffer > * m_pDrmBufferQueue
pointer to renderer's DRM buffer queue
void CloseDecoder(void)
Close the decoder.
int m_hardwareQuirks
hardware specific quirks
cVideoDecoder * m_pDecoder
video decoder
void Exit(void)
Exit video stream.
virtual ~cVideoStream(void)
cVideoStream destructor
void CancelFilterThread(void)
Stop filter thread.
cVideoRender * m_pRender
video renderer
int m_trickpkts
how many avpkt does the decoder need in trickspeed mode?
void RenderFrame(AVFrame *)
Render a frame.
cQueue< AVPacket > m_packets
AVPackets queue.
void ExitDecodingThread(void)
Stop decoding thread.
void FlushDecoder(void)
Flush the decoder.
void Open(AVCodecID, AVCodecParameters *=nullptr, AVRational={ .num=1,.den=90000 })
Open a video codec.
bool PushAvPacket(AVPacket *avpkt)
Pushes a pre-assembled AVPacket directly to the processing queue.
int64_t GetInputPtsMs(void)
std::string m_filterThreadName
filter thread name string (persists for object lifetime)
virtual void SetDeinterlacerDeactivated(bool deactivate)
std::atomic< struct AVRational > m_timebase
current codec timebase
cVideoStream(cVideoRender *, cQueue< cDrmBuffer > *, cSoftHdConfig *, bool, std::function< void(AVFrame *)>)
cVideoStream constructor
Video decoder header file.
SoftHdDevice config header file.
Logger class header file.
#define LOGFATAL
Logger macros.
Misc function header file.
static bool isInterlacedFrame(AVFrame *frame)
Check, if this is an interlaced frame.
Thread-safe queue header file.
Thread classes header file.
Rendering class header file.
static size_t ReadLineFromFile(char *buf, size_t size, const char *file)
Helper function to read a line from a given file.
static int ReadHWPlatform(void)
Helper function to find out which platform we are on.
Videostream class header file.
#define QUIRK_CODEC_FLUSH_WORKAROUND
set, if we have to close and reopen the codec instead of avcodec_flush_buffers (rpi)
#define QUIRK_CODEC_NEEDS_EXT_INIT
set, if codec needs some infos for init (coded_width and coded_height)
#define QUIRK_NO_HW_DEINT
set, if no hw deinterlacer available
#define QUIRK_CODEC_SKIP_FIRST_FRAMES
set, if codec should skip first I-Frames