FFmpeg: Decoder skeleton

This commit is contained in:
Vicki Pfau 2020-06-28 19:03:21 -07:00
parent 3795a64b77
commit 390ed6c83c
7 changed files with 269 additions and 26 deletions

View File

@ -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()

View File

@ -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

View File

@ -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
}
}

View File

@ -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

View File

@ -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>

View File

@ -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;

View File

@ -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;