summaryrefslogtreecommitdiffstats
path: root/gst/hdvparse/gsthdvparse.c
diff options
context:
space:
mode:
Diffstat (limited to 'gst/hdvparse/gsthdvparse.c')
-rw-r--r--gst/hdvparse/gsthdvparse.c362
1 files changed, 362 insertions, 0 deletions
diff --git a/gst/hdvparse/gsthdvparse.c b/gst/hdvparse/gsthdvparse.c
new file mode 100644
index 00000000..9914cfa2
--- /dev/null
+++ b/gst/hdvparse/gsthdvparse.c
@@ -0,0 +1,362 @@
+/*
+ * GStreamer
+ * Copyright (C) 2009 Edward Hervey <bilboed@bilboed.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * SECTION:element-HDVParse
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * <para>
+ * <programlisting>
+ * gst-launch -v -m filesrc ! mpegtsdemux ! hdvparse ! fakesink silent=TRUE
+ * </programlisting>
+ * </para>
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include <gst/base/gstbasetransform.h>
+
+#include "gsthdvparse.h"
+
+GST_DEBUG_CATEGORY_STATIC (gst_hdvparse_debug);
+#define GST_CAT_DEFAULT gst_hdvparse_debug
+
+/* Filter signals and args */
+enum
+{
+ /* FILL ME */
+ LAST_SIGNAL
+};
+
+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}
+};
+
+/* 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.
+ */
+static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("private/hdv-a1")
+ );
+
+static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("private/hdv-a1,parsed=(boolean)True")
+ );
+
+/* debug category for fltering log messages
+ *
+ * exchange the string 'Template HDVParse' with your description
+ */
+#define DEBUG_INIT(bla) \
+ GST_DEBUG_CATEGORY_INIT (gst_hdvparse_debug, "hdvparse", 0, "HDV private stream parser");
+
+GST_BOILERPLATE_FULL (GstHDVParse, gst_hdvparse, GstBaseTransform,
+ GST_TYPE_BASE_TRANSFORM, DEBUG_INIT);
+
+static GstFlowReturn gst_hdvparse_transform_ip (GstBaseTransform * base,
+ GstBuffer * outbuf);
+
+/* GObject vmethod implementations */
+
+static void
+gst_hdvparse_base_init (gpointer klass)
+{
+ static GstElementDetails element_details = {
+ "HDVParser",
+ "Data/Parser",
+ "HDV private stream Parser",
+ "Edward Hervey <bilboed@bilboed.com>"
+ };
+ GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&src_template));
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&sink_template));
+ gst_element_class_set_details (element_class, &element_details);
+}
+
+/* initialize the HDVParse's class */
+static void
+gst_hdvparse_class_init (GstHDVParseClass * klass)
+{
+ GST_BASE_TRANSFORM_CLASS (klass)->transform_ip =
+ GST_DEBUG_FUNCPTR (gst_hdvparse_transform_ip);
+}
+
+/* initialize the new element
+ * initialize instance structure
+ */
+static void
+gst_hdvparse_init (GstHDVParse * filter, GstHDVParseClass * klass)
+{
+ GstBaseTransform *transform = GST_BASE_TRANSFORM (filter);
+
+ gst_base_transform_set_in_place (transform, TRUE);
+ gst_base_transform_set_passthrough (transform, TRUE);
+}
+
+static guint
+get_shutter_speed (guint8 vala, guint8 valb)
+{
+ guint i;
+
+ 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;
+}
+
+static void
+gst_hdvparse_parse (GstHDVParse * filter, GstBuffer * buf)
+{
+ 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);
+ }
+
+ /* 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);
+ }
+
+ /* 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 */
+
+static GstFlowReturn
+gst_hdvparse_transform_ip (GstBaseTransform * base, GstBuffer * outbuf)
+{
+ GstHDVParse *filter = GST_HDVPARSE (base);
+
+ gst_hdvparse_parse (filter, outbuf);
+
+ return GST_FLOW_OK;
+}
+
+
+/* entry point to initialize the plug-in
+ * initialize the plug-in itself
+ * register the element factories and other features
+ */
+static gboolean
+HDVParse_init (GstPlugin * HDVParse)
+{
+ return gst_element_register (HDVParse, "hdvparse", GST_RANK_NONE,
+ GST_TYPE_HDVPARSE);
+}
+
+/* gstreamer looks for this structure to register HDVParses
+ *
+ * exchange the string 'Template HDVParse' with you HDVParse description
+ */
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ "hdvparse",
+ "HDV private stream parser",
+ HDVParse_init, VERSION, "LGPL", "GStreamer", "http://gstreamer.net/")