/* * GStreamer * Copyright (C) 2009 Edward Hervey * * 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 * * * Example launch line * * * gst-launch -v -m filesrc ! mpegtsdemux ! hdvparse ! fakesink silent=TRUE * * * */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #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 " }; 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/")