mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-11 18:05:37 +00:00
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.
This commit is contained in:
parent
6f88e17f67
commit
c4ef659ebd
1 changed files with 664 additions and 183 deletions
|
@ -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);
|
||||
|
||||
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;
|
||||
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);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
static inline const gchar *
|
||||
sfr_to_framerate (guint8 sfr)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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]);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
guint apertured, shutter;
|
||||
gfloat gain;
|
||||
gboolean dst = FALSE;
|
||||
GstStructure *str;
|
||||
GstMessage *msg;
|
||||
guint64 offs = 0;
|
||||
guint64 insize = GST_BUFFER_SIZE (buf);
|
||||
|
||||
GST_MEMDUMP_OBJECT (filter, "BUFFER", data, 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
|
||||
*/
|
||||
|
||||
str = gst_structure_empty_new ("HDV");
|
||||
gst_util_dump_mem (data, insize);
|
||||
|
||||
/* 0x1f - 0x23 : TimeCode */
|
||||
while (res == GST_FLOW_OK && (offs < insize)) {
|
||||
guint8 kw = data[offs] & 0x7f;
|
||||
guint8 size;
|
||||
|
||||
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);
|
||||
/* Variable size packs */
|
||||
if (kw >= 0x40) {
|
||||
size = data[offs + 1];
|
||||
} else
|
||||
size = 4;
|
||||
|
||||
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);
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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;
|
||||
return res;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/* Check for partials */
|
||||
if (GST_BUFFER_SIZE (buf) < 0x50) {
|
||||
goto beach;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue