summaryrefslogtreecommitdiff
path: root/gst/hdvparse
diff options
context:
space:
mode:
authorEdward Hervey <bilboed@bilboed.com>2009-06-05 10:47:41 +0200
committerEdward Hervey <bilboed@bilboed.com>2009-06-05 20:23:44 +0200
commitc4ef659ebd9b6360fe2c4e23374ba4484617fd8b (patch)
treec49cb3a84a76271b61334e6ded14bdfffe8bb749 /gst/hdvparse
parent6f88e17f67f44a89c122c95caf0f9baf9dfdbbfa (diff)
downloadgstreamer-plugins-bad-c4ef659ebd9b6360fe2c4e23374ba4484617fd8b.tar.gz
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.c849
1 files changed, 665 insertions, 184 deletions
diff --git a/gst/hdvparse/gsthdvparse.c b/gst/hdvparse/gsthdvparse.c
index 9914cfa22..733672474 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);
}