make swfdec_as_object_mark() only mark if not marked yet
[swfdec.git] / swfdec / swfdec_video_decoder_gst.c
blob38f393d9938ad25595ce2e1cd4aa0e08496d03fd
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, SwfdecBuffer *buffer)
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 case SWFDEC_VIDEO_CODEC_H264:
44 caps = gst_caps_from_string ("video/x-h264");
45 if (buffer) {
46 GstBuffer *gstbuf;
48 swfdec_buffer_ref (buffer);
49 gstbuf = swfdec_gst_buffer_new (buffer);
50 gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER, gstbuf, NULL);
51 gst_buffer_unref (gstbuf);
53 break;
54 default:
55 return NULL;
57 g_assert (caps);
58 return caps;
61 static GstCaps *
62 swfdec_video_decoder_get_sink_caps (guint codec)
64 switch (swfdec_video_codec_get_format (codec)) {
65 case SWFDEC_VIDEO_FORMAT_RGBA:
66 #if G_BYTE_ORDER == G_BIG_ENDIAN
67 return gst_caps_from_string ("video/x-raw-rgb, bpp=32, endianness=4321, depth=24, "
68 "red_mask=16711680, green_mask=65280, blue_mask=255");
69 #else
70 return gst_caps_from_string ("video/x-raw-rgb, bpp=32, endianness=4321, depth=24, "
71 "red_mask=65280, green_mask=16711680, blue_mask=-16777216");
72 #endif
73 case SWFDEC_VIDEO_FORMAT_I420:
74 return gst_caps_from_string ("video/x-raw-yuv, format=(fourcc)I420");
75 default:
76 g_return_val_if_reached (NULL);
80 G_DEFINE_TYPE (SwfdecVideoDecoderGst, swfdec_video_decoder_gst, SWFDEC_TYPE_VIDEO_DECODER)
82 static gboolean
83 swfdec_video_decoder_gst_prepare (guint codec, char **missing)
85 GstElementFactory *factory;
86 GstCaps *caps;
88 /* Check if we can handle the format at all. If not, no plugin will help us. */
89 caps = swfdec_video_decoder_get_caps (codec, NULL);
90 if (caps == NULL)
91 return FALSE;
93 /* If we can already handle it, woohoo! */
94 factory = swfdec_gst_get_element_factory (caps);
95 if (factory != NULL) {
96 gst_object_unref (factory);
97 gst_caps_unref (caps);
98 return TRUE;
101 /* need to install plugins... */
102 *missing = gst_missing_decoder_installer_detail_new (caps);
103 gst_caps_unref (caps);
104 return FALSE;
107 static SwfdecVideoDecoder *
108 swfdec_video_decoder_gst_create (guint codec, SwfdecBuffer *buffer)
110 SwfdecVideoDecoderGst *player;
111 GstCaps *srccaps, *sinkcaps;
113 srccaps = swfdec_video_decoder_get_caps (codec, buffer);
114 if (srccaps == NULL)
115 return NULL;
116 sinkcaps = swfdec_video_decoder_get_sink_caps (codec);
118 player = g_object_new (SWFDEC_TYPE_VIDEO_DECODER_GST, NULL);
120 if (!swfdec_gst_decoder_init (&player->dec, srccaps, sinkcaps, NULL)) {
121 g_object_unref (player);
122 gst_caps_unref (srccaps);
123 gst_caps_unref (sinkcaps);
124 return NULL;
127 gst_caps_unref (srccaps);
128 gst_caps_unref (sinkcaps);
129 return &player->decoder;
132 static void
133 swfdec_video_decoder_gst_decode (SwfdecVideoDecoder *dec, SwfdecBuffer *buffer)
135 SwfdecVideoDecoderGst *player = SWFDEC_VIDEO_DECODER_GST (dec);
136 #define SWFDEC_ALIGN(x, n) (((x) + (n) - 1) & (~((n) - 1)))
137 GstBuffer *buf;
138 GstCaps *caps;
139 GstStructure *structure;
141 buf = swfdec_gst_buffer_new (swfdec_buffer_ref (buffer));
142 if (!swfdec_gst_decoder_push (&player->dec, buf)) {
143 swfdec_video_decoder_error (dec, "failed to push buffer");
144 return;
147 buf = swfdec_gst_decoder_pull (&player->dec);
148 if (buf == NULL) {
149 SWFDEC_ERROR ("failed to pull decoded buffer. Broken stream?");
150 return;
151 } else {
152 if (player->last)
153 gst_buffer_unref (player->last);
154 player->last = buf;
157 while ((buf = swfdec_gst_decoder_pull (&player->dec))) {
158 SWFDEC_ERROR ("too many output buffers!");
159 gst_buffer_unref (buf);
161 caps = gst_buffer_get_caps (player->last);
162 if (caps == NULL) {
163 swfdec_video_decoder_error (dec, "no caps on decoded buffer");
164 return;
166 structure = gst_caps_get_structure (caps, 0);
167 if (!gst_structure_get_int (structure, "width", (int *) &dec->width) ||
168 !gst_structure_get_int (structure, "height", (int *) &dec->height)) {
169 swfdec_video_decoder_error (dec, "invalid caps on decoded buffer");
170 return;
172 buf = player->last;
173 switch (swfdec_video_codec_get_format (dec->codec)) {
174 case SWFDEC_VIDEO_FORMAT_RGBA:
175 dec->plane[0] = buf->data;
176 dec->rowstride[0] = dec->width * 4;
177 break;
178 case SWFDEC_VIDEO_FORMAT_I420:
179 dec->plane[0] = buf->data;
180 dec->rowstride[0] = SWFDEC_ALIGN (dec->width, 4);
181 dec->plane[1] = dec->plane[0] + dec->rowstride[0] * SWFDEC_ALIGN (dec->height, 2);
182 dec->rowstride[1] = SWFDEC_ALIGN (dec->width, 8) / 2;
183 dec->plane[2] = dec->plane[1] + dec->rowstride[1] * SWFDEC_ALIGN (dec->height, 2) / 2;
184 dec->rowstride[2] = dec->rowstride[1];
185 g_assert (dec->plane[2] + dec->rowstride[2] * SWFDEC_ALIGN (dec->height, 2) / 2 == dec->plane[0] + buf->size);
186 break;
187 default:
188 g_return_if_reached ();
190 #undef SWFDEC_ALIGN
193 static void
194 swfdec_video_decoder_gst_dispose (GObject *object)
196 SwfdecVideoDecoderGst *player = SWFDEC_VIDEO_DECODER_GST (object);
198 swfdec_gst_decoder_finish (&player->dec);
199 if (player->last)
200 gst_buffer_unref (player->last);
202 G_OBJECT_CLASS (swfdec_video_decoder_gst_parent_class)->dispose (object);
205 static void
206 swfdec_video_decoder_gst_class_init (SwfdecVideoDecoderGstClass *klass)
208 GObjectClass *object_class = G_OBJECT_CLASS (klass);
209 SwfdecVideoDecoderClass *decoder_class = SWFDEC_VIDEO_DECODER_CLASS (klass);
211 object_class->dispose = swfdec_video_decoder_gst_dispose;
213 decoder_class->prepare = swfdec_video_decoder_gst_prepare;
214 decoder_class->create = swfdec_video_decoder_gst_create;
215 decoder_class->decode = swfdec_video_decoder_gst_decode;
218 static void
219 swfdec_video_decoder_gst_init (SwfdecVideoDecoderGst *dec)