add blend mode tests
[swfdec.git] / swfdec / swfdec_video_decoder_screen.c
blob42504b5be76c118e1cfd954c236af5c3f5ca9c61
1 /* Swfdec
2 * Copyright (C) 2007-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 "swfdec_video_decoder_screen.h"
25 #include "swfdec_bits.h"
26 #include "swfdec_debug.h"
28 G_DEFINE_TYPE (SwfdecVideoDecoderScreen, swfdec_video_decoder_screen, SWFDEC_TYPE_VIDEO_DECODER)
30 static gboolean
31 swfdec_video_decoder_screen_prepare (guint codec, char **missing)
33 return codec == SWFDEC_VIDEO_CODEC_SCREEN;
36 static SwfdecVideoDecoder *
37 swfdec_video_decoder_screen_create (guint codec)
39 if (codec != SWFDEC_VIDEO_CODEC_SCREEN)
40 return NULL;
42 return g_object_new (SWFDEC_TYPE_VIDEO_DECODER_SCREEN, NULL);
45 static void
46 swfdec_video_decoder_screen_decode (SwfdecVideoDecoder *dec, SwfdecBuffer *buffer)
48 SwfdecBits bits;
49 guint i, j, w, h, bw, bh, stride;
51 swfdec_bits_init (&bits, buffer);
52 bw = (swfdec_bits_getbits (&bits, 4) + 1) * 16;
53 w = swfdec_bits_getbits (&bits, 12);
54 bh = (swfdec_bits_getbits (&bits, 4) + 1) * 16;
55 h = swfdec_bits_getbits (&bits, 12);
56 if (dec->width == 0 || dec->height == 0) {
57 if (w == 0 || h == 0) {
58 swfdec_video_decoder_error (dec, "width or height is 0: %ux%u", w, h);
59 return;
61 /* check for overflow */
62 if (w * 4 * h < w * 4) {
63 swfdec_video_decoder_error (dec, "overflowing video size: %ux%u", w, h);
64 return;
66 dec->plane[0] = g_try_malloc (w * h * 4);
67 if (dec->plane[0] == NULL) {
68 swfdec_video_decoder_error (dec, "could not allocate %u bytes", w * h * 4);
69 return;
71 dec->width = w;
72 dec->height = h;
73 dec->rowstride[0] = w * 4;
74 } else if (dec->width != w || dec->height != h) {
75 swfdec_video_decoder_error (dec, "width or height differ from original: was %ux%u, is %ux%u",
76 dec->width, dec->height, w, h);
77 /* FIXME: this is what ffmpeg does, should we be more forgiving? */
78 return;
80 stride = w * 4;
81 SWFDEC_LOG ("size: %u x %u - block size %u x %u", w, h, bw, bh);
82 for (j = 0; j < h; j += bh) {
83 for (i = 0; i < w; i += bw) {
84 guint x, y, size, curw, curh;
85 SwfdecBuffer *buf;
86 guint8 *in, *out;
87 size = swfdec_bits_get_bu16 (&bits);
88 if (size == 0)
89 continue;
90 curw = MIN (bw, w - i);
91 curh = MIN (bh, h - j);
92 buf = swfdec_bits_decompress (&bits, size, curw * curh * 3);
93 if (buf == NULL) {
94 SWFDEC_ERROR ("could not decode block at %ux%u", i, j);
95 continue;
97 /* convert format and write out data */
98 out = dec->plane[0] + stride * (h - j - 1) + i * 4;
99 in = buf->data;
100 for (y = 0; y < curh; y++) {
101 for (x = 0; x < curw; x++) {
102 out[x * 4 + SWFDEC_COLOR_INDEX_BLUE] = *in++;
103 out[x * 4 + SWFDEC_COLOR_INDEX_GREEN] = *in++;
104 out[x * 4 + SWFDEC_COLOR_INDEX_RED] = *in++;
105 out[x * 4 + SWFDEC_COLOR_INDEX_ALPHA] = 0xFF;
107 out -= stride;
109 swfdec_buffer_unref (buf);
114 static void
115 swfdec_video_decoder_screen_dispose (GObject *object)
117 SwfdecVideoDecoder *dec = SWFDEC_VIDEO_DECODER (object);
119 g_free (dec->plane[0]);
121 G_OBJECT_CLASS (swfdec_video_decoder_screen_parent_class)->dispose (object);
124 static void
125 swfdec_video_decoder_screen_class_init (SwfdecVideoDecoderScreenClass *klass)
127 GObjectClass *object_class = G_OBJECT_CLASS (klass);
128 SwfdecVideoDecoderClass *decoder_class = SWFDEC_VIDEO_DECODER_CLASS (klass);
130 object_class->dispose = swfdec_video_decoder_screen_dispose;
132 decoder_class->prepare = swfdec_video_decoder_screen_prepare;
133 decoder_class->create = swfdec_video_decoder_screen_create;
134 decoder_class->decode = swfdec_video_decoder_screen_decode;
137 static void
138 swfdec_video_decoder_screen_init (SwfdecVideoDecoderScreen *dec)