mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-25 17:50:36 +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;
|
||||
GstOggChain *chain;
|
||||
gint64 duration;
|
||||
int offset;
|
||||
int trim;
|
||||
|
||||
GST_DEBUG_OBJECT (ogg,
|
||||
"%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 =
|
||||
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 */
|
||||
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;
|
||||
|
||||
/* 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);
|
||||
|
||||
|
@ -494,10 +527,17 @@ gst_ogg_demux_chain_peer (GstOggPad * pad, ogg_packet * packet)
|
|||
gst_ogg_stream_granulepos_to_key_granule (&pad->map,
|
||||
packet->granulepos);
|
||||
}
|
||||
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);
|
||||
if (pad->map.is_ogm) {
|
||||
GST_BUFFER_TIMESTAMP (buf) = gst_ogg_stream_granule_to_time (&pad->map,
|
||||
pad->current_granule);
|
||||
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_ogg_stream_granule_to_granulepos (&pad->map, pad->current_granule,
|
||||
pad->keyframe_granule);
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
#include "gstoggstream.h"
|
||||
#include "dirac_parse.h"
|
||||
|
||||
#include <gst/riff/riff-media.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
GST_DEBUG_CATEGORY_EXTERN (gst_ogg_demux_debug);
|
||||
|
@ -241,12 +243,14 @@ granule_to_granulepos_default (GstOggStream * pad, gint64 granule,
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef unused
|
||||
static gboolean
|
||||
is_header_unknown (GstOggStream * pad, ogg_packet * packet)
|
||||
{
|
||||
GST_WARNING ("don't know how to detect header");
|
||||
return FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
static gboolean
|
||||
is_header_true (GstOggStream * pad, ogg_packet * packet)
|
||||
|
@ -688,10 +692,6 @@ gst_ogg_map_add_fisbone (GstOggStream * pad,
|
|||
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?
|
||||
* ogm->hdr.size = GST_READ_UINT32_LE (&data[13]);
|
||||
* 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]);
|
||||
*/
|
||||
|
||||
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
|
||||
setup_ogmaudio_mapper (GstOggStream * pad, ogg_packet * packet)
|
||||
{
|
||||
guint8 *data = packet->packet;
|
||||
guint size = packet->bytes;
|
||||
|
||||
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;
|
||||
}
|
||||
guint32 fourcc;
|
||||
|
||||
pad->granulerate_n = GST_READ_UINT64_LE (data + 25);
|
||||
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);
|
||||
if (pad->granulerate_n == 0)
|
||||
return FALSE;
|
||||
|
||||
/* FIXME */
|
||||
pad->caps = gst_caps_new_simple ("audio/x-unknown",
|
||||
"rate", G_TYPE_INT, pad->granulerate_n, NULL);
|
||||
if (pad->caps) {
|
||||
gst_caps_set_simple (pad->caps,
|
||||
"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;
|
||||
}
|
||||
|
@ -731,28 +771,47 @@ static gboolean
|
|||
setup_ogmvideo_mapper (GstOggStream * pad, ogg_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 ||
|
||||
memcmp (data, "\001video\000\000\000", 9) != 0) {
|
||||
GST_WARNING ("not an ogm video identification header");
|
||||
return FALSE;
|
||||
}
|
||||
GST_DEBUG ("time unit %d", GST_READ_UINT32_LE (data + 16));
|
||||
GST_DEBUG ("samples per unit %d", GST_READ_UINT32_LE (data + 24));
|
||||
|
||||
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",
|
||||
pad->granulerate_n, pad->granulerate_d,
|
||||
(double) pad->granulerate_n / pad->granulerate_d);
|
||||
|
||||
if (pad->granulerate_d <= 0)
|
||||
return FALSE;
|
||||
fourcc = GST_READ_UINT32_LE (data + 9);
|
||||
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_caps_new_simple ("video/x-unknown",
|
||||
"framerate", GST_TYPE_FRACTION, pad->granulerate_n,
|
||||
pad->granulerate_d, NULL);
|
||||
pad->caps = gst_riff_create_video_caps (fourcc, NULL, NULL, NULL, NULL, NULL);
|
||||
|
||||
if (pad->caps == 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;
|
||||
}
|
||||
|
@ -761,16 +820,14 @@ static gboolean
|
|||
setup_ogmtext_mapper (GstOggStream * pad, ogg_packet * packet)
|
||||
{
|
||||
guint8 *data = packet->packet;
|
||||
guint size = packet->bytes;
|
||||
|
||||
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;
|
||||
}
|
||||
gint64 time_unit;
|
||||
|
||||
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",
|
||||
pad->granulerate_n, pad->granulerate_d,
|
||||
|
@ -779,8 +836,11 @@ setup_ogmtext_mapper (GstOggStream * pad, ogg_packet * packet)
|
|||
if (pad->granulerate_d <= 0)
|
||||
return FALSE;
|
||||
|
||||
/* FIXME */
|
||||
pad->caps = gst_caps_new_simple ("text/x-unknown", NULL);
|
||||
pad->caps = gst_caps_new_simple ("text/plain", NULL);
|
||||
|
||||
pad->n_header_packets = 1;
|
||||
pad->is_ogm = TRUE;
|
||||
pad->is_ogm_text = TRUE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -1123,34 +1183,34 @@ static const GstOggMap mappers[] = {
|
|||
packet_duration_constant
|
||||
},
|
||||
{
|
||||
"OGM audio", 100, 0,
|
||||
"\001audio\0\0\0", 9, 53,
|
||||
"application/x-ogm-audio",
|
||||
setup_ogmaudio_mapper,
|
||||
granulepos_to_granule_default,
|
||||
granule_to_granulepos_default,
|
||||
is_keyframe_true,
|
||||
is_header_unknown,
|
||||
NULL
|
||||
is_header_ogm,
|
||||
packet_duration_ogm
|
||||
},
|
||||
{
|
||||
"OGM video", 100, 0,
|
||||
"\001video\0\0\0", 9, 53,
|
||||
"application/x-ogm-video",
|
||||
setup_ogmvideo_mapper,
|
||||
granulepos_to_granule_default,
|
||||
granule_to_granulepos_default,
|
||||
NULL,
|
||||
is_header_unknown,
|
||||
NULL
|
||||
is_header_ogm,
|
||||
packet_duration_ogm
|
||||
},
|
||||
{
|
||||
"OGM text", 100, 0,
|
||||
"\001text\0\0\0", 9, 9,
|
||||
"application/x-ogm-text",
|
||||
setup_ogmtext_mapper,
|
||||
granulepos_to_granule_default,
|
||||
granule_to_granulepos_default,
|
||||
is_keyframe_true,
|
||||
is_header_unknown,
|
||||
NULL
|
||||
is_header_ogm,
|
||||
packet_duration_ogm
|
||||
}
|
||||
};
|
||||
/* *INDENT-ON* */
|
||||
|
@ -1171,7 +1231,8 @@ gst_ogg_stream_setup_map (GstOggStream * pad, ogg_packet * packet)
|
|||
pad->map = i;
|
||||
return TRUE;
|
||||
} 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;
|
||||
/* theora stuff */
|
||||
gboolean theora_has_zero_keyoffset;
|
||||
/* OGM stuff */
|
||||
gboolean is_ogm;
|
||||
gboolean is_ogm_text;
|
||||
};
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue