mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-06-07 07:58:51 +00:00
Merge branch 'master' into 0.11
Conflicts: ext/ogg/gstoggmux.c ext/vorbis/gstvorbisenc.c
This commit is contained in:
commit
232a5a3d0a
5 changed files with 223 additions and 54 deletions
|
@ -491,8 +491,13 @@ gst_ogg_demux_chain_peer (GstOggPad * pad, ogg_packet * packet,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get timing info for the packet */
|
/* get timing info for the packet */
|
||||||
duration = gst_ogg_stream_get_packet_duration (&pad->map, packet);
|
if (gst_ogg_stream_packet_is_header (&pad->map, packet)) {
|
||||||
GST_DEBUG_OBJECT (ogg, "packet duration %" G_GUINT64_FORMAT, duration);
|
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) {
|
if (packet->b_o_s) {
|
||||||
out_timestamp = GST_CLOCK_TIME_NONE;
|
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++) {
|
for (i = 0; i < chain->streams->len; i++) {
|
||||||
GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i);
|
GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i);
|
||||||
|
|
||||||
if (pad->map.is_sparse)
|
if (pad->map.is_skeleton)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* can do this if the pad start time is not defined */
|
/* 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) {
|
if (pad->start_time == GST_CLOCK_TIME_NONE) {
|
||||||
start_time = G_MAXUINT64;
|
if (!pad->map.is_sparse) {
|
||||||
break;
|
start_time = G_MAXUINT64;
|
||||||
|
break;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
start_time = MIN (start_time, pad->start_time);
|
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,
|
if (gst_ogg_map_parse_fisbone (&pad->map, packet->packet, packet->bytes,
|
||||||
&serialno, &type)) {
|
&serialno, &type)) {
|
||||||
|
|
||||||
GST_WARNING_OBJECT (pad->ogg,
|
GST_DEBUG_OBJECT (pad->ogg,
|
||||||
"got skeleton packet for stream 0x%08x", serialno);
|
"got skeleton packet for stream 0x%08x", serialno);
|
||||||
|
|
||||||
skel_pad = gst_ogg_chain_get_stream (pad->chain, 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;
|
GstFlowReturn ret;
|
||||||
GstOggChain *chain = NULL;
|
GstOggChain *chain = NULL;
|
||||||
gint64 offset = ogg->offset;
|
gint64 offset = ogg->offset;
|
||||||
ogg_page op;
|
ogg_page og;
|
||||||
gboolean done;
|
gboolean done;
|
||||||
gint i;
|
gint i;
|
||||||
|
|
||||||
|
@ -2638,17 +2648,23 @@ gst_ogg_demux_read_chain (GstOggDemux * ogg, GstOggChain ** res_chain)
|
||||||
GstOggPad *pad;
|
GstOggPad *pad;
|
||||||
guint32 serial;
|
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) {
|
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;
|
break;
|
||||||
}
|
}
|
||||||
if (!ogg_page_bos (&op)) {
|
if (!ogg_page_bos (&og)) {
|
||||||
GST_WARNING_OBJECT (ogg, "page is not BOS page");
|
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
|
/* if we did not find a chain yet, assume this is a bogus stream and
|
||||||
* ignore it */
|
* ignore it */
|
||||||
if (!chain)
|
if (!chain) {
|
||||||
|
GST_WARNING_OBJECT (ogg, "No chain found, no Ogg data in stream ?");
|
||||||
ret = GST_FLOW_UNEXPECTED;
|
ret = GST_FLOW_UNEXPECTED;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2657,7 +2673,7 @@ gst_ogg_demux_read_chain (GstOggDemux * ogg, GstOggChain ** res_chain)
|
||||||
chain->offset = offset;
|
chain->offset = offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
serial = ogg_page_serialno (&op);
|
serial = ogg_page_serialno (&og);
|
||||||
if (gst_ogg_chain_get_stream (chain, serial) != NULL) {
|
if (gst_ogg_chain_get_stream (chain, serial) != NULL) {
|
||||||
GST_WARNING_OBJECT (ogg,
|
GST_WARNING_OBJECT (ogg,
|
||||||
"found serial %08x BOS page twice, ignoring", serial);
|
"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);
|
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) {
|
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;
|
gboolean known_serial = FALSE;
|
||||||
GstFlowReturn ret;
|
GstFlowReturn ret;
|
||||||
|
|
||||||
serial = ogg_page_serialno (&op);
|
serial = ogg_page_serialno (&og);
|
||||||
done = TRUE;
|
done = TRUE;
|
||||||
for (i = 0; i < chain->streams->len; i++) {
|
for (i = 0; i < chain->streams->len; i++) {
|
||||||
GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, 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
|
/* submit the page now, this will fill in the start_time when the
|
||||||
* internal decoder finds it */
|
* 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
|
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.
|
/* 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
|
* We have no chance of finding a start_time for every pad so
|
||||||
* stop searching for the other start_time(s).
|
* stop searching for the other start_time(s).
|
||||||
|
@ -2747,7 +2763,7 @@ gst_ogg_demux_read_chain (GstOggDemux * ogg, GstOggChain ** res_chain)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!done) {
|
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)
|
if (ret != GST_FLOW_OK)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -2805,7 +2821,7 @@ gst_ogg_demux_read_end_chain (GstOggDemux * ogg, GstOggChain * chain)
|
||||||
for (i = 0; i < chain->streams->len; i++) {
|
for (i = 0; i < chain->streams->len; i++) {
|
||||||
GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i);
|
GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i);
|
||||||
|
|
||||||
if (pad->map.is_sparse)
|
if (pad->map.is_skeleton)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (pad->map.serialno == ogg_page_serialno (&og)) {
|
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++) {
|
for (j = 0; j < chain->streams->len; j++) {
|
||||||
GstOggPad *stream = g_array_index (chain->streams, GstOggPad *, 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_INFO_OBJECT (ogg, " start time: %" GST_TIME_FORMAT,
|
||||||
GST_TIME_ARGS (stream->start_time));
|
GST_TIME_ARGS (stream->start_time));
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
|
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
#include <gst/base/gstcollectpads.h>
|
#include <gst/base/gstcollectpads.h>
|
||||||
|
#include <gst/base/gstbytewriter.h>
|
||||||
#include <gst/tag/tag.h>
|
#include <gst/tag/tag.h>
|
||||||
|
|
||||||
#include "gstoggmux.h"
|
#include "gstoggmux.h"
|
||||||
|
@ -83,12 +84,15 @@ enum
|
||||||
#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)
|
#define DEFAULT_MAX_TOLERANCE G_GINT64_CONSTANT(40000000)
|
||||||
|
#define DEFAULT_SKELETON FALSE
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
ARG_0,
|
ARG_0,
|
||||||
ARG_MAX_DELAY,
|
ARG_MAX_DELAY,
|
||||||
ARG_MAX_PAGE_DELAY,
|
ARG_MAX_PAGE_DELAY,
|
||||||
ARG_MAX_TOLERANCE
|
ARG_MAX_TOLERANCE,
|
||||||
|
ARG_SKELETON
|
||||||
};
|
};
|
||||||
|
|
||||||
static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
|
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",
|
"Maximum timestamp difference for maintaining perfect granules",
|
||||||
0, G_MAXUINT64, DEFAULT_MAX_TOLERANCE,
|
0, G_MAXUINT64, DEFAULT_MAX_TOLERANCE,
|
||||||
(GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
(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;
|
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
|
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;
|
packet->granulepos = 0;
|
||||||
/* mark BOS and packet number */
|
/* mark BOS and packet number */
|
||||||
packet->b_o_s = (pad->packetno == 0);
|
packet->b_o_s = bos;
|
||||||
packet->packetno = pad->packetno++;
|
|
||||||
/* mark EOS */
|
/* 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;
|
GList *hbufs, *hwalk;
|
||||||
GstCaps *caps;
|
GstCaps *caps;
|
||||||
GstFlowReturn ret;
|
GstFlowReturn ret;
|
||||||
|
ogg_page page;
|
||||||
|
ogg_stream_state skeleton_stream;
|
||||||
|
|
||||||
hbufs = NULL;
|
hbufs = NULL;
|
||||||
ret = GST_FLOW_OK;
|
ret = GST_FLOW_OK;
|
||||||
|
@ -1132,7 +1232,6 @@ gst_ogg_mux_send_headers (GstOggMux * mux)
|
||||||
GstOggPadData *pad;
|
GstOggPadData *pad;
|
||||||
GstBuffer *buf;
|
GstBuffer *buf;
|
||||||
ogg_packet packet;
|
ogg_packet packet;
|
||||||
ogg_page page;
|
|
||||||
GstPad *thepad;
|
GstPad *thepad;
|
||||||
GstCaps *caps;
|
GstCaps *caps;
|
||||||
GstStructure *structure;
|
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.packet = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
|
||||||
packet.bytes = size;
|
packet.bytes = size;
|
||||||
|
|
||||||
create_header_packet (&packet, pad);
|
gst_ogg_mux_create_header_packet (&packet, pad);
|
||||||
|
|
||||||
/* swap the packet in */
|
/* swap the packet in */
|
||||||
ogg_stream_packetin (&pad->map.stream, &packet);
|
ogg_stream_packetin (&pad->map.stream, &packet);
|
||||||
|
@ -1203,6 +1302,16 @@ gst_ogg_mux_send_headers (GstOggMux * mux)
|
||||||
gst_caps_unref (caps);
|
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");
|
GST_LOG_OBJECT (mux, "creating next headers");
|
||||||
walk = mux->collect->data;
|
walk = mux->collect->data;
|
||||||
while (walk) {
|
while (walk) {
|
||||||
|
@ -1214,6 +1323,9 @@ gst_ogg_mux_send_headers (GstOggMux * mux)
|
||||||
|
|
||||||
walk = walk->next;
|
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_LOG_OBJECT (mux, "looping over headers for pad %s:%s",
|
||||||
GST_DEBUG_PAD_NAME (thepad));
|
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.packet = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
|
||||||
packet.bytes = size;
|
packet.bytes = size;
|
||||||
|
|
||||||
create_header_packet (&packet, pad);
|
gst_ogg_mux_create_header_packet (&packet, pad);
|
||||||
|
|
||||||
/* swap the packet in */
|
/* swap the packet in */
|
||||||
ogg_stream_packetin (&pad->map.stream, &packet);
|
ogg_stream_packetin (&pad->map.stream, &packet);
|
||||||
|
@ -1262,6 +1374,21 @@ gst_ogg_mux_send_headers (GstOggMux * mux)
|
||||||
g_list_free (pad->map.headers);
|
g_list_free (pad->map.headers);
|
||||||
pad->map.headers = NULL;
|
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 */
|
/* hbufs holds all buffers for the headers now */
|
||||||
|
|
||||||
/* create caps with the buffers */
|
/* create caps with the buffers */
|
||||||
|
@ -1706,6 +1833,9 @@ gst_ogg_mux_get_property (GObject * object,
|
||||||
case ARG_MAX_TOLERANCE:
|
case ARG_MAX_TOLERANCE:
|
||||||
g_value_set_uint64 (value, ogg_mux->max_tolerance);
|
g_value_set_uint64 (value, ogg_mux->max_tolerance);
|
||||||
break;
|
break;
|
||||||
|
case ARG_SKELETON:
|
||||||
|
g_value_set_boolean (value, ogg_mux->use_skeleton);
|
||||||
|
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;
|
||||||
|
@ -1730,6 +1860,9 @@ gst_ogg_mux_set_property (GObject * object,
|
||||||
case ARG_MAX_TOLERANCE:
|
case ARG_MAX_TOLERANCE:
|
||||||
ogg_mux->max_tolerance = g_value_get_uint64 (value);
|
ogg_mux->max_tolerance = g_value_get_uint64 (value);
|
||||||
break;
|
break;
|
||||||
|
case ARG_SKELETON:
|
||||||
|
ogg_mux->use_skeleton = g_value_get_boolean (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;
|
||||||
|
|
|
@ -127,6 +127,9 @@ struct _GstOggMux
|
||||||
pages as delta frames up to the page that has the
|
pages as delta frames up to the page that has the
|
||||||
keyframe */
|
keyframe */
|
||||||
|
|
||||||
|
|
||||||
|
/* whether to create a skeleton track */
|
||||||
|
gboolean use_skeleton;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstOggMuxClass
|
struct _GstOggMuxClass
|
||||||
|
|
|
@ -139,7 +139,8 @@ gst_ogg_stream_granulepos_to_granule (GstOggStream * pad, gint64 granulepos)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mappers[pad->map].granulepos_to_granule_func == NULL) {
|
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;
|
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) {
|
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;
|
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) {
|
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;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,7 +198,8 @@ gboolean
|
||||||
gst_ogg_stream_packet_is_header (GstOggStream * pad, ogg_packet * packet)
|
gst_ogg_stream_packet_is_header (GstOggStream * pad, ogg_packet * packet)
|
||||||
{
|
{
|
||||||
if (mappers[pad->map].is_header_func == NULL) {
|
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;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,7 +210,8 @@ gint64
|
||||||
gst_ogg_stream_get_packet_duration (GstOggStream * pad, ogg_packet * packet)
|
gst_ogg_stream_get_packet_duration (GstOggStream * pad, ogg_packet * packet)
|
||||||
{
|
{
|
||||||
if (mappers[pad->map].packet_duration_func == NULL) {
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1087,7 +1092,7 @@ setup_fishead_mapper (GstOggStream * pad, ogg_packet * packet)
|
||||||
pad->is_skeleton = TRUE;
|
pad->is_skeleton = TRUE;
|
||||||
pad->is_sparse = 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;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -1099,12 +1104,15 @@ gst_ogg_map_parse_fisbone (GstOggStream * pad, const guint8 * data, guint size,
|
||||||
GstOggSkeleton stype;
|
GstOggSkeleton stype;
|
||||||
guint serial_offset;
|
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);
|
GST_WARNING ("small fisbone packet of size %d, ignoring", size);
|
||||||
return FALSE;
|
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");
|
GST_INFO ("got fisbone packet");
|
||||||
stype = GST_OGG_SKELETON_FISBONE;
|
stype = GST_OGG_SKELETON_FISBONE;
|
||||||
serial_offset = 12;
|
serial_offset = 12;
|
||||||
|
|
|
@ -1000,12 +1000,12 @@ gst_vorbis_enc_buffer_check_discontinuous (GstVorbisEnc * vorbisenc,
|
||||||
vorbisenc->expected_ts != GST_CLOCK_TIME_NONE &&
|
vorbisenc->expected_ts != GST_CLOCK_TIME_NONE &&
|
||||||
timestamp + duration != vorbisenc->expected_ts) {
|
timestamp + duration != vorbisenc->expected_ts) {
|
||||||
/* It turns out that a lot of elements don't generate perfect streams due
|
/* 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.
|
* 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
|
GST_DEBUG_OBJECT (vorbisenc, "Expected TS %" GST_TIME_FORMAT
|
||||||
", buffer TS %" GST_TIME_FORMAT,
|
", buffer TS %" GST_TIME_FORMAT,
|
||||||
GST_TIME_ARGS (vorbisenc->expected_ts), GST_TIME_ARGS (timestamp));
|
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 &&
|
if (vorbisenc->expected_ts != GST_CLOCK_TIME_NONE &&
|
||||||
timestamp < vorbisenc->expected_ts) {
|
timestamp < vorbisenc->expected_ts) {
|
||||||
|
int threesample = GST_SECOND / vorbisenc->frequency * 3;
|
||||||
guint64 diff = vorbisenc->expected_ts - timestamp;
|
guint64 diff = vorbisenc->expected_ts - timestamp;
|
||||||
guint64 diff_bytes;
|
guint64 diff_bytes;
|
||||||
gsize size;
|
gsize size;
|
||||||
|
|
||||||
GST_WARNING_OBJECT (vorbisenc, "Buffer is older than previous "
|
/* Don't freak out on tiny jitters; use the same < 3 sample
|
||||||
"timestamp + duration (%" GST_TIME_FORMAT "< %" GST_TIME_FORMAT
|
tolerance as in the discontinuous detection */
|
||||||
"), cannot handle. Clipping buffer.",
|
if ((GstClockTimeDiff) (vorbisenc->expected_ts - timestamp) > threesample) {
|
||||||
GST_TIME_ARGS (timestamp), GST_TIME_ARGS (vorbisenc->expected_ts));
|
|
||||||
|
|
||||||
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 =
|
size = gst_buffer_get_size (buffer);
|
||||||
GST_CLOCK_TIME_TO_FRAMES (diff,
|
|
||||||
vorbisenc->frequency) * vorbisenc->channels * sizeof (gfloat);
|
diff_bytes =
|
||||||
if (diff_bytes >= size) {
|
GST_CLOCK_TIME_TO_FRAMES (diff,
|
||||||
gst_buffer_unref (buffer);
|
vorbisenc->frequency) * vorbisenc->channels * sizeof (gfloat);
|
||||||
return GST_FLOW_OK;
|
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;
|
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,
|
if (gst_vorbis_enc_buffer_check_discontinuous (vorbisenc, timestamp,
|
||||||
|
|
Loading…
Reference in a new issue