dvdemux: Parse SMPTE time codes
authorDavid Schleef <ds@schleef.org>
Fri, 4 Jun 2010 19:09:23 +0000 (12:09 -0700)
committerDavid Schleef <ds@schleef.org>
Sat, 4 Sep 2010 19:39:25 +0000 (12:39 -0700)
ext/dv/Makefile.am
ext/dv/gstdvdemux.c
ext/dv/gstsmptetimecode.h

index 928d475..e63154d 100644 (file)
@@ -1,6 +1,6 @@
 plugin_LTLIBRARIES = libgstdv.la
 
-libgstdv_la_SOURCES = gstdv.c gstdvdec.c gstdvdemux.c
+libgstdv_la_SOURCES = gstdv.c gstdvdec.c gstdvdemux.c gstsmptetimecode.c
 libgstdv_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(LIBDV_CFLAGS)
 libgstdv_la_LIBADD = \
        $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_MAJORMINOR) \
index 0308249..5261d47 100644 (file)
@@ -26,6 +26,7 @@
 
 #include <gst/audio/audio.h>
 #include "gstdvdemux.h"
+#include "gstsmptetimecode.h"
 
 /**
  * SECTION:element-dvdemux
@@ -1357,6 +1358,48 @@ gst_dvdemux_demux_video (GstDVDemux * dvdemux, GstBuffer * buffer,
   return ret;
 }
 
+static int
+get_ssyb_offset (int dif, int ssyb)
+{
+  int offset;
+
+  offset = dif * 12000;         /* to dif */
+  offset += 80 * (1 + (ssyb / 6));      /* to subcode pack */
+  offset += 3;                  /* past header */
+  offset += 8 * (ssyb % 6);     /* to ssyb */
+
+  return offset;
+}
+
+static gboolean
+gst_dvdemux_get_timecode (GstDVDemux * dvdemux, GstBuffer * buffer,
+    GstSMPTETimeCode * timecode)
+{
+  guint8 *data = GST_BUFFER_DATA (buffer);
+  int offset;
+  int dif;
+  int n_difs = dvdemux->decoder->num_dif_seqs;
+
+  for (dif = 0; dif < n_difs; dif++) {
+    offset = get_ssyb_offset (dif, 3);
+    if (data[offset + 3] == 0x13) {
+      timecode->frames = ((data[offset + 4] >> 4) & 0x3) * 10 +
+          (data[offset + 4] & 0xf);
+      timecode->seconds = ((data[offset + 5] >> 4) & 0x3) * 10 +
+          (data[offset + 5] & 0xf);
+      timecode->minutes = ((data[offset + 6] >> 4) & 0x3) * 10 +
+          (data[offset + 6] & 0xf);
+      timecode->hours = ((data[offset + 7] >> 4) & 0x3) * 10 +
+          (data[offset + 7] & 0xf);
+      GST_DEBUG ("got timecode %" GST_SMPTE_TIME_CODE_FORMAT,
+          GST_SMPTE_TIME_CODE_ARGS (timecode));
+      return TRUE;
+    }
+  }
+
+  return FALSE;
+}
+
 static gboolean
 gst_dvdemux_is_new_media (GstDVDemux * dvdemux, GstBuffer * buffer)
 {
@@ -1390,6 +1433,8 @@ gst_dvdemux_demux_frame (GstDVDemux * dvdemux, GstBuffer * buffer)
   GstFlowReturn aret, vret, ret;
   guint8 *data;
   guint64 duration;
+  GstSMPTETimeCode timecode;
+  int frame_number;
 
   if (G_UNLIKELY (dvdemux->need_segment)) {
     GstEvent *event;
@@ -1428,6 +1473,12 @@ gst_dvdemux_demux_frame (GstDVDemux * dvdemux, GstBuffer * buffer)
     dvdemux->need_segment = FALSE;
   }
 
+  gst_dvdemux_get_timecode (dvdemux, buffer, &timecode);
+  gst_smpte_time_code_get_frame_number (
+      (dvdemux->decoder->system == e_dv_system_625_50) ?
+      GST_SMPTE_TIME_CODE_SYSTEM_25 : GST_SMPTE_TIME_CODE_SYSTEM_30,
+      &frame_number, &timecode);
+
   next_ts = gst_util_uint64_scale_int (
       (dvdemux->frame_offset + 1) * GST_SECOND,
       dvdemux->framerate_denominator, dvdemux->framerate_numerator);
index 2f08c92..cdda03e 100644 (file)
@@ -50,6 +50,11 @@ struct _GstSMPTETimeCode {
 #define GST_SMPTE_TIME_CODE_SYSTEM_IS_VALID(x) \
   ((x) >= GST_SMPTE_TIME_CODE_SYSTEM_30 && (x) <= GST_SMPTE_TIME_CODE_SYSTEM_24)
 
+#define GST_SMPTE_TIME_CODE_FORMAT "02d:%02d:%02d:%02d"
+#define GST_SMPTE_TIME_CODE_ARGS(timecode) \
+  (timecode)->hours, (timecode)->minutes, \
+  (timecode)->seconds, (timecode)->frames
+
 gboolean gst_smpte_time_code_is_valid (GstSMPTETimeCodeSystem system,
     GstSMPTETimeCode *time_code);
 gboolean gst_smpte_time_code_from_frame_number (GstSMPTETimeCodeSystem system,