GST_OGG_SET_STATE (ogg, GST_OGG_STATE_SEEK);
FOR_PAD_IN_CURRENT_CHAIN (ogg, pad,
- pad->flags |= GST_OGG_PAD_NEEDS_DISCONT;);
+ pad->flags |= GST_OGG_PAD_NEEDS_DISCONT;
+ );
GST_DEBUG_OBJECT (ogg,
"initiating seeking to format %d, offset %" G_GUINT64_FORMAT, format,
offset);
gst_event_unref (event);
GST_FLAG_UNSET (ogg, GST_OGG_FLAG_WAIT_FOR_DISCONT);
FOR_PAD_IN_CURRENT_CHAIN (ogg, pad,
- pad->flags |= GST_OGG_PAD_NEEDS_DISCONT;);
+ pad->flags |= GST_OGG_PAD_NEEDS_DISCONT;
+ );
break;
default:
gst_pad_event_default (pad, event);
*end = G_MAXINT64;
g_assert (ogg->current_chain >= 0);
- FOR_PAD_IN_CURRENT_CHAIN (ogg, pad, *start = MAX (*start, pad->end_offset););
+ FOR_PAD_IN_CURRENT_CHAIN (ogg, pad, *start = MAX (*start, pad->end_offset);
+ );
if (ogg->setup_state == SETUP_FIND_LAST_CHAIN) {
*end = gst_file_pad_get_length (ogg->sinkpad);
} else {
endpos = G_MAXINT64;
FOR_PAD_IN_CHAIN (ogg, pad, ogg->chains->len - 1,
- endpos = MIN (endpos, pad->start_offset););
+ endpos = MIN (endpos, pad->start_offset);
+ );
}
if (!ogg->seek_skipped || gst_ogg_demux_position (ogg) >= endpos) {
/* have we found the endposition for all streams yet? */
break;
case 1:
GST_LOG_OBJECT (ogg,
- "processing ogg page (serial %d, packet %ld, granule pos %llu",
+ "processing ogg page (serial %d, packet %ld, granule pos %llu, state: %d",
ogg_page_serialno (&page), ogg_page_pageno (&page),
- ogg_page_granulepos (&page));
+ ogg_page_granulepos (&page), ogg->state);
switch (ogg->state) {
case GST_OGG_STATE_SETUP:
if (!setup_funcs[ogg->setup_state].process (ogg, &page)) {
while (TRUE) {
ret = ogg_stream_packetout (&pad->stream, &packet);
+ GST_LOG_OBJECT (ogg, "packetout gave %d", ret);
switch (ret) {
case 0:
return;
case -1:
- gst_ogg_pad_reset (ogg, pad);
+ /* out of sync, could call gst_ogg_pad_reset() here but ogg can decode
+ * the packet just fine. We should probably send a DISCONT though. */
break;
case 1:{
/* only push data when playing, not during seek or similar */
guint state; /* state of the pad */
GList *headers;
+
+ gboolean new_page; /* starting a new page */
+ gboolean first_delta; /* was the first packet in the page a delta */
+ gboolean prev_delta; /* was the previous buffer a delta frame */
}
GstOggPad;
guint64 max_delay;
guint64 max_page_delay;
- gboolean keyframe_mode; /* when a delta frame is detected on a stream, we mark
+ GstOggPad *delta_pad; /* when a delta frame is detected on a stream, we mark
pages as delta frames up to the page that has the
keyframe */
};
ogg_mux->max_delay = DEFAULT_MAX_DELAY;
ogg_mux->max_page_delay = DEFAULT_MAX_PAGE_DELAY;
+ ogg_mux->delta_pad = NULL;
+
gst_element_set_loop_function (GST_ELEMENT (ogg_mux), gst_ogg_mux_loop);
}
oggpad->eos = FALSE;
/* we assume there will be some control data first for this pad */
oggpad->state = GST_OGG_PAD_STATE_CONTROL;
+ oggpad->new_page = TRUE;
+ oggpad->first_delta = FALSE;
+ oggpad->prev_delta = FALSE;
/* save a pointer to our data in the pad */
gst_pad_set_element_private (newpad, oggpad);
GST_DEBUG ("muxer: got incaps buffer in control state, ignoring");
/* just ignore */
gst_buffer_unref (buf);
+ /* pull next one in next iteration */
data = NULL;
} else {
GST_DEBUG
}
static GstBuffer *
-gst_ogg_mux_buffer_from_page (GstOggMux * mux, ogg_page * page)
+gst_ogg_mux_buffer_from_page (GstOggMux * mux, ogg_page * page, gboolean delta)
{
GstBuffer *buffer;
GST_BUFFER_OFFSET (buffer) = mux->offset;
mux->offset += GST_BUFFER_SIZE (buffer);
GST_BUFFER_OFFSET_END (buffer) = mux->offset;
+ if (delta)
+ GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_DELTA_UNIT);
return buffer;
}
static void
-gst_ogg_mux_push_page (GstOggMux * mux, ogg_page * page)
+gst_ogg_mux_push_page (GstOggMux * mux, ogg_page * page, gboolean delta)
{
if (GST_PAD_IS_USABLE (mux->srcpad)) {
- GstBuffer *buffer = gst_ogg_mux_buffer_from_page (mux, page);
+ GstBuffer *buffer = gst_ogg_mux_buffer_from_page (mux, page, delta);
gst_pad_push (mux->srcpad, GST_DATA (buffer));
}
GST_LOG ("flushing page with first packet");
while (ogg_stream_flush (&pad->stream, &page)) {
- GstBuffer *hbuf = gst_ogg_mux_buffer_from_page (mux, &page);
+ GstBuffer *hbuf = gst_ogg_mux_buffer_from_page (mux, &page, FALSE);
GST_LOG ("swapped out page");
hbufs = g_list_append (hbufs, hbuf);
GST_LOG ("flushing page as packet %d is first or last packet",
pad->packetno);
while (ogg_stream_flush (&pad->stream, &page)) {
- GstBuffer *hbuf = gst_ogg_mux_buffer_from_page (mux, &page);
+ GstBuffer *hbuf = gst_ogg_mux_buffer_from_page (mux, &page, FALSE);
GST_LOG ("swapped out page");
hbufs = g_list_append (hbufs, hbuf);
GST_LOG ("try to swap out page");
/* just try to swap out a page then */
while (ogg_stream_pageout (&pad->stream, &page) > 0) {
- GstBuffer *hbuf = gst_ogg_mux_buffer_from_page (mux, &page);
+ GstBuffer *hbuf = gst_ogg_mux_buffer_from_page (mux, &page, FALSE);
GST_LOG ("swapped out page");
hbufs = g_list_append (hbufs, hbuf);
{
GstOggMux *ogg_mux;
GstOggPad *best;
+ gboolean delta_unit;
ogg_mux = GST_OGG_MUX (element);
ogg_page page;
while (ogg_stream_flush (&ogg_mux->pulling->stream, &page)) {
- gst_ogg_mux_push_page (ogg_mux, &page);
+ gst_ogg_mux_push_page (ogg_mux, &page, ogg_mux->pulling->first_delta);
/* increment the page number counter */
ogg_mux->pulling->pageno++;
+ ogg_mux->pulling->first_delta = TRUE;
}
ogg_mux->pulling = NULL;
+ ogg_mux->pulling->new_page = TRUE;
}
}
GstBuffer *buf, *tmpbuf;
GstOggPad *pad = ogg_mux->pulling;
gint64 duration;
+ gboolean force_flush;
/* now see if we have a buffer */
buf = pad->buffer;
}
}
+ delta_unit = GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_DELTA_UNIT);
duration = GST_BUFFER_DURATION (buf);
/* create a packet from the buffer */
/* mark EOS */
packet.e_o_s = (tmpbuf == NULL ? 1 : 0);
- /* swap the packet in */
- ogg_stream_packetin (&pad->stream, &packet);
-
- /* don't need the old buffer anymore */
- gst_buffer_unref (pad->buffer);
- /* store new readahead buffer */
- pad->buffer = tmpbuf;
-
+ /* we flush when we see a new keyframe */
+ force_flush = (pad->prev_delta && !delta_unit);
if (duration != -1) {
pad->duration += duration;
/* if page duration exceeds max, flush page */
if (pad->duration > ogg_mux->max_page_delay) {
- while (ogg_stream_flush (&pad->stream, &page)) {
- gst_ogg_mux_push_page (ogg_mux, &page);
- /* increment the page number counter */
- pad->pageno++;
- }
+ force_flush = TRUE;
pad->duration = 0;
- return;
}
}
- /* flush out the pages now. The packet we got could end up in
- * more than one page so we need to flush them all */
+ /* force flush */
+ if (force_flush) {
+ while (ogg_stream_flush (&pad->stream, &page)) {
+ gst_ogg_mux_push_page (ogg_mux, &page, pad->first_delta);
+ /* increment the page number counter */
+ pad->pageno++;
+ pad->first_delta = TRUE;
+ }
+ pad->new_page = TRUE;
+ }
+
+ /* if this is the first packet of a new page figure out the delta flag */
+ if (pad->new_page) {
+ if (delta_unit) {
+ /* This page is a delta frame */
+ if (ogg_mux->delta_pad == NULL) {
+ /* we got a delta unit on this pad */
+ ogg_mux->delta_pad = pad;
+ }
+ /* mark the page as delta */
+ pad->first_delta = TRUE;
+ } else {
+ /* got a keyframe */
+ if (ogg_mux->delta_pad == pad) {
+ /* if we get it on the pad with deltaunits,
+ * we mark the page as non delta */
+ pad->first_delta = FALSE;
+ }
+ }
+ pad->new_page = FALSE;
+ }
+
+ /* save key unit to track delta->key unit transitions */
+ pad->prev_delta = delta_unit;
+
+ /* swap the packet in */
+ ogg_stream_packetin (&pad->stream, &packet);
+
+ /* don't need the old buffer anymore */
+ gst_buffer_unref (pad->buffer);
+ /* store new readahead buffer */
+ pad->buffer = tmpbuf;
+
+ /* let ogg write out the pages now. The packet we got could end
+ * up in more than one page so we need to write them all */
while (ogg_stream_pageout (&pad->stream, &page) > 0) {
/* we have a complete page now, we can push the page
* and make sure to pull on a new pad the next time around */
- gst_ogg_mux_push_page (ogg_mux, &page);
+ gst_ogg_mux_push_page (ogg_mux, &page, pad->first_delta);
/* increment the page number counter */
pad->pageno++;
/* we're done pulling on this pad, make sure to choose a new
* pad for pulling in the next iteration */
ogg_mux->pulling = NULL;
+ pad->first_delta = TRUE;
pad->duration = 0;
+ pad->new_page = TRUE;
}
}
}