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 */ /* fallback on the packet */
pad->have_type = gst_ogg_stream_setup_map (&pad->map, &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) { if (!pad->have_type) {
GST_ERROR_OBJECT (data->pad, GST_ERROR_OBJECT (data->pad,
"mapper didn't recognise input stream " "(pad caps: %" "mapper didn't recognise input stream " "(pad caps: %"
@ -1097,6 +1102,7 @@ gst_ogg_mux_get_headers (GstOggPadData * pad)
GstCaps *caps; GstCaps *caps;
const GValue *streamheader; const GValue *streamheader;
GstPad *thepad; GstPad *thepad;
GstBuffer *header;
thepad = pad->collect.pad; 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")) { } else if (gst_structure_has_name (structure, "video/x-dirac")) {
res = g_list_append (res, pad->buffer); res = g_list_append (res, pad->buffer);
pad->buffer = NULL; pad->buffer = NULL;
} else if (pad->have_type
&& (header = gst_ogg_stream_get_headers (&pad->map))) {
res = g_list_append (res, header);
} else { } else {
GST_LOG_OBJECT (thepad, "caps don't have streamheader"); GST_LOG_OBJECT (thepad, "caps don't have streamheader");
} }

View file

@ -40,6 +40,8 @@ typedef struct _GstOggMap GstOggMap;
typedef gboolean (*GstOggMapSetupFunc) (GstOggStream * pad, typedef gboolean (*GstOggMapSetupFunc) (GstOggStream * pad,
ogg_packet * packet); ogg_packet * packet);
typedef gboolean (*GstOggMapSetupFromCapsFunc) (GstOggStream * pad,
const GstCaps * caps);
typedef GstClockTime (*GstOggMapToTimeFunc) (GstOggStream * pad, typedef GstClockTime (*GstOggMapToTimeFunc) (GstOggStream * pad,
gint64 granulepos); gint64 granulepos);
typedef gint64 (*GstOggMapToGranuleFunc) (GstOggStream * pad, typedef gint64 (*GstOggMapToGranuleFunc) (GstOggStream * pad,
@ -66,6 +68,8 @@ typedef void (*GstOggMapExtractTagsFunc) (GstOggStream * pad,
typedef gint64 (*GstOggMapGranuleposToKeyGranuleFunc) (GstOggStream * pad, typedef gint64 (*GstOggMapGranuleposToKeyGranuleFunc) (GstOggStream * pad,
gint64 granulepos); gint64 granulepos);
typedef GstBuffer *(*GstOggMapGetHeadersFunc) (GstOggStream * pad);
#define SKELETON_FISBONE_MIN_SIZE 52 #define SKELETON_FISBONE_MIN_SIZE 52
#define SKELETON_FISHEAD_3_3_MIN_SIZE 112 #define SKELETON_FISHEAD_3_3_MIN_SIZE 112
#define SKELETON_FISHEAD_4_0_MIN_SIZE 80 #define SKELETON_FISHEAD_4_0_MIN_SIZE 80
@ -77,6 +81,7 @@ struct _GstOggMap
int min_packet_size; int min_packet_size;
const gchar *media_type; const gchar *media_type;
GstOggMapSetupFunc setup_func; GstOggMapSetupFunc setup_func;
GstOggMapSetupFromCapsFunc setup_from_caps_func;
GstOggMapToGranuleFunc granulepos_to_granule_func; GstOggMapToGranuleFunc granulepos_to_granule_func;
GstOggMapToGranuleposFunc granule_to_granulepos_func; GstOggMapToGranuleposFunc granule_to_granulepos_func;
GstOggMapIsGranuleposKeyFrameFunc is_granulepos_key_frame_func; GstOggMapIsGranuleposKeyFrameFunc is_granulepos_key_frame_func;
@ -85,6 +90,7 @@ struct _GstOggMap
GstOggMapPacketDurationFunc packet_duration_func; GstOggMapPacketDurationFunc packet_duration_func;
GstOggMapGranuleposToKeyGranuleFunc granulepos_to_key_granule_func; GstOggMapGranuleposToKeyGranuleFunc granulepos_to_key_granule_func;
GstOggMapExtractTagsFunc extract_tags_func; GstOggMapExtractTagsFunc extract_tags_func;
GstOggMapGetHeadersFunc get_headers_func;
}; };
extern const GstOggMap mappers[]; extern const GstOggMap mappers[];
@ -265,6 +271,15 @@ gst_ogg_stream_get_media_type (GstOggStream * pad)
return gst_structure_get_name (structure); 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 */ /* some generic functions */
static gboolean static gboolean
@ -650,6 +665,50 @@ setup_vp8_mapper (GstOggStream * pad, ogg_packet * packet)
return TRUE; 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 static gboolean
is_keyframe_vp8 (GstOggStream * pad, gint64 granulepos) 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 */ /* vorbis */
static gboolean static gboolean
@ -2141,6 +2212,7 @@ const GstOggMap mappers[] = {
"\200theora", 7, 42, "\200theora", 7, 42,
"video/x-theora", "video/x-theora",
setup_theora_mapper, setup_theora_mapper,
NULL,
granulepos_to_granule_theora, granulepos_to_granule_theora,
granule_to_granulepos_default, granule_to_granulepos_default,
is_granulepos_keyframe_theora, is_granulepos_keyframe_theora,
@ -2148,12 +2220,14 @@ const GstOggMap mappers[] = {
is_header_theora, is_header_theora,
packet_duration_constant, packet_duration_constant,
NULL, NULL,
extract_tags_theora extract_tags_theora,
NULL
}, },
{ {
"\001vorbis", 7, 22, "\001vorbis", 7, 22,
"audio/x-vorbis", "audio/x-vorbis",
setup_vorbis_mapper, setup_vorbis_mapper,
NULL,
granulepos_to_granule_default, granulepos_to_granule_default,
granule_to_granulepos_default, granule_to_granulepos_default,
is_granulepos_keyframe_true, is_granulepos_keyframe_true,
@ -2161,12 +2235,14 @@ const GstOggMap mappers[] = {
is_header_vorbis, is_header_vorbis,
packet_duration_vorbis, packet_duration_vorbis,
NULL, NULL,
extract_tags_vorbis extract_tags_vorbis,
NULL
}, },
{ {
"Speex", 5, 80, "Speex", 5, 80,
"audio/x-speex", "audio/x-speex",
setup_speex_mapper, setup_speex_mapper,
NULL,
granulepos_to_granule_default, granulepos_to_granule_default,
granule_to_granulepos_default, granule_to_granulepos_default,
is_granulepos_keyframe_true, is_granulepos_keyframe_true,
@ -2174,7 +2250,8 @@ const GstOggMap mappers[] = {
is_header_count, is_header_count,
packet_duration_constant, packet_duration_constant,
NULL, NULL,
extract_tags_count extract_tags_count,
NULL
}, },
{ {
"PCM ", 8, 0, "PCM ", 8, 0,
@ -2184,9 +2261,11 @@ const GstOggMap mappers[] = {
NULL, NULL,
NULL, NULL,
NULL, NULL,
NULL,
is_header_count, is_header_count,
NULL, NULL,
NULL, NULL,
NULL,
NULL NULL
}, },
{ {
@ -2197,15 +2276,18 @@ const GstOggMap mappers[] = {
NULL, NULL,
NULL, NULL,
NULL, NULL,
NULL,
is_header_count, is_header_count,
NULL, NULL,
NULL, NULL,
NULL,
NULL NULL
}, },
{ {
"Annodex", 7, 0, "Annodex", 7, 0,
"application/x-annodex", "application/x-annodex",
setup_fishead_mapper, setup_fishead_mapper,
NULL,
granulepos_to_granule_default, granulepos_to_granule_default,
granule_to_granulepos_default, granule_to_granulepos_default,
NULL, NULL,
@ -2213,6 +2295,7 @@ const GstOggMap mappers[] = {
is_header_count, is_header_count,
NULL, NULL,
NULL, NULL,
NULL,
NULL NULL
}, },
{ {
@ -2223,15 +2306,18 @@ const GstOggMap mappers[] = {
NULL, NULL,
NULL, NULL,
NULL, NULL,
NULL,
is_header_true, is_header_true,
NULL, NULL,
NULL, NULL,
NULL,
NULL NULL
}, },
{ {
"fLaC", 4, 0, "fLaC", 4, 0,
"audio/x-flac", "audio/x-flac",
setup_fLaC_mapper, setup_fLaC_mapper,
NULL,
granulepos_to_granule_default, granulepos_to_granule_default,
granule_to_granulepos_default, granule_to_granulepos_default,
is_granulepos_keyframe_true, is_granulepos_keyframe_true,
@ -2239,12 +2325,14 @@ const GstOggMap mappers[] = {
is_header_fLaC, is_header_fLaC,
packet_duration_flac, packet_duration_flac,
NULL, NULL,
NULL,
NULL NULL
}, },
{ {
"\177FLAC", 5, 36, "\177FLAC", 5, 36,
"audio/x-flac", "audio/x-flac",
setup_flac_mapper, setup_flac_mapper,
NULL,
granulepos_to_granule_default, granulepos_to_granule_default,
granule_to_granulepos_default, granule_to_granulepos_default,
is_granulepos_keyframe_true, is_granulepos_keyframe_true,
@ -2252,7 +2340,8 @@ const GstOggMap mappers[] = {
is_header_flac, is_header_flac,
packet_duration_flac, packet_duration_flac,
NULL, NULL,
extract_tags_flac extract_tags_flac,
NULL
}, },
{ {
"AnxData", 7, 0, "AnxData", 7, 0,
@ -2264,12 +2353,15 @@ const GstOggMap mappers[] = {
NULL, NULL,
NULL, NULL,
NULL, NULL,
NULL,
NULL,
NULL NULL
}, },
{ {
"CELT ", 8, 0, "CELT ", 8, 0,
"audio/x-celt", "audio/x-celt",
setup_celt_mapper, setup_celt_mapper,
NULL,
granulepos_to_granule_default, granulepos_to_granule_default,
granule_to_granulepos_default, granule_to_granulepos_default,
NULL, NULL,
@ -2277,12 +2369,14 @@ const GstOggMap mappers[] = {
is_header_count, is_header_count,
packet_duration_constant, packet_duration_constant,
NULL, NULL,
extract_tags_count extract_tags_count,
NULL
}, },
{ {
"\200kate\0\0\0", 8, 0, "\200kate\0\0\0", 8, 0,
"text/x-kate", "text/x-kate",
setup_kate_mapper, setup_kate_mapper,
NULL,
granulepos_to_granule_default, granulepos_to_granule_default,
granule_to_granulepos_default, granule_to_granulepos_default,
NULL, NULL,
@ -2290,12 +2384,14 @@ const GstOggMap mappers[] = {
is_header_count, is_header_count,
packet_duration_kate, packet_duration_kate,
NULL, NULL,
extract_tags_kate extract_tags_kate,
NULL
}, },
{ {
"BBCD\0", 5, 13, "BBCD\0", 5, 13,
"video/x-dirac", "video/x-dirac",
setup_dirac_mapper, setup_dirac_mapper,
NULL,
granulepos_to_granule_dirac, granulepos_to_granule_dirac,
granule_to_granulepos_dirac, granule_to_granulepos_dirac,
is_keyframe_dirac, is_keyframe_dirac,
@ -2303,12 +2399,14 @@ const GstOggMap mappers[] = {
is_header_count, is_header_count,
packet_duration_constant, packet_duration_constant,
granulepos_to_key_granule_dirac, granulepos_to_key_granule_dirac,
NULL,
NULL NULL
}, },
{ {
"OVP80\1\1", 7, 4, "OVP80\1\1", 7, 4,
"video/x-vp8", "video/x-vp8",
setup_vp8_mapper, setup_vp8_mapper,
setup_vp8_mapper_from_caps,
granulepos_to_granule_vp8, granulepos_to_granule_vp8,
granule_to_granulepos_vp8, granule_to_granulepos_vp8,
is_keyframe_vp8, is_keyframe_vp8,
@ -2316,12 +2414,14 @@ const GstOggMap mappers[] = {
is_header_vp8, is_header_vp8,
packet_duration_vp8, packet_duration_vp8,
granulepos_to_key_granule_vp8, granulepos_to_key_granule_vp8,
extract_tags_vp8 extract_tags_vp8,
get_headers_vp8
}, },
{ {
"OpusHead", 8, 0, "OpusHead", 8, 0,
"audio/x-opus", "audio/x-opus",
setup_opus_mapper, setup_opus_mapper,
NULL,
granulepos_to_granule_opus, granulepos_to_granule_opus,
granule_to_granulepos_default, granule_to_granulepos_default,
NULL, NULL,
@ -2329,12 +2429,14 @@ const GstOggMap mappers[] = {
is_header_opus, is_header_opus,
packet_duration_opus, packet_duration_opus,
NULL, NULL,
extract_tags_opus extract_tags_opus,
NULL
}, },
{ {
"\001audio\0\0\0", 9, 53, "\001audio\0\0\0", 9, 53,
"application/x-ogm-audio", "application/x-ogm-audio",
setup_ogmaudio_mapper, setup_ogmaudio_mapper,
NULL,
granulepos_to_granule_default, granulepos_to_granule_default,
granule_to_granulepos_default, granule_to_granulepos_default,
is_granulepos_keyframe_true, is_granulepos_keyframe_true,
@ -2342,12 +2444,14 @@ const GstOggMap mappers[] = {
is_header_ogm, is_header_ogm,
packet_duration_ogm, packet_duration_ogm,
NULL, NULL,
NULL,
NULL NULL
}, },
{ {
"\001video\0\0\0", 9, 53, "\001video\0\0\0", 9, 53,
"application/x-ogm-video", "application/x-ogm-video",
setup_ogmvideo_mapper, setup_ogmvideo_mapper,
NULL,
granulepos_to_granule_default, granulepos_to_granule_default,
granule_to_granulepos_default, granule_to_granulepos_default,
NULL, NULL,
@ -2355,12 +2459,14 @@ const GstOggMap mappers[] = {
is_header_ogm, is_header_ogm,
packet_duration_constant, packet_duration_constant,
NULL, NULL,
NULL,
NULL NULL
}, },
{ {
"\001text\0\0\0", 9, 9, "\001text\0\0\0", 9, 9,
"application/x-ogm-text", "application/x-ogm-text",
setup_ogmtext_mapper, setup_ogmtext_mapper,
NULL,
granulepos_to_granule_default, granulepos_to_granule_default,
granule_to_granulepos_default, granule_to_granulepos_default,
is_granulepos_keyframe_true, is_granulepos_keyframe_true,
@ -2368,12 +2474,14 @@ const GstOggMap mappers[] = {
is_header_ogm, is_header_ogm,
packet_duration_ogm, packet_duration_ogm,
NULL, NULL,
extract_tags_ogm extract_tags_ogm,
NULL
}, },
{ {
"\200daala", 6, 42, "\200daala", 6, 42,
"video/x-daala", "video/x-daala",
setup_daala_mapper, setup_daala_mapper,
NULL,
granulepos_to_granule_daala, granulepos_to_granule_daala,
granule_to_granulepos_default, granule_to_granulepos_default,
is_granulepos_keyframe_daala, is_granulepos_keyframe_daala,
@ -2381,7 +2489,8 @@ const GstOggMap mappers[] = {
is_header_daala, is_header_daala,
packet_duration_constant, packet_duration_constant,
NULL, NULL,
extract_tags_daala extract_tags_daala,
NULL
}, },
}; };
@ -2419,6 +2528,42 @@ gst_ogg_stream_setup_map (GstOggStream * pad, ogg_packet * packet)
return FALSE; 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 gboolean
gst_ogg_stream_setup_map_from_caps_headers (GstOggStream * pad, gst_ogg_stream_setup_map_from_caps_headers (GstOggStream * pad,
const GstCaps * caps) 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 (GstOggStream * pad, ogg_packet *packet);
gboolean gst_ogg_stream_setup_map_from_caps_headers (GstOggStream * pad, gboolean gst_ogg_stream_setup_map_from_caps_headers (GstOggStream * pad,
const GstCaps * caps); 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, GstClockTime gst_ogg_stream_get_end_time_for_granulepos (GstOggStream *pad,
gint64 granulepos); gint64 granulepos);
GstClockTime gst_ogg_stream_get_start_time_for_granulepos (GstOggStream *pad, 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); gint64 gst_ogg_stream_get_packet_duration (GstOggStream * pad, ogg_packet *packet);
void gst_ogg_stream_extract_tags (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); 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, gboolean gst_ogg_map_parse_fisbone (GstOggStream * pad, const guint8 * data, guint size,
guint32 * serialno, GstOggSkeleton *type); guint32 * serialno, GstOggSkeleton *type);