oggmux: create vp8 header data if not provided in caps

vp8 stream header shouldn't be assumed to be provided in caps always
as this would repeat the same code in all demuxers/encoders. Instead,
make oggmux generate them if they are not supplied.

https://bugzilla.gnome.org/show_bug.cgi?id=722682
This commit is contained in:
Thiago Santos 2014-03-05 16:34:42 -03:00
parent 0b30fdbfbe
commit e00c306571
3 changed files with 167 additions and 10 deletions

View file

@ -1008,6 +1008,11 @@ gst_ogg_mux_queue_pads (GstOggMux * ogg_mux, gboolean * popped)
/* fallback on the packet */
pad->have_type = gst_ogg_stream_setup_map (&pad->map, &packet);
}
if (!pad->have_type) {
/* fallback 2 to try to get the mapping from the caps */
pad->have_type =
gst_ogg_stream_setup_map_from_caps (&pad->map, caps);
}
if (!pad->have_type) {
GST_ERROR_OBJECT (data->pad,
"mapper didn't recognise input stream " "(pad caps: %"
@ -1097,6 +1102,7 @@ gst_ogg_mux_get_headers (GstOggPadData * pad)
GstCaps *caps;
const GValue *streamheader;
GstPad *thepad;
GstBuffer *header;
thepad = pad->collect.pad;
@ -1138,6 +1144,9 @@ gst_ogg_mux_get_headers (GstOggPadData * pad)
} else if (gst_structure_has_name (structure, "video/x-dirac")) {
res = g_list_append (res, pad->buffer);
pad->buffer = NULL;
} else if (pad->have_type
&& (header = gst_ogg_stream_get_headers (&pad->map))) {
res = g_list_append (res, header);
} else {
GST_LOG_OBJECT (thepad, "caps don't have streamheader");
}

View file

@ -40,6 +40,8 @@ typedef struct _GstOggMap GstOggMap;
typedef gboolean (*GstOggMapSetupFunc) (GstOggStream * pad,
ogg_packet * packet);
typedef gboolean (*GstOggMapSetupFromCapsFunc) (GstOggStream * pad,
const GstCaps * caps);
typedef GstClockTime (*GstOggMapToTimeFunc) (GstOggStream * pad,
gint64 granulepos);
typedef gint64 (*GstOggMapToGranuleFunc) (GstOggStream * pad,
@ -66,6 +68,8 @@ typedef void (*GstOggMapExtractTagsFunc) (GstOggStream * pad,
typedef gint64 (*GstOggMapGranuleposToKeyGranuleFunc) (GstOggStream * pad,
gint64 granulepos);
typedef GstBuffer *(*GstOggMapGetHeadersFunc) (GstOggStream * pad);
#define SKELETON_FISBONE_MIN_SIZE 52
#define SKELETON_FISHEAD_3_3_MIN_SIZE 112
#define SKELETON_FISHEAD_4_0_MIN_SIZE 80
@ -77,6 +81,7 @@ struct _GstOggMap
int min_packet_size;
const gchar *media_type;
GstOggMapSetupFunc setup_func;
GstOggMapSetupFromCapsFunc setup_from_caps_func;
GstOggMapToGranuleFunc granulepos_to_granule_func;
GstOggMapToGranuleposFunc granule_to_granulepos_func;
GstOggMapIsGranuleposKeyFrameFunc is_granulepos_key_frame_func;
@ -85,6 +90,7 @@ struct _GstOggMap
GstOggMapPacketDurationFunc packet_duration_func;
GstOggMapGranuleposToKeyGranuleFunc granulepos_to_key_granule_func;
GstOggMapExtractTagsFunc extract_tags_func;
GstOggMapGetHeadersFunc get_headers_func;
};
extern const GstOggMap mappers[];
@ -265,6 +271,15 @@ gst_ogg_stream_get_media_type (GstOggStream * pad)
return gst_structure_get_name (structure);
}
GstBuffer *
gst_ogg_stream_get_headers (GstOggStream * pad)
{
if (!mappers[pad->map].get_headers_func)
return NULL;
return mappers[pad->map].get_headers_func (pad);
}
/* some generic functions */
static gboolean
@ -650,6 +665,50 @@ setup_vp8_mapper (GstOggStream * pad, ogg_packet * packet)
return TRUE;
}
static gboolean
vp8_fill_header (GstOggStream * pad, const GstCaps * caps, guint8 * data)
{
gint width, height, par_n, par_d, fps_n, fps_d;
GstStructure *structure = gst_caps_get_structure (caps, 0);
if (!(gst_structure_get_int (structure, "width", &width) &&
gst_structure_get_int (structure, "height", &height) &&
gst_structure_get_fraction (structure, "framerate", &fps_n,
&fps_d))) {
GST_DEBUG ("Failed to get width, height or framerate from caps %"
GST_PTR_FORMAT, caps);
return FALSE;
}
if (!gst_structure_get_fraction (structure, "pixel-aspect-ratio", &par_n,
&par_d)) {
par_n = par_d = 1;
}
memcpy (data, "OVP80\1\1", 8);
GST_WRITE_UINT16_BE (data + 8, width);
GST_WRITE_UINT16_BE (data + 10, height);
GST_WRITE_UINT24_BE (data + 12, par_n);
GST_WRITE_UINT24_BE (data + 15, par_d);
GST_WRITE_UINT32_BE (data + 18, fps_n);
GST_WRITE_UINT32_BE (data + 22, fps_d);
return TRUE;
}
static gboolean
setup_vp8_mapper_from_caps (GstOggStream * pad, const GstCaps * caps)
{
guint8 data[26];
ogg_packet packet;
if (!vp8_fill_header (pad, caps, data))
return FALSE;
packet.packet = data;
packet.bytes = 26;
return setup_vp8_mapper (pad, &packet);
}
static gboolean
is_keyframe_vp8 (GstOggStream * pad, gint64 granulepos)
{
@ -742,6 +801,18 @@ extract_tags_vp8 (GstOggStream * pad, ogg_packet * packet)
}
}
static GstBuffer *
get_headers_vp8 (GstOggStream * pad)
{
guint8 *data = g_malloc (26);
if (vp8_fill_header (pad, pad->caps, data)) {
return gst_buffer_new_wrapped (data, 26);
}
g_free (data);
return NULL;
}
/* vorbis */
static gboolean
@ -2141,6 +2212,7 @@ const GstOggMap mappers[] = {
"\200theora", 7, 42,
"video/x-theora",
setup_theora_mapper,
NULL,
granulepos_to_granule_theora,
granule_to_granulepos_default,
is_granulepos_keyframe_theora,
@ -2148,12 +2220,14 @@ const GstOggMap mappers[] = {
is_header_theora,
packet_duration_constant,
NULL,
extract_tags_theora
extract_tags_theora,
NULL
},
{
"\001vorbis", 7, 22,
"audio/x-vorbis",
setup_vorbis_mapper,
NULL,
granulepos_to_granule_default,
granule_to_granulepos_default,
is_granulepos_keyframe_true,
@ -2161,12 +2235,14 @@ const GstOggMap mappers[] = {
is_header_vorbis,
packet_duration_vorbis,
NULL,
extract_tags_vorbis
extract_tags_vorbis,
NULL
},
{
"Speex", 5, 80,
"audio/x-speex",
setup_speex_mapper,
NULL,
granulepos_to_granule_default,
granule_to_granulepos_default,
is_granulepos_keyframe_true,
@ -2174,7 +2250,8 @@ const GstOggMap mappers[] = {
is_header_count,
packet_duration_constant,
NULL,
extract_tags_count
extract_tags_count,
NULL
},
{
"PCM ", 8, 0,
@ -2184,9 +2261,11 @@ const GstOggMap mappers[] = {
NULL,
NULL,
NULL,
NULL,
is_header_count,
NULL,
NULL,
NULL,
NULL
},
{
@ -2197,15 +2276,18 @@ const GstOggMap mappers[] = {
NULL,
NULL,
NULL,
NULL,
is_header_count,
NULL,
NULL,
NULL,
NULL
},
{
"Annodex", 7, 0,
"application/x-annodex",
setup_fishead_mapper,
NULL,
granulepos_to_granule_default,
granule_to_granulepos_default,
NULL,
@ -2213,6 +2295,7 @@ const GstOggMap mappers[] = {
is_header_count,
NULL,
NULL,
NULL,
NULL
},
{
@ -2223,15 +2306,18 @@ const GstOggMap mappers[] = {
NULL,
NULL,
NULL,
NULL,
is_header_true,
NULL,
NULL,
NULL,
NULL
},
{
"fLaC", 4, 0,
"audio/x-flac",
setup_fLaC_mapper,
NULL,
granulepos_to_granule_default,
granule_to_granulepos_default,
is_granulepos_keyframe_true,
@ -2239,12 +2325,14 @@ const GstOggMap mappers[] = {
is_header_fLaC,
packet_duration_flac,
NULL,
NULL,
NULL
},
{
"\177FLAC", 5, 36,
"audio/x-flac",
setup_flac_mapper,
NULL,
granulepos_to_granule_default,
granule_to_granulepos_default,
is_granulepos_keyframe_true,
@ -2252,7 +2340,8 @@ const GstOggMap mappers[] = {
is_header_flac,
packet_duration_flac,
NULL,
extract_tags_flac
extract_tags_flac,
NULL
},
{
"AnxData", 7, 0,
@ -2264,12 +2353,15 @@ const GstOggMap mappers[] = {
NULL,
NULL,
NULL,
NULL,
NULL,
NULL
},
{
"CELT ", 8, 0,
"audio/x-celt",
setup_celt_mapper,
NULL,
granulepos_to_granule_default,
granule_to_granulepos_default,
NULL,
@ -2277,12 +2369,14 @@ const GstOggMap mappers[] = {
is_header_count,
packet_duration_constant,
NULL,
extract_tags_count
extract_tags_count,
NULL
},
{
"\200kate\0\0\0", 8, 0,
"text/x-kate",
setup_kate_mapper,
NULL,
granulepos_to_granule_default,
granule_to_granulepos_default,
NULL,
@ -2290,12 +2384,14 @@ const GstOggMap mappers[] = {
is_header_count,
packet_duration_kate,
NULL,
extract_tags_kate
extract_tags_kate,
NULL
},
{
"BBCD\0", 5, 13,
"video/x-dirac",
setup_dirac_mapper,
NULL,
granulepos_to_granule_dirac,
granule_to_granulepos_dirac,
is_keyframe_dirac,
@ -2303,12 +2399,14 @@ const GstOggMap mappers[] = {
is_header_count,
packet_duration_constant,
granulepos_to_key_granule_dirac,
NULL,
NULL
},
{
"OVP80\1\1", 7, 4,
"video/x-vp8",
setup_vp8_mapper,
setup_vp8_mapper_from_caps,
granulepos_to_granule_vp8,
granule_to_granulepos_vp8,
is_keyframe_vp8,
@ -2316,12 +2414,14 @@ const GstOggMap mappers[] = {
is_header_vp8,
packet_duration_vp8,
granulepos_to_key_granule_vp8,
extract_tags_vp8
extract_tags_vp8,
get_headers_vp8
},
{
"OpusHead", 8, 0,
"audio/x-opus",
setup_opus_mapper,
NULL,
granulepos_to_granule_opus,
granule_to_granulepos_default,
NULL,
@ -2329,12 +2429,14 @@ const GstOggMap mappers[] = {
is_header_opus,
packet_duration_opus,
NULL,
extract_tags_opus
extract_tags_opus,
NULL
},
{
"\001audio\0\0\0", 9, 53,
"application/x-ogm-audio",
setup_ogmaudio_mapper,
NULL,
granulepos_to_granule_default,
granule_to_granulepos_default,
is_granulepos_keyframe_true,
@ -2342,12 +2444,14 @@ const GstOggMap mappers[] = {
is_header_ogm,
packet_duration_ogm,
NULL,
NULL,
NULL
},
{
"\001video\0\0\0", 9, 53,
"application/x-ogm-video",
setup_ogmvideo_mapper,
NULL,
granulepos_to_granule_default,
granule_to_granulepos_default,
NULL,
@ -2355,12 +2459,14 @@ const GstOggMap mappers[] = {
is_header_ogm,
packet_duration_constant,
NULL,
NULL,
NULL
},
{
"\001text\0\0\0", 9, 9,
"application/x-ogm-text",
setup_ogmtext_mapper,
NULL,
granulepos_to_granule_default,
granule_to_granulepos_default,
is_granulepos_keyframe_true,
@ -2368,12 +2474,14 @@ const GstOggMap mappers[] = {
is_header_ogm,
packet_duration_ogm,
NULL,
extract_tags_ogm
extract_tags_ogm,
NULL
},
{
"\200daala", 6, 42,
"video/x-daala",
setup_daala_mapper,
NULL,
granulepos_to_granule_daala,
granule_to_granulepos_default,
is_granulepos_keyframe_daala,
@ -2381,7 +2489,8 @@ const GstOggMap mappers[] = {
is_header_daala,
packet_duration_constant,
NULL,
extract_tags_daala
extract_tags_daala,
NULL
},
};
@ -2419,6 +2528,42 @@ gst_ogg_stream_setup_map (GstOggStream * pad, ogg_packet * packet)
return FALSE;
}
gboolean
gst_ogg_stream_setup_map_from_caps (GstOggStream * pad, const GstCaps * caps)
{
int i;
gboolean ret;
GstStructure *structure;
g_return_val_if_fail (caps != NULL, FALSE);
structure = gst_caps_get_structure (caps, 0);
for (i = 0; i < G_N_ELEMENTS (mappers); i++) {
if (mappers[i].setup_from_caps_func &&
gst_structure_has_name (structure, mappers[i].media_type)) {
GST_DEBUG ("found mapper for '%s'", mappers[i].id);
if (mappers[i].setup_from_caps_func)
ret = mappers[i].setup_from_caps_func (pad, caps);
else
continue;
if (ret) {
GST_DEBUG ("got stream type %" GST_PTR_FORMAT, pad->caps);
pad->map = i;
return TRUE;
} else {
GST_WARNING ("mapper '%s' did not accept caps %" GST_PTR_FORMAT,
mappers[i].media_type, caps);
}
}
}
return FALSE;
}
gboolean
gst_ogg_stream_setup_map_from_caps_headers (GstOggStream * pad,
const GstCaps * caps)

View file

@ -116,6 +116,8 @@ struct _GstOggStream
gboolean gst_ogg_stream_setup_map (GstOggStream * pad, ogg_packet *packet);
gboolean gst_ogg_stream_setup_map_from_caps_headers (GstOggStream * pad,
const GstCaps * caps);
gboolean gst_ogg_stream_setup_map_from_caps (GstOggStream * pad,
const GstCaps * caps);
GstClockTime gst_ogg_stream_get_end_time_for_granulepos (GstOggStream *pad,
gint64 granulepos);
GstClockTime gst_ogg_stream_get_start_time_for_granulepos (GstOggStream *pad,
@ -133,6 +135,7 @@ gboolean gst_ogg_stream_packet_is_key_frame (GstOggStream *pad, ogg_packet *pack
gint64 gst_ogg_stream_get_packet_duration (GstOggStream * pad, ogg_packet *packet);
void gst_ogg_stream_extract_tags (GstOggStream * pad, ogg_packet * packet);
const char *gst_ogg_stream_get_media_type (GstOggStream * pad);
GstBuffer *gst_ogg_stream_get_headers (GstOggStream *pad);
gboolean gst_ogg_map_parse_fisbone (GstOggStream * pad, const guint8 * data, guint size,
guint32 * serialno, GstOggSkeleton *type);