diff --git a/CMakeLists.txt b/CMakeLists.txt index 7d6a87d886..b1d5c5111d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -171,17 +171,18 @@ else() message("Xrandr NOT found") endif(XRANDR_FOUND) -option(ENCODE_FRAMEDUMPS "Encode framedumps in MPG format" ON) +option(ENCODE_FRAMEDUMPS "Encode framedumps in AVI format" ON) if(ENCODE_FRAMEDUMPS) pkg_search_module(AVCODEC libavcodec>=52.72.2) + pkg_search_module(AVFORMAT libavformat>=52.64.2) pkg_search_module(SWSCALE libswscale>=0.11.0) - if(AVCODEC_FOUND AND SWSCALE_FOUND) - message("avcodec found, enabling MPG frame dumps") + if(AVCODEC_FOUND AND AVFORMAT_FOUND AND SWSCALE_FOUND) + message("libav found, enabling AVI frame dumps") set(ENCODE_FRAMEDUMPS ON) add_definitions(-DHAVE_AVCODEC) else() set(ENCODE_FRAMEDUMPS OFF) - message("avcodec not found, disabling MPG frame dumps") + message("libav not found, disabling AVI frame dumps") endif() endif() diff --git a/Source/Core/VideoCommon/CMakeLists.txt b/Source/Core/VideoCommon/CMakeLists.txt index 3692d120d1..32a5066ac2 100644 --- a/Source/Core/VideoCommon/CMakeLists.txt +++ b/Source/Core/VideoCommon/CMakeLists.txt @@ -45,7 +45,7 @@ endif() add_library(videocommon STATIC ${SRCS}) if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") if(ENCODE_FRAMEDUMPS) - target_link_libraries(videocommon avcodec swscale) + target_link_libraries(videocommon avcodec avformat swscale) add_definitions(-D__STDC_CONSTANT_MACROS) endif() add_definitions(-fPIC) diff --git a/Source/Core/VideoCommon/Src/AVIDump.cpp b/Source/Core/VideoCommon/Src/AVIDump.cpp index 1fd7d57304..79d554dabf 100644 --- a/Source/Core/VideoCommon/Src/AVIDump.cpp +++ b/Source/Core/VideoCommon/Src/AVIDump.cpp @@ -204,12 +204,12 @@ bool AVIDump::SetVideoFormat() extern "C" { #include +#include #include } -FILE* f_pFrameDump = NULL; -AVCodec *s_Codec = NULL; -AVCodecContext *s_CodecContext = NULL; +AVFormatContext *s_FormatContext = NULL; +AVStream *s_Stream = NULL; AVFrame *s_BGRFrame = NULL, *s_YUVFrame = NULL; uint8_t *s_YUVBuffer = NULL; uint8_t *s_OutBuffer = NULL; @@ -223,8 +223,7 @@ static void InitAVCodec() static bool first_run = true; if (first_run) { - avcodec_init(); - avcodec_register_all(); + av_register_all(); first_run = false; } } @@ -240,28 +239,40 @@ bool AVIDump::Start(int w, int h) bool AVIDump::CreateFile() { - s_Codec = avcodec_find_encoder(CODEC_ID_MPEG1VIDEO); - if (!s_Codec) + AVCodec *codec = NULL; + + s_FormatContext = avformat_alloc_context(); + snprintf(s_FormatContext->filename, sizeof(s_FormatContext->filename), "%s", + StringFromFormat("%sframedump0.avi", File::GetUserPath(D_DUMPFRAMES_IDX)).c_str()); + + if (!(s_FormatContext->oformat = av_guess_format("avi", NULL, NULL)) || + !(s_Stream = av_new_stream(s_FormatContext, 0))) + { + CloseFile(); return false; + } - s_CodecContext = avcodec_alloc_context(); + s_Stream->codec->codec_id = s_FormatContext->oformat->video_codec; + 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 = (AVRational){1, 30}; + s_Stream->codec->gop_size = 12; + s_Stream->codec->pix_fmt = PIX_FMT_YUV420P; - s_CodecContext->bit_rate = 400000; - s_CodecContext->width = s_width; - s_CodecContext->height = s_height; - s_CodecContext->time_base = (AVRational){1, 30}; - s_CodecContext->gop_size = 10; - s_CodecContext->max_b_frames = 1; - s_CodecContext->pix_fmt = PIX_FMT_YUV420P; + av_set_parameters(s_FormatContext, NULL); - NOTICE_LOG(VIDEO, "Opening MPG file framedump.mpg for dumping"); - if ((avcodec_open(s_CodecContext, s_Codec) < 0) || - !(f_pFrameDump = fopen(StringFromFormat("%sframedump.mpg", - File::GetUserPath(D_DUMPFRAMES_IDX)).c_str(), "wb")) || - !(s_SwsContext = sws_getContext(s_width, s_height, PIX_FMT_BGR24, s_width, s_height, + if (!(codec = avcodec_find_encoder(s_Stream->codec->codec_id)) || + (avcodec_open(s_Stream->codec, codec) < 0)) + { + CloseFile(); + return false; + } + + if(!(s_SwsContext = sws_getContext(s_width, s_height, PIX_FMT_BGR24, s_width, s_height, PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL))) { - WARN_LOG(VIDEO, "Unable to initialize mpg dump file"); CloseFile(); return false; } @@ -276,6 +287,16 @@ bool AVIDump::CreateFile() s_OutBuffer = new uint8_t[s_size]; + NOTICE_LOG(VIDEO, "Opening file %s for dumping", s_FormatContext->filename); + if (url_fopen(&s_FormatContext->pb, s_FormatContext->filename, URL_WRONLY) < 0) + { + WARN_LOG(VIDEO, "Could not open %s", s_FormatContext->filename); + CloseFile(); + return false; + } + + av_write_header(s_FormatContext); + return true; } @@ -288,38 +309,45 @@ void AVIDump::AddFrame(uint8_t *data) s_height, s_YUVFrame->data, s_YUVFrame->linesize); // Encode and write the image - int s_iOutSize = avcodec_encode_video(s_CodecContext, s_OutBuffer, s_size, s_YUVFrame); - fwrite(s_OutBuffer, 1, s_iOutSize, f_pFrameDump); - fflush(f_pFrameDump); - - // Encode and write delayed frames - do + int outsize = avcodec_encode_video(s_Stream->codec, s_OutBuffer, s_size, s_YUVFrame); + while (outsize > 0) { - s_iOutSize = avcodec_encode_video(s_CodecContext, s_OutBuffer, s_size, NULL); - fwrite(s_OutBuffer, 1, s_iOutSize, f_pFrameDump); - fflush(f_pFrameDump); - } while (s_iOutSize); + AVPacket pkt; + av_init_packet(&pkt); + + if (s_Stream->codec->coded_frame->pts != (unsigned int)AV_NOPTS_VALUE) + pkt.pts = av_rescale_q(s_Stream->codec->coded_frame->pts, + s_Stream->codec->time_base, s_Stream->time_base); + if(s_Stream->codec->coded_frame->key_frame) + pkt.flags |= AV_PKT_FLAG_KEY; + pkt.stream_index = s_Stream->index; + pkt.data = s_OutBuffer; + pkt.size = outsize; + + // Write the compressed frame in the media file + av_interleaved_write_frame(s_FormatContext, &pkt); + + // Encode delayed frames + outsize = avcodec_encode_video(s_Stream->codec, s_OutBuffer, s_size, NULL); + } } void AVIDump::Stop() { - // Write MPG footer - s_OutBuffer[0] = 0x00; - s_OutBuffer[1] = 0x00; - s_OutBuffer[2] = 0x01; - s_OutBuffer[3] = 0xb7; - fwrite(s_OutBuffer, 1, 4, f_pFrameDump); - fflush(f_pFrameDump); - + av_write_trailer(s_FormatContext); CloseFile(); NOTICE_LOG(VIDEO, "Stopping frame dump"); } void AVIDump::CloseFile() { - if (f_pFrameDump) - fclose(f_pFrameDump); - f_pFrameDump = NULL; + if (s_Stream) + { + if (s_Stream->codec) + avcodec_close(s_Stream->codec); + av_free(s_Stream); + s_Stream = NULL; + } if (s_YUVBuffer) delete[] s_YUVBuffer; @@ -329,13 +357,6 @@ void AVIDump::CloseFile() delete[] s_OutBuffer; s_OutBuffer = NULL; - if (s_CodecContext) - { - avcodec_close(s_CodecContext); - av_free(s_CodecContext); - } - s_CodecContext = NULL; - if (s_BGRFrame) av_free(s_BGRFrame); s_BGRFrame = NULL; @@ -347,6 +368,13 @@ void AVIDump::CloseFile() if (s_SwsContext) sws_freeContext(s_SwsContext); s_SwsContext = NULL; + + if (s_FormatContext) + { + if (s_FormatContext->pb) + url_fclose(s_FormatContext->pb); + av_free(s_FormatContext); + } } #endif diff --git a/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp b/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp index 805d7b3bf0..ef4ad64282 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp @@ -1124,12 +1124,8 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons else { OSD::AddMessage(StringFromFormat( - #ifdef _WIN32 - "Dumping Frames to \"%sframedump0.avi\" (%dx%d RGB24)", - #else - "Dumping Frames to \"%sframedump.mpg\" (%dx%d RGB24)", - #endif - File::GetUserPath(D_DUMPFRAMES_IDX), w, h).c_str(), 2000); + "Dumping Frames to \"%sframedump0.avi\" (%dx%d RGB24)", + File::GetUserPath(D_DUMPFRAMES_IDX), w, h).c_str(), 2000); } } if (s_bAVIDumping)