androidmedia: Add support for H265/HEVC

This commit is contained in:
Sebastian Dröge 2015-07-08 11:42:48 +03:00
parent cc3d79f7cc
commit 42a1a95f3e
5 changed files with 215 additions and 3 deletions

View file

@ -116,6 +116,41 @@ enum
COLOR_FormatYV12 = 0x32315659,
};
enum
{
HEVCProfileMain = 0x01,
HEVCProfileMain10 = 0x02
};
enum
{
HEVCMainTierLevel1 = 0x1,
HEVCHighTierLevel1 = 0x2,
HEVCMainTierLevel2 = 0x4,
HEVCHighTierLevel2 = 0x8,
HEVCMainTierLevel21 = 0x10,
HEVCHighTierLevel21 = 0x20,
HEVCMainTierLevel3 = 0x40,
HEVCHighTierLevel3 = 0x80,
HEVCMainTierLevel31 = 0x100,
HEVCHighTierLevel31 = 0x200,
HEVCMainTierLevel4 = 0x400,
HEVCHighTierLevel4 = 0x800,
HEVCMainTierLevel41 = 0x1000,
HEVCHighTierLevel41 = 0x2000,
HEVCMainTierLevel5 = 0x4000,
HEVCHighTierLevel5 = 0x8000,
HEVCMainTierLevel51 = 0x10000,
HEVCHighTierLevel51 = 0x20000,
HEVCMainTierLevel52 = 0x40000,
HEVCHighTierLevel52 = 0x80000,
HEVCMainTierLevel6 = 0x100000,
HEVCHighTierLevel6 = 0x200000,
HEVCMainTierLevel61 = 0x400000,
HEVCHighTierLevel61 = 0x800000,
HEVCMainTierLevel62 = 0x1000000
};
enum
{
AVCProfileBaseline = 0x01,

View file

@ -2535,6 +2535,109 @@ done:
return ret;
}
static const struct
{
gint id;
const gchar *str;
} hevc_profile_mapping_table[] = {
{
HEVCProfileMain, "main"}, {
HEVCProfileMain10, "main-10"}
};
const gchar *
gst_amc_hevc_profile_to_string (gint profile)
{
gint i;
for (i = 0; i < G_N_ELEMENTS (hevc_profile_mapping_table); i++) {
if (hevc_profile_mapping_table[i].id == profile) {
return hevc_profile_mapping_table[i].str;
}
}
return NULL;
}
gint
gst_amc_hevc_profile_from_string (const gchar * profile)
{
gint i;
g_return_val_if_fail (profile != NULL, -1);
for (i = 0; i < G_N_ELEMENTS (hevc_profile_mapping_table); i++) {
if (strcmp (hevc_profile_mapping_table[i].str, profile) == 0)
return hevc_profile_mapping_table[i].id;
}
return -1;
}
static const struct
{
gint id;
const gchar *tier_str;
const gchar *level_str;
} hevc_tier_level_mapping_table[] = {
{
HEVCMainTierLevel1, "main", "1"}, {
HEVCMainTierLevel2, "main", "2"}, {
HEVCMainTierLevel21, "main", "2.1"}, {
HEVCMainTierLevel3, "main", "3"}, {
HEVCMainTierLevel31, "main", "3.1"}, {
HEVCMainTierLevel4, "main", "4"}, {
HEVCMainTierLevel41, "main", "4.1"}, {
HEVCMainTierLevel5, "main", "5"}, {
HEVCMainTierLevel51, "main", "5.1"}, {
HEVCMainTierLevel52, "main", "5.2"}, {
HEVCMainTierLevel6, "main", "6"}, {
HEVCMainTierLevel61, "main", "6.1"}, {
HEVCMainTierLevel62, "main", "6.2"}, {
HEVCHighTierLevel1, "high", "1"}, {
HEVCHighTierLevel2, "high", "2"}, {
HEVCHighTierLevel21, "high", "2.1"}, {
HEVCHighTierLevel3, "high", "3"}, {
HEVCHighTierLevel31, "high", "3.1"}, {
HEVCHighTierLevel4, "high", "4"}, {
HEVCHighTierLevel41, "high", "4.1"}, {
HEVCHighTierLevel5, "high", "5"}, {
HEVCHighTierLevel51, "high", "5.1"}, {
HEVCHighTierLevel52, "high", "5.2"}, {
HEVCHighTierLevel6, "high", "6"}, {
HEVCHighTierLevel61, "high", "6.1"}
};
const gchar *
gst_amc_hevc_tier_level_to_string (gint tier_level, const gchar ** tier)
{
gint i;
for (i = 0; i < G_N_ELEMENTS (hevc_tier_level_mapping_table); i++) {
if (hevc_tier_level_mapping_table[i].id == tier_level)
*tier = hevc_tier_level_mapping_table[i].tier_str;
return hevc_tier_level_mapping_table[i].level_str;
}
return NULL;
}
gint
gst_amc_hevc_tier_level_from_string (const gchar * tier, const gchar * level)
{
gint i;
g_return_val_if_fail (level != NULL, -1);
for (i = 0; i < G_N_ELEMENTS (hevc_tier_level_mapping_table); i++) {
if (strcmp (hevc_tier_level_mapping_table[i].tier_str, tier) == 0 &&
strcmp (hevc_tier_level_mapping_table[i].level_str, level) == 0)
return hevc_tier_level_mapping_table[i].id;
}
return -1;
}
static const struct
{
gint id;
@ -2757,7 +2860,7 @@ gst_amc_mpeg4_profile_to_string (gint profile)
}
gint
gst_amc_avc_mpeg4_profile_from_string (const gchar * profile)
gst_amc_mpeg4_profile_from_string (const gchar * profile)
{
gint i;
@ -3577,6 +3680,74 @@ gst_amc_codec_info_to_caps (const GstAmcCodecInfo * codec_info,
}
}
if (!have_profile_level) {
encoded_ret = gst_caps_merge_structure (encoded_ret, tmp);
} else {
gst_structure_free (tmp);
}
} else if (strcmp (type->mime, "video/hevc") == 0) {
gint j;
gboolean have_profile_level = FALSE;
tmp = gst_structure_new ("video/x-h265",
"width", GST_TYPE_INT_RANGE, 16, 4096,
"height", GST_TYPE_INT_RANGE, 16, 4096,
"framerate", GST_TYPE_FRACTION_RANGE,
0, 1, G_MAXINT, 1,
"parsed", G_TYPE_BOOLEAN, TRUE,
"stream-format", G_TYPE_STRING, "byte-stream",
"alignment", G_TYPE_STRING, "au", NULL);
if (type->n_profile_levels) {
for (j = type->n_profile_levels - 1; j >= 0; j--) {
const gchar *profile;
profile =
gst_amc_hevc_profile_to_string (type->profile_levels[j].
profile);
if (!profile) {
GST_ERROR ("Unable to map H265 profile 0x%08x",
type->profile_levels[j].profile);
continue;
}
tmp2 = gst_structure_copy (tmp);
gst_structure_set (tmp2, "profile", G_TYPE_STRING, profile, NULL);
/* FIXME: Implement tier/level support here */
#if 0
if (codec_info->is_encoder) {
const gchar *level, *tier;
gint k;
GValue va = { 0, };
GValue v = { 0, };
g_value_init (&va, GST_TYPE_LIST);
g_value_init (&v, G_TYPE_STRING);
for (k = 1; k <= type->profile_levels[j].level && k != 0;
k <<= 1) {
level = gst_amc_hevc_tier_level_to_string (k, &tier);
if (!level)
continue;
g_value_set_string (&v, level);
gst_value_list_append_value (&va, &v);
g_value_reset (&v);
}
gst_structure_set_value (tmp2, "level", &va);
g_value_unset (&va);
g_value_unset (&v);
}
#endif
encoded_ret = gst_caps_merge_structure (encoded_ret, tmp2);
have_profile_level = TRUE;
}
}
if (!have_profile_level) {
encoded_ret = gst_caps_merge_structure (encoded_ret, tmp);
} else {

View file

@ -147,12 +147,16 @@ const gchar * gst_amc_avc_profile_to_string (gint profile, const gchar **alterna
gint gst_amc_avc_profile_from_string (const gchar *profile);
const gchar * gst_amc_avc_level_to_string (gint level);
gint gst_amc_avc_level_from_string (const gchar *level);
const gchar * gst_amc_hevc_profile_to_string (gint profile);
gint gst_amc_hevc_profile_from_string (const gchar *profile);
const gchar * gst_amc_hevc_tier_level_to_string (gint tier_level, const gchar ** tier);
gint gst_amc_hevc_tier_level_from_string (const gchar * tier, const gchar *level);
gint gst_amc_h263_profile_to_gst_id (gint profile);
gint gst_amc_h263_profile_from_gst_id (gint profile);
gint gst_amc_h263_level_to_gst_id (gint level);
gint gst_amc_h263_level_from_gst_id (gint level);
const gchar * gst_amc_mpeg4_profile_to_string (gint profile);
gint gst_amc_avc_mpeg4_profile_from_string (const gchar *profile);
gint gst_amc_mpeg4_profile_from_string (const gchar *profile);
const gchar * gst_amc_mpeg4_level_to_string (gint level);
gint gst_amc_mpeg4_level_from_string (const gchar *level);
const gchar * gst_amc_aac_profile_to_string (gint profile);

View file

@ -172,6 +172,8 @@ caps_to_mime (GstCaps * caps)
return "video/3gpp";
} else if (strcmp (name, "video/x-h264") == 0) {
return "video/avc";
} else if (strcmp (name, "video/x-h265") == 0) {
return "video/hevc";
} else if (strcmp (name, "video/x-vp8") == 0) {
return "video/x-vnd.on2.vp8";
} else if (strcmp (name, "video/x-divx") == 0) {

View file

@ -185,7 +185,7 @@ create_amc_format (GstAmcVideoEnc * encoder, GstVideoCodecState * input_state,
if (profile_string) {
amc_profile.key = "profile"; /* named profile ? */
amc_profile.id = gst_amc_avc_mpeg4_profile_from_string (profile_string);
amc_profile.id = gst_amc_mpeg4_profile_from_string (profile_string);
}
if (level_string) {