Imported Upstream version 0.10.23
[profile/ivi/gst-plugins-bad.git] / gst / videoparsers / gstdiracparse.c
1 /* GStreamer
2  * Copyright (C) 2010 David Schleef <ds@schleef.org>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 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  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19 /**
20  * SECTION:element-gstdiracparse
21  *
22  * The gstdiracparse element does FIXME stuff.
23  *
24  * <refsect2>
25  * <title>Example launch line</title>
26  * |[
27  * gst-launch -v fakesrc ! gstdiracparse ! FIXME ! fakesink
28  * ]|
29  * FIXME Describe what the pipeline does.
30  * </refsect2>
31  */
32
33 #ifdef HAVE_CONFIG_H
34 #include "config.h"
35 #endif
36
37 #include <gst/gst.h>
38 #include <gst/base/gstbytereader.h>
39 #include <string.h>
40 #include "gstdiracparse.h"
41 #include "dirac_parse.h"
42
43 /* prototypes */
44
45
46 static void gst_dirac_parse_set_property (GObject * object,
47     guint property_id, const GValue * value, GParamSpec * pspec);
48 static void gst_dirac_parse_get_property (GObject * object,
49     guint property_id, GValue * value, GParamSpec * pspec);
50 static void gst_dirac_parse_dispose (GObject * object);
51 static void gst_dirac_parse_finalize (GObject * object);
52
53 static gboolean gst_dirac_parse_start (GstBaseParse * parse);
54 static gboolean gst_dirac_parse_stop (GstBaseParse * parse);
55 static gboolean gst_dirac_parse_set_sink_caps (GstBaseParse * parse,
56     GstCaps * caps);
57 static GstCaps *gst_dirac_parse_get_sink_caps (GstBaseParse * parse);
58 static gboolean gst_dirac_parse_check_valid_frame (GstBaseParse * parse,
59     GstBaseParseFrame * frame, guint * framesize, gint * skipsize);
60 static GstFlowReturn gst_dirac_parse_parse_frame (GstBaseParse * parse,
61     GstBaseParseFrame * frame);
62 static gboolean gst_dirac_parse_convert (GstBaseParse * parse,
63     GstFormat src_format, gint64 src_value, GstFormat dest_format,
64     gint64 * dest_value);
65 static gboolean gst_dirac_parse_event (GstBaseParse * parse, GstEvent * event);
66 static gboolean gst_dirac_parse_src_event (GstBaseParse * parse,
67     GstEvent * event);
68 static GstFlowReturn gst_dirac_parse_pre_push_frame (GstBaseParse * parse,
69     GstBaseParseFrame * frame);
70
71 enum
72 {
73   PROP_0
74 };
75
76 /* pad templates */
77
78 static GstStaticPadTemplate gst_dirac_parse_sink_template =
79 GST_STATIC_PAD_TEMPLATE ("sink",
80     GST_PAD_SINK,
81     GST_PAD_ALWAYS,
82     GST_STATIC_CAPS ("video/x-dirac")
83     );
84
85 static GstStaticPadTemplate gst_dirac_parse_src_template =
86 GST_STATIC_PAD_TEMPLATE ("src",
87     GST_PAD_SRC,
88     GST_PAD_ALWAYS,
89     GST_STATIC_CAPS ("video/x-dirac, parsed=(boolean)TRUE, "
90         "width=(int)[1,MAX], height=(int)[1,MAX], "
91         "framerate=(fraction)[0/1,MAX], "
92         "pixel-aspect-ratio=(fraction)[0/1,MAX], "
93         "interlaced=(boolean){TRUE,FALSE}, "
94         "profile=(int)[0,MAX], level=(int)[0,MAX]")
95     );
96
97 /* class initialization */
98
99 GST_BOILERPLATE (GstDiracParse, gst_dirac_parse, GstBaseParse,
100     GST_TYPE_BASE_PARSE);
101
102 static void
103 gst_dirac_parse_base_init (gpointer g_class)
104 {
105   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
106
107   gst_element_class_add_static_pad_template (element_class,
108       &gst_dirac_parse_src_template);
109   gst_element_class_add_static_pad_template (element_class,
110       &gst_dirac_parse_sink_template);
111
112   gst_element_class_set_details_simple (element_class, "Dirac parser",
113       "Codec/Parser/Video", "Parses Dirac streams",
114       "David Schleef <ds@schleef.org>");
115 }
116
117 static void
118 gst_dirac_parse_class_init (GstDiracParseClass * klass)
119 {
120   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
121   GstBaseParseClass *base_parse_class = GST_BASE_PARSE_CLASS (klass);
122
123   gobject_class->set_property = gst_dirac_parse_set_property;
124   gobject_class->get_property = gst_dirac_parse_get_property;
125   gobject_class->dispose = gst_dirac_parse_dispose;
126   gobject_class->finalize = gst_dirac_parse_finalize;
127   base_parse_class->start = GST_DEBUG_FUNCPTR (gst_dirac_parse_start);
128   base_parse_class->stop = GST_DEBUG_FUNCPTR (gst_dirac_parse_stop);
129   base_parse_class->set_sink_caps =
130       GST_DEBUG_FUNCPTR (gst_dirac_parse_set_sink_caps);
131   base_parse_class->get_sink_caps =
132       GST_DEBUG_FUNCPTR (gst_dirac_parse_get_sink_caps);
133   base_parse_class->check_valid_frame =
134       GST_DEBUG_FUNCPTR (gst_dirac_parse_check_valid_frame);
135   base_parse_class->parse_frame =
136       GST_DEBUG_FUNCPTR (gst_dirac_parse_parse_frame);
137   base_parse_class->convert = GST_DEBUG_FUNCPTR (gst_dirac_parse_convert);
138   base_parse_class->event = GST_DEBUG_FUNCPTR (gst_dirac_parse_event);
139   base_parse_class->src_event = GST_DEBUG_FUNCPTR (gst_dirac_parse_src_event);
140   base_parse_class->pre_push_frame =
141       GST_DEBUG_FUNCPTR (gst_dirac_parse_pre_push_frame);
142
143 }
144
145 static void
146 gst_dirac_parse_init (GstDiracParse * diracparse,
147     GstDiracParseClass * diracparse_class)
148 {
149   gst_base_parse_set_min_frame_size (GST_BASE_PARSE (diracparse), 13);
150
151 }
152
153 void
154 gst_dirac_parse_set_property (GObject * object, guint property_id,
155     const GValue * value, GParamSpec * pspec)
156 {
157   g_return_if_fail (GST_IS_DIRAC_PARSE (object));
158
159   switch (property_id) {
160     default:
161       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
162       break;
163   }
164 }
165
166 void
167 gst_dirac_parse_get_property (GObject * object, guint property_id,
168     GValue * value, GParamSpec * pspec)
169 {
170   g_return_if_fail (GST_IS_DIRAC_PARSE (object));
171
172   switch (property_id) {
173     default:
174       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
175       break;
176   }
177 }
178
179 void
180 gst_dirac_parse_dispose (GObject * object)
181 {
182   g_return_if_fail (GST_IS_DIRAC_PARSE (object));
183
184   /* clean up as possible.  may be called multiple times */
185
186   G_OBJECT_CLASS (parent_class)->dispose (object);
187 }
188
189 void
190 gst_dirac_parse_finalize (GObject * object)
191 {
192   g_return_if_fail (GST_IS_DIRAC_PARSE (object));
193
194   /* clean up object here */
195
196   G_OBJECT_CLASS (parent_class)->finalize (object);
197 }
198
199
200 static gboolean
201 gst_dirac_parse_start (GstBaseParse * parse)
202 {
203   gst_base_parse_set_min_frame_size (parse, 13);
204
205   return TRUE;
206 }
207
208 static gboolean
209 gst_dirac_parse_stop (GstBaseParse * parse)
210 {
211   return TRUE;
212 }
213
214 static gboolean
215 gst_dirac_parse_set_sink_caps (GstBaseParse * parse, GstCaps * caps)
216 {
217   /* Called when sink caps are set */
218   return TRUE;
219 }
220
221 static gboolean
222 gst_dirac_parse_check_valid_frame (GstBaseParse * parse,
223     GstBaseParseFrame * frame, guint * framesize, gint * skipsize)
224 {
225   GstByteReader reader = GST_BYTE_READER_INIT_FROM_BUFFER (frame->buffer);
226   int off;
227   guint32 next_header;
228   guint8 *data;
229   int size;
230   gboolean have_picture = FALSE;
231   int offset;
232
233   data = GST_BUFFER_DATA (frame->buffer);
234   size = GST_BUFFER_SIZE (frame->buffer);
235
236   if (G_UNLIKELY (size < 13))
237     return FALSE;
238
239   GST_DEBUG ("%d: %02x %02x %02x %02x", size, data[0], data[1], data[2],
240       data[3]);
241
242   if (GST_READ_UINT32_BE (data) != 0x42424344) {
243     off = gst_byte_reader_masked_scan_uint32 (&reader, 0xffffffff,
244         0x42424344, 0, GST_BUFFER_SIZE (frame->buffer));
245
246     if (off < 0) {
247       *skipsize = GST_BUFFER_SIZE (frame->buffer) - 3;
248       return FALSE;
249     }
250
251     GST_LOG_OBJECT (parse, "possible sync at buffer offset %d", off);
252
253     GST_DEBUG ("skipping %d", off);
254     *skipsize = off;
255     return FALSE;
256   }
257
258   /* have sync, parse chunks */
259
260   offset = 0;
261   while (!have_picture) {
262     GST_DEBUG ("offset %d:", offset);
263
264     if (offset + 13 >= size) {
265       *framesize = offset + 13;
266       return FALSE;
267     }
268
269     GST_DEBUG ("chunk type %02x", data[offset + 4]);
270
271     if (GST_READ_UINT32_BE (data + offset) != 0x42424344) {
272       GST_DEBUG ("bad header");
273       *skipsize = 3;
274       return FALSE;
275     }
276
277     next_header = GST_READ_UINT32_BE (data + offset + 5);
278     GST_DEBUG ("next_header %d", next_header);
279     if (next_header == 0)
280       next_header = 13;
281
282     if (SCHRO_PARSE_CODE_IS_PICTURE (data[offset + 4])) {
283       have_picture = TRUE;
284     }
285
286     offset += next_header;
287     if (offset >= size) {
288       *framesize = offset;
289       return FALSE;
290     }
291   }
292
293   *framesize = offset;
294   GST_DEBUG ("framesize %d", *framesize);
295
296   return TRUE;
297 }
298
299 static GstFlowReturn
300 gst_dirac_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
301 {
302   GstDiracParse *diracparse = GST_DIRAC_PARSE (parse);
303   guint8 *data;
304   int size;
305
306   /* Called when processing incoming buffers.  Function should parse
307      a checked frame. */
308   /* MUST implement */
309
310   data = GST_BUFFER_DATA (frame->buffer);
311   size = GST_BUFFER_SIZE (frame->buffer);
312
313   //GST_ERROR("got here %d", size);
314
315   if (data[4] == SCHRO_PARSE_CODE_SEQUENCE_HEADER) {
316     GstCaps *caps;
317     DiracSequenceHeader sequence_header;
318     int ret;
319
320     ret = dirac_sequence_header_parse (&sequence_header, data + 13, size - 13);
321     if (ret) {
322       memcpy (&diracparse->sequence_header, &sequence_header,
323           sizeof (sequence_header));
324       caps = gst_caps_new_simple ("video/x-dirac",
325           "width", G_TYPE_INT, sequence_header.width,
326           "height", G_TYPE_INT, sequence_header.height,
327           "framerate", GST_TYPE_FRACTION,
328           sequence_header.frame_rate_numerator,
329           sequence_header.frame_rate_denominator,
330           "pixel-aspect-ratio", GST_TYPE_FRACTION,
331           sequence_header.aspect_ratio_numerator,
332           sequence_header.aspect_ratio_denominator,
333           "interlaced", G_TYPE_BOOLEAN, sequence_header.interlaced,
334           "profile", G_TYPE_INT, sequence_header.profile,
335           "level", G_TYPE_INT, sequence_header.level, NULL);
336       gst_pad_set_caps (GST_BASE_PARSE_SRC_PAD (parse), caps);
337       gst_caps_unref (caps);
338
339       gst_base_parse_set_frame_rate (parse,
340           sequence_header.frame_rate_numerator,
341           sequence_header.frame_rate_denominator, 0, 0);
342     }
343   }
344
345   gst_buffer_set_caps (frame->buffer,
346       GST_PAD_CAPS (GST_BASE_PARSE_SRC_PAD (parse)));
347
348   gst_base_parse_set_min_frame_size (parse, 13);
349
350   return GST_FLOW_OK;
351 }
352
353 static gboolean
354 gst_dirac_parse_convert (GstBaseParse * parse, GstFormat src_format,
355     gint64 src_value, GstFormat dest_format, gint64 * dest_value)
356 {
357   /* Convert between formats */
358
359   return FALSE;
360 }
361
362 static gboolean
363 gst_dirac_parse_event (GstBaseParse * parse, GstEvent * event)
364 {
365   /* Sink pad event handler */
366
367   return FALSE;
368 }
369
370 static gboolean
371 gst_dirac_parse_src_event (GstBaseParse * parse, GstEvent * event)
372 {
373   /* Src pad event handler */
374
375   return FALSE;
376 }
377
378 static GstFlowReturn
379 gst_dirac_parse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
380 {
381
382   return GST_FLOW_OK;
383 }
384
385 static GstCaps *
386 gst_dirac_parse_get_sink_caps (GstBaseParse * parse)
387 {
388   GstCaps *peercaps;
389   GstCaps *res;
390
391   peercaps = gst_pad_get_allowed_caps (GST_BASE_PARSE_SRC_PAD (parse));
392   if (peercaps) {
393     guint i, n;
394
395     /* Remove the parsed field */
396     peercaps = gst_caps_make_writable (peercaps);
397     n = gst_caps_get_size (peercaps);
398     for (i = 0; i < n; i++) {
399       GstStructure *s = gst_caps_get_structure (peercaps, i);
400       gst_structure_remove_field (s, "parsed");
401     }
402
403     res =
404         gst_caps_intersect_full (peercaps,
405         gst_pad_get_pad_template_caps (GST_BASE_PARSE_SINK_PAD (parse)),
406         GST_CAPS_INTERSECT_FIRST);
407     gst_caps_unref (peercaps);
408   } else {
409     res =
410         gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_PARSE_SINK_PAD
411             (parse)));
412   }
413
414   return res;
415 }