Decode whole buffers
[swfdec.git] / tools / swfdec-extract.c
blobb864fef86df561a2f99de85629b901a3678defe9
1 /* Swfdec
2 * Copyright (C) 2006-2008 Benjamin Otte <otte@gnome.org>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301 USA
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
24 #include <math.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <cairo.h>
28 #ifdef CAIRO_HAS_SVG_SURFACE
29 # include <cairo-svg.h>
30 #endif
31 #ifdef CAIRO_HAS_PDF_SURFACE
32 # include <cairo-pdf.h>
33 #endif
34 #include <swfdec/swfdec.h>
35 #include <swfdec/swfdec_audio_stream.h>
36 #include <swfdec/swfdec_button.h>
37 #include <swfdec/swfdec_graphic.h>
38 #include <swfdec/swfdec_image.h>
39 #include <swfdec/swfdec_player_internal.h>
40 #include <swfdec/swfdec_sound.h>
41 #include <swfdec/swfdec_sprite.h>
42 #include <swfdec/swfdec_sprite_movie.h>
43 #include <swfdec/swfdec_swf_decoder.h>
44 #include <swfdec/swfdec_renderer_internal.h>
45 #include <swfdec/swfdec_resource.h>
47 static SwfdecBuffer *
48 encode_wav (SwfdecBuffer *buffer)
50 SwfdecBuffer *wav = swfdec_buffer_new (buffer->length + 44);
51 unsigned char *data;
52 guint i;
54 data = wav->data;
55 /* FIXME: too much magic in this memmove */
56 memmove (data, "RIFF----WAVEfmt \020\0\0\0"
57 "\001\0ccRRRRbbbbAAbbdata", 40);
58 *(guint32 *) (void *) &data[4] = GUINT32_TO_LE (buffer->length + 36);
59 /* rate */
60 *(guint16 *) (void *) &data[22] = GUINT16_TO_LE (44100);
61 /* channels */
62 *(guint32 *) (void *) &data[24] = GUINT32_TO_LE (2);
63 /* bits per sample */
64 *(guint16 *) (void *) &data[34] = GUINT16_TO_LE (16);
65 /* block align */
66 *(guint16 *) (void *) &data[32] = GUINT16_TO_LE (16 * 2);
67 /* bytes per second */
68 *(guint32 *) (void *) &data[28] = GUINT32_TO_LE (16 * 2 * 44100);
69 *(guint32 *) (void *) &data[40] = GUINT32_TO_LE (buffer->length);
70 data += 44;
71 for (i = 0; i < buffer->length; i += 2) {
72 *(gint16 *) (void *) (data + i) = GINT16_TO_LE (*(gint16* ) (void *) (buffer->data + i));
74 return wav;
77 static gboolean
78 export_sound (SwfdecSound *sound, const char *filename)
80 GError *error = NULL;
81 SwfdecBuffer *wav, *buffer;
83 /* try to render the sound, that should decode it. */
84 buffer = swfdec_sound_get_decoded (sound);
85 if (buffer == NULL) {
86 g_printerr ("Couldn't decode sound. For extraction of streams extract the sprite.\n");
87 return FALSE;
89 wav = encode_wav (buffer);
90 if (!g_file_set_contents (filename, (char *) wav->data,
91 wav->length, &error)) {
92 g_printerr ("Couldn't save sound to file \"%s\": %s\n", filename, error->message);
93 swfdec_buffer_unref (wav);
94 g_error_free (error);
95 return FALSE;
97 swfdec_buffer_unref (wav);
98 return TRUE;
101 static gboolean
102 export_sprite_sound (SwfdecSprite *sprite, const char *filename)
104 g_printerr ("FIXME: Someone implement sound export from sprites plz\n");
105 return FALSE;
106 #if 0
107 GError *error = NULL;
108 guint i, depth;
109 SwfdecAudio *audio;
110 SwfdecBufferQueue *queue;
111 SwfdecBuffer *buffer, *wav;
113 audio = swfdec_audio_stream_new (NULL, sprite, i);
114 i = 4096;
115 queue = swfdec_buffer_queue_new ();
116 while (i > 0) {
117 buffer = swfdec_buffer_new0 (i * 4);
119 swfdec_audio_render (audio, (gint16 *) (void *) buffer->data, 0, i);
121 i = swfdec_audio_iterate (audio, i);
122 i = MIN (i, 4096);
123 swfdec_buffer_queue_push (queue, buffer);
125 depth = swfdec_buffer_queue_get_depth (queue);
126 if (depth == 0) {
127 swfdec_buffer_queue_unref (queue);
128 g_printerr ("Sprite contains no sound\n");
129 return FALSE;
131 buffer = swfdec_buffer_queue_pull (queue, depth);
132 swfdec_buffer_queue_unref (queue);
133 wav = encode_wav (buffer);
134 swfdec_buffer_unref (buffer);
135 if (!g_file_set_contents (filename, (char *) wav->data,
136 wav->length, &error)) {
137 g_printerr ("Couldn't save sound to file \"%s\": %s\n", filename, error->message);
138 swfdec_buffer_unref (wav);
139 g_error_free (error);
140 return FALSE;
142 swfdec_buffer_unref (wav);
143 return TRUE;
144 #endif
147 static cairo_surface_t *
148 surface_create_for_filename (const char *filename, int width, int height)
150 G_GNUC_UNUSED guint len = strlen (filename);
151 cairo_surface_t *surface;
152 if (FALSE) {
153 #ifdef CAIRO_HAS_PDF_SURFACE
154 } else if (len >= 3 && g_ascii_strcasecmp (filename + len - 3, "pdf") == 0) {
155 surface = cairo_pdf_surface_create (filename, width, height);
156 #endif
157 #ifdef CAIRO_HAS_SVG_SURFACE
158 } else if (len >= 3 && g_ascii_strcasecmp (filename + len - 3, "svg") == 0) {
159 surface = cairo_svg_surface_create (filename, width, height);
160 #endif
161 } else {
162 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
164 return surface;
167 static gboolean
168 surface_destroy_for_type (cairo_surface_t *surface, const char *filename)
170 if (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_IMAGE) {
171 cairo_status_t status = cairo_surface_write_to_png (surface, filename);
172 if (status != CAIRO_STATUS_SUCCESS) {
173 g_printerr ("Error saving file: %s\n", cairo_status_to_string (status));
174 cairo_surface_destroy (surface);
175 return FALSE;
178 cairo_surface_destroy (surface);
179 return TRUE;
182 static gboolean
183 export_graphic (SwfdecGraphic *graphic, const char *filename)
185 SwfdecRenderer *renderer;
186 cairo_surface_t *surface;
187 cairo_t *cr;
188 guint width, height;
189 const SwfdecColorTransform trans = { FALSE, 256, 0, 256, 0, 256, 0, 256, 0 };
191 if (SWFDEC_IS_SPRITE (graphic)) {
192 g_printerr ("Sprites can not be exported\n");
193 return FALSE;
195 if (SWFDEC_IS_BUTTON (graphic)) {
196 g_printerr ("Buttons can not be exported\n");
197 return FALSE;
199 width = ceil (graphic->extents.x1 / SWFDEC_TWIPS_SCALE_FACTOR)
200 - floor (graphic->extents.x0 / SWFDEC_TWIPS_SCALE_FACTOR);
201 height = ceil (graphic->extents.y1 / SWFDEC_TWIPS_SCALE_FACTOR)
202 - floor (graphic->extents.y0 / SWFDEC_TWIPS_SCALE_FACTOR);
203 surface = surface_create_for_filename (filename, width, height);
204 cr = cairo_create (surface);
205 cairo_translate (cr, - floor (graphic->extents.x0 / SWFDEC_TWIPS_SCALE_FACTOR),
206 - floor (graphic->extents.y0 / SWFDEC_TWIPS_SCALE_FACTOR));
207 cairo_scale (cr, 1.0 / SWFDEC_TWIPS_SCALE_FACTOR, 1.0 / SWFDEC_TWIPS_SCALE_FACTOR);
208 renderer = swfdec_renderer_new (surface);
209 swfdec_renderer_attach (renderer, cr);
210 swfdec_graphic_render (graphic, cr, &trans);
211 cairo_show_page (cr);
212 cairo_destroy (cr);
213 g_object_unref (renderer);
214 return surface_destroy_for_type (surface, filename);
217 static gboolean
218 export_image (SwfdecImage *image, const char *filename)
220 cairo_surface_t *surface = swfdec_image_create_surface (image, NULL);
222 if (surface == NULL)
223 return FALSE;
224 return surface_destroy_for_type (surface, filename);
227 static void
228 usage (const char *app)
230 g_print ("usage: %s SWFFILE ID OUTFILE\n\n", app);
234 main (int argc, char *argv[])
236 SwfdecCharacter *character;
237 int ret = 0;
238 SwfdecPlayer *player;
239 glong id;
240 SwfdecURL *url;
242 swfdec_init ();
244 if (argc != 4) {
245 usage (argv[0]);
246 return 0;
249 player = swfdec_player_new (NULL);
250 url = swfdec_url_new_from_input (argv[1]);
251 swfdec_player_set_url (player, url);
252 swfdec_url_free (url);
253 /* FIXME: HACK! */
254 swfdec_player_advance (player, 0);
255 if (!SWFDEC_IS_SPRITE_MOVIE (player->priv->roots->data)) {
256 g_printerr ("Error parsing file \"%s\"\n", argv[1]);
257 g_object_unref (player);
258 player = NULL;
259 return 1;
261 id = strtol (argv[2], NULL, 0);
262 if (id >= 0) {
263 character = swfdec_swf_decoder_get_character (
264 SWFDEC_SWF_DECODER (SWFDEC_MOVIE (player->priv->roots->data)->resource->decoder),
265 id);
266 } else {
267 character = SWFDEC_CHARACTER (SWFDEC_SWF_DECODER (
268 SWFDEC_MOVIE (player->priv->roots->data)->resource->decoder)->main_sprite);
270 if (SWFDEC_IS_SPRITE (character)) {
271 if (!export_sprite_sound (SWFDEC_SPRITE (character), argv[3]))
272 ret = 1;
273 } else if (SWFDEC_IS_SOUND (character)) {
274 if (!export_sound (SWFDEC_SOUND (character), argv[3]))
275 ret = 1;
276 } else if (SWFDEC_IS_GRAPHIC (character)) {
277 if (!export_graphic (SWFDEC_GRAPHIC (character), argv[3]))
278 ret = 1;
279 } else if (SWFDEC_IS_IMAGE (character)) {
280 if (!export_image (SWFDEC_IMAGE (character), argv[3]))
281 ret = 1;
282 } else {
283 g_printerr ("id %ld does not specify an exportable object\n", id);
284 ret = 1;
287 g_object_unref (player);
288 player = NULL;
290 return ret;