2 * Copyright (C) 2007 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_codec_video.h"
26 #include "swfdec_color.h"
27 #include "swfdec_debug.h"
28 #include "swfdec_internal.h"
31 * swfdec_video_decoder_new:
32 * @codec: #SwfdecVideoCodec to create the #SwfdecVideoDecoder for
34 * Creates a new decoder to decode videos of type @codec. If no suitable
35 * decoder could be created, %NULL is returned.
40 swfdec_video_decoder_new (SwfdecVideoCodec codec
)
42 SwfdecVideoDecoder
*ret
;
44 ret
= swfdec_video_decoder_screen_new (codec
);
46 ret
= swfdec_video_decoder_vp6_alpha_new (codec
);
49 ret
= swfdec_video_decoder_ffmpeg_new (codec
);
53 ret
= swfdec_video_decoder_gst_new (codec
);
58 g_return_val_if_fail (ret
->decode
, ret
);
59 g_return_val_if_fail (ret
->free
, ret
);
61 SWFDEC_WARNING ("no decoder found for codec %u", (guint
) codec
);
67 * swfdec_video_decoder_free:
68 * @decoder: a #SwfdecVideoDecoder
70 * Frees the given @decoder and all associated ressources.
73 swfdec_video_decoder_free (SwfdecVideoDecoder
*decoder
)
75 g_return_if_fail (decoder
);
77 decoder
->free (decoder
);
80 #define oil_argb(a,r,g,b) (((a) << 24) | ((r) << 16) | ((g) << 8) | b)
81 static gint16 jfif_matrix
[24] = {
84 0, 16384, 16384, 16384,
91 yuv_mux (guint32
*dest
, const guint8
*src_y
, const guint8
*src_u
, const guint8
*src_v
,
95 for (i
= 0; i
< n
; i
++) {
96 dest
[i
] = oil_argb(255, src_y
[i
], src_u
[i
], src_v
[i
]);
101 upsample (guint8
*d
, guint8
*s
, int n
)
107 for (i
= 0; i
< n
-3; i
+=2) {
108 d
[i
+ 1] = (3*s
[i
/2] + s
[i
/2+1] + 2)>>2;
109 d
[i
+ 2] = (s
[i
/2] + 3*s
[i
/2+1] + 2)>>2;
122 swfdec_video_i420_to_rgb (SwfdecVideoImage
*image
)
129 const guint8
*yp
, *up
, *vp
;
135 halfwidth
= (image
->width
+ 1)>>1;
136 tmp
= g_malloc (4 * image
->width
* image
->height
);
137 tmp_u
= g_malloc (image
->width
);
138 tmp_v
= g_malloc (image
->width
);
139 tmp1
= g_malloc (halfwidth
);
140 argb_image
= g_malloc (4 * image
->width
* image
->height
);
142 yp
= image
->plane
[0];
143 up
= image
->plane
[1];
144 vp
= image
->plane
[2];
146 halfheight
= (image
->height
+1)>>1;
147 for(j
=0;(guint
)j
<image
->height
;j
++){
148 guint32 weight
= 192 - 128*(j
&1);
150 oil_merge_linear_u8(tmp1
,
151 up
+ image
->rowstride
[1] * CLAMP((j
-1)/2,0,halfheight
-1),
152 up
+ image
->rowstride
[1] * CLAMP((j
+1)/2,0,halfheight
-1),
154 upsample (tmp_u
, tmp1
, image
->width
);
155 oil_merge_linear_u8(tmp1
,
156 vp
+ image
->rowstride
[2] * CLAMP((j
-1)/2,0,halfheight
-1),
157 vp
+ image
->rowstride
[2] * CLAMP((j
+1)/2,0,halfheight
-1),
159 upsample (tmp_v
, tmp1
, image
->width
);
161 yuv_mux (tmp
, yp
, tmp_u
, tmp_v
, image
->width
);
162 oil_colorspace_argb(argbp
, tmp
, jfif_matrix
, image
->width
);
163 yp
+= image
->rowstride
[0];
164 argbp
+= image
->width
;
170 return (unsigned char *)argb_image
;
173 /* FIXME: use liboil for this */
175 swfdec_video_codec_apply_mask (guint8
*data
, guint rowstride
, const guint8
*mask
,
176 guint mask_rowstride
, guint width
, guint height
)
182 data
+= SWFDEC_COLOR_INDEX_ALPHA
;
183 for (y
= 0; y
< height
; y
++) {
186 for (x
= 0; x
< width
; x
++) {
191 mask
+= mask_rowstride
;
197 * swfdec_video_decoder_decode:
198 * @decoder: a #SwfdecVideoDecoder
199 * @buffer: buffer to decode
201 * Decodes the given buffer into an image surface.
203 * Returns: a new cairo image surface or %NULL on error.
206 swfdec_video_decoder_decode (SwfdecVideoDecoder
*decoder
, SwfdecBuffer
*buffer
)
208 SwfdecVideoImage image
;
209 static const cairo_user_data_key_t key
;
210 cairo_surface_t
*surface
;
214 g_return_val_if_fail (decoder
!= NULL
, NULL
);
215 g_return_val_if_fail (buffer
!= NULL
, NULL
);
217 if (!decoder
->decode (decoder
, buffer
, &image
)) {
218 SWFDEC_ERROR ("failed to decode video");
221 g_assert (image
.width
!= 0 && image
.height
!= 0);
222 /* FIXME: use cairo for all of this when cairo accelerates it */
223 if (swfdec_video_codec_get_format (decoder
->codec
) == SWFDEC_VIDEO_FORMAT_I420
) {
224 data
= swfdec_video_i420_to_rgb (&image
);
226 SWFDEC_ERROR ("I420 => RGB conversion failed");
229 rowstride
= image
.width
* 4;
231 rowstride
= image
.rowstride
[0];
232 data
= g_memdup (image
.plane
[0], rowstride
* image
.height
);
235 swfdec_video_codec_apply_mask (data
, image
.width
* 4, image
.mask
,
236 image
.mask_rowstride
, image
.width
, image
.height
);
238 surface
= cairo_image_surface_create_for_data (data
,
239 image
.mask
? CAIRO_FORMAT_ARGB32
: CAIRO_FORMAT_RGB24
,
240 image
.width
, image
.height
, rowstride
);
241 if (cairo_surface_status (surface
)) {
242 SWFDEC_ERROR ("failed to create surface: %s",
243 cairo_status_to_string (cairo_surface_status (surface
)));
244 cairo_surface_destroy (surface
);
247 cairo_surface_set_user_data (surface
, &key
, data
,
248 (cairo_destroy_func_t
) g_free
);
253 * swfdec_video_codec_get_format:
254 * @codec: codec to check
256 * Returns the output format used for this codec. Video codecs must use these
257 * codecs when decoding video.
259 * Returns: the output format to use for this format
262 swfdec_video_codec_get_format (SwfdecVideoCodec codec
)
265 case SWFDEC_VIDEO_CODEC_H263
:
266 case SWFDEC_VIDEO_CODEC_VP6
:
267 case SWFDEC_VIDEO_CODEC_VP6_ALPHA
:
268 return SWFDEC_VIDEO_FORMAT_I420
;
270 return SWFDEC_VIDEO_FORMAT_RGBA
;