blob: b899e95b8cde8bd35afb50fcc5a1f39de3af1bc0 [file] [log] [blame]
Olivier Naudanb28313f2012-04-16 08:10:18 -04001/*
2 * GStreamer
3 * Copyright (C) 2009 Edward Hervey <bilboed@bilboed.com>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
Sebastian Drögee6513c12013-07-14 12:12:42 +020017 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
Olivier Naudanb28313f2012-04-16 08:10:18 -040019 */
20
21/**
22 * SECTION:element-HDVParse
23 *
24 * <refsect2>
25 * <title>Example launch line</title>
26 * <para>
27 * <programlisting>
28 * gst-launch -v -m filesrc ! mpegtsdemux ! hdvparse ! fakesink silent=TRUE
29 * </programlisting>
30 * </para>
31 * </refsect2>
32 */
33
34#ifdef HAVE_CONFIG_H
35#include "config.h"
36#endif
37
38#include <math.h>
39
40#include <gst/gst.h>
41#include <gst/base/gstbasetransform.h>
42
43#include "gsthdvparse.h"
44
45GST_DEBUG_CATEGORY_STATIC (gst_hdvparse_debug);
46#define GST_CAT_DEFAULT gst_hdvparse_debug
47
48/* Filter signals and args */
49enum
50{
51 /* FILL ME */
52 LAST_SIGNAL
53};
54
55enum
56{
57 PROP_0,
58};
59
60
61
62#define CLOCK_BASE 9LL
63#define CLOCK_FREQ (CLOCK_BASE * 10000)
64
65#define MPEGTIME_TO_GSTTIME(time) (gst_util_uint64_scale ((time), \
66 GST_MSECOND/10, CLOCK_BASE))
67#define GSTTIME_TO_MPEGTIME(time) (gst_util_uint64_scale ((time), \
68 CLOCK_BASE, GST_MSECOND/10))
69
70/* If set to 1, then extra validation will be applied to check
71 * for complete spec compliance wherever applicable. */
72#define VALIDATE 0
73
74/* Binary-coded decimal reading macro */
75#define BCD(c) ( ((((c) >> 4) & 0x0f) * 10) + ((c) & 0x0f) )
76/* Same as before, but with a mask */
77#define BCD_M(c, mask) (BCD ((c) & (mask)))
78
79/* the capabilities of the inputs and outputs.
80 *
81 * describe the real formats here.
82 */
83static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
84 GST_PAD_SINK,
85 GST_PAD_ALWAYS,
86 GST_STATIC_CAPS ("hdv/aux-v;hdv/aux-a")
87 );
88
89static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
90 GST_PAD_SRC,
91 GST_PAD_ALWAYS,
92 GST_STATIC_CAPS
93 ("hdv/aux-v,parsed=(boolean)True;hdv/aux-a,parsed=(boolean)True")
94 );
95
96/* debug category for fltering log messages
97 *
98 * exchange the string 'Template HDVParse' with your description
99 */
100#define DEBUG_INIT(bla) \
101 GST_DEBUG_CATEGORY_INIT (gst_hdvparse_debug, "hdvparse", 0, "HDV private stream parser");
102
103GST_BOILERPLATE_FULL (GstHDVParse, gst_hdvparse, GstBaseTransform,
104 GST_TYPE_BASE_TRANSFORM, DEBUG_INIT);
105
106static GstFlowReturn gst_hdvparse_transform_ip (GstBaseTransform * base,
107 GstBuffer * outbuf);
108static GstCaps *gst_hdvparse_transform_caps (GstBaseTransform * trans,
109 GstPadDirection dir, GstCaps * incaps);
110
111/* GObject vmethod implementations */
112
113static void
114gst_hdvparse_base_init (gpointer klass)
115{
116
117 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
118
Sebastian Dröged89778c2016-07-06 12:52:14 +0300119 gst_element_class_add_static_pad_template (element_class, &src_template);
120 gst_element_class_add_static_pad_template (element_class, &sink_template);
Sebastian Dröge6a5ec012012-10-25 14:10:09 +0200121 gst_element_class_set_static_metadata (element_class, "HDVParser",
Olivier Naudanb28313f2012-04-16 08:10:18 -0400122 "Data/Parser",
123 "HDV private stream Parser", "Edward Hervey <bilboed@bilboed.com>");
124}
125
126/* initialize the HDVParse's class */
127static void
128gst_hdvparse_class_init (GstHDVParseClass * klass)
129{
130 GST_BASE_TRANSFORM_CLASS (klass)->transform_ip =
131 GST_DEBUG_FUNCPTR (gst_hdvparse_transform_ip);
132 GST_BASE_TRANSFORM_CLASS (klass)->transform_caps =
133 GST_DEBUG_FUNCPTR (gst_hdvparse_transform_caps);
134}
135
136/* initialize the new element
137 * initialize instance structure
138 */
139static void
140gst_hdvparse_init (GstHDVParse * filter, GstHDVParseClass * klass)
141{
142 GstBaseTransform *transform = GST_BASE_TRANSFORM (filter);
143
144 gst_base_transform_set_in_place (transform, TRUE);
145 gst_base_transform_set_passthrough (transform, TRUE);
146}
147
148static GstCaps *
149gst_hdvparse_transform_caps (GstBaseTransform * trans, GstPadDirection dir,
150 GstCaps * incaps)
151{
152 GstCaps *res = NULL;
153 GstStructure *st = gst_caps_get_structure (incaps, 0);
154
155 GST_WARNING_OBJECT (trans, "dir:%d, incaps:%" GST_PTR_FORMAT, dir, incaps);
156
157 if (dir == GST_PAD_SINK) {
158 res = gst_caps_new_simple (gst_structure_get_name (st),
159 "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
160 } else {
161 res = gst_caps_new_simple (gst_structure_get_name (st), NULL);
162 }
163
164 return res;
165}
166
167
168static inline const gchar *
169sfr_to_framerate (guint8 sfr)
170{
171 switch (sfr) {
172 case 4:
173 return "30000/1001";
174 case 3:
175 return "25/1";
176 case 1:
177 return "24000/1001";
178 default:
179 return "RESERVED";
180 }
181}
182
183static GstFlowReturn
184parse_dv_multi_pack (GstHDVParse * filter, guint8 * data, guint64 size,
185 GstStructure * st)
186{
187 guint64 offs = 1;
188
189 while (size / 5) {
190 GST_LOG ("DV pack 0x%x", data[offs]);
191 switch (data[offs]) {
192 case 0x70:{
193 guint8 irispos, ae, agc, wbmode, whitebal, focusmode, focuspos;
194
195 irispos = data[offs + 1] & 0x3f;
196 ae = data[offs + 2] >> 4;
197 agc = data[offs + 2] & 0xf;
198 wbmode = data[offs + 3] >> 5;
199 whitebal = data[offs + 3] & 0x1f;
200 focusmode = data[offs + 4] >> 7;
201 focuspos = data[offs + 4] & 0x7f;
202
203 GST_LOG (" Consumer Camera 1");
204
205 GST_LOG (" Iris position %d (0x%x)", irispos, irispos);
206 /* Iris position = 2 ^ (IP/8) (for 0 < IP < 0x3C) */
207 if (irispos < 0x3c) {
208 GST_LOG (" IRIS F%0.2f", powf (2.0, (((float) irispos) / 8.0)));
209 gst_structure_set (st, "aperture-fnumber", G_TYPE_FLOAT,
210 powf (2.0, (((float) irispos) / 8.0)), NULL);
211 } else if (irispos == 0x3d) {
212 GST_LOG (" IRIS < 1.0");
213 } else if (irispos == 0x3e) {
214 GST_LOG (" IRIS closed");
215 }
216
217 /* AE Mode:
218 * 0 : Full automatic
219 * 1 : Gain Priority mode
220 * 2 : Shutter Priority mode
221 * 3 : Iris priority mode
222 * 4 : Manual
223 * ..: Reserved
224 * F : No information */
225 GST_LOG (" AE Mode: %d (0x%x)", ae, ae);
226
227 GST_LOG (" AGC: %d (0x%x)", agc, agc);
228 if (agc < 0xd) {
229 /* This is what the spec says.. but I'm not seeing the same on my camera :( */
230 GST_LOG (" Gain:%02.2fdB", (agc * 3.0) - 3.0);
231 gst_structure_set (st, "gain", G_TYPE_FLOAT, (agc * 3.0) - 3.0, NULL);
232 }
233 /* White balance mode
234 * 0 : Automatic
235 * 1 : hold
236 * 2 : one push
237 * 3 : pre-set
238 * 7 : no-information */
239 if (wbmode != 7)
240 GST_LOG (" White balance mode : %d (0x%x)", wbmode, wbmode);
241 /* White balance
242 * 0 : Candle
243 * 1 : Incandescent lamp
244 * 2 : low color temperature fluorescent lamp
245 * 3 : high color temperature fluorescent lamp
246 * 4 : sunlight
247 * 5 : cloudy weather
248 * F : No information
249 */
250 if (whitebal != 0xf)
251 GST_LOG (" White balance : %d (0x%x)", whitebal, whitebal);
252 if (focuspos != 0x7f) {
253 GST_LOG (" Focus mode : %s", focusmode ? "MANUAL" : "AUTOMATIC");
254 GST_LOG (" Focus position: %d (0x%x)", focuspos, focuspos);
255 }
256 }
257 break;
258 case 0x71:{
259 guint8 v_pan, h_pan, focal_length, e_zoom;
260 gboolean is, zen;
261
262 v_pan = data[offs + 1] & 0x3f;
263 is = data[offs + 2] >> 7;
264 h_pan = data[offs + 2] & 0x7f;
265 focal_length = data[offs + 3];
266 zen = data[offs + 4] >> 7;
267 e_zoom = data[offs + 4] & 0x7f;
268
269 GST_LOG (" Consumer Camera 2");
270 if (v_pan != 0x3f)
271 GST_LOG (" Vertical Panning : %d (0x%d)", v_pan, v_pan);
272 if (h_pan != 0x7f)
273 GST_LOG (" Horizontal Panning : %d (0x%d)", h_pan, h_pan);
274 GST_LOG (" Stabilizer : %s", is ? "OFF" : "ON");
275 if (focal_length != 0xff)
276 GST_LOG (" Focal Length : %f mm",
277 (focal_length & 0x7f) * pow (10, focal_length & 0x80));
278 if (zen == 0)
279 GST_LOG (" Electric Zoom %02dd.%03d", e_zoom >> 5, e_zoom & 0x1f);
280 }
281 break;
282 case 0x7f:{
283 guint16 speed;
284 guint16 speedint;
285
286 GST_LOG (" Shutter");
287 if (data[offs + 1] != 0xff)
288 GST_LOG (" Shutter Speed (1) : %d, 0x%x",
289 data[offs + 1], data[offs + 1]);
290 if (data[offs + 2] != 0xff)
291 GST_LOG (" Shutter Speed (1) : %d, 0x%x",
292 data[offs + 2], data[offs + 2]);
293
294 speed = data[offs + 3] | (data[offs + 4] & 0x7f) << 8;
295
296 /* The shutter speed is 1/(CSS * horizontal scanning period) */
297 /* FIXME : 34000 is a value interpolated by observations */
298 speedint = (int) (34000.0 / (float) speed);
299 /* Only the highest two decimal digits are valid */
300 if (speedint > 100)
301 speedint = speedint / 10 * 10;
302
303 GST_LOG (" Shutter speed : 1/%d", speedint);
304 gst_structure_set (st, "shutter-speed", GST_TYPE_FRACTION,
305 1, speedint, NULL);
306 }
307 break;
308 default:
309 GST_MEMDUMP ("Unknown pack", data + offs, 5);
310 break;
311 }
312 size -= 5;
313 offs += 5;
314 }
315 return GST_FLOW_OK;
316}
317
318static GstFlowReturn
319parse_video_frame (GstHDVParse * filter, guint8 * data, guint64 size,
320 GstStructure * st)
321{
322 guint32 etn, bitrate;
323 guint8 nbframes, data_h, hdr_size, sfr, sdm;
324 guint8 aspect, framerate, profile, level, format, chroma;
325 guint8 gop_n, gop_m, cgms, recst, abst;
326 guint16 vbv_delay, width, height, vbv_buffer;
327 guint64 dts;
328 gboolean pf, tf, rf;
329
330 GST_LOG_OBJECT (filter, "Video Frame Pack");
331
332 /* Byte | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
333 * ---------------------------------
334 * 0 | Size (0x39) |
335 * ---------------------------------
336 * 1 | |
337 * 2 | ETN |
338 * 3 | |
339 * ---------------------------------
340 */
341
342 if (data[0] != 0x39) {
343 GST_WARNING ("Invalid size for Video frame");
344 return GST_FLOW_ERROR;
345 }
346 etn = data[3] << 16 | data[2] << 8 | data[1];
347
348 GST_LOG_OBJECT (filter, " ETN : %" G_GUINT32_FORMAT, etn);
349
350 /* Pack-V Information
351 * ---------------------------------
352 * 4 | Number of Video Frames |
353 * ---------------------------------
354 * 5 | 0 | 0 | 0 | 0 | DATA-H |
355 * ---------------------------------
356 * 6 | VBV |
357 * 7 | DELAY |
358 * ---------------------------------
359 * 8 | HEADER SIZE |
360 * ---------------------------------
361 * 9 | |
362 * 10 | DTS |
363 * 11 | |
364 * 12 | |
365 * ----------------------------- |
366 * 13 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | |
367 * ---------------------------------
368 * 14 |PF |TF |RF | 0 | SFR |
369 * ---------------------------------
370 */
371
372 nbframes = data[4];
373
374 if (VALIDATE && (data[5] >> 4))
375 return GST_FLOW_ERROR;
376 data_h = data[5] & 0xf;
377
378 vbv_delay = data[6] | data[7] << 8;
379
380 hdr_size = data[8];
381
382 dts = data[9] | data[10] << 8 | data[11] << 16 | data[12] << 24;
383 dts |= (guint64) (data[13] & 0x1) << 32;
384 if (G_UNLIKELY (VALIDATE && (data[13] & 0xfe))) {
385 return GST_FLOW_ERROR;
386 }
387
388 pf = data[14] & 0x80;
389 tf = data[14] & 0x40;
390 rf = data[14] & 0x20;
391 if (G_UNLIKELY (VALIDATE && (data[14] & 0x10)))
392 return GST_FLOW_ERROR;
393
394 sfr = data[14] & 0x07;
395
396 GST_LOG_OBJECT (filter, " Pack-V Information");
397 GST_LOG_OBJECT (filter, " Number of Video Frames : %d", nbframes);
398 GST_LOG_OBJECT (filter, " Leading PES-V picture type %s (0x%x)",
399 (data_h == 0x1) ? "I-picture" : "other", data_h);
400 GST_LOG_OBJECT (filter, " VBV Delay of first frame: %" G_GUINT32_FORMAT,
401 vbv_delay);
402 GST_LOG_OBJECT (filter, " Header Size:%d", hdr_size);
403 GST_LOG_OBJECT (filter, " DTS: %" GST_TIME_FORMAT " (%" G_GUINT64_FORMAT ")",
404 GST_TIME_ARGS (MPEGTIME_TO_GSTTIME (dts)), dts);
405 GST_LOG_OBJECT (filter, " Video source : %s %s %s (0x%x 0x%x 0x%x)",
406 pf ? "Progressive" : "Interlaced",
407 tf ? "TFF" : "", rf ? "RFF" : "", pf, tf, rf);
408 GST_LOG_OBJECT (filter, " Source Frame Rate : %s (0x%x)",
409 sfr_to_framerate (sfr), sfr);
410
411 gst_structure_set (st, "DTS", G_TYPE_UINT64, MPEGTIME_TO_GSTTIME (dts),
412 "interlaced", G_TYPE_BOOLEAN, !pf, NULL);
413
414 /* Search Data Mode
415 * ---------------------------------
416 * 15 | Search Data Mode |
417 * ---------------------------------
418 */
419 sdm = data[15];
420 GST_LOG_OBJECT (filter, " Search Data Mode : 0x%x", sdm);
421 GST_LOG_OBJECT (filter, " %s %s %s",
422 sdm & 0x2 ? "8x-Base" : "",
423 sdm & 0x4 ? "8x-Helper" : "", sdm & 0x10 ? "24x" : "");
424
425 /* Video Mode
426 * ---------------------------------
427 * 16 | Horizontal size |
428 * ----------------- |
429 * 17 | 0 | 0 | 0 | 0 | |
430 * ---------------------------------
431 * 18 | Vertical size |
432 * ----------------- |
433 * 19 | 0 | 0 | 0 | 0 | |
434 * ---------------------------------
435 * 20 | Aspect ratio | Frame Rate |
436 * ---------------------------------
437 * 21 | |
438 * 22 | bitrate |
439 * ------------------------- |
440 * 23 | 0 | 0 | 0 | 0 | 0 | 0 | |
441 * ---------------------------------
442 * 24 | VBV Buffer size |
443 * ------------------------- |
444 * 25 | 0 | 0 | 0 | 0 | 0 | 0 | |
445 * ---------------------------------
446 * 26 | 0 | Profile | Level |
447 * ---------------------------------
448 * 27 | 0 | Format |Chroma | 0 | 0 |
449 * ---------------------------------
450 * 28 | GOP N | GOP M |
451 * ---------------------------------
452 */
453 width = data[16] | (data[17] & 0xf) << 8;
454 height = data[18] | (data[19] & 0xf) << 8;
455 if (VALIDATE && ((data[17] & 0xf0) || data[19] & 0xf0))
456 return GST_FLOW_ERROR;
457 aspect = data[20] >> 4;
458 framerate = data[20] & 0xf;
459 bitrate = data[21] | data[22] << 8 | (data[23] & 0x3) << 16;
460 if (VALIDATE && (data[23] & 0xfc))
461 return GST_FLOW_ERROR;
462 vbv_buffer = data[24] | (data[25] & 0x3) << 8;
463 if (VALIDATE && (data[25] & 0xfc))
464 return GST_FLOW_ERROR;
465 profile = (data[26] >> 4) & 0x7;
466 level = data[26] & 0xf;
467 format = (data[27] >> 4) & 0x7;
468 chroma = (data[27] >> 2) & 0x3;
469 gop_n = data[28] >> 3;
470 gop_m = data[28] & 0x7;
471
472 GST_LOG_OBJECT (filter, " Video Mode");
473 GST_LOG_OBJECT (filter, " width:%d, height:%d", width, height);
474 GST_LOG_OBJECT (filter, " Aspect Ratio : %s (0x%x)",
475 (aspect == 0x3) ? "16/9" : "RESERVED", aspect);
476 GST_LOG_OBJECT (filter, " Framerate: %s (0x%x)",
477 sfr_to_framerate (framerate), framerate);
478 GST_LOG_OBJECT (filter, " Bitrate: %d bit/s", bitrate * 400);
479 GST_LOG_OBJECT (filter, " VBV buffer Size : %d bits",
480 vbv_buffer * 16 * 1024);
481 GST_LOG_OBJECT (filter, " MPEG Profile : %s (0x%x)",
482 (profile == 0x4) ? "Main" : "RESERVED", profile);
483 GST_LOG_OBJECT (filter, " MPEG Level : %s (0x%x)",
484 (level == 0x6) ? "High-1440" : "RESERVED", level);
485 GST_LOG_OBJECT (filter, " Video format : %s (0x%x)",
486 (format == 0) ? "Component" : "Reserved", format);
487 GST_LOG_OBJECT (filter, " Chroma : %s (0x%x)",
488 (chroma == 0x1) ? "4:2:0" : "RESERVED", chroma);
489 GST_LOG_OBJECT (filter, " GOP N/M : %d / %d", gop_n, gop_m);
490
491 /* data availability
492 * ---------------------------------
493 * 29 | 0 | 0 | 0 | 0 | 0 |PE2|PE1|PE0|
494 * ---------------------------------
495 * PE0 : HD2 TTC is valid
496 * PE1 : REC DATE is valid
497 * PE2 : REC TIME is valid
498 */
499 if (data[29] & 0x1) {
500 guint8 fr, sec, min, hr;
501 gboolean bf, df;
502 gchar *ttcs;
503
504 /* HD2 TTC
505 * ---------------------------------
506 * 30 |BF |DF |Tens Fr|Units of Frames|
507 * ---------------------------------
508 * 31 | 1 |Tens second|Units of Second|
509 * ---------------------------------
510 * 32 | 1 |Tens minute|Units of Minute|
511 * ---------------------------------
512 * 33 | 1 | 1 |Tens Hr|Units of Hours |
513 * ---------------------------------
514 */
515 bf = data[30] >> 7;
516 df = (data[30] >> 6) & 0x1;
517 fr = BCD (data[30] & 0x3f);
518 sec = BCD (data[31] & 0x7f);
519 min = BCD (data[32] & 0x7f);
520 hr = BCD (data[33] & 0x3f);
521 GST_LOG_OBJECT (filter, " HD2 Title Time Code");
522 GST_LOG_OBJECT (filter, " BF:%d, Drop Frame:%d", bf, df);
523 ttcs = g_strdup_printf ("%02d:%02d:%02d.%02d", hr, min, sec, fr);
524 GST_LOG_OBJECT (filter, " Timecode %s", ttcs);
525 /* FIXME : Use framerate information from above to convert to GstClockTime */
526 gst_structure_set (st, "title-time-code", G_TYPE_STRING, ttcs, NULL);
527 g_free (ttcs);
528
529 }
530
531 if (data[29] & 0x2) {
532 gboolean ds, tm;
533 guint8 tz, day, dow, month, year;
534 GDate *date;
535
536 /* REC DATE
537 * ---------------------------------
538 * 34 |DS |TM |Tens TZ|Units of TimeZn|
539 * ---------------------------------
540 * 35 | 1 | 1 |Tens dy| Units of Days |
541 * ---------------------------------
542 * 36 | Week |TMN|Units of Months|
543 * ---------------------------------
544 * 37 | Tens of Years |Units of Years |
545 * ---------------------------------
546 */
547 ds = data[34] >> 7;
548 tm = (data[34] >> 6) & 0x1;
549 tz = BCD (data[34] & 0x3f);
550 day = BCD (data[35] & 0x3f);
551 dow = data[36] >> 5;
552 month = BCD (data[36] & 0x1f);
553 year = BCD (data[37]);
554
555 GST_LOG_OBJECT (filter, " REC DATE");
556 GST_LOG_OBJECT (filter, " ds:%d, tm:%d", ds, tm);
557 GST_LOG_OBJECT (filter, " Timezone: %d", tz);
558 GST_LOG_OBJECT (filter, " Date: %d %02d/%02d/%04d", dow, day, month, year);
559 date = g_date_new_dmy (day, month, year);
560 gst_structure_set (st, "date", GST_TYPE_DATE, date,
561 "timezone", G_TYPE_INT, tz,
562 "daylight-saving", G_TYPE_BOOLEAN, ds, NULL);
563 g_date_free (date);
564 }
565
566 if (data[29] & 0x4) {
567 guint8 fr, sec, min, hr;
568 gchar *times;
569
570 /* REC TIME
571 * ---------------------------------
572 * 38 | 1 | 1 |Tens Fr|Units of Frames|
573 * ---------------------------------
574 * 39 | 1 |Tens second|Units of Second|
575 * ---------------------------------
576 * 40 | 1 |Tens minute|Units of Minute|
577 * ---------------------------------
578 * 41 | 1 | 1 |Tens Hr|Units of Hours |
579 * ---------------------------------
580 */
581 fr = BCD (data[38] & 0x3f);
582 sec = BCD (data[39] & 0x7f);
583 min = BCD (data[40] & 0x7f);
584 hr = BCD (data[41] & 0x3f);
585 times = g_strdup_printf ("%02d:%02d:%02d", hr, min, sec);
586 GST_LOG_OBJECT (filter, " REC TIME %02d:%02d:%02d.%02d", hr, min, sec, fr);
587 gst_structure_set (st, "time", G_TYPE_STRING, times, NULL);
588 g_free (times);
589 }
590
591 /* MISC
592 * ---------------------------------
593 * 42 | CGMS |REC|ABS| 0 | 0 | 0 | 0 |
594 * ---------------------------------
595 */
596 cgms = data[42] >> 6;
597 recst = (data[42] >> 5) & 0x1;
598 abst = (data[42] >> 4) & 0x1;
599
600 GST_LOG_OBJECT (filter, " CGMS:0x%x", cgms);
601 GST_LOG_OBJECT (filter, " Recording Start Point : %s",
602 (recst == 0) ? "PRESENT" : "ABSENT");
603 GST_LOG_OBJECT (filter, " ABST : %s",
604 (abst == 0) ? "DISCONTINUITY" : "NO DISCONTINUITY");
605
606 gst_structure_set (st, "recording-start-point", G_TYPE_BOOLEAN, !recst, NULL);
607
608 /* Extended DV Pack #1
609 * 43 - 47
610 */
611 GST_LOG_OBJECT (filter, " Extended DV Pack #1 : 0x%x", data[43]);
612
613 /* Extended DV Pack #1
614 * 48 - 52
615 */
616 GST_LOG_OBJECT (filter, " Extended DV Pack #2 : 0x%x", data[48]);
617
618 /* Extended DV Pack #1
619 * 53 - 57
620 */
621 GST_LOG_OBJECT (filter, " Extended DV Pack #3 : 0x%x", data[53]);
622
623 return GST_FLOW_OK;
624
625}
626
627static GstFlowReturn
628parse_audio_frame (GstHDVParse * filter, guint8 * data, guint64 size,
629 GstStructure * st)
630{
631 guint32 etn;
632 guint8 nbmute, nbaau;
633 guint64 pts;
634 guint16 audio_comp;
635 guint8 bitrate, fs, compress, channel;
636 guint8 option, cgms;
637 gboolean acly, recst;
638
639 GST_LOG_OBJECT (filter, "Audio Frame Pack");
640
641 /* Byte | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
642 * ---------------------------------
643 * 0 | Size (0x0f) |
644 * ---------------------------------
645 * 1 | |
646 * 2 | ETN |
647 * 3 | |
648 * ---------------------------------
649 * 4 |Nb Audio Mute | Number of AAU |
650 * ---------------------------------
651 */
652
653 if (data[0] != 0x0f) {
654 GST_WARNING ("Invalid size for audio frame");
655 return GST_FLOW_ERROR;
656 }
657 etn = data[3] << 16 | data[2] << 8 | data[1];
658
659 GST_LOG_OBJECT (filter, " ETN : %" G_GUINT32_FORMAT, etn);
660
661 /* Pack-A Information
662 * ---------------------------------
663 * 4 |Nb Audio Mute | Number of AAU |
664 * ---------------------------------
665 * 5 | |
666 * 6 | PTS |
667 * 7 | |
668 * 8 | |
669 * ----------------------------- |
670 * 9 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | |
671 * ---------------------------------
672 * 10 | Audio |
673 * 11 | Compensation |
674 * ---------------------------------
675 */
676
677 /* Number of Audio Mute Frames */
678 nbmute = data[4] >> 4;
679 /* Number of AAU */
680 nbaau = data[4] & 0x0f;
681 /* PTS of the first AAU immediatly following */
682 pts = (data[5] | data[6] << 8 | data[7] << 16 | data[8] << 24);
683 pts |= (guint64) (data[9] & 0x1) << 32;
684 if (G_UNLIKELY (VALIDATE && (data[9] & 0xfe))) {
685 return GST_FLOW_ERROR;
686 }
687
688 /* Amount of compensation */
689 audio_comp = data[10] | data[11] << 8;
690
691 GST_LOG_OBJECT (filter, " Pack-A Information");
692 GST_LOG_OBJECT (filter, " Nb Audio Mute Frames : %d", nbmute);
693 GST_LOG_OBJECT (filter, " Nb AAU : %d", nbaau);
694 GST_LOG_OBJECT (filter,
695 " PTS : %" GST_TIME_FORMAT " (%" G_GUINT64_FORMAT ")",
696 GST_TIME_ARGS (MPEGTIME_TO_GSTTIME (pts)), pts);
697 GST_LOG_OBJECT (filter, " Audio Compensation : %" G_GUINT32_FORMAT,
698 audio_comp);
699
700 /* Audio Mode
701 * ---------------------------------
702 * 12 | Bitrate Index | 0 |Samplerate |
703 * ---------------------------------
704 * 13 | Compression | Channels |
705 * ---------------------------------
706 * 14 | X | Anciliary Option |
707 * ---------------------------------
708 *
709 * X : Anciliary data present
710 */
711
712 bitrate = data[12] >> 4;
713 fs = data[12] & 0x7;
714 if (G_UNLIKELY (VALIDATE && (data[12] & 0x08)))
715 return GST_FLOW_ERROR;
716
717 compress = data[13] >> 4;
718 channel = data[13] & 0xf;
719 acly = data[14] & 0x80;
720 option = data[14] & 0x7f;
721
722 GST_LOG_OBJECT (filter, " Audio Mode");
723 GST_LOG_OBJECT (filter, " Bitrate : %s (0x%x)",
724 (bitrate == 0xe) ? "384kbps" : "RESERVED", bitrate);
725 GST_LOG_OBJECT (filter, " Samplerate : %s (0x%x)",
726 (fs == 0x1) ? "48 kHz" : "RESERVED", fs);
727 GST_LOG_OBJECT (filter, " Compression : %s (0x%x)",
728 (compress == 0x2) ? "MPEG-1 Layer II" : "RESERVED", compress);
729 GST_LOG_OBJECT (filter, " Channels : %s (0x%x)",
730 (channel == 0) ? "Stereo" : "RESERVED", channel);
731 GST_LOG_OBJECT (filter, " Anciliary data %s %s (0x%x)",
732 acly ? "PRESENT" : "ABSENT",
733 (option == 0xc) ? "IEC 13818-3" : "ABSENT/RESERVED", option);
734 /*
735 * ---------------------------------
736 * 15 | CGMS | R | 0 | 0 | 0 | 0 | 0 |
737 * ---------------------------------
738 *
739 * R : Recording Start Point
740 */
741
742 cgms = data[15] & 0xc0;
743 recst = data[15] & 0x20;
744
745 GST_LOG_OBJECT (filter, " Misc");
746 GST_LOG_OBJECT (filter, " CGMS : 0x%x", cgms);
747 GST_LOG_OBJECT (filter, " Recording Start Point %s",
748 (recst) ? "ABSENT" : "PRESENT");
749
750 gst_structure_set (st, "PTS", G_TYPE_UINT64, MPEGTIME_TO_GSTTIME (pts),
751 "recording-start-point", G_TYPE_BOOLEAN, !recst, NULL);
752
753 return GST_FLOW_OK;
754}
755
756static GstFlowReturn
757gst_hdvparse_parse (GstHDVParse * filter, GstBuffer * buf)
758{
759 GstFlowReturn res = GST_FLOW_OK;
760 guint8 *data = GST_BUFFER_DATA (buf);
761 guint64 offs = 0;
762 guint64 insize = GST_BUFFER_SIZE (buf);
763 GstStructure *st;
764
765 /* Byte | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
766 * ---------------------------------
767 * 0 | 0 | KEYWORD |
768 * (1) | LENGTH |
769 * ....
770 *
771 * KEYWORD :
772 * 0x00 - 0x3F : Constant length (5 bytes)
773 * 0x40 - 0x7F : Variable length (LENGTH + 1)
774 *
775 * LENGTH : if present, size of fields 1-N
776 *
777 * Known keyword values:
778 * 0x00-0x07 : AUX-V
779 * 0x08-0x3E : RESERVED
780 * 0x3F : AUX-N NO-INFO
781 * 0x40-0x43 : AUX-A
782 * 0x44-0x47 : AUX-V
783 * 0x48-0x4F : AUX-N
784 * 0x50-0x53 : AUX-SYS
785 * 0x54-0x7E : RESERVED
786 * 0x7F : AUX-N NULL PACK
787 */
788
789 st = gst_structure_empty_new ("hdv-aux");
790
791 while (res == GST_FLOW_OK && (offs < insize)) {
792 guint8 kw = data[offs] & 0x7f;
793 guint8 size;
794
795 /* Variable size packs */
796 if (kw >= 0x40) {
797 size = data[offs + 1];
798 } else
799 size = 4;
800
801 /* Size validation */
802 GST_DEBUG ("kw:0x%x, insize:%" G_GUINT64_FORMAT ", offs:%" G_GUINT64_FORMAT
803 ", size:%d", kw, insize, offs, size);
804 if (insize < offs + size) {
805 res = GST_FLOW_ERROR;
806 goto beach;
807 }
808
809 switch (kw) {
810 case 0x01:
811 GST_LOG ("BINARY GROUP");
812 offs += size + 1;
813 break;
814 case 0x07:
815 GST_LOG ("ETN pack");
816 break;
817 case 0x40:
818 GST_LOG ("Audio frame pack");
819 res = parse_audio_frame (filter, data + offs + 1, size, st);
820 offs += size + 2;
821 break;
822 case 0x3f:
823 GST_LOG ("NO INFO pack");
824 offs += size + 1;
825 break;
826 case 0x44:
827 GST_LOG ("Video frame pack");
828 res = parse_video_frame (filter, data + offs + 1, size, st);
829 offs += size + 2;
830 break;
831 case 0x48:
832 case 0x49:
833 case 0x4A:
834 case 0x4B:
835 GST_LOG ("DV multi-pack");
836 res = parse_dv_multi_pack (filter, data + offs + 1, size, st);
837 offs += size + 2;
838 break;
839 default:
840 GST_WARNING_OBJECT (filter, "Unknown AUX pack data of type 0x%x", kw);
841 res = GST_FLOW_ERROR;
842 }
843 }
844
845beach:
846 if (gst_structure_n_fields (st)) {
847 GstMessage *msg;
848 /* Emit the element message */
849 msg = gst_message_new_element (GST_OBJECT (filter), st);
850 gst_element_post_message (GST_ELEMENT (filter), msg);
851 } else
852 gst_structure_free (st);
853
854 return res;
855
856}
857
858/* GstBaseTransform vmethod implementations */
859
860static GstFlowReturn
861gst_hdvparse_transform_ip (GstBaseTransform * base, GstBuffer * outbuf)
862{
863 GstHDVParse *filter = GST_HDVPARSE (base);
864
865 return gst_hdvparse_parse (filter, outbuf);
866}
867
868
869/* entry point to initialize the plug-in
870 * initialize the plug-in itself
871 * register the element factories and other features
872 */
873static gboolean
874HDVParse_init (GstPlugin * HDVParse)
875{
876 return gst_element_register (HDVParse, "hdvparse", GST_RANK_NONE,
877 GST_TYPE_HDVPARSE);
878}
879
880/* gstreamer looks for this structure to register HDVParses
881 *
882 * exchange the string 'Template HDVParse' with you HDVParse description
883 */
884GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
885 GST_VERSION_MINOR,
886 hdvparse,
887 "HDV private stream parser",
888 HDVParse_init, VERSION, "LGPL", "GStreamer", "http://gstreamer.net/")