From 2362d71d70adb8bf99e960b78a04d2ead4c8db57 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 16 Feb 2021 00:03:56 -0800 Subject: [PATCH 1/9] Mpeg: Remove deprecated codec register calls. --- Core/AVIDump.cpp | 2 ++ Core/HLE/sceAtrac.cpp | 4 ++++ Core/HLE/sceMpeg.cpp | 4 ++++ Core/HW/SimpleAudioDec.cpp | 4 ++++ 4 files changed, 14 insertions(+) diff --git a/Core/AVIDump.cpp b/Core/AVIDump.cpp index 19cbcf1227ad..4e7d7f40ec63 100644 --- a/Core/AVIDump.cpp +++ b/Core/AVIDump.cpp @@ -65,7 +65,9 @@ static void InitAVCodec() { static bool first_run = true; if (first_run) { #ifdef USE_FFMPEG +#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(58, 12, 100) av_register_all(); +#endif #endif first_run = false; } diff --git a/Core/HLE/sceAtrac.cpp b/Core/HLE/sceAtrac.cpp index bdaeea8b98bf..1c6a1fb664cc 100644 --- a/Core/HLE/sceAtrac.cpp +++ b/Core/HLE/sceAtrac.cpp @@ -636,8 +636,12 @@ void __AtracInit() { atracIDTypes[5] = 0; #ifdef USE_FFMPEG +#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(58, 18, 100) avcodec_register_all(); +#endif +#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(58, 12, 100) av_register_all(); +#endif #endif // USE_FFMPEG } diff --git a/Core/HLE/sceMpeg.cpp b/Core/HLE/sceMpeg.cpp index b98f57d7b409..f2dbb8a0d049 100644 --- a/Core/HLE/sceMpeg.cpp +++ b/Core/HLE/sceMpeg.cpp @@ -393,9 +393,13 @@ void __MpegInit() { actionPostPut = __KernelRegisterActionType(PostPutAction::Create); #ifdef USE_FFMPEG +#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(58, 18, 100) avcodec_register_all(); +#endif +#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(58, 12, 100) av_register_all(); #endif +#endif } void __MpegDoState(PointerWrap &p) { diff --git a/Core/HW/SimpleAudioDec.cpp b/Core/HW/SimpleAudioDec.cpp index 2e9ac873d42d..12bac4ba182b 100644 --- a/Core/HW/SimpleAudioDec.cpp +++ b/Core/HW/SimpleAudioDec.cpp @@ -62,8 +62,12 @@ SimpleAudio::SimpleAudio(int audioType, int sample_rate, int channels) void SimpleAudio::Init() { #ifdef USE_FFMPEG +#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(58, 18, 100) avcodec_register_all(); +#endif +#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(58, 12, 100) av_register_all(); +#endif InitFFmpeg(); frame_ = av_frame_alloc(); From 26eca0ba3dc087daeb4da54267ae8fc459e988b4 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 16 Feb 2021 00:12:27 -0800 Subject: [PATCH 2/9] AVI: Avoid deprecated ffmpeg context usage. --- Core/AVIDump.cpp | 121 +++++++++++++++++++++++++++-------------------- 1 file changed, 70 insertions(+), 51 deletions(-) diff --git a/Core/AVIDump.cpp b/Core/AVIDump.cpp index 4e7d7f40ec63..898288b0f1ed 100644 --- a/Core/AVIDump.cpp +++ b/Core/AVIDump.cpp @@ -44,11 +44,12 @@ extern "C" { #define av_frame_free avcodec_free_frame #endif -static AVFormatContext* s_format_context = nullptr; -static AVStream* s_stream = nullptr; -static AVFrame* s_src_frame = nullptr; -static AVFrame* s_scaled_frame = nullptr; -static SwsContext* s_sws_context = nullptr; +static AVFormatContext *s_format_context = nullptr; +static AVCodecContext *s_codec_context = nullptr; +static AVStream *s_stream = nullptr; +static AVFrame *s_src_frame = nullptr; +static AVFrame *s_scaled_frame = nullptr; +static SwsContext *s_sws_context = nullptr; #endif @@ -89,51 +90,70 @@ bool AVIDump::Start(int w, int h) bool AVIDump::CreateAVI() { #ifdef USE_FFMPEG - AVCodec* codec = nullptr; + AVCodec *codec = nullptr; // Use gameID_EmulatedTimestamp for filename std::string discID = g_paramSFO.GetDiscID(); std::string video_file_name = StringFromFormat("%s%s_%s.avi", GetSysDirectory(DIRECTORY_VIDEO).c_str(), discID.c_str(), KernelTimeNowFormatted().c_str()).c_str(); s_format_context = avformat_alloc_context(); - std::stringstream s_file_index_str; - s_file_index_str << video_file_name; - snprintf(s_format_context->filename, sizeof(s_format_context->filename), "%s", s_file_index_str.str().c_str()); - INFO_LOG(COMMON, "Recording Video to: %s", s_format_context->filename); +#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(58, 7, 0) + char *filename = av_strdup(video_file_name.c_str()); + // Freed when the context is freed. + s_format_context->url = filename; +#else + const char *filename = s_format_context->filename; + snprintf(s_format_context->filename, sizeof(s_format_context->filename), "%s", video_file_name.c_str()); +#endif + INFO_LOG(COMMON, "Recording Video to: %s", filename); + // Make sure that the path exists if (!File::Exists(GetSysDirectory(DIRECTORY_VIDEO))) File::CreateDir(GetSysDirectory(DIRECTORY_VIDEO)); - if (File::Exists(s_format_context->filename)) - File::Delete(s_format_context->filename); + if (File::Exists(filename)) + File::Delete(filename); - if (!(s_format_context->oformat = av_guess_format("avi", nullptr, nullptr)) || !(s_stream = avformat_new_stream(s_format_context, codec))) - { + s_format_context->oformat = av_guess_format("avi", nullptr, nullptr); + if (!s_format_context->oformat) + return false; + s_stream = avformat_new_stream(s_format_context, codec); + if (!s_stream) return false; - } - s_stream->codec->codec_id = g_Config.bUseFFV1 ? AV_CODEC_ID_FFV1 : s_format_context->oformat->video_codec; +#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(57, 48, 101) + s_codec_context = s_stream->codec; +#else + s_codec_context = avcodec_alloc_context3(codec); +#endif + s_codec_context->codec_id = g_Config.bUseFFV1 ? AV_CODEC_ID_FFV1 : s_format_context->oformat->video_codec; if (!g_Config.bUseFFV1) - s_stream->codec->codec_tag = MKTAG('X', 'V', 'I', 'D'); // Force XVID FourCC for better compatibility - s_stream->codec->codec_type = AVMEDIA_TYPE_VIDEO; - s_stream->codec->bit_rate = 400000; - s_stream->codec->width = s_width; - s_stream->codec->height = s_height; - s_stream->codec->time_base.num = 1001; - s_stream->codec->time_base.den = 60000; - s_stream->codec->gop_size = 12; - s_stream->codec->pix_fmt = g_Config.bUseFFV1 ? AV_PIX_FMT_BGRA : AV_PIX_FMT_YUV420P; - - if (!(codec = avcodec_find_encoder(s_stream->codec->codec_id)) || (avcodec_open2(s_stream->codec, codec, nullptr) < 0)) - { + s_codec_context->codec_tag = MKTAG('X', 'V', 'I', 'D'); // Force XVID FourCC for better compatibility + s_codec_context->codec_type = AVMEDIA_TYPE_VIDEO; + s_codec_context->bit_rate = 400000; + s_codec_context->width = s_width; + s_codec_context->height = s_height; + s_codec_context->time_base.num = 1001; + s_codec_context->time_base.den = 60000; + s_codec_context->gop_size = 12; + s_codec_context->pix_fmt = g_Config.bUseFFV1 ? AV_PIX_FMT_BGRA : AV_PIX_FMT_YUV420P; + +#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101) + if (avcodec_parameters_from_context(s_stream->codecpar, s_codec_context) < 0) + return false; +#endif + + codec = avcodec_find_encoder(s_codec_context->codec_id); + if (!codec) + return false; + if (avcodec_open2(s_codec_context, codec, nullptr) < 0) return false; - } s_src_frame = av_frame_alloc(); s_scaled_frame = av_frame_alloc(); - s_scaled_frame->format = s_stream->codec->pix_fmt; + s_scaled_frame->format = s_codec_context->pix_fmt; s_scaled_frame->width = s_width; s_scaled_frame->height = s_height; @@ -141,14 +161,13 @@ bool AVIDump::CreateAVI() { if (av_frame_get_buffer(s_scaled_frame, 1)) return false; #else - if (avcodec_default_get_buffer(s_stream->codec, s_scaled_frame)) + if (avcodec_default_get_buffer(s_codec_context, s_scaled_frame)) return false; #endif - NOTICE_LOG(G3D, "Opening file %s for dumping", s_format_context->filename); - if (avio_open(&s_format_context->pb, s_format_context->filename, AVIO_FLAG_WRITE) < 0 || avformat_write_header(s_format_context, nullptr)) - { - WARN_LOG(G3D, "Could not open %s", s_format_context->filename); + NOTICE_LOG(G3D, "Opening file %s for dumping", filename); + if (avio_open(&s_format_context->pb, filename, AVIO_FLAG_WRITE) < 0 || avformat_write_header(s_format_context, nullptr)) { + WARN_LOG(G3D, "Could not open %s", filename); return false; } @@ -194,12 +213,12 @@ void AVIDump::AddFrame() s_src_frame->height = s_height; // Convert image from BGR24 to desired pixel format, and scale to initial width and height - if ((s_sws_context = sws_getCachedContext(s_sws_context, w, h, AV_PIX_FMT_RGB24, s_width, s_height, s_stream->codec->pix_fmt, SWS_BICUBIC, nullptr, nullptr, nullptr))) + if ((s_sws_context = sws_getCachedContext(s_sws_context, w, h, AV_PIX_FMT_RGB24, s_width, s_height, s_codec_context->pix_fmt, SWS_BICUBIC, nullptr, nullptr, nullptr))) { sws_scale(s_sws_context, s_src_frame->data, s_src_frame->linesize, 0, h, s_scaled_frame->data, s_scaled_frame->linesize); } - s_scaled_frame->format = s_stream->codec->pix_fmt; + s_scaled_frame->format = s_codec_context->pix_fmt; s_scaled_frame->width = s_width; s_scaled_frame->height = s_height; @@ -207,20 +226,20 @@ void AVIDump::AddFrame() AVPacket pkt; PreparePacket(&pkt); int got_packet; - int error = avcodec_encode_video2(s_stream->codec, &pkt, s_scaled_frame, &got_packet); + int error = avcodec_encode_video2(s_codec_context, &pkt, s_scaled_frame, &got_packet); while (!error && got_packet) { // Write the compressed frame in the media file. if (pkt.pts != (s64)AV_NOPTS_VALUE) { - pkt.pts = av_rescale_q(pkt.pts, s_stream->codec->time_base, s_stream->time_base); + pkt.pts = av_rescale_q(pkt.pts, s_codec_context->time_base, s_stream->time_base); } if (pkt.dts != (s64)AV_NOPTS_VALUE) { - pkt.dts = av_rescale_q(pkt.dts, s_stream->codec->time_base, s_stream->time_base); + pkt.dts = av_rescale_q(pkt.dts, s_codec_context->time_base, s_stream->time_base); } #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(56, 60, 100) - if (s_stream->codec->coded_frame->key_frame) + if (s_codec_context->coded_frame->key_frame) pkt.flags |= AV_PKT_FLAG_KEY; #endif pkt.stream_index = s_stream->index; @@ -228,7 +247,7 @@ void AVIDump::AddFrame() // Handle delayed frames. PreparePacket(&pkt); - error = avcodec_encode_video2(s_stream->codec, &pkt, nullptr, &got_packet); + error = avcodec_encode_video2(s_codec_context, &pkt, nullptr, &got_packet); } if (error) ERROR_LOG(G3D, "Error while encoding video: %d", error); @@ -248,18 +267,18 @@ void AVIDump::Stop() { void AVIDump::CloseFile() { #ifdef USE_FFMPEG - - if (s_stream) - { - if (s_stream->codec) - { + if (s_codec_context) { #if LIBAVCODEC_VERSION_MAJOR < 55 - avcodec_default_release_buffer(s_stream->codec, s_src_frame); + avcodec_default_release_buffer(s_codec_context, s_src_frame); +#endif +#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101) + avcodec_free_context(&s_codec_context); +#else + avcodec_close(s_codec_context); + s_codec_context = nullptr; #endif - avcodec_close(s_stream->codec); - } - av_freep(&s_stream); } + av_freep(&s_stream); av_frame_free(&s_src_frame); av_frame_free(&s_scaled_frame); From 6656c8a533ee2816defe4522e071fe2f1e2718b4 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 16 Feb 2021 00:46:42 -0800 Subject: [PATCH 3/9] AVI: Update to latest FFmpeg packet pump. --- Core/AVIDump.cpp | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/Core/AVIDump.cpp b/Core/AVIDump.cpp index 898288b0f1ed..1e3f1803d5bf 100644 --- a/Core/AVIDump.cpp +++ b/Core/AVIDump.cpp @@ -187,8 +187,7 @@ static void PreparePacket(AVPacket* pkt) { #endif -void AVIDump::AddFrame() -{ +void AVIDump::AddFrame() { u32 w = 0; u32 h = 0; if (g_Config.bDumpVideoOutput) { @@ -213,8 +212,7 @@ void AVIDump::AddFrame() s_src_frame->height = s_height; // Convert image from BGR24 to desired pixel format, and scale to initial width and height - if ((s_sws_context = sws_getCachedContext(s_sws_context, w, h, AV_PIX_FMT_RGB24, s_width, s_height, s_codec_context->pix_fmt, SWS_BICUBIC, nullptr, nullptr, nullptr))) - { + if ((s_sws_context = sws_getCachedContext(s_sws_context, w, h, AV_PIX_FMT_RGB24, s_width, s_height, s_codec_context->pix_fmt, SWS_BICUBIC, nullptr, nullptr, nullptr))) { sws_scale(s_sws_context, s_src_frame->data, s_src_frame->linesize, 0, h, s_scaled_frame->data, s_scaled_frame->linesize); } @@ -225,17 +223,22 @@ void AVIDump::AddFrame() // Encode and write the image. AVPacket pkt; PreparePacket(&pkt); +#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101) + int error = avcodec_send_frame(s_codec_context, s_scaled_frame); + int got_packet = 0; + if (avcodec_receive_packet(s_codec_context, &pkt) >= 0) { + got_packet = 1; + } +#else int got_packet; int error = avcodec_encode_video2(s_codec_context, &pkt, s_scaled_frame, &got_packet); - while (!error && got_packet) - { +#endif + while (error >= 0 && got_packet) { // Write the compressed frame in the media file. - if (pkt.pts != (s64)AV_NOPTS_VALUE) - { + if (pkt.pts != (s64)AV_NOPTS_VALUE) { pkt.pts = av_rescale_q(pkt.pts, s_codec_context->time_base, s_stream->time_base); } - if (pkt.dts != (s64)AV_NOPTS_VALUE) - { + if (pkt.dts != (s64)AV_NOPTS_VALUE) { pkt.dts = av_rescale_q(pkt.dts, s_codec_context->time_base, s_stream->time_base); } #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(56, 60, 100) @@ -246,11 +249,23 @@ void AVIDump::AddFrame() av_interleaved_write_frame(s_format_context, &pkt); // Handle delayed frames. +#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101) + av_packet_unref(&pkt); + error = avcodec_receive_packet(s_codec_context, &pkt); + got_packet = error >= 0 ? 1 : 0; +#else PreparePacket(&pkt); error = avcodec_encode_video2(s_codec_context, &pkt, nullptr, &got_packet); +#endif } - if (error) +#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101) + av_packet_unref(&pkt); + if (error < 0 && error != AVERROR(EAGAIN) && error != AVERROR_EOF) ERROR_LOG(G3D, "Error while encoding video: %d", error); +#else + if (error < 0) + ERROR_LOG(G3D, "Error while encoding video: %d", error); +#endif #endif delete[] flipbuffer; } From 2b2dae60d316b321e084eac7e0bb96d682e4ea37 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Wed, 17 Feb 2021 22:28:32 -0800 Subject: [PATCH 4/9] Mpeg: Use direct pts value checks in newer FFmpeg. --- Core/HLE/sceMpeg.cpp | 13 ++++++++++--- Core/HW/MediaEngine.cpp | 13 ++++++++++--- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/Core/HLE/sceMpeg.cpp b/Core/HLE/sceMpeg.cpp index f2dbb8a0d049..4c4a4b0e592f 100644 --- a/Core/HLE/sceMpeg.cpp +++ b/Core/HLE/sceMpeg.cpp @@ -1023,10 +1023,17 @@ static bool decodePmpVideo(PSPPointer ringbuffer, u32 pmpctxA sws_freeContext(img_convert_ctx); // update timestamp - if (av_frame_get_best_effort_timestamp(mediaengine->m_pFrame) != AV_NOPTS_VALUE) - mediaengine->m_videopts = av_frame_get_best_effort_timestamp(mediaengine->m_pFrame) + av_frame_get_pkt_duration(mediaengine->m_pFrame) - mediaengine->m_firstTimeStamp; +#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(55, 58, 100) + int64_t bestPts = mediaengine->m_pFrame->best_effort_timestamp; + int64_t ptsDuration = mediaengine->m_pFrame->pkt_duration; +#else + int64_t bestPts = av_frame_get_best_effort_timestamp(mediaengine->m_pFrame); + int64_t ptsDuration = av_frame_get_pkt_duration(mediaengine->m_pFrame); +#endif + if (bestPts != AV_NOPTS_VALUE) + mediaengine->m_videopts = bestPts + ptsDuration - mediaengine->m_firstTimeStamp; else - mediaengine->m_videopts += av_frame_get_pkt_duration(mediaengine->m_pFrame); + mediaengine->m_videopts += ptsDuration; // push the decoded frame into pmp_queue pmp_queue.push_back(pFrameRGB); diff --git a/Core/HW/MediaEngine.cpp b/Core/HW/MediaEngine.cpp index 0a1e50f52707..2da0792edfc7 100644 --- a/Core/HW/MediaEngine.cpp +++ b/Core/HW/MediaEngine.cpp @@ -666,10 +666,17 @@ bool MediaEngine::stepVideo(int videoPixelMode, bool skipFrame) { m_pCodecCtx->height, m_pFrameRGB->data, m_pFrameRGB->linesize); } - if (av_frame_get_best_effort_timestamp(m_pFrame) != AV_NOPTS_VALUE) - m_videopts = av_frame_get_best_effort_timestamp(m_pFrame) + av_frame_get_pkt_duration(m_pFrame) - m_firstTimeStamp; +#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(55, 58, 100) + int64_t bestPts = m_pFrame->best_effort_timestamp; + int64_t ptsDuration = m_pFrame->pkt_duration; +#else + int64_t bestPts = av_frame_get_best_effort_timestamp(m_pFrame); + int64_t ptsDuration = av_frame_get_pkt_duration(m_pFrame); +#endif + if (bestPts != AV_NOPTS_VALUE) + m_videopts = bestPts + ptsDuration - m_firstTimeStamp; else - m_videopts += av_frame_get_pkt_duration(m_pFrame); + m_videopts += ptsDuration; bGetFrame = true; } if (result <= 0 && dataEnd) { From b19e39efb0caf044ce93ceac03e83343a1eaf00e Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Wed, 17 Feb 2021 23:30:33 -0800 Subject: [PATCH 5/9] Audiocodec: Update to latest FFmpeg packet pump. --- Core/HW/SimpleAudioDec.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Core/HW/SimpleAudioDec.cpp b/Core/HW/SimpleAudioDec.cpp index 12bac4ba182b..990d6f233b76 100644 --- a/Core/HW/SimpleAudioDec.cpp +++ b/Core/HW/SimpleAudioDec.cpp @@ -192,7 +192,25 @@ bool SimpleAudio::Decode(void *inbuf, int inbytes, uint8_t *outbuf, int *outbyte *outbytes = 0; srcPos = 0; +#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101) + if (inbytes != 0) { + int err = avcodec_send_packet(codecCtx_, &packet); + if (err < 0) { + ERROR_LOG(ME, "Error sending audio frame to decoder (%d bytes): %d (%08x)", inbytes, err, err); + return false; + } + } + int err = avcodec_receive_frame(codecCtx_, frame_); + int len = 0; + if (err >= 0) { + len = frame_->pkt_size; + got_frame = 1; + } else if (err != AVERROR(EAGAIN)) { + len = err; + } +#else int len = avcodec_decode_audio4(codecCtx_, frame_, &got_frame, &packet); +#endif #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 12, 100) av_packet_unref(&packet); #else From e5849d109dc25ecf8874f7bb4e0079a8dbc6d4db Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 18 Feb 2021 00:04:58 -0800 Subject: [PATCH 6/9] Mpeg: Correct stream detection in newer FFmpeg. --- Core/HW/MediaEngine.cpp | 50 +++++++++++++++++++++++++++++------------ 1 file changed, 36 insertions(+), 14 deletions(-) diff --git a/Core/HW/MediaEngine.cpp b/Core/HW/MediaEngine.cpp index 2da0792edfc7..7d3ccee417d2 100644 --- a/Core/HW/MediaEngine.cpp +++ b/Core/HW/MediaEngine.cpp @@ -280,9 +280,8 @@ bool MediaEngine::SetupStreams() { for (int i = videoStreamNum + 1; i < m_expectedVideoStreams; i++) { addVideoStream(i); } - - #endif + return true; } @@ -328,13 +327,19 @@ bool MediaEngine::openContext(bool keepReadPos) { if (m_videoStream == -1) { // Find the first video stream - for(int i = 0; i < (int)m_pFormatCtx->nb_streams; i++) { - if(m_pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) { + for (int i = 0; i < (int)m_pFormatCtx->nb_streams; i++) { + const AVStream *s = m_pFormatCtx->streams[i]; +#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(57, 33, 100) + AVMediaType type = s->codecpar->codec_type; +#else + AVMediaType type = s->codec->codec_type; +#endif + if (type == AVMEDIA_TYPE_VIDEO) { m_videoStream = i; break; } } - if(m_videoStream == -1) + if (m_videoStream == -1) return false; } @@ -361,8 +366,13 @@ void MediaEngine::closeContext() av_free(m_pIOContext->buffer); if (m_pIOContext) av_free(m_pIOContext); - for (auto it = m_pCodecCtxs.begin(), end = m_pCodecCtxs.end(); it != end; ++it) - avcodec_close(it->second); + for (auto it : m_pCodecCtxs) { +#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(57, 33, 100) + avcodec_free_context(&it.second); +#else + avcodec_close(it.second); +#endif + } m_pCodecCtxs.clear(); if (m_pFormatCtx) avformat_close_input(&m_pFormatCtx); @@ -411,6 +421,10 @@ bool MediaEngine::addVideoStream(int streamNum, int streamId) { streamId = PSMF_VIDEO_STREAM_ID | streamNum; stream->id = 0x00000100 | streamId; +#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(57, 33, 100) + stream->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; + stream->codecpar->codec_id = AV_CODEC_ID_H264; +#endif stream->request_probe = 0; stream->need_parsing = AVSTREAM_PARSE_FULL; // We could set the width here, but we don't need to. @@ -496,21 +510,29 @@ bool MediaEngine::setVideoStream(int streamNum, bool force) { if ((u32)streamNum >= m_pFormatCtx->nb_streams) { return false; } - AVCodecContext *m_pCodecCtx = m_pFormatCtx->streams[streamNum]->codec; -#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(57,33,100) - AVCodecParameters *m_pCodecPar = m_pFormatCtx->streams[streamNum]->codecpar; - // Update from deprecated public codec context - if (avcodec_parameters_from_context(m_pCodecPar, m_pCodecCtx) < 0) { + AVStream *stream = m_pFormatCtx->streams[streamNum]; + int err; +#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(57, 33, 100) + AVCodec *pCodec = avcodec_find_decoder(stream->codecpar->codec_id); + if (!pCodec) { + WARN_LOG_REPORT(ME, "Could not find decoder for %d", (int)stream->codecpar->codec_id); return false; } -#endif - + AVCodecContext *m_pCodecCtx = avcodec_alloc_context3(pCodec); + err = avcodec_parameters_to_context(m_pCodecCtx, stream->codecpar); + if (err < 0) { + WARN_LOG_REPORT(ME, "Failed to prepare context parameters: %08x", err); + return false; + } +#else + AVCodecContext *m_pCodecCtx = stream->codec; // Find the decoder for the video stream AVCodec *pCodec = avcodec_find_decoder(m_pCodecCtx->codec_id); if (pCodec == nullptr) { return false; } +#endif AVDictionary *opt = nullptr; // Allow ffmpeg to use any number of threads it wants. Without this, it doesn't use threads. From e3be3d5f7b0ed7fff6cfbdfb2d7b820e123cfc2f Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 18 Feb 2021 00:08:00 -0800 Subject: [PATCH 7/9] Mpeg: Clarify fallback problems. Also, modify it in case some packager was patching, so they see this. --- Core/HW/MediaEngine.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Core/HW/MediaEngine.cpp b/Core/HW/MediaEngine.cpp index 7d3ccee417d2..f8f008f73d6f 100644 --- a/Core/HW/MediaEngine.cpp +++ b/Core/HW/MediaEngine.cpp @@ -313,8 +313,10 @@ bool MediaEngine::openContext(bool keepReadPos) { av_dict_free(&open_opt); if (!SetupStreams()) { - // Fallback to old behavior. - if (avformat_find_stream_info(m_pFormatCtx, NULL) < 0) { + // Fallback to old behavior. Reads too much and corrupts when game doesn't read fast enough. + // SetupStreams should work for newer FFmpeg 3.1+ now. + WARN_LOG_REPORT_ONCE(setupStreams, ME, "Failed to read valid video stream data from header"); + if (avformat_find_stream_info(m_pFormatCtx, nullptr) < 0) { closeContext(); return false; } From 0ab6f1d0804cd8d68a00a1afeee7b70b463dc2a9 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 18 Feb 2021 00:18:35 -0800 Subject: [PATCH 8/9] Mpeg: Update videos to latest FFmpeg packet pump. --- Core/HLE/sceMpeg.cpp | 14 ++++++++++++++ Core/HW/MediaEngine.cpp | 18 ++++++++++++++++-- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/Core/HLE/sceMpeg.cpp b/Core/HLE/sceMpeg.cpp index 4c4a4b0e592f..3701f08a476a 100644 --- a/Core/HLE/sceMpeg.cpp +++ b/Core/HLE/sceMpeg.cpp @@ -993,7 +993,21 @@ static bool decodePmpVideo(PSPPointer ringbuffer, u32 pmpctxA // decode video frame +#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101) + avcodec_send_packet(pCodecCtx, &packet); + int len = avcodec_receive_frame(pCodecCtx, pFrame); + if (len == 0) { + len = pFrame->pkt_size; + got_picture = 1; + } else if (len == AVERROR(EAGAIN)) { + len = 0; + got_picture = 0; + } else { + got_picture = 0; + } +#else int len = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, &packet); +#endif DEBUG_LOG(ME, "got_picture %d", got_picture); if (got_picture){ SwsContext *img_convert_ctx = NULL; diff --git a/Core/HW/MediaEngine.cpp b/Core/HW/MediaEngine.cpp index f8f008f73d6f..2dfddfdc8919 100644 --- a/Core/HW/MediaEngine.cpp +++ b/Core/HW/MediaEngine.cpp @@ -664,9 +664,9 @@ bool MediaEngine::stepVideo(int videoPixelMode, bool skipFrame) { while (!bGetFrame) { bool dataEnd = av_read_frame(m_pFormatCtx, &packet) < 0; // Even if we've read all frames, some may have been re-ordered frames at the end. - // Still need to decode those, so keep calling avcodec_decode_video2(). + // Still need to decode those, so keep calling avcodec_decode_video2() / avcodec_receive_frame(). if (dataEnd || packet.stream_index == m_videoStream) { - // avcodec_decode_video2() gives us the re-ordered frames with a NULL packet. + // avcodec_decode_video2() / avcodec_send_packet() gives us the re-ordered frames with a NULL packet. #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 12, 100) if (dataEnd) av_packet_unref(&packet); @@ -675,7 +675,21 @@ bool MediaEngine::stepVideo(int videoPixelMode, bool skipFrame) { av_free_packet(&packet); #endif +#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101) + avcodec_send_packet(m_pCodecCtx, &packet); + int result = avcodec_receive_frame(m_pCodecCtx, m_pFrame); + if (result == 0) { + result = m_pFrame->pkt_size; + frameFinished = 1; + } else if (result == AVERROR(EAGAIN)) { + result = 0; + frameFinished = 0; + } else { + frameFinished = 0; + } +#else int result = avcodec_decode_video2(m_pCodecCtx, m_pFrame, &frameFinished, &packet); +#endif if (frameFinished) { if (!m_pFrameRGB) { setVideoDim(); From 54dd4e4c0cd7d5d42347a8eb976f8638022e451f Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 18 Feb 2021 00:31:50 -0800 Subject: [PATCH 9/9] Mpeg: Remove request_probe usage in newer FFmpeg. No longer needed. --- Core/HW/MediaEngine.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Core/HW/MediaEngine.cpp b/Core/HW/MediaEngine.cpp index 2dfddfdc8919..4f7b213e5d85 100644 --- a/Core/HW/MediaEngine.cpp +++ b/Core/HW/MediaEngine.cpp @@ -426,8 +426,9 @@ bool MediaEngine::addVideoStream(int streamNum, int streamId) { #if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(57, 33, 100) stream->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; stream->codecpar->codec_id = AV_CODEC_ID_H264; -#endif +#else stream->request_probe = 0; +#endif stream->need_parsing = AVSTREAM_PARSE_FULL; // We could set the width here, but we don't need to. if (streamNum >= m_expectedVideoStreams) {