);
static GstStaticCaps gst_alpha_alpha_caps =
- GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("AYUV")
- ";" GST_VIDEO_CAPS_ARGB ";" GST_VIDEO_CAPS_BGRA ";" GST_VIDEO_CAPS_ABGR ";"
- GST_VIDEO_CAPS_RGBA);
+GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ AYUV, ARGB, BGRA, ABGR, RGBA }"));
+ /* FIXME: why do we need our own lock for this? */
+ #if !GLIB_CHECK_VERSION (2, 31, 0)
#define GST_ALPHA_LOCK(alpha) G_STMT_START { \
GST_LOG_OBJECT (alpha, "Locking alpha from thread %p", g_thread_self ()); \
g_static_mutex_lock (&alpha->lock); \
GST_LOG_OBJECT (alpha, "Unlocking alpha from thread %p", g_thread_self ()); \
g_static_mutex_unlock (&alpha->lock); \
} G_STMT_END
+ #else
+ #define GST_ALPHA_LOCK(alpha) G_STMT_START { \
+ GST_LOG_OBJECT (alpha, "Locking alpha from thread %p", g_thread_self ()); \
+ g_mutex_lock (&alpha->lock); \
+ GST_LOG_OBJECT (alpha, "Locked alpha from thread %p", g_thread_self ()); \
+ } G_STMT_END
+
+ #define GST_ALPHA_UNLOCK(alpha) G_STMT_START { \
+ GST_LOG_OBJECT (alpha, "Unlocking alpha from thread %p", g_thread_self ()); \
+ g_mutex_unlock (&alpha->lock); \
+ } G_STMT_END
+ #endif
-static gboolean gst_alpha_start (GstBaseTransform * trans);
-static gboolean gst_alpha_get_unit_size (GstBaseTransform * btrans,
- GstCaps * caps, guint * size);
static GstCaps *gst_alpha_transform_caps (GstBaseTransform * btrans,
- GstPadDirection direction, GstCaps * caps);
-static gboolean gst_alpha_set_caps (GstBaseTransform * btrans,
- GstCaps * incaps, GstCaps * outcaps);
-static GstFlowReturn gst_alpha_transform (GstBaseTransform * btrans,
- GstBuffer * in, GstBuffer * out);
+ GstPadDirection direction, GstCaps * caps, GstCaps * filter);
static void gst_alpha_before_transform (GstBaseTransform * btrans,
GstBuffer * buf);
/* <private> */
/* caps */
+ #if !GLIB_CHECK_VERSION (2, 31, 0)
GStaticMutex lock;
+ #else
+ GMutex lock;
+ #endif
- GstVideoFormat in_format, out_format;
- gint width, height;
gboolean in_sdtv, out_sdtv;
/* properties */
needed_data);
}
- GST_BUFFER_SIZE (buffer), GST_BASE_PARSE_DRAINING (parse),
- framesize, &needed_data);
+ } else if (aacparse->header_type == DSPAAC_HEADER_LOAS) {
+ guint needed_data = 1024;
+
+ ret = gst_aac_parse_check_loas_frame (aacparse, data,
++ size, GST_BASE_PARSE_DRAINING (parse), framesize, &needed_data);
+
+ if (!ret) {
+ GST_DEBUG ("buffer didn't contain valid frame");
+ gst_base_parse_set_min_frame_size (GST_BASE_PARSE (aacparse),
+ needed_data);
+ }
+
} else {
GST_DEBUG ("buffer didn't contain valid frame");
gst_base_parse_set_min_frame_size (GST_BASE_PARSE (aacparse),
aacparse = GST_AAC_PARSE (parse);
buffer = frame->buffer;
- if (G_UNLIKELY (aacparse->header_type != DSPAAC_HEADER_ADTS))
- return ret;
+ if (aacparse->header_type == DSPAAC_HEADER_ADTS) {
+ /* see above */
+ frame->overhead = 7;
- /* see above */
- frame->overhead = 7;
- gst_aac_parse_parse_adts_header (aacparse, GST_BUFFER_DATA (buffer),
++ data = gst_buffer_map (buffer, &size, NULL, GST_MAP_READ);
++ gst_aac_parse_parse_adts_header (aacparse, data,
+ &rate, &channels, NULL, NULL);
++ gst_buffer_unmap (buffer, data, size);
+
- data = gst_buffer_map (buffer, &size, NULL, GST_MAP_READ);
- gst_aac_parse_parse_adts_header (aacparse, data,
- &rate, &channels, NULL, NULL);
- gst_buffer_unmap (buffer, data, size);
-
- GST_LOG_OBJECT (aacparse, "rate: %d, chans: %d", rate, channels);
+ GST_LOG_OBJECT (aacparse, "rate: %d, chans: %d", rate, channels);
- if (G_UNLIKELY (rate != aacparse->sample_rate
- || channels != aacparse->channels)) {
- GstCaps *sinkcaps;
+ if (G_UNLIKELY (rate != aacparse->sample_rate
+ || channels != aacparse->channels)) {
++ GstCaps *sinkcaps;
+
- aacparse->sample_rate = rate;
- aacparse->channels = channels;
+ aacparse->sample_rate = rate;
+ aacparse->channels = channels;
- sinkcaps = gst_pad_get_current_caps (GST_BASE_PARSE (aacparse)->sinkpad);
- if (!gst_aac_parse_set_src_caps (aacparse, sinkcaps)) {
- /* If linking fails, we need to return appropriate error */
- if (!gst_aac_parse_set_src_caps (aacparse,
- GST_PAD_CAPS (GST_BASE_PARSE (aacparse)->sinkpad))) {
++ sinkcaps = gst_pad_get_current_caps (GST_BASE_PARSE (aacparse)->sinkpad);
++ if (!gst_aac_parse_set_src_caps (aacparse, sinkcaps)) {
+ /* If linking fails, we need to return appropriate error */
+ ret = GST_FLOW_NOT_LINKED;
+ }
+ gst_caps_unref (sinkcaps);
- ret = GST_FLOW_NOT_LINKED;
+
+ gst_base_parse_set_frame_rate (GST_BASE_PARSE (aacparse),
+ aacparse->sample_rate, aacparse->frame_samples, 2, 2);
}
- gst_caps_unref (sinkcaps);
+ } else if (aacparse->header_type == DSPAAC_HEADER_LOAS) {
+ gboolean setcaps = FALSE;
+
+ /* see above */
+ frame->overhead = 3;
+
- if (!gst_aac_parse_read_loas_config (aacparse, GST_BUFFER_DATA (buffer),
- GST_BUFFER_SIZE (buffer), &rate, &channels, NULL)) {
++ data = gst_buffer_map (buffer, &size, NULL, GST_MAP_READ);
++ if (!gst_aac_parse_read_loas_config (aacparse, data, size, &rate, &channels,
++ NULL)) {
+ GST_WARNING_OBJECT (aacparse, "Error reading LOAS config");
+ } else if (G_UNLIKELY (rate != aacparse->sample_rate
+ || channels != aacparse->channels)) {
+ aacparse->sample_rate = rate;
+ aacparse->channels = channels;
+ setcaps = TRUE;
+ GST_INFO_OBJECT (aacparse, "New LOAS config: %d Hz, %d channels", rate,
+ channels);
+ }
++ gst_buffer_unmap (buffer, data, size);
+
+ /* We want to set caps both at start, and when rate/channels change.
+ Since only some LOAS frames have that info, we may receive frames
+ before knowing about rate/channels. */
- if (setcaps || !GST_PAD_CAPS (GST_BASE_PARSE_SRC_PAD (aacparse))) {
- if (!gst_aac_parse_set_src_caps (aacparse,
- GST_PAD_CAPS (GST_BASE_PARSE (aacparse)->sinkpad))) {
++ if (setcaps
++ || !gst_pad_has_current_caps (GST_BASE_PARSE_SRC_PAD (aacparse))) {
++ GstCaps *sinkcaps =
++ gst_pad_get_current_caps (GST_BASE_PARSE (aacparse)->sinkpad);
++ if (!gst_aac_parse_set_src_caps (aacparse, sinkcaps)) {
+ /* If linking fails, we need to return appropriate error */
+ ret = GST_FLOW_NOT_LINKED;
+ }
++ gst_caps_unref (sinkcaps);
- gst_base_parse_set_frame_rate (GST_BASE_PARSE (aacparse),
- aacparse->sample_rate, aacparse->frame_samples, 2, 2);
+ gst_base_parse_set_frame_rate (GST_BASE_PARSE (aacparse),
+ aacparse->sample_rate, aacparse->frame_samples, 2, 2);
+ }
}
return ret;
/* spec not quite clear here: decoder should decode if less than 8,
* but seemingly only defines 6 and 8 cases */
- if (bsid > 8) {
+ /* Files with 9 and 10 happen, and seem to comply with the <= 8
+ format, so let them through. The spec says nothing about 9 and 10 */
+ if (bsid > 10) {
GST_DEBUG_OBJECT (ac3parse, "unexpected bsid=%d", bsid);
- return FALSE;
+ goto cleanup;
} else if (bsid != 8 && bsid != 6) {
GST_DEBUG_OBJECT (ac3parse, "undefined bsid=%d", bsid);
}
"wmaversion = (int) [ 1, 2 ] ")
);
-static void gst_avi_mux_base_init (gpointer g_class);
-static void gst_avi_mux_class_init (GstAviMuxClass * klass);
-static void gst_avi_mux_init (GstAviMux * avimux);
static void gst_avi_mux_pad_reset (GstAviPad * avipad, gboolean free);
- static GstFlowReturn gst_avi_mux_collect_pads (GstCollectPads * pads,
+ static GstFlowReturn gst_avi_mux_collect_pads (GstCollectPads2 * pads,
GstAviMux * avimux);
- static gboolean gst_avi_mux_handle_event (GstPad * pad, GstObject * parent,
- GstEvent * event);
+ static gboolean gst_avi_mux_handle_event (GstCollectPads2 * pad,
+ GstCollectData2 * data, GstEvent * event, gpointer user_data);
static GstPad *gst_avi_mux_request_new_pad (GstElement * element,
- GstPadTemplate * templ, const gchar * name);
+ GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
static void gst_avi_mux_release_pad (GstElement * element, GstPad * pad);
static void gst_avi_mux_set_property (GObject * object,
guint prop_id, const GValue * value, GParamSpec * pspec);
g_free (name);
- avipad->collect = gst_collect_pads_add_pad (avimux->collect,
- newpad, sizeof (GstAviCollectData), NULL);
+ avipad->collect = gst_collect_pads2_add_pad (avimux->collect,
+ newpad, sizeof (GstAviCollectData));
((GstAviCollectData *) (avipad->collect))->avipad = avipad;
- /* FIXME: hacked way to override/extend the event function of
- * GstCollectPads; because it sets its own event function giving the
- * element no access to events */
- avimux->collect_event = GST_PAD_EVENTFUNC (newpad);
- gst_pad_set_event_function (newpad,
- GST_DEBUG_FUNCPTR (gst_avi_mux_handle_event));
+
if (!gst_element_add_pad (element, newpad))
goto pad_add_failed;
/* handle events (search) */
static gboolean
- gst_avi_mux_handle_event (GstPad * pad, GstObject * parent, GstEvent * event)
+ gst_avi_mux_handle_event (GstCollectPads2 * pads, GstCollectData2 * data,
+ GstEvent * event, gpointer user_data)
{
GstAviMux *avimux;
- gboolean ret = TRUE;
++ gboolean ret = FALSE;
- avimux = GST_AVI_MUX (parent);
+ avimux = GST_AVI_MUX (user_data);
switch (GST_EVENT_TYPE (event)) {
- collect_pad = (GstAviCollectData *) gst_pad_get_element_private (pad);
+ case GST_EVENT_CAPS:
+ {
+ GstCaps *caps;
+ GstAviCollectData *collect_pad;
+ GstAviVideoPad *avipad;
+
+ gst_event_parse_caps (event, &caps);
+
+ /* find stream data */
- ret = gst_avi_mux_vidsink_set_caps (pad, caps);
++ collect_pad = (GstAviCollectData *) data;
+ g_assert (collect_pad);
+ avipad = (GstAviVideoPad *) collect_pad->avipad;
+ g_assert (avipad);
+
+ if (avipad->parent.is_video) {
- ret = gst_avi_mux_audsink_set_caps (pad, caps);
++ ret = gst_avi_mux_vidsink_set_caps (GST_PAD (avipad), caps);
+ } else {
++ ret = gst_avi_mux_audsink_set_caps (GST_PAD (avipad), caps);
+ }
+ break;
+ }
case GST_EVENT_TAG:{
GstTagList *list;
GstTagSetter *setter = GST_TAG_SETTER (avimux);
break;
}
- /* now GstCollectPads can take care of the rest, e.g. EOS */
- if (ret)
- ret = avimux->collect_event (pad, parent, event);
-
+ /* now GstCollectPads2 can take care of the rest, e.g. EOS */
- return FALSE;
+ return ret;
}
/* send extra 'padding' data */
GstBuffer *data, *header;
gulong total_size, pad_bytes = 0;
guint flags;
+ gsize datasize;
- data = gst_collect_pads_pop (avimux->collect, avipad->collect);
+ data = gst_collect_pads2_pop (avimux->collect, avipad->collect);
/* arrange downstream running time */
- data = gst_buffer_make_metadata_writable (data);
+ data = gst_buffer_make_writable (data);
GST_BUFFER_TIMESTAMP (data) =
gst_segment_to_running_time (&avipad->collect->segment,
GST_FORMAT_TIME, GST_BUFFER_TIMESTAMP (data));
static void gst_flv_mux_finalize (GObject * object);
static GstFlowReturn
- gst_flv_mux_collected (GstCollectPads * pads, gpointer user_data);
+ gst_flv_mux_handle_buffer (GstCollectPads2 * pads, GstCollectData2 * cdata,
+ GstBuffer * buf, gpointer user_data);
+ static gboolean
+ gst_flv_mux_handle_sink_event (GstCollectPads2 * pads, GstCollectData2 * data,
+ GstEvent * event, gpointer user_data);
-static gboolean gst_flv_mux_handle_src_event (GstPad * pad, GstEvent * event);
+static gboolean gst_flv_mux_handle_src_event (GstPad * pad, GstObject * parent,
+ GstEvent * event);
static GstPad *gst_flv_mux_request_new_pad (GstElement * element,
- GstPadTemplate * templ, const gchar * name);
+ GstPadTemplate * templ, const gchar * req_name, const GstCaps * caps);
static void gst_flv_mux_release_pad (GstElement * element, GstPad * pad);
+static gboolean gst_flv_mux_video_pad_setcaps (GstPad * pad, GstCaps * caps);
+static gboolean gst_flv_mux_audio_pad_setcaps (GstPad * pad, GstCaps * caps);
+
static void gst_flv_mux_get_property (GObject * object,
guint prop_id, GValue * value, GParamSpec * pspec);
static void gst_flv_mux_set_property (GObject * object,
}
static gboolean
- gst_flv_mux_handle_sink_event (GstPad * pad, GstObject * parent,
- GstEvent * event)
+ gst_flv_mux_handle_sink_event (GstCollectPads2 * pads, GstCollectData2 * data,
+ GstEvent * event, gpointer user_data)
{
- GstFlvMux *mux = GST_FLV_MUX (parent);
- gboolean ret = TRUE;
+ GstFlvMux *mux = GST_FLV_MUX (user_data);
++ gboolean ret = FALSE;
switch (GST_EVENT_TYPE (event)) {
- flvpad = (GstFlvPad *) gst_pad_get_element_private (pad);
+ case GST_EVENT_CAPS:
+ {
+ GstCaps *caps;
+ GstFlvPad *flvpad;
+
+ gst_event_parse_caps (event, &caps);
+
+ /* find stream data */
- ret = gst_flv_mux_video_pad_setcaps (pad, caps);
++ flvpad = (GstFlvPad *) data;
+ g_assert (flvpad);
+
+ if (flvpad->video) {
- ret = gst_flv_mux_audio_pad_setcaps (pad, caps);
++ ret = gst_flv_mux_video_pad_setcaps (data->pad, caps);
+ } else {
++ ret = gst_flv_mux_audio_pad_setcaps (data->pad, caps);
+ }
+ /* and eat */
+ ret = FALSE;
+ gst_event_unref (event);
+ break;
+ }
case GST_EVENT_TAG:{
GstTagList *list;
GstTagSetter *setter = GST_TAG_SETTER (mux);
break;
}
- /* now GstCollectPads can take care of the rest, e.g. EOS */
- if (ret)
- ret = mux->collect_event (pad, parent, event);
-
+ /* now GstCollectPads2 can take care of the rest, e.g. EOS */
- return FALSE;
+ return ret;
}
static gboolean
cpad->video_codec_data = NULL;
gst_flv_mux_reset_pad (mux, cpad, video);
- /* FIXME: hacked way to override/extend the event function of
- * GstCollectPads; because it sets its own event function giving the
- * element no access to events.
- */
- mux->collect_event = (GstPadEventFunction) GST_PAD_EVENTFUNC (pad);
- gst_pad_set_event_function (pad,
- GST_DEBUG_FUNCPTR (gst_flv_mux_handle_sink_event));
-
- gst_pad_set_setcaps_function (pad, setcapsfunc);
gst_pad_set_active (pad, TRUE);
gst_element_add_pad (element, pad);
}
}
+ if (!full)
+ goto end;
+
if (mux->duration == GST_CLOCK_TIME_NONE) {
GSList *l;
-
- GstFormat fmt = GST_FORMAT_TIME;
guint64 dur;
for (l = mux->collect->data; l; l = l->next) {
- GstCollectData *cdata = l->data;
+ GstCollectData2 *cdata = l->data;
- fmt = GST_FORMAT_TIME;
-
- if (gst_pad_query_peer_duration (cdata->pad, &fmt, (gint64 *) & dur) &&
- fmt == GST_FORMAT_TIME && dur != GST_CLOCK_TIME_NONE) {
+ if (gst_pad_peer_query_duration (cdata->pad, GST_FORMAT_TIME,
+ (gint64 *) & dur) && dur != GST_CLOCK_TIME_NONE) {
if (mux->duration == GST_CLOCK_TIME_NONE)
mux->duration = dur;
else
tags_written++;
}
- tmp = gst_buffer_new_and_alloc (2 + 0 + 1);
- data = GST_BUFFER_DATA (tmp);
+ end:
+
+ if (!tags_written) {
+ gst_buffer_unref (script_tag);
+ script_tag = NULL;
+ goto exit;
+ }
+
+ _gst_buffer_new_and_alloc (2 + 0 + 1, &tmp, &data);
data[0] = 0; /* 0 byte size */
data[1] = 0;
data[2] = 9; /* end marker */
script_tag = gst_buffer_join (script_tag, tmp);
tags_written++;
- tmp = gst_buffer_new_and_alloc (4);
- data = GST_BUFFER_DATA (tmp);
- GST_WRITE_UINT32_BE (data, GST_BUFFER_SIZE (script_tag));
+ _gst_buffer_new_and_alloc (4, &tmp, &data);
+ GST_WRITE_UINT32_BE (data, gst_buffer_get_size (script_tag));
script_tag = gst_buffer_join (script_tag, tmp);
- data = GST_BUFFER_DATA (script_tag);
- data[1] = ((GST_BUFFER_SIZE (script_tag) - 11 - 4) >> 16) & 0xff;
- data[2] = ((GST_BUFFER_SIZE (script_tag) - 11 - 4) >> 8) & 0xff;
- data[3] = ((GST_BUFFER_SIZE (script_tag) - 11 - 4) >> 0) & 0xff;
+ data = gst_buffer_map (script_tag, NULL, NULL, GST_MAP_WRITE);
+ data[1] = ((gst_buffer_get_size (script_tag) - 11 - 4) >> 16) & 0xff;
+ data[2] = ((gst_buffer_get_size (script_tag) - 11 - 4) >> 8) & 0xff;
+ data[3] = ((gst_buffer_get_size (script_tag) - 11 - 4) >> 0) & 0xff;
GST_WRITE_UINT32_BE (data + 11 + 13 + 1, tags_written);
+ gst_buffer_unmap (script_tag, data, -1);
+ exit:
return script_tag;
}
GList *l;
guint32 index_len, allocate_size;
guint32 i, index_skip;
+ GstSegment segment;
+ GstClockTime dur;
if (mux->streamable)
return GST_FLOW_OK;
GstFlvPad *best;
GstClockTime best_time;
GstFlowReturn ret;
- GSList *sl;
- gboolean eos = TRUE;
if (mux->state == GST_FLV_MUX_STATE_HEADER) {
+ GstSegment segment;
+
if (mux->collect->data == NULL) {
GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
("No input streams configured"));
if (!mux->streamable && GST_CLOCK_TIME_IS_VALID (best_time)
&& best_time / GST_MSECOND > G_MAXINT32) {
GST_WARNING_OBJECT (mux, "Timestamp larger than FLV supports - EOS");
- eos = TRUE;
+ gst_buffer_unref (buffer);
+ buffer = NULL;
+ best = NULL;
}
- if (!eos && best) {
- return gst_flv_mux_write_buffer (mux, best);
- } else if (eos) {
+ if (best) {
+ return gst_flv_mux_write_buffer (mux, best, buffer);
+ } else {
gst_flv_mux_rewrite_header (mux);
gst_pad_push_event (mux->srcpad, gst_event_new_eos ());
- return GST_FLOW_UNEXPECTED;
+ return GST_FLOW_EOS;
- } else {
- return GST_FLOW_OK;
}
}
}
if (G_UNLIKELY (qtmux->state == GST_QT_MUX_STATE_EOS))
- return GST_FLOW_UNEXPECTED;
+ return GST_FLOW_EOS;
- /* select the best buffer */
- walk = qtmux->collect->data;
- while (walk) {
- GstQTPad *pad;
- GstCollectData *data;
-
- data = (GstCollectData *) walk->data;
- pad = (GstQTPad *) data;
-
- walk = g_slist_next (walk);
-
- buf = gst_collect_pads_peek (pads, data);
- if (buf == NULL) {
- GST_LOG_OBJECT (qtmux, "Pad %s has no buffers",
- GST_PAD_NAME (pad->collect.pad));
- continue;
- }
- time = GST_BUFFER_TIMESTAMP (buf);
- gst_buffer_unref (buf);
-
- /* invalid should pass */
- if (G_LIKELY (GST_CLOCK_TIME_IS_VALID (time))) {
- time =
- gst_segment_to_running_time (&data->segment, GST_FORMAT_TIME, time);
- if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (time))) {
- GST_DEBUG_OBJECT (qtmux, "clipping buffer on pad %s outside segment",
- GST_PAD_NAME (data->pad));
- buf = gst_collect_pads_pop (pads, data);
- gst_buffer_unref (buf);
- return GST_FLOW_OK;
- }
- }
-
- if (best_pad == NULL || !GST_CLOCK_TIME_IS_VALID (time) ||
- (GST_CLOCK_TIME_IS_VALID (best_time) && time < best_time)) {
- best_pad = pad;
- best_time = time;
- }
- }
+ best_pad = (GstQTPad *) cdata;
+ /* clipping already converted to running time */
if (best_pad != NULL) {
+ g_assert (buf);
+ best_time = GST_BUFFER_TIMESTAMP (buf);
GST_LOG_OBJECT (qtmux, "selected pad %s with time %" GST_TIME_FORMAT,
GST_PAD_NAME (best_pad->collect.pad), GST_TIME_ARGS (best_time));
- buf = gst_collect_pads_pop (pads, &best_pad->collect);
- buf = gst_buffer_make_writable (buf);
- GST_BUFFER_TIMESTAMP (buf) = best_time;
ret = gst_qt_mux_add_buffer (qtmux, best_pad, buf);
} else {
ret = gst_qt_mux_stop_file (qtmux);
}
static gboolean
- gst_qt_mux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
+ gst_qt_mux_sink_event (GstCollectPads2 * pads, GstCollectData2 * data,
+ GstEvent * event, gpointer user_data)
{
- gboolean ret;
GstQTMux *qtmux;
guint32 avg_bitrate = 0, max_bitrate = 0;
+ GstPad *pad = data->pad;
- qtmux = GST_QT_MUX_CAST (parent);
-
+ qtmux = GST_QT_MUX_CAST (user_data);
switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_CAPS:
+ {
+ GstCaps *caps;
+ GstQTPad *collect_pad;
+
+ gst_event_parse_caps (event, &caps);
+
+ /* find stream data */
+ collect_pad = (GstQTPad *) gst_pad_get_element_private (pad);
+ g_assert (collect_pad);
+ g_assert (collect_pad->set_caps);
+
+ collect_pad->set_caps (pad, caps);
+ break;
+ }
case GST_EVENT_TAG:{
GstTagList *list;
GstTagSetter *setter = GST_TAG_SETTER (qtmux);
/* set up pad functions */
if (audio)
- gst_pad_set_setcaps_function (newpad,
- GST_DEBUG_FUNCPTR (gst_qt_mux_audio_sink_set_caps));
+ collect_pad->set_caps = GST_DEBUG_FUNCPTR (gst_qt_mux_audio_sink_set_caps);
else
- gst_pad_set_setcaps_function (newpad,
- GST_DEBUG_FUNCPTR (gst_qt_mux_video_sink_set_caps));
+ collect_pad->set_caps = GST_DEBUG_FUNCPTR (gst_qt_mux_video_sink_set_caps);
- /* FIXME: hacked way to override/extend the event function of
- * GstCollectPads; because it sets its own event function giving the
- * element no access to events.
- */
- qtmux->collect_event = (GstPadEventFunction) GST_PAD_EVENTFUNC (newpad);
- gst_pad_set_event_function (newpad,
- GST_DEBUG_FUNCPTR (gst_qt_mux_sink_event));
-
gst_pad_set_active (newpad, TRUE);
gst_element_add_pad (element, newpad);
GST_OBJECT_LOCK (demux);
if (context)
gst_query_set_position (query, GST_FORMAT_TIME,
- context->pos - demux->stream_start_time);
+ MAX (context->pos, demux->stream_start_time) -
+ demux->stream_start_time);
else
gst_query_set_position (query, GST_FORMAT_TIME,
- demux->common.segment.position - demux->stream_start_time);
- MAX (demux->common.segment.last_stop, demux->stream_start_time) -
++ MAX (demux->common.segment.position, demux->stream_start_time) -
+ demux->stream_start_time);
GST_OBJECT_UNLOCK (demux);
} else if (format == GST_FORMAT_DEFAULT && context
&& context->default_duration) {
/* estimate using start and current position */
GST_OBJECT_LOCK (demux);
opos = demux->common.offset - demux->common.ebml_segment_start;
- otime = demux->common.segment.last_stop;
+ otime = demux->common.segment.position;
GST_OBJECT_UNLOCK (demux);
+ /* sanitize */
+ time = MAX (time, demux->stream_start_time);
+
/* avoid division by zero in first estimation below */
- if (otime == 0)
+ if (otime <= demux->stream_start_time)
otime = time;
retry:
* segment when we close the current segment. */
memcpy (&seeksegment, &demux->common.segment, sizeof (GstSegment));
- if (!demux->streaming && !demux->common.index &&
- demux->invalid_duration) {
- gst_segment_set_duration (&seeksegment, GST_FORMAT_TIME,
- GST_CLOCK_TIME_NONE);
+ /* pull mode without index means that the actual duration is not known,
+ * we might be playing a file that's still being recorded
+ * so, invalidate our current duration, which is only a moving target,
+ * and should not be used to clamp anything */
++ if (!demux->streaming && !demux->common.index && demux->invalid_duration) {
++ seeksegment.duration = GST_CLOCK_TIME_NONE;
+ }
+
if (event) {
GST_DEBUG_OBJECT (demux, "configuring seek");
- gst_segment_set_seek (&seeksegment, rate, format, flags,
+ gst_segment_do_seek (&seeksegment, rate, format, flags,
cur_type, cur, stop_type, stop, &update);
/* compensate for clip start time */
if (GST_CLOCK_TIME_IS_VALID (demux->stream_start_time)) {
}
}
- gst_segment_set_duration (&seeksegment, GST_FORMAT_TIME,
- demux->common.segment.duration);
+ /* restore segment duration (if any effect),
+ * would be determined again when parsing, but anyway ... */
++ seeksegment.duration = demux->common.segment.duration;
+
flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
keyunit = ! !(flags & GST_SEEK_FLAG_KEY_UNIT);
GST_OBJECT_LOCK (demux);
track = gst_matroska_read_common_get_seek_track (&demux->common, track);
if ((entry = gst_matroska_read_common_do_index_seek (&demux->common, track,
- seeksegment.last_stop, &demux->seek_index, &demux->seek_entry)) ==
+ seeksegment.position, &demux->seek_index, &demux->seek_entry)) ==
NULL) {
/* pull mode without index can scan later on */
- if (demux->common.index || demux->streaming) {
+ if (demux->streaming) {
GST_DEBUG_OBJECT (demux, "No matching seek entry in index");
GST_OBJECT_UNLOCK (demux);
return FALSE;
GST_PAD_STREAM_LOCK (demux->common.sinkpad);
/* pull mode without index can do some scanning */
- if (!demux->streaming && !demux->common.index) {
+ if (!demux->streaming && !entry) {
/* need to stop flushing upstream as we need it next */
if (flush)
- gst_pad_push_event (demux->common.sinkpad, gst_event_new_flush_stop ());
- entry = gst_matroska_demux_search_pos (demux, seeksegment.last_stop);
+ gst_pad_push_event (demux->common.sinkpad,
+ gst_event_new_flush_stop (TRUE));
+ entry = gst_matroska_demux_search_pos (demux, seeksegment.position);
/* keep local copy */
if (entry) {
scan_entry = *entry;
if (keyunit) {
GST_DEBUG_OBJECT (demux, "seek to key unit, adjusting segment start to %"
GST_TIME_FORMAT, GST_TIME_ARGS (entry->time));
- seeksegment.start = entry->time;
- seeksegment.position = entry->time;
- seeksegment.time = entry->time - demux->stream_start_time;
+ seeksegment.start = MAX (entry->time, demux->stream_start_time);
- seeksegment.last_stop = seeksegment.start;
++ seeksegment.position = seeksegment.start;
+ seeksegment.time = seeksegment.start - demux->stream_start_time;
}
exit:
"Setting stream start time to %" GST_TIME_FORMAT,
GST_TIME_ARGS (lace_time));
}
- clace_time = MAX (lace_time, demux->stream_start_time);
- gst_segment_set_newsegment (&demux->common.segment, FALSE,
- demux->common.segment.rate, GST_FORMAT_TIME, clace_time,
- GST_CLOCK_TIME_NONE, clace_time - demux->stream_start_time);
+ if (GST_CLOCK_TIME_IS_VALID (segment->stop))
+ segment_duration = segment->stop - segment->start;
+ else if (GST_CLOCK_TIME_IS_VALID (segment->position))
+ segment_duration = segment->position - segment->start;
+ segment->base += segment_duration / fabs (segment->rate);
- segment->start = lace_time;
++ segment->start = MAX (lace_time, demux->stream_start_time);
+ segment->stop = GST_CLOCK_TIME_NONE;
- segment->position = lace_time - demux->stream_start_time;
++ segment->position = segment->start - demux->stream_start_time;
/* now convey our segment notion downstream */
- gst_matroska_demux_send_event (demux, gst_event_new_new_segment (FALSE,
- demux->common.segment.rate, demux->common.segment.format,
- demux->common.segment.start, demux->common.segment.stop,
- demux->common.segment.start));
- demux->need_newsegment = FALSE;
+ gst_matroska_demux_send_event (demux, gst_event_new_segment (segment));
+ demux->need_segment = FALSE;
}
if (block_duration != -1) {
GST_OBJECT_LOCK (demux);
if (demux->common.segment.duration == -1 ||
- demux->common.segment.duration <
- lace_time - demux->stream_start_time) {
+ demux->stream_start_time + demux->common.segment.duration <
+ last_stop_end) {
- gst_segment_set_duration (&demux->common.segment, GST_FORMAT_TIME,
- last_stop_end - demux->stream_start_time);
+ demux->common.segment.duration =
+ last_stop_end - demux->stream_start_time;
GST_OBJECT_UNLOCK (demux);
gst_element_post_message (GST_ELEMENT_CAST (demux),
gst_message_new_duration (GST_OBJECT_CAST (demux),
/* Close the segment, i.e. update segment stop with the duration
* if no stop was set */
if (GST_CLOCK_TIME_IS_VALID (demux->last_stop_end) &&
- !GST_CLOCK_TIME_IS_VALID (demux->common.segment.stop)) {
+ !GST_CLOCK_TIME_IS_VALID (demux->common.segment.stop) &&
+ GST_CLOCK_TIME_IS_VALID (demux->common.segment.start) &&
+ demux->last_stop_end > demux->common.segment.start) {
- /* arrange to accumulate duration downstream, but avoid sending
- * newsegment with decreasing start (w.r.t. sync newsegment events) */
- GstEvent *event =
- gst_event_new_new_segment_full (TRUE, demux->common.segment.rate,
- demux->common.segment.applied_rate, demux->common.segment.format,
- demux->last_stop_end, demux->last_stop_end,
- demux->common.segment.time + (demux->last_stop_end -
- demux->common.segment.start));
+ GstSegment segment = demux->common.segment;
+ GstEvent *event;
+
- segment.stop = MAX (demux->last_stop_end, segment.start);
++ segment.stop = demux->last_stop_end;
+ event = gst_event_new_segment (&segment);
gst_matroska_demux_send_event (demux, event);
}
break;
}
- return gst_pad_event_default (pad, event);
+ return gst_pad_event_default (pad, parent, event);
}
+ static void
+ gst_matroska_mux_build_vobsub_private (GstMatroskaTrackContext * context,
+ const guint * clut)
+ {
+ gchar *clutv[17];
+ gchar *sclut;
+ gint i;
+ guint32 col;
+ gdouble y, u, v;
+ guint8 r, g, b;
+
+ /* produce comma-separated list in hex format */
+ for (i = 0; i < 16; ++i) {
+ col = clut[i];
+ /* replicate vobsub's slightly off RGB conversion calculation */
+ y = (((col >> 16) & 0xff) - 16) * 255 / 219;
+ u = ((col >> 8) & 0xff) - 128;
+ v = (col & 0xff) - 128;
+ r = CLAMP (1.0 * y + 1.4022 * u, 0, 255);
+ g = CLAMP (1.0 * y - 0.3456 * u - 0.7145 * v, 0, 255);
+ b = CLAMP (1.0 * y + 1.7710 * v, 0, 255);
+ clutv[i] = g_strdup_printf ("%02x%02x%02x", r, g, b);
+ }
+ clutv[i] = NULL;
+ sclut = g_strjoinv (",", clutv);
+
+ /* build codec private; only palette for now */
+ g_free (context->codec_priv);
+ context->codec_priv = (guint8 *) g_strdup_printf ("palette: %s", sclut);
+ /* include terminating 0 */
+ context->codec_priv_size = strlen ((gchar *) context->codec_priv) + 1;
+ g_free (sclut);
+ for (i = 0; i < 16; ++i) {
+ g_free (clutv[i]);
+ }
+ }
+
+
/**
* gst_matroska_mux_handle_sink_event:
* @pad: Pad which received the event.
* Returns: #TRUE on success.
*/
static gboolean
- gst_matroska_mux_handle_sink_event (GstPad * pad, GstObject * parent,
- GstEvent * event)
+ gst_matroska_mux_handle_sink_event (GstCollectPads2 * pads,
+ GstCollectData2 * data, GstEvent * event, gpointer user_data)
{
-- GstMatroskaTrackContext *context;
GstMatroskaPad *collect_pad;
- GstMatroskaMux *mux = GST_MATROSKA_MUX (parent);
++ GstMatroskaTrackContext *context;
+ GstMatroskaMux *mux;
+ GstPad *pad;
GstTagList *list;
- gboolean ret = TRUE;
++ gboolean ret = FALSE;
+
+ mux = GST_MATROSKA_MUX (user_data);
+ collect_pad = (GstMatroskaPad *) data;
+ pad = data->pad;
+ context = collect_pad->track;
+ g_assert (context);
switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_CAPS:{
+ GstCaps *caps;
+
+ collect_pad = (GstMatroskaPad *) gst_pad_get_element_private (pad);
+ gst_event_parse_caps (event, &caps);
+
+ ret = collect_pad->capsfunc (pad, caps);
+ gst_event_unref (event);
+ event = NULL;
+ break;
+ }
case GST_EVENT_TAG:{
gchar *lang = NULL;
event = NULL;
break;
}
- case GST_EVENT_NEWSEGMENT:{
- GstFormat format;
+ case GST_EVENT_SEGMENT:{
+ const GstSegment *segment;
- gst_event_parse_new_segment (event, NULL, NULL, &format, NULL, NULL,
- NULL);
- if (format != GST_FORMAT_TIME) {
+ gst_event_parse_segment (event, &segment);
+ if (segment->format != GST_FORMAT_TIME) {
- ret = FALSE;
gst_event_unref (event);
event = NULL;
}
break;
}
- /* now GstCollectPads can take care of the rest, e.g. EOS */
- if (event)
- ret = mux->collect_event (pad, parent, event);
-
+ /* now GstCollectPads2 can take care of the rest, e.g. EOS */
- if (event)
- return FALSE;
- else
- return TRUE;
+ return ret;
}
+ static void
+ gst_matroska_mux_set_codec_id (GstMatroskaTrackContext * context,
+ const char *id)
+ {
+ g_assert (context && id);
+ if (context->codec_id)
+ g_free (context->codec_id);
+ context->codec_id = g_strdup (id);
+ }
/**
* gst_matroska_mux_video_pad_setcaps:
/* extract codec_data, may turn out needed */
value = gst_structure_get_value (structure, "codec_data");
if (value)
- codec_buf = gst_value_get_buffer (value);
+ codec_buf = (GstBuffer *) gst_value_get_buffer (value);
/* find type */
- if (!strcmp (mimetype, "video/x-raw-yuv")) {
+ if (!strcmp (mimetype, "video/x-raw")) {
+ const gchar *fstr;
- context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_UNCOMPRESSED);
+ gst_matroska_mux_set_codec_id (context,
+ GST_MATROSKA_CODEC_ID_VIDEO_UNCOMPRESSED);
- gst_structure_get_fourcc (structure, "format", &videocontext->fourcc);
+ fstr = gst_structure_get_string (structure, "format");
+ if (fstr && strlen (fstr) == 4)
+ videocontext->fourcc = GST_STR_FOURCC (fstr);
+ } else if (!strcmp (mimetype, "image/jpeg")) {
- context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_MJPEG);
++ gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_VIDEO_MJPEG);
} else if (!strcmp (mimetype, "video/x-xvid") /* MS/VfW compatibility cases */
||!strcmp (mimetype, "video/x-huffyuv")
|| !strcmp (mimetype, "video/x-divx")
/* process codec private/initialization data, if any */
if (codec_buf) {
- size += GST_BUFFER_SIZE (codec_buf);
+ size += gst_buffer_get_size (codec_buf);
bih = g_realloc (bih, size);
GST_WRITE_UINT32_LE (&bih->size, size);
- memcpy ((guint8 *) bih + sizeof (gst_riff_strf_vids),
- GST_BUFFER_DATA (codec_buf), GST_BUFFER_SIZE (codec_buf));
+ gst_buffer_extract (codec_buf, 0,
+ (guint8 *) bih + sizeof (gst_riff_strf_vids), -1);
}
- context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_VIDEO_VFW_FOURCC);
+ gst_matroska_mux_set_codec_id (context,
+ GST_MATROSKA_CODEC_ID_VIDEO_VFW_FOURCC);
context->codec_priv = (gpointer) bih;
context->codec_priv_size = size;
} else if (!strcmp (mimetype, "video/x-h264")) {
goto refuse_caps;
}
- /* FIXME: where is this spec'ed out? (tpm) */
- if ((width == 8 && signedness) || (width >= 16 && !signedness)) {
- GST_DEBUG_OBJECT (mux, "8-bit PCM must be unsigned, 16-bit PCM signed");
- goto refuse_caps;
- }
-
- audiocontext->bitdepth = depth;
- if (endianness == G_BIG_ENDIAN)
- gst_matroska_mux_set_codec_id (context,
- GST_MATROSKA_CODEC_ID_AUDIO_PCM_INT_BE);
- else
- gst_matroska_mux_set_codec_id (context,
- GST_MATROSKA_CODEC_ID_AUDIO_PCM_INT_LE);
-
- } else if (!strcmp (mimetype, "audio/x-raw-float")) {
- gint width;
+ switch (GST_AUDIO_INFO_FORMAT (&info)) {
+ case GST_AUDIO_FORMAT_U8:
+ case GST_AUDIO_FORMAT_S16BE:
+ case GST_AUDIO_FORMAT_S16LE:
+ case GST_AUDIO_FORMAT_S24BE:
+ case GST_AUDIO_FORMAT_S24LE:
+ case GST_AUDIO_FORMAT_S32BE:
+ case GST_AUDIO_FORMAT_S32LE:
+ if (GST_AUDIO_INFO_WIDTH (&info) != GST_AUDIO_INFO_DEPTH (&info)) {
+ GST_DEBUG_OBJECT (mux, "width must be same as depth!");
+ goto refuse_caps;
+ }
+ if (GST_AUDIO_INFO_IS_BIG_ENDIAN (&info))
- context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_PCM_INT_BE);
++ gst_matroska_mux_set_codec_id (context,
++ GST_MATROSKA_CODEC_ID_AUDIO_PCM_INT_BE);
+ else
- context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_PCM_INT_LE);
++ gst_matroska_mux_set_codec_id (context,
++ GST_MATROSKA_CODEC_ID_AUDIO_PCM_INT_LE);
+ break;
-
+ case GST_AUDIO_FORMAT_F32LE:
+ case GST_AUDIO_FORMAT_F64LE:
- context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_PCM_FLOAT);
++ gst_matroska_mux_set_codec_id (context,
++ GST_MATROSKA_CODEC_ID_AUDIO_PCM_FLOAT);
+ break;
- if (!gst_structure_get_int (structure, "width", &width)) {
- GST_DEBUG_OBJECT (mux, "broken caps, width field missing");
- goto refuse_caps;
+ default:
+ GST_DEBUG_OBJECT (mux, "wrong format in raw audio caps");
+ goto refuse_caps;
}
- audiocontext->bitdepth = width;
- gst_matroska_mux_set_codec_id (context,
- GST_MATROSKA_CODEC_ID_AUDIO_PCM_FLOAT);
-
+ audiocontext->bitdepth = GST_AUDIO_INFO_WIDTH (&info);
-
} else if (!strcmp (mimetype, "audio/x-vorbis")) {
const GValue *streamheader;
/* process codec private/initialization data, if any */
if (buf) {
- memcpy ((guint8 *) codec_priv + WAVEFORMATEX_SIZE,
- GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
+ gst_buffer_extract (buf, 0,
+ (guint8 *) codec_priv + WAVEFORMATEX_SIZE, -1);
}
- context->codec_id = g_strdup (GST_MATROSKA_CODEC_ID_AUDIO_ACM);
+ gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_AUDIO_ACM);
context->codec_priv = (gpointer) codec_priv;
context->codec_priv_size = codec_priv_size;
}
GstMatroskaPad *collect_pad;
const gchar *mimetype;
GstStructure *structure;
- const GstBuffer *buf = NULL;
+ const GValue *value = NULL;
++ GstBuffer *buf = NULL;
+ gchar *id = NULL;
+ gboolean ret = TRUE;
mux = GST_MATROSKA_MUX (GST_PAD_PARENT (pad));
if (!kate_streamheader_to_codecdata (streamheader, context)) {
GST_ELEMENT_ERROR (mux, STREAM, MUX, (NULL),
("kate stream headers missing or malformed"));
- return FALSE;
- }
- return TRUE;
+ ret = FALSE;
+ goto exit;
+ }
+ } else if (!strcmp (mimetype, "text/plain")) {
+ gst_matroska_mux_set_codec_id (context,
+ GST_MATROSKA_CODEC_ID_SUBTITLE_UTF8);
+ } else if (!strcmp (mimetype, "application/x-ssa")) {
+ gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_SUBTITLE_SSA);
+ } else if (!strcmp (mimetype, "application/x-ass")) {
+ gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_SUBTITLE_ASS);
+ } else if (!strcmp (mimetype, "application/x-usf")) {
+ gst_matroska_mux_set_codec_id (context, GST_MATROSKA_CODEC_ID_SUBTITLE_USF);
+ } else if (!strcmp (mimetype, "video/x-dvd-subpicture")) {
+ gst_matroska_mux_set_codec_id (context,
+ GST_MATROSKA_CODEC_ID_SUBTITLE_VOBSUB);
+ } else {
+ id = NULL;
+ ret = FALSE;
+ goto exit;
}
- return FALSE;
+ /* maybe some private data, e.g. vobsub */
+ value = gst_structure_get_value (structure, "codec_data");
+ if (value)
+ buf = gst_value_get_buffer (value);
+ if (buf != NULL) {
- guint8 *priv_data = NULL;
- guint priv_data_size = 0;
++ guint8 *priv_data = NULL, *priv_buffer_data;
++ gsize priv_data_size = 0;
+
- priv_data_size = GST_BUFFER_SIZE (buf);
++ priv_buffer_data =
++ gst_buffer_map (buf, &priv_data_size, NULL, GST_MAP_READ);
+ if (priv_data_size > SUBTITLE_MAX_CODEC_PRIVATE) {
+ GST_WARNING_OBJECT (mux, "pad %" GST_PTR_FORMAT " subtitle private data"
+ " exceeded maximum (%d); discarding", pad,
+ SUBTITLE_MAX_CODEC_PRIVATE);
++ gst_buffer_unmap (buf, priv_data, priv_data_size);
+ return TRUE;
+ }
+
+ if (context->codec_priv != NULL)
+ g_free (context->codec_priv);
+
+ priv_data = g_malloc0 (priv_data_size);
- memcpy (priv_data, GST_BUFFER_DATA (buf), priv_data_size);
++ memcpy (priv_data, priv_buffer_data, priv_data_size);
+ context->codec_priv = priv_data;
+ context->codec_priv_size = priv_data_size;
++ gst_buffer_unmap (buf, priv_buffer_data, priv_data_size);
+ }
+
+ GST_DEBUG_OBJECT (pad, "codec_id %s, codec data size %u",
+ GST_STR_NULL (context->codec_id), context->codec_priv_size);
+
+ exit:
+ /* free default if modified */
+ if (id)
+ g_free (id);
+
+ return ret;
}
GstMatroskamuxPad *newpad;
gchar *name = NULL;
const gchar *pad_name = NULL;
- GstPadSetCapsFunction setcapsfunc = NULL;
+ GstMatroskaCapsFunc capsfunc = NULL;
GstMatroskaTrackContext *context = NULL;
gint pad_id;
+ gboolean locked = TRUE;
+ gchar *id = NULL;
- if (templ == gst_element_class_get_pad_template (klass, "audio_%d")) {
+ if (templ == gst_element_class_get_pad_template (klass, "audio_%u")) {
/* don't mix named and unnamed pads, if the pad already exists we fail when
* trying to add it */
- if (req_name != NULL && sscanf (req_name, "audio_%d", &pad_id) == 1) {
+ if (req_name != NULL && sscanf (req_name, "audio_%u", &pad_id) == 1) {
pad_name = req_name;
} else {
- name = g_strdup_printf ("audio_%d", mux->num_a_streams++);
+ name = g_strdup_printf ("audio_%u", mux->num_a_streams++);
pad_name = name;
}
- setcapsfunc = GST_DEBUG_FUNCPTR (gst_matroska_mux_audio_pad_setcaps);
+ capsfunc = GST_DEBUG_FUNCPTR (gst_matroska_mux_audio_pad_setcaps);
context = (GstMatroskaTrackContext *)
g_new0 (GstMatroskaTrackAudioContext, 1);
context->type = GST_MATROSKA_TRACK_TYPE_AUDIO;
collect_pad->track = context;
gst_matroska_pad_reset (collect_pad, FALSE);
-
- /* FIXME: hacked way to override/extend the event function of
- * GstCollectPads; because it sets its own event function giving the
- * element no access to events.
- * TODO GstCollectPads should really give its 'users' a clean chance to
- * properly handle events that are not meant for collectpads itself.
- * Perhaps a callback or so, though rejected (?) in #340060.
- * This would allow (clean) transcoding of info from demuxer/streams
- * to another muxer */
- mux->collect_event = (GstPadEventFunction) GST_PAD_EVENTFUNC (newpad);
- gst_pad_set_event_function (GST_PAD (newpad),
- GST_DEBUG_FUNCPTR (gst_matroska_mux_handle_sink_event));
+ collect_pad->track->codec_id = id;
- gst_pad_set_setcaps_function (GST_PAD (newpad), setcapsfunc);
+ collect_pad->capsfunc = capsfunc;
gst_pad_set_active (GST_PAD (newpad), TRUE);
if (!gst_element_add_pad (element, GST_PAD (newpad)))
goto pad_add_failed;
mux->state = GST_MATROSKA_MUX_STATE_DATA;
}
- do {
- /* which stream to write from? */
- best = gst_matroska_mux_best_pad (mux, &popped);
+ /* provided with stream to write from */
+ best = (GstMatroskaPad *) data;
- /* if there is no best pad, we have reached EOS */
- if (best == NULL) {
- /* buffer popped, but none returned means it was clipped */
- if (popped)
- break;
- GST_DEBUG_OBJECT (mux, "No best pad finishing...");
- if (!mux->streamable) {
- gst_matroska_mux_finish (mux);
- } else {
- GST_DEBUG_OBJECT (mux, "... but streamable, nothing to finish");
- }
- gst_pad_push_event (mux->srcpad, gst_event_new_eos ());
- ret = GST_FLOW_EOS;
- break;
+ /* if there is no best pad, we have reached EOS */
+ if (best == NULL) {
+ GST_DEBUG_OBJECT (mux, "No best pad finishing...");
+ if (!mux->streamable) {
+ gst_matroska_mux_finish (mux);
+ } else {
+ GST_DEBUG_OBJECT (mux, "... but streamable, nothing to finish");
}
- GST_DEBUG_OBJECT (best->collect.pad, "best pad - buffer ts %"
- GST_TIME_FORMAT " dur %" GST_TIME_FORMAT,
- GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (best->buffer)),
- GST_TIME_ARGS (GST_BUFFER_DURATION (best->buffer)));
+ gst_pad_push_event (mux->srcpad, gst_event_new_eos ());
- ret = GST_FLOW_UNEXPECTED;
++ ret = GST_FLOW_EOS;
+ goto exit;
+ }
- /* make note of first and last encountered timestamps, so we can calculate
- * the actual duration later when we send an updated header on eos */
- if (GST_BUFFER_TIMESTAMP_IS_VALID (best->buffer)) {
- GstClockTime start_ts = GST_BUFFER_TIMESTAMP (best->buffer);
- GstClockTime end_ts = start_ts;
+ /* if we have a best stream, should also have a buffer */
+ g_assert (buf);
- if (GST_BUFFER_DURATION_IS_VALID (best->buffer))
- end_ts += GST_BUFFER_DURATION (best->buffer);
- else if (best->track->default_duration)
- end_ts += best->track->default_duration;
+ GST_DEBUG_OBJECT (best->collect.pad, "best pad - buffer ts %"
+ GST_TIME_FORMAT " dur %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
+ GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
- if (!GST_CLOCK_TIME_IS_VALID (best->end_ts) || end_ts > best->end_ts)
- best->end_ts = end_ts;
+ /* make note of first and last encountered timestamps, so we can calculate
+ * the actual duration later when we send an updated header on eos */
+ if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
+ GstClockTime start_ts = GST_BUFFER_TIMESTAMP (buf);
+ GstClockTime end_ts = start_ts;
- if (G_UNLIKELY (best->start_ts == GST_CLOCK_TIME_NONE ||
- start_ts < best->start_ts))
- best->start_ts = start_ts;
- }
+ if (GST_BUFFER_DURATION_IS_VALID (buf))
+ end_ts += GST_BUFFER_DURATION (buf);
+ else if (best->track->default_duration)
+ end_ts += best->track->default_duration;
+
+ if (!GST_CLOCK_TIME_IS_VALID (best->end_ts) || end_ts > best->end_ts)
+ best->end_ts = end_ts;
+
+ if (G_UNLIKELY (best->start_ts == GST_CLOCK_TIME_NONE ||
+ start_ts < best->start_ts))
+ best->start_ts = start_ts;
+ }
- /* write one buffer */
- ret = gst_matroska_mux_write_data (mux, best);
- } while (ret == GST_FLOW_OK && !popped);
+ /* write one buffer */
+ ret = gst_matroska_mux_write_data (mux, best, buf);
+ exit:
return ret;
}
/* all information needed for one matroska stream */
typedef struct
{
- GstCollectData collect; /* we extend the CollectData */
+ GstCollectData2 collect; /* we extend the CollectData */
+ GstMatroskaCapsFunc capsfunc;
GstMatroskaTrackContext *track;
- GstBuffer *buffer; /* the queued buffer for this pad */
-
guint64 duration;
GstClockTime start_ts;
GstClockTime end_ts; /* last timestamp + (if available) duration */
DEBUG_ELEMENT_STOP (common, ebml, "CueTrackPositions", ret);
- if ((ret == GST_FLOW_OK || ret == GST_FLOW_UNEXPECTED)
+ /* (e.g.) lavf typically creates entries without a block number,
+ * which is bogus and leads to contradictory information */
+ if (common->index->len) {
+ GstMatroskaIndex *last_idx;
+
+ last_idx = &g_array_index (common->index, GstMatroskaIndex,
+ common->index->len - 1);
+ if (last_idx->block == idx.block && last_idx->pos == idx.pos &&
+ last_idx->track == idx.track && idx.time > last_idx->time) {
+ GST_DEBUG_OBJECT (common, "Cue entry refers to same location, "
+ "but has different time than previous entry; discarding");
+ idx.track = 0;
+ }
+ }
+
+ if ((ret == GST_FLOW_OK || ret == GST_FLOW_EOS)
&& idx.pos != (guint64) - 1 && idx.track > 0) {
g_array_append_val (common->index, idx);
(*nentries)++;
return GST_FLOW_ERROR;
}
stdio_write_error:
- {
- GST_ELEMENT_ERROR (multifilesink, RESOURCE, WRITE,
- ("Error while writing to file."), (NULL));
- gst_buffer_unmap (buffer, data, size);
- return GST_FLOW_ERROR;
+ switch (errno) {
+ case ENOSPC:
+ GST_ELEMENT_ERROR (multifilesink, RESOURCE, NO_SPACE_LEFT,
+ ("Error while writing to file."), ("%s", g_strerror (errno)));
+ break;
+ default:
+ GST_ELEMENT_ERROR (multifilesink, RESOURCE, WRITE,
+ ("Error while writing to file."), ("%s", g_strerror (errno)));
}
++ gst_buffer_unmap (buffer, data, size);
+ return GST_FLOW_ERROR;
}
-static GstBufferListItem
-buffer_list_calc_size (GstBuffer ** buf, guint group, guint idx, gpointer data)
+static gboolean
+buffer_list_calc_size (GstBuffer ** buf, guint idx, gpointer data)
{
guint *p_size = data;
guint buf_size;
GstMultipartPadData *multipartpad;
multipartpad = (GstMultipartPadData *)
- gst_collect_pads_add_pad (multipart_mux->collect, newpad,
- sizeof (GstMultipartPadData), NULL);
+ gst_collect_pads2_add_pad (multipart_mux->collect, newpad,
+ sizeof (GstMultipartPadData));
/* save a pointer to our data in the pad */
+ multipartpad->pad = newpad;
gst_pad_set_element_private (newpad, multipartpad);
multipart_mux->numpads++;
}
#include <gst/rtp/gstrtpbuffer.h>
#include <gst/rtp/gstrtcpbuffer.h>
-#include <gst/netbuffer/gstnetbuffer.h>
+ #include <gst/glib-compat-private.h>
+
#include "gstrtpbin-marshal.h"
#include "rtpsession.h"
static GstStateChangeReturn gst_wavparse_change_state (GstElement * element,
GstStateChange transition);
-static const GstQueryType *gst_wavparse_get_query_types (GstPad * pad);
-static gboolean gst_wavparse_pad_query (GstPad * pad, GstQuery * query);
-static gboolean gst_wavparse_pad_convert (GstPad * pad,
- GstFormat src_format,
+static gboolean gst_wavparse_pad_query (GstPad * pad, GstObject * parent,
+ GstQuery * query);
+static gboolean gst_wavparse_pad_convert (GstPad * pad, GstFormat src_format,
gint64 src_value, GstFormat * dest_format, gint64 * dest_value);
-static GstFlowReturn gst_wavparse_chain (GstPad * pad, GstBuffer * buf);
-static gboolean gst_wavparse_sink_event (GstPad * pad, GstEvent * event);
+static GstFlowReturn gst_wavparse_chain (GstPad * pad, GstObject * parent,
+ GstBuffer * buf);
+static gboolean gst_wavparse_sink_event (GstPad * pad, GstObject * parent,
+ GstEvent * event);
static void gst_wavparse_loop (GstPad * pad);
-static gboolean gst_wavparse_srcpad_event (GstPad * pad, GstEvent * event);
+static gboolean gst_wavparse_srcpad_event (GstPad * pad, GstObject * parent,
+ GstEvent * event);
+ static void gst_wavparse_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+ static void gst_wavparse_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+
+ #define DEFAULT_IGNORE_LENGTH FALSE
+
+ enum
+ {
+ PROP_0,
+ PROP_IGNORE_LENGTH,
+ };
+
static GstStaticPadTemplate sink_template_factory =
-GST_STATIC_PAD_TEMPLATE ("wavparse_sink",
+GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("audio/x-wav")
object_class->dispose = gst_wavparse_dispose;
+ object_class->set_property = gst_wavparse_set_property;
+ object_class->get_property = gst_wavparse_get_property;
+
+ /**
+ * GstWavParse:ignore-length
+ *
+ * This selects whether the length found in a data chunk
+ * should be ignored. This may be useful for streamed audio
+ * where the length is unknown until the end of streaming,
+ * and various software/hardware just puts some random value
+ * in there and hopes it doesn't break too much.
+ *
+ * Since: 0.10.36
+ */
+ g_object_class_install_property (object_class, PROP_IGNORE_LENGTH,
+ g_param_spec_boolean ("ignore-length",
+ "Ignore length",
+ "Ignore length from the Wave header",
+ DEFAULT_IGNORE_LENGTH, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
+ );
+
gstelement_class->change_state = gst_wavparse_change_state;
gstelement_class->send_event = gst_wavparse_send_event;
+
+ /* register pads */
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&sink_template_factory));
+
+ src_template = gst_pad_template_new ("src", GST_PAD_SRC,
+ GST_PAD_ALWAYS, gst_riff_create_audio_template_caps ());
+ gst_element_class_add_pad_template (gstelement_class, src_template);
+
+ gst_element_class_set_details_simple (gstelement_class, "WAV audio demuxer",
+ "Codec/Demuxer/Audio",
+ "Parse a .wav file into raw audio",
+ "Erik Walthinsen <omega@cse.ogi.edu>");
}
static void
GST_DEBUG_FUNCPTR (gst_wavparse_pad_query));
gst_pad_set_event_function (wavparse->srcpad,
GST_DEBUG_FUNCPTR (gst_wavparse_srcpad_event));
-
- GST_DEBUG_OBJECT (wavparse, "srcpad created");
+ gst_element_add_pad (GST_ELEMENT_CAST (wavparse), wavparse->srcpad);
}
- /* Compute (value * nom) % denom, avoiding overflow. This can be used
- * to perform ceiling or rounding division together with
- * gst_util_uint64_scale[_int]. */
- #define uint64_scale_modulo(val, nom, denom) \
- ((val % denom) * (nom % denom) % denom)
-
- /* Like gst_util_uint64_scale, but performs ceiling division. */
- static guint64
- uint64_ceiling_scale_int (guint64 val, gint num, gint denom)
- {
- guint64 result = gst_util_uint64_scale_int (val, num, denom);
-
- if (uint64_scale_modulo (val, num, denom) == 0)
- return result;
- else
- return result + 1;
- }
-
- /* Like gst_util_uint64_scale, but performs ceiling division. */
- static guint64
- uint64_ceiling_scale (guint64 val, guint64 num, guint64 denom)
- {
- guint64 result = gst_util_uint64_scale (val, num, denom);
-
- if (uint64_scale_modulo (val, num, denom) == 0)
- return result;
- else
- return result + 1;
- }
-
-
/* FIXME: why is that not in use? */
#if 0
static void
if (gst_adapter_available (wav->adapter) < 8)
return FALSE;
- data = gst_adapter_peek (wav->adapter, 8);
+ data = gst_adapter_map (wav->adapter, 8);
*tag = GST_READ_UINT32_LE (data);
*size = GST_READ_UINT32_LE (data + 4);
+ gst_adapter_unmap (wav->adapter);
- GST_DEBUG ("Next chunk size is %d bytes, type %" GST_FOURCC_FORMAT, *size,
+ GST_DEBUG ("Next chunk size is %u bytes, type %" GST_FOURCC_FORMAT, *size,
GST_FOURCC_ARGS (*tag));
return TRUE;
if (gst_wavparse_calculate_duration (wav)) {
gst_segment_init (&wav->segment, GST_FORMAT_TIME);
- wav->segment.duration = wav->duration;
+ if (!wav->ignore_length)
- gst_segment_set_duration (&wav->segment, GST_FORMAT_TIME, wav->duration);
++ wav->segment.duration = wav->duration;
} else {
/* no bitrate, let downstream peer do the math, we'll feed it bytes. */
gst_segment_init (&wav->segment, GST_FORMAT_BYTES);
- wav->segment.duration = wav->datasize;
+ if (!wav->ignore_length)
- gst_segment_set_duration (&wav->segment, GST_FORMAT_BYTES, wav->datasize);
++ wav->segment.duration = wav->datasize;
}
/* now we have all the info to perform a pending seek if any, if no
#include <unistd.h>
#include "gst/video/video.h"
+#include "gst/video/gstvideometa.h"
+#include "gst/video/gstvideopool.h"
#include <gstv4l2bufferpool.h>
+
#include "gstv4l2src.h"
-#ifdef HAVE_EXPERIMENTAL
#include "gstv4l2sink.h"
-#endif
#include "v4l2_calls.h"
#include "gst/gst-i18n-plugin.h"
+ #include <gst/glib-compat-private.h>
/* videodev2.h is not versioned and we can't easily check for the presence
* of enum values at compile time, but the V4L2_CAP_VIDEO_OUTPUT_OVERLAY define
$(GST_PLUGINS_BASE_LIBS) -lgstinterfaces-@GST_MAJORMINOR@ \
$(LDADD)
-elements_videocrop_LDADD = $(GST_BASE_LIBS) $(LDADD)
-elements_videocrop_CFLAGS = $(GST_BASE_CFLAGS) $(CFLAGS) $(AM_CFLAGS)
+ elements_udpsrc_CFLAGS = $(AM_CFLAGS) $(GIO_CFLAGS)
+ elements_udpsrc_LDADD = $(LDADD) $(GIO_LIBS)
+
+elements_videocrop_LDADD = $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) -lgstvideo-$(GST_MAJORMINOR) $(LDADD)
+elements_videocrop_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(CFLAGS) $(AM_CFLAGS)
elements_videofilter_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(CFLAGS) $(AM_CFLAGS)
elements_videofilter_LDADD = $(GST_PLUGINS_BASE_LIBS) -lgstvideo-$(GST_MAJORMINOR) $(LDADD)
}
static void
- ev = gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME, 0, -1, 0);
+ send_newsegment_and_empty_buffer (void)
+ {
+ GstBuffer *buf;
+ GstEvent *ev;
++ GstSegment segment;
+
+ fail_unless (g_list_length (events) == 0);
+
++ gst_segment_init (&segment, GST_FORMAT_TIME);
++ ev = gst_event_new_segment (&segment);
+ fail_unless (gst_pad_push_event (mysrcpad, ev),
+ "Pushing newsegment event failed");
+
+ buf = test_buffer_new (0.0);
+ GST_BUFFER_SIZE (buf) = 0;
+ GST_BUFFER_DURATION (buf) = 0;
+ GST_BUFFER_OFFSET_END (buf) = GST_BUFFER_OFFSET (buf);
+ fail_unless (gst_pad_push (mysrcpad, buf) == GST_FLOW_OK);
+
+ fail_unless (g_list_length (events) == 1);
+ fail_unless (events->data == ev);
+ gst_mini_object_unref ((GstMiniObject *) events->data);
+ events = g_list_remove (events, ev);
+
+ fail_unless (g_list_length (buffers) == 1);
+ fail_unless (buffers->data == buf);
+ gst_mini_object_unref ((GstMiniObject *) buffers->data);
+ buffers = g_list_remove (buffers, buf);
+ }
+
+ static void
cleanup_rgvolume (GstElement * element)
{
GST_DEBUG ("cleanup_rgvolume");
set_playing_state (element);
- tag_list = gst_tag_list_new ();
+ send_newsegment_and_empty_buffer ();
+
+ tag_list = gst_tag_list_new_empty ();
gst_tag_list_add (tag_list, GST_TAG_MERGE_REPLACE,
GST_TAG_TRACK_GAIN, +4.95, GST_TAG_TRACK_PEAK, 0.59463,
GST_TAG_ALBUM_GAIN, -1.54, GST_TAG_ALBUM_PEAK, 0.693415,
"pre-amp", -6.00, "fallback-gain", +1.23, NULL);
set_playing_state (element);
- tag_list = gst_tag_list_new ();
+ send_newsegment_and_empty_buffer ();
+
+ tag_list = gst_tag_list_new_empty ();
gst_tag_list_add (tag_list, GST_TAG_MERGE_REPLACE,
GST_TAG_TRACK_GAIN, -3.45, GST_TAG_TRACK_PEAK, 1.0,
GST_TAG_ALBUM_GAIN, +2.09, GST_TAG_ALBUM_PEAK, 1.0, NULL);
"pre-amp", -6.00, "fallback-gain", -3.00, NULL);
set_playing_state (element);
- tag_list = gst_tag_list_new ();
+ send_newsegment_and_empty_buffer ();
+
+ tag_list = gst_tag_list_new_empty ();
gst_tag_list_add (tag_list, GST_TAG_MERGE_REPLACE,
GST_TAG_TRACK_GAIN, +3.5, GST_TAG_TRACK_PEAK, 1.0,
GST_TAG_ALBUM_GAIN, -0.5, GST_TAG_ALBUM_PEAK, 1.0, NULL);
"pre-amp", -6.00, "fallback-gain", +1.23, NULL);
set_playing_state (element);
- tag_list = gst_tag_list_new ();
+ send_newsegment_and_empty_buffer ();
+
+ tag_list = gst_tag_list_new_empty ();
gst_tag_list_add (tag_list, GST_TAG_MERGE_REPLACE,
GST_TAG_TRACK_GAIN, +2.11, GST_TAG_TRACK_PEAK, 1.0, NULL);
fail_unless (send_tag_event (element, gst_event_new_tag (tag_list)) == NULL);
"pre-amp", -6.00, "fallback-gain", +1.23, NULL);
set_playing_state (element);
- tag_list = gst_tag_list_new ();
+ send_newsegment_and_empty_buffer ();
+
+ tag_list = gst_tag_list_new_empty ();
gst_tag_list_add (tag_list, GST_TAG_MERGE_REPLACE,
GST_TAG_ALBUM_GAIN, +3.73, GST_TAG_ALBUM_PEAK, 1.0, NULL);
fail_unless (send_tag_event (element, gst_event_new_tag (tag_list)) == NULL);
"pre-amp", +0.00, "fallback-gain", +1.23, NULL);
set_playing_state (element);
- tag_list = gst_tag_list_new ();
+ send_newsegment_and_empty_buffer ();
+
+ tag_list = gst_tag_list_new_empty ();
gst_tag_list_add (tag_list, GST_TAG_MERGE_REPLACE,
GST_TAG_TRACK_GAIN, +3.50, GST_TAG_TRACK_PEAK, 1.0, NULL);
fail_unless (send_tag_event (element, gst_event_new_tag (tag_list)) == NULL);
"headroom", +0.00, "pre-amp", +0.00, "fallback-gain", +1.23, NULL);
set_playing_state (element);
- tag_list = gst_tag_list_new ();
+ send_newsegment_and_empty_buffer ();
+
+ tag_list = gst_tag_list_new_empty ();
gst_tag_list_add (tag_list, GST_TAG_MERGE_REPLACE,
GST_TAG_TRACK_GAIN, 0.00, GST_TAG_TRACK_PEAK, 0.2,
GST_TAG_REFERENCE_LEVEL, 83., NULL);