mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2025-07-20 15:15:46 +00:00
Fix video decoding on newer versions of FFmpeg (#155)
Fixes video decoding issues and enables compatibility with newer versions of FFmpeg. Co-authored-by: MaranBr <maranbr@outlook.com> Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/155
This commit is contained in:
parent
2d0f15ccac
commit
6397bb0809
2 changed files with 15 additions and 175 deletions
|
@ -1,9 +1,6 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 suyu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2025 eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
|
@ -54,8 +51,7 @@ AVPixelFormat GetGpuFormat(AVCodecContext* codec_context, const AVPixelFormat* p
|
|||
return codec_context->pix_fmt;
|
||||
}
|
||||
|
||||
std::string AVError(int errnum)
|
||||
{
|
||||
std::string AVError(int errnum) {
|
||||
char errbuf[AV_ERROR_MAX_STRING_SIZE] = {};
|
||||
av_make_error_string(errbuf, sizeof(errbuf) - 1, errnum);
|
||||
return errbuf;
|
||||
|
@ -223,167 +219,6 @@ bool DecoderContext::OpenContext(const Decoder& decoder) {
|
|||
return true;
|
||||
}
|
||||
|
||||
// Nasty but allows linux builds to pass.
|
||||
// Requires double checks when FFMPEG gets updated.
|
||||
// Hopefully a future FFMPEG update will all and expose a solution in the public API.
|
||||
namespace {
|
||||
|
||||
typedef struct FFCodecDefault {
|
||||
const char* key;
|
||||
const char* value;
|
||||
} FFCodecDefault;
|
||||
|
||||
typedef struct FFCodec {
|
||||
/**
|
||||
* The public AVCodec. See codec.h for it.
|
||||
*/
|
||||
AVCodec p;
|
||||
|
||||
/**
|
||||
* Internal codec capabilities FF_CODEC_CAP_*.
|
||||
*/
|
||||
unsigned caps_internal : 29;
|
||||
|
||||
/**
|
||||
* This field determines the type of the codec (decoder/encoder)
|
||||
* and also the exact callback cb implemented by the codec.
|
||||
* cb_type uses enum FFCodecType values.
|
||||
*/
|
||||
unsigned cb_type : 3;
|
||||
|
||||
int priv_data_size;
|
||||
/**
|
||||
* @name Frame-level threading support functions
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* Copy necessary context variables from a previous thread context to the current one.
|
||||
* If not defined, the next thread will start automatically; otherwise, the codec
|
||||
* must call ff_thread_finish_setup().
|
||||
*
|
||||
* dst and src will (rarely) point to the same context, in which case memcpy should be skipped.
|
||||
*/
|
||||
int (*update_thread_context)(struct AVCodecContext* dst, const struct AVCodecContext* src);
|
||||
|
||||
/**
|
||||
* Copy variables back to the user-facing context
|
||||
*/
|
||||
int (*update_thread_context_for_user)(struct AVCodecContext* dst,
|
||||
const struct AVCodecContext* src);
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* Private codec-specific defaults.
|
||||
*/
|
||||
const FFCodecDefault* defaults;
|
||||
|
||||
/**
|
||||
* Initialize codec static data, called from av_codec_iterate().
|
||||
*
|
||||
* This is not intended for time consuming operations as it is
|
||||
* run for every codec regardless of that codec being used.
|
||||
*/
|
||||
void (*init_static_data)(struct FFCodec* codec);
|
||||
|
||||
int (*init)(struct AVCodecContext*);
|
||||
|
||||
union {
|
||||
/**
|
||||
* Decode to an AVFrame.
|
||||
* cb is in this state if cb_type is FF_CODEC_CB_TYPE_DECODE.
|
||||
*
|
||||
* @param avctx codec context
|
||||
* @param[out] frame AVFrame for output
|
||||
* @param[out] got_frame_ptr decoder sets to 0 or 1 to indicate that
|
||||
* a non-empty frame was returned in frame.
|
||||
* @param[in] avpkt AVPacket containing the data to be decoded
|
||||
* @return amount of bytes read from the packet on success,
|
||||
* negative error code on failure
|
||||
*/
|
||||
int (*decode)(struct AVCodecContext* avctx, struct AVFrame* frame, int* got_frame_ptr,
|
||||
struct AVPacket* avpkt);
|
||||
/**
|
||||
* Decode subtitle data to an AVSubtitle.
|
||||
* cb is in this state if cb_type is FF_CODEC_CB_TYPE_DECODE_SUB.
|
||||
*
|
||||
* Apart from that this is like the decode callback.
|
||||
*/
|
||||
int (*decode_sub)(struct AVCodecContext* avctx, struct AVSubtitle* sub, int* got_frame_ptr,
|
||||
const struct AVPacket* avpkt);
|
||||
/**
|
||||
* Decode API with decoupled packet/frame dataflow.
|
||||
* cb is in this state if cb_type is FF_CODEC_CB_TYPE_RECEIVE_FRAME.
|
||||
*
|
||||
* This function is called to get one output frame. It should call
|
||||
* ff_decode_get_packet() to obtain input data.
|
||||
*/
|
||||
int (*receive_frame)(struct AVCodecContext* avctx, struct AVFrame* frame);
|
||||
/**
|
||||
* Encode data to an AVPacket.
|
||||
* cb is in this state if cb_type is FF_CODEC_CB_TYPE_ENCODE
|
||||
*
|
||||
* @param avctx codec context
|
||||
* @param[out] avpkt output AVPacket
|
||||
* @param[in] frame AVFrame containing the input to be encoded
|
||||
* @param[out] got_packet_ptr encoder sets to 0 or 1 to indicate that a
|
||||
* non-empty packet was returned in avpkt.
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
int (*encode)(struct AVCodecContext* avctx, struct AVPacket* avpkt,
|
||||
const struct AVFrame* frame, int* got_packet_ptr);
|
||||
/**
|
||||
* Encode subtitles to a raw buffer.
|
||||
* cb is in this state if cb_type is FF_CODEC_CB_TYPE_ENCODE_SUB.
|
||||
*/
|
||||
int (*encode_sub)(struct AVCodecContext* avctx, uint8_t* buf, int buf_size,
|
||||
const struct AVSubtitle* sub);
|
||||
/**
|
||||
* Encode API with decoupled frame/packet dataflow.
|
||||
* cb is in this state if cb_type is FF_CODEC_CB_TYPE_RECEIVE_PACKET.
|
||||
*
|
||||
* This function is called to get one output packet.
|
||||
* It should call ff_encode_get_frame() to obtain input data.
|
||||
*/
|
||||
int (*receive_packet)(struct AVCodecContext* avctx, struct AVPacket* avpkt);
|
||||
} cb;
|
||||
|
||||
int (*close)(struct AVCodecContext*);
|
||||
|
||||
/**
|
||||
* Flush buffers.
|
||||
* Will be called when seeking
|
||||
*/
|
||||
void (*flush)(struct AVCodecContext*);
|
||||
|
||||
/**
|
||||
* Decoding only, a comma-separated list of bitstream filters to apply to
|
||||
* packets before decoding.
|
||||
*/
|
||||
const char* bsfs;
|
||||
|
||||
/**
|
||||
* Array of pointers to hardware configurations supported by the codec,
|
||||
* or NULL if no hardware supported. The array is terminated by a NULL
|
||||
* pointer.
|
||||
*
|
||||
* The user can only access this field via avcodec_get_hw_config().
|
||||
*/
|
||||
const struct AVCodecHWConfigInternal* const* hw_configs;
|
||||
|
||||
/**
|
||||
* List of supported codec_tags, terminated by FF_CODEC_TAGS_END.
|
||||
*/
|
||||
const uint32_t* codec_tags;
|
||||
} FFCodec;
|
||||
|
||||
#ifndef ANDROID
|
||||
static av_always_inline const FFCodec* ffcodec(const AVCodec* codec) {
|
||||
return (const FFCodec*)codec;
|
||||
}
|
||||
#endif
|
||||
} // namespace
|
||||
|
||||
|
||||
bool DecoderContext::SendPacket(const Packet& packet) {
|
||||
m_temp_frame = std::make_shared<Frame>();
|
||||
m_got_frame = 0;
|
||||
|
@ -394,10 +229,8 @@ bool DecoderContext::SendPacket(const Packet& packet) {
|
|||
if (!m_codec_context->hw_device_ctx && m_codec_context->codec_id == AV_CODEC_ID_H264) {
|
||||
m_decode_order = true;
|
||||
auto* codec{ffcodec(m_decoder.GetCodec())};
|
||||
if (const int ret = codec->cb.decode(m_codec_context,
|
||||
m_temp_frame->GetFrame(),
|
||||
&m_got_frame,
|
||||
packet.GetPacket());
|
||||
if (const int ret = codec->cb.decode(m_codec_context, m_temp_frame->GetFrame(),
|
||||
&m_got_frame, packet.GetPacket());
|
||||
ret < 0) {
|
||||
LOG_DEBUG(Service_NVDRV, "avcodec_send_packet error {}", AVError(ret));
|
||||
return false;
|
||||
|
@ -417,7 +250,6 @@ bool DecoderContext::SendPacket(const Packet& packet) {
|
|||
std::shared_ptr<Frame> DecoderContext::ReceiveFrame() {
|
||||
// Android can randomly crash when calling decode directly, so skip.
|
||||
// TODO update ffmpeg and hope that fixes it.
|
||||
// TODO: This is causing issues on linux, need to bisect
|
||||
#ifndef ANDROID
|
||||
if (!m_codec_context->hw_device_ctx && m_codec_context->codec_id == AV_CODEC_ID_H264) {
|
||||
m_decode_order = true;
|
||||
|
@ -475,8 +307,12 @@ std::shared_ptr<Frame> DecoderContext::ReceiveFrame() {
|
|||
}
|
||||
|
||||
#if defined(FF_API_INTERLACED_FRAME) || LIBAVUTIL_VERSION_MAJOR >= 59
|
||||
m_temp_frame->GetFrame()->interlaced_frame =
|
||||
(m_temp_frame->GetFrame()->flags & AV_FRAME_FLAG_INTERLACED) != 0;
|
||||
if (m_temp_frame->GetFrame()->flags & AV_FRAME_FLAG_INTERLACED)
|
||||
m_temp_frame->GetFrame()->flags &= ~AV_FRAME_FLAG_INTERLACED;
|
||||
else
|
||||
m_temp_frame->GetFrame()->flags |= AV_FRAME_FLAG_INTERLACED;
|
||||
#else
|
||||
m_temp_frame->GetFrame()->interlaced_frame = !m_temp_frame->GetFrame()->interlaced_frame;
|
||||
#endif
|
||||
return std::move(m_temp_frame);
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ extern "C" {
|
|||
#include <libavcodec/avcodec.h>
|
||||
#include <libavutil/opt.h>
|
||||
#ifndef ANDROID
|
||||
#include <libavcodec/codec.h>
|
||||
#include <libavcodec/codec_internal.h>
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
|
@ -106,7 +106,11 @@ public:
|
|||
}
|
||||
|
||||
bool IsInterlaced() const {
|
||||
return m_frame->interlaced_frame != 0;
|
||||
#if defined(FF_API_INTERLACED_FRAME) || LIBAVUTIL_VERSION_MAJOR >= 59
|
||||
return m_frame->flags & AV_FRAME_FLAG_INTERLACED;
|
||||
#else
|
||||
return m_frame->interlaced_frame;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool IsHardwareDecoded() const {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue