mirror of https://github.com/mgba-emu/mgba.git
Core: Allow changing video dimensions
This commit is contained in:
parent
aac1add766
commit
f33a70a9dc
|
@ -21,6 +21,7 @@ typedef uint32_t color_t;
|
|||
struct blip_t;
|
||||
|
||||
struct mAVStream {
|
||||
void (*videoDimensionsChanged)(struct mAVStream*, unsigned width, unsigned height);
|
||||
void (*postVideoFrame)(struct mAVStream*, const color_t* buffer, size_t stride);
|
||||
void (*postAudioFrame)(struct mAVStream*, int16_t left, int16_t right);
|
||||
void (*postAudioBuffer)(struct mAVStream*, struct blip_t* left, struct blip_t* right);
|
||||
|
|
|
@ -117,6 +117,9 @@ static size_t _GBCoreGetAudioBufferSize(struct mCore* core) {
|
|||
static void _GBCoreSetAVStream(struct mCore* core, struct mAVStream* stream) {
|
||||
struct GB* gb = core->board;
|
||||
gb->stream = stream;
|
||||
if (stream && stream->videoDimensionsChanged) {
|
||||
stream->videoDimensionsChanged(stream, GB_VIDEO_HORIZONTAL_PIXELS, GB_VIDEO_VERTICAL_PIXELS);
|
||||
}
|
||||
}
|
||||
|
||||
static bool _GBCoreLoadROM(struct mCore* core, struct VFile* vf) {
|
||||
|
|
|
@ -148,6 +148,9 @@ static size_t _GBACoreGetAudioBufferSize(struct mCore* core) {
|
|||
static void _GBACoreSetAVStream(struct mCore* core, struct mAVStream* stream) {
|
||||
struct GBA* gba = core->board;
|
||||
gba->stream = stream;
|
||||
if (stream && stream->videoDimensionsChanged) {
|
||||
stream->videoDimensionsChanged(stream, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS);
|
||||
}
|
||||
}
|
||||
|
||||
static bool _GBACoreLoadROM(struct mCore* core, struct VFile* vf) {
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
static void _ffmpegPostVideoFrame(struct mAVStream*, const color_t* pixels, size_t stride);
|
||||
static void _ffmpegPostAudioFrame(struct mAVStream*, int16_t left, int16_t right);
|
||||
static void _ffmpegSetVideoDimensions(struct mAVStream*, unsigned width, unsigned height);
|
||||
|
||||
enum {
|
||||
PREFERRED_SAMPLE_RATE = 0x8000
|
||||
|
@ -32,6 +33,7 @@ enum {
|
|||
void FFmpegEncoderInit(struct FFmpegEncoder* encoder) {
|
||||
av_register_all();
|
||||
|
||||
encoder->d.videoDimensionsChanged = _ffmpegSetVideoDimensions;
|
||||
encoder->d.postVideoFrame = _ffmpegPostVideoFrame;
|
||||
encoder->d.postAudioFrame = _ffmpegPostAudioFrame;
|
||||
encoder->d.postAudioBuffer = 0;
|
||||
|
@ -43,9 +45,12 @@ void FFmpegEncoderInit(struct FFmpegEncoder* encoder) {
|
|||
FFmpegEncoderSetVideo(encoder, "png", 0);
|
||||
FFmpegEncoderSetContainer(encoder, "matroska");
|
||||
FFmpegEncoderSetDimensions(encoder, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS);
|
||||
encoder->iwidth = VIDEO_HORIZONTAL_PIXELS;
|
||||
encoder->iheight = VIDEO_VERTICAL_PIXELS;
|
||||
encoder->resampleContext = 0;
|
||||
encoder->absf = 0;
|
||||
encoder->context = 0;
|
||||
encoder->scaleContext = NULL;
|
||||
}
|
||||
|
||||
bool FFmpegEncoderSetAudio(struct FFmpegEncoder* encoder, const char* acodec, unsigned abr) {
|
||||
|
@ -290,22 +295,7 @@ bool FFmpegEncoderOpen(struct FFmpegEncoder* encoder, const char* outfile) {
|
|||
encoder->videoFrame->width = encoder->video->width;
|
||||
encoder->videoFrame->height = encoder->video->height;
|
||||
encoder->videoFrame->pts = 0;
|
||||
encoder->scaleContext = sws_getContext(VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS,
|
||||
#ifdef COLOR_16_BIT
|
||||
#ifdef COLOR_5_6_5
|
||||
AV_PIX_FMT_RGB565,
|
||||
#else
|
||||
AV_PIX_FMT_BGR555,
|
||||
#endif
|
||||
#else
|
||||
#ifndef USE_LIBAV
|
||||
AV_PIX_FMT_0BGR32,
|
||||
#else
|
||||
AV_PIX_FMT_BGR32,
|
||||
#endif
|
||||
#endif
|
||||
encoder->videoFrame->width, encoder->videoFrame->height, encoder->video->pix_fmt,
|
||||
SWS_POINT, 0, 0, 0);
|
||||
_ffmpegSetVideoDimensions(&encoder->d, encoder->iwidth, encoder->iheight);
|
||||
av_image_alloc(encoder->videoFrame->data, encoder->videoFrame->linesize, encoder->video->width, encoder->video->height, encoder->video->pix_fmt, 32);
|
||||
|
||||
avio_open(&encoder->context->pb, outfile, AVIO_FLAG_WRITE);
|
||||
|
@ -351,6 +341,7 @@ void FFmpegEncoderClose(struct FFmpegEncoder* encoder) {
|
|||
avcodec_close(encoder->video);
|
||||
|
||||
sws_freeContext(encoder->scaleContext);
|
||||
encoder->scaleContext = NULL;
|
||||
|
||||
avformat_free_context(encoder->context);
|
||||
encoder->context = 0;
|
||||
|
@ -437,7 +428,7 @@ void _ffmpegPostVideoFrame(struct mAVStream* stream, const color_t* pixels, size
|
|||
encoder->videoFrame->pts = av_rescale_q(encoder->currentVideoFrame, encoder->video->time_base, encoder->videoStream->time_base);
|
||||
++encoder->currentVideoFrame;
|
||||
|
||||
sws_scale(encoder->scaleContext, (const uint8_t* const*) &pixels, (const int*) &stride, 0, VIDEO_VERTICAL_PIXELS, encoder->videoFrame->data, encoder->videoFrame->linesize);
|
||||
sws_scale(encoder->scaleContext, (const uint8_t* const*) &pixels, (const int*) &stride, 0, encoder->iheight, encoder->videoFrame->data, encoder->videoFrame->linesize);
|
||||
|
||||
int gotData;
|
||||
avcodec_encode_video2(encoder->video, &packet, encoder->videoFrame, &gotData);
|
||||
|
@ -450,3 +441,28 @@ void _ffmpegPostVideoFrame(struct mAVStream* stream, const color_t* pixels, size
|
|||
}
|
||||
av_free_packet(&packet);
|
||||
}
|
||||
|
||||
static void _ffmpegSetVideoDimensions(struct mAVStream* stream, unsigned width, unsigned height) {
|
||||
struct FFmpegEncoder* encoder = (struct FFmpegEncoder*) stream;
|
||||
encoder->iwidth = width;
|
||||
encoder->iheight = height;
|
||||
if (encoder->scaleContext) {
|
||||
sws_freeContext(encoder->scaleContext);
|
||||
}
|
||||
encoder->scaleContext = sws_getContext(encoder->iwidth, encoder->iheight,
|
||||
#ifdef COLOR_16_BIT
|
||||
#ifdef COLOR_5_6_5
|
||||
AV_PIX_FMT_RGB565,
|
||||
#else
|
||||
AV_PIX_FMT_BGR555,
|
||||
#endif
|
||||
#else
|
||||
#ifndef USE_LIBAV
|
||||
AV_PIX_FMT_0BGR32,
|
||||
#else
|
||||
AV_PIX_FMT_BGR32,
|
||||
#endif
|
||||
#endif
|
||||
encoder->videoFrame->width, encoder->videoFrame->height, encoder->video->pix_fmt,
|
||||
SWS_POINT, 0, 0, 0);
|
||||
}
|
||||
|
|
|
@ -42,6 +42,8 @@ struct FFmpegEncoder {
|
|||
struct AVFrame* videoFrame;
|
||||
int width;
|
||||
int height;
|
||||
int iwidth;
|
||||
int iheight;
|
||||
int64_t currentVideoFrame;
|
||||
struct SwsContext* scaleContext;
|
||||
struct AVStream* videoStream;
|
||||
|
|
|
@ -9,16 +9,21 @@
|
|||
#include "util/string.h"
|
||||
|
||||
static void _magickPostVideoFrame(struct mAVStream*, const color_t* pixels, size_t stride);
|
||||
static void _magickVideoDimensionsChanged(struct mAVStream*, unsigned width, unsigned height);
|
||||
|
||||
void ImageMagickGIFEncoderInit(struct ImageMagickGIFEncoder* encoder) {
|
||||
encoder->wand = 0;
|
||||
|
||||
encoder->d.videoDimensionsChanged = _magickVideoDimensionsChanged;
|
||||
encoder->d.postVideoFrame = _magickPostVideoFrame;
|
||||
encoder->d.postAudioFrame = 0;
|
||||
encoder->d.postAudioBuffer = 0;
|
||||
|
||||
encoder->frameskip = 2;
|
||||
encoder->delayMs = -1;
|
||||
|
||||
encoder->iwidth = VIDEO_HORIZONTAL_PIXELS;
|
||||
encoder->iheight = VIDEO_VERTICAL_PIXELS;
|
||||
}
|
||||
|
||||
void ImageMagickGIFEncoderSetParams(struct ImageMagickGIFEncoder* encoder, int frameskip, int delayMs) {
|
||||
|
@ -35,7 +40,7 @@ bool ImageMagickGIFEncoderOpen(struct ImageMagickGIFEncoder* encoder, const char
|
|||
MagickSetImageFormat(encoder->wand, "GIF");
|
||||
MagickSetImageDispose(encoder->wand, PreviousDispose);
|
||||
encoder->outfile = strdup(outfile);
|
||||
encoder->frame = malloc(VIDEO_HORIZONTAL_PIXELS * VIDEO_VERTICAL_PIXELS * 4);
|
||||
encoder->frame = malloc(encoder->iwidth * encoder->iheight * 4);
|
||||
encoder->currentFrame = 0;
|
||||
return true;
|
||||
}
|
||||
|
@ -68,11 +73,11 @@ static void _magickPostVideoFrame(struct mAVStream* stream, const color_t* pixel
|
|||
|
||||
const uint8_t* p8 = (const uint8_t*) pixels;
|
||||
size_t row;
|
||||
for (row = 0; row < VIDEO_VERTICAL_PIXELS; ++row) {
|
||||
memcpy(&encoder->frame[row * VIDEO_HORIZONTAL_PIXELS], &p8[row * 4 * stride], VIDEO_HORIZONTAL_PIXELS * 4);
|
||||
for (row = 0; row < encoder->iheight; ++row) {
|
||||
memcpy(&encoder->frame[row * encoder->iwidth], &p8[row * 4 * stride], encoder->iwidth * 4);
|
||||
}
|
||||
|
||||
MagickConstituteImage(encoder->wand, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, "RGBP", CharPixel, encoder->frame);
|
||||
MagickConstituteImage(encoder->wand, encoder->iwidth, encoder->iheight, "RGBP", CharPixel, encoder->frame);
|
||||
uint64_t ts = encoder->currentFrame;
|
||||
uint64_t nts = encoder->currentFrame + encoder->frameskip + 1;
|
||||
if (encoder->delayMs >= 0) {
|
||||
|
@ -89,3 +94,9 @@ static void _magickPostVideoFrame(struct mAVStream* stream, const color_t* pixel
|
|||
MagickSetImageDelay(encoder->wand, nts - ts);
|
||||
++encoder->currentFrame;
|
||||
}
|
||||
|
||||
static void _magickVideoDimensionsChanged(struct mAVStream* stream, unsigned width, unsigned height) {
|
||||
struct ImageMagickGIFEncoder* encoder = (struct ImageMagickGIFEncoder*) stream;
|
||||
encoder->iwidth = width;
|
||||
encoder->iheight = height;
|
||||
}
|
||||
|
|
|
@ -22,6 +22,9 @@ struct ImageMagickGIFEncoder {
|
|||
unsigned currentFrame;
|
||||
int frameskip;
|
||||
int delayMs;
|
||||
|
||||
unsigned iwidth;
|
||||
unsigned iheight;
|
||||
};
|
||||
|
||||
void ImageMagickGIFEncoderInit(struct ImageMagickGIFEncoder*);
|
||||
|
|
Loading…
Reference in New Issue