add a test for just-fixed crasher
[swfdec.git] / swfdec / swfdec_video_decoder_gst.c
blob893fc450e1c402ea55989073ce8b3eaf068eb23e
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 <string.h>
25 #include <gst/pbutils/pbutils.h>
27 #include "swfdec_video_decoder_gst.h"
28 #include "swfdec_codec_gst.h"
29 #include "swfdec_debug.h"
31 static GstCaps *
32 swfdec_video_decoder_get_caps (guint codec)
34 GstCaps *caps;
36 switch (codec) {
37 case SWFDEC_VIDEO_CODEC_H263:
38 caps = gst_caps_from_string ("video/x-flash-video");
39 break;
40 case SWFDEC_VIDEO_CODEC_VP6:
41 caps = gst_caps_from_string ("video/x-vp6-flash");
42 break;
43 default:
44 return NULL;
46 g_assert (caps);
47 return caps;
50 static GstCaps *
51 swfdec_video_decoder_get_sink_caps (guint codec)
53 switch (swfdec_video_codec_get_format (codec)) {
54 case SWFDEC_VIDEO_FORMAT_RGBA:
55 #if G_BYTE_ORDER == G_BIG_ENDIAN
56 return gst_caps_from_string ("video/x-raw-rgb, bpp=32, endianness=4321, depth=24, "
57 "red_mask=16711680, green_mask=65280, blue_mask=255");
58 #else
59 return gst_caps_from_string ("video/x-raw-rgb, bpp=32, endianness=4321, depth=24, "
60 "red_mask=65280, green_mask=16711680, blue_mask=-16777216");
61 #endif
62 case SWFDEC_VIDEO_FORMAT_I420:
63 return gst_caps_from_string ("video/x-raw-yuv, format=(fourcc)I420");
64 default:
65 g_return_val_if_reached (NULL);
69 G_DEFINE_TYPE (SwfdecVideoDecoderGst, swfdec_video_decoder_gst, SWFDEC_TYPE_VIDEO_DECODER)
71 static gboolean
72 swfdec_video_decoder_gst_prepare (guint codec, char **missing)
74 GstElementFactory *factory;
75 GstCaps *caps;
77 /* Check if we can handle the format at all. If not, no plugin will help us. */
78 caps = swfdec_video_decoder_get_caps (codec);
79 if (caps == NULL)
80 return FALSE;
82 /* If we can already handle it, woohoo! */
83 factory = swfdec_gst_get_element_factory (caps);
84 if (factory != NULL) {
85 gst_object_unref (factory);
86 gst_caps_unref (caps);
87 return TRUE;
90 /* need to install plugins... */
91 *missing = gst_missing_decoder_installer_detail_new (caps);
92 gst_caps_unref (caps);
93 return FALSE;
96 static SwfdecVideoDecoder *
97 swfdec_video_decoder_gst_create (guint codec)
99 SwfdecVideoDecoderGst *player;
100 GstCaps *srccaps, *sinkcaps;
102 srccaps = swfdec_video_decoder_get_caps (codec);
103 if (srccaps == NULL)
104 return NULL;
105 sinkcaps = swfdec_video_decoder_get_sink_caps (codec);
107 player = g_object_new (SWFDEC_TYPE_VIDEO_DECODER_GST, NULL);
109 if (!swfdec_gst_decoder_init (&player->dec, srccaps, sinkcaps, NULL)) {
110 g_object_unref (player);
111 gst_caps_unref (srccaps);
112 gst_caps_unref (sinkcaps);
113 return NULL;
116 gst_caps_unref (srccaps);
117 gst_caps_unref (sinkcaps);
118 return &player->decoder;
121 static void
122 swfdec_video_decoder_gst_decode (SwfdecVideoDecoder *dec, SwfdecBuffer *buffer)
124 SwfdecVideoDecoderGst *player = SWFDEC_VIDEO_DECODER_GST (dec);
125 #define SWFDEC_ALIGN(x, n) (((x) + (n) - 1) & (~((n) - 1)))
126 GstBuffer *buf;
127 GstCaps *caps;
128 GstStructure *structure;
130 buf = swfdec_gst_buffer_new (swfdec_buffer_ref (buffer));
131 if (!swfdec_gst_decoder_push (&player->dec, buf)) {
132 swfdec_video_decoder_error (dec, "failed to push buffer");
133 return;
136 buf = swfdec_gst_decoder_pull (&player->dec);
137 if (buf == NULL) {
138 SWFDEC_ERROR ("failed to pull decoded buffer. Broken stream?");
139 return;
140 } else {
141 if (player->last)
142 gst_buffer_unref (player->last);
143 player->last = buf;
146 while ((buf = swfdec_gst_decoder_pull (&player->dec))) {
147 SWFDEC_ERROR ("too many output buffers!");
148 gst_buffer_unref (buf);
150 caps = gst_buffer_get_caps (player->last);
151 if (caps == NULL) {
152 swfdec_video_decoder_error (dec, "no caps on decoded buffer");
153 return;
155 structure = gst_caps_get_structure (caps, 0);
156 if (!gst_structure_get_int (structure, "width", (int *) &dec->width) ||
157 !gst_structure_get_int (structure, "height", (int *) &dec->height)) {
158 swfdec_video_decoder_error (dec, "invalid caps on decoded buffer");
159 return;
161 buf = player->last;
162 switch (swfdec_video_codec_get_format (dec->codec)) {
163 case SWFDEC_VIDEO_FORMAT_RGBA:
164 dec->plane[0] = buf->data;
165 dec->rowstride[0] = dec->width * 4;
166 break;
167 case SWFDEC_VIDEO_FORMAT_I420:
168 dec->plane[0] = buf->data;
169 dec->rowstride[0] = SWFDEC_ALIGN (dec->width, 4);
170 dec->plane[1] = dec->plane[0] + dec->rowstride[0] * SWFDEC_ALIGN (dec->height, 2);
171 dec->rowstride[1] = SWFDEC_ALIGN (dec->width, 8) / 2;
172 dec->plane[2] = dec->plane[1] + dec->rowstride[1] * SWFDEC_ALIGN (dec->height, 2) / 2;
173 dec->rowstride[2] = dec->rowstride[1];
174 g_assert (dec->plane[2] + dec->rowstride[2] * SWFDEC_ALIGN (dec->height, 2) / 2 == dec->plane[0] + buf->size);
175 break;
176 default:
177 g_return_if_reached ();
179 #undef SWFDEC_ALIGN
182 static void
183 swfdec_video_decoder_gst_dispose (GObject *object)
185 SwfdecVideoDecoderGst *player = SWFDEC_VIDEO_DECODER_GST (object);
187 swfdec_gst_decoder_finish (&player->dec);
188 if (player->last)
189 gst_buffer_unref (player->last);
191 G_OBJECT_CLASS (swfdec_video_decoder_gst_parent_class)->dispose (object);
194 static void
195 swfdec_video_decoder_gst_class_init (SwfdecVideoDecoderGstClass *klass)
197 GObjectClass *object_class = G_OBJECT_CLASS (klass);
198 SwfdecVideoDecoderClass *decoder_class = SWFDEC_VIDEO_DECODER_CLASS (klass);
200 object_class->dispose = swfdec_video_decoder_gst_dispose;
202 decoder_class->prepare = swfdec_video_decoder_gst_prepare;
203 decoder_class->create = swfdec_video_decoder_gst_create;
204 decoder_class->decode = swfdec_video_decoder_gst_decode;
207 static void
208 swfdec_video_decoder_gst_init (SwfdecVideoDecoderGst *dec)