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.
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
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
)
33 swfdec_video_decoder_do_set_codec_data (SwfdecVideoDecoder
*decoder
,
36 SWFDEC_WARNING ("%s does not implement codec data",
37 G_OBJECT_TYPE_NAME (decoder
));
41 swfdec_video_decoder_class_init (SwfdecVideoDecoderClass
*klass
)
43 klass
->set_codec_data
= swfdec_video_decoder_do_set_codec_data
;
47 swfdec_video_decoder_init (SwfdecVideoDecoder
*video_decoder
)
51 static GSList
*video_codecs
= NULL
;
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
));
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
71 swfdec_video_codec_get_format (guint 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
;
84 SWFDEC_ERROR ("unknown codec %u, assuming RGBA format", codec
);
85 return SWFDEC_VIDEO_FORMAT_RGBA
;
90 swfdec_video_decoder_prepare (guint codec
, char **missing
)
92 char *detail
= NULL
, *s
= NULL
;
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
)) {
102 g_type_class_unref (klass
);
112 g_type_class_unref (klass
);
122 * swfdec_video_decoder_new:
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
131 swfdec_video_decoder_new (guint codec
)
133 SwfdecVideoDecoder
*ret
= NULL
;
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
);
145 ret
= g_object_new (SWFDEC_TYPE_VIDEO_DECODER
, NULL
);
146 swfdec_video_decoder_error (ret
, "no suitable decoder for video codec %u", codec
);
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.
164 swfdec_video_decoder_set_codec_data (SwfdecVideoDecoder
*decoder
, SwfdecBuffer
*buffer
)
166 SwfdecVideoDecoderClass
*klass
;
168 g_return_if_fail (SWFDEC_IS_VIDEO_DECODER (decoder
));
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.
186 swfdec_video_decoder_decode (SwfdecVideoDecoder
*decoder
, SwfdecBuffer
*buffer
)
188 SwfdecVideoDecoderClass
*klass
;
190 g_return_if_fail (SWFDEC_IS_VIDEO_DECODER (decoder
));
194 klass
= SWFDEC_VIDEO_DECODER_GET_CLASS (decoder
);
195 klass
->decode (decoder
, buffer
);
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
;
207 swfdec_video_decoder_get_error (SwfdecVideoDecoder
*decoder
)
209 g_return_val_if_fail (SWFDEC_IS_VIDEO_DECODER (decoder
), TRUE
);
211 return decoder
->error
;
215 swfdec_video_decoder_get_width (SwfdecVideoDecoder
*decoder
)
217 g_return_val_if_fail (SWFDEC_IS_VIDEO_DECODER (decoder
), 0);
219 return decoder
->width
;
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] = {
234 0, 16384, 16384, 16384,
241 yuv_mux (guint32
*dest
, const guint8
*src_y
, const guint8
*src_u
, const guint8
*src_v
,
245 for (i
= 0; i
< n
; i
++) {
246 dest
[i
] = oil_argb(255, src_y
[i
], src_u
[i
], src_v
[i
]);
251 upsample (guint8
*d
, guint8
*s
, int n
)
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;
272 swfdec_video_i420_to_rgb (SwfdecVideoDecoder
*decoder
)
279 const guint8
*yp
, *up
, *vp
;
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];
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),
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),
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
;
320 return (unsigned char *)argb_image
;
323 /* FIXME: use liboil (or better: cairo) for this */
325 swfdec_video_codec_apply_mask (guint8
*data
, guint rowstride
, const guint8
*mask
,
326 guint mask_rowstride
, guint width
, guint height
)
332 data
+= SWFDEC_COLOR_INDEX_ALPHA
;
333 for (y
= 0; y
< height
; y
++) {
336 for (x
= 0; x
< width
; x
++) {
341 mask
+= mask_rowstride
;
347 swfdec_video_decoder_get_image (SwfdecVideoDecoder
*decoder
, SwfdecRenderer
*renderer
)
349 cairo_surface_t
*surface
;
353 g_return_val_if_fail (SWFDEC_IS_VIDEO_DECODER (decoder
), NULL
);
354 g_return_val_if_fail (SWFDEC_IS_RENDERER (renderer
), 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
)
364 if (swfdec_video_codec_get_format (decoder
->codec
) == SWFDEC_VIDEO_FORMAT_I420
) {
365 data
= swfdec_video_i420_to_rgb (decoder
);
367 SWFDEC_ERROR ("I420 => RGB conversion failed");
370 rowstride
= decoder
->width
* 4;
372 rowstride
= decoder
->rowstride
[0];
373 data
= g_memdup (decoder
->plane
[0], rowstride
* decoder
->height
);
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
);
386 swfdec_video_decoder_error (SwfdecVideoDecoder
*decoder
, const char *error
, ...)
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
);
399 swfdec_video_decoder_errorv (SwfdecVideoDecoder
*decoder
, const char *error
, va_list args
)
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
);
409 decoder
->error
= TRUE
;