dv: port to 0.11

This commit is contained in:
Mark Nauwelaerts 2012-02-06 22:13:53 +01:00
parent 92a0c01732
commit 9be8a6f48c
6 changed files with 369 additions and 366 deletions

View file

@ -314,7 +314,7 @@ dnl Make sure you have a space before and after all plugins
GST_PLUGINS_NONPORTED="deinterlace interleave flx goom2k1 \
imagefreeze interleave monoscope smpte \
videobox \
cairo cairo_gobject dv1394 gdk_pixbuf libdv \
cairo cairo_gobject dv1394 gdk_pixbuf \
oss oss4 shout2 \
wavpack \
osx_video osx_audio "

View file

@ -3,8 +3,8 @@ plugin_LTLIBRARIES = libgstdv.la
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) \
$(GST_BASE_LIBS) $(GST_LIBS) $(LIBDV_LIBS)
$(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_MAJORMINOR) -lgstvideo-$(GST_MAJORMINOR) \
$(GST_BASE_LIBS) $(GST_LIBS) $(LIBDV_LIBS)
libgstdv_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgstdv_la_LIBTOOLFLAGS = --tag=disable-static

View file

@ -44,6 +44,7 @@
#include <string.h>
#include <math.h>
#include <gst/video/video.h>
#include <gst/video/gstvideopool.h>
#include "gstdvdec.h"
@ -101,27 +102,10 @@ static GstStaticPadTemplate sink_temp = GST_STATIC_PAD_TEMPLATE ("sink",
static GstStaticPadTemplate src_temp = GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("video/x-raw-yuv, "
"format = (fourcc) YUY2, "
"width = (int) 720, "
"framerate = (fraction) [ 1/1, 60/1 ];"
"video/x-raw-rgb, "
"bpp = (int) 32, "
"depth = (int) 24, "
"endianness = (int) " G_STRINGIFY (G_BIG_ENDIAN) ", "
"red_mask = (int) 0x0000ff00, "
"green_mask = (int) 0x00ff0000, "
"blue_mask = (int) 0xff000000, "
"width = (int) 720, "
"framerate = (fraction) [ 1/1, 60/1 ];"
"video/x-raw-rgb, "
"bpp = (int) 24, "
"depth = (int) 24, "
"endianness = (int) " G_STRINGIFY (G_BIG_ENDIAN) ", "
"red_mask = (int) 0x00ff0000, "
"green_mask = (int) 0x0000ff00, "
"blue_mask = (int) 0x000000ff, "
"width = (int) 720, " "framerate = (fraction) [ 1/1, 60/1 ]")
GST_STATIC_CAPS ("video/x-raw, "
"format = (string) { YUY2, BGRx, RGB }, "
"framerate = (fraction) [ 1/1, 60/1 ], "
"width = (int) 720, " "height = (int) { 576, 480 }")
);
#define GST_TYPE_DVDEC_QUALITY (gst_dvdec_quality_get_type())
@ -146,12 +130,13 @@ gst_dvdec_quality_get_type (void)
return qtype;
}
GST_BOILERPLATE (GstDVDec, gst_dvdec, GstElement, GST_TYPE_ELEMENT);
#define gst_dvdec_parent_class parent_class
G_DEFINE_TYPE (GstDVDec, gst_dvdec, GST_TYPE_ELEMENT);
static void gst_dvdec_finalize (GObject * object);
static gboolean gst_dvdec_sink_setcaps (GstPad * pad, GstCaps * caps);
static GstFlowReturn gst_dvdec_chain (GstPad * pad, GstBuffer * buffer);
static gboolean gst_dvdec_sink_event (GstPad * pad, GstEvent * event);
static GstFlowReturn gst_dvdec_chain (GstPad * pad, GstObject * parent,
GstBuffer * buffer);
static gboolean gst_dvdec_sink_event (GstPad * pad, GstObject * parent,
GstEvent * event);
static GstStateChangeReturn gst_dvdec_change_state (GstElement * element,
GstStateChange transition);
@ -161,24 +146,6 @@ static void gst_dvdec_set_property (GObject * object, guint prop_id,
static void gst_dvdec_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void
gst_dvdec_base_init (gpointer g_class)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&sink_temp));
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&src_temp));
gst_element_class_set_details_simple (element_class, "DV video decoder",
"Codec/Decoder/Video",
"Uses libdv to decode DV video (smpte314) (libdv.sourceforge.net)",
"Erik Walthinsen <omega@cse.ogi.edu>," "Wim Taymans <wim@fluendo.com>");
GST_DEBUG_CATEGORY_INIT (dvdec_debug, "dvdec", 0, "DV decoding element");
}
static void
gst_dvdec_class_init (GstDVDecClass * klass)
{
@ -188,7 +155,6 @@ gst_dvdec_class_init (GstDVDecClass * klass)
gobject_class = (GObjectClass *) klass;
gstelement_class = (GstElementClass *) klass;
gobject_class->finalize = gst_dvdec_finalize;
gobject_class->set_property = gst_dvdec_set_property;
gobject_class->get_property = gst_dvdec_get_property;
@ -207,15 +173,25 @@ gst_dvdec_class_init (GstDVDecClass * klass)
1, G_MAXINT, DV_DEFAULT_DECODE_NTH,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
gstelement_class->change_state = gst_dvdec_change_state;
gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_dvdec_change_state);
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&sink_temp));
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&src_temp));
gst_element_class_set_details_simple (gstelement_class, "DV video decoder",
"Codec/Decoder/Video",
"Uses libdv to decode DV video (smpte314) (libdv.sourceforge.net)",
"Erik Walthinsen <omega@cse.ogi.edu>," "Wim Taymans <wim@fluendo.com>");
GST_DEBUG_CATEGORY_INIT (dvdec_debug, "dvdec", 0, "DV decoding element");
}
static void
gst_dvdec_init (GstDVDec * dvdec, GstDVDecClass * g_class)
gst_dvdec_init (GstDVDec * dvdec)
{
dvdec->sinkpad = gst_pad_new_from_static_template (&sink_temp, "sink");
gst_pad_set_setcaps_function (dvdec->sinkpad,
GST_DEBUG_FUNCPTR (gst_dvdec_sink_setcaps));
gst_pad_set_chain_function (dvdec->sinkpad, gst_dvdec_chain);
gst_pad_set_event_function (dvdec->sinkpad, gst_dvdec_sink_event);
gst_element_add_pad (GST_ELEMENT (dvdec), dvdec->sinkpad);
@ -232,28 +208,14 @@ gst_dvdec_init (GstDVDec * dvdec, GstDVDecClass * g_class)
dvdec->clamp_luma = FALSE;
dvdec->clamp_chroma = FALSE;
dvdec->quality = DV_DEFAULT_QUALITY;
dvdec->segment = gst_segment_new ();
}
static void
gst_dvdec_finalize (GObject * object)
{
GstDVDec *dvdec = GST_DVDEC (object);
gst_segment_free (dvdec->segment);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static gboolean
gst_dvdec_sink_setcaps (GstPad * pad, GstCaps * caps)
gst_dvdec_sink_setcaps (GstDVDec * dvdec, GstCaps * caps)
{
GstDVDec *dvdec;
GstStructure *s;
const GValue *par = NULL, *rate = NULL;
dvdec = GST_DVDEC (gst_pad_get_parent (pad));
/* first parse the caps */
s = gst_caps_get_structure (caps, 0);
@ -276,19 +238,64 @@ gst_dvdec_sink_setcaps (GstPad * pad, GstCaps * caps)
dvdec->sink_negotiated = TRUE;
dvdec->src_negotiated = FALSE;
gst_object_unref (dvdec);
return TRUE;
/* ERRORS */
no_framerate:
{
GST_DEBUG_OBJECT (dvdec, "no framerate specified in caps");
gst_object_unref (dvdec);
return FALSE;
}
}
static void
gst_dvdec_negotiate_pool (GstDVDec * dec, GstCaps * caps, GstVideoInfo * info)
{
GstQuery *query;
GstBufferPool *pool = NULL;
guint size, min, max, prefix, alignment;
GstStructure *config;
/* find a pool for the negotiated caps now */
query = gst_query_new_allocation (caps, TRUE);
if (gst_pad_peer_query (dec->srcpad, query)) {
GST_DEBUG_OBJECT (dec, "got downstream ALLOCATION hints");
/* we got configuration from our peer, parse them */
gst_query_parse_allocation_params (query, &size, &min, &max, &prefix,
&alignment, &pool);
size = MAX (size, info->size);
} else {
GST_DEBUG_OBJECT (dec, "didn't get downstream ALLOCATION hints");
size = info->size;
min = max = 0;
prefix = 0;
alignment = 0;
}
if (pool == NULL) {
/* we did not get a pool, make one ourselves then */
pool = gst_buffer_pool_new ();
}
if (dec->pool)
gst_object_unref (dec->pool);
dec->pool = pool;
config = gst_buffer_pool_get_config (pool);
gst_buffer_pool_config_set (config, caps, size, min, max, prefix, alignment);
/* just set the option, if the pool can support it we will transparently use
* it through the video info API. We could also see if the pool support this
* option and only activate it then. */
gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
gst_buffer_pool_set_config (pool, config);
/* and activate */
gst_buffer_pool_set_active (pool, TRUE);
gst_query_unref (query);
}
static gboolean
gst_dvdec_src_negotiate (GstDVDec * dvdec)
{
@ -320,16 +327,24 @@ gst_dvdec_src_negotiate (GstDVDec * dvdec)
/* ignoring rgb, bgr0 for now */
dvdec->bpp = 2;
othercaps = gst_caps_new_simple ("video/x-raw-yuv",
"format", GST_TYPE_FOURCC, GST_STR_FOURCC ("YUY2"),
"width", G_TYPE_INT, 720,
"height", G_TYPE_INT, dvdec->height,
"framerate", GST_TYPE_FRACTION, dvdec->framerate_numerator,
dvdec->framerate_denominator,
"pixel-aspect-ratio", GST_TYPE_FRACTION, dvdec->par_x,
dvdec->par_y, "interlaced", G_TYPE_BOOLEAN, dvdec->interlaced, NULL);
gst_video_info_set_format (&dvdec->vinfo, GST_VIDEO_FORMAT_YUY2,
720, dvdec->height);
dvdec->vinfo.fps_n = dvdec->framerate_numerator;
dvdec->vinfo.fps_d = dvdec->framerate_denominator;
dvdec->vinfo.par_n = dvdec->par_x;
dvdec->vinfo.par_d = dvdec->par_y;
if (dvdec->interlaced) {
dvdec->vinfo.interlace_mode = GST_VIDEO_INTERLACE_MODE_INTERLEAVED;
dvdec->vinfo.flags |= GST_VIDEO_FLAG_INTERLACED;
} else {
dvdec->vinfo.interlace_mode = GST_VIDEO_INTERLACE_MODE_PROGRESSIVE;
dvdec->vinfo.flags &= GST_VIDEO_FLAG_INTERLACED;
}
othercaps = gst_video_info_to_caps (&dvdec->vinfo);
gst_pad_set_caps (dvdec->srcpad, othercaps);
gst_dvdec_negotiate_pool (dvdec, othercaps, &dvdec->vinfo);
gst_caps_unref (othercaps);
dvdec->src_negotiated = TRUE;
@ -338,69 +353,77 @@ gst_dvdec_src_negotiate (GstDVDec * dvdec)
}
static gboolean
gst_dvdec_sink_event (GstPad * pad, GstEvent * event)
gst_dvdec_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
{
GstDVDec *dvdec;
gboolean res = TRUE;
dvdec = GST_DVDEC (gst_pad_get_parent (pad));
dvdec = GST_DVDEC (parent);
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_FLUSH_STOP:
gst_segment_init (dvdec->segment, GST_FORMAT_UNDEFINED);
gst_segment_init (&dvdec->segment, GST_FORMAT_UNDEFINED);
break;
case GST_EVENT_NEWSEGMENT:{
gboolean update;
gdouble rate, applied_rate;
GstFormat format;
gint64 start, stop, position;
case GST_EVENT_SEGMENT:{
const GstSegment *segment;
gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate,
&format, &start, &stop, &position);
gst_event_parse_segment (event, &segment);
GST_DEBUG_OBJECT (dvdec, "Got NEWSEGMENT [%" GST_TIME_FORMAT
" - %" GST_TIME_FORMAT " / %" GST_TIME_FORMAT "]",
GST_TIME_ARGS (start), GST_TIME_ARGS (stop),
GST_TIME_ARGS (position));
GST_DEBUG_OBJECT (dvdec, "Got NEWSEGMENT %" GST_SEGMENT_FORMAT, &segment);
gst_segment_set_newsegment_full (dvdec->segment, update, rate,
applied_rate, format, start, stop, position);
gst_segment_copy_into (segment, &dvdec->segment);
break;
}
case GST_EVENT_CAPS:
{
GstCaps *caps;
gst_event_parse_caps (event, &caps);
gst_dvdec_sink_setcaps (dvdec, caps);
gst_event_unref (event);
event = NULL;
res = TRUE;
break;
}
default:
break;
}
res = gst_pad_push_event (dvdec->srcpad, event);
if (event)
res = gst_pad_push_event (dvdec->srcpad, event);
return res;
}
static GstFlowReturn
gst_dvdec_chain (GstPad * pad, GstBuffer * buf)
gst_dvdec_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
{
GstDVDec *dvdec;
guint8 *inframe;
guint8 *outframe;
guint8 *outframe_ptrs[3];
gint outframe_pitches[3];
GstMapInfo map;
GstVideoFrame frame;
GstBuffer *outbuf;
GstFlowReturn ret = GST_FLOW_OK;
guint length;
gint64 cstart, cstop;
guint64 cstart, cstop;
gboolean PAL, wide;
dvdec = GST_DVDEC (gst_pad_get_parent (pad));
inframe = GST_BUFFER_DATA (buf);
dvdec = GST_DVDEC (parent);
gst_buffer_map (buf, &map, GST_MAP_READ);
inframe = map.data;
/* buffer should be at least the size of one NTSC frame, this should
* be enough to decode the header. */
if (G_UNLIKELY (GST_BUFFER_SIZE (buf) < NTSC_BUFFER))
if (G_UNLIKELY (map.size < NTSC_BUFFER))
goto wrong_size;
/* preliminary dropping. unref and return if outside of configured segment */
if ((dvdec->segment->format == GST_FORMAT_TIME) &&
(!(gst_segment_clip (dvdec->segment, GST_FORMAT_TIME,
if ((dvdec->segment.format == GST_FORMAT_TIME) &&
(!(gst_segment_clip (&dvdec->segment, GST_FORMAT_TIME,
GST_BUFFER_TIMESTAMP (buf),
GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf),
&cstart, &cstop))))
@ -416,7 +439,7 @@ gst_dvdec_chain (GstPad * pad, GstBuffer * buf)
/* check the buffer is of right size after we know if we are
* dealing with PAL or NTSC */
length = (PAL ? PAL_BUFFER : NTSC_BUFFER);
if (G_UNLIKELY (GST_BUFFER_SIZE (buf) < length))
if (G_UNLIKELY (map.size < length))
goto wrong_size;
dv_parse_packs (dvdec->decoder, inframe);
@ -441,32 +464,39 @@ gst_dvdec_chain (GstPad * pad, GstBuffer * buf)
goto not_negotiated;
}
ret =
gst_pad_alloc_buffer_and_set_caps (dvdec->srcpad, 0,
(720 * dvdec->height) * dvdec->bpp,
GST_PAD_CAPS (dvdec->srcpad), &outbuf);
if (gst_pad_check_reconfigure (dvdec->srcpad)) {
GstCaps *caps;
caps = gst_pad_get_current_caps (dvdec->srcpad);
gst_dvdec_negotiate_pool (dvdec, caps, &dvdec->vinfo);
gst_caps_unref (caps);
}
ret = gst_buffer_pool_acquire_buffer (dvdec->pool, &outbuf, NULL);
if (G_UNLIKELY (ret != GST_FLOW_OK))
goto no_buffer;
outframe = GST_BUFFER_DATA (outbuf);
gst_video_frame_map (&frame, &dvdec->vinfo, outbuf, GST_MAP_WRITE);
outframe_ptrs[0] = outframe;
outframe_pitches[0] = 720 * dvdec->bpp;
outframe_ptrs[0] = GST_VIDEO_FRAME_COMP_DATA (&frame, 0);
outframe_pitches[0] = GST_VIDEO_FRAME_COMP_STRIDE (&frame, 0);
/* the rest only matters for YUY2 */
if (dvdec->bpp < 3) {
outframe_ptrs[1] = outframe_ptrs[0] + 720 * dvdec->height;
outframe_ptrs[2] = outframe_ptrs[1] + 360 * dvdec->height;
outframe_ptrs[1] = GST_VIDEO_FRAME_COMP_DATA (&frame, 1);
outframe_ptrs[2] = GST_VIDEO_FRAME_COMP_DATA (&frame, 2);
outframe_pitches[1] = dvdec->height / 2;
outframe_pitches[2] = outframe_pitches[1];
outframe_pitches[1] = GST_VIDEO_FRAME_COMP_STRIDE (&frame, 1);
outframe_pitches[2] = GST_VIDEO_FRAME_COMP_STRIDE (&frame, 2);
}
GST_DEBUG_OBJECT (dvdec, "decoding and pushing buffer");
dv_decode_full_frame (dvdec->decoder, inframe,
e_dv_color_yuv, outframe_ptrs, outframe_pitches);
GST_BUFFER_FLAG_UNSET (outbuf, GST_VIDEO_BUFFER_TFF);
gst_video_frame_unmap (&frame);
GST_BUFFER_FLAG_UNSET (outbuf, GST_VIDEO_BUFFER_FLAG_TFF);
GST_BUFFER_OFFSET (outbuf) = GST_BUFFER_OFFSET (buf);
GST_BUFFER_OFFSET_END (outbuf) = GST_BUFFER_OFFSET_END (buf);
@ -479,8 +509,8 @@ skip:
dvdec->video_offset++;
done:
gst_buffer_unmap (buf, &map);
gst_buffer_unref (buf);
gst_object_unref (dvdec);
return ret;
@ -534,7 +564,8 @@ gst_dvdec_change_state (GstElement * element, GstStateChange transition)
dv_decoder_new (0, dvdec->clamp_luma, dvdec->clamp_chroma);
dvdec->decoder->quality = qualities[dvdec->quality];
dv_set_error_log (dvdec->decoder, NULL);
gst_segment_init (dvdec->segment, GST_FORMAT_UNDEFINED);
gst_video_info_init (&dvdec->vinfo);
gst_segment_init (&dvdec->segment, GST_FORMAT_UNDEFINED);
dvdec->src_negotiated = FALSE;
dvdec->sink_negotiated = FALSE;
/*
@ -549,7 +580,7 @@ gst_dvdec_change_state (GstElement * element, GstStateChange transition)
break;
}
ret = parent_class->change_state (element, transition);
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
switch (transition) {
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
@ -557,6 +588,11 @@ gst_dvdec_change_state (GstElement * element, GstStateChange transition)
case GST_STATE_CHANGE_PAUSED_TO_READY:
dv_decoder_free (dvdec->decoder);
dvdec->decoder = NULL;
if (dvdec->pool) {
gst_buffer_pool_set_active (dvdec->pool, FALSE);
gst_object_unref (dvdec->pool);
dvdec->pool = NULL;
}
break;
case GST_STATE_CHANGE_READY_TO_NULL:
break;

View file

@ -23,6 +23,8 @@
#include <gst/gst.h>
#include <gst/video/video.h>
#include <libdv/dv.h>
@ -63,6 +65,7 @@ struct _GstDVDec {
/* input caps */
gboolean sink_negotiated;
GstVideoInfo vinfo;
gint framerate_numerator;
gint framerate_denominator;
gint height;
@ -78,7 +81,8 @@ struct _GstDVDec {
gint video_offset;
gint drop_factor;
GstSegment *segment;
GstBufferPool *pool;
GstSegment segment;
};
struct _GstDVDecClass {

View file

@ -123,25 +123,23 @@ static GstStaticPadTemplate video_src_temp = GST_STATIC_PAD_TEMPLATE ("video",
static GstStaticPadTemplate audio_src_temp = GST_STATIC_PAD_TEMPLATE ("audio",
GST_PAD_SRC,
GST_PAD_SOMETIMES,
GST_STATIC_CAPS ("audio/x-raw-int, "
"depth = (int) 16, "
"width = (int) 16, "
"signed = (boolean) TRUE, "
"channels = (int) {2, 4}, "
"endianness = (int) " G_STRINGIFY (G_BYTE_ORDER) ", "
"rate = (int) { 32000, 44100, 48000 }")
GST_STATIC_CAPS ("audio/x-raw, "
"format = (string) " GST_AUDIO_NE (S16) ", "
"layout = (string) interleaved, "
"rate = (int) { 32000, 44100, 48000 }, " "channels = (int) {2, 4}")
);
GST_BOILERPLATE (GstDVDemux, gst_dvdemux, GstElement, GST_TYPE_ELEMENT);
#define gst_dvdemux_parent_class parent_class
G_DEFINE_TYPE (GstDVDemux, gst_dvdemux, GST_TYPE_ELEMENT);
static void gst_dvdemux_finalize (GObject * object);
/* query functions */
static const GstQueryType *gst_dvdemux_get_src_query_types (GstPad * pad);
static gboolean gst_dvdemux_src_query (GstPad * pad, GstQuery * query);
static const GstQueryType *gst_dvdemux_get_sink_query_types (GstPad * pad);
static gboolean gst_dvdemux_sink_query (GstPad * pad, GstQuery * query);
static gboolean gst_dvdemux_src_query (GstPad * pad, GstObject * parent,
GstQuery * query);
static gboolean gst_dvdemux_sink_query (GstPad * pad, GstObject * parent,
GstQuery * query);
/* convert functions */
static gboolean gst_dvdemux_sink_convert (GstDVDemux * demux,
@ -153,43 +151,25 @@ static gboolean gst_dvdemux_src_convert (GstDVDemux * demux, GstPad * pad,
/* event functions */
static gboolean gst_dvdemux_send_event (GstElement * element, GstEvent * event);
static gboolean gst_dvdemux_handle_src_event (GstPad * pad, GstEvent * event);
static gboolean gst_dvdemux_handle_sink_event (GstPad * pad, GstEvent * event);
static gboolean gst_dvdemux_handle_src_event (GstPad * pad, GstObject * parent,
GstEvent * event);
static gboolean gst_dvdemux_handle_sink_event (GstPad * pad, GstObject * parent,
GstEvent * event);
/* scheduling functions */
static void gst_dvdemux_loop (GstPad * pad);
static GstFlowReturn gst_dvdemux_flush (GstDVDemux * dvdemux);
static GstFlowReturn gst_dvdemux_chain (GstPad * pad, GstBuffer * buffer);
static GstFlowReturn gst_dvdemux_chain (GstPad * pad, GstObject * parent,
GstBuffer * buffer);
/* state change functions */
static gboolean gst_dvdemux_sink_activate (GstPad * sinkpad);
static gboolean gst_dvdemux_sink_activate_push (GstPad * sinkpad,
gboolean active);
static gboolean gst_dvdemux_sink_activate_pull (GstPad * sinkpad,
gboolean active);
static gboolean gst_dvdemux_sink_activate (GstPad * sinkpad,
GstObject * parent);
static gboolean gst_dvdemux_sink_activate_mode (GstPad * sinkpad,
GstObject * parent, GstPadMode mode, gboolean active);
static GstStateChangeReturn gst_dvdemux_change_state (GstElement * element,
GstStateChange transition);
static void
gst_dvdemux_base_init (gpointer g_class)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&sink_temp));
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&video_src_temp));
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&audio_src_temp));
gst_element_class_set_details_simple (element_class,
"DV system stream demuxer", "Codec/Demuxer",
"Uses libdv to separate DV audio from DV video (libdv.sourceforge.net)",
"Erik Walthinsen <omega@cse.ogi.edu>, Wim Taymans <wim@fluendo.com>");
GST_DEBUG_CATEGORY_INIT (dvdemux_debug, "dvdemux", 0, "DV demuxer element");
}
static void
gst_dvdemux_class_init (GstDVDemuxClass * klass)
{
@ -203,10 +183,24 @@ gst_dvdemux_class_init (GstDVDemuxClass * klass)
gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_dvdemux_change_state);
gstelement_class->send_event = GST_DEBUG_FUNCPTR (gst_dvdemux_send_event);
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&sink_temp));
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&video_src_temp));
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&audio_src_temp));
gst_element_class_set_details_simple (gstelement_class,
"DV system stream demuxer", "Codec/Demuxer",
"Uses libdv to separate DV audio from DV video (libdv.sourceforge.net)",
"Erik Walthinsen <omega@cse.ogi.edu>, Wim Taymans <wim@fluendo.com>");
GST_DEBUG_CATEGORY_INIT (dvdemux_debug, "dvdemux", 0, "DV demuxer element");
}
static void
gst_dvdemux_init (GstDVDemux * dvdemux, GstDVDemuxClass * g_class)
gst_dvdemux_init (GstDVDemux * dvdemux)
{
gint i;
@ -216,11 +210,8 @@ gst_dvdemux_init (GstDVDemux * dvdemux, GstDVDemuxClass * g_class)
gst_pad_set_activate_function (dvdemux->sinkpad,
GST_DEBUG_FUNCPTR (gst_dvdemux_sink_activate));
/* the function to activate in push mode */
gst_pad_set_activatepush_function (dvdemux->sinkpad,
GST_DEBUG_FUNCPTR (gst_dvdemux_sink_activate_push));
/* the function to activate in pull mode */
gst_pad_set_activatepull_function (dvdemux->sinkpad,
GST_DEBUG_FUNCPTR (gst_dvdemux_sink_activate_pull));
gst_pad_set_activatemode_function (dvdemux->sinkpad,
GST_DEBUG_FUNCPTR (gst_dvdemux_sink_activate_mode));
/* for push mode, this is the chain function */
gst_pad_set_chain_function (dvdemux->sinkpad,
GST_DEBUG_FUNCPTR (gst_dvdemux_chain));
@ -230,8 +221,6 @@ gst_dvdemux_init (GstDVDemux * dvdemux, GstDVDemuxClass * g_class)
/* query functions */
gst_pad_set_query_function (dvdemux->sinkpad,
GST_DEBUG_FUNCPTR (gst_dvdemux_sink_query));
gst_pad_set_query_type_function (dvdemux->sinkpad,
GST_DEBUG_FUNCPTR (gst_dvdemux_get_sink_query_types));
/* now add the pad */
gst_element_add_pad (GST_ELEMENT (dvdemux), dvdemux->sinkpad);
@ -296,8 +285,6 @@ gst_dvdemux_add_pad (GstDVDemux * dvdemux, GstStaticPadTemplate * template)
gst_pad_set_query_function (pad, GST_DEBUG_FUNCPTR (gst_dvdemux_src_query));
gst_pad_set_query_type_function (pad,
GST_DEBUG_FUNCPTR (gst_dvdemux_get_src_query_types));
gst_pad_set_event_function (pad,
GST_DEBUG_FUNCPTR (gst_dvdemux_handle_src_event));
gst_pad_use_fixed_caps (pad);
@ -311,14 +298,12 @@ gst_dvdemux_add_pad (GstDVDemux * dvdemux, GstStaticPadTemplate * template)
if (no_more_pads)
gst_element_no_more_pads (GST_ELEMENT (dvdemux));
gst_pad_push_event (pad, gst_event_new_new_segment (FALSE,
dvdemux->byte_segment.rate, GST_FORMAT_TIME,
dvdemux->time_segment.start, dvdemux->time_segment.stop,
dvdemux->time_segment.start));
gst_pad_push_event (pad, gst_event_new_segment (&dvdemux->time_segment));
if (no_more_pads) {
gst_element_found_tags (GST_ELEMENT (dvdemux),
gst_tag_list_new_full (GST_TAG_CONTAINER_FORMAT, "DV", NULL));
gst_pad_push_event (pad,
gst_event_new_tag (gst_tag_list_new (GST_TAG_CONTAINER_FORMAT, "DV",
NULL)));
}
return pad;
@ -532,26 +517,13 @@ error:
}
}
static const GstQueryType *
gst_dvdemux_get_src_query_types (GstPad * pad)
{
static const GstQueryType src_query_types[] = {
GST_QUERY_POSITION,
GST_QUERY_DURATION,
GST_QUERY_CONVERT,
0
};
return src_query_types;
}
static gboolean
gst_dvdemux_src_query (GstPad * pad, GstQuery * query)
gst_dvdemux_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
{
gboolean res = TRUE;
GstDVDemux *dvdemux;
dvdemux = GST_DVDEMUX (gst_pad_get_parent (pad));
dvdemux = GST_DVDEMUX (parent);
switch (GST_QUERY_TYPE (query)) {
case GST_QUERY_POSITION:
@ -564,7 +536,7 @@ gst_dvdemux_src_query (GstPad * pad, GstQuery * query)
/* bring the position to the requested format. */
if (!(res = gst_dvdemux_src_convert (dvdemux, pad,
GST_FORMAT_TIME, dvdemux->time_segment.last_stop,
GST_FORMAT_TIME, dvdemux->time_segment.position,
&format, &cur)))
goto error;
gst_query_set_position (query, format, cur);
@ -618,40 +590,27 @@ gst_dvdemux_src_query (GstPad * pad, GstQuery * query)
break;
}
default:
res = gst_pad_query_default (pad, query);
res = gst_pad_query_default (pad, parent, query);
break;
}
gst_object_unref (dvdemux);
return res;
/* ERRORS */
error:
{
gst_object_unref (dvdemux);
GST_DEBUG ("error source query");
return FALSE;
}
}
static const GstQueryType *
gst_dvdemux_get_sink_query_types (GstPad * pad)
{
static const GstQueryType sink_query_types[] = {
GST_QUERY_CONVERT,
0
};
return sink_query_types;
}
static gboolean
gst_dvdemux_sink_query (GstPad * pad, GstQuery * query)
gst_dvdemux_sink_query (GstPad * pad, GstObject * parent, GstQuery * query)
{
gboolean res = TRUE;
GstDVDemux *dvdemux;
dvdemux = GST_DVDEMUX (gst_pad_get_parent (pad));
dvdemux = GST_DVDEMUX (parent);
switch (GST_QUERY_TYPE (query)) {
case GST_QUERY_CONVERT:
@ -668,17 +627,15 @@ gst_dvdemux_sink_query (GstPad * pad, GstQuery * query)
break;
}
default:
res = gst_pad_query_default (pad, query);
res = gst_pad_query_default (pad, parent, query);
break;
}
gst_object_unref (dvdemux);
return res;
/* ERRORS */
error:
{
gst_object_unref (dvdemux);
GST_DEBUG ("error handling sink query");
return FALSE;
}
@ -704,9 +661,10 @@ gst_dvdemux_push_event (GstDVDemux * dvdemux, GstEvent * event)
}
static gboolean
gst_dvdemux_handle_sink_event (GstPad * pad, GstEvent * event)
gst_dvdemux_handle_sink_event (GstPad * pad, GstObject * parent,
GstEvent * event)
{
GstDVDemux *dvdemux = GST_DVDEMUX (gst_pad_get_parent (pad));
GstDVDemux *dvdemux = GST_DVDEMUX (parent);
gboolean res = TRUE;
switch (GST_EVENT_TYPE (event)) {
@ -723,29 +681,24 @@ gst_dvdemux_handle_sink_event (GstPad * pad, GstEvent * event)
gst_segment_init (&dvdemux->time_segment, GST_FORMAT_TIME);
res = gst_dvdemux_push_event (dvdemux, event);
break;
case GST_EVENT_NEWSEGMENT:
case GST_EVENT_SEGMENT:
{
gboolean update;
gdouble rate;
GstFormat format;
gint64 start, stop, time;
const GstSegment *segment;
/* parse byte start and stop positions */
gst_event_parse_new_segment (event, &update, &rate, &format,
&start, &stop, &time);
switch (format) {
gst_event_parse_segment (event, &segment);
switch (segment->format) {
case GST_FORMAT_BYTES:
gst_segment_set_newsegment (&dvdemux->byte_segment, update,
rate, format, start, stop, time);
gst_segment_copy_into (segment, &dvdemux->byte_segment);
#if 0
/* FIXME ?? no longer such subtle distinction in 0.11 */
/* the update can always be sent */
if (update) {
GstEvent *update;
update = gst_event_new_new_segment (TRUE,
dvdemux->time_segment.rate, dvdemux->time_segment.format,
dvdemux->time_segment.start, dvdemux->time_segment.last_stop,
dvdemux->time_segment.start, dvdemux->time_segment.position,
dvdemux->time_segment.time);
gst_dvdemux_push_event (dvdemux, update);
@ -755,11 +708,12 @@ gst_dvdemux_handle_sink_event (GstPad * pad, GstEvent * event)
* frames, etc.. */
dvdemux->need_segment = TRUE;
}
#endif
dvdemux->need_segment = TRUE;
gst_event_unref (event);
break;
case GST_FORMAT_TIME:
gst_segment_set_newsegment (&dvdemux->time_segment, update,
rate, format, start, stop, time);
gst_segment_copy_into (segment, &dvdemux->time_segment);
/* and we can just forward this time event */
res = gst_dvdemux_push_event (dvdemux, event);
@ -780,13 +734,14 @@ gst_dvdemux_handle_sink_event (GstPad * pad, GstEvent * event)
/* and clear the adapter */
gst_adapter_clear (dvdemux->adapter);
break;
case GST_EVENT_CAPS:
gst_event_unref (event);
break;
default:
res = gst_dvdemux_push_event (dvdemux, event);
break;
}
gst_object_unref (dvdemux);
return res;
}
@ -947,22 +902,25 @@ gst_dvdemux_do_seek (GstDVDemux * demux, GstSegment * segment)
* timestamp can be found. */
format = GST_FORMAT_BYTES;
res = gst_dvdemux_sink_convert (demux,
segment->format, segment->last_stop,
&format, &demux->byte_segment.last_stop);
segment->format, segment->position,
&format, (gint64 *) & demux->byte_segment.position);
if (!res)
goto done;
/* update byte segment start */
gst_dvdemux_sink_convert (demux,
segment->format, segment->start, &format, &demux->byte_segment.start);
segment->format, segment->start, &format,
(gint64 *) & demux->byte_segment.start);
/* update byte segment stop */
gst_dvdemux_sink_convert (demux,
segment->format, segment->stop, &format, &demux->byte_segment.stop);
segment->format, segment->stop, &format,
(gint64 *) & demux->byte_segment.stop);
/* update byte segment time */
gst_dvdemux_sink_convert (demux,
segment->format, segment->time, &format, &demux->byte_segment.time);
segment->format, segment->time, &format,
(gint64 *) & demux->byte_segment.time);
/* calculate current frame number */
format = GST_FORMAT_DEFAULT;
@ -1043,34 +1001,22 @@ gst_dvdemux_handle_pull_seek (GstDVDemux * demux, GstPad * pad,
/* now configure the seek segment */
if (event) {
gst_segment_set_seek (&seeksegment, rate, format, flags,
gst_segment_do_seek (&seeksegment, rate, format, flags,
cur_type, cur, stop_type, stop, &update);
}
GST_DEBUG_OBJECT (demux, "segment configured from %" G_GINT64_FORMAT
" to %" G_GINT64_FORMAT ", position %" G_GINT64_FORMAT,
seeksegment.start, seeksegment.stop, seeksegment.last_stop);
seeksegment.start, seeksegment.stop, seeksegment.position);
/* do the seek, segment.last_stop contains new position. */
/* do the seek, segment.position contains new position. */
res = gst_dvdemux_do_seek (demux, &seeksegment);
/* and prepare to continue streaming */
if (flush) {
/* send flush stop, peer will accept data and events again. We
* are not yet providing data as we still have the STREAM_LOCK. */
gst_dvdemux_push_event (demux, gst_event_new_flush_stop ());
} else if (res && demux->running) {
/* we are running the current segment and doing a non-flushing seek,
* close the segment first based on the last_stop. */
GST_DEBUG_OBJECT (demux, "closing running segment %" G_GINT64_FORMAT
" to %" G_GINT64_FORMAT, demux->time_segment.start,
demux->time_segment.last_stop);
gst_dvdemux_push_event (demux,
gst_event_new_new_segment (TRUE,
demux->time_segment.rate, demux->time_segment.format,
demux->time_segment.start, demux->time_segment.last_stop,
demux->time_segment.time));
gst_dvdemux_push_event (demux, gst_event_new_flush_stop (TRUE));
}
/* if successfull seek, we update our real segment and push
@ -1081,7 +1027,7 @@ gst_dvdemux_handle_pull_seek (GstDVDemux * demux, GstPad * pad,
if (demux->time_segment.flags & GST_SEEK_FLAG_SEGMENT) {
gst_element_post_message (GST_ELEMENT_CAST (demux),
gst_message_new_segment_start (GST_OBJECT_CAST (demux),
demux->time_segment.format, demux->time_segment.last_stop));
demux->time_segment.format, demux->time_segment.position));
}
if ((stop = demux->time_segment.stop) == -1)
stop = demux->time_segment.duration;
@ -1092,14 +1038,11 @@ gst_dvdemux_handle_pull_seek (GstDVDemux * demux, GstPad * pad,
if (demux->pending_segment)
gst_event_unref (demux->pending_segment);
demux->pending_segment = gst_event_new_new_segment (FALSE,
demux->time_segment.rate, demux->time_segment.format,
demux->time_segment.last_stop, stop, demux->time_segment.time);
demux->pending_segment = gst_event_new_segment (&demux->time_segment);
demux->need_segment = FALSE;
}
demux->running = TRUE;
/* and restart the task in case it got paused explicitely or by
* the FLUSH_START event we pushed out. */
gst_pad_start_task (demux->sinkpad, (GstTaskFunction) gst_dvdemux_loop,
@ -1166,12 +1109,13 @@ gst_dvdemux_send_event (GstElement * element, GstEvent * event)
/* handle an event on the source pad, it's most likely a seek */
static gboolean
gst_dvdemux_handle_src_event (GstPad * pad, GstEvent * event)
gst_dvdemux_handle_src_event (GstPad * pad, GstObject * parent,
GstEvent * event)
{
gboolean res = TRUE;
GstDVDemux *dvdemux;
dvdemux = GST_DVDEMUX (gst_pad_get_parent (pad));
dvdemux = GST_DVDEMUX (parent);
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_SEEK:
@ -1186,7 +1130,8 @@ gst_dvdemux_handle_src_event (GstPad * pad, GstEvent * event)
res = FALSE;
break;
case GST_EVENT_NAVIGATION:
/* no navigation either... */
case GST_EVENT_CAPS:
/* no navigation or caps either... */
res = FALSE;
break;
default:
@ -1197,8 +1142,6 @@ gst_dvdemux_handle_src_event (GstPad * pad, GstEvent * event)
if (event)
gst_event_unref (event);
gst_object_unref (dvdemux);
return res;
}
@ -1209,11 +1152,11 @@ gst_dvdemux_demux_audio (GstDVDemux * dvdemux, GstBuffer * buffer,
{
gint num_samples;
GstFlowReturn ret;
const guint8 *data;
GstMapInfo map;
data = GST_BUFFER_DATA (buffer);
dv_decode_full_audio (dvdemux->decoder, data, dvdemux->audio_buffers);
gst_buffer_map (buffer, &map, GST_MAP_READ);
dv_decode_full_audio (dvdemux->decoder, map.data, dvdemux->audio_buffers);
gst_buffer_unmap (buffer, &map);
if (G_LIKELY ((num_samples = dv_get_num_samples (dvdemux->decoder)) > 0)) {
gint16 *a_ptr;
@ -1231,18 +1174,15 @@ gst_dvdemux_demux_audio (GstDVDemux * dvdemux, GstBuffer * buffer,
if (G_UNLIKELY ((frequency != dvdemux->frequency)
|| (channels != dvdemux->channels))) {
GstCaps *caps;
GstAudioInfo info;
dvdemux->frequency = frequency;
dvdemux->channels = channels;
/* and set new caps */
caps = gst_caps_new_simple ("audio/x-raw-int",
"rate", G_TYPE_INT, frequency,
"depth", G_TYPE_INT, 16,
"width", G_TYPE_INT, 16,
"signed", G_TYPE_BOOLEAN, TRUE,
"channels", G_TYPE_INT, channels,
"endianness", G_TYPE_INT, G_BYTE_ORDER, NULL);
gst_audio_info_init (&info);
gst_audio_info_set_format (&info, GST_AUDIO_FORMAT_S16LE,
frequency, channels, NULL);
caps = gst_audio_info_to_caps (&info);
gst_pad_set_caps (dvdemux->audiosrcpad, caps);
gst_caps_unref (caps);
}
@ -1250,18 +1190,20 @@ gst_dvdemux_demux_audio (GstDVDemux * dvdemux, GstBuffer * buffer,
outbuf = gst_buffer_new_and_alloc (num_samples *
sizeof (gint16) * dvdemux->channels);
a_ptr = (gint16 *) GST_BUFFER_DATA (outbuf);
gst_buffer_map (outbuf, &map, GST_MAP_WRITE);
a_ptr = (gint16 *) map.data;
for (i = 0; i < num_samples; i++) {
for (j = 0; j < dvdemux->channels; j++) {
*(a_ptr++) = dvdemux->audio_buffers[j][i];
}
}
gst_buffer_unmap (outbuf, &map);
GST_DEBUG ("pushing audio %" GST_TIME_FORMAT,
GST_TIME_ARGS (dvdemux->time_segment.last_stop));
GST_TIME_ARGS (dvdemux->time_segment.position));
GST_BUFFER_TIMESTAMP (outbuf) = dvdemux->time_segment.last_stop;
GST_BUFFER_TIMESTAMP (outbuf) = dvdemux->time_segment.position;
GST_BUFFER_DURATION (outbuf) = duration;
GST_BUFFER_OFFSET (outbuf) = dvdemux->audio_offset;
dvdemux->audio_offset += num_samples;
@ -1269,7 +1211,6 @@ gst_dvdemux_demux_audio (GstDVDemux * dvdemux, GstBuffer * buffer,
if (dvdemux->new_media)
GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
gst_buffer_set_caps (outbuf, GST_PAD_CAPS (dvdemux->audiosrcpad));
ret = gst_pad_push (dvdemux->audiosrcpad, outbuf);
} else {
@ -1337,19 +1278,18 @@ gst_dvdemux_demux_video (GstDVDemux * dvdemux, GstBuffer * buffer,
/* takes ownership of buffer here, we just need to modify
* the metadata. */
outbuf = gst_buffer_make_metadata_writable (buffer);
outbuf = gst_buffer_make_writable (buffer);
GST_BUFFER_TIMESTAMP (outbuf) = dvdemux->time_segment.last_stop;
GST_BUFFER_TIMESTAMP (outbuf) = dvdemux->time_segment.position;
GST_BUFFER_OFFSET (outbuf) = dvdemux->video_offset;
GST_BUFFER_OFFSET_END (outbuf) = dvdemux->video_offset + 1;
GST_BUFFER_DURATION (outbuf) = duration;
if (dvdemux->new_media)
GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
gst_buffer_set_caps (outbuf, GST_PAD_CAPS (dvdemux->videosrcpad));
GST_DEBUG ("pushing video %" GST_TIME_FORMAT,
GST_TIME_ARGS (dvdemux->time_segment.last_stop));
GST_TIME_ARGS (dvdemux->time_segment.position));
ret = gst_pad_push (dvdemux->videosrcpad, outbuf);
@ -1375,11 +1315,14 @@ static gboolean
gst_dvdemux_get_timecode (GstDVDemux * dvdemux, GstBuffer * buffer,
GstSMPTETimeCode * timecode)
{
guint8 *data = GST_BUFFER_DATA (buffer);
guint8 *data;
GstMapInfo map;
int offset;
int dif;
int n_difs = dvdemux->decoder->num_dif_seqs;
gst_buffer_map (buffer, &map, GST_MAP_READ);
data = map.data;
for (dif = 0; dif < n_difs; dif++) {
offset = get_ssyb_offset (dif, 3);
if (data[offset + 3] == 0x13) {
@ -1393,23 +1336,28 @@ gst_dvdemux_get_timecode (GstDVDemux * dvdemux, GstBuffer * buffer,
(data[offset + 7] & 0xf);
GST_DEBUG ("got timecode %" GST_SMPTE_TIME_CODE_FORMAT,
GST_SMPTE_TIME_CODE_ARGS (timecode));
gst_buffer_unmap (buffer, &map);
return TRUE;
}
}
gst_buffer_unmap (buffer, &map);
return FALSE;
}
static gboolean
gst_dvdemux_is_new_media (GstDVDemux * dvdemux, GstBuffer * buffer)
{
guint8 *data = GST_BUFFER_DATA (buffer);
guint8 *data;
GstMapInfo map;
int aaux_offset;
int dif;
int n_difs;
n_difs = dvdemux->decoder->num_dif_seqs;
gst_buffer_map (buffer, &map, GST_MAP_READ);
data = map.data;
for (dif = 0; dif < n_difs; dif++) {
if (dif & 1) {
aaux_offset = (dif * 12000) + (6 + 16 * 1) * 80 + 3;
@ -1417,11 +1365,14 @@ gst_dvdemux_is_new_media (GstDVDemux * dvdemux, GstBuffer * buffer)
aaux_offset = (dif * 12000) + (6 + 16 * 4) * 80 + 3;
}
if (data[aaux_offset + 0] == 0x51) {
if ((data[aaux_offset + 2] & 0x80) == 0)
if ((data[aaux_offset + 2] & 0x80) == 0) {
gst_buffer_unmap (buffer, &map);
return TRUE;
}
}
}
gst_buffer_unmap (buffer, &map);
return FALSE;
}
@ -1431,13 +1382,12 @@ gst_dvdemux_demux_frame (GstDVDemux * dvdemux, GstBuffer * buffer)
{
GstClockTime next_ts;
GstFlowReturn aret, vret, ret;
guint8 *data;
GstMapInfo map;
guint64 duration;
GstSMPTETimeCode timecode;
int frame_number;
if (G_UNLIKELY (dvdemux->need_segment)) {
GstEvent *event;
GstFormat format;
/* convert to time and store as start/end_timestamp */
@ -1445,12 +1395,12 @@ gst_dvdemux_demux_frame (GstDVDemux * dvdemux, GstBuffer * buffer)
if (!(gst_dvdemux_convert_sink_pair (dvdemux,
GST_FORMAT_BYTES, dvdemux->byte_segment.start,
dvdemux->byte_segment.stop, format,
&dvdemux->time_segment.start, &dvdemux->time_segment.stop)))
(gint64 *) & dvdemux->time_segment.start,
(gint64 *) & dvdemux->time_segment.stop)))
goto segment_error;
dvdemux->time_segment.rate = dvdemux->byte_segment.rate;
dvdemux->time_segment.abs_rate = dvdemux->byte_segment.abs_rate;
dvdemux->time_segment.last_stop = dvdemux->time_segment.start;
dvdemux->time_segment.position = dvdemux->time_segment.start;
/* calculate current frame number */
format = GST_FORMAT_DEFAULT;
@ -1465,10 +1415,8 @@ gst_dvdemux_demux_frame (GstDVDemux * dvdemux, GstBuffer * buffer)
GST_TIME_ARGS (dvdemux->time_segment.stop),
GST_TIME_ARGS (dvdemux->time_segment.start));
event = gst_event_new_new_segment (FALSE, dvdemux->byte_segment.rate,
GST_FORMAT_TIME, dvdemux->time_segment.start,
dvdemux->time_segment.stop, dvdemux->time_segment.start);
gst_dvdemux_push_event (dvdemux, event);
gst_dvdemux_push_event (dvdemux,
gst_event_new_segment (&dvdemux->time_segment));
dvdemux->need_segment = FALSE;
}
@ -1482,11 +1430,11 @@ gst_dvdemux_demux_frame (GstDVDemux * dvdemux, GstBuffer * buffer)
next_ts = gst_util_uint64_scale_int (
(dvdemux->frame_offset + 1) * GST_SECOND,
dvdemux->framerate_denominator, dvdemux->framerate_numerator);
duration = next_ts - dvdemux->time_segment.last_stop;
duration = next_ts - dvdemux->time_segment.position;
data = GST_BUFFER_DATA (buffer);
dv_parse_packs (dvdemux->decoder, data);
gst_buffer_map (buffer, &map, GST_MAP_READ);
dv_parse_packs (dvdemux->decoder, map.data);
gst_buffer_unmap (buffer, &map);
dvdemux->new_media = FALSE;
if (gst_dvdemux_is_new_media (dvdemux, buffer) &&
dvdemux->frames_since_new_media > 2) {
@ -1513,7 +1461,7 @@ gst_dvdemux_demux_frame (GstDVDemux * dvdemux, GstBuffer * buffer)
goto done;
}
gst_segment_set_last_stop (&dvdemux->time_segment, GST_FORMAT_TIME, next_ts);
dvdemux->time_segment.position = next_ts;
dvdemux->frame_offset++;
/* check for the end of the segment */
@ -1545,11 +1493,14 @@ gst_dvdemux_flush (GstDVDemux * dvdemux)
gint length;
/* get the accumulated bytes */
data = gst_adapter_peek (dvdemux->adapter, dvdemux->frame_len);
data = gst_adapter_map (dvdemux->adapter, dvdemux->frame_len);
/* parse header to know the length and other params */
if (G_UNLIKELY (dv_parse_header (dvdemux->decoder, data) < 0))
if (G_UNLIKELY (dv_parse_header (dvdemux->decoder, data) < 0)) {
gst_adapter_unmap (dvdemux->adapter);
goto parse_header_error;
}
gst_adapter_unmap (dvdemux->adapter);
/* after parsing the header we know the length of the data */
length = dvdemux->frame_len = dvdemux->decoder->frame_size;
@ -1569,13 +1520,7 @@ gst_dvdemux_flush (GstDVDemux * dvdemux)
if (G_LIKELY (gst_adapter_available (dvdemux->adapter) >= length)) {
GstBuffer *buffer;
data = gst_adapter_take (dvdemux->adapter, length);
/* create buffer for the remainder of the code */
buffer = gst_buffer_new ();
GST_BUFFER_DATA (buffer) = (guint8 *) data;
GST_BUFFER_SIZE (buffer) = length;
GST_BUFFER_MALLOCDATA (buffer) = (guint8 *) data;
buffer = gst_adapter_take_buffer (dvdemux->adapter, length);
/* and decode the buffer, takes ownership */
ret = gst_dvdemux_demux_frame (dvdemux, buffer);
@ -1600,13 +1545,13 @@ parse_header_error:
* accumulate data until we have a frame, then decode.
*/
static GstFlowReturn
gst_dvdemux_chain (GstPad * pad, GstBuffer * buffer)
gst_dvdemux_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
{
GstDVDemux *dvdemux;
GstFlowReturn ret;
GstClockTime timestamp;
dvdemux = GST_DVDEMUX (gst_pad_get_parent (pad));
dvdemux = GST_DVDEMUX (parent);
/* a discontinuity in the stream, we need to get rid of
* accumulated data in the adapter and assume a new frame
@ -1617,8 +1562,7 @@ gst_dvdemux_chain (GstPad * pad, GstBuffer * buffer)
/* a timestamp always should be respected */
timestamp = GST_BUFFER_TIMESTAMP (buffer);
if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
gst_segment_set_last_stop (&dvdemux->time_segment, GST_FORMAT_TIME,
timestamp);
dvdemux->time_segment.position = timestamp;
/* FIXME, adjust frame_offset and other counters */
}
@ -1637,8 +1581,6 @@ gst_dvdemux_chain (GstPad * pad, GstBuffer * buffer)
/* and try to flush pending frames */
ret = gst_dvdemux_flush (dvdemux);
gst_object_unref (dvdemux);
return ret;
}
@ -1653,7 +1595,7 @@ gst_dvdemux_loop (GstPad * pad)
GstFlowReturn ret;
GstDVDemux *dvdemux;
GstBuffer *buffer = NULL;
const guint8 *data;
GstMapInfo map;
dvdemux = GST_DVDEMUX (gst_pad_get_parent (pad));
@ -1662,19 +1604,21 @@ gst_dvdemux_loop (GstPad * pad)
/* pull in NTSC sized buffer to figure out the frame
* length */
ret = gst_pad_pull_range (dvdemux->sinkpad,
dvdemux->byte_segment.last_stop, NTSC_BUFFER, &buffer);
dvdemux->byte_segment.position, NTSC_BUFFER, &buffer);
if (G_UNLIKELY (ret != GST_FLOW_OK))
goto pause;
/* check buffer size, don't want to read small buffers */
if (G_UNLIKELY (GST_BUFFER_SIZE (buffer) < NTSC_BUFFER))
if (G_UNLIKELY (gst_buffer_get_size (buffer) < NTSC_BUFFER))
goto small_buffer;
data = GST_BUFFER_DATA (buffer);
gst_buffer_map (buffer, &map, GST_MAP_READ);
/* parse header to know the length and other params */
if (G_UNLIKELY (dv_parse_header (dvdemux->decoder, data) < 0))
if (G_UNLIKELY (dv_parse_header (dvdemux->decoder, map.data) < 0)) {
gst_buffer_unmap (buffer, &map);
goto parse_header_error;
}
gst_buffer_unmap (buffer, &map);
/* after parsing the header we know the length of the data */
dvdemux->frame_len = dvdemux->decoder->frame_size;
@ -1736,15 +1680,15 @@ gst_dvdemux_loop (GstPad * pad)
if (G_LIKELY (buffer == NULL)) {
GST_DEBUG_OBJECT (dvdemux, "pulling buffer at offset %" G_GINT64_FORMAT,
dvdemux->byte_segment.last_stop);
dvdemux->byte_segment.position);
ret = gst_pad_pull_range (dvdemux->sinkpad,
dvdemux->byte_segment.last_stop, dvdemux->frame_len, &buffer);
dvdemux->byte_segment.position, dvdemux->frame_len, &buffer);
if (ret != GST_FLOW_OK)
goto pause;
/* check buffer size, don't want to read small buffers */
if (GST_BUFFER_SIZE (buffer) < dvdemux->frame_len)
if (gst_buffer_get_size (buffer) < dvdemux->frame_len)
goto small_buffer;
}
/* and decode the buffer */
@ -1753,7 +1697,7 @@ gst_dvdemux_loop (GstPad * pad)
goto pause;
/* and position ourselves for the next buffer */
dvdemux->byte_segment.last_stop += dvdemux->frame_len;
dvdemux->byte_segment.position += dvdemux->frame_len;
done:
gst_object_unref (dvdemux);
@ -1766,7 +1710,6 @@ parse_header_error:
GST_ELEMENT_ERROR (dvdemux, STREAM, DECODE,
(NULL), ("Error parsing DV header"));
gst_buffer_unref (buffer);
dvdemux->running = FALSE;
gst_pad_pause_task (dvdemux->sinkpad);
gst_dvdemux_push_event (dvdemux, gst_event_new_eos ());
goto done;
@ -1776,7 +1719,6 @@ small_buffer:
GST_ELEMENT_ERROR (dvdemux, STREAM, DECODE,
(NULL), ("Error reading buffer"));
gst_buffer_unref (buffer);
dvdemux->running = FALSE;
gst_pad_pause_task (dvdemux->sinkpad);
gst_dvdemux_push_event (dvdemux, gst_event_new_eos ());
goto done;
@ -1784,15 +1726,21 @@ small_buffer:
pause:
{
GST_INFO_OBJECT (dvdemux, "pausing task, %s", gst_flow_get_name (ret));
dvdemux->running = FALSE;
gst_pad_pause_task (dvdemux->sinkpad);
if (ret == GST_FLOW_EOS) {
GST_LOG_OBJECT (dvdemux, "got eos");
/* so align our position with the end of it, if there is one
* this ensures a subsequent will arrive at correct base/acc time */
if (dvdemux->time_segment.rate > 0.0 &&
GST_CLOCK_TIME_IS_VALID (dvdemux->time_segment.stop))
dvdemux->time_segment.position = dvdemux->time_segment.stop;
else if (dvdemux->time_segment.rate < 0.0)
dvdemux->time_segment.position = dvdemux->time_segment.start;
/* perform EOS logic */
if (dvdemux->time_segment.flags & GST_SEEK_FLAG_SEGMENT) {
gst_element_post_message (GST_ELEMENT (dvdemux),
gst_message_new_segment_done (GST_OBJECT_CAST (dvdemux),
dvdemux->time_segment.format, dvdemux->time_segment.last_stop));
dvdemux->time_segment.format, dvdemux->time_segment.position));
} else {
gst_dvdemux_push_event (dvdemux, gst_event_new_eos ());
}
@ -1807,53 +1755,69 @@ pause:
}
static gboolean
gst_dvdemux_sink_activate_push (GstPad * sinkpad, gboolean active)
gst_dvdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
GstPadMode mode, gboolean active)
{
GstDVDemux *demux = GST_DVDEMUX (gst_pad_get_parent (sinkpad));
gboolean res;
GstDVDemux *demux = GST_DVDEMUX (parent);
if (active) {
demux->seek_handler = gst_dvdemux_handle_push_seek;
} else {
demux->seek_handler = NULL;
switch (mode) {
case GST_PAD_MODE_PULL:
if (active) {
demux->seek_handler = gst_dvdemux_handle_pull_seek;
res = gst_pad_start_task (sinkpad,
(GstTaskFunction) gst_dvdemux_loop, sinkpad);
} else {
demux->seek_handler = NULL;
res = gst_pad_stop_task (sinkpad);
}
break;
case GST_PAD_MODE_PUSH:
if (active) {
GST_DEBUG_OBJECT (demux, "activating push/chain function");
demux->seek_handler = gst_dvdemux_handle_push_seek;
} else {
GST_DEBUG_OBJECT (demux, "deactivating push/chain function");
demux->seek_handler = NULL;
}
res = TRUE;
break;
default:
res = FALSE;
break;
}
gst_object_unref (demux);
return TRUE;
return res;
}
static gboolean
gst_dvdemux_sink_activate_pull (GstPad * sinkpad, gboolean active)
{
GstDVDemux *demux = GST_DVDEMUX (gst_pad_get_parent (sinkpad));
if (active) {
demux->running = TRUE;
demux->seek_handler = gst_dvdemux_handle_pull_seek;
gst_pad_start_task (sinkpad, (GstTaskFunction) gst_dvdemux_loop, sinkpad);
} else {
demux->seek_handler = NULL;
gst_pad_stop_task (sinkpad);
demux->running = FALSE;
}
gst_object_unref (demux);
return TRUE;
};
/* decide on push or pull based scheduling */
static gboolean
gst_dvdemux_sink_activate (GstPad * sinkpad)
gst_dvdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
{
gboolean ret;
GstQuery *query;
gboolean pull_mode;
if (gst_pad_check_pull_range (sinkpad))
ret = gst_pad_activate_pull (sinkpad, TRUE);
else
ret = gst_pad_activate_push (sinkpad, TRUE);
query = gst_query_new_scheduling ();
return ret;
};
if (!gst_pad_peer_query (sinkpad, query)) {
gst_query_unref (query);
goto activate_push;
}
pull_mode = gst_query_has_scheduling_mode (query, GST_PAD_MODE_PULL);
gst_query_unref (query);
if (!pull_mode)
goto activate_push;
GST_DEBUG_OBJECT (sinkpad, "activating pull");
return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
activate_push:
{
GST_DEBUG_OBJECT (sinkpad, "activating push");
return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
}
}
static GstStateChangeReturn
gst_dvdemux_change_state (GstElement * element, GstStateChange transition)
@ -1875,7 +1839,7 @@ gst_dvdemux_change_state (GstElement * element, GstStateChange transition)
break;
}
ret = parent_class->change_state (element, transition);
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
switch (transition) {
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:

View file

@ -75,7 +75,6 @@ struct _GstDVDemux {
GstDVDemuxSeekHandler seek_handler;
GstSegment byte_segment;
GstSegment time_segment;
gboolean running;
gboolean need_segment;
gboolean new_media;
int frames_since_new_media;