mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-26 02:00:33 +00:00
oggdemux: reimplement OGM support
OGM demuxing no longer requires helper elements. It's done internally in oggdemux. Vorbis comments are still not handled because I don't have anything to test with.
This commit is contained in:
parent
4378851102
commit
8bbe0d126a
3 changed files with 157 additions and 53 deletions
|
@ -462,13 +462,46 @@ gst_ogg_demux_chain_peer (GstOggPad * pad, ogg_packet * packet)
|
||||||
gint64 current_time;
|
gint64 current_time;
|
||||||
GstOggChain *chain;
|
GstOggChain *chain;
|
||||||
gint64 duration;
|
gint64 duration;
|
||||||
|
int offset;
|
||||||
|
int trim;
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (ogg,
|
GST_DEBUG_OBJECT (ogg,
|
||||||
"%p streaming to peer serial %08x", pad, pad->map.serialno);
|
"%p streaming to peer serial %08x", pad, pad->map.serialno);
|
||||||
|
|
||||||
|
if (pad->map.is_ogm) {
|
||||||
|
const guint8 *data;
|
||||||
|
|
||||||
|
data = packet->packet;
|
||||||
|
|
||||||
|
if (data[0] & 1) {
|
||||||
|
/* We don't push header packets for OGM */
|
||||||
|
cret = gst_ogg_demux_combine_flows (ogg, pad, GST_FLOW_OK);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset = 1 + (((data[0] & 0xc0) >> 6) | ((data[0] & 0x02) << 1));
|
||||||
|
|
||||||
|
if (offset > packet->bytes) {
|
||||||
|
GST_ERROR ("buffer too small");
|
||||||
|
//goto buffer_too_small;
|
||||||
|
}
|
||||||
|
if (pad->map.is_ogm) {
|
||||||
|
trim = 0;
|
||||||
|
while (data[packet->bytes - 1 - trim] == 0) {
|
||||||
|
trim++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
trim = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
offset = 0;
|
||||||
|
trim = 0;
|
||||||
|
}
|
||||||
|
|
||||||
ret =
|
ret =
|
||||||
gst_pad_alloc_buffer_and_set_caps (GST_PAD_CAST (pad),
|
gst_pad_alloc_buffer_and_set_caps (GST_PAD_CAST (pad),
|
||||||
GST_BUFFER_OFFSET_NONE, packet->bytes, GST_PAD_CAPS (pad), &buf);
|
GST_BUFFER_OFFSET_NONE, packet->bytes - offset - trim,
|
||||||
|
GST_PAD_CAPS (pad), &buf);
|
||||||
|
|
||||||
/* combine flows */
|
/* combine flows */
|
||||||
cret = gst_ogg_demux_combine_flows (ogg, pad, ret);
|
cret = gst_ogg_demux_combine_flows (ogg, pad, ret);
|
||||||
|
@ -476,7 +509,7 @@ gst_ogg_demux_chain_peer (GstOggPad * pad, ogg_packet * packet)
|
||||||
goto no_buffer;
|
goto no_buffer;
|
||||||
|
|
||||||
/* copy packet in buffer */
|
/* copy packet in buffer */
|
||||||
memcpy (buf->data, packet->packet, packet->bytes);
|
memcpy (buf->data, packet->packet + offset, packet->bytes - offset - trim);
|
||||||
|
|
||||||
duration = gst_ogg_stream_get_packet_duration (&pad->map, packet);
|
duration = gst_ogg_stream_get_packet_duration (&pad->map, packet);
|
||||||
|
|
||||||
|
@ -494,10 +527,17 @@ gst_ogg_demux_chain_peer (GstOggPad * pad, ogg_packet * packet)
|
||||||
gst_ogg_stream_granulepos_to_key_granule (&pad->map,
|
gst_ogg_stream_granulepos_to_key_granule (&pad->map,
|
||||||
packet->granulepos);
|
packet->granulepos);
|
||||||
}
|
}
|
||||||
GST_BUFFER_TIMESTAMP (buf) = gst_ogg_stream_granule_to_time (&pad->map,
|
if (pad->map.is_ogm) {
|
||||||
pad->current_granule - duration);
|
GST_BUFFER_TIMESTAMP (buf) = gst_ogg_stream_granule_to_time (&pad->map,
|
||||||
GST_BUFFER_DURATION (buf) = gst_ogg_stream_granule_to_time (&pad->map,
|
pad->current_granule);
|
||||||
pad->current_granule) - GST_BUFFER_TIMESTAMP (buf);
|
GST_BUFFER_DURATION (buf) = gst_util_uint64_scale (duration,
|
||||||
|
GST_SECOND * pad->map.granulerate_d, pad->map.granulerate_n);
|
||||||
|
} else {
|
||||||
|
GST_BUFFER_TIMESTAMP (buf) = gst_ogg_stream_granule_to_time (&pad->map,
|
||||||
|
pad->current_granule - duration);
|
||||||
|
GST_BUFFER_DURATION (buf) = gst_ogg_stream_granule_to_time (&pad->map,
|
||||||
|
pad->current_granule) - GST_BUFFER_TIMESTAMP (buf);
|
||||||
|
}
|
||||||
GST_BUFFER_OFFSET_END (buf) =
|
GST_BUFFER_OFFSET_END (buf) =
|
||||||
gst_ogg_stream_granule_to_granulepos (&pad->map, pad->current_granule,
|
gst_ogg_stream_granule_to_granulepos (&pad->map, pad->current_granule,
|
||||||
pad->keyframe_granule);
|
pad->keyframe_granule);
|
||||||
|
|
|
@ -25,6 +25,8 @@
|
||||||
#include "gstoggstream.h"
|
#include "gstoggstream.h"
|
||||||
#include "dirac_parse.h"
|
#include "dirac_parse.h"
|
||||||
|
|
||||||
|
#include <gst/riff/riff-media.h>
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
GST_DEBUG_CATEGORY_EXTERN (gst_ogg_demux_debug);
|
GST_DEBUG_CATEGORY_EXTERN (gst_ogg_demux_debug);
|
||||||
|
@ -241,12 +243,14 @@ granule_to_granulepos_default (GstOggStream * pad, gint64 granule,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef unused
|
||||||
static gboolean
|
static gboolean
|
||||||
is_header_unknown (GstOggStream * pad, ogg_packet * packet)
|
is_header_unknown (GstOggStream * pad, ogg_packet * packet)
|
||||||
{
|
{
|
||||||
GST_WARNING ("don't know how to detect header");
|
GST_WARNING ("don't know how to detect header");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
is_header_true (GstOggStream * pad, ogg_packet * packet)
|
is_header_true (GstOggStream * pad, ogg_packet * packet)
|
||||||
|
@ -688,10 +692,6 @@ gst_ogg_map_add_fisbone (GstOggStream * pad,
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define STREAMHEADER_OGM_AUDIO_MIN_SIZE 53
|
|
||||||
#define STREAMHEADER_OGM_VIDEO_MIN_SIZE 53
|
|
||||||
#define STREAMHEADER_OGM_TEXT_MIN_SIZE 9
|
|
||||||
|
|
||||||
/* Do we need these for something?
|
/* Do we need these for something?
|
||||||
* ogm->hdr.size = GST_READ_UINT32_LE (&data[13]);
|
* ogm->hdr.size = GST_READ_UINT32_LE (&data[13]);
|
||||||
* ogm->hdr.time_unit = GST_READ_UINT64_LE (&data[17]);
|
* ogm->hdr.time_unit = GST_READ_UINT64_LE (&data[17]);
|
||||||
|
@ -701,28 +701,68 @@ gst_ogg_map_add_fisbone (GstOggStream * pad,
|
||||||
* ogm->hdr.bits_per_sample = GST_READ_UINT32_LE (&data[41]);
|
* ogm->hdr.bits_per_sample = GST_READ_UINT32_LE (&data[41]);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
is_header_ogm (GstOggStream * pad, ogg_packet * packet)
|
||||||
|
{
|
||||||
|
if (packet->bytes >= 1 && (packet->packet[0] & 0x01)) {
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gint64
|
||||||
|
packet_duration_ogm (GstOggStream * pad, ogg_packet * packet)
|
||||||
|
{
|
||||||
|
const guint8 *data;
|
||||||
|
int samples;
|
||||||
|
int offset;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
data = packet->packet;
|
||||||
|
offset = 1 + (((data[0] & 0xc0) >> 6) | ((data[0] & 0x02) << 1));
|
||||||
|
|
||||||
|
if (offset > packet->bytes) {
|
||||||
|
GST_ERROR ("buffer too small");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
samples = 0;
|
||||||
|
for (n = offset - 1; n > 0; n--) {
|
||||||
|
samples = (samples << 8) | data[n];
|
||||||
|
}
|
||||||
|
|
||||||
|
return samples;
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
setup_ogmaudio_mapper (GstOggStream * pad, ogg_packet * packet)
|
setup_ogmaudio_mapper (GstOggStream * pad, ogg_packet * packet)
|
||||||
{
|
{
|
||||||
guint8 *data = packet->packet;
|
guint8 *data = packet->packet;
|
||||||
guint size = packet->bytes;
|
guint32 fourcc;
|
||||||
|
|
||||||
if (size < STREAMHEADER_OGM_AUDIO_MIN_SIZE ||
|
|
||||||
memcmp (data, "\001audio\000\000\000", 9) != 0) {
|
|
||||||
GST_WARNING ("not an ogm audio identification header");
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
pad->granulerate_n = GST_READ_UINT64_LE (data + 25);
|
pad->granulerate_n = GST_READ_UINT64_LE (data + 25);
|
||||||
pad->granulerate_d = 1;
|
pad->granulerate_d = 1;
|
||||||
|
|
||||||
|
fourcc = GST_READ_UINT32_LE (data + 9);
|
||||||
|
GST_DEBUG ("fourcc: %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
|
||||||
|
|
||||||
|
pad->caps = gst_riff_create_audio_caps (fourcc, NULL, NULL, NULL, NULL, NULL);
|
||||||
|
|
||||||
GST_LOG ("sample rate: %d", pad->granulerate_n);
|
GST_LOG ("sample rate: %d", pad->granulerate_n);
|
||||||
if (pad->granulerate_n == 0)
|
if (pad->granulerate_n == 0)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
/* FIXME */
|
if (pad->caps) {
|
||||||
pad->caps = gst_caps_new_simple ("audio/x-unknown",
|
gst_caps_set_simple (pad->caps,
|
||||||
"rate", G_TYPE_INT, pad->granulerate_n, NULL);
|
"rate", G_TYPE_INT, pad->granulerate_n, NULL);
|
||||||
|
} else {
|
||||||
|
pad->caps = gst_caps_new_simple ("audio/x-ogm-unknown",
|
||||||
|
"fourcc", GST_TYPE_FOURCC, fourcc,
|
||||||
|
"rate", G_TYPE_INT, pad->granulerate_n, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
pad->n_header_packets = 1;
|
||||||
|
pad->is_ogm = TRUE;
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -731,28 +771,47 @@ static gboolean
|
||||||
setup_ogmvideo_mapper (GstOggStream * pad, ogg_packet * packet)
|
setup_ogmvideo_mapper (GstOggStream * pad, ogg_packet * packet)
|
||||||
{
|
{
|
||||||
guint8 *data = packet->packet;
|
guint8 *data = packet->packet;
|
||||||
guint size = packet->bytes;
|
guint32 fourcc;
|
||||||
|
int width, height;
|
||||||
|
gint64 time_unit;
|
||||||
|
|
||||||
if (size < STREAMHEADER_OGM_VIDEO_MIN_SIZE ||
|
GST_DEBUG ("time unit %d", GST_READ_UINT32_LE (data + 16));
|
||||||
memcmp (data, "\001video\000\000\000", 9) != 0) {
|
GST_DEBUG ("samples per unit %d", GST_READ_UINT32_LE (data + 24));
|
||||||
GST_WARNING ("not an ogm video identification header");
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
pad->granulerate_n = 10000000;
|
pad->granulerate_n = 10000000;
|
||||||
pad->granulerate_d = GST_READ_UINT64_LE (data + 17);
|
time_unit = GST_READ_UINT64_LE (data + 17);
|
||||||
|
if (time_unit > G_MAXINT || time_unit < G_MININT) {
|
||||||
|
GST_WARNING ("timeunit is out of range");
|
||||||
|
}
|
||||||
|
pad->granulerate_d = (gint) CLAMP (time_unit, G_MININT, G_MAXINT);
|
||||||
|
|
||||||
GST_LOG ("fps = %d/%d = %.3f",
|
GST_LOG ("fps = %d/%d = %.3f",
|
||||||
pad->granulerate_n, pad->granulerate_d,
|
pad->granulerate_n, pad->granulerate_d,
|
||||||
(double) pad->granulerate_n / pad->granulerate_d);
|
(double) pad->granulerate_n / pad->granulerate_d);
|
||||||
|
|
||||||
if (pad->granulerate_d <= 0)
|
fourcc = GST_READ_UINT32_LE (data + 9);
|
||||||
return FALSE;
|
width = GST_READ_UINT32_LE (data + 45);
|
||||||
|
height = GST_READ_UINT32_LE (data + 49);
|
||||||
|
GST_DEBUG ("fourcc: %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
|
||||||
|
|
||||||
/* FIXME */
|
pad->caps = gst_riff_create_video_caps (fourcc, NULL, NULL, NULL, NULL, NULL);
|
||||||
pad->caps = gst_caps_new_simple ("video/x-unknown",
|
|
||||||
"framerate", GST_TYPE_FRACTION, pad->granulerate_n,
|
if (pad->caps == NULL) {
|
||||||
pad->granulerate_d, NULL);
|
pad->caps = gst_caps_new_simple ("video/x-ogm-unknown",
|
||||||
|
"fourcc", GST_TYPE_FOURCC, fourcc,
|
||||||
|
"framerate", GST_TYPE_FRACTION, pad->granulerate_n,
|
||||||
|
pad->granulerate_d, NULL);
|
||||||
|
} else {
|
||||||
|
gst_caps_set_simple (pad->caps,
|
||||||
|
"framerate", GST_TYPE_FRACTION, pad->granulerate_n,
|
||||||
|
pad->granulerate_d,
|
||||||
|
"width", G_TYPE_INT, width, "height", G_TYPE_INT, height, NULL);
|
||||||
|
}
|
||||||
|
GST_DEBUG ("caps: %" GST_PTR_FORMAT, pad->caps);
|
||||||
|
|
||||||
|
pad->n_header_packets = 1;
|
||||||
|
pad->frame_size = 1;
|
||||||
|
pad->is_ogm = TRUE;
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -761,16 +820,14 @@ static gboolean
|
||||||
setup_ogmtext_mapper (GstOggStream * pad, ogg_packet * packet)
|
setup_ogmtext_mapper (GstOggStream * pad, ogg_packet * packet)
|
||||||
{
|
{
|
||||||
guint8 *data = packet->packet;
|
guint8 *data = packet->packet;
|
||||||
guint size = packet->bytes;
|
gint64 time_unit;
|
||||||
|
|
||||||
if (size < STREAMHEADER_OGM_AUDIO_MIN_SIZE ||
|
|
||||||
memcmp (data, "\001text\000\000\000\000", 9) != 0) {
|
|
||||||
GST_WARNING ("not an ogm text identification header");
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
pad->granulerate_n = 10000000;
|
pad->granulerate_n = 10000000;
|
||||||
pad->granulerate_d = GST_READ_UINT64_LE (data + 17);
|
time_unit = GST_READ_UINT64_LE (data + 17);
|
||||||
|
if (time_unit > G_MAXINT || time_unit < G_MININT) {
|
||||||
|
GST_WARNING ("timeunit is out of range");
|
||||||
|
}
|
||||||
|
pad->granulerate_d = (gint) CLAMP (time_unit, G_MININT, G_MAXINT);
|
||||||
|
|
||||||
GST_LOG ("fps = %d/%d = %.3f",
|
GST_LOG ("fps = %d/%d = %.3f",
|
||||||
pad->granulerate_n, pad->granulerate_d,
|
pad->granulerate_n, pad->granulerate_d,
|
||||||
|
@ -779,8 +836,11 @@ setup_ogmtext_mapper (GstOggStream * pad, ogg_packet * packet)
|
||||||
if (pad->granulerate_d <= 0)
|
if (pad->granulerate_d <= 0)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
/* FIXME */
|
pad->caps = gst_caps_new_simple ("text/plain", NULL);
|
||||||
pad->caps = gst_caps_new_simple ("text/x-unknown", NULL);
|
|
||||||
|
pad->n_header_packets = 1;
|
||||||
|
pad->is_ogm = TRUE;
|
||||||
|
pad->is_ogm_text = TRUE;
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -1123,34 +1183,34 @@ static const GstOggMap mappers[] = {
|
||||||
packet_duration_constant
|
packet_duration_constant
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"OGM audio", 100, 0,
|
"\001audio\0\0\0", 9, 53,
|
||||||
"application/x-ogm-audio",
|
"application/x-ogm-audio",
|
||||||
setup_ogmaudio_mapper,
|
setup_ogmaudio_mapper,
|
||||||
granulepos_to_granule_default,
|
granulepos_to_granule_default,
|
||||||
granule_to_granulepos_default,
|
granule_to_granulepos_default,
|
||||||
is_keyframe_true,
|
is_keyframe_true,
|
||||||
is_header_unknown,
|
is_header_ogm,
|
||||||
NULL
|
packet_duration_ogm
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"OGM video", 100, 0,
|
"\001video\0\0\0", 9, 53,
|
||||||
"application/x-ogm-video",
|
"application/x-ogm-video",
|
||||||
setup_ogmvideo_mapper,
|
setup_ogmvideo_mapper,
|
||||||
granulepos_to_granule_default,
|
granulepos_to_granule_default,
|
||||||
granule_to_granulepos_default,
|
granule_to_granulepos_default,
|
||||||
NULL,
|
NULL,
|
||||||
is_header_unknown,
|
is_header_ogm,
|
||||||
NULL
|
packet_duration_ogm
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"OGM text", 100, 0,
|
"\001text\0\0\0", 9, 9,
|
||||||
"application/x-ogm-text",
|
"application/x-ogm-text",
|
||||||
setup_ogmtext_mapper,
|
setup_ogmtext_mapper,
|
||||||
granulepos_to_granule_default,
|
granulepos_to_granule_default,
|
||||||
granule_to_granulepos_default,
|
granule_to_granulepos_default,
|
||||||
is_keyframe_true,
|
is_keyframe_true,
|
||||||
is_header_unknown,
|
is_header_ogm,
|
||||||
NULL
|
packet_duration_ogm
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
/* *INDENT-ON* */
|
/* *INDENT-ON* */
|
||||||
|
@ -1171,7 +1231,8 @@ gst_ogg_stream_setup_map (GstOggStream * pad, ogg_packet * packet)
|
||||||
pad->map = i;
|
pad->map = i;
|
||||||
return TRUE;
|
return TRUE;
|
||||||
} else {
|
} else {
|
||||||
GST_WARNING ("mapper '%s' did not accept setup header", mappers[i].id);
|
GST_WARNING ("mapper '%s' did not accept setup header",
|
||||||
|
mappers[i].media_type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,6 +65,9 @@ struct _GstOggStream
|
||||||
int last_size;
|
int last_size;
|
||||||
/* theora stuff */
|
/* theora stuff */
|
||||||
gboolean theora_has_zero_keyoffset;
|
gboolean theora_has_zero_keyoffset;
|
||||||
|
/* OGM stuff */
|
||||||
|
gboolean is_ogm;
|
||||||
|
gboolean is_ogm_text;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue