Cameron Gutman 952ebcd0d2 Prefer zero-copy formats for non-hwaccel hardware decoders
SpacemiT K1's BSP has a version of FFmpeg that contains both
v4l2m2m and their own *_stcodec decoders. Not only is their
V4L2 driver for their mvx decoder seemingly totally broken
(output buffers are all zeros), but it doesn't have any of
the DRM_PRIME support work that is maintained out of tree.

The result is we use a broken copyback decoder instead of
a (mostly) working zero-copy decoder because we didn't
include any logic to rank non-hwaccel decoders by pixfmt
like we have with device type for hwaccel decoders.
2024-07-12 18:45:46 -05:00

123 lines
4.2 KiB
C++

#pragma once
#include <functional>
#include <QQueue>
#include "decoder.h"
#include "ffmpeg-renderers/renderer.h"
#include "ffmpeg-renderers/pacer/pacer.h"
extern "C" {
#include <libavcodec/avcodec.h>
}
class FFmpegVideoDecoder : public IVideoDecoder {
public:
FFmpegVideoDecoder(bool testOnly);
virtual ~FFmpegVideoDecoder() override;
virtual bool initialize(PDECODER_PARAMETERS params) override;
virtual bool isHardwareAccelerated() override;
virtual bool isAlwaysFullScreen() override;
virtual bool isHdrSupported() override;
virtual int getDecoderCapabilities() override;
virtual int getDecoderColorspace() override;
virtual int getDecoderColorRange() override;
virtual QSize getDecoderMaxResolution() override;
virtual int submitDecodeUnit(PDECODE_UNIT du) override;
virtual void renderFrameOnMainThread() override;
virtual void setHdrMode(bool enabled) override;
virtual bool notifyWindowChanged(PWINDOW_STATE_CHANGE_INFO info) override;
virtual IFFmpegRenderer* getBackendRenderer();
private:
bool completeInitialization(const AVCodec* decoder,
enum AVPixelFormat requiredFormat,
PDECODER_PARAMETERS params,
bool testFrame,
bool useAlternateFrontend);
void stringifyVideoStats(VIDEO_STATS& stats, char* output, int length);
void logVideoStats(VIDEO_STATS& stats, const char* title);
void addVideoStats(VIDEO_STATS& src, VIDEO_STATS& dst);
bool createFrontendRenderer(PDECODER_PARAMETERS params, bool useAlternateFrontend);
static
bool isDecoderIgnored(const AVCodec* decoder);
static
bool isZeroCopyFormat(AVPixelFormat format);
static
int getAVCodecCapabilities(const AVCodec *codec);
bool tryInitializeHwAccelDecoder(PDECODER_PARAMETERS params,
int pass,
QSet<const AVCodec*>& terminallyFailedHardwareDecoders);
bool tryInitializeNonHwAccelDecoder(PDECODER_PARAMETERS params,
bool requireZeroCopyFormat,
QSet<const AVCodec*>& terminallyFailedHardwareDecoders);
bool tryInitializeRendererForUnknownDecoder(const AVCodec* decoder,
PDECODER_PARAMETERS params,
bool tryHwAccel);
bool tryInitializeRenderer(const AVCodec* decoder,
enum AVPixelFormat requiredFormat,
PDECODER_PARAMETERS params,
const AVCodecHWConfig* hwConfig,
IFFmpegRenderer::InitFailureReason* failureReason,
std::function<IFFmpegRenderer*()> createRendererFunc);
static IFFmpegRenderer* createHwAccelRenderer(const AVCodecHWConfig* hwDecodeCfg, int pass);
void reset();
void writeBuffer(PLENTRY entry, int& offset);
static
enum AVPixelFormat ffGetFormat(AVCodecContext* context,
const enum AVPixelFormat* pixFmts);
void decoderThreadProc();
static int decoderThreadProcThunk(void* context);
AVPacket* m_Pkt;
AVCodecContext* m_VideoDecoderCtx;
enum AVPixelFormat m_RequiredPixelFormat;
QByteArray m_DecodeBuffer;
const AVCodecHWConfig* m_HwDecodeCfg;
IFFmpegRenderer* m_BackendRenderer;
IFFmpegRenderer* m_FrontendRenderer;
int m_ConsecutiveFailedDecodes;
Pacer* m_Pacer;
VIDEO_STATS m_ActiveWndVideoStats;
VIDEO_STATS m_LastWndVideoStats;
VIDEO_STATS m_GlobalVideoStats;
int m_FramesIn;
int m_FramesOut;
int m_LastFrameNumber;
int m_StreamFps;
int m_VideoFormat;
bool m_NeedsSpsFixup;
bool m_TestOnly;
SDL_Thread* m_DecoderThread;
SDL_atomic_t m_DecoderThreadShouldQuit;
// Data buffers in the queued DU are not valid
QQueue<DECODE_UNIT> m_FrameInfoQueue;
static const uint8_t k_H264TestFrame[];
static const uint8_t k_HEVCMainTestFrame[];
static const uint8_t k_HEVCMain10TestFrame[];
static const uint8_t k_AV1Main8TestFrame[];
static const uint8_t k_AV1Main10TestFrame[];
};