format: make media types and properties dynamic

Use URI properties to dynamically register the media types/subtypes and
property names. Add some helpers to set up the mappings.
This commit is contained in:
Wim Taymans 2017-03-21 11:28:23 +01:00
parent ee470fc6c6
commit 3f5a3e215b
25 changed files with 769 additions and 685 deletions

View file

@ -22,78 +22,42 @@
#include <stdio.h>
#include <string.h>
#include <lib/mapper.h>
#include <spa/audio/raw.h>
#include <spa/audio/format.h>
typedef struct {
uint32_t key;
uint32_t type;
off_t offset;
} ParseInfo;
static const ParseInfo raw_parse_info[] = {
{ SPA_PROP_ID_AUDIO_INFO, SPA_POD_TYPE_BYTES, offsetof (SpaAudioInfo, info.raw) },
{ SPA_PROP_ID_AUDIO_FORMAT, SPA_POD_TYPE_INT, offsetof (SpaAudioInfo, info.raw.format) },
{ SPA_PROP_ID_AUDIO_FLAGS, SPA_POD_TYPE_INT, offsetof (SpaAudioInfo, info.raw.flags) },
{ SPA_PROP_ID_AUDIO_LAYOUT, SPA_POD_TYPE_INT, offsetof (SpaAudioInfo, info.raw.layout) },
{ SPA_PROP_ID_AUDIO_RATE, SPA_POD_TYPE_INT, offsetof (SpaAudioInfo, info.raw.rate) },
{ SPA_PROP_ID_AUDIO_CHANNELS, SPA_POD_TYPE_INT, offsetof (SpaAudioInfo, info.raw.channels) },
{ SPA_PROP_ID_AUDIO_CHANNEL_MASK, SPA_POD_TYPE_INT, offsetof (SpaAudioInfo, info.raw.channel_mask) },
{ 0, }
};
static const ParseInfo *
parse_info_find (const ParseInfo *info, uint32_t key, uint32_t type)
{
while (info->key) {
if (info->key == key && info->type == type)
return info;
info++;
}
return NULL;
}
SpaResult
spa_format_audio_parse (const SpaFormat *format,
SpaAudioInfo *info)
{
SpaPODProp *prop;
const ParseInfo *pinfo, *find;
static SpaMediaTypes media_types = { 0, };
static SpaMediaSubtypes media_subtypes = { 0, };
static SpaMediaSubtypesAudio media_subtypes_audio = { 0, };
static SpaPropAudio prop_audio = { 0, };
if (format->body.media_type.value != SPA_MEDIA_TYPE_AUDIO)
spa_media_types_fill (&media_types, spa_id_map_get_default());
spa_media_subtypes_map (spa_id_map_get_default(), &media_subtypes);
spa_media_subtypes_audio_map (spa_id_map_get_default (), &media_subtypes_audio);
spa_prop_audio_map (spa_id_map_get_default (), &prop_audio);
if (format->body.media_type.value != media_types.audio)
return SPA_RESULT_INVALID_MEDIA_TYPE;
info->media_type = format->body.media_type.value;
info->media_subtype = format->body.media_subtype.value;
switch (info->media_subtype) {
case SPA_MEDIA_SUBTYPE_RAW:
pinfo = raw_parse_info;
break;
case SPA_MEDIA_SUBTYPE_MP3:
case SPA_MEDIA_SUBTYPE_AAC:
case SPA_MEDIA_SUBTYPE_VORBIS:
case SPA_MEDIA_SUBTYPE_WMA:
case SPA_MEDIA_SUBTYPE_RA:
case SPA_MEDIA_SUBTYPE_SBC:
case SPA_MEDIA_SUBTYPE_ADPCM:
case SPA_MEDIA_SUBTYPE_G723:
case SPA_MEDIA_SUBTYPE_G726:
case SPA_MEDIA_SUBTYPE_G729:
case SPA_MEDIA_SUBTYPE_AMR:
case SPA_MEDIA_SUBTYPE_GSM:
return SPA_RESULT_NOT_IMPLEMENTED;
default:
return SPA_RESULT_INVALID_ARGUMENTS;
if (info->media_subtype == media_subtypes.raw) {
spa_format_query (format,
prop_audio.format, SPA_POD_TYPE_INT, &info->info.raw.format,
prop_audio.flags, SPA_POD_TYPE_INT, &info->info.raw.flags,
prop_audio.layout, SPA_POD_TYPE_INT, &info->info.raw.layout,
prop_audio.rate, SPA_POD_TYPE_INT, &info->info.raw.rate,
prop_audio.channels, SPA_POD_TYPE_INT, &info->info.raw.channels,
prop_audio.channel_mask, SPA_POD_TYPE_INT, &info->info.raw.channel_mask,
0);
}
else
return SPA_RESULT_NOT_IMPLEMENTED;
SPA_FORMAT_FOREACH (format, prop) {
if ((find = parse_info_find (pinfo, prop->body.key, prop->body.value.type))) {
memcpy (SPA_MEMBER (info, find->offset, void),
SPA_POD_BODY (&prop->body.value),
SPA_POD_BODY_SIZE (&prop->body.value));
}
}
return SPA_RESULT_OK;
}

View file

@ -19,6 +19,7 @@
#include <stdio.h>
#include <lib/mapper.h>
#include "debug.h"
static const struct meta_type_name {
@ -180,92 +181,12 @@ spa_debug_props (const SpaProps *props, bool print_ranges)
return SPA_RESULT_OK;
}
static const char* media_audio_prop_names[] = {
"info",
"format",
"flags",
"layout",
"rate",
"channels",
"channel-mask",
};
static const char* media_video_prop_names[] = {
"info",
"format",
"size",
"framerate",
"max-framerate",
"views",
"interlace-mode",
"pixel-aspect-ratio",
"multiview-mode",
"multiview-flags",
"chroma-site",
"color-range",
"color-matrix",
"transfer-function",
"color-primaries",
"profile",
"stream-format",
"alignment",
};
static const struct media_type_name {
const char *name;
unsigned int first;
unsigned int last;
unsigned int idx;
const char **prop_names;
} media_type_names[] = {
{ "invalid", 0, 0, 0 },
{ "audio", SPA_MEDIA_SUBTYPE_AUDIO_FIRST, SPA_MEDIA_SUBTYPE_AUDIO_LAST, 16, media_audio_prop_names },
{ "video", SPA_MEDIA_SUBTYPE_VIDEO_FIRST, SPA_MEDIA_SUBTYPE_VIDEO_LAST, 2, media_video_prop_names },
{ "image", 0, 0 },
};
static const struct media_subtype_name {
const char *name;
} media_subtype_names[] = {
{ "invalid" },
{ "raw" },
{ "h264" },
{ "mjpg" },
{ "dv" },
{ "mpegts" },
{ "h263" },
{ "mpeg1" },
{ "mpeg2" },
{ "mpeg4" },
{ "xvid" },
{ "vc1" },
{ "vp8" },
{ "vp9" },
{ "jpeg" },
{ "bayer" },
{ "mp3" },
{ "aac" },
{ "vorbis" },
{ "wma" },
{ "ra" },
{ "sbc" },
{ "adpcm" },
{ "g723" },
{ "g726" },
{ "g729" },
{ "amr" },
{ "gsm" },
};
struct pod_type_name {
const char *name;
const char *CCName;
} pod_type_names[] = {
{ "invalid", "*Invalid*" },
{ "ignored", "ignored" },
{ "bool", "Bool" },
{ "uri", "URI" },
{ "int", "Int" },
@ -291,7 +212,8 @@ print_pod_value (uint32_t size, uint32_t type, void *body, int prefix)
printf ("%-*sBool %d\n", prefix, "", *(int32_t *) body);
break;
case SPA_POD_TYPE_URI:
printf ("%-*sURI %d\n", prefix, "", *(int32_t *) body);
printf ("%-*sURI %d %s\n", prefix, "", *(int32_t *) body,
spa_id_map_get_uri (spa_id_map_get_default(), *(int32_t*)body));
break;
case SPA_POD_TYPE_INT:
printf ("%-*sInt %d\n", prefix, "", *(int32_t *) body);
@ -357,7 +279,8 @@ print_pod_value (uint32_t size, uint32_t type, void *body, int prefix)
void *alt;
int i;
printf ("%-*sProp: key %d, flags %d\n", prefix, "", b->key, b->flags);
printf ("%-*sProp: key %s, flags %d\n", prefix, "",
spa_id_map_get_uri (spa_id_map_get_default(), b->key), b->flags);
if (b->flags & SPA_POD_PROP_FLAG_UNSET)
printf ("%-*sUnset (Default):\n", prefix + 2, "");
else
@ -441,10 +364,9 @@ print_format_value (uint32_t size, uint32_t type, void *body)
SpaResult
spa_debug_format (const SpaFormat *format)
{
int i, first, last, idx;
int i;
const char *media_type;
const char *media_subtype;
const char **prop_names;
SpaPODProp *prop;
uint32_t mtype, mstype;
@ -454,35 +376,22 @@ spa_debug_format (const SpaFormat *format)
mtype = format->body.media_type.value;
mstype = format->body.media_subtype.value;
if (mtype > 0 && mtype < SPA_N_ELEMENTS (media_type_names)) {
media_type = media_type_names[mtype].name;
first = media_type_names[mtype].first;
last = media_type_names[mtype].last;
idx = media_type_names[mtype].idx;
prop_names = media_type_names[mtype].prop_names;
}
else {
media_type = "unknown";
idx = first = last = -1;
prop_names = NULL;
}
media_type = spa_id_map_get_uri (spa_id_map_get_default (), mtype);
media_subtype = spa_id_map_get_uri (spa_id_map_get_default (), mstype);
if (mstype >= SPA_MEDIA_SUBTYPE_ANY_FIRST &&
mstype <= SPA_MEDIA_SUBTYPE_ANY_LAST) {
media_subtype = media_subtype_names[mstype].name;
} else if (mstype >= first && mstype <= last)
media_subtype = media_subtype_names[mstype - first + idx].name;
else
media_subtype = "unknown";
fprintf (stderr, "%-6s %s/%s\n", "", media_type, media_subtype);
fprintf (stderr, "%-6s %s/%s\n", "", strstr (media_type, "#")+1, strstr (media_subtype, "#")+1);
SPA_FORMAT_FOREACH (format, prop) {
const char *key;
if ((prop->body.flags & SPA_POD_PROP_FLAG_UNSET) &&
(prop->body.flags & SPA_POD_PROP_FLAG_OPTIONAL))
continue;
fprintf (stderr, " %20s : (%s) ", prop_names[prop->body.key - SPA_PROP_ID_MEDIA_CUSTOM_START], pod_type_names[prop->body.value.type].name);
key = spa_id_map_get_uri (spa_id_map_get_default (), prop->body.key);
fprintf (stderr, " %20s : (%s) ", strstr (key, "#")+1, pod_type_names[prop->body.value.type].name);
if (!(prop->body.flags & SPA_POD_PROP_FLAG_UNSET)) {
print_format_value (prop->body.value.size, prop->body.value.type, SPA_POD_BODY (&prop->body.value));
} else {

View file

@ -45,6 +45,7 @@ id_map_get_id (SpaIDMap *map, const char *uri)
if (strcmp (this->uris[i], uri) == 0)
return i;
}
printf ("spa adding %d %s\n", i, uri);
this->uris[i] = (char *)uri;
this->n_uris++;
}
@ -56,6 +57,8 @@ id_map_get_uri (SpaIDMap *map, uint32_t id)
{
IDMap *this = SPA_CONTAINER_OF (map, IDMap, map);
printf ("spa get %d\n", id);
if (id < this->n_uris)
return this->uris[id];
return 0;
@ -71,8 +74,16 @@ static IDMap default_id_map = {
0
};
static SpaIDMap *default_map = &default_id_map.map;
SpaIDMap *
spa_id_map_get_default (void)
{
return &default_id_map.map;
return default_map;
}
void
spa_id_map_set_default (SpaIDMap *map)
{
default_map = map;
}

View file

@ -26,6 +26,7 @@ extern "C" {
#include <spa/id-map.h>
void spa_id_map_set_default (SpaIDMap *map);
SpaIDMap * spa_id_map_get_default (void);
#ifdef __cplusplus

View file

@ -26,107 +26,60 @@
#include <spa/video/format.h>
#include <spa/format-builder.h>
#include <lib/props.h>
typedef struct {
uint32_t key;
uint32_t type;
off_t offset;
} ParseInfo;
static const ParseInfo raw_parse_info[] = {
{ SPA_PROP_ID_VIDEO_INFO, SPA_POD_TYPE_BYTES, offsetof (SpaVideoInfo, info.raw) },
{ SPA_PROP_ID_VIDEO_FORMAT, SPA_POD_TYPE_INT, offsetof (SpaVideoInfo, info.raw.format) },
{ SPA_PROP_ID_VIDEO_SIZE, SPA_POD_TYPE_RECTANGLE, offsetof (SpaVideoInfo, info.raw.size) },
{ SPA_PROP_ID_VIDEO_FRAMERATE, SPA_POD_TYPE_FRACTION, offsetof (SpaVideoInfo, info.raw.framerate) },
{ SPA_PROP_ID_VIDEO_MAX_FRAMERATE, SPA_POD_TYPE_FRACTION, offsetof (SpaVideoInfo, info.raw.max_framerate) },
{ SPA_PROP_ID_VIDEO_VIEWS, SPA_POD_TYPE_INT, offsetof (SpaVideoInfo, info.raw.views) },
{ SPA_PROP_ID_VIDEO_INTERLACE_MODE, SPA_POD_TYPE_INT, offsetof (SpaVideoInfo, info.raw.interlace_mode) },
{ SPA_PROP_ID_VIDEO_PIXEL_ASPECT_RATIO, SPA_POD_TYPE_FRACTION, offsetof (SpaVideoInfo, info.raw.pixel_aspect_ratio) },
{ SPA_PROP_ID_VIDEO_MULTIVIEW_MODE, SPA_POD_TYPE_INT, offsetof (SpaVideoInfo, info.raw.multiview_mode) },
{ SPA_PROP_ID_VIDEO_MULTIVIEW_FLAGS, SPA_POD_TYPE_INT, offsetof (SpaVideoInfo, info.raw.multiview_flags) },
{ SPA_PROP_ID_VIDEO_CHROMA_SITE, SPA_POD_TYPE_INT, offsetof (SpaVideoInfo, info.raw.chroma_site) },
{ SPA_PROP_ID_VIDEO_COLOR_RANGE, SPA_POD_TYPE_INT, offsetof (SpaVideoInfo, info.raw.color_range) },
{ SPA_PROP_ID_VIDEO_COLOR_MATRIX, SPA_POD_TYPE_INT, offsetof (SpaVideoInfo, info.raw.color_matrix) },
{ SPA_PROP_ID_VIDEO_TRANSFER_FUNCTION, SPA_POD_TYPE_INT, offsetof (SpaVideoInfo, info.raw.transfer_function) },
{ SPA_PROP_ID_VIDEO_COLOR_PRIMARIES, SPA_POD_TYPE_INT, offsetof (SpaVideoInfo, info.raw.color_primaries) },
{ 0, }
};
static const ParseInfo h264_parse_info[] = {
{ SPA_PROP_ID_VIDEO_INFO, SPA_POD_TYPE_BYTES, offsetof (SpaVideoInfo, info.h264) },
{ SPA_PROP_ID_VIDEO_SIZE, SPA_POD_TYPE_RECTANGLE, offsetof (SpaVideoInfo, info.h264.size) },
{ SPA_PROP_ID_VIDEO_FRAMERATE, SPA_POD_TYPE_FRACTION, offsetof (SpaVideoInfo, info.h264.framerate) },
{ SPA_PROP_ID_VIDEO_MAX_FRAMERATE, SPA_POD_TYPE_FRACTION, offsetof (SpaVideoInfo, info.h264.max_framerate) },
{ 0, }
};
static const ParseInfo mjpg_parse_info[] = {
{ SPA_PROP_ID_VIDEO_INFO, SPA_POD_TYPE_BYTES, offsetof (SpaVideoInfo, info.h264) },
{ SPA_PROP_ID_VIDEO_SIZE, SPA_POD_TYPE_RECTANGLE, offsetof (SpaVideoInfo, info.h264.size) },
{ SPA_PROP_ID_VIDEO_FRAMERATE, SPA_POD_TYPE_FRACTION, offsetof (SpaVideoInfo, info.h264.framerate) },
{ SPA_PROP_ID_VIDEO_MAX_FRAMERATE, SPA_POD_TYPE_FRACTION, offsetof (SpaVideoInfo, info.h264.max_framerate) },
{ 0, }
};
static const ParseInfo *
parse_info_find (const ParseInfo *info, uint32_t key, uint32_t type)
{
while (info->key) {
if (info->key == key && info->type == type)
return info;
info++;
}
return NULL;
}
#include <lib/mapper.h>
SpaResult
spa_format_video_parse (const SpaFormat *format,
SpaVideoInfo *info)
spa_format_video_parse (const SpaFormat *format,
SpaVideoInfo *info)
{
SpaPODProp *prop;
const ParseInfo *pinfo, *find;
static SpaMediaTypes media_types = { 0, };
static SpaMediaSubtypes media_subtypes = { 0, };
static SpaMediaSubtypesVideo media_subtypes_video = { 0, };
static SpaPropVideo prop_video = { 0, };
if (format->body.media_type.value != SPA_MEDIA_TYPE_VIDEO)
spa_media_types_fill (&media_types, spa_id_map_get_default ());
spa_media_subtypes_map (spa_id_map_get_default (), &media_subtypes);
spa_media_subtypes_video_map (spa_id_map_get_default (), &media_subtypes_video);
spa_prop_video_map (spa_id_map_get_default (), &prop_video);
if (format->body.media_type.value != media_types.video)
return SPA_RESULT_INVALID_MEDIA_TYPE;
info->media_type = format->body.media_type.value;
info->media_subtype = format->body.media_subtype.value;
switch (info->media_subtype) {
case SPA_MEDIA_SUBTYPE_RAW:
pinfo = raw_parse_info;
break;
case SPA_MEDIA_SUBTYPE_H264:
pinfo = h264_parse_info;
break;
case SPA_MEDIA_SUBTYPE_MJPG:
pinfo = mjpg_parse_info;
break;
case SPA_MEDIA_SUBTYPE_DV:
case SPA_MEDIA_SUBTYPE_MPEGTS:
case SPA_MEDIA_SUBTYPE_H263:
case SPA_MEDIA_SUBTYPE_MPEG1:
case SPA_MEDIA_SUBTYPE_MPEG2:
case SPA_MEDIA_SUBTYPE_MPEG4:
case SPA_MEDIA_SUBTYPE_XVID:
case SPA_MEDIA_SUBTYPE_VC1:
case SPA_MEDIA_SUBTYPE_VP8:
case SPA_MEDIA_SUBTYPE_VP9:
case SPA_MEDIA_SUBTYPE_JPEG:
case SPA_MEDIA_SUBTYPE_BAYER:
return SPA_RESULT_NOT_IMPLEMENTED;
if (info->media_subtype == media_subtypes.raw)
spa_format_query (format,
prop_video.format, SPA_POD_TYPE_INT, &info->info.raw.format,
prop_video.size, SPA_POD_TYPE_RECTANGLE, &info->info.raw.size,
prop_video.framerate, SPA_POD_TYPE_FRACTION, &info->info.raw.framerate,
prop_video.max_framerate, SPA_POD_TYPE_FRACTION, &info->info.raw.max_framerate,
prop_video.views, SPA_POD_TYPE_INT, &info->info.raw.views,
prop_video.interlace_mode, SPA_POD_TYPE_INT, &info->info.raw.interlace_mode,
prop_video.pixel_aspect_ratio, SPA_POD_TYPE_FRACTION, &info->info.raw.pixel_aspect_ratio,
prop_video.multiview_mode, SPA_POD_TYPE_INT, &info->info.raw.multiview_mode,
prop_video.multiview_flags, SPA_POD_TYPE_INT, &info->info.raw.multiview_flags,
prop_video.chroma_site, SPA_POD_TYPE_INT, &info->info.raw.chroma_site,
prop_video.color_range, SPA_POD_TYPE_INT, &info->info.raw.color_range,
prop_video.color_matrix, SPA_POD_TYPE_INT, &info->info.raw.color_matrix,
prop_video.transfer_function, SPA_POD_TYPE_INT, &info->info.raw.transfer_function,
prop_video.color_primaries, SPA_POD_TYPE_INT, &info->info.raw.color_primaries,
0);
else if (info->media_subtype == media_subtypes_video.h264)
spa_format_query (format,
prop_video.size, SPA_POD_TYPE_RECTANGLE, &info->info.h264.size,
prop_video.framerate, SPA_POD_TYPE_FRACTION, &info->info.h264.framerate,
prop_video.max_framerate, SPA_POD_TYPE_FRACTION, &info->info.h264.max_framerate,
0);
else if (info->media_subtype == media_subtypes_video.mjpg)
spa_format_query (format,
prop_video.size, SPA_POD_TYPE_RECTANGLE, &info->info.mjpg.size,
prop_video.framerate, SPA_POD_TYPE_FRACTION, &info->info.mjpg.framerate,
prop_video.max_framerate, SPA_POD_TYPE_FRACTION, &info->info.mjpg.max_framerate,
0);
else
return SPA_RESULT_NOT_IMPLEMENTED;
default:
return SPA_RESULT_INVALID_ARGUMENTS;
}
SPA_FORMAT_FOREACH (format, prop) {
if ((find = parse_info_find (pinfo, prop->body.key, prop->body.value.type))) {
memcpy (SPA_MEMBER (info, find->offset, void),
SPA_POD_BODY (&prop->body.value),
SPA_POD_BODY_SIZE (&prop->body.value));
}
}
return SPA_RESULT_OK;
}