codecparser: mpeg4 type error
[profile/ivi/gst-plugins-bad.git] / gst / sdi / gstsdidemux.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-gstsdidemux
21  *
22  * The gstsdidemux element does FIXME stuff.
23  *
24  * <refsect2>
25  * <title>Example launch line</title>
26  * |[
27  * gst-launch -v fakesrc ! gstsdidemux ! 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/gst.h>
39 #include <string.h>
40 #include "gstsdidemux.h"
41
42 /* prototypes */
43
44
45 static void gst_sdi_demux_set_property (GObject * object,
46     guint property_id, const GValue * value, GParamSpec * pspec);
47 static void gst_sdi_demux_get_property (GObject * object,
48     guint property_id, GValue * value, GParamSpec * pspec);
49 static void gst_sdi_demux_dispose (GObject * object);
50 static void gst_sdi_demux_finalize (GObject * object);
51
52 static GstStateChangeReturn
53 gst_sdi_demux_change_state (GstElement * element, GstStateChange transition);
54 static GstFlowReturn gst_sdi_demux_chain (GstPad * pad, GstBuffer * buffer);
55 static gboolean gst_sdi_demux_sink_event (GstPad * pad, GstEvent * event);
56 static gboolean gst_sdi_demux_src_event (GstPad * pad, GstEvent * event);
57 static GstCaps *gst_sdi_demux_src_getcaps (GstPad * pad);
58
59
60 enum
61 {
62   PROP_0
63 };
64
65 /* pad templates */
66
67 #define GST_VIDEO_CAPS_NTSC(fourcc) \
68   "video/x-raw-yuv,format=(fourcc)" fourcc ",width=720,height=480," \
69   "framerate=30000/1001,interlaced=TRUE,pixel-aspect-ratio=10/11," \
70   "chroma-site=mpeg2,color-matrix=sdtv"
71 #define GST_VIDEO_CAPS_NTSC_WIDE(fourcc) \
72   "video/x-raw-yuv,format=(fourcc)" fourcc ",width=720,height=480," \
73   "framerate=30000/1001,interlaced=TRUE,pixel-aspect-ratio=40/33," \
74   "chroma-site=mpeg2,color-matrix=sdtv"
75 #define GST_VIDEO_CAPS_PAL(fourcc) \
76   "video/x-raw-yuv,format=(fourcc)" fourcc ",width=720,height=576," \
77   "framerate=25/1,interlaced=TRUE,pixel-aspect-ratio=12/11," \
78   "chroma-site=mpeg2,color-matrix=sdtv"
79 #define GST_VIDEO_CAPS_PAL_WIDE(fourcc) \
80   "video/x-raw-yuv,format=(fourcc)" fourcc ",width=720,height=576," \
81   "framerate=25/1,interlaced=TRUE,pixel-aspect-ratio=16/11," \
82   "chroma-site=mpeg2,color-matrix=sdtv"
83
84 static GstStaticPadTemplate gst_sdi_demux_sink_template =
85 GST_STATIC_PAD_TEMPLATE ("sink",
86     GST_PAD_SINK,
87     GST_PAD_ALWAYS,
88     GST_STATIC_CAPS ("application/x-raw-sdi")
89     );
90
91 static GstStaticPadTemplate gst_sdi_demux_src_template =
92     GST_STATIC_PAD_TEMPLATE ("src",
93     GST_PAD_SRC,
94     GST_PAD_ALWAYS,
95     GST_STATIC_CAPS (GST_VIDEO_CAPS_NTSC ("UYVY") ";"
96         GST_VIDEO_CAPS_PAL ("UYVY"))
97     );
98
99 /* class initialization */
100
101 GST_BOILERPLATE (GstSdiDemux, gst_sdi_demux, GstElement, GST_TYPE_ELEMENT);
102
103 static void
104 gst_sdi_demux_base_init (gpointer g_class)
105 {
106   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
107
108   gst_element_class_add_static_pad_template (element_class,
109       &gst_sdi_demux_src_template);
110   gst_element_class_add_static_pad_template (element_class,
111       &gst_sdi_demux_sink_template);
112
113   gst_element_class_set_details_simple (element_class,
114       "SDI Demuxer",
115       "Demuxer",
116       "Demultiplex SDI streams into raw audio and video",
117       "David Schleef <ds@schleef.org>");
118 }
119
120 static void
121 gst_sdi_demux_class_init (GstSdiDemuxClass * klass)
122 {
123   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
124   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
125
126   gobject_class->set_property = gst_sdi_demux_set_property;
127   gobject_class->get_property = gst_sdi_demux_get_property;
128   gobject_class->dispose = gst_sdi_demux_dispose;
129   gobject_class->finalize = gst_sdi_demux_finalize;
130   if (0)
131     element_class->change_state =
132         GST_DEBUG_FUNCPTR (gst_sdi_demux_change_state);
133
134 }
135
136 static void
137 gst_sdi_demux_init (GstSdiDemux * sdidemux, GstSdiDemuxClass * sdidemux_class)
138 {
139
140   sdidemux->sinkpad =
141       gst_pad_new_from_static_template (&gst_sdi_demux_sink_template, "sink");
142   gst_pad_set_event_function (sdidemux->sinkpad,
143       GST_DEBUG_FUNCPTR (gst_sdi_demux_sink_event));
144   gst_pad_set_chain_function (sdidemux->sinkpad,
145       GST_DEBUG_FUNCPTR (gst_sdi_demux_chain));
146   gst_element_add_pad (GST_ELEMENT (sdidemux), sdidemux->sinkpad);
147
148   sdidemux->srcpad =
149       gst_pad_new_from_static_template (&gst_sdi_demux_src_template, "src");
150   gst_pad_set_event_function (sdidemux->srcpad,
151       GST_DEBUG_FUNCPTR (gst_sdi_demux_src_event));
152   gst_pad_set_getcaps_function (sdidemux->srcpad,
153       GST_DEBUG_FUNCPTR (gst_sdi_demux_src_getcaps));
154   gst_element_add_pad (GST_ELEMENT (sdidemux), sdidemux->srcpad);
155
156
157 }
158
159 void
160 gst_sdi_demux_set_property (GObject * object, guint property_id,
161     const GValue * value, GParamSpec * pspec)
162 {
163   g_return_if_fail (GST_IS_SDI_DEMUX (object));
164
165   switch (property_id) {
166     default:
167       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
168       break;
169   }
170 }
171
172 void
173 gst_sdi_demux_get_property (GObject * object, guint property_id,
174     GValue * value, GParamSpec * pspec)
175 {
176   g_return_if_fail (GST_IS_SDI_DEMUX (object));
177
178   switch (property_id) {
179     default:
180       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
181       break;
182   }
183 }
184
185 void
186 gst_sdi_demux_dispose (GObject * object)
187 {
188   g_return_if_fail (GST_IS_SDI_DEMUX (object));
189
190   /* clean up as possible.  may be called multiple times */
191
192   G_OBJECT_CLASS (parent_class)->dispose (object);
193 }
194
195 void
196 gst_sdi_demux_finalize (GObject * object)
197 {
198   g_return_if_fail (GST_IS_SDI_DEMUX (object));
199
200   /* clean up object here */
201
202   G_OBJECT_CLASS (parent_class)->finalize (object);
203 }
204
205
206 static GstStateChangeReturn
207 gst_sdi_demux_change_state (GstElement * element, GstStateChange transition)
208 {
209
210   return GST_STATE_CHANGE_SUCCESS;
211 }
212
213 static GstCaps *
214 gst_sdi_demux_src_getcaps (GstPad * pad)
215 {
216   return gst_caps_from_string (GST_VIDEO_CAPS_NTSC ("UYVY"));
217 }
218
219 static void
220 gst_sdi_demux_get_output_buffer (GstSdiDemux * sdidemux)
221 {
222   sdidemux->output_buffer =
223       gst_buffer_new_and_alloc (720 * sdidemux->format->active_lines * 2);
224   gst_buffer_set_caps (sdidemux->output_buffer,
225       gst_caps_from_string (GST_VIDEO_CAPS_PAL ("UYVY")));
226   GST_BUFFER_TIMESTAMP (sdidemux->output_buffer) =
227       GST_SECOND * sdidemux->frame_number;
228   sdidemux->frame_number++;
229 }
230
231 static guint32
232 get_word10 (guint8 * ptr)
233 {
234   guint32 a;
235
236   a = (((ptr[0] >> 2) | (ptr[1] << 6)) & 0xff) << 24;
237   a |= (((ptr[1] >> 4) | (ptr[2] << 4)) & 0xff) << 16;
238   a |= (((ptr[2] >> 6) | (ptr[3] << 2)) & 0xff) << 8;
239   a |= ptr[4];
240
241   return a;
242 }
243
244 static void
245 line10_copy (guint8 * dest, guint8 * src, int n)
246 {
247   int i;
248   guint32 a;
249   for (i = 0; i < n; i++) {
250     a = get_word10 (src);
251     GST_WRITE_UINT32_BE (dest, a);
252     src += 5;
253     dest += 4;
254   }
255
256 }
257
258
259 static GstFlowReturn
260 copy_line (GstSdiDemux * sdidemux, guint8 * line)
261 {
262   guint8 *output_data;
263   GstFlowReturn ret = GST_FLOW_OK;
264   GstSdiFormat *format = sdidemux->format;
265
266   output_data = GST_BUFFER_DATA (sdidemux->output_buffer);
267
268   /* line is one less than the video line */
269   if (sdidemux->line >= format->start0 - 1 &&
270       sdidemux->line < format->start0 - 1 + format->active_lines / 2) {
271 #if 0
272     memcpy (output_data + 720 * 2 * ((sdidemux->line -
273                 (format->start0 - 1)) * 2 + (!format->tff)),
274         line + (format->width - 720) * 2, 720 * 2);
275 #else
276     line10_copy (output_data + 720 * 2 * ((sdidemux->line -
277                 (format->start0 - 1)) * 2 + (!format->tff)),
278         line + (format->width - 720) / 2 * 5, 720 / 2);
279 #endif
280   }
281   if (sdidemux->line >= format->start1 - 1 &&
282       sdidemux->line < format->start1 - 1 + format->active_lines / 2) {
283 #if 0
284     memcpy (output_data + 720 * 2 * ((sdidemux->line -
285                 (format->start1 - 1)) * 2 + (format->tff)),
286         line + (format->width - 720) * 2, 720 * 2);
287 #else
288     line10_copy (output_data + 720 * 2 * ((sdidemux->line -
289                 (format->start1 - 1)) * 2 + (format->tff)),
290         line + (format->width - 720) / 2 * 5, 720 / 2);
291 #endif
292   }
293
294   sdidemux->offset = 0;
295   sdidemux->line++;
296   if (sdidemux->line == format->lines) {
297     ret = gst_pad_push (sdidemux->srcpad, sdidemux->output_buffer);
298     gst_sdi_demux_get_output_buffer (sdidemux);
299     sdidemux->line = 0;
300   }
301
302   return ret;
303 }
304
305 #define SDI_IS_SYNC(a) (((a)&0xffffff80) == 0xff000080)
306 #define SDI_SYNC_F(a) (((a)>>6)&1)
307 #define SDI_SYNC_V(a) (((a)>>5)&1)
308 #define SDI_SYNC_H(a) (((a)>>4)&1)
309
310 GstSdiFormat sd_ntsc = { 525, 480, 858, 20, 283, 0 };
311 GstSdiFormat sd_pal = { 625, 576, 864, 23, 336, 1 };
312
313 static GstFlowReturn
314 gst_sdi_demux_chain (GstPad * pad, GstBuffer * buffer)
315 {
316   GstSdiDemux *sdidemux;
317   int offset = 0;
318   guint8 *data = GST_BUFFER_DATA (buffer);
319   int size = GST_BUFFER_SIZE (buffer);
320   GstFlowReturn ret = GST_FLOW_OK;
321   GstSdiFormat *format;
322
323   sdidemux = GST_SDI_DEMUX (gst_pad_get_parent (pad));
324   sdidemux->format = &sd_pal;
325   format = sdidemux->format;
326
327   GST_DEBUG_OBJECT (sdidemux, "chain");
328
329   if (GST_BUFFER_IS_DISCONT (buffer)) {
330     sdidemux->have_hsync = FALSE;
331     sdidemux->have_vsync = FALSE;
332   }
333
334   if (!sdidemux->have_hsync) {
335 #if 0
336     for (offset = 0; offset < size; offset += 4) {
337       guint32 sync = READ_UINT32_BE (data + offset);
338       GST_ERROR ("sync value %08x", sync);
339       if (SDI_IS_SYNC (sync) && SDI_SYNC_H (sync)) {
340         sdidemux->have_hsync = TRUE;
341         sdidemux->line = 0;
342         sdidemux->offset = 0;
343         break;
344       }
345     }
346 #else
347     for (offset = 0; offset < size; offset += 5) {
348       guint32 sync = get_word10 (data + offset);
349       //GST_ERROR("sync value %08x", sync);
350       if (SDI_IS_SYNC (sync) && SDI_SYNC_H (sync)) {
351         sdidemux->have_hsync = TRUE;
352         sdidemux->line = 0;
353         sdidemux->offset = 0;
354         break;
355       }
356     }
357 #endif
358     if (!sdidemux->have_hsync) {
359       GST_ERROR ("no sync");
360       goto out;
361     }
362   }
363
364   if (sdidemux->output_buffer == NULL) {
365     gst_sdi_demux_get_output_buffer (sdidemux);
366   }
367 #if 0
368   if (sdidemux->offset) {
369     int n;
370
371     /* second half of a line */
372     n = MIN (size - offset, format->width * 2 - sdidemux->offset);
373
374     memcpy (sdidemux->stored_line + sdidemux->offset, data + offset, n);
375
376     offset += n;
377     sdidemux->offset += n;
378
379     if (sdidemux->offset == format->width * 2) {
380       guint32 sync =
381           GST_READ_UINT32_BE (data + offset + (format->width - 720 - 2) * 2);
382
383       //GST_ERROR("%08x", sync);
384       if (!sdidemux->have_vsync) {
385         //GST_ERROR("%08x", GST_READ_UINT32_BE(data+offset));
386         if (SDI_IS_SYNC (sync) && !SDI_SYNC_F (sync) &&
387             SDI_SYNC_F (sdidemux->last_sync)) {
388           sdidemux->have_vsync = TRUE;
389         }
390         sdidemux->line = 0;
391       }
392
393       ret = copy_line (sdidemux, sdidemux->stored_line);
394
395       sdidemux->last_sync = sync;
396     }
397   }
398
399   while (size - offset >= format->width * 2) {
400     guint32 sync =
401         GST_READ_UINT32_BE (data + offset + (format->width - 720 - 2) * 2);
402
403     //GST_ERROR("%08x", sync);
404     if (!sdidemux->have_vsync) {
405       if (SDI_IS_SYNC (sync) && !SDI_SYNC_F (sync) &&
406           SDI_SYNC_F (sdidemux->last_sync)) {
407         sdidemux->have_vsync = TRUE;
408       }
409       sdidemux->line = 0;
410     }
411
412     ret = copy_line (sdidemux, data + offset);
413     offset += format->width * 2;
414
415     sdidemux->last_sync = sync;
416   }
417
418   if (size - offset > 0) {
419     memcpy (sdidemux->stored_line, data + offset, size - offset);
420     sdidemux->offset = size - offset;
421   }
422 #else
423   if (sdidemux->offset) {
424     int n;
425
426     /* second half of a line */
427     n = MIN (size - offset, format->width / 2 * 5 - sdidemux->offset);
428
429     memcpy (sdidemux->stored_line + sdidemux->offset, data + offset, n);
430
431     offset += n;
432     sdidemux->offset += n;
433
434     if (sdidemux->offset == (format->width / 2) * 5) {
435       guint32 sync =
436           get_word10 (data + offset + ((format->width - 720 - 2) / 2) * 5);
437
438       if (!sdidemux->have_vsync) {
439         //GST_ERROR("%08x", GST_READ_UINT32_BE(data+offset));
440         if (SDI_IS_SYNC (sync) && !SDI_SYNC_F (sync) &&
441             SDI_SYNC_F (sdidemux->last_sync)) {
442           sdidemux->have_vsync = TRUE;
443         }
444         sdidemux->line = 0;
445       }
446
447       ret = copy_line (sdidemux, sdidemux->stored_line);
448
449       sdidemux->last_sync = sync;
450     }
451   }
452
453   while (size - offset >= format->width / 2 * 5) {
454     guint32 sync =
455         get_word10 (data + offset + ((format->width - 720 - 2) / 2) * 5);
456
457     //GST_ERROR("%08x", sync);
458     if (!sdidemux->have_vsync) {
459       if (SDI_IS_SYNC (sync) && !SDI_SYNC_F (sync) &&
460           SDI_SYNC_F (sdidemux->last_sync)) {
461         sdidemux->have_vsync = TRUE;
462       }
463       sdidemux->line = 0;
464     }
465
466     ret = copy_line (sdidemux, data + offset);
467     offset += (format->width / 2) * 5;
468
469     sdidemux->last_sync = sync;
470   }
471
472   if (size - offset > 0) {
473     memcpy (sdidemux->stored_line, data + offset, size - offset);
474     sdidemux->offset = size - offset;
475   }
476 #endif
477
478 out:
479   gst_buffer_unref (buffer);
480   gst_object_unref (sdidemux);
481   return ret;
482 }
483
484 static gboolean
485 gst_sdi_demux_sink_event (GstPad * pad, GstEvent * event)
486 {
487   gboolean res = TRUE;
488   GstSdiDemux *sdidemux;
489
490   sdidemux = GST_SDI_DEMUX (gst_pad_get_parent (pad));
491
492   GST_DEBUG_OBJECT (sdidemux, "event");
493
494   switch (GST_EVENT_TYPE (event)) {
495     case GST_EVENT_FLUSH_START:
496       res = gst_pad_push_event (sdidemux->srcpad, event);
497       break;
498     case GST_EVENT_FLUSH_STOP:
499       res = gst_pad_push_event (sdidemux->srcpad, event);
500       break;
501     case GST_EVENT_NEWSEGMENT:
502       res = gst_pad_push_event (sdidemux->srcpad, event);
503       break;
504     case GST_EVENT_EOS:
505       res = gst_pad_push_event (sdidemux->srcpad, event);
506       break;
507     default:
508       res = gst_pad_push_event (sdidemux->srcpad, event);
509       break;
510   }
511
512   gst_object_unref (sdidemux);
513   return res;
514 }
515
516 static gboolean
517 gst_sdi_demux_src_event (GstPad * pad, GstEvent * event)
518 {
519   gboolean res;
520   GstSdiDemux *sdidemux;
521
522   sdidemux = GST_SDI_DEMUX (gst_pad_get_parent (pad));
523
524   GST_DEBUG_OBJECT (sdidemux, "event");
525
526   switch (GST_EVENT_TYPE (event)) {
527     case GST_EVENT_SEEK:
528       res = gst_pad_push_event (sdidemux->sinkpad, event);
529       break;
530     default:
531       res = gst_pad_push_event (sdidemux->sinkpad, event);
532       break;
533   }
534
535   gst_object_unref (sdidemux);
536   return res;
537 }