Core: Allow changing video dimensions

This commit is contained in:
Jeffrey Pfau 2016-02-15 22:19:15 -08:00
parent aac1add766
commit f33a70a9dc
7 changed files with 60 additions and 21 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -22,6 +22,9 @@ struct ImageMagickGIFEncoder {
unsigned currentFrame;
int frameskip;
int delayMs;
unsigned iwidth;
unsigned iheight;
};
void ImageMagickGIFEncoderInit(struct ImageMagickGIFEncoder*);