mirror of https://github.com/mgba-emu/mgba.git
FFmpeg: Decoder skeleton
This commit is contained in:
parent
3795a64b77
commit
390ed6c83c
|
@ -535,8 +535,8 @@ if(USE_FFMPEG)
|
|||
endif()
|
||||
include_directories(AFTER ${FFMPEG_INCLUDE_DIRS} ${LIBAVCODEC_INCLUDE_DIRS} ${LIBAVFILTER_INCLUDE_DIRS} ${LIBAVFORMAT_INCLUDE_DIRS} ${LIBAVRESAMPLE_INCLUDE_DIRS} ${LIBAVUTIL_INCLUDE_DIRS} ${LIBSWRESAMPLE_INCLUDE_DIRS} ${LIBSWSCALE_INCLUDE_DIRS})
|
||||
link_directories(${FFMPEG_LIBRARY_DIRS} ${LIBAVCODEC_LIBRARY_DIRS} ${LIBAVFILTER_LIBRARY_DIRS} ${LIBAVFORMAT_LIBRARY_DIRS} ${LIBAVRESAMPLE_LIBRARY_DIRS} ${LIBAVUTIL_LIBRARY_DIRS} ${LIBSWRESAMPLE_LIBRARY_DIRS} ${LIBSWSCALE_LIBRARY_DIRS})
|
||||
list(APPEND FEATURE_SRC "${CMAKE_CURRENT_SOURCE_DIR}/src/feature/ffmpeg/ffmpeg-encoder.c")
|
||||
list(APPEND DEPENDENCY_LIB ${FFMPEG_LIBRARIES} ${LIBAVCODEC_LIBRARIES} ${LIBAVFILTER_LIBRARIES} ${LIBAVFORMAT_LIBRARIES} ${LIBAVRESAMPLE_LIBRARIES} ${LIBAVUTIL_LIBRARIES} ${LIBSWSCALE_LIBRARIES} ${LIBSWRESAMPLE_LIBRARIES})
|
||||
list(APPEND FEATURE_SRC "${CMAKE_CURRENT_SOURCE_DIR}/src/feature/ffmpeg/ffmpeg-encoder.c" "${CMAKE_CURRENT_SOURCE_DIR}/src/feature/ffmpeg/ffmpeg-decoder.c")
|
||||
list(APPEND DEPENDENCY_LIB ${FFMPEG_LIBRARIES} ${LIBAVCODEC_LIBRARIES} ${LIBAVFILTER_LIBRARIES} ${LIBAVFORMAT_LIBRARIES} ${LIBAVRESAMPLE_LIBRARIES} ${LIBAVUTIL_LIBRARIES} ${LIBSWSCALE_LIBRARIES} ${LIBSWRESAMPLE_LIBRARIES})
|
||||
if(WIN32 AND NOT DEFINED VCPKG_TARGET_TRIPLET)
|
||||
list(APPEND DEPENDENCY_LIB bcrypt)
|
||||
endif()
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
/* Copyright (c) 2013-2020 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#ifndef FFMPEG_COMMON
|
||||
#define FFMPEG_COMMON
|
||||
|
||||
#include <mgba-util/common.h>
|
||||
|
||||
CXX_GUARD_START
|
||||
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libavcodec/version.h>
|
||||
|
||||
// Version 57.16 in FFmpeg
|
||||
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 37, 100)
|
||||
#define FFMPEG_USE_PACKETS
|
||||
#endif
|
||||
|
||||
// Version 57.15 in libav
|
||||
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 35, 0)
|
||||
#define FFMPEG_USE_NEW_BSF
|
||||
#endif
|
||||
|
||||
// Version 57.14 in libav
|
||||
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 0)
|
||||
#define FFMPEG_USE_CODECPAR
|
||||
#endif
|
||||
|
||||
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 8, 0)
|
||||
#define FFMPEG_USE_PACKET_UNREF
|
||||
#endif
|
||||
|
||||
CXX_GUARD_END
|
||||
|
||||
#endif
|
|
@ -0,0 +1,170 @@
|
|||
/* Copyright (c) 2013-2020 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "ffmpeg-decoder.h"
|
||||
|
||||
void FFmpegDecoderInit(struct FFmpegDecoder* decoder) {
|
||||
#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(58, 9, 100)
|
||||
av_register_all();
|
||||
#endif
|
||||
|
||||
memset(decoder, 0, sizeof(*decoder));
|
||||
decoder->audioStream = -1;
|
||||
decoder->videoStream = -1;
|
||||
}
|
||||
|
||||
bool FFmpegDecoderOpen(struct FFmpegDecoder* decoder, const char* infile) {
|
||||
if (FFmpegDecoderIsOpen(decoder)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (avformat_open_input(&decoder->context, infile, NULL, NULL) < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (avformat_find_stream_info(decoder->context, NULL) < 0) {
|
||||
FFmpegDecoderClose(decoder);
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned i;
|
||||
for (i = 0; i < decoder->context->nb_streams; ++i) {
|
||||
#ifdef FFMPEG_USE_CODECPAR
|
||||
enum AVMediaType type = decoder->context->streams[i]->codecpar->codec_type;
|
||||
#else
|
||||
enum AVMediaType type = decoder->context->streams[i]->codec->codec_type;
|
||||
#endif
|
||||
struct AVCodec* codec;
|
||||
struct AVCodecContext* context = NULL;
|
||||
if (type == AVMEDIA_TYPE_VIDEO && decoder->videoStream < 0) {
|
||||
decoder->video = avcodec_alloc_context3(NULL);
|
||||
if (!decoder->video) {
|
||||
FFmpegDecoderClose(decoder);
|
||||
return false;
|
||||
}
|
||||
context = decoder->video;
|
||||
}
|
||||
|
||||
if (type == AVMEDIA_TYPE_AUDIO && decoder->audioStream < 0) {
|
||||
decoder->audio = avcodec_alloc_context3(NULL);
|
||||
if (!decoder->audio) {
|
||||
FFmpegDecoderClose(decoder);
|
||||
return false;
|
||||
}
|
||||
context = decoder->audio;
|
||||
}
|
||||
if (!context) {
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifdef FFMPEG_USE_CODECPAR
|
||||
if (avcodec_parameters_to_context(context, decoder->context->streams[i]->codecpar) < 0) {
|
||||
FFmpegDecoderClose(decoder);
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
codec = avcodec_find_decoder(context->codec_id);
|
||||
if (!codec) {
|
||||
FFmpegDecoderClose(decoder);
|
||||
return false;
|
||||
}
|
||||
if (avcodec_open2(context, codec, NULL) < 0) {
|
||||
FFmpegDecoderClose(decoder);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (type == AVMEDIA_TYPE_VIDEO) {
|
||||
decoder->videoStream = i;
|
||||
decoder->width = context->coded_width;
|
||||
decoder->height = context->coded_height;
|
||||
if (decoder->d.videoDimensionsChanged) {
|
||||
decoder->d.videoDimensionsChanged(&decoder->d, decoder->width, decoder->height);
|
||||
}
|
||||
#if LIBAVCODEC_VERSION_MAJOR >= 55
|
||||
decoder->videoFrame = av_frame_alloc();
|
||||
#else
|
||||
decoder->videoFrame = avcodec_alloc_frame();
|
||||
#endif
|
||||
}
|
||||
|
||||
if (type == AVMEDIA_TYPE_AUDIO) {
|
||||
decoder->audioStream = i;
|
||||
#if LIBAVCODEC_VERSION_MAJOR >= 55
|
||||
decoder->audioFrame = av_frame_alloc();
|
||||
#else
|
||||
decoder->audioFrame = avcodec_alloc_frame();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void FFmpegDecoderClose(struct FFmpegDecoder* decoder) {
|
||||
if (decoder->audioFrame) {
|
||||
#if LIBAVCODEC_VERSION_MAJOR >= 55
|
||||
av_frame_free(&decoder->audioFrame);
|
||||
#else
|
||||
avcodec_free_frame(&decoder->audioFrame);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (decoder->audio) {
|
||||
avcodec_close(decoder->audio);
|
||||
decoder->audio = NULL;
|
||||
}
|
||||
|
||||
if (decoder->videoFrame) {
|
||||
#if LIBAVCODEC_VERSION_MAJOR >= 55
|
||||
av_frame_free(&decoder->videoFrame);
|
||||
#else
|
||||
avcodec_free_frame(&decoder->videoFrame);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (decoder->video) {
|
||||
avcodec_close(decoder->video);
|
||||
decoder->video = NULL;
|
||||
}
|
||||
|
||||
if (decoder->context) {
|
||||
avformat_close_input(&decoder->context);
|
||||
}
|
||||
}
|
||||
|
||||
bool FFmpegDecoderIsOpen(struct FFmpegDecoder* decoder) {
|
||||
return !!decoder->context;
|
||||
}
|
||||
|
||||
bool FFmpegDecoderRead(struct FFmpegDecoder* decoder) {
|
||||
while (true) {
|
||||
AVPacket packet;
|
||||
if (av_read_frame(decoder->context, &packet) < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (packet.stream_index == decoder->audioStream) {
|
||||
|
||||
} else if (packet.stream_index == decoder->videoStream) {
|
||||
#ifdef FFMPEG_USE_CODECPAR
|
||||
if (avcodec_send_packet(decoder->video, &packet) < 0) {
|
||||
|
||||
}
|
||||
if (avcodec_receive_frame(decoder->video, decoder->videoFrame) < 0) {
|
||||
|
||||
}
|
||||
#else
|
||||
int gotData;
|
||||
if (avcodec_decode_video2(decoder->video, decoder->videoFrame, &gotData, &packet) < 0 || !gotData) {
|
||||
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#ifdef FFMPEG_USE_PACKET_UNREF
|
||||
av_packet_unref(&packet);
|
||||
#else
|
||||
av_free_packet(&packet);
|
||||
#endif
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/* Copyright (c) 2013-2020 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#ifndef FFMPEG_DECODER
|
||||
#define FFMPEG_DECODER
|
||||
|
||||
#include <mgba-util/common.h>
|
||||
|
||||
CXX_GUARD_START
|
||||
|
||||
#include <mgba/core/interface.h>
|
||||
|
||||
#include "feature/ffmpeg/ffmpeg-common.h"
|
||||
|
||||
#define FFMPEG_DECODER_BUFSIZE 4096
|
||||
|
||||
struct FFmpegDecoder {
|
||||
struct mAVStream d;
|
||||
struct AVFormatContext* context;
|
||||
|
||||
int audioStream;
|
||||
AVFrame* audioFrame;
|
||||
struct AVCodecContext* audio;
|
||||
|
||||
int videoStream;
|
||||
AVFrame* videoFrame;
|
||||
struct AVCodecContext* video;
|
||||
|
||||
int width;
|
||||
int height;
|
||||
};
|
||||
|
||||
void FFmpegDecoderInit(struct FFmpegDecoder*);
|
||||
bool FFmpegDecoderOpen(struct FFmpegDecoder*, const char* infile);
|
||||
void FFmpegDecoderClose(struct FFmpegDecoder*);
|
||||
bool FFmpegDecoderIsOpen(struct FFmpegDecoder*);
|
||||
bool FFmpegDecoderRead(struct FFmpegDecoder*);
|
||||
|
||||
CXX_GUARD_END
|
||||
|
||||
#endif
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include <mgba/core/core.h>
|
||||
#include <mgba/gba/interface.h>
|
||||
#include <mgba/internal/gba/gba.h>
|
||||
#include <mgba-util/math.h>
|
||||
|
||||
#include <libavcodec/version.h>
|
||||
|
|
|
@ -10,29 +10,9 @@
|
|||
|
||||
CXX_GUARD_START
|
||||
|
||||
#include <mgba/internal/gba/gba.h>
|
||||
#include <mgba/core/interface.h>
|
||||
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libavcodec/version.h>
|
||||
|
||||
// Version 57.16 in FFmpeg
|
||||
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 37, 100)
|
||||
#define FFMPEG_USE_PACKETS
|
||||
#endif
|
||||
|
||||
// Version 57.15 in libav
|
||||
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 35, 0)
|
||||
#define FFMPEG_USE_NEW_BSF
|
||||
#endif
|
||||
|
||||
// Version 57.14 in libav
|
||||
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 0)
|
||||
#define FFMPEG_USE_CODECPAR
|
||||
#endif
|
||||
|
||||
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 8, 0)
|
||||
#define FFMPEG_USE_PACKET_UNREF
|
||||
#endif
|
||||
#include "feature/ffmpeg/ffmpeg-common.h"
|
||||
|
||||
#define FFMPEG_FILTERS_MAX 4
|
||||
|
||||
|
@ -73,7 +53,7 @@ struct FFmpegEncoder {
|
|||
struct AVCodecContext* video;
|
||||
enum AVPixelFormat pixFormat;
|
||||
enum AVPixelFormat ipixFormat;
|
||||
struct AVFrame* videoFrame;
|
||||
AVFrame* videoFrame;
|
||||
int width;
|
||||
int height;
|
||||
int iwidth;
|
||||
|
|
|
@ -16,6 +16,10 @@
|
|||
#include <mgba-util/vector.h>
|
||||
#include <mgba-util/vfs.h>
|
||||
|
||||
#ifdef USE_FFMPEG
|
||||
#include "feature/ffmpeg/ffmpeg-decoder.h"
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <mgba-util/platform/windows/getopt.h>
|
||||
#else
|
||||
|
@ -566,10 +570,12 @@ void CInemaTestRun(struct CInemaTest* test, struct Table* configTree) {
|
|||
unsigned limit = 9999;
|
||||
unsigned skip = 0;
|
||||
unsigned fail = 0;
|
||||
unsigned video = 0;
|
||||
|
||||
CInemaConfigGetUInt(configTree, test->name, "frames", &limit);
|
||||
CInemaConfigGetUInt(configTree, test->name, "skip", &skip);
|
||||
CInemaConfigGetUInt(configTree, test->name, "fail", &fail);
|
||||
CInemaConfigGetUInt(configTree, test->name, "video", &video);
|
||||
CInemaConfigLoad(configTree, test->name, core);
|
||||
|
||||
core->loadROM(core, rom);
|
||||
|
@ -600,7 +606,13 @@ void CInemaTestRun(struct CInemaTest* test, struct Table* configTree) {
|
|||
.height = image.height,
|
||||
.stride = image.width,
|
||||
};
|
||||
if (_loadBaseline(dir, &expected, frame, &test->status)) {
|
||||
bool baselineFound = false;
|
||||
if (video) {
|
||||
baselineFound = false;
|
||||
} else {
|
||||
baselineFound = _loadBaseline(dir, &expected, frame, &test->status);
|
||||
}
|
||||
if (baselineFound) {
|
||||
uint8_t* testPixels = image.data;
|
||||
uint8_t* expectPixels = expected.data;
|
||||
size_t x;
|
||||
|
|
Loading…
Reference in New Issue