diff options
author | Edward Hervey <bilboed@bilboed.com> | 2009-06-05 10:47:41 +0200 |
---|---|---|
committer | Edward Hervey <bilboed@bilboed.com> | 2009-06-05 20:23:44 +0200 |
commit | c4ef659ebd9b6360fe2c4e23374ba4484617fd8b (patch) | |
tree | c49cb3a84a76271b61334e6ded14bdfffe8bb749 /gst/hdvparse | |
parent | 6f88e17f67f44a89c122c95caf0f9baf9dfdbbfa (diff) | |
download | gst-plugins-bad-c4ef659ebd9b6360fe2c4e23374ba4484617fd8b.tar.gz gst-plugins-bad-c4ef659ebd9b6360fe2c4e23374ba4484617fd8b.tar.bz2 gst-plugins-bad-c4ef659ebd9b6360fe2c4e23374ba4484617fd8b.zip |
hdvparse: Rewrite from scratch. Handle both hdv-a and hdv-v
This time we analyze a lot more information.
Still need to re-add the message emission.
Diffstat (limited to 'gst/hdvparse')
-rw-r--r-- | gst/hdvparse/gsthdvparse.c | 849 |
1 files changed, 665 insertions, 184 deletions
diff --git a/gst/hdvparse/gsthdvparse.c b/gst/hdvparse/gsthdvparse.c index 9914cfa2..73367247 100644 --- a/gst/hdvparse/gsthdvparse.c +++ b/gst/hdvparse/gsthdvparse.c @@ -35,6 +35,8 @@ #include "config.h" #endif +#include <math.h> + #include <gst/gst.h> #include <gst/base/gstbasetransform.h> @@ -55,90 +57,25 @@ enum PROP_0, }; -static gchar *aperture_table[] = { - "???", - "cls", - "1.0", - "1.2", - "1.4", - "1.6", - "1.7", - "1.8", - "2.0", - "2.2", - "2.4", - "2.6", - "2.8", - "3.1", - "3.4", - "3.7", - "4.0", - "4.4", - "4.8", - "5.2", - "5.6", - "6.2", - "6.8", - "7.3", - "8.0", - "8.7", - "9.6", - "10", - "11", - "12", - "14", - "14", - "16", - "17", - "18", - "6.7" -}; -/* Observations from my HDV Camera (Canon HV20 Pal) - * FIXME : replace with with code once we've figured out the algorithm. - * Shutter speed 0x4f 0x50 - * ------------------------------------ - * 1/6 F3 95 - * 1/8 90 91 - * 1/12 FA 8A - * 1/15 C8 88 - * 1/24 7D 85 - * 1/30 64 84 - * 1/48 BE 82 - * 1/60 32 82 - * 1/100 51 81 - * 1/250 87 80 - * 1/500 43 80 - * 1/1000 22 80 - * 1/2000 11 80 - */ -typedef struct -{ - guint vala, valb, shutter; -} Shutter_t; - -static Shutter_t shutter_table[] = { - {0xf3, 0x95, 6}, - {0x90, 0x91, 8}, - {0xfa, 0x8a, 12}, - {0xc8, 0x88, 15}, - {0x7d, 0x85, 24}, - {0x64, 0x84, 30}, - {0xbe, 0x82, 48}, - {0x32, 0x82, 60}, - {0x51, 0x81, 100}, - {0x87, 0x80, 250}, - {0x43, 0x80, 500}, - {0x22, 0x80, 1000}, - {0x11, 0x80, 2000} -}; + +#define CLOCK_BASE 9LL +#define CLOCK_FREQ (CLOCK_BASE * 10000) + +#define MPEGTIME_TO_GSTTIME(time) (gst_util_uint64_scale ((time), \ + GST_MSECOND/10, CLOCK_BASE)) +#define GSTTIME_TO_MPEGTIME(time) (gst_util_uint64_scale ((time), \ + CLOCK_BASE, GST_MSECOND/10)) + +/* If set to 1, then extra validation will be applied to check + * for complete spec compliance wherever applicable. */ +#define VALIDATE 1 /* Binary-coded decimal reading macro */ #define BCD(c) ( ((((c) >> 4) & 0x0f) * 10) + ((c) & 0x0f) ) /* Same as before, but with a mask */ #define BCD_M(c, mask) (BCD ((c) & (mask))) - /* the capabilities of the inputs and outputs. * * describe the real formats here. @@ -146,13 +83,14 @@ static Shutter_t shutter_table[] = { static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, - GST_STATIC_CAPS ("private/hdv-a1") + GST_STATIC_CAPS ("hdv/aux-v;hdv/aux-a") ); static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS, - GST_STATIC_CAPS ("private/hdv-a1,parsed=(boolean)True") + GST_STATIC_CAPS + ("hdv/aux-v,parsed=(boolean)True;hdv/aux-a,parsed=(boolean)True") ); /* debug category for fltering log messages @@ -167,6 +105,8 @@ GST_BOILERPLATE_FULL (GstHDVParse, gst_hdvparse, GstBaseTransform, static GstFlowReturn gst_hdvparse_transform_ip (GstBaseTransform * base, GstBuffer * outbuf); +static GstCaps *gst_hdvparse_transform_caps (GstBaseTransform * trans, + GstPadDirection dir, GstCaps * incaps); /* GObject vmethod implementations */ @@ -194,6 +134,8 @@ gst_hdvparse_class_init (GstHDVParseClass * klass) { GST_BASE_TRANSFORM_CLASS (klass)->transform_ip = GST_DEBUG_FUNCPTR (gst_hdvparse_transform_ip); + GST_BASE_TRANSFORM_CLASS (klass)->transform_caps = + GST_DEBUG_FUNCPTR (gst_hdvparse_transform_caps); } /* initialize the new element @@ -208,123 +150,664 @@ gst_hdvparse_init (GstHDVParse * filter, GstHDVParseClass * klass) gst_base_transform_set_passthrough (transform, TRUE); } -static guint -get_shutter_speed (guint8 vala, guint8 valb) +static GstCaps * +gst_hdvparse_transform_caps (GstBaseTransform * trans, GstPadDirection dir, + GstCaps * incaps) { - guint i; + GstCaps *res = NULL; + GstStructure *st = gst_caps_get_structure (incaps, 0); + + GST_WARNING_OBJECT (trans, "dir:%d, incaps:%" GST_PTR_FORMAT, dir, incaps); + + if (dir == GST_PAD_SINK) { + res = gst_caps_new_simple (gst_structure_get_name (st), + "parsed", G_TYPE_BOOLEAN, TRUE, NULL); + } else { + res = gst_caps_new_simple (gst_structure_get_name (st), NULL); + } - for (i = 0; i < G_N_ELEMENTS (shutter_table); i++) - if (shutter_table[i].vala == vala && shutter_table[i].valb == valb) - return shutter_table[i].shutter; - GST_WARNING ("Unknown shutter speed ! vala:0x%02x, valb:0x%02x", vala, valb); - return 0; + return res; } -static void -gst_hdvparse_parse (GstHDVParse * filter, GstBuffer * buf) + +static inline const gchar * +sfr_to_framerate (guint8 sfr) { - guint8 *data = GST_BUFFER_DATA (buf); - guint apertured, shutter; - gfloat gain; - gboolean dst = FALSE; - GstStructure *str; - GstMessage *msg; - - GST_MEMDUMP_OBJECT (filter, "BUFFER", data, GST_BUFFER_SIZE (buf)); - - str = gst_structure_empty_new ("HDV"); - - /* 0x1f - 0x23 : TimeCode */ - - if (data[0x1f] != 0xff) { - guint8 tframe, tsec, tmin, thour; - gchar *timecode = NULL; - tframe = BCD (data[0x1f] & 0x3f); - tsec = BCD (data[0x20] & 0x7f); - tmin = BCD (data[0x21] & 0x7f); - thour = BCD (data[0x22] & 0x3f); - - timecode = - g_strdup_printf ("%01d:%02d:%02d.%02d", thour, tmin, tsec, tframe); - gst_structure_set (str, "timecode", G_TYPE_STRING, timecode, NULL); - g_free (timecode); - GST_LOG_OBJECT (filter, timecode); + switch (sfr) { + case 4: + return "30000/1001"; + case 3: + return "25/1"; + case 1: + return "24000/1001"; + default: + return "RESERVED"; + } +} + +static GstFlowReturn +parse_dv_multi_pack (GstHDVParse * filter, guint8 * data, guint64 size) +{ + guint64 offs = 1; + + while (size / 5) { + GST_LOG ("DV pack 0x%x", data[offs]); + switch (data[offs]) { + case 0x70:{ + guint8 irispos, ae, agc, wbmode, whitebal, focusmode, focuspos; + + irispos = data[offs + 1] & 0x3f; + ae = data[offs + 2] >> 4; + agc = data[offs + 2] & 0xf; + wbmode = data[offs + 3] >> 5; + whitebal = data[offs + 3] & 0x1f; + focusmode = data[offs + 4] >> 7; + focuspos = data[offs + 4] & 0x7f; + + GST_LOG (" Consumer Camera 1"); + + GST_LOG (" Iris position %d (0x%x)", irispos, irispos); + /* Iris position = 2 ^ (IP/8) (for 0 < IP < 0x3C) */ + if (irispos < 0x3c) + GST_LOG (" IRIS F%0.2f", powf (2.0, (((float) irispos) / 8.0))); + else if (irispos == 0x3d) + GST_LOG (" IRIS < 1.0"); + else if (irispos == 0x3e) + GST_LOG (" IRIS closed"); + + /* AE Mode: + * 0 : Full automatic + * 1 : Gain Priority mode + * 2 : Shutter Priority mode + * 3 : Iris priority mode + * 4 : Manual + * ..: Reserved + * F : No information */ + GST_LOG (" AE Mode: %d (0x%x)", ae, ae); + + GST_LOG (" AGC: %d (0x%x)", agc, agc); + if (agc < 0xd) { + GST_LOG (" Gain:%02.2fdB", (agc - 1.0) * 1.5); + GST_LOG (" Gain:%02.2fdB", (agc * 3.0) - 3); + } + /* White balance mode + * 0 : Automatic + * 1 : hold + * 2 : one push + * 3 : pre-set + * 7 : no-information */ + if (wbmode != 7) + GST_LOG (" White balance mode : %d (0x%x)", wbmode, wbmode); + /* White balance + * 0 : Candle + * 1 : Incandescent lamp + * 2 : low color temperature fluorescent lamp + * 3 : high color temperature fluorescent lamp + * 4 : sunlight + * 5 : cloudy weather + * F : No information + */ + if (whitebal != 0xf) + GST_LOG (" White balance : %d (0x%x)", whitebal, whitebal); + if (focuspos != 0x7f) { + GST_LOG (" Focus mode : %s", focusmode ? "MANUAL" : "AUTOMATIC"); + GST_LOG (" Focus position: %d (0x%x)", focuspos, focuspos); + } + } + break; + case 0x71:{ + guint8 v_pan, h_pan, focal_length, e_zoom; + gboolean is, zen; + + v_pan = data[offs + 1] & 0x3f; + is = data[offs + 2] >> 7; + h_pan = data[offs + 2] & 0x7f; + focal_length = data[offs + 3]; + zen = data[offs + 4] >> 7; + e_zoom = data[offs + 4] & 0x7f; + + GST_LOG (" Consumer Camera 2"); + if (v_pan != 0x3f) + GST_LOG (" Vertical Panning : %d (0x%d)", v_pan, v_pan); + if (h_pan != 0x7f) + GST_LOG (" Horizontal Panning : %d (0x%d)", h_pan, h_pan); + GST_LOG (" Stabilizer : %s", is ? "OFF" : "ON"); + if (focal_length != 0xff) + GST_LOG (" Focal Length : %d mm", + (focal_length & 0x7f) * pow (10, focal_length & 0x80)); + if (zen == 0) + GST_LOG (" Electric Zoom %02dd.%03d", e_zoom >> 5, e_zoom & 0x1f); + } + break; + case 0x7f:{ + guint16 speed; + guint16 speedint; + + GST_LOG (" Shutter"); + if (data[offs + 1] != 0xff) + GST_LOG (" Shutter Speed (1) : %d, 0x%x", + data[offs + 1], data[offs + 1]); + if (data[offs + 2] != 0xff) + GST_LOG (" Shutter Speed (1) : %d, 0x%x", + data[offs + 2], data[offs + 2]); + + speed = data[offs + 3] | (data[offs + 4] & 0x7f) << 8; + + /* The shutter speed is 1/(CSS * horizontal scanning period) */ + /* FIXME : 34000 is a value interpolated by observations */ + speedint = (int) (34000.0 / (float) speed); + /* Only the highest two decimal digits are valid */ + if (speedint > 100) + speedint = speedint / 10 * 10; + + GST_LOG (" Shutter speed : 1/%d", speedint); + } + break; + default: + gst_util_dump_mem (data + offs, 5); + break; + } + size -= 5; + offs += 5; } + return GST_FLOW_OK; +} - /* 0x23 : Timezone / Dailight Saving Time */ - /* 0x24 - 0x2a : Original time */ - if (data[0x23] != 0xff) { - GDate *date = NULL; - guint tzone = 0; - guint day, month, year, hour, min, sec; - gchar *datetime; - - tzone = data[0x23]; - dst = !(tzone & 0x80); - tzone = - BCD (tzone & 0x1f) > 12 ? BCD (tzone & 0x1f) - 12 : BCD (tzone & 0x1f); - GST_LOG_OBJECT (filter, "TimeZone : %d, DST : %d", tzone, dst); - - day = BCD_M (data[0x24], 0x3f); - month = BCD_M (data[0x25], 0x1f); - year = BCD (data[0x26]); - if (year > 90) - year += 1900; - else - year += 2000; - /* 0x27: ??? */ - sec = BCD_M (data[0x28], 0x7f); - min = BCD_M (data[0x29], 0x7f); - hour = BCD_M (data[0x2a], 0x3f); - - /* FIXME : we need a date/time object ! */ - date = g_date_new_dmy (day, month, year); - datetime = - g_strdup_printf ("%02d/%02d/%02d %02d:%02d:%02d", day, month, year, - hour, min, sec); - gst_structure_set (str, "date", GST_TYPE_DATE, date, "recording-time", - G_TYPE_STRING, datetime, NULL); - g_free (datetime); - GST_LOG_OBJECT (filter, datetime); +static GstFlowReturn +parse_video_frame (GstHDVParse * filter, guint8 * data, guint64 size) +{ + guint32 etn, bitrate; + guint8 nbframes, data_h, hdr_size, sfr, sdm; + guint8 aspect, framerate, profile, level, format, chroma; + guint8 gop_n, gop_m, cgms, recst, abst; + guint16 vbv_delay, width, height, vbv_buffer; + guint64 dts; + gboolean pf, tf, rf; + + GST_LOG_OBJECT (filter, "Video Frame Pack"); + + /* Byte | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | + * --------------------------------- + * 0 | Size (0x39) | + * --------------------------------- + * 1 | | + * 2 | ETN | + * 3 | | + * --------------------------------- + */ + + if (data[0] != 0x39) { + GST_WARNING ("Invalid size for Video frame"); + return GST_FLOW_ERROR; + } + etn = data[3] << 16 | data[2] << 8 | data[1]; + + GST_LOG_OBJECT (filter, " ETN : %" G_GUINT32_FORMAT, etn); + + /* Pack-V Information + * --------------------------------- + * 4 | Number of Video Frames | + * --------------------------------- + * 5 | 0 | 0 | 0 | 0 | DATA-H | + * --------------------------------- + * 6 | VBV | + * 7 | DELAY | + * --------------------------------- + * 8 | HEADER SIZE | + * --------------------------------- + * 9 | | + * 10 | DTS | + * 11 | | + * 12 | | + * ----------------------------- | + * 13 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | | + * --------------------------------- + * 14 |PF |TF |RF | 0 | SFR | + * --------------------------------- + */ + + nbframes = data[4]; + + if (VALIDATE && (data[5] >> 4)) + return GST_FLOW_ERROR; + data_h = data[5] & 0xf; + + vbv_delay = data[6] | data[7] << 8; + + hdr_size = data[8]; + + dts = data[9] | data[10] << 8 | data[11] << 16 | data[12] << 24; + dts |= (guint64) (data[13] & 0x1) << 32; + if (G_UNLIKELY (VALIDATE && (data[13] & 0xfe))) { + return GST_FLOW_ERROR; } - /* 0x2b : Various flags, including scene-change */ - if (!((data[0x2b] & 0x20) >> 5)) { - GST_LOG_OBJECT (filter, "Scene change !"); - gst_structure_set (str, "scene-change", G_TYPE_BOOLEAN, TRUE, NULL); + pf = data[14] & 0x80; + tf = data[14] & 0x40; + rf = data[14] & 0x20; + if (G_UNLIKELY (VALIDATE && (data[14] & 0x10))) + return GST_FLOW_ERROR; + + sfr = data[14] & 0x07; + + GST_LOG_OBJECT (filter, " Pack-V Information"); + GST_LOG_OBJECT (filter, " Number of Video Frames : %d", nbframes); + GST_LOG_OBJECT (filter, " Leading PES-V picture type %s (0x%x)", + (data_h == 0x1) ? "I-picture" : "other", data_h); + GST_LOG_OBJECT (filter, " VBV Delay of first frame: %" G_GUINT32_FORMAT, + vbv_delay); + GST_LOG_OBJECT (filter, " Header Size:%d", hdr_size); + GST_LOG_OBJECT (filter, " DTS: %" GST_TIME_FORMAT " (%" G_GUINT64_FORMAT ")", + GST_TIME_ARGS (MPEGTIME_TO_GSTTIME (dts)), dts); + GST_LOG_OBJECT (filter, " Video source : %s %s %s (0x%x 0x%x 0x%x)", + pf ? "Progressive" : "Interlaced", + tf ? "TFF" : "", rf ? "RFF" : "", pf, tf, rf); + GST_LOG_OBJECT (filter, " Source Frame Rate : %s (0x%x)", + sfr_to_framerate (sfr), sfr); + + /* Search Data Mode + * --------------------------------- + * 15 | Search Data Mode | + * --------------------------------- + */ + sdm = data[15]; + GST_LOG_OBJECT (filter, " Search Data Mode : 0x%x", sdm); + GST_LOG_OBJECT (filter, " %s %s %s", + sdm & 0x2 ? "8x-Base" : "", + sdm & 0x4 ? "8x-Helper" : "", sdm & 0x10 ? "24x" : ""); + + /* Video Mode + * --------------------------------- + * 16 | Horizontal size | + * ----------------- | + * 17 | 0 | 0 | 0 | 0 | | + * --------------------------------- + * 18 | Vertical size | + * ----------------- | + * 19 | 0 | 0 | 0 | 0 | | + * --------------------------------- + * 20 | Aspect ratio | Frame Rate | + * --------------------------------- + * 21 | | + * 22 | bitrate | + * ------------------------- | + * 23 | 0 | 0 | 0 | 0 | 0 | 0 | | + * --------------------------------- + * 24 | VBV Buffer size | + * ------------------------- | + * 25 | 0 | 0 | 0 | 0 | 0 | 0 | | + * --------------------------------- + * 26 | 0 | Profile | Level | + * --------------------------------- + * 27 | 0 | Format |Chroma | 0 | 0 | + * --------------------------------- + * 28 | GOP N | GOP M | + * --------------------------------- + */ + width = data[16] | (data[17] & 0xf) << 8; + height = data[18] | (data[19] & 0xf) << 8; + if (VALIDATE && ((data[17] & 0xf0) || data[19] & 0xf0)) + return GST_FLOW_ERROR; + aspect = data[20] >> 4; + framerate = data[20] & 0xf; + bitrate = data[21] | data[22] << 8 | (data[23] & 0x3) << 16; + if (VALIDATE && (data[23] & 0xfc)) + return GST_FLOW_ERROR; + vbv_buffer = data[24] | (data[25] & 0x3) << 8; + if (VALIDATE && (data[25] & 0xfc)) + return GST_FLOW_ERROR; + profile = (data[26] >> 4) & 0x7; + level = data[26] & 0xf; + format = (data[27] >> 4) & 0x7; + chroma = (data[27] >> 2) & 0x3; + gop_n = data[28] >> 3; + gop_m = data[28] & 0x7; + + GST_LOG_OBJECT (filter, " Video Mode"); + GST_LOG_OBJECT (filter, " width:%d, height:%d", width, height); + GST_LOG_OBJECT (filter, " Aspect Ratio : %s (0x%x)", + (aspect == 0x3) ? "16/9" : "RESERVED", aspect); + GST_LOG_OBJECT (filter, " Framerate: %s (0x%x)", + sfr_to_framerate (framerate), framerate); + GST_LOG_OBJECT (filter, " Bitrate: %d bit/s", bitrate * 400); + GST_LOG_OBJECT (filter, " VBV buffer Size : %d bits", + vbv_buffer * 16 * 1024); + GST_LOG_OBJECT (filter, " MPEG Profile : %s (0x%x)", + (profile == 0x4) ? "Main" : "RESERVED", profile); + GST_LOG_OBJECT (filter, " MPEG Level : %s (0x%x)", + (level == 0x6) ? "High-1440" : "RESERVED", level); + GST_LOG_OBJECT (filter, " Video format : %s (0x%x)", + (format == 0) ? "Component" : "Reserved", format); + GST_LOG_OBJECT (filter, " Chroma : %s (0x%x)", + (chroma == 0x1) ? "4:2:0" : "RESERVED", chroma); + GST_LOG_OBJECT (filter, " GOP N/M : %d / %d", gop_n, gop_m); + + + /* data availability + * --------------------------------- + * 29 | 0 | 0 | 0 | 0 | 0 |PE2|PE1|PE0| + * --------------------------------- + * PE0 : HD2 TTC is valid + * PE1 : REC DATE is valid + * PE2 : REC TIME is valid + */ + if (data[29] & 0x1) { + guint8 fr, sec, min, hr; + gboolean bf, df; + /* HD2 TTC + * --------------------------------- + * 30 |BF |DF |Tens Fr|Units of Frames| + * --------------------------------- + * 31 | 1 |Tens second|Units of Second| + * --------------------------------- + * 32 | 1 |Tens minute|Units of Minute| + * --------------------------------- + * 33 | 1 | 1 |Tens Hr|Units of Hours | + * --------------------------------- + */ + bf = data[30] >> 7; + df = (data[30] >> 6) & 0x1; + fr = BCD (data[30] & 0x3f); + sec = BCD (data[31] & 0x7f); + min = BCD (data[32] & 0x7f); + hr = BCD (data[33] & 0x3f); + GST_LOG_OBJECT (filter, " HD2 Title Time Code"); + GST_LOG_OBJECT (filter, " BF:%d, Drop Frame:%d", bf, df); + GST_LOG_OBJECT (filter, " Timecode %02d:%02d:%02d.%02d", hr, min, sec, fr); + /* FIXME : Use framerate information from above to convert to GstClockTime */ } + if (data[29] & 0x2) { + gboolean ds, tm; + guint8 tz, day, dow, month, year; + /* REC DATE + * --------------------------------- + * 34 |DS |TM |Tens TZ|Units of TimeZn| + * --------------------------------- + * 35 | 1 | 1 |Tens dy| Units of Days | + * --------------------------------- + * 36 | Week |TMN|Units of Months| + * --------------------------------- + * 37 | Tens of Years |Units of Years | + * --------------------------------- + */ + ds = data[32] >> 7; + tm = (data[32] >> 6) & 0x1; + tz = BCD (data[32] & 0x3f); + day = BCD (data[35] & 0x3f); + dow = data[36] >> 5; + month = BCD (data[36] & 0x1f); + year = BCD (data[37]); + + GST_LOG_OBJECT (filter, " REC DATE"); + GST_LOG_OBJECT (filter, " ds:%d, tm:%d", ds, tm); + GST_LOG_OBJECT (filter, " Timezone: %d", tz); + GST_LOG_OBJECT (filter, " Date: %d %02d/%02d/%04d", dow, day, month, year); + } + if (data[29] & 0x4) { + guint8 fr, sec, min, hr; + /* REC TIME + * --------------------------------- + * 38 | 1 | 1 |Tens Fr|Units of Frames| + * --------------------------------- + * 39 | 1 |Tens second|Units of Second| + * --------------------------------- + * 40 | 1 |Tens minute|Units of Minute| + * --------------------------------- + * 41 | 1 | 1 |Tens Hr|Units of Hours | + * --------------------------------- + */ + fr = BCD (data[38] & 0x3f); + sec = BCD (data[39] & 0x7f); + min = BCD (data[40] & 0x7f); + hr = BCD (data[41] & 0x3f); + GST_LOG_OBJECT (filter, " REC TIME %02d:%02d:%02d.%02d", hr, min, sec, fr); + } + + /* MISC + * --------------------------------- + * 42 | CGMS |REC|ABS| 0 | 0 | 0 | 0 | + * --------------------------------- + */ + cgms = data[42] >> 6; + recst = (data[42] >> 5) & 0x1; + abst = (data[42] >> 4) & 0x1; + + GST_LOG_OBJECT (filter, " CGMS:0x%x", cgms); + GST_LOG_OBJECT (filter, " Recording Start Point : %s", + (recst == 0) ? "PRESENT" : "ABSENT"); + GST_LOG_OBJECT (filter, " ABST : %s", + (abst == 0) ? "DISCONTINUITY" : "NO DISCONTINUITY"); + + /* Extended DV Pack #1 + * 43 - 47 + */ + GST_LOG_OBJECT (filter, " Extended DV Pack #1 : 0x%x", data[43]); + + /* Extended DV Pack #1 + * 48 - 52 + */ + GST_LOG_OBJECT (filter, " Extended DV Pack #2 : 0x%x", data[48]); + + /* Extended DV Pack #1 + * 53 - 57 + */ + GST_LOG_OBJECT (filter, " Extended DV Pack #3 : 0x%x", data[53]); - /* Check for partials */ - if (GST_BUFFER_SIZE (buf) < 0x50) { - goto beach; + return GST_FLOW_OK; + +} + +static GstFlowReturn +parse_audio_frame (GstHDVParse * filter, guint8 * data, guint64 size) +{ + guint32 etn; + guint8 nbmute, nbaau; + guint64 pts; + guint16 audio_comp; + guint8 bitrate, fs, compress, channel; + guint8 option, cgms; + gboolean acly, recst; + + GST_LOG_OBJECT (filter, "Audio Frame Pack"); + + /* Byte | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | + * --------------------------------- + * 0 | Size (0x0f) | + * --------------------------------- + * 1 | | + * 2 | ETN | + * 3 | | + * --------------------------------- + * 4 |Nb Audio Mute | Number of AAU | + * --------------------------------- + */ + + if (data[0] != 0x0f) { + GST_WARNING ("Invalid size for audio frame"); + return GST_FLOW_ERROR; + } + etn = data[3] << 16 | data[2] << 8 | data[1]; + + GST_LOG_OBJECT (filter, " ETN : %" G_GUINT32_FORMAT, etn); + + /* Pack-A Information + * --------------------------------- + * 4 |Nb Audio Mute | Number of AAU | + * --------------------------------- + * 5 | | + * 6 | PTS | + * 7 | | + * 8 | | + * ----------------------------- | + * 9 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | | + * --------------------------------- + * 10 | Audio | + * 11 | Compensation | + * --------------------------------- + */ + + /* Number of Audio Mute Frames */ + nbmute = data[4] >> 4; + /* Number of AAU */ + nbaau = data[4] & 0x0f; + /* PTS of the first AAU immediatly following */ + pts = (data[5] | data[6] << 8 | data[7] << 16 | data[8] << 24); + pts |= (guint64) (data[9] & 0x1) << 32; + if (G_UNLIKELY (VALIDATE && (data[9] & 0xfe))) { + return GST_FLOW_ERROR; } - /* 0x43 : Aperture */ - apertured = data[0x43] & 0x3f; - if (apertured < 35) { - GST_LOG_OBJECT (filter, "Aperture : F%s", aperture_table[apertured]); - gst_structure_set (str, "aperture", G_TYPE_STRING, - aperture_table[apertured], NULL); - } else { - GST_LOG_OBJECT (filter, "Aperture : %d", apertured); + /* Amount of compensation */ + audio_comp = data[10] | data[11] << 8; + + GST_LOG_OBJECT (filter, " Pack-A Information"); + GST_LOG_OBJECT (filter, " Nb Audio Mute Frames : %d", nbmute); + GST_LOG_OBJECT (filter, " Nb AAU : %d", nbaau); + GST_LOG_OBJECT (filter, + " PTS : %" GST_TIME_FORMAT " (%" G_GUINT64_FORMAT ")", + GST_TIME_ARGS (MPEGTIME_TO_GSTTIME (pts)), pts); + GST_LOG_OBJECT (filter, " Audio Compensation : %" G_GUINT32_FORMAT, + audio_comp); + + /* Audio Mode + * --------------------------------- + * 12 | Bitrate Index | 0 |Samplerate | + * --------------------------------- + * 13 | Compression | Channels | + * --------------------------------- + * 14 | X | Anciliary Option | + * --------------------------------- + * + * X : Anciliary data present + */ + + bitrate = data[12] >> 4; + fs = data[12] & 0x7; + if (G_UNLIKELY (VALIDATE && (data[12] & 0x08))) + return GST_FLOW_ERROR; + + compress = data[13] >> 4; + channel = data[13] & 0xf; + acly = data[14] & 0x80; + option = data[14] & 0x7f; + + GST_LOG_OBJECT (filter, " Audio Mode"); + GST_LOG_OBJECT (filter, " Bitrate : %s (0x%x)", + (bitrate == 0xe) ? "384kbps" : "RESERVED", bitrate); + GST_LOG_OBJECT (filter, " Samplerate : %s (0x%x)", + (fs == 0x1) ? "48 kHz" : "RESERVED", fs); + GST_LOG_OBJECT (filter, " Compression : %s (0x%x)", + (compress == 0x2) ? "MPEG-1 Layer II" : "RESERVED", compress); + GST_LOG_OBJECT (filter, " Channels : %s (0x%x)", + (channel == 0) ? "Stereo" : "RESERVED", channel); + GST_LOG_OBJECT (filter, " Anciliary data %s %s (0x%x)", + acly ? "PRESENT" : "ABSENT", + (option == 0xc) ? "IEC 13818-3" : "ABSENT/RESERVED", option); + /* + * --------------------------------- + * 15 | CGMS | R | 0 | 0 | 0 | 0 | 0 | + * --------------------------------- + * + * R : Recording Start Point + */ + + cgms = data[15] & 0xc0; + recst = data[15] & 0x20; + + GST_LOG_OBJECT (filter, " Misc"); + GST_LOG_OBJECT (filter, " CGMS : 0x%x", cgms); + GST_LOG_OBJECT (filter, " Recording Start Point %s", + (recst) ? "ABSENT" : "PRESENT"); + return GST_FLOW_OK; +} + +static GstFlowReturn +gst_hdvparse_parse (GstHDVParse * filter, GstBuffer * buf) +{ + GstFlowReturn res = GST_FLOW_OK; + guint8 *data = GST_BUFFER_DATA (buf); + guint64 offs = 0; + guint64 insize = GST_BUFFER_SIZE (buf); + + /* Byte | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | + * --------------------------------- + * 0 | 0 | KEYWORD | + * (1) | LENGTH | + * .... + * + * KEYWORD : + * 0x00 - 0x3F : Constant length (5 bytes) + * 0x40 - 0x7F : Variable length (LENGTH + 1) + * + * LENGTH : if present, size of fields 1-N + * + * Known keyword values: + * 0x00-0x07 : AUX-V + * 0x08-0x3E : RESERVED + * 0x3F : AUX-N NO-INFO + * 0x40-0x43 : AUX-A + * 0x44-0x47 : AUX-V + * 0x48-0x4F : AUX-N + * 0x50-0x53 : AUX-SYS + * 0x54-0x7E : RESERVED + * 0x7F : AUX-N NULL PACK + */ + + gst_util_dump_mem (data, insize); + + while (res == GST_FLOW_OK && (offs < insize)) { + guint8 kw = data[offs] & 0x7f; + guint8 size; + + /* Variable size packs */ + if (kw >= 0x40) { + size = data[offs + 1]; + } else + size = 4; + + /* Size validation */ + GST_DEBUG ("kw:0x%x, insize:%d, offs:%d, size:%d", kw, insize, offs, size); + if (insize < offs + size) + return GST_FLOW_ERROR; + + switch (kw) { + case 0x01: + GST_LOG ("BINARY GROUP"); + offs += size + 1; + break; + case 0x07: + GST_LOG ("ETN pack"); + break; + case 0x40: + GST_LOG ("Audio frame pack"); + res = parse_audio_frame (filter, data + offs + 1, size); + offs += size + 2; + break; + case 0x3f: + GST_LOG ("NO INFO pack"); + offs += size + 1; + break; + case 0x44: + GST_LOG ("Video frame pack"); + res = parse_video_frame (filter, data + offs + 1, size); + offs += size + 2; + break; + case 0x48: + case 0x49: + case 0x4A: + case 0x4B: + GST_LOG ("DV multi-pack"); + res = parse_dv_multi_pack (filter, data + offs + 1, size); + offs += size + 2; + break; + default: + GST_WARNING_OBJECT (filter, "Unknown AUX pack data of type 0x%x", kw); + res = GST_FLOW_ERROR; + } } - /* 0x44 : Gain */ - gain = ((data[0x44] & 0xf) - 1) * 1.5; - GST_LOG_OBJECT (filter, "Gain : %03f db", gain); - gst_structure_set (str, "gain", G_TYPE_FLOAT, gain, NULL); - - /* 0x4f - 0x50 : Shutter */ - shutter = get_shutter_speed (data[0x4f], data[0x50]); - GST_LOG_OBJECT (filter, "Shutter speed : 1/%d", shutter); - if (shutter) - gst_structure_set (str, "shutter-speed", GST_TYPE_FRACTION, 1, shutter, - NULL); - -beach: - msg = gst_message_new_element (GST_OBJECT (filter), str); - gst_element_post_message (GST_ELEMENT (filter), msg); - return; + return res; + } /* GstBaseTransform vmethod implementations */ @@ -334,9 +817,7 @@ gst_hdvparse_transform_ip (GstBaseTransform * base, GstBuffer * outbuf) { GstHDVParse *filter = GST_HDVPARSE (base); - gst_hdvparse_parse (filter, outbuf); - - return GST_FLOW_OK; + return gst_hdvparse_parse (filter, outbuf); } |