mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-26 17:18:15 +00:00
Merge remote-tracking branch 'origin/master' into 0.11
Conflicts: ext/theora/gsttheoraenc.c gst-libs/gst/tag/gstexiftag.c gst/adder/gstadder.c gst/adder/gstadder.h gst/playback/gstdecodebin2.c gst/playback/gstsubtitleoverlay.c tests/check/libs/tag.c
This commit is contained in:
commit
f562a29284
20 changed files with 870 additions and 613 deletions
|
@ -310,6 +310,8 @@ gst_ogg_pad_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
|
|||
if (ogg->pullmode) {
|
||||
seekable = TRUE;
|
||||
stop = ogg->total_time;
|
||||
} else if (ogg->push_disable_seeking) {
|
||||
seekable = FALSE;
|
||||
} else if (ogg->current_chain->streams->len) {
|
||||
gint i;
|
||||
|
||||
|
@ -3238,6 +3240,10 @@ gst_ogg_demux_check_duration_push (GstOggDemux * ogg, GstSeekFlags flags,
|
|||
ogg->push_byte_length = length;
|
||||
GST_DEBUG_OBJECT (ogg,
|
||||
"File byte length %" G_GINT64_FORMAT, ogg->push_byte_length);
|
||||
} else {
|
||||
GST_DEBUG_OBJECT (ogg, "File byte length unknown, assuming live");
|
||||
ogg->push_disable_seeking = TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
res = gst_pad_query_duration (peer, GST_FORMAT_TIME, &length);
|
||||
gst_object_unref (peer);
|
||||
|
@ -4545,8 +4551,22 @@ gst_ogg_demux_change_state (GstElement * element, GstStateChange transition)
|
|||
ogg->push_byte_length = -1;
|
||||
ogg->push_time_length = GST_CLOCK_TIME_NONE;
|
||||
ogg->push_time_offset = GST_CLOCK_TIME_NONE;
|
||||
ogg->push_disable_seeking = FALSE;
|
||||
ogg->push_state = PUSH_PLAYING;
|
||||
|
||||
ogg->push_disable_seeking = FALSE;
|
||||
if (!ogg->pullmode) {
|
||||
GstPad *peer;
|
||||
if ((peer = gst_pad_get_peer (ogg->sinkpad)) != NULL) {
|
||||
gint64 length = -1;
|
||||
if (!gst_pad_query_duration (peer, GST_FORMAT_BYTES, &length)
|
||||
|| length <= 0) {
|
||||
GST_DEBUG_OBJECT (ogg,
|
||||
"Unable to determine stream size, assuming live, seeking disabled");
|
||||
ogg->push_disable_seeking = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GST_PUSH_UNLOCK (ogg);
|
||||
gst_segment_init (&ogg->segment, GST_FORMAT_TIME);
|
||||
break;
|
||||
|
|
|
@ -452,7 +452,6 @@ gst_ogg_mux_request_new_pad (GstElement * element,
|
|||
ogg_mux->active_pads++;
|
||||
|
||||
oggpad->map.serialno = serial;
|
||||
ogg_stream_init (&oggpad->map.stream, oggpad->map.serialno);
|
||||
oggpad->packetno = 0;
|
||||
oggpad->pageno = 0;
|
||||
oggpad->eos = FALSE;
|
||||
|
@ -462,12 +461,18 @@ gst_ogg_mux_request_new_pad (GstElement * element,
|
|||
oggpad->first_delta = FALSE;
|
||||
oggpad->prev_delta = FALSE;
|
||||
oggpad->data_pushed = FALSE;
|
||||
oggpad->pagebuffers = g_queue_new ();
|
||||
oggpad->map.headers = NULL;
|
||||
oggpad->map.queued = NULL;
|
||||
oggpad->next_granule = 0;
|
||||
oggpad->keyframe_granule = -1;
|
||||
|
||||
if (GST_STATE (ogg_mux) > GST_STATE_READY) {
|
||||
/* This will be initialized in init_collectpads when going from ready
|
||||
* paused state */
|
||||
ogg_stream_init (&oggpad->map.stream, oggpad->map.serialno);
|
||||
oggpad->pagebuffers = g_queue_new ();
|
||||
}
|
||||
|
||||
gst_segment_init (&oggpad->segment, GST_FORMAT_TIME);
|
||||
|
||||
oggpad->collect_event = (GstPadEventFunction) GST_PAD_EVENTFUNC (newpad);
|
||||
|
|
|
@ -61,6 +61,7 @@
|
|||
#include <stdlib.h> /* free */
|
||||
|
||||
#include <gst/tag/tag.h>
|
||||
#include <gst/video/video.h>
|
||||
|
||||
#define GST_CAT_DEFAULT theoraenc_debug
|
||||
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
|
||||
|
@ -129,6 +130,7 @@ _ilog (unsigned int v)
|
|||
#define THEORA_DEF_RATE_BUFFER 0
|
||||
#define THEORA_DEF_MULTIPASS_CACHE_FILE NULL
|
||||
#define THEORA_DEF_MULTIPASS_MODE MULTIPASS_MODE_SINGLE_PASS
|
||||
#define THEORA_DEF_DUP_ON_GAP FALSE
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
|
@ -151,7 +153,8 @@ enum
|
|||
PROP_CAP_UNDERFLOW,
|
||||
PROP_RATE_BUFFER,
|
||||
PROP_MULTIPASS_CACHE_FILE,
|
||||
PROP_MULTIPASS_MODE
|
||||
PROP_MULTIPASS_MODE,
|
||||
PROP_DUP_ON_GAP
|
||||
/* FILL ME */
|
||||
};
|
||||
|
||||
|
@ -270,6 +273,11 @@ static gboolean theora_enc_write_multipass_cache (GstTheoraEnc * enc,
|
|||
|
||||
static char *theora_enc_get_supported_formats (void);
|
||||
|
||||
static void theora_timefifo_free (GstTheoraEnc * enc);
|
||||
static GstFlowReturn
|
||||
theora_enc_encode_and_push (GstTheoraEnc * enc, ogg_packet op,
|
||||
GstBuffer * buffer);
|
||||
|
||||
static void
|
||||
gst_theora_enc_class_init (GstTheoraEncClass * klass)
|
||||
{
|
||||
|
@ -394,6 +402,16 @@ gst_theora_enc_class_init (GstTheoraEncClass * klass)
|
|||
"Single pass or first/second pass", GST_TYPE_MULTIPASS_MODE,
|
||||
THEORA_DEF_MULTIPASS_MODE,
|
||||
(GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
g_object_class_install_property (gobject_class, PROP_DUP_ON_GAP,
|
||||
g_param_spec_boolean ("dup-on-gap", "Create DUP frame on GAP flag",
|
||||
"Allow codec to handle frames with GAP flag as duplicates "
|
||||
"of previous frame. "
|
||||
"This is good to work with variable frame rate stabilized "
|
||||
"by videorate element. It will add variable latency with maximal "
|
||||
"size of keyframe distance, this way it is a bad idea "
|
||||
"to use with live streams.",
|
||||
THEORA_DEF_DUP_ON_GAP,
|
||||
(GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
gst_element_class_add_pad_template (gstelement_class,
|
||||
gst_static_pad_template_get (&theora_enc_src_factory));
|
||||
|
@ -447,6 +465,7 @@ gst_theora_enc_init (GstTheoraEnc * enc)
|
|||
enc->cap_overflow = THEORA_DEF_CAP_OVERFLOW;
|
||||
enc->cap_underflow = THEORA_DEF_CAP_UNDERFLOW;
|
||||
enc->rate_buffer = THEORA_DEF_RATE_BUFFER;
|
||||
enc->dup_on_gap = THEORA_DEF_DUP_ON_GAP;
|
||||
|
||||
enc->multipass_mode = THEORA_DEF_MULTIPASS_MODE;
|
||||
enc->multipass_cache_file = THEORA_DEF_MULTIPASS_CACHE_FILE;
|
||||
|
@ -549,6 +568,8 @@ theora_enc_clear (GstTheoraEnc * enc)
|
|||
enc->granulepos_offset = 0;
|
||||
enc->timestamp_offset = 0;
|
||||
|
||||
theora_timefifo_free (enc);
|
||||
|
||||
enc->next_ts = GST_CLOCK_TIME_NONE;
|
||||
enc->next_discont = FALSE;
|
||||
enc->expected_ts = GST_CLOCK_TIME_NONE;
|
||||
|
@ -924,6 +945,9 @@ theora_enc_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
|
|||
}
|
||||
case GST_EVENT_EOS:
|
||||
if (enc->initialised) {
|
||||
/* clear all standing buffers */
|
||||
if (enc->dup_on_gap)
|
||||
theora_enc_encode_and_push (enc, op, NULL);
|
||||
/* push last packet with eos flag, should not be called */
|
||||
while (th_encode_packetout (enc->encoder, 1, &op)) {
|
||||
GstClockTime next_time =
|
||||
|
@ -945,6 +969,7 @@ theora_enc_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
|
|||
case GST_EVENT_FLUSH_STOP:
|
||||
gst_segment_init (&enc->segment, GST_FORMAT_UNDEFINED);
|
||||
res = gst_pad_push_event (enc->srcpad, event);
|
||||
theora_timefifo_free (enc);
|
||||
break;
|
||||
case GST_EVENT_CUSTOM_DOWNSTREAM:
|
||||
{
|
||||
|
@ -1152,20 +1177,197 @@ theora_enc_write_multipass_cache (GstTheoraEnc * enc, gboolean begin,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_slice_free can't be used with g_queue_foreach.
|
||||
* so we create new function with predefined GstClockTime size.
|
||||
*/
|
||||
static void
|
||||
theora_free_gstclocktime (gpointer mem)
|
||||
{
|
||||
g_slice_free (GstClockTime, mem);
|
||||
}
|
||||
|
||||
static void
|
||||
theora_timefifo_in (GstTheoraEnc * enc, const GstClockTime * timestamp)
|
||||
{
|
||||
GstClockTime *ptr;
|
||||
|
||||
if (!enc->t_queue)
|
||||
enc->t_queue = g_queue_new ();
|
||||
|
||||
g_assert (enc->t_queue != NULL);
|
||||
|
||||
ptr = g_slice_new (GstClockTime);
|
||||
*ptr = *timestamp;
|
||||
|
||||
g_queue_push_head (enc->t_queue, ptr);
|
||||
}
|
||||
|
||||
static GstClockTime
|
||||
theora_timefifo_out (GstTheoraEnc * enc)
|
||||
{
|
||||
GstClockTime ret, *ptr;
|
||||
|
||||
g_assert (enc->t_queue != NULL);
|
||||
|
||||
ptr = g_queue_pop_tail (enc->t_queue);
|
||||
g_assert (ptr != NULL);
|
||||
|
||||
ret = *ptr;
|
||||
theora_free_gstclocktime (ptr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* theora_timefifo_truncate - truncate the timestamp queue.
|
||||
* After frame encoding we should have only one buffer for next time.
|
||||
* The count of timestamps should be the same. If it is less,
|
||||
* some thing really bad has happened. If it is bigger, encoder
|
||||
* decided to return less then we ordered.
|
||||
* TODO: for now we will just drop this timestamps. The better solution
|
||||
* probably will be to recovery frames by recovery timestamps with
|
||||
* last buffer.
|
||||
*/
|
||||
static void
|
||||
theora_timefifo_truncate (GstTheoraEnc * enc)
|
||||
{
|
||||
if (enc->dup_on_gap) {
|
||||
guint length;
|
||||
g_assert (enc->t_queue != NULL);
|
||||
length = g_queue_get_length (enc->t_queue);
|
||||
|
||||
if (length > 1) {
|
||||
/* it is also not good if we have more then 1. */
|
||||
GST_DEBUG_OBJECT (enc, "Dropping %u time stamps", length - 1);
|
||||
while (g_queue_get_length (enc->t_queue) > 1) {
|
||||
theora_timefifo_out (enc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
theora_timefifo_free (GstTheoraEnc * enc)
|
||||
{
|
||||
if (enc->t_queue) {
|
||||
if (g_queue_get_length (enc->t_queue))
|
||||
g_queue_foreach (enc->t_queue, (GFunc) theora_free_gstclocktime, NULL);
|
||||
g_queue_free (enc->t_queue);
|
||||
enc->t_queue = NULL;
|
||||
}
|
||||
/* prevbuf makes no sense without timestamps,
|
||||
* so clear it too. */
|
||||
if (enc->prevbuf) {
|
||||
gst_buffer_unref (enc->prevbuf);
|
||||
enc->prevbuf = NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
theora_update_prevbuf (GstTheoraEnc * enc, GstBuffer * buffer)
|
||||
{
|
||||
if (enc->prevbuf) {
|
||||
gst_buffer_unref (enc->prevbuf);
|
||||
enc->prevbuf = NULL;
|
||||
}
|
||||
enc->prevbuf = gst_buffer_ref (buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* theora_enc_encode_and_push - encode buffer or queued previous buffer
|
||||
* buffer - buffer to encode. If set to NULL it should encode only
|
||||
* queued buffers and produce dups if needed.
|
||||
*/
|
||||
|
||||
static GstFlowReturn
|
||||
theora_enc_encode_and_push (GstTheoraEnc * enc, ogg_packet op,
|
||||
GstClockTime timestamp, GstClockTime running_time,
|
||||
GstClockTime duration, GstBuffer * buffer)
|
||||
GstBuffer * buffer)
|
||||
{
|
||||
GstFlowReturn ret;
|
||||
GstVideoFrame frame;
|
||||
th_ycbcr_buffer ycbcr;
|
||||
gint res;
|
||||
GstVideoFrame frame;
|
||||
|
||||
gst_video_frame_map (&frame, &enc->vinfo, buffer, GST_MAP_READ);
|
||||
theora_enc_init_buffer (ycbcr, &frame);
|
||||
if (enc->dup_on_gap) {
|
||||
guint t_queue_length;
|
||||
|
||||
if (theora_enc_is_discontinuous (enc, running_time, duration)) {
|
||||
if (enc->t_queue)
|
||||
t_queue_length = g_queue_get_length (enc->t_queue);
|
||||
else
|
||||
t_queue_length = 0;
|
||||
|
||||
if (buffer) {
|
||||
GstClockTime timestamp = GST_BUFFER_TIMESTAMP (buffer);
|
||||
|
||||
/* videorate can easy create 200 dup frames in one shot.
|
||||
* In this case th_encode_ctl will just return TH_EINVAL
|
||||
* and we will generate only one frame as result.
|
||||
* To make us more bullet proof, make sure we have no
|
||||
* more dup frames than keyframe interval.
|
||||
*/
|
||||
if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_GAP) &&
|
||||
enc->keyframe_force > t_queue_length) {
|
||||
GST_DEBUG_OBJECT (enc, "Got GAP frame, queue as duplicate.");
|
||||
|
||||
theora_timefifo_in (enc, ×tamp);
|
||||
gst_buffer_unref (buffer);
|
||||
return GST_FLOW_OK;
|
||||
} else {
|
||||
theora_timefifo_in (enc, ×tamp);
|
||||
/* We should have one frame delay to create correct frame order.
|
||||
* First time we got buffer, prevbuf should be empty. Nothing else
|
||||
* should be done here.
|
||||
*/
|
||||
if (!enc->prevbuf) {
|
||||
theora_update_prevbuf (enc, buffer);
|
||||
gst_buffer_unref (buffer);
|
||||
return GST_FLOW_OK;
|
||||
} else {
|
||||
theora_update_prevbuf (enc, buffer);
|
||||
/* after theora_update_prevbuf t_queue_length was changed */
|
||||
t_queue_length++;
|
||||
|
||||
if (t_queue_length > 2) {
|
||||
/* now in t_queue_length should be two real buffers: current and
|
||||
* previous. All others are timestamps of duplicate frames. */
|
||||
t_queue_length -= 2;
|
||||
res = th_encode_ctl (enc->encoder, TH_ENCCTL_SET_DUP_COUNT,
|
||||
&t_queue_length, sizeof (t_queue_length));
|
||||
if (res < 0)
|
||||
GST_WARNING_OBJECT (enc, "Failed marking dups for last frame");
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* if there is no buffer, then probably we got EOS or discontinuous.
|
||||
* We need to encode every thing what was left in the queue
|
||||
*/
|
||||
GST_DEBUG_OBJECT (enc, "Encode collected buffers.");
|
||||
if (t_queue_length > 1) {
|
||||
t_queue_length--;
|
||||
res = th_encode_ctl (enc->encoder, TH_ENCCTL_SET_DUP_COUNT,
|
||||
&t_queue_length, sizeof (t_queue_length));
|
||||
if (res < 0)
|
||||
GST_WARNING_OBJECT (enc, "Failed marking dups for last frame.");
|
||||
} else {
|
||||
GST_DEBUG_OBJECT (enc, "Prevbuffer is empty. Nothing to encode.");
|
||||
return GST_FLOW_OK;
|
||||
}
|
||||
}
|
||||
gst_video_frame_map (&frame, &enc->vinfo, enc->prevbuf, GST_MAP_READ);
|
||||
theora_enc_init_buffer (ycbcr, &frame);
|
||||
} else {
|
||||
gst_video_frame_map (&frame, &enc->vinfo, buffer, GST_MAP_READ);
|
||||
theora_enc_init_buffer (ycbcr, &frame);
|
||||
}
|
||||
|
||||
/* check for buffer, it can be optional */
|
||||
if (enc->current_discont && buffer) {
|
||||
GstClockTime timestamp = GST_BUFFER_TIMESTAMP (buffer);
|
||||
GstClockTime running_time =
|
||||
gst_segment_to_running_time (&enc->segment, GST_FORMAT_TIME, timestamp);
|
||||
theora_enc_reset (enc);
|
||||
enc->granulepos_offset =
|
||||
gst_util_uint64_scale (running_time, enc->vinfo.fps_n,
|
||||
|
@ -1197,22 +1399,34 @@ theora_enc_encode_and_push (GstTheoraEnc * enc, ogg_packet op,
|
|||
|
||||
ret = GST_FLOW_OK;
|
||||
while (th_encode_packetout (enc->encoder, 0, &op)) {
|
||||
GstClockTime next_time;
|
||||
GstClockTime next_time, duration;
|
||||
GstClockTime timestamp = 0;
|
||||
GST_DEBUG_OBJECT (enc, "encoded. granule:%" G_GINT64_FORMAT ", packet:%p, "
|
||||
"bytes:%ld", op.granulepos, op.packet, op.bytes);
|
||||
|
||||
next_time = th_granule_time (enc->encoder, op.granulepos) * GST_SECOND;
|
||||
duration = next_time - enc->next_ts;
|
||||
|
||||
ret =
|
||||
theora_push_packet (enc, &op, timestamp, enc->next_ts,
|
||||
next_time - enc->next_ts);
|
||||
if (enc->dup_on_gap && !enc->current_discont)
|
||||
timestamp = theora_timefifo_out (enc);
|
||||
else
|
||||
timestamp = GST_BUFFER_TIMESTAMP (buffer);
|
||||
|
||||
ret = theora_push_packet (enc, &op, timestamp, enc->next_ts, duration);
|
||||
|
||||
enc->next_ts = next_time;
|
||||
if (ret != GST_FLOW_OK)
|
||||
if (ret != GST_FLOW_OK) {
|
||||
theora_timefifo_truncate (enc);
|
||||
goto data_push;
|
||||
}
|
||||
}
|
||||
|
||||
theora_timefifo_truncate (enc);
|
||||
done:
|
||||
gst_video_frame_unmap (&frame);
|
||||
gst_buffer_unref (buffer);
|
||||
if (buffer)
|
||||
gst_buffer_unref (buffer);
|
||||
enc->current_discont = FALSE;
|
||||
|
||||
return ret;
|
||||
|
||||
|
@ -1380,8 +1594,14 @@ theora_enc_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
|
|||
enc->next_ts = 0;
|
||||
}
|
||||
|
||||
ret = theora_enc_encode_and_push (enc, op, timestamp, running_time, duration,
|
||||
buffer);
|
||||
enc->current_discont = theora_enc_is_discontinuous (enc,
|
||||
running_time, duration);
|
||||
|
||||
/* empty queue if discontinuous */
|
||||
if (enc->current_discont && enc->dup_on_gap)
|
||||
theora_enc_encode_and_push (enc, op, NULL);
|
||||
|
||||
ret = theora_enc_encode_and_push (enc, op, buffer);
|
||||
|
||||
return ret;
|
||||
|
||||
|
@ -1563,6 +1783,9 @@ theora_enc_set_property (GObject * object, guint prop_id,
|
|||
case PROP_MULTIPASS_MODE:
|
||||
enc->multipass_mode = g_value_get_enum (value);
|
||||
break;
|
||||
case PROP_DUP_ON_GAP:
|
||||
enc->dup_on_gap = g_value_get_boolean (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
|
@ -1640,6 +1863,9 @@ theora_enc_get_property (GObject * object, guint prop_id,
|
|||
case PROP_MULTIPASS_MODE:
|
||||
g_value_set_enum (value, enc->multipass_mode);
|
||||
break;
|
||||
case PROP_DUP_ON_GAP:
|
||||
g_value_set_boolean (value, enc->dup_on_gap);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
|
|
|
@ -122,6 +122,13 @@ struct _GstTheoraEnc
|
|||
gboolean cap_underflow;
|
||||
int rate_buffer;
|
||||
|
||||
/* variables for dup-on-gap */
|
||||
gboolean dup_on_gap;
|
||||
gboolean current_discont;
|
||||
GstBuffer *prevbuf;
|
||||
GQueue *t_queue;
|
||||
/* end dup-on-gap */
|
||||
|
||||
GstTheoraEncMultipassMode multipass_mode;
|
||||
GIOChannel *multipass_cache_fd;
|
||||
GstAdapter *multipass_cache_adapter;
|
||||
|
|
|
@ -1921,7 +1921,8 @@ out_of_segment:
|
|||
too_late:
|
||||
{
|
||||
GST_DEBUG_OBJECT (sink, "dropping late sample");
|
||||
return GST_FLOW_OK;
|
||||
ret = GST_FLOW_OK;
|
||||
goto done;
|
||||
}
|
||||
/* ERRORS */
|
||||
payload_failed:
|
||||
|
|
|
@ -440,6 +440,7 @@ gst_audio_decoder_reset (GstAudioDecoder * dec, gboolean full)
|
|||
|
||||
gst_audio_info_init (&dec->priv->ctx.info);
|
||||
memset (&dec->priv->ctx, 0, sizeof (dec->priv->ctx));
|
||||
dec->priv->ctx.max_errors = GST_AUDIO_DECODER_MAX_ERRORS;
|
||||
|
||||
if (dec->priv->taglist) {
|
||||
gst_tag_list_free (dec->priv->taglist);
|
||||
|
@ -2225,7 +2226,8 @@ gst_audio_decoder_get_delay (GstAudioDecoder * dec)
|
|||
* @num: max tolerated errors
|
||||
*
|
||||
* Sets numbers of tolerated decoder errors, where a tolerated one is then only
|
||||
* warned about, but more than tolerated will lead to fatal error.
|
||||
* warned about, but more than tolerated will lead to fatal error. Default
|
||||
* is set to GST_AUDIO_DECODER_MAX_ERRORS.
|
||||
*
|
||||
* Since: 0.10.36
|
||||
*/
|
||||
|
|
|
@ -127,6 +127,16 @@ G_STMT_START { \
|
|||
GST_FUNCTION, __LINE__); \
|
||||
} G_STMT_END
|
||||
|
||||
|
||||
/**
|
||||
* GST_AUDIO_DECODER_MAX_ERRORS:
|
||||
*
|
||||
* Default maximum number of errors tolerated before signaling error.
|
||||
*
|
||||
* Since: 0.10.36
|
||||
*/
|
||||
#define GST_AUDIO_DECODER_MAX_ERRORS 10
|
||||
|
||||
/**
|
||||
* GstAudioDecoder:
|
||||
*
|
||||
|
@ -179,7 +189,7 @@ struct _GstAudioDecoder
|
|||
* most notably a call to gst_audio_decoder_finish_frame().
|
||||
* @flush: Optional.
|
||||
* Instructs subclass to clear any codec caches and discard
|
||||
* any pending samples and not yet returned encoded data.
|
||||
* any pending samples and not yet returned decoded data.
|
||||
* @hard indicates whether a FLUSH is being processed,
|
||||
* or otherwise a DISCONT (or conceptually similar).
|
||||
* @event: Optional.
|
||||
|
|
|
@ -805,10 +805,13 @@ gst_audio_encoder_push_buffers (GstAudioEncoder * enc, gboolean force)
|
|||
static GstFlowReturn
|
||||
gst_audio_encoder_drain (GstAudioEncoder * enc)
|
||||
{
|
||||
GST_DEBUG_OBJECT (enc, "draining");
|
||||
if (enc->priv->drained)
|
||||
return GST_FLOW_OK;
|
||||
else
|
||||
else {
|
||||
GST_DEBUG_OBJECT (enc, "... really");
|
||||
return gst_audio_encoder_push_buffers (enc, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -3,6 +3,21 @@
|
|||
* Functions copied from glib 2.10
|
||||
*
|
||||
* Copyright 2005 David Schleef <ds@schleef.org>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GLIB_COMPAT_PRIVATE_H__
|
||||
|
|
|
@ -612,7 +612,7 @@ gst_tag_list_has_ifd_tags (const GstTagList * taglist,
|
|||
static void
|
||||
gst_exif_writer_write_tag_header (GstExifWriter * writer,
|
||||
guint16 exif_tag, guint16 exif_type, guint32 count, guint32 offset,
|
||||
gboolean is_data)
|
||||
const guint32 * offset_data)
|
||||
{
|
||||
GST_DEBUG ("Writing tag entry: id %x, type %u, count %u, offset %u",
|
||||
exif_tag, exif_type, count, offset);
|
||||
|
@ -621,13 +621,17 @@ gst_exif_writer_write_tag_header (GstExifWriter * writer,
|
|||
gst_byte_writer_put_uint16_le (&writer->tagwriter, exif_tag);
|
||||
gst_byte_writer_put_uint16_le (&writer->tagwriter, exif_type);
|
||||
gst_byte_writer_put_uint32_le (&writer->tagwriter, count);
|
||||
gst_byte_writer_put_uint32_le (&writer->tagwriter, offset);
|
||||
if (offset_data != NULL) {
|
||||
gst_byte_writer_put_data (&writer->tagwriter, (guint8 *) offset_data, 4);
|
||||
} else {
|
||||
gst_byte_writer_put_uint32_le (&writer->tagwriter, offset);
|
||||
}
|
||||
} else if (writer->byte_order == G_BIG_ENDIAN) {
|
||||
gst_byte_writer_put_uint16_be (&writer->tagwriter, exif_tag);
|
||||
gst_byte_writer_put_uint16_be (&writer->tagwriter, exif_type);
|
||||
gst_byte_writer_put_uint32_be (&writer->tagwriter, count);
|
||||
if (is_data) {
|
||||
gst_byte_writer_put_uint32_le (&writer->tagwriter, offset);
|
||||
if (offset_data != NULL) {
|
||||
gst_byte_writer_put_data (&writer->tagwriter, (guint8 *) offset_data, 4);
|
||||
} else {
|
||||
gst_byte_writer_put_uint32_be (&writer->tagwriter, offset);
|
||||
}
|
||||
|
@ -671,7 +675,7 @@ gst_exif_writer_write_rational_tag (GstExifWriter * writer,
|
|||
guint32 offset = gst_byte_writer_get_size (&writer->datawriter);
|
||||
|
||||
gst_exif_writer_write_tag_header (writer, tag, EXIF_TYPE_RATIONAL,
|
||||
1, offset, FALSE);
|
||||
1, offset, NULL);
|
||||
|
||||
gst_exif_writer_write_rational_data (writer, frac_n, frac_d);
|
||||
}
|
||||
|
@ -683,7 +687,7 @@ gst_exif_writer_write_signed_rational_tag (GstExifWriter * writer,
|
|||
guint32 offset = gst_byte_writer_get_size (&writer->datawriter);
|
||||
|
||||
gst_exif_writer_write_tag_header (writer, tag, EXIF_TYPE_SRATIONAL,
|
||||
1, offset, FALSE);
|
||||
1, offset, NULL);
|
||||
|
||||
gst_exif_writer_write_signed_rational_data (writer, frac_n, frac_d);
|
||||
}
|
||||
|
@ -720,7 +724,7 @@ gst_exif_writer_write_byte_tag (GstExifWriter * writer, guint16 tag,
|
|||
|
||||
GST_WRITE_UINT8 ((guint8 *) & offset, value);
|
||||
gst_exif_writer_write_tag_header (writer, tag, EXIF_TYPE_BYTE,
|
||||
1, offset, TRUE);
|
||||
1, offset, &offset);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -736,7 +740,7 @@ gst_exif_writer_write_short_tag (GstExifWriter * writer, guint16 tag,
|
|||
}
|
||||
|
||||
gst_exif_writer_write_tag_header (writer, tag, EXIF_TYPE_SHORT,
|
||||
1, offset, TRUE);
|
||||
1, offset, &offset);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -751,7 +755,7 @@ gst_exif_writer_write_long_tag (GstExifWriter * writer, guint16 tag,
|
|||
}
|
||||
|
||||
gst_exif_writer_write_tag_header (writer, tag, EXIF_TYPE_LONG,
|
||||
1, offset, TRUE);
|
||||
1, offset, &offset);
|
||||
}
|
||||
|
||||
|
||||
|
@ -766,29 +770,25 @@ write_exif_undefined_tag (GstExifWriter * writer, guint16 tag,
|
|||
* resulting tag headers offset and the base offset */
|
||||
offset = gst_byte_writer_get_size (&writer->datawriter);
|
||||
gst_exif_writer_write_tag_header (writer, tag, EXIF_TYPE_UNDEFINED,
|
||||
size, offset, FALSE);
|
||||
size, offset, NULL);
|
||||
gst_byte_writer_put_data (&writer->datawriter, data, size);
|
||||
} else {
|
||||
/* small enough to go in the offset */
|
||||
memcpy ((guint8 *) & offset, data, size);
|
||||
gst_exif_writer_write_tag_header (writer, tag, EXIF_TYPE_UNDEFINED,
|
||||
size, offset, TRUE);
|
||||
size, offset, &offset);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
write_exif_ascii_tag (GstExifWriter * writer, guint16 tag, const gchar * str)
|
||||
{
|
||||
gint size;
|
||||
guint32 offset = 0;
|
||||
gchar *ascii_str;
|
||||
gsize ascii_size;
|
||||
GError *error = NULL;
|
||||
|
||||
size = strlen (str) + 1;
|
||||
|
||||
ascii_str =
|
||||
g_convert (str, size, "latin1", "utf8", NULL, &ascii_size, &error);
|
||||
ascii_str = g_convert (str, -1, "latin1", "utf8", NULL, &ascii_size, &error);
|
||||
|
||||
if (error) {
|
||||
GST_WARNING ("Failed to convert exif tag to ascii: 0x%x - %s. Error: %s",
|
||||
|
@ -806,13 +806,13 @@ write_exif_ascii_tag (GstExifWriter * writer, guint16 tag, const gchar * str)
|
|||
* resulting tag headers offset and the base offset */
|
||||
offset = gst_byte_writer_get_size (&writer->datawriter);
|
||||
gst_exif_writer_write_tag_header (writer, tag, EXIF_TYPE_ASCII,
|
||||
ascii_size, offset, FALSE);
|
||||
ascii_size, offset, NULL);
|
||||
gst_byte_writer_put_string (&writer->datawriter, ascii_str);
|
||||
} else {
|
||||
/* small enough to go in the offset */
|
||||
memcpy ((guint8 *) & offset, ascii_str, ascii_size);
|
||||
gst_exif_writer_write_tag_header (writer, tag, EXIF_TYPE_ASCII,
|
||||
ascii_size, offset, TRUE);
|
||||
ascii_size, offset, &offset);
|
||||
}
|
||||
|
||||
g_free (ascii_str);
|
||||
|
@ -1460,7 +1460,7 @@ parse_exif_rational_tag (GstExifReader * exif_reader,
|
|||
}
|
||||
|
||||
static GstBuffer *
|
||||
write_exif_ifd (const GstTagList * taglist, gboolean byte_order,
|
||||
write_exif_ifd (const GstTagList * taglist, guint byte_order,
|
||||
guint32 base_offset, const GstExifTagMatch * tag_map)
|
||||
{
|
||||
GstExifWriter writer;
|
||||
|
@ -1520,7 +1520,7 @@ write_exif_ifd (const GstTagList * taglist, gboolean byte_order,
|
|||
GST_DEBUG ("Adding inner ifd: %x", tag_map[i].exif_tag);
|
||||
gst_exif_writer_write_tag_header (&writer, tag_map[i].exif_tag,
|
||||
EXIF_TYPE_LONG, 1,
|
||||
gst_byte_writer_get_size (&writer.datawriter), FALSE);
|
||||
gst_byte_writer_get_size (&writer.datawriter), NULL);
|
||||
|
||||
data = gst_buffer_map (inner_ifd, &size, NULL, GST_MAP_READ);
|
||||
gst_byte_writer_put_data (&writer.datawriter, data, size);
|
||||
|
@ -1998,7 +1998,7 @@ serialize_geo_coordinate (GstExifWriter * writer, const GstTagList * taglist,
|
|||
|
||||
offset = gst_byte_writer_get_size (&writer->datawriter);
|
||||
gst_exif_writer_write_tag_header (writer, exiftag->exif_tag,
|
||||
EXIF_TYPE_RATIONAL, 3, offset, FALSE);
|
||||
EXIF_TYPE_RATIONAL, 3, offset, NULL);
|
||||
gst_exif_writer_write_rational_data (writer, degrees, 1);
|
||||
gst_exif_writer_write_rational_data (writer, minutes, 1);
|
||||
gst_exif_writer_write_rational_data (writer, seconds, 1);
|
||||
|
|
|
@ -1325,7 +1325,10 @@ gst_tag_list_from_xmp_buffer (GstBuffer * buffer)
|
|||
if (*xp1 != '>')
|
||||
goto missing_header;
|
||||
|
||||
max_ft_len = 1 + strlen ("<?xpacket end=\".\"?>");
|
||||
/* Use 2 here to count for an extra trailing \n that was added
|
||||
* in old versions, this makes it able to parse xmp packets with
|
||||
* and without this trailing char */
|
||||
max_ft_len = 2 + strlen ("<?xpacket end=\".\"?>");
|
||||
if (len < max_ft_len)
|
||||
goto missing_footer;
|
||||
|
||||
|
|
|
@ -1193,9 +1193,9 @@ matrix_yuv_to_rgb (guint8 * tmpline, guint width)
|
|||
g = (298 * y - 55 * u - 136 * v + 19681) >> 8;
|
||||
b = (298 * y + 541 * u - 73988) >> 8;
|
||||
|
||||
tmpline[i * 4 + ARGB_R] = CLAMP (r, 0, 255);
|
||||
tmpline[i * 4 + ARGB_G] = CLAMP (g, 0, 255);
|
||||
tmpline[i * 4 + ARGB_B] = CLAMP (b, 0, 255);
|
||||
tmpline[i * 4 + 1] = CLAMP (r, 0, 255);
|
||||
tmpline[i * 4 + 2] = CLAMP (g, 0, 255);
|
||||
tmpline[i * 4 + 3] = CLAMP (b, 0, 255);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
#include "config.h"
|
||||
#endif
|
||||
#include "gstadder.h"
|
||||
#include <gst/audio/audio.h>
|
||||
#include <string.h> /* strcmp */
|
||||
#include "gstadderorc.h"
|
||||
|
||||
|
@ -122,10 +123,13 @@ static void gst_adder_release_pad (GstElement * element, GstPad * pad);
|
|||
static GstStateChangeReturn gst_adder_change_state (GstElement * element,
|
||||
GstStateChange transition);
|
||||
|
||||
static GstBuffer *gst_adder_do_clip (GstCollectPads * pads,
|
||||
GstCollectData * data, GstBuffer * buffer, gpointer user_data);
|
||||
static GstFlowReturn gst_adder_collected (GstCollectPads * pads,
|
||||
static GstFlowReturn gst_adder_do_clip (GstCollectPads2 * pads,
|
||||
GstCollectData2 * data, GstBuffer * buffer, GstBuffer ** out,
|
||||
gpointer user_data);
|
||||
static GstFlowReturn gst_adder_collected (GstCollectPads2 * pads,
|
||||
gpointer user_data);
|
||||
static gboolean gst_adder_event (GstCollectPads2 * pads, GstCollectData2 * pad,
|
||||
GstEvent * event, gpointer user_data);
|
||||
|
||||
/* non-clipping versions (for float) */
|
||||
#define MAKE_FUNC_NC(name,type) \
|
||||
|
@ -678,12 +682,14 @@ gst_adder_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
|
|||
|
||||
/* check if we are flushing */
|
||||
if (flush) {
|
||||
/* make sure we accept nothing anymore and return WRONG_STATE */
|
||||
gst_collect_pads_set_flushing (adder->collect, TRUE);
|
||||
|
||||
/* flushing seek, start flush downstream, the flush will be done
|
||||
* when all pads received a FLUSH_STOP. */
|
||||
* when all pads received a FLUSH_STOP.
|
||||
* Make sure we accept nothing anymore and return WRONG_STATE.
|
||||
* We send a flush-start before, to ensure no streaming is done
|
||||
* as we need to take the stream lock.
|
||||
*/
|
||||
gst_pad_push_event (adder->srcpad, gst_event_new_flush_start ());
|
||||
gst_collect_pads2_set_flushing (adder->collect, TRUE);
|
||||
|
||||
/* We can't send FLUSH_STOP here since upstream could start pushing data
|
||||
* after we unlock adder->collect.
|
||||
|
@ -698,7 +704,7 @@ gst_adder_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
|
|||
/* now wait for the collected to be finished and mark a new
|
||||
* segment. After we have the lock, no collect function is running and no
|
||||
* new collect function will be called for as long as we're flushing. */
|
||||
GST_OBJECT_LOCK (adder->collect);
|
||||
GST_COLLECT_PADS2_STREAM_LOCK (adder->collect);
|
||||
adder->segment.rate = rate;
|
||||
if (curtype == GST_SEEK_TYPE_SET)
|
||||
adder->segment.start = cur;
|
||||
|
@ -711,9 +717,9 @@ gst_adder_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
|
|||
if (flush) {
|
||||
/* Yes, we need to call _set_flushing again *WHEN* the streaming threads
|
||||
* have stopped so that the cookie gets properly updated. */
|
||||
gst_collect_pads_set_flushing (adder->collect, TRUE);
|
||||
gst_collect_pads2_set_flushing (adder->collect, TRUE);
|
||||
}
|
||||
GST_OBJECT_UNLOCK (adder->collect);
|
||||
GST_COLLECT_PADS2_STREAM_UNLOCK (adder->collect);
|
||||
GST_DEBUG_OBJECT (adder, "forwarding seek event: %" GST_PTR_FORMAT,
|
||||
event);
|
||||
|
||||
|
@ -776,29 +782,27 @@ gst_adder_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
|
|||
goto beach;
|
||||
}
|
||||
case GST_EVENT_FLUSH_STOP:
|
||||
/* we received a flush-stop. The collect_event function will push the
|
||||
* event past our element. We simply forward all flush-stop events, even
|
||||
* when no flush-stop was pending, this is required because collectpads
|
||||
* does not provide an API to handle-but-not-forward the flush-stop.
|
||||
* We unset the pending flush-stop flag so that we don't send anymore
|
||||
* flush-stop from the collect function later.
|
||||
/* we received a flush-stop. The collect_event function will call the
|
||||
* gst_adder_event function we have set on the GstCollectPads2, so we
|
||||
* have control over whether the event is sent past our element.
|
||||
* We will only forward it when flush_stop_pending is set, and we will
|
||||
* unset it then.
|
||||
*/
|
||||
GST_OBJECT_LOCK (adder->collect);
|
||||
GST_COLLECT_PADS2_STREAM_LOCK (adder->collect);
|
||||
g_atomic_int_set (&adder->new_segment_pending, TRUE);
|
||||
g_atomic_int_set (&adder->flush_stop_pending, FALSE);
|
||||
/* Clear pending tags */
|
||||
if (adder->pending_events) {
|
||||
g_list_foreach (adder->pending_events, (GFunc) gst_event_unref, NULL);
|
||||
g_list_free (adder->pending_events);
|
||||
adder->pending_events = NULL;
|
||||
}
|
||||
GST_OBJECT_UNLOCK (adder->collect);
|
||||
GST_COLLECT_PADS2_STREAM_UNLOCK (adder->collect);
|
||||
break;
|
||||
case GST_EVENT_TAG:
|
||||
GST_OBJECT_LOCK (adder->collect);
|
||||
GST_COLLECT_PADS2_STREAM_LOCK (adder->collect);
|
||||
/* collect tags here so we can push them out when we collect data */
|
||||
adder->pending_events = g_list_append (adder->pending_events, event);
|
||||
GST_OBJECT_UNLOCK (adder->collect);
|
||||
GST_COLLECT_PADS2_STREAM_UNLOCK (adder->collect);
|
||||
goto beach;
|
||||
case GST_EVENT_SEGMENT:
|
||||
if (g_atomic_int_compare_and_exchange (&adder->wait_for_new_segment,
|
||||
|
@ -812,7 +816,7 @@ gst_adder_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
|
|||
break;
|
||||
}
|
||||
|
||||
/* now GstCollectPads can take care of the rest, e.g. EOS */
|
||||
/* now GstCollectPads2 can take care of the rest, e.g. EOS */
|
||||
ret = adder->collect_event (pad, parent, event);
|
||||
|
||||
beach:
|
||||
|
@ -879,11 +883,13 @@ gst_adder_init (GstAdder * adder)
|
|||
adder->filter_caps = NULL;
|
||||
|
||||
/* keep track of the sinkpads requested */
|
||||
adder->collect = gst_collect_pads_new ();
|
||||
gst_collect_pads_set_function (adder->collect,
|
||||
adder->collect = gst_collect_pads2_new ();
|
||||
gst_collect_pads2_set_function (adder->collect,
|
||||
GST_DEBUG_FUNCPTR (gst_adder_collected), adder);
|
||||
gst_collect_pads_set_clip_function (adder->collect,
|
||||
gst_collect_pads2_set_clip_function (adder->collect,
|
||||
GST_DEBUG_FUNCPTR (gst_adder_do_clip), adder);
|
||||
gst_collect_pads2_set_event_function (adder->collect,
|
||||
GST_DEBUG_FUNCPTR (gst_adder_event), adder);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -985,11 +991,10 @@ gst_adder_request_new_pad (GstElement * element, GstPadTemplate * templ,
|
|||
g_free (name);
|
||||
|
||||
gst_pad_set_query_function (newpad, GST_DEBUG_FUNCPTR (gst_adder_sink_query));
|
||||
gst_collect_pads_add_pad (adder->collect, newpad, sizeof (GstCollectData),
|
||||
NULL);
|
||||
gst_collect_pads2_add_pad (adder->collect, newpad, sizeof (GstCollectData2));
|
||||
|
||||
/* FIXME: hacked way to override/extend the event function of
|
||||
* GstCollectPads; because it sets its own event function giving the
|
||||
* GstCollectPads2; because it sets its own event function giving the
|
||||
* element no access to events */
|
||||
adder->collect_event = (GstPadEventFunction) GST_PAD_EVENTFUNC (newpad);
|
||||
gst_pad_set_event_function (newpad, GST_DEBUG_FUNCPTR (gst_adder_sink_event));
|
||||
|
@ -1009,7 +1014,7 @@ not_sink:
|
|||
could_not_add:
|
||||
{
|
||||
GST_DEBUG_OBJECT (adder, "could not add pad");
|
||||
gst_collect_pads_remove_pad (adder->collect, newpad);
|
||||
gst_collect_pads2_remove_pad (adder->collect, newpad);
|
||||
gst_object_unref (newpad);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -1024,13 +1029,13 @@ gst_adder_release_pad (GstElement * element, GstPad * pad)
|
|||
|
||||
GST_DEBUG_OBJECT (adder, "release pad %s:%s", GST_DEBUG_PAD_NAME (pad));
|
||||
|
||||
gst_collect_pads_remove_pad (adder->collect, pad);
|
||||
gst_collect_pads2_remove_pad (adder->collect, pad);
|
||||
gst_element_remove_pad (element, pad);
|
||||
}
|
||||
|
||||
static GstBuffer *
|
||||
gst_adder_do_clip (GstCollectPads * pads, GstCollectData * data,
|
||||
GstBuffer * buffer, gpointer user_data)
|
||||
static GstFlowReturn
|
||||
gst_adder_do_clip (GstCollectPads2 * pads, GstCollectData2 * data,
|
||||
GstBuffer * buffer, GstBuffer ** out, gpointer user_data)
|
||||
{
|
||||
GstAdder *adder = GST_ADDER (user_data);
|
||||
gint rate, bpf;
|
||||
|
@ -1040,11 +1045,12 @@ gst_adder_do_clip (GstCollectPads * pads, GstCollectData * data,
|
|||
|
||||
buffer = gst_audio_buffer_clip (buffer, &data->segment, rate, bpf);
|
||||
|
||||
return buffer;
|
||||
*out = buffer;
|
||||
return GST_FLOW_OK;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_adder_collected (GstCollectPads * pads, gpointer user_data)
|
||||
gst_adder_collected (GstCollectPads2 * pads, gpointer user_data)
|
||||
{
|
||||
/*
|
||||
* combine streams by adding data values
|
||||
|
@ -1086,7 +1092,7 @@ gst_adder_collected (GstCollectPads * pads, gpointer user_data)
|
|||
|
||||
/* get available bytes for reading, this can be 0 which could mean empty
|
||||
* buffers or EOS, which we will catch when we loop over the pads. */
|
||||
outsize = gst_collect_pads_available (pads);
|
||||
outsize = gst_collect_pads2_available (pads);
|
||||
/* can only happen when no pads to collect or all EOS */
|
||||
if (outsize == 0)
|
||||
goto eos;
|
||||
|
@ -1100,18 +1106,18 @@ gst_adder_collected (GstCollectPads * pads, gpointer user_data)
|
|||
outsize, bps, bpf);
|
||||
|
||||
for (collected = pads->data; collected; collected = next) {
|
||||
GstCollectData *collect_data;
|
||||
GstCollectData2 *collect_data;
|
||||
GstBuffer *inbuf;
|
||||
gboolean is_gap;
|
||||
|
||||
/* take next to see if this is the last collectdata */
|
||||
next = g_slist_next (collected);
|
||||
|
||||
collect_data = (GstCollectData *) collected->data;
|
||||
collect_data = (GstCollectData2 *) collected->data;
|
||||
|
||||
/* get a buffer of size bytes, if we get a buffer, it is at least outsize
|
||||
* bytes big. */
|
||||
inbuf = gst_collect_pads_take_buffer (pads, collect_data, outsize);
|
||||
inbuf = gst_collect_pads2_take_buffer (pads, collect_data, outsize);
|
||||
/* NULL means EOS or an empty buffer so we still need to flush in
|
||||
* case of an empty buffer. */
|
||||
if (inbuf == NULL) {
|
||||
|
@ -1286,6 +1292,24 @@ eos:
|
|||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_adder_event (GstCollectPads2 * pads, GstCollectData2 * pad,
|
||||
GstEvent * event, gpointer user_data)
|
||||
{
|
||||
GstAdder *adder = GST_ADDER (user_data);
|
||||
if (GST_EVENT_TYPE (event) == GST_EVENT_FLUSH_STOP) {
|
||||
if (g_atomic_int_compare_and_exchange (&adder->flush_stop_pending,
|
||||
TRUE, FALSE)) {
|
||||
return FALSE;
|
||||
} else {
|
||||
gst_event_unref (event);
|
||||
return TRUE;
|
||||
}
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static GstStateChangeReturn
|
||||
gst_adder_change_state (GstElement * element, GstStateChange transition)
|
||||
{
|
||||
|
@ -1304,14 +1328,14 @@ gst_adder_change_state (GstElement * element, GstStateChange transition)
|
|||
adder->new_segment_pending = TRUE;
|
||||
adder->wait_for_new_segment = FALSE;
|
||||
gst_segment_init (&adder->segment, GST_FORMAT_TIME);
|
||||
gst_collect_pads_start (adder->collect);
|
||||
gst_collect_pads2_start (adder->collect);
|
||||
break;
|
||||
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
|
||||
break;
|
||||
case GST_STATE_CHANGE_PAUSED_TO_READY:
|
||||
/* need to unblock the collectpads before calling the
|
||||
/* need to unblock the collectpads2 before calling the
|
||||
* parent change_state so that streaming can finish */
|
||||
gst_collect_pads_stop (adder->collect);
|
||||
gst_collect_pads2_stop (adder->collect);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
#define __GST_ADDER_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/base/gstcollectpads.h>
|
||||
#include <gst/base/gstcollectpads2.h>
|
||||
#include <gst/audio/audio.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
@ -51,7 +51,7 @@ struct _GstAdder {
|
|||
GstElement element;
|
||||
|
||||
GstPad *srcpad;
|
||||
GstCollectPads *collect;
|
||||
GstCollectPads2 *collect;
|
||||
/* pad counter, used for creating unique request pads */
|
||||
gint padcount;
|
||||
|
||||
|
|
|
@ -3442,7 +3442,8 @@ gst_decode_chain_get_topology (GstDecodeChain * chain)
|
|||
u = gst_structure_new_id_empty (topology_structure_name);
|
||||
|
||||
/* Now at the last element */
|
||||
if (chain->elements && (chain->endpad || chain->deadend)) {
|
||||
if ((chain->elements || !chain->active_group) &&
|
||||
(chain->endpad || chain->deadend)) {
|
||||
s = gst_structure_new_id_empty (topology_structure_name);
|
||||
gst_structure_id_set (u, topology_caps, GST_TYPE_CAPS, chain->endcaps,
|
||||
NULL);
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -103,6 +103,9 @@ get_int_caps (guint channels, gint endianness, guint width,
|
|||
gchar *string;
|
||||
GstAudioFormat fmt;
|
||||
|
||||
GST_DEBUG ("channels:%d, endianness:%d, width:%d, depth:%d, signedness:%d",
|
||||
channels, endianness, width, depth, signedness);
|
||||
|
||||
fmt = gst_audio_format_build_integer (signedness, endianness, width, depth);
|
||||
|
||||
string = g_strdup_printf ("audio/x-raw, "
|
||||
|
|
|
@ -168,6 +168,8 @@ GST_START_TEST (test_reuse_without_decoders)
|
|||
/* there shouldn't be any errors */
|
||||
fail_if (gst_bus_poll (GST_ELEMENT_BUS (pipe), GST_MESSAGE_ERROR, 0) != NULL);
|
||||
|
||||
GST_DEBUG ("Resetting pipeline");
|
||||
|
||||
/* reset */
|
||||
gst_element_set_state (pipe, GST_STATE_READY);
|
||||
|
||||
|
|
|
@ -986,13 +986,21 @@ GST_START_TEST (test_xmp_parsing)
|
|||
{
|
||||
GstTagList *list;
|
||||
GstBuffer *buf;
|
||||
guint i, result_size;
|
||||
guint i, j, result_size;
|
||||
gchar *text;
|
||||
const gchar *xmp_header =
|
||||
"<?xpacket begin=\"\xEF\xBB\xBF\" id=\"W5M0MpCehiHzreSzNTczkc9d\"?>"
|
||||
"<x:xmpmeta xmlns:x=\"adobe:ns:meta/\" x:xmptk=\"GStreamer\">"
|
||||
"<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\" xmlns:dc=\"http://purl.org/dc/elements/1.1/\">";
|
||||
const gchar *xmp_footer = "</rdf:RDF>" "</x:xmpmeta>" "<?xpacket end=\"r\"?>";
|
||||
|
||||
/* We used to write an extra trailing \n after the footer, keep compatibility
|
||||
* with our old generated media by checking that it still can be parsed */
|
||||
const gchar *xmp_footers[] = {
|
||||
"</rdf:RDF>" "</x:xmpmeta>" "<?xpacket end=\"r\"?>",
|
||||
"</rdf:RDF>" "</x:xmpmeta>" "<?xpacket end=\"r\"?>\n",
|
||||
NULL
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
const gchar *xmp_data;
|
||||
|
@ -1012,41 +1020,46 @@ GST_START_TEST (test_xmp_parsing)
|
|||
};
|
||||
|
||||
/* test data */
|
||||
j = 0;
|
||||
i = 0;
|
||||
while (test_data[i].xmp_data) {
|
||||
gsize len;
|
||||
while (xmp_footers[j]) {
|
||||
while (test_data[i].xmp_data) {
|
||||
gsize len;
|
||||
|
||||
GST_DEBUG ("trying test-data %u", i);
|
||||
GST_DEBUG ("trying test-data %u", i);
|
||||
|
||||
text = g_strconcat (xmp_header, test_data[i].xmp_data, xmp_footer, NULL);
|
||||
text =
|
||||
g_strconcat (xmp_header, test_data[i].xmp_data, xmp_footers[j], NULL);
|
||||
|
||||
buf = gst_buffer_new ();
|
||||
len = strlen (text) + 1;
|
||||
gst_buffer_take_memory (buf, -1,
|
||||
gst_memory_new_wrapped (0, text, NULL, len, 0, len));
|
||||
buf = gst_buffer_new ();
|
||||
len = strlen (text) + 1;
|
||||
gst_buffer_take_memory (buf, -1,
|
||||
gst_memory_new_wrapped (0, text, NULL, len, 0, len));
|
||||
|
||||
list = gst_tag_list_from_xmp_buffer (buf);
|
||||
if (test_data[i].result_size >= 0) {
|
||||
fail_unless (list != NULL);
|
||||
list = gst_tag_list_from_xmp_buffer (buf);
|
||||
if (test_data[i].result_size >= 0) {
|
||||
fail_unless (list != NULL);
|
||||
|
||||
result_size = gst_structure_n_fields ((GstStructure *) list);
|
||||
fail_unless (result_size == test_data[i].result_size);
|
||||
result_size = gst_structure_n_fields ((GstStructure *) list);
|
||||
fail_unless (result_size == test_data[i].result_size);
|
||||
|
||||
/* check the taglist content */
|
||||
switch (test_data[i].result_test) {
|
||||
case 0:
|
||||
ASSERT_TAG_LIST_HAS_STRING (list, "description", "test");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
/* check the taglist content */
|
||||
switch (test_data[i].result_test) {
|
||||
case 0:
|
||||
ASSERT_TAG_LIST_HAS_STRING (list, "description", "test");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (list)
|
||||
gst_tag_list_free (list);
|
||||
if (list)
|
||||
gst_tag_list_free (list);
|
||||
|
||||
gst_buffer_unref (buf);
|
||||
g_free (text);
|
||||
i++;
|
||||
gst_buffer_unref (buf);
|
||||
g_free (text);
|
||||
i++;
|
||||
}
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -413,15 +413,17 @@ GST_START_TEST (test_video_formats)
|
|||
fourcc = GST_MAKE_FOURCC (s[0], s[1], s[2], s[3]);
|
||||
fmt = gst_video_format_from_fourcc (fourcc);
|
||||
|
||||
if (fmt == GST_VIDEO_FORMAT_UNKNOWN)
|
||||
if (fmt == GST_VIDEO_FORMAT_UNKNOWN) {
|
||||
GST_DEBUG ("Unknown format %s, skipping tests", fourcc_list[i].fourcc);
|
||||
continue;
|
||||
}
|
||||
|
||||
vf_info = gst_video_format_get_info (fmt);
|
||||
fail_unless (vf_info != NULL);
|
||||
|
||||
fail_unless_equals_int (GST_VIDEO_FORMAT_INFO_FORMAT (vf_info), fmt);
|
||||
|
||||
GST_INFO ("Fourcc %s, packed=%", fourcc_list[i].fourcc,
|
||||
GST_INFO ("Fourcc %s, packed=%d", fourcc_list[i].fourcc,
|
||||
gst_video_format_is_packed (fmt));
|
||||
|
||||
fail_unless (GST_VIDEO_FORMAT_INFO_IS_YUV (vf_info));
|
||||
|
@ -632,7 +634,9 @@ GST_START_TEST (test_parse_caps_rgb)
|
|||
/* make sure they're serialised back correctly */
|
||||
caps2 = gst_video_info_to_caps (&vinfo);
|
||||
fail_unless (caps != NULL);
|
||||
fail_unless (gst_caps_is_equal (caps, caps2));
|
||||
fail_unless (gst_caps_is_equal (caps, caps2),
|
||||
"caps [%" GST_PTR_FORMAT "] not equal to caps2 [%" GST_PTR_FORMAT "]",
|
||||
caps, caps2);
|
||||
|
||||
gst_caps_unref (caps);
|
||||
gst_caps_unref (caps2);
|
||||
|
|
Loading…
Reference in a new issue