all repos — mgba @ f6a7fedb2813d070a07cd6da65e8ddd666cd41d1

mGBA Game Boy Advance Emulator

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

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