all repos — mgba @ e6ea94d2296eae963a48a18d009217a38d92bf9b

mGBA Game Boy Advance Emulator

src/platform/imagemagick/imagemagick-gif-encoder.c (view raw)

 1#include "imagemagick-gif-encoder.h"
 2
 3#include "gba-video.h"
 4
 5static void _magickPostVideoFrame(struct GBAAVStream*, struct GBAVideoRenderer* renderer);
 6static void _magickPostAudioFrame(struct GBAAVStream*, int32_t left, int32_t right);
 7
 8void ImageMagickGIFEncoderInit(struct ImageMagickGIFEncoder* encoder) {
 9	encoder->wand = 0;
10
11	encoder->d.postVideoFrame = _magickPostVideoFrame;
12	encoder->d.postAudioFrame = _magickPostAudioFrame;
13
14	encoder->frameskip = 2;
15}
16
17bool ImageMagickGIFEncoderOpen(struct ImageMagickGIFEncoder* encoder, const char* outfile) {
18	MagickWandGenesis();
19	encoder->wand = NewMagickWand();
20	encoder->outfile = strdup(outfile);
21	encoder->frame = malloc(VIDEO_HORIZONTAL_PIXELS * VIDEO_VERTICAL_PIXELS * 4);
22	encoder->currentFrame = 0;
23	return true;
24}
25void ImageMagickGIFEncoderClose(struct ImageMagickGIFEncoder* encoder) {
26	if (!encoder->wand) {
27		return;
28	}
29	MagickWriteImages(encoder->wand, encoder->outfile, MagickTrue);
30	free(encoder->outfile);
31	free(encoder->frame);
32	DestroyMagickWand(encoder->wand);
33	encoder->wand = 0;
34	MagickWandTerminus();
35}
36
37bool ImageMagickGIFEncoderIsOpen(struct ImageMagickGIFEncoder* encoder) {
38	return !!encoder->wand;
39}
40
41static void _magickPostVideoFrame(struct GBAAVStream* stream, struct GBAVideoRenderer* renderer) {
42	struct ImageMagickGIFEncoder* encoder = (struct ImageMagickGIFEncoder*) stream;
43
44	if (encoder->currentFrame % (encoder->frameskip + 1)) {
45		++encoder->currentFrame;
46		return;
47	}
48
49	uint8_t* pixels;
50	unsigned stride;
51	renderer->getPixels(renderer, &stride, (void**) &pixels);
52	size_t row;
53	for (row = 0; row < VIDEO_VERTICAL_PIXELS; ++row) {
54		memcpy(&encoder->frame[row * VIDEO_HORIZONTAL_PIXELS], &pixels[row * 4 *stride], VIDEO_HORIZONTAL_PIXELS * 4);
55	}
56
57	MagickConstituteImage(encoder->wand, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, "RGBP", CharPixel, encoder->frame);
58	uint64_t ts = encoder->currentFrame;
59	uint64_t nts = encoder->currentFrame + encoder->frameskip + 1;
60	ts *= VIDEO_TOTAL_LENGTH * 100;
61	nts *= VIDEO_TOTAL_LENGTH * 100;
62	ts /= GBA_ARM7TDMI_FREQUENCY;
63	nts /= GBA_ARM7TDMI_FREQUENCY;
64	MagickSetImageDelay(encoder->wand, nts - ts);
65	++encoder->currentFrame;
66}
67
68static void _magickPostAudioFrame(struct GBAAVStream* stream, int32_t left, int32_t right) {
69	UNUSED(stream);
70	UNUSED(left);
71	UNUSED(right);
72	// This is a video-only format...
73}