diff --git a/ext/ogg/gstoggdemux.c b/ext/ogg/gstoggdemux.c index ac904e9675..f33cf328ba 100644 --- a/ext/ogg/gstoggdemux.c +++ b/ext/ogg/gstoggdemux.c @@ -491,8 +491,13 @@ gst_ogg_demux_chain_peer (GstOggPad * pad, ogg_packet * packet, } /* get timing info for the packet */ - duration = gst_ogg_stream_get_packet_duration (&pad->map, packet); - GST_DEBUG_OBJECT (ogg, "packet duration %" G_GUINT64_FORMAT, duration); + if (gst_ogg_stream_packet_is_header (&pad->map, packet)) { + duration = 0; + GST_DEBUG_OBJECT (ogg, "packet is header"); + } else { + duration = gst_ogg_stream_get_packet_duration (&pad->map, packet); + GST_DEBUG_OBJECT (ogg, "packet duration %" G_GUINT64_FORMAT, duration); + } if (packet->b_o_s) { out_timestamp = GST_CLOCK_TIME_NONE; @@ -671,13 +676,18 @@ gst_ogg_demux_collect_start_time (GstOggDemux * ogg, GstOggChain * chain) for (i = 0; i < chain->streams->len; i++) { GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i); - if (pad->map.is_sparse) + if (pad->map.is_skeleton) continue; /* can do this if the pad start time is not defined */ + GST_DEBUG_OBJECT (ogg, "Pad %08x (%s) start time is %" GST_TIME_FORMAT, + pad->map.serialno, gst_ogg_stream_get_media_type (&pad->map), + GST_TIME_ARGS (pad->start_time)); if (pad->start_time == GST_CLOCK_TIME_NONE) { - start_time = G_MAXUINT64; - break; + if (!pad->map.is_sparse) { + start_time = G_MAXUINT64; + break; + } } else { start_time = MIN (start_time, pad->start_time); } @@ -734,7 +744,7 @@ gst_ogg_pad_submit_packet (GstOggPad * pad, ogg_packet * packet) if (gst_ogg_map_parse_fisbone (&pad->map, packet->packet, packet->bytes, &serialno, &type)) { - GST_WARNING_OBJECT (pad->ogg, + GST_DEBUG_OBJECT (pad->ogg, "got skeleton packet for stream 0x%08x", serialno); skel_pad = gst_ogg_chain_get_stream (pad->chain, serialno); @@ -2626,7 +2636,7 @@ gst_ogg_demux_read_chain (GstOggDemux * ogg, GstOggChain ** res_chain) GstFlowReturn ret; GstOggChain *chain = NULL; gint64 offset = ogg->offset; - ogg_page op; + ogg_page og; gboolean done; gint i; @@ -2638,17 +2648,23 @@ gst_ogg_demux_read_chain (GstOggDemux * ogg, GstOggChain ** res_chain) GstOggPad *pad; guint32 serial; - ret = gst_ogg_demux_get_next_page (ogg, &op, -1, NULL); + ret = gst_ogg_demux_get_next_page (ogg, &og, -1, NULL); if (ret != GST_FLOW_OK) { - GST_WARNING_OBJECT (ogg, "problem reading BOS page: ret=%d", ret); + if (ret == GST_FLOW_UNEXPECTED) { + GST_DEBUG_OBJECT (ogg, "Reached EOS, done reading end chain"); + } else { + GST_WARNING_OBJECT (ogg, "problem reading BOS page: ret=%d", ret); + } break; } - if (!ogg_page_bos (&op)) { - GST_WARNING_OBJECT (ogg, "page is not BOS page"); + if (!ogg_page_bos (&og)) { + GST_INFO_OBJECT (ogg, "page is not BOS page, all streams identified"); /* if we did not find a chain yet, assume this is a bogus stream and * ignore it */ - if (!chain) + if (!chain) { + GST_WARNING_OBJECT (ogg, "No chain found, no Ogg data in stream ?"); ret = GST_FLOW_UNEXPECTED; + } break; } @@ -2657,7 +2673,7 @@ gst_ogg_demux_read_chain (GstOggDemux * ogg, GstOggChain ** res_chain) chain->offset = offset; } - serial = ogg_page_serialno (&op); + serial = ogg_page_serialno (&og); if (gst_ogg_chain_get_stream (chain, serial) != NULL) { GST_WARNING_OBJECT (ogg, "found serial %08x BOS page twice, ignoring", serial); @@ -2665,7 +2681,7 @@ gst_ogg_demux_read_chain (GstOggDemux * ogg, GstOggChain ** res_chain) } pad = gst_ogg_chain_new_stream (chain, serial); - gst_ogg_pad_submit_page (pad, &op); + gst_ogg_pad_submit_page (pad, &og); } if (ret != GST_FLOW_OK || chain == NULL) { @@ -2704,7 +2720,7 @@ gst_ogg_demux_read_chain (GstOggDemux * ogg, GstOggChain ** res_chain) gboolean known_serial = FALSE; GstFlowReturn ret; - serial = ogg_page_serialno (&op); + serial = ogg_page_serialno (&og); done = TRUE; for (i = 0; i < chain->streams->len; i++) { GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i); @@ -2718,10 +2734,10 @@ gst_ogg_demux_read_chain (GstOggDemux * ogg, GstOggChain ** res_chain) /* submit the page now, this will fill in the start_time when the * internal decoder finds it */ - gst_ogg_pad_submit_page (pad, &op); + gst_ogg_pad_submit_page (pad, &og); if (!pad->map.is_skeleton && pad->start_time == -1 - && ogg_page_eos (&op)) { + && ogg_page_eos (&og)) { /* got EOS on a pad before we could find its start_time. * We have no chance of finding a start_time for every pad so * stop searching for the other start_time(s). @@ -2747,7 +2763,7 @@ gst_ogg_demux_read_chain (GstOggDemux * ogg, GstOggChain ** res_chain) } if (!done) { - ret = gst_ogg_demux_get_next_page (ogg, &op, -1, NULL); + ret = gst_ogg_demux_get_next_page (ogg, &og, -1, NULL); if (ret != GST_FLOW_OK) break; } @@ -2805,7 +2821,7 @@ gst_ogg_demux_read_end_chain (GstOggDemux * ogg, GstOggChain * chain) for (i = 0; i < chain->streams->len; i++) { GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i); - if (pad->map.is_sparse) + if (pad->map.is_skeleton) continue; if (pad->map.serialno == ogg_page_serialno (&og)) { @@ -3677,7 +3693,8 @@ gst_ogg_print (GstOggDemux * ogg) for (j = 0; j < chain->streams->len; j++) { GstOggPad *stream = g_array_index (chain->streams, GstOggPad *, j); - GST_INFO_OBJECT (ogg, " stream %08x:", stream->map.serialno); + GST_INFO_OBJECT (ogg, " stream %08x: %s", stream->map.serialno, + gst_ogg_stream_get_media_type (&stream->map)); GST_INFO_OBJECT (ogg, " start time: %" GST_TIME_FORMAT, GST_TIME_ARGS (stream->start_time)); } diff --git a/ext/ogg/gstoggmux.c b/ext/ogg/gstoggmux.c index f153c986dc..40ce9fc2ef 100644 --- a/ext/ogg/gstoggmux.c +++ b/ext/ogg/gstoggmux.c @@ -41,6 +41,7 @@ #include #include +#include #include #include "gstoggmux.h" @@ -83,12 +84,15 @@ enum #define DEFAULT_MAX_DELAY G_GINT64_CONSTANT(500000000) #define DEFAULT_MAX_PAGE_DELAY G_GINT64_CONSTANT(500000000) #define DEFAULT_MAX_TOLERANCE G_GINT64_CONSTANT(40000000) +#define DEFAULT_SKELETON FALSE + enum { ARG_0, ARG_MAX_DELAY, ARG_MAX_PAGE_DELAY, - ARG_MAX_TOLERANCE + ARG_MAX_TOLERANCE, + ARG_SKELETON }; static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src", @@ -169,6 +173,11 @@ gst_ogg_mux_class_init (GstOggMuxClass * klass) "Maximum timestamp difference for maintaining perfect granules", 0, G_MAXUINT64, DEFAULT_MAX_TOLERANCE, (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, ARG_SKELETON, + g_param_spec_boolean ("skeleton", "Skeleton", + "Whether to include a Skeleton track", + DEFAULT_SKELETON, + (GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); gstelement_class->change_state = gst_ogg_mux_change_state; @@ -1075,14 +1084,103 @@ gst_ogg_mux_set_header_on_caps (GstCaps * caps, GList * buffers) } static void -create_header_packet (ogg_packet * packet, GstOggPadData * pad) +gst_ogg_mux_create_header_packet_with_flags (ogg_packet * packet, + gboolean bos, gboolean eos) { packet->granulepos = 0; /* mark BOS and packet number */ - packet->b_o_s = (pad->packetno == 0); - packet->packetno = pad->packetno++; + packet->b_o_s = bos; /* mark EOS */ - packet->e_o_s = 0; + packet->e_o_s = eos; +} + +static void +gst_ogg_mux_create_header_packet (ogg_packet * packet, GstOggPadData * pad) +{ + gst_ogg_mux_create_header_packet_with_flags (packet, pad->packetno == 0, 0); + packet->packetno = pad->packetno++; +} + +static void +gst_ogg_mux_submit_skeleton_header_packet (GstOggMux * mux, + ogg_stream_state * os, GstBuffer * buf, gboolean bos, gboolean eos) +{ + ogg_packet packet; + gsize size; + + packet.packet = gst_buffer_map (buf, &size, NULL, GST_MAP_READ); + packet.bytes = size; + gst_ogg_mux_create_header_packet_with_flags (&packet, bos, eos); + ogg_stream_packetin (os, &packet); + gst_buffer_unref (buf); +} + +static void +gst_ogg_mux_make_fishead (GstOggMux * mux, ogg_stream_state * os) +{ + GstByteWriter bw; + GstBuffer *fishead; + + GST_DEBUG_OBJECT (mux, "Creating fishead"); + + gst_byte_writer_init_with_size (&bw, 64, TRUE); + gst_byte_writer_put_string_utf8 (&bw, "fishead"); + gst_byte_writer_put_int16_le (&bw, 3); /* version major */ + gst_byte_writer_put_int16_le (&bw, 0); /* version minor */ + gst_byte_writer_put_int64_le (&bw, 0); /* presentation time numerator */ + gst_byte_writer_put_int64_le (&bw, 1000); /* ...and denominator */ + gst_byte_writer_put_int64_le (&bw, 0); /* base time numerator */ + gst_byte_writer_put_int64_le (&bw, 1000); /* ...and denominator */ + gst_byte_writer_fill (&bw, ' ', 20); /* UTC time */ + g_assert (gst_byte_writer_get_pos (&bw) == 64); + fishead = gst_byte_writer_reset_and_get_buffer (&bw); + gst_ogg_mux_submit_skeleton_header_packet (mux, os, fishead, 1, 0); +} + +static void +gst_ogg_mux_byte_writer_put_string_utf8 (GstByteWriter * bw, const char *s) +{ + gst_byte_writer_put_data (bw, (const guint8 *) s, strlen (s)); +} + +static void +gst_ogg_mux_make_fisbone (GstOggMux * mux, ogg_stream_state * os, + GstOggPadData * pad) +{ + GstByteWriter bw; + + GST_DEBUG_OBJECT (mux, + "Creating %s fisbone for serial %08x", + gst_ogg_stream_get_media_type (&pad->map), pad->map.serialno); + + gst_byte_writer_init (&bw); + gst_byte_writer_put_string_utf8 (&bw, "fisbone"); + gst_byte_writer_put_int32_le (&bw, 44); /* offset to message headers */ + gst_byte_writer_put_uint32_le (&bw, pad->map.serialno); + gst_byte_writer_put_uint32_le (&bw, pad->map.n_header_packets); + gst_byte_writer_put_uint64_le (&bw, pad->map.granulerate_n); + gst_byte_writer_put_uint64_le (&bw, pad->map.granulerate_d); + gst_byte_writer_put_uint64_le (&bw, 0); /* base granule */ + gst_byte_writer_put_uint32_le (&bw, pad->map.preroll); + gst_byte_writer_put_uint8 (&bw, pad->map.granuleshift); + gst_byte_writer_fill (&bw, 0, 3); /* padding */ + /* message header fields - MIME type for now */ + gst_ogg_mux_byte_writer_put_string_utf8 (&bw, "Content-Type: "); + gst_ogg_mux_byte_writer_put_string_utf8 (&bw, + gst_ogg_stream_get_media_type (&pad->map)); + gst_ogg_mux_byte_writer_put_string_utf8 (&bw, "\r\n"); + + gst_ogg_mux_submit_skeleton_header_packet (mux, os, + gst_byte_writer_reset_and_get_buffer (&bw), 0, 0); +} + +static void +gst_ogg_mux_make_fistail (GstOggMux * mux, ogg_stream_state * os) +{ + GST_DEBUG_OBJECT (mux, "Creating fistail"); + + gst_ogg_mux_submit_skeleton_header_packet (mux, os, + gst_buffer_new_and_alloc (0), 0, 1); } /* @@ -1100,6 +1198,8 @@ gst_ogg_mux_send_headers (GstOggMux * mux) GList *hbufs, *hwalk; GstCaps *caps; GstFlowReturn ret; + ogg_page page; + ogg_stream_state skeleton_stream; hbufs = NULL; ret = GST_FLOW_OK; @@ -1132,7 +1232,6 @@ gst_ogg_mux_send_headers (GstOggMux * mux) GstOggPadData *pad; GstBuffer *buf; ogg_packet packet; - ogg_page page; GstPad *thepad; GstCaps *caps; GstStructure *structure; @@ -1169,7 +1268,7 @@ gst_ogg_mux_send_headers (GstOggMux * mux) packet.packet = gst_buffer_map (buf, &size, NULL, GST_MAP_READ); packet.bytes = size; - create_header_packet (&packet, pad); + gst_ogg_mux_create_header_packet (&packet, pad); /* swap the packet in */ ogg_stream_packetin (&pad->map.stream, &packet); @@ -1203,6 +1302,16 @@ gst_ogg_mux_send_headers (GstOggMux * mux) gst_caps_unref (caps); } + /* The Skeleton BOS goes first - even before the video that went first before */ + if (mux->use_skeleton) { + ogg_stream_init (&skeleton_stream, gst_ogg_mux_generate_serialno (mux)); + gst_ogg_mux_make_fishead (mux, &skeleton_stream); + while (ogg_stream_flush (&skeleton_stream, &page) > 0) { + GstBuffer *hbuf = gst_ogg_mux_buffer_from_page (mux, &page, FALSE); + hbufs = g_list_append (hbufs, hbuf); + } + } + GST_LOG_OBJECT (mux, "creating next headers"); walk = mux->collect->data; while (walk) { @@ -1214,6 +1323,9 @@ gst_ogg_mux_send_headers (GstOggMux * mux) walk = walk->next; + if (mux->use_skeleton) + gst_ogg_mux_make_fisbone (mux, &skeleton_stream, pad); + GST_LOG_OBJECT (mux, "looping over headers for pad %s:%s", GST_DEBUG_PAD_NAME (thepad)); @@ -1230,7 +1342,7 @@ gst_ogg_mux_send_headers (GstOggMux * mux) packet.packet = gst_buffer_map (buf, &size, NULL, GST_MAP_READ); packet.bytes = size; - create_header_packet (&packet, pad); + gst_ogg_mux_create_header_packet (&packet, pad); /* swap the packet in */ ogg_stream_packetin (&pad->map.stream, &packet); @@ -1262,6 +1374,21 @@ gst_ogg_mux_send_headers (GstOggMux * mux) g_list_free (pad->map.headers); pad->map.headers = NULL; } + + if (mux->use_skeleton) { + /* flush accumulated fisbones, the fistail must be on a separate page */ + while (ogg_stream_flush (&skeleton_stream, &page) > 0) { + GstBuffer *hbuf = gst_ogg_mux_buffer_from_page (mux, &page, FALSE); + hbufs = g_list_append (hbufs, hbuf); + } + gst_ogg_mux_make_fistail (mux, &skeleton_stream); + while (ogg_stream_flush (&skeleton_stream, &page) > 0) { + GstBuffer *hbuf = gst_ogg_mux_buffer_from_page (mux, &page, FALSE); + hbufs = g_list_append (hbufs, hbuf); + } + ogg_stream_clear (&skeleton_stream); + } + /* hbufs holds all buffers for the headers now */ /* create caps with the buffers */ @@ -1706,6 +1833,9 @@ gst_ogg_mux_get_property (GObject * object, case ARG_MAX_TOLERANCE: g_value_set_uint64 (value, ogg_mux->max_tolerance); break; + case ARG_SKELETON: + g_value_set_boolean (value, ogg_mux->use_skeleton); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1730,6 +1860,9 @@ gst_ogg_mux_set_property (GObject * object, case ARG_MAX_TOLERANCE: ogg_mux->max_tolerance = g_value_get_uint64 (value); break; + case ARG_SKELETON: + ogg_mux->use_skeleton = g_value_get_boolean (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; diff --git a/ext/ogg/gstoggmux.h b/ext/ogg/gstoggmux.h index 3edc1f5b51..3db42e7a5b 100644 --- a/ext/ogg/gstoggmux.h +++ b/ext/ogg/gstoggmux.h @@ -127,6 +127,9 @@ struct _GstOggMux pages as delta frames up to the page that has the keyframe */ + + /* whether to create a skeleton track */ + gboolean use_skeleton; }; struct _GstOggMuxClass diff --git a/ext/ogg/gstoggstream.c b/ext/ogg/gstoggstream.c index c694fad07c..317237d92f 100644 --- a/ext/ogg/gstoggstream.c +++ b/ext/ogg/gstoggstream.c @@ -139,7 +139,8 @@ gst_ogg_stream_granulepos_to_granule (GstOggStream * pad, gint64 granulepos) } if (mappers[pad->map].granulepos_to_granule_func == NULL) { - GST_WARNING ("Failed to convert granulepos to granule"); + GST_WARNING ("Failed to convert %s granulepos to granule", + gst_ogg_stream_get_media_type (pad)); return -1; } @@ -168,7 +169,8 @@ gst_ogg_stream_granule_to_granulepos (GstOggStream * pad, gint64 granule, } if (mappers[pad->map].granule_to_granulepos_func == NULL) { - GST_WARNING ("Failed to convert granule to granulepos"); + GST_WARNING ("Failed to convert %s granule to granulepos", + gst_ogg_stream_get_media_type (pad)); return -1; } @@ -184,7 +186,8 @@ gst_ogg_stream_granulepos_is_key_frame (GstOggStream * pad, gint64 granulepos) } if (mappers[pad->map].is_key_frame_func == NULL) { - GST_WARNING ("Failed to determine key frame"); + GST_WARNING ("Failed to determine keyframeness for %s granulepos", + gst_ogg_stream_get_media_type (pad)); return FALSE; } @@ -195,7 +198,8 @@ gboolean gst_ogg_stream_packet_is_header (GstOggStream * pad, ogg_packet * packet) { if (mappers[pad->map].is_header_func == NULL) { - GST_WARNING ("Failed to determine header"); + GST_WARNING ("Failed to determine headerness of %s packet", + gst_ogg_stream_get_media_type (pad)); return FALSE; } @@ -206,7 +210,8 @@ gint64 gst_ogg_stream_get_packet_duration (GstOggStream * pad, ogg_packet * packet) { if (mappers[pad->map].packet_duration_func == NULL) { - GST_WARNING ("Failed to determine packet duration"); + GST_WARNING ("Failed to determine %s packet duration", + gst_ogg_stream_get_media_type (pad)); return -1; } @@ -1087,7 +1092,7 @@ setup_fishead_mapper (GstOggStream * pad, ogg_packet * packet) pad->is_skeleton = TRUE; pad->is_sparse = TRUE; - pad->caps = gst_caps_new_simple ("none/none", NULL); + pad->caps = gst_caps_new_simple ("application/x-ogg-skeleton", NULL); return TRUE; } @@ -1099,12 +1104,15 @@ gst_ogg_map_parse_fisbone (GstOggStream * pad, const guint8 * data, guint size, GstOggSkeleton stype; guint serial_offset; - if (size < SKELETON_FISBONE_MIN_SIZE) { + if (size != 0 && size < SKELETON_FISBONE_MIN_SIZE) { GST_WARNING ("small fisbone packet of size %d, ignoring", size); return FALSE; } - if (memcmp (data, "fisbone\0", 8) == 0) { + if (size == 0) { + /* Skeleton EOS packet is zero bytes */ + return FALSE; + } else if (memcmp (data, "fisbone\0", 8) == 0) { GST_INFO ("got fisbone packet"); stype = GST_OGG_SKELETON_FISBONE; serial_offset = 12; diff --git a/ext/vorbis/gstvorbisenc.c b/ext/vorbis/gstvorbisenc.c index f5ff3d37e9..54800bb26a 100644 --- a/ext/vorbis/gstvorbisenc.c +++ b/ext/vorbis/gstvorbisenc.c @@ -1000,12 +1000,12 @@ gst_vorbis_enc_buffer_check_discontinuous (GstVorbisEnc * vorbisenc, vorbisenc->expected_ts != GST_CLOCK_TIME_NONE && timestamp + duration != vorbisenc->expected_ts) { /* It turns out that a lot of elements don't generate perfect streams due - * to rounding errors. So, we permit small errors (< 1/2 a sample) without + * to rounding errors. So, we permit small errors (< 3 samples) without * causing a discont. */ - int halfsample = GST_SECOND / vorbisenc->frequency / 2; + int threesample = GST_SECOND / vorbisenc->frequency * 3; - if ((GstClockTimeDiff) (timestamp - vorbisenc->expected_ts) > halfsample) { + if ((GstClockTimeDiff) (timestamp - vorbisenc->expected_ts) > threesample) { GST_DEBUG_OBJECT (vorbisenc, "Expected TS %" GST_TIME_FORMAT ", buffer TS %" GST_TIME_FORMAT, GST_TIME_ARGS (vorbisenc->expected_ts), GST_TIME_ARGS (timestamp)); @@ -1119,30 +1119,38 @@ gst_vorbis_enc_chain (GstPad * pad, GstBuffer * buffer) if (vorbisenc->expected_ts != GST_CLOCK_TIME_NONE && timestamp < vorbisenc->expected_ts) { + int threesample = GST_SECOND / vorbisenc->frequency * 3; guint64 diff = vorbisenc->expected_ts - timestamp; guint64 diff_bytes; gsize size; - GST_WARNING_OBJECT (vorbisenc, "Buffer is older than previous " - "timestamp + duration (%" GST_TIME_FORMAT "< %" GST_TIME_FORMAT - "), cannot handle. Clipping buffer.", - GST_TIME_ARGS (timestamp), GST_TIME_ARGS (vorbisenc->expected_ts)); + /* Don't freak out on tiny jitters; use the same < 3 sample + tolerance as in the discontinuous detection */ + if ((GstClockTimeDiff) (vorbisenc->expected_ts - timestamp) > threesample) { - size = gst_buffer_get_size (buffer); + GST_WARNING_OBJECT (vorbisenc, "Buffer is older than previous " + "timestamp + duration (%" GST_TIME_FORMAT "< %" GST_TIME_FORMAT + "), cannot handle. Clipping buffer.", + GST_TIME_ARGS (timestamp), GST_TIME_ARGS (vorbisenc->expected_ts)); - diff_bytes = - GST_CLOCK_TIME_TO_FRAMES (diff, - vorbisenc->frequency) * vorbisenc->channels * sizeof (gfloat); - if (diff_bytes >= size) { - gst_buffer_unref (buffer); - return GST_FLOW_OK; + size = gst_buffer_get_size (buffer); + + diff_bytes = + GST_CLOCK_TIME_TO_FRAMES (diff, + vorbisenc->frequency) * vorbisenc->channels * sizeof (gfloat); + if (diff_bytes >= size) { + gst_buffer_unref (buffer); + return GST_FLOW_OK; + } + buffer = gst_buffer_make_writable (buffer); + gst_buffer_resize (buffer, diff_bytes, size - diff_bytes); + + if (GST_BUFFER_DURATION_IS_VALID (buffer)) + GST_BUFFER_DURATION (buffer) -= diff; } - buffer = gst_buffer_make_writable (buffer); - gst_buffer_resize (buffer, diff_bytes, size - diff_bytes); + /* adjust the input timestamp in either case */ GST_BUFFER_TIMESTAMP (buffer) += diff; - if (GST_BUFFER_DURATION_IS_VALID (buffer)) - GST_BUFFER_DURATION (buffer) -= diff; } if (gst_vorbis_enc_buffer_check_discontinuous (vorbisenc, timestamp,