fix build for --disable-gtk-doc
[swfdec.git] / swfdec / swfdec_video_decoder.c
blob527ac1e0dcb98843113a6a37d89854ea91a91361
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 <liboil/liboil.h>
25 #include "swfdec_video_decoder.h"
26 #include "swfdec_color.h"
27 #include "swfdec_debug.h"
28 #include "swfdec_renderer_internal.h"
30 G_DEFINE_TYPE (SwfdecVideoDecoder, swfdec_video_decoder, G_TYPE_OBJECT)
32 static void
33 swfdec_video_decoder_do_set_codec_data (SwfdecVideoDecoder *decoder,
34 SwfdecBuffer *buffer)
36 SWFDEC_WARNING ("%s does not implement codec data",
37 G_OBJECT_TYPE_NAME (decoder));
40 static void
41 swfdec_video_decoder_class_init (SwfdecVideoDecoderClass *klass)
43 klass->set_codec_data = swfdec_video_decoder_do_set_codec_data;
46 static void
47 swfdec_video_decoder_init (SwfdecVideoDecoder *video_decoder)
51 static GSList *video_codecs = NULL;
53 void
54 swfdec_video_decoder_register (GType type)
56 g_return_if_fail (g_type_is_a (type, SWFDEC_TYPE_VIDEO_DECODER));
58 video_codecs = g_slist_append (video_codecs, GSIZE_TO_POINTER ((gsize) type));
61 /**
62 * swfdec_video_codec_get_format:
63 * @codec: codec to check
65 * Returns the output format used for this codec. Video codecs must use these
66 * codecs when decoding video.
68 * Returns: the output format to use for this format
69 **/
70 SwfdecVideoFormat
71 swfdec_video_codec_get_format (guint codec)
73 switch (codec) {
74 case SWFDEC_VIDEO_CODEC_H263:
75 case SWFDEC_VIDEO_CODEC_VP6:
76 case SWFDEC_VIDEO_CODEC_VP6_ALPHA:
77 case SWFDEC_VIDEO_CODEC_H264:
78 return SWFDEC_VIDEO_FORMAT_I420;
79 case SWFDEC_VIDEO_CODEC_UNDEFINED:
80 case SWFDEC_VIDEO_CODEC_SCREEN:
81 case SWFDEC_VIDEO_CODEC_SCREEN2:
82 return SWFDEC_VIDEO_FORMAT_RGBA;
83 default:
84 SWFDEC_ERROR ("unknown codec %u, assuming RGBA format", codec);
85 return SWFDEC_VIDEO_FORMAT_RGBA;
89 gboolean
90 swfdec_video_decoder_prepare (guint codec, char **missing)
92 char *detail = NULL, *s = NULL;
93 GSList *walk;
95 for (walk = video_codecs; walk; walk = walk->next) {
96 SwfdecVideoDecoderClass *klass = g_type_class_ref (GPOINTER_TO_SIZE (walk->data));
97 if (klass->prepare (codec, &s)) {
98 g_free (detail);
99 g_free (s);
100 if (missing)
101 *missing = NULL;
102 g_type_class_unref (klass);
103 return TRUE;
105 if (s) {
106 if (detail == NULL)
107 detail = s;
108 else
109 g_free (s);
110 s = NULL;
112 g_type_class_unref (klass);
114 if (missing)
115 *missing = detail;
116 else
117 g_free (detail);
118 return FALSE;
122 * swfdec_video_decoder_new:
123 * @codec: codec id
125 * Creates a decoder suitable for decoding @format. If no decoder is available
126 * for the given for mat, %NULL is returned.
128 * Returns: a new decoder or %NULL
130 SwfdecVideoDecoder *
131 swfdec_video_decoder_new (guint codec)
133 SwfdecVideoDecoder *ret = NULL;
134 GSList *walk;
136 for (walk = video_codecs; walk; walk = walk->next) {
137 SwfdecVideoDecoderClass *klass = g_type_class_ref (GPOINTER_TO_SIZE (walk->data));
138 ret = klass->create (codec);
139 g_type_class_unref (klass);
140 if (ret)
141 break;
144 if (ret == NULL) {
145 ret = g_object_new (SWFDEC_TYPE_VIDEO_DECODER, NULL);
146 swfdec_video_decoder_error (ret, "no suitable decoder for video codec %u", codec);
149 ret->codec = codec;
151 return ret;
155 * swfdec_video_decoder_set_codec_data:
156 * @decoder: a video decoder
157 * @buffer: setup data for the decoder. May be %NULL
159 * Provides setup data for the video decoder. This function is usually called
160 * on initialization, but can be called at any time. Currently this
161 * functionality is only used for H264.
163 void
164 swfdec_video_decoder_set_codec_data (SwfdecVideoDecoder *decoder, SwfdecBuffer *buffer)
166 SwfdecVideoDecoderClass *klass;
168 g_return_if_fail (SWFDEC_IS_VIDEO_DECODER (decoder));
170 if (decoder->error)
171 return;
172 klass = SWFDEC_VIDEO_DECODER_GET_CLASS (decoder);
173 klass->set_codec_data (decoder, buffer);
177 * swfdec_video_decoder_decode:
178 * @decoder: a #SwfdecVideoDecoder
179 * @buffer: a #SwfdecBuffer to process
181 * Hands the decoder a new buffer for decoding. The buffer should be decoded
182 * immediately. It is assumed that width, height and data areas are set to the
183 * correct values upon return from this function.
185 void
186 swfdec_video_decoder_decode (SwfdecVideoDecoder *decoder, SwfdecBuffer *buffer)
188 SwfdecVideoDecoderClass *klass;
190 g_return_if_fail (SWFDEC_IS_VIDEO_DECODER (decoder));
192 if (decoder->error)
193 return;
194 klass = SWFDEC_VIDEO_DECODER_GET_CLASS (decoder);
195 klass->decode (decoder, buffer);
198 guint
199 swfdec_video_decoder_get_codec (SwfdecVideoDecoder *decoder)
201 g_return_val_if_fail (SWFDEC_IS_VIDEO_DECODER (decoder), SWFDEC_VIDEO_CODEC_UNDEFINED);
203 return decoder->codec;
206 gboolean
207 swfdec_video_decoder_get_error (SwfdecVideoDecoder *decoder)
209 g_return_val_if_fail (SWFDEC_IS_VIDEO_DECODER (decoder), TRUE);
211 return decoder->error;
214 guint
215 swfdec_video_decoder_get_width (SwfdecVideoDecoder *decoder)
217 g_return_val_if_fail (SWFDEC_IS_VIDEO_DECODER (decoder), 0);
219 return decoder->width;
222 guint
223 swfdec_video_decoder_get_height (SwfdecVideoDecoder *decoder)
225 g_return_val_if_fail (SWFDEC_IS_VIDEO_DECODER (decoder), 0);
227 return decoder->height;
230 #define oil_argb(a,r,g,b) (((a) << 24) | ((r) << 16) | ((g) << 8) | b)
231 static gint16 jfif_matrix[24] = {
232 0, 0, -8192, -8192,
233 16384, 0, 0, 0,
234 0, 16384, 16384, 16384,
235 0, 0, -5638, 29032,
236 0, 22970, -11700, 0,
237 0, 0, 0, 0
240 static void
241 yuv_mux (guint32 *dest, const guint8 *src_y, const guint8 *src_u, const guint8 *src_v,
242 int n)
244 int i;
245 for (i = 0; i < n; i++) {
246 dest[i] = oil_argb(255, src_y[i], src_u[i], src_v[i]);
250 static void
251 upsample (guint8 *d, guint8 *s, int n)
253 int i;
255 d[0] = s[0];
257 for (i = 0; i < n-3; i+=2) {
258 d[i + 1] = (3*s[i/2] + s[i/2+1] + 2)>>2;
259 d[i + 2] = (s[i/2] + 3*s[i/2+1] + 2)>>2;
262 if (n&1) {
263 i = n-3;
264 d[n-2] = s[n/2];
265 d[n-1] = s[n/2];
266 } else {
267 d[n-1] = s[n/2-1];
271 static guint8 *
272 swfdec_video_i420_to_rgb (SwfdecVideoDecoder *decoder)
274 guint32 *tmp;
275 guint8 *tmp_u;
276 guint8 *tmp_v;
277 guint8 *tmp1;
278 guint32 *argb_image;
279 const guint8 *yp, *up, *vp;
280 guint32 *argbp;
281 int j;
282 guint halfwidth;
283 int halfheight;
285 halfwidth = (decoder->width + 1)>>1;
286 tmp = g_malloc (4 * decoder->width * decoder->height);
287 tmp_u = g_malloc (decoder->width);
288 tmp_v = g_malloc (decoder->width);
289 tmp1 = g_malloc (halfwidth);
290 argb_image = g_malloc (4 * decoder->width * decoder->height);
292 yp = decoder->plane[0];
293 up = decoder->plane[1];
294 vp = decoder->plane[2];
295 argbp = argb_image;
296 halfheight = (decoder->height+1)>>1;
297 for(j=0;(guint)j<decoder->height;j++){
298 guint32 weight = 192 - 128*(j&1);
300 oil_merge_linear_u8(tmp1,
301 up + decoder->rowstride[1] * CLAMP((j-1)/2,0,halfheight-1),
302 up + decoder->rowstride[1] * CLAMP((j+1)/2,0,halfheight-1),
303 &weight, halfwidth);
304 upsample (tmp_u, tmp1, decoder->width);
305 oil_merge_linear_u8(tmp1,
306 vp + decoder->rowstride[2] * CLAMP((j-1)/2,0,halfheight-1),
307 vp + decoder->rowstride[2] * CLAMP((j+1)/2,0,halfheight-1),
308 &weight, halfwidth);
309 upsample (tmp_v, tmp1, decoder->width);
311 yuv_mux (tmp, yp, tmp_u, tmp_v, decoder->width);
312 oil_colorspace_argb(argbp, tmp, jfif_matrix, decoder->width);
313 yp += decoder->rowstride[0];
314 argbp += decoder->width;
316 g_free(tmp);
317 g_free(tmp_u);
318 g_free(tmp_v);
319 g_free(tmp1);
320 return (unsigned char *)argb_image;
323 /* FIXME: use liboil (or better: cairo) for this */
324 static void
325 swfdec_video_codec_apply_mask (guint8 *data, guint rowstride, const guint8 *mask,
326 guint mask_rowstride, guint width, guint height)
328 const guint8 *in;
329 guint8 *out;
330 guint x, y;
332 data += SWFDEC_COLOR_INDEX_ALPHA;
333 for (y = 0; y < height; y++) {
334 in = mask;
335 out = data;
336 for (x = 0; x < width; x++) {
337 *out = *in;
338 out += 4;
339 in++;
341 mask += mask_rowstride;
342 data += rowstride;
346 cairo_surface_t *
347 swfdec_video_decoder_get_image (SwfdecVideoDecoder *decoder, SwfdecRenderer *renderer)
349 cairo_surface_t *surface;
350 guint rowstride;
351 guint8 *data;
353 g_return_val_if_fail (SWFDEC_IS_VIDEO_DECODER (decoder), NULL);
354 g_return_val_if_fail (SWFDEC_IS_RENDERER (renderer), NULL);
356 if (decoder->error)
357 return NULL;
358 /* special case: If decoding an image failed, setting plane[0] to NULL means
359 * "currently no image available". This is generally only useful for the
360 * first image, as otherwise the video decoder is meant to keep the last image. */
361 if (decoder->plane[0] == NULL)
362 return NULL;
364 if (swfdec_video_codec_get_format (decoder->codec) == SWFDEC_VIDEO_FORMAT_I420) {
365 data = swfdec_video_i420_to_rgb (decoder);
366 if (data == NULL) {
367 SWFDEC_ERROR ("I420 => RGB conversion failed");
368 return NULL;
370 rowstride = decoder->width * 4;
371 } else {
372 rowstride = decoder->rowstride[0];
373 data = g_memdup (decoder->plane[0], rowstride * decoder->height);
375 if (decoder->mask) {
376 swfdec_video_codec_apply_mask (data, rowstride, decoder->mask,
377 decoder->mask_rowstride, decoder->width, decoder->height);
379 surface = swfdec_renderer_create_for_data (renderer, data,
380 decoder->mask ? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_RGB24,
381 decoder->width, decoder->height, rowstride);
382 return surface;
385 void
386 swfdec_video_decoder_error (SwfdecVideoDecoder *decoder, const char *error, ...)
388 va_list args;
390 g_return_if_fail (SWFDEC_IS_VIDEO_DECODER (decoder));
391 g_return_if_fail (error != NULL);
393 va_start (args, error);
394 swfdec_video_decoder_errorv (decoder, error, args);
395 va_end (args);
398 void
399 swfdec_video_decoder_errorv (SwfdecVideoDecoder *decoder, const char *error, va_list args)
401 char *real;
403 g_return_if_fail (SWFDEC_IS_VIDEO_DECODER (decoder));
404 g_return_if_fail (error != NULL);
406 real = g_strdup_vprintf (error, args);
407 SWFDEC_ERROR ("error decoding video: %s", real);
408 g_free (real);
409 decoder->error = TRUE;