mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-25 17:50:36 +00:00
Merge branch 'master' into 0.11
Conflicts: ext/theora/gsttheoraenc.c
This commit is contained in:
commit
c88ee10c9b
6 changed files with 243 additions and 95 deletions
|
@ -62,11 +62,6 @@ GST_DEBUG_CATEGORY_STATIC (gst_ogg_mux_debug);
|
||||||
? GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf) \
|
? GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf) \
|
||||||
: GST_BUFFER_TIMESTAMP (buf))
|
: GST_BUFFER_TIMESTAMP (buf))
|
||||||
|
|
||||||
#define GST_BUFFER_RUNNING_TIME(buf, oggpad) \
|
|
||||||
(GST_BUFFER_DURATION_IS_VALID (buf) \
|
|
||||||
? gst_segment_to_running_time (&(oggpad)->segment, GST_FORMAT_TIME, \
|
|
||||||
GST_BUFFER_TIMESTAMP (buf)) : 0)
|
|
||||||
|
|
||||||
#define GST_GP_FORMAT "[gp %8" G_GINT64_FORMAT "]"
|
#define GST_GP_FORMAT "[gp %8" G_GINT64_FORMAT "]"
|
||||||
#define GST_GP_CAST(_gp) ((gint64) _gp)
|
#define GST_GP_CAST(_gp) ((gint64) _gp)
|
||||||
|
|
||||||
|
@ -87,11 +82,13 @@ enum
|
||||||
/* set to 0.5 seconds by default */
|
/* set to 0.5 seconds by default */
|
||||||
#define DEFAULT_MAX_DELAY G_GINT64_CONSTANT(500000000)
|
#define DEFAULT_MAX_DELAY G_GINT64_CONSTANT(500000000)
|
||||||
#define DEFAULT_MAX_PAGE_DELAY G_GINT64_CONSTANT(500000000)
|
#define DEFAULT_MAX_PAGE_DELAY G_GINT64_CONSTANT(500000000)
|
||||||
|
#define DEFAULT_MAX_TOLERANCE G_GINT64_CONSTANT(40000000)
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
ARG_0,
|
ARG_0,
|
||||||
ARG_MAX_DELAY,
|
ARG_MAX_DELAY,
|
||||||
ARG_MAX_PAGE_DELAY,
|
ARG_MAX_PAGE_DELAY,
|
||||||
|
ARG_MAX_TOLERANCE
|
||||||
};
|
};
|
||||||
|
|
||||||
static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
|
static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
|
||||||
|
@ -167,6 +164,11 @@ gst_ogg_mux_class_init (GstOggMuxClass * klass)
|
||||||
"Maximum delay for sending out a page", 0, G_MAXUINT64,
|
"Maximum delay for sending out a page", 0, G_MAXUINT64,
|
||||||
DEFAULT_MAX_PAGE_DELAY,
|
DEFAULT_MAX_PAGE_DELAY,
|
||||||
(GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
(GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||||
|
g_object_class_install_property (gobject_class, ARG_MAX_TOLERANCE,
|
||||||
|
g_param_spec_uint64 ("max-tolerance", "Max time tolerance",
|
||||||
|
"Maximum timestamp difference for maintaining perfect granules",
|
||||||
|
0, G_MAXUINT64, DEFAULT_MAX_TOLERANCE,
|
||||||
|
(GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||||
|
|
||||||
gstelement_class->change_state = gst_ogg_mux_change_state;
|
gstelement_class->change_state = gst_ogg_mux_change_state;
|
||||||
|
|
||||||
|
@ -220,6 +222,7 @@ gst_ogg_mux_init (GstOggMux * ogg_mux)
|
||||||
|
|
||||||
ogg_mux->max_delay = DEFAULT_MAX_DELAY;
|
ogg_mux->max_delay = DEFAULT_MAX_DELAY;
|
||||||
ogg_mux->max_page_delay = DEFAULT_MAX_PAGE_DELAY;
|
ogg_mux->max_page_delay = DEFAULT_MAX_PAGE_DELAY;
|
||||||
|
ogg_mux->max_tolerance = DEFAULT_MAX_TOLERANCE;
|
||||||
|
|
||||||
gst_ogg_mux_clear (ogg_mux);
|
gst_ogg_mux_clear (ogg_mux);
|
||||||
}
|
}
|
||||||
|
@ -403,6 +406,8 @@ gst_ogg_mux_request_new_pad (GstElement * element,
|
||||||
oggpad->pagebuffers = g_queue_new ();
|
oggpad->pagebuffers = g_queue_new ();
|
||||||
oggpad->map.headers = NULL;
|
oggpad->map.headers = NULL;
|
||||||
oggpad->map.queued = NULL;
|
oggpad->map.queued = NULL;
|
||||||
|
oggpad->next_granule = 0;
|
||||||
|
oggpad->keyframe_granule = -1;
|
||||||
|
|
||||||
gst_segment_init (&oggpad->segment, GST_FORMAT_TIME);
|
gst_segment_init (&oggpad->segment, GST_FORMAT_TIME);
|
||||||
|
|
||||||
|
@ -500,7 +505,7 @@ gst_ogg_mux_push_buffer (GstOggMux * mux, GstBuffer * buffer,
|
||||||
|
|
||||||
/* Ensure we have monotonically increasing timestamps in the output. */
|
/* Ensure we have monotonically increasing timestamps in the output. */
|
||||||
if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer)) {
|
if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer)) {
|
||||||
gint64 run_time = GST_BUFFER_RUNNING_TIME (buffer, oggpad);
|
gint64 run_time = GST_BUFFER_TIMESTAMP (buffer);
|
||||||
if (mux->last_ts != GST_CLOCK_TIME_NONE && run_time < mux->last_ts)
|
if (mux->last_ts != GST_CLOCK_TIME_NONE && run_time < mux->last_ts)
|
||||||
GST_BUFFER_TIMESTAMP (buffer) = mux->last_ts;
|
GST_BUFFER_TIMESTAMP (buffer) = mux->last_ts;
|
||||||
else
|
else
|
||||||
|
@ -699,11 +704,6 @@ gst_ogg_mux_compare_pads (GstOggMux * ogg_mux, GstOggPadData * first,
|
||||||
if (secondtime == GST_CLOCK_TIME_NONE)
|
if (secondtime == GST_CLOCK_TIME_NONE)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
firsttime = gst_segment_to_running_time (&first->segment, GST_FORMAT_TIME,
|
|
||||||
firsttime);
|
|
||||||
secondtime = gst_segment_to_running_time (&second->segment, GST_FORMAT_TIME,
|
|
||||||
secondtime);
|
|
||||||
|
|
||||||
/* first buffer has higher timestamp, second one should go first */
|
/* first buffer has higher timestamp, second one should go first */
|
||||||
if (secondtime < firsttime)
|
if (secondtime < firsttime)
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -723,6 +723,116 @@ gst_ogg_mux_compare_pads (GstOggMux * ogg_mux, GstOggPadData * first,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GstBuffer *
|
||||||
|
gst_ogg_mux_decorate_buffer (GstOggMux * ogg_mux, GstOggPadData * pad,
|
||||||
|
GstBuffer * buf)
|
||||||
|
{
|
||||||
|
GstClockTime time;
|
||||||
|
gint64 duration, granule, limit;
|
||||||
|
GstClockTime next_time;
|
||||||
|
GstClockTimeDiff diff;
|
||||||
|
ogg_packet packet;
|
||||||
|
gsize size;
|
||||||
|
|
||||||
|
/* ensure messing with metadata is ok */
|
||||||
|
buf = gst_buffer_make_writable (buf);
|
||||||
|
|
||||||
|
/* convert time to running time, so we need no longer bother about that */
|
||||||
|
time = GST_BUFFER_TIMESTAMP (buf);
|
||||||
|
if (G_LIKELY (GST_CLOCK_TIME_IS_VALID (time))) {
|
||||||
|
time = gst_segment_to_running_time (&pad->segment, GST_FORMAT_TIME, time);
|
||||||
|
if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (time))) {
|
||||||
|
gst_buffer_unref (buf);
|
||||||
|
return NULL;
|
||||||
|
} else {
|
||||||
|
GST_BUFFER_TIMESTAMP (buf) = time;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* now come up with granulepos stuff corresponding to time */
|
||||||
|
if (!pad->have_type ||
|
||||||
|
pad->map.granulerate_n <= 0 || pad->map.granulerate_d <= 0)
|
||||||
|
goto no_granule;
|
||||||
|
|
||||||
|
packet.packet = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
|
||||||
|
packet.bytes = size;
|
||||||
|
duration = gst_ogg_stream_get_packet_duration (&pad->map, &packet);
|
||||||
|
gst_buffer_unmap (buf, packet.packet, size);
|
||||||
|
|
||||||
|
/* give up if no duration can be determined, relying on upstream */
|
||||||
|
if (G_UNLIKELY (duration < 0)) {
|
||||||
|
/* well, if some day we really could handle sparse input ... */
|
||||||
|
if (pad->map.is_sparse) {
|
||||||
|
limit = 1;
|
||||||
|
diff = 2;
|
||||||
|
goto resync;
|
||||||
|
}
|
||||||
|
GST_WARNING_OBJECT (pad->collect.pad,
|
||||||
|
"failed to determine packet duration");
|
||||||
|
goto no_granule;
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_LOG_OBJECT (pad->collect.pad, "buffer ts %" GST_TIME_FORMAT
|
||||||
|
", duration %" GST_TIME_FORMAT ", granule duration %" G_GINT64_FORMAT,
|
||||||
|
GST_TIME_ARGS (time), GST_TIME_ARGS (GST_BUFFER_DURATION (buf)),
|
||||||
|
duration);
|
||||||
|
|
||||||
|
/* determine granule corresponding to time,
|
||||||
|
* using the inverse of oggdemux' granule -> time */
|
||||||
|
|
||||||
|
/* see if interpolated granule matches good enough */
|
||||||
|
granule = pad->next_granule;
|
||||||
|
next_time = gst_ogg_stream_granule_to_time (&pad->map, pad->next_granule);
|
||||||
|
diff = GST_CLOCK_DIFF (next_time, time);
|
||||||
|
|
||||||
|
/* we tolerate deviation up to configured or within granule granularity */
|
||||||
|
limit = gst_ogg_stream_granule_to_time (&pad->map, 1) / 2;
|
||||||
|
limit = MAX (limit, ogg_mux->max_tolerance);
|
||||||
|
|
||||||
|
GST_LOG_OBJECT (pad->collect.pad, "expected granule %" G_GINT64_FORMAT " == "
|
||||||
|
"time %" GST_TIME_FORMAT " --> ts diff %" GST_TIME_FORMAT
|
||||||
|
" < tolerance %" GST_TIME_FORMAT " (?)",
|
||||||
|
granule, GST_TIME_ARGS (next_time), GST_TIME_ARGS (ABS (diff)),
|
||||||
|
GST_TIME_ARGS (limit));
|
||||||
|
|
||||||
|
resync:
|
||||||
|
/* if not good enough, determine granule based on time */
|
||||||
|
if (diff > limit || diff < -limit) {
|
||||||
|
granule = gst_util_uint64_scale_round (time, pad->map.granulerate_n,
|
||||||
|
GST_SECOND * pad->map.granulerate_d);
|
||||||
|
GST_DEBUG_OBJECT (pad->collect.pad,
|
||||||
|
"resyncing to determined granule %" G_GINT64_FORMAT, granule);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pad->map.is_ogm || pad->map.is_sparse) {
|
||||||
|
pad->next_granule = granule;
|
||||||
|
} else {
|
||||||
|
granule += duration;
|
||||||
|
pad->next_granule = granule;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* track previous keyframe */
|
||||||
|
if (!GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT))
|
||||||
|
pad->keyframe_granule = granule;
|
||||||
|
|
||||||
|
/* determine corresponding time and granulepos */
|
||||||
|
GST_BUFFER_OFFSET (buf) = gst_ogg_stream_granule_to_time (&pad->map, granule);
|
||||||
|
GST_BUFFER_OFFSET_END (buf) =
|
||||||
|
gst_ogg_stream_granule_to_granulepos (&pad->map, granule,
|
||||||
|
pad->keyframe_granule);
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
|
||||||
|
/* ERRORS */
|
||||||
|
no_granule:
|
||||||
|
{
|
||||||
|
GST_DEBUG_OBJECT (pad->collect.pad, "could not determine granulepos, "
|
||||||
|
"falling back to upstream provided metadata");
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* make sure at least one buffer is queued on all pads, two if possible
|
/* make sure at least one buffer is queued on all pads, two if possible
|
||||||
*
|
*
|
||||||
* if pad->buffer == NULL, pad->next_buffer != NULL, then
|
* if pad->buffer == NULL, pad->next_buffer != NULL, then
|
||||||
|
@ -786,11 +896,6 @@ gst_ogg_mux_queue_pads (GstOggMux * ogg_mux)
|
||||||
packet.packet = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
|
packet.packet = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
|
||||||
packet.bytes = size;
|
packet.bytes = size;
|
||||||
|
|
||||||
if (GST_BUFFER_OFFSET_END_IS_VALID (buf))
|
|
||||||
packet.granulepos = GST_BUFFER_OFFSET_END (buf);
|
|
||||||
else
|
|
||||||
packet.granulepos = 0;
|
|
||||||
|
|
||||||
/* if we're not yet in data mode, ensure we're setup on the first packet */
|
/* if we're not yet in data mode, ensure we're setup on the first packet */
|
||||||
if (!pad->have_type) {
|
if (!pad->have_type) {
|
||||||
GstCaps *caps;
|
GstCaps *caps;
|
||||||
|
@ -837,8 +942,25 @@ gst_ogg_mux_queue_pads (GstOggMux * ogg_mux)
|
||||||
"got data buffer in control state, switching to data mode");
|
"got data buffer in control state, switching to data mode");
|
||||||
/* this is a data buffer so switch to data state */
|
/* this is a data buffer so switch to data state */
|
||||||
pad->state = GST_OGG_PAD_STATE_DATA;
|
pad->state = GST_OGG_PAD_STATE_DATA;
|
||||||
|
|
||||||
|
/* check if this type of stream allows generating granulepos
|
||||||
|
* metadata here, if not, upstream will have to provide */
|
||||||
|
if (gst_ogg_stream_granule_to_granulepos (&pad->map, 1, 1) < 0) {
|
||||||
|
GST_WARNING_OBJECT (data->pad, "can not generate metadata; "
|
||||||
|
"relying on upstream");
|
||||||
|
/* disable metadata code path, otherwise not used anyway */
|
||||||
|
pad->map.granulerate_n = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* so now we should have a real data packet;
|
||||||
|
* see that it is properly decorated */
|
||||||
|
if (G_LIKELY (buf)) {
|
||||||
|
buf = gst_ogg_mux_decorate_buffer (ogg_mux, pad, buf);
|
||||||
|
if (G_UNLIKELY (!buf))
|
||||||
|
GST_DEBUG_OBJECT (data->pad, "buffer clipped");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
GST_DEBUG_OBJECT (data->pad, "EOS on pad");
|
GST_DEBUG_OBJECT (data->pad, "EOS on pad");
|
||||||
if (!pad->eos) {
|
if (!pad->eos) {
|
||||||
|
@ -1626,6 +1748,9 @@ gst_ogg_mux_get_property (GObject * object,
|
||||||
case ARG_MAX_PAGE_DELAY:
|
case ARG_MAX_PAGE_DELAY:
|
||||||
g_value_set_uint64 (value, ogg_mux->max_page_delay);
|
g_value_set_uint64 (value, ogg_mux->max_page_delay);
|
||||||
break;
|
break;
|
||||||
|
case ARG_MAX_TOLERANCE:
|
||||||
|
g_value_set_uint64 (value, ogg_mux->max_tolerance);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
|
@ -1647,6 +1772,9 @@ gst_ogg_mux_set_property (GObject * object,
|
||||||
case ARG_MAX_PAGE_DELAY:
|
case ARG_MAX_PAGE_DELAY:
|
||||||
ogg_mux->max_page_delay = g_value_get_uint64 (value);
|
ogg_mux->max_page_delay = g_value_get_uint64 (value);
|
||||||
break;
|
break;
|
||||||
|
case ARG_MAX_TOLERANCE:
|
||||||
|
ogg_mux->max_tolerance = g_value_get_uint64 (value);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -82,6 +82,9 @@ typedef struct
|
||||||
gboolean prev_delta; /* was the previous buffer a delta frame */
|
gboolean prev_delta; /* was the previous buffer a delta frame */
|
||||||
gboolean data_pushed; /* whether we pushed data already */
|
gboolean data_pushed; /* whether we pushed data already */
|
||||||
|
|
||||||
|
gint64 next_granule; /* expected granule of next buffer ts */
|
||||||
|
gint64 keyframe_granule; /* granule of last preceding keyframe */
|
||||||
|
|
||||||
GstPadEventFunction collect_event;
|
GstPadEventFunction collect_event;
|
||||||
|
|
||||||
gboolean always_flush_page;
|
gboolean always_flush_page;
|
||||||
|
@ -123,6 +126,7 @@ struct _GstOggMux
|
||||||
|
|
||||||
guint64 max_delay;
|
guint64 max_delay;
|
||||||
guint64 max_page_delay;
|
guint64 max_page_delay;
|
||||||
|
guint64 max_tolerance;
|
||||||
|
|
||||||
GstOggPadData *delta_pad; /* when a delta frame is detected on a stream, we mark
|
GstOggPadData *delta_pad; /* when a delta frame is detected on a stream, we mark
|
||||||
pages as delta frames up to the page that has the
|
pages as delta frames up to the page that has the
|
||||||
|
|
|
@ -1130,6 +1130,89 @@ theora_enc_write_multipass_cache (GstTheoraEnc * enc, gboolean begin,
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GstFlowReturn
|
||||||
|
theora_enc_encode_and_push (GstTheoraEnc * enc, ogg_packet op,
|
||||||
|
GstClockTime timestamp, GstClockTime running_time,
|
||||||
|
GstClockTime duration, GstBuffer * buffer)
|
||||||
|
{
|
||||||
|
GstFlowReturn ret;
|
||||||
|
th_ycbcr_buffer ycbcr;
|
||||||
|
gint res;
|
||||||
|
guint8 *data;
|
||||||
|
gsize size;
|
||||||
|
|
||||||
|
data = gst_buffer_map (buffer, &size, NULL, GST_MAP_READ);
|
||||||
|
theora_enc_init_buffer (ycbcr, &enc->info, data);
|
||||||
|
|
||||||
|
if (theora_enc_is_discontinuous (enc, running_time, duration)) {
|
||||||
|
theora_enc_reset (enc);
|
||||||
|
enc->granulepos_offset =
|
||||||
|
gst_util_uint64_scale (running_time, enc->fps_n,
|
||||||
|
GST_SECOND * enc->fps_d);
|
||||||
|
enc->timestamp_offset = running_time;
|
||||||
|
enc->next_ts = 0;
|
||||||
|
enc->next_discont = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enc->multipass_cache_fd
|
||||||
|
&& enc->multipass_mode == MULTIPASS_MODE_SECOND_PASS) {
|
||||||
|
if (!theora_enc_read_multipass_cache (enc)) {
|
||||||
|
ret = GST_FLOW_ERROR;
|
||||||
|
goto multipass_read_failed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res = th_encode_ycbcr_in (enc->encoder, ycbcr);
|
||||||
|
/* none of the failure cases can happen here */
|
||||||
|
g_assert (res == 0);
|
||||||
|
|
||||||
|
if (enc->multipass_cache_fd
|
||||||
|
&& enc->multipass_mode == MULTIPASS_MODE_FIRST_PASS) {
|
||||||
|
if (!theora_enc_write_multipass_cache (enc, FALSE, FALSE)) {
|
||||||
|
ret = GST_FLOW_ERROR;
|
||||||
|
goto multipass_write_failed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = GST_FLOW_OK;
|
||||||
|
while (th_encode_packetout (enc->encoder, 0, &op)) {
|
||||||
|
GstClockTime next_time;
|
||||||
|
|
||||||
|
next_time = th_granule_time (enc->encoder, op.granulepos) * GST_SECOND;
|
||||||
|
|
||||||
|
ret =
|
||||||
|
theora_push_packet (enc, &op, timestamp, enc->next_ts,
|
||||||
|
next_time - enc->next_ts);
|
||||||
|
|
||||||
|
enc->next_ts = next_time;
|
||||||
|
if (ret != GST_FLOW_OK)
|
||||||
|
goto data_push;
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
gst_buffer_unmap (buffer, data, size);
|
||||||
|
gst_buffer_unref (buffer);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* ERRORS */
|
||||||
|
multipass_read_failed:
|
||||||
|
{
|
||||||
|
GST_DEBUG_OBJECT (enc, "multipass read failed");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
multipass_write_failed:
|
||||||
|
{
|
||||||
|
GST_DEBUG_OBJECT (enc, "multipass write failed");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
data_push:
|
||||||
|
{
|
||||||
|
GST_DEBUG_OBJECT (enc, "error pushing buffer: %s", gst_flow_get_name (ret));
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
theora_enc_chain (GstPad * pad, GstBuffer * buffer)
|
theora_enc_chain (GstPad * pad, GstBuffer * buffer)
|
||||||
{
|
{
|
||||||
|
@ -1275,80 +1358,12 @@ theora_enc_chain (GstPad * pad, GstBuffer * buffer)
|
||||||
enc->next_ts = 0;
|
enc->next_ts = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
ret = theora_enc_encode_and_push (enc, op, timestamp, running_time, duration,
|
||||||
th_ycbcr_buffer ycbcr;
|
buffer);
|
||||||
gint res;
|
|
||||||
guint8 *data;
|
|
||||||
gsize size;
|
|
||||||
|
|
||||||
data = gst_buffer_map (buffer, &size, NULL, GST_MAP_READ);
|
|
||||||
theora_enc_init_buffer (ycbcr, &enc->info, data);
|
|
||||||
|
|
||||||
if (theora_enc_is_discontinuous (enc, running_time, duration)) {
|
|
||||||
theora_enc_reset (enc);
|
|
||||||
enc->granulepos_offset =
|
|
||||||
gst_util_uint64_scale (running_time, enc->fps_n,
|
|
||||||
GST_SECOND * enc->fps_d);
|
|
||||||
enc->timestamp_offset = running_time;
|
|
||||||
enc->next_ts = 0;
|
|
||||||
enc->next_discont = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (enc->multipass_cache_fd
|
|
||||||
&& enc->multipass_mode == MULTIPASS_MODE_SECOND_PASS) {
|
|
||||||
if (!theora_enc_read_multipass_cache (enc)) {
|
|
||||||
gst_buffer_unmap (buffer, data, size);
|
|
||||||
ret = GST_FLOW_ERROR;
|
|
||||||
goto multipass_read_failed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
res = th_encode_ycbcr_in (enc->encoder, ycbcr);
|
|
||||||
/* none of the failure cases can happen here */
|
|
||||||
g_assert (res == 0);
|
|
||||||
|
|
||||||
if (enc->multipass_cache_fd
|
|
||||||
&& enc->multipass_mode == MULTIPASS_MODE_FIRST_PASS) {
|
|
||||||
if (!theora_enc_write_multipass_cache (enc, FALSE, FALSE)) {
|
|
||||||
gst_buffer_unmap (buffer, data, size);
|
|
||||||
ret = GST_FLOW_ERROR;
|
|
||||||
goto multipass_write_failed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = GST_FLOW_OK;
|
|
||||||
while (th_encode_packetout (enc->encoder, 0, &op)) {
|
|
||||||
GstClockTime next_time;
|
|
||||||
|
|
||||||
next_time = th_granule_time (enc->encoder, op.granulepos) * GST_SECOND;
|
|
||||||
|
|
||||||
ret =
|
|
||||||
theora_push_packet (enc, &op, timestamp, enc->next_ts,
|
|
||||||
next_time - enc->next_ts);
|
|
||||||
|
|
||||||
enc->next_ts = next_time;
|
|
||||||
if (ret != GST_FLOW_OK) {
|
|
||||||
gst_buffer_unmap (buffer, data, size);
|
|
||||||
goto data_push;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
gst_buffer_unmap (buffer, data, size);
|
|
||||||
gst_buffer_unref (buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
/* ERRORS */
|
/* ERRORS */
|
||||||
multipass_read_failed:
|
|
||||||
{
|
|
||||||
gst_buffer_unref (buffer);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
multipass_write_failed:
|
|
||||||
{
|
|
||||||
gst_buffer_unref (buffer);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
header_buffer_alloc:
|
header_buffer_alloc:
|
||||||
{
|
{
|
||||||
gst_buffer_unref (buffer);
|
gst_buffer_unref (buffer);
|
||||||
|
@ -1359,11 +1374,6 @@ header_push:
|
||||||
gst_buffer_unref (buffer);
|
gst_buffer_unref (buffer);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
data_push:
|
|
||||||
{
|
|
||||||
gst_buffer_unref (buffer);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
encoder_disabled:
|
encoder_disabled:
|
||||||
{
|
{
|
||||||
GST_ELEMENT_ERROR (enc, STREAM, ENCODE, (NULL),
|
GST_ELEMENT_ERROR (enc, STREAM, ENCODE, (NULL),
|
||||||
|
|
|
@ -1025,9 +1025,9 @@ handle_current_async (GstDiscoverer * dc)
|
||||||
{
|
{
|
||||||
GSource *source;
|
GSource *source;
|
||||||
static GSourceCallbackFuncs cb_funcs = {
|
static GSourceCallbackFuncs cb_funcs = {
|
||||||
.ref = _void_g_object_ref,
|
_void_g_object_ref,
|
||||||
.unref = g_object_unref,
|
g_object_unref,
|
||||||
.get = get_async_cb,
|
get_async_cb,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Attach a timeout to the main context */
|
/* Attach a timeout to the main context */
|
||||||
|
|
|
@ -1215,7 +1215,9 @@ gst_tag_demux_sink_activate (GstPad * sinkpad)
|
||||||
demux->priv->strip_start + demux->priv->strip_end) {
|
demux->priv->strip_start + demux->priv->strip_end) {
|
||||||
/* There was no data (probably due to a truncated file) */
|
/* There was no data (probably due to a truncated file) */
|
||||||
GST_DEBUG_OBJECT (demux, "No data in file");
|
GST_DEBUG_OBJECT (demux, "No data in file");
|
||||||
return FALSE;
|
/* so we don't know about type either */
|
||||||
|
GST_ELEMENT_ERROR (demux, STREAM, TYPE_NOT_FOUND, (NULL), (NULL));
|
||||||
|
goto done_activate;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 3 - Do typefinding on data */
|
/* 3 - Do typefinding on data */
|
||||||
|
|
|
@ -980,7 +980,11 @@ gst_adder_request_new_pad (GstElement * element, GstPadTemplate * templ,
|
||||||
adder = GST_ADDER (element);
|
adder = GST_ADDER (element);
|
||||||
|
|
||||||
/* increment pad counter */
|
/* increment pad counter */
|
||||||
|
#if GLIB_CHECK_VERSION(2,29,5)
|
||||||
|
padcount = g_atomic_int_add (&adder->padcount, 1);
|
||||||
|
#else
|
||||||
padcount = g_atomic_int_exchange_and_add (&adder->padcount, 1);
|
padcount = g_atomic_int_exchange_and_add (&adder->padcount, 1);
|
||||||
|
#endif
|
||||||
|
|
||||||
name = g_strdup_printf ("sink%d", padcount);
|
name = g_strdup_printf ("sink%d", padcount);
|
||||||
newpad = gst_pad_new_from_template (templ, name);
|
newpad = gst_pad_new_from_template (templ, name);
|
||||||
|
|
Loading…
Reference in a new issue