transcode: use av codec string names instead IDs

- to allow the selection from the multiple encoders for same type
This commit is contained in:
Jaroslav Kysela 2014-10-12 10:03:26 +02:00
parent 47f56f7f1f
commit 9ca0248069
4 changed files with 160 additions and 122 deletions

View file

@ -1041,6 +1041,46 @@ config_migrate_v13 ( void )
}
}
static const char *
config_migrate_v14_codec(int i)
{
switch (i) {
case 1: return "mpeg2video";
case 2: return "mp2";
case 3: return "libx264";
case 4: return "ac3";
case 8: return "aac";
case 13: return "libvpx";
case 14: return "libvorbis";
default: return "";
}
}
static void
config_migrate_v14 ( void )
{
htsmsg_t *c, *e;
htsmsg_field_t *f;
int i;
if ((c = hts_settings_load("profile")) != NULL) {
HTSMSG_FOREACH(f, c) {
if (!(e = htsmsg_field_get_map(f))) continue;
if (!htsmsg_get_s32(e, "vcodec", &i)) {
htsmsg_delete_field(e, "vcodec");
htsmsg_set_str(e, "vcodec", config_migrate_v14_codec(i));
}
if (!htsmsg_get_s32(e, "acodec", &i)) {
htsmsg_delete_field(e, "acodec");
htsmsg_set_str(e, "acodec", config_migrate_v14_codec(i));
}
if (!htsmsg_get_s32(e, "scodec", &i))
htsmsg_delete_field(e, "scodec");
hts_settings_save(e, "profile/%s", f->hmf_name);
}
}
}
/*
* Perform backup
*/
@ -1142,7 +1182,8 @@ static const config_migrate_t config_migrate_table[] = {
config_migrate_v10,
config_migrate_v11,
config_migrate_v12,
config_migrate_v13
config_migrate_v13,
config_migrate_v14
};
/*

View file

@ -184,28 +184,13 @@ transcoder_get_decoder(streaming_component_type_t ty)
*
*/
static AVCodec *
transcoder_get_encoder(streaming_component_type_t ty)
transcoder_get_encoder(const char *codec_name)
{
enum AVCodecID codec_id;
AVCodec *codec;
codec_id = streaming_component_type2codec_id(ty);
if (codec_id == AV_CODEC_ID_NONE) {
tvhlog(LOG_ERR, "transcode", "Unable to find %s codec",
streaming_component_type2txt(ty));
return NULL;
}
if (!WORKING_ENCODER(codec_id)) {
tvhlog(LOG_WARNING, "transcode", "Unsupported output codec %s",
streaming_component_type2txt(ty));
return NULL;
}
codec = avcodec_find_encoder(codec_id);
codec = avcodec_find_encoder_by_name(codec_name);
if (!codec) {
tvhlog(LOG_ERR, "transcode", "Unable to find %s encoder",
streaming_component_type2txt(ty));
tvhlog(LOG_ERR, "transcode", "Unable to find %s encoder", codec_name);
return NULL;
}
tvhlog(LOG_DEBUG, "transcode", "Using encoder %s", codec->name);
@ -1416,11 +1401,12 @@ transcoder_init_subtitle(transcoder_t *t, streaming_start_component_t *ssc)
subtitle_stream_t *ss;
AVCodec *icodec, *ocodec;
transcoder_props_t *tp = &t->t_props;
int sct;
if (tp->tp_scodec == SCT_NONE)
if (tp->tp_scodec[0] == '\0')
return 0;
else if (tp->tp_scodec == SCT_UNKNOWN)
else if (!strcmp(tp->tp_scodec, "copy"))
return transcoder_init_stream(t, ssc);
else if (!(icodec = transcoder_get_decoder(ssc->ssc_type)))
@ -1429,13 +1415,15 @@ transcoder_init_subtitle(transcoder_t *t, streaming_start_component_t *ssc)
else if (!(ocodec = transcoder_get_encoder(tp->tp_scodec)))
return transcoder_init_stream(t, ssc);
if (tp->tp_scodec == ssc->ssc_type)
sct = codec_id2streaming_component_type(ocodec->id);
if (sct == ssc->ssc_type)
return transcoder_init_stream(t, ssc);
ss = calloc(1, sizeof(subtitle_stream_t));
ss->ts_index = ssc->ssc_index;
ss->ts_type = tp->tp_scodec;
ss->ts_type = sct;
ss->ts_target = t->t_output;
ss->ts_handle_pkt = transcoder_stream_subtitle;
ss->ts_destroy = transcoder_destroy_subtitle;
@ -1453,7 +1441,7 @@ transcoder_init_subtitle(transcoder_t *t, streaming_start_component_t *ssc)
streaming_component_type2txt(ssc->ssc_type),
streaming_component_type2txt(ss->ts_type));
ssc->ssc_type = tp->tp_scodec;
ssc->ssc_type = sct;
ssc->ssc_gh = NULL;
return 1;
@ -1506,11 +1494,12 @@ transcoder_init_audio(transcoder_t *t, streaming_start_component_t *ssc)
transcoder_stream_t *ts;
AVCodec *icodec, *ocodec;
transcoder_props_t *tp = &t->t_props;
int sct;
if (tp->tp_acodec == SCT_NONE)
if (tp->tp_acodec[0] == '\0')
return 0;
else if (tp->tp_acodec == SCT_UNKNOWN)
else if (!strcmp(tp->tp_acodec, "copy"))
return transcoder_init_stream(t, ssc);
else if (!(icodec = transcoder_get_decoder(ssc->ssc_type)))
@ -1523,13 +1512,15 @@ transcoder_init_audio(transcoder_t *t, streaming_start_component_t *ssc)
if (SCT_ISAUDIO(ts->ts_type))
return 0;
if (tp->tp_acodec == ssc->ssc_type)
sct = codec_id2streaming_component_type(ocodec->id);
if (sct == ssc->ssc_type)
return transcoder_init_stream(t, ssc);
as = calloc(1, sizeof(audio_stream_t));
as->ts_index = ssc->ssc_index;
as->ts_type = tp->tp_acodec;
as->ts_type = sct;
as->ts_target = t->t_output;
as->ts_handle_pkt = transcoder_stream_audio;
as->ts_destroy = transcoder_destroy_audio;
@ -1559,7 +1550,7 @@ transcoder_init_audio(transcoder_t *t, streaming_start_component_t *ssc)
streaming_component_type2txt(ssc->ssc_type),
streaming_component_type2txt(as->ts_type));
ssc->ssc_type = tp->tp_acodec;
ssc->ssc_type = sct;
ssc->ssc_gh = NULL;
// resampling not implemented yet
@ -1621,11 +1612,12 @@ transcoder_init_video(transcoder_t *t, streaming_start_component_t *ssc)
AVCodec *icodec, *ocodec;
double aspect;
transcoder_props_t *tp = &t->t_props;
int sct;
if (tp->tp_vcodec == SCT_NONE)
if (tp->tp_vcodec[0] == '\0')
return 0;
else if (tp->tp_vcodec == SCT_UNKNOWN)
else if (!strcmp(tp->tp_vcodec, "copy"))
return transcoder_init_stream(t, ssc);
else if (!(icodec = transcoder_get_decoder(ssc->ssc_type)))
@ -1634,10 +1626,12 @@ transcoder_init_video(transcoder_t *t, streaming_start_component_t *ssc)
else if (!(ocodec = transcoder_get_encoder(tp->tp_vcodec)))
return transcoder_init_stream(t, ssc);
sct = codec_id2streaming_component_type(ocodec->id);
vs = calloc(1, sizeof(video_stream_t));
vs->ts_index = ssc->ssc_index;
vs->ts_type = tp->tp_vcodec;
vs->ts_type = sct;
vs->ts_target = t->t_output;
vs->ts_handle_pkt = transcoder_stream_video;
vs->ts_destroy = transcoder_destroy_video;
@ -1683,7 +1677,7 @@ transcoder_init_video(transcoder_t *t, streaming_start_component_t *ssc)
vs->vid_width,
vs->vid_height);
ssc->ssc_type = tp->tp_vcodec;
ssc->ssc_type = sct;
ssc->ssc_width = vs->vid_width;
ssc->ssc_height = vs->vid_height;
ssc->ssc_gh = NULL;
@ -1712,7 +1706,7 @@ transcoder_calc_stream_count(transcoder_t *t, streaming_start_t *ss) {
continue;
if (SCT_ISVIDEO(ssc->ssc_type)) {
if (t->t_props.tp_vcodec == SCT_NONE)
if (t->t_props.tp_vcodec[0] == '\0')
video = 0;
else if (t->t_props.tp_vcodec == SCT_UNKNOWN)
video++;
@ -1720,7 +1714,7 @@ transcoder_calc_stream_count(transcoder_t *t, streaming_start_t *ss) {
video = 1;
} else if (SCT_ISAUDIO(ssc->ssc_type)) {
if (t->t_props.tp_acodec == SCT_NONE)
if (t->t_props.tp_acodec[0] == '\0')
audio = 0;
else if (t->t_props.tp_acodec == SCT_UNKNOWN)
audio++;
@ -1728,7 +1722,7 @@ transcoder_calc_stream_count(transcoder_t *t, streaming_start_t *ss) {
audio = 1;
} else if (SCT_ISSUBTITLE(ssc->ssc_type)) {
if (t->t_props.tp_scodec == SCT_NONE)
if (t->t_props.tp_scodec[0] == '\0')
subtitle = 0;
else if (t->t_props.tp_scodec == SCT_UNKNOWN)
subtitle++;
@ -1898,9 +1892,9 @@ transcoder_set_properties(streaming_target_t *st,
transcoder_t *t = (transcoder_t *)st;
transcoder_props_t *tp = &t->t_props;
tp->tp_vcodec = props->tp_vcodec;
tp->tp_acodec = props->tp_acodec;
tp->tp_scodec = props->tp_scodec;
strncpy(tp->tp_vcodec, props->tp_vcodec, sizeof(tp->tp_vcodec)-1);
strncpy(tp->tp_acodec, props->tp_acodec, sizeof(tp->tp_acodec)-1);
strncpy(tp->tp_scodec, props->tp_scodec, sizeof(tp->tp_scodec)-1);
tp->tp_channels = props->tp_channels;
tp->tp_bandwidth = props->tp_bandwidth;
tp->tp_resolution = props->tp_resolution;
@ -1930,7 +1924,7 @@ transcoder_get_capabilities(int experimental)
{
AVCodec *p = NULL;
streaming_component_type_t sct;
htsmsg_t *array = htsmsg_create_list();
htsmsg_t *array = htsmsg_create_list(), *m;
while ((p = av_codec_next(p))) {
@ -1947,7 +1941,13 @@ transcoder_get_capabilities(int experimental)
if (sct == SCT_NONE)
continue;
htsmsg_add_s32(array, NULL, sct);
m = htsmsg_create_map();
htsmsg_add_s32(m, "type", sct);
htsmsg_add_u32(m, "id", p->id);
htsmsg_add_str(m, "name", p->name);
if (p->long_name)
htsmsg_add_str(m, "long_name", p->long_name);
htsmsg_add_msg(array, NULL, m);
}
return array;
}

View file

@ -21,9 +21,9 @@
#include "htsmsg.h"
typedef struct transcoder_prop {
streaming_component_type_t tp_vcodec;
streaming_component_type_t tp_acodec;
streaming_component_type_t tp_scodec;
char tp_vcodec[32];
char tp_acodec[32];
char tp_scodec[32];
int8_t tp_channels;
int32_t tp_bandwidth;

View file

@ -539,9 +539,9 @@ typedef struct profile_transcode {
uint32_t pro_channels;
uint32_t pro_bandwidth;
char *pro_language;
int pro_vcodec;
int pro_acodec;
int pro_scodec;
char *pro_vcodec;
char *pro_acodec;
char *pro_scodec;
} profile_transcode_t;
static htsmsg_t *
@ -611,90 +611,80 @@ profile_class_check_sct(htsmsg_t *c, int sct)
}
static htsmsg_t *
profile_class_vcodec_list(void *o)
profile_class_codec_list(int (*check)(int sct))
{
htsmsg_t *l = htsmsg_create_list(), *e, *c;
int i;
htsmsg_t *l = htsmsg_create_list(), *e, *c, *m;
htsmsg_field_t *f;
const char *s, *s2;
char buf[128];
int sct;
e = htsmsg_create_map();
htsmsg_add_s32(e, "key", -1);
htsmsg_add_str(e, "key", "");
htsmsg_add_str(e, "val", "Do not use");
htsmsg_add_msg(l, NULL, e);
e = htsmsg_create_map();
htsmsg_add_s32(e, "key", 0);
htsmsg_add_str(e, "key", "copy");
htsmsg_add_str(e, "val", "Copy codec type");
htsmsg_add_msg(l, NULL, e);
c = transcoder_get_capabilities(profile_transcode_experimental_codecs);
for (i = 0; i <= SCT_LAST; i++) {
if (!SCT_ISVIDEO(i))
HTSMSG_FOREACH(f, c) {
if (!(m = htsmsg_field_get_map(f)))
continue;
if (!profile_class_check_sct(c, i))
if (htsmsg_get_s32(m, "type", &sct))
continue;
if (!check(sct))
continue;
if (!(s = htsmsg_get_str(m, "name")))
continue;
s2 = htsmsg_get_str(m, "long_name");
if (s2)
snprintf(buf, sizeof(buf), "%s (%s)", s, s2);
else
snprintf(buf, sizeof(buf), "%s", s);
e = htsmsg_create_map();
htsmsg_add_u32(e, "key", i);
htsmsg_add_str(e, "val", streaming_component_type2txt(i));
htsmsg_add_str(e, "key", s);
htsmsg_add_str(e, "val", buf);
htsmsg_add_msg(l, NULL, e);
}
htsmsg_destroy(c);
return l;
}
static int
profile_class_vcodec_sct_check(int sct)
{
return SCT_ISVIDEO(sct);
}
static htsmsg_t *
profile_class_vcodec_list(void *o)
{
return profile_class_codec_list(profile_class_vcodec_sct_check);
}
static int
profile_class_acodec_sct_check(int sct)
{
return SCT_ISAUDIO(sct);
}
static htsmsg_t *
profile_class_acodec_list(void *o)
{
htsmsg_t *l = htsmsg_create_list(), *e, *c;
int i;
return profile_class_codec_list(profile_class_acodec_sct_check);
}
e = htsmsg_create_map();
htsmsg_add_s32(e, "key", -1);
htsmsg_add_str(e, "val", "Do not use");
htsmsg_add_msg(l, NULL, e);
e = htsmsg_create_map();
htsmsg_add_s32(e, "key", 0);
htsmsg_add_str(e, "val", "Copy codec type");
htsmsg_add_msg(l, NULL, e);
c = transcoder_get_capabilities(profile_transcode_experimental_codecs);
for (i = 0; i <= SCT_LAST; i++) {
if (!SCT_ISAUDIO(i))
continue;
if (!profile_class_check_sct(c, i))
continue;
e = htsmsg_create_map();
htsmsg_add_s32(e, "key", i);
htsmsg_add_str(e, "val", streaming_component_type2txt(i));
htsmsg_add_msg(l, NULL, e);
}
htsmsg_destroy(c);
return l;
static int
profile_class_scodec_sct_check(int sct)
{
return SCT_ISSUBTITLE(sct);
}
static htsmsg_t *
profile_class_scodec_list(void *o)
{
htsmsg_t *l = htsmsg_create_list(), *e, *c;
int i;
e = htsmsg_create_map();
htsmsg_add_s32(e, "key", -1);
htsmsg_add_str(e, "val", "Do not use");
htsmsg_add_msg(l, NULL, e);
e = htsmsg_create_map();
htsmsg_add_s32(e, "key", 0);
htsmsg_add_str(e, "val", "Copy codec type");
htsmsg_add_msg(l, NULL, e);
c = transcoder_get_capabilities(profile_transcode_experimental_codecs);
for (i = 0; i <= SCT_LAST; i++) {
if (!SCT_ISSUBTITLE(i))
continue;
if (!profile_class_check_sct(c, i))
continue;
e = htsmsg_create_map();
htsmsg_add_s32(e, "key", i);
htsmsg_add_str(e, "val", streaming_component_type2txt(i));
htsmsg_add_msg(l, NULL, e);
}
htsmsg_destroy(c);
return l;
return profile_class_codec_list(profile_class_scodec_sct_check);
}
const idclass_t profile_transcode_class =
@ -734,27 +724,27 @@ const idclass_t profile_transcode_class =
.list = profile_class_language_list,
},
{
.type = PT_INT,
.type = PT_STR,
.id = "vcodec",
.name = "Video Codec",
.off = offsetof(profile_transcode_t, pro_vcodec),
.def.i = SCT_H264,
.def.s = "libx264",
.list = profile_class_vcodec_list,
},
{
.type = PT_INT,
.type = PT_STR,
.id = "acodec",
.name = "Audio Codec",
.off = offsetof(profile_transcode_t, pro_acodec),
.def.i = SCT_VORBIS,
.def.s = "libvorbis",
.list = profile_class_acodec_list,
},
{
.type = PT_INT,
.type = PT_STR,
.id = "scodec",
.name = "Subtitles Codec",
.off = offsetof(profile_transcode_t, pro_scodec),
.def.i = SCT_NONE,
.def.s = "",
.list = profile_class_scodec_list,
},
{ }
@ -777,9 +767,9 @@ profile_transcode_work(profile_t *_pro, streaming_target_t *src,
streaming_target_t *st;
memset(&props, 0, sizeof(props));
props.tp_vcodec = pro->pro_vcodec;
props.tp_acodec = pro->pro_acodec;
props.tp_scodec = pro->pro_scodec;
strncpy(props.tp_vcodec, pro->pro_vcodec ?: "", sizeof(props.tp_vcodec)-1);
strncpy(props.tp_acodec, pro->pro_acodec ?: "", sizeof(props.tp_acodec)-1);
strncpy(props.tp_scodec, pro->pro_scodec ?: "", sizeof(props.tp_scodec)-1);
props.tp_resolution = pro->pro_resolution >= 240 ? pro->pro_resolution : 240;
props.tp_channels = pro->pro_channels;
props.tp_bandwidth = pro->pro_bandwidth >= 64 ? pro->pro_bandwidth : 64;
@ -842,10 +832,20 @@ profile_transcode_get_mc(profile_t *_pro)
return pro->pro_mc;
}
static void
profile_transcode_free(profile_t *_pro)
{
profile_transcode_t *pro = (profile_transcode_t *)_pro;
free(pro->pro_vcodec);
free(pro->pro_acodec);
free(pro->pro_scodec);
}
static profile_t *
profile_transcode_builder(void)
{
profile_transcode_t *pro = calloc(1, sizeof(*pro));
pro->pro_free = profile_transcode_free;
pro->pro_work = profile_transcode_work;
pro->pro_open = profile_transcode_open;
pro->pro_get_mc = profile_transcode_get_mc;
@ -925,9 +925,8 @@ profile_init(void)
htsmsg_add_s32 (conf, "container", MC_WEBM);
htsmsg_add_u32 (conf, "resolution", 384);
htsmsg_add_u32 (conf, "channels", 2);
htsmsg_add_s32 (conf, "vcodec", SCT_VP8);
htsmsg_add_s32 (conf, "acodec", SCT_VORBIS);
htsmsg_add_s32 (conf, "scodec", SCT_NONE);
htsmsg_add_str (conf, "vcodec", "libvpx");
htsmsg_add_str (conf, "acodec", "libvorbis");
htsmsg_add_bool(conf, "shield", 1);
(void)profile_create(NULL, conf, 1);
htsmsg_destroy(conf);
@ -945,9 +944,8 @@ profile_init(void)
htsmsg_add_s32 (conf, "container", MC_MPEGTS);
htsmsg_add_u32 (conf, "resolution", 384);
htsmsg_add_u32 (conf, "channels", 2);
htsmsg_add_s32 (conf, "vcodec", SCT_H264);
htsmsg_add_s32 (conf, "acodec", SCT_AAC);
htsmsg_add_s32 (conf, "scodec", SCT_NONE);
htsmsg_add_str (conf, "vcodec", "libx264");
htsmsg_add_str (conf, "acodec", "aac");
htsmsg_add_bool(conf, "shield", 1);
(void)profile_create(NULL, conf, 1);
htsmsg_destroy(conf);
@ -965,9 +963,8 @@ profile_init(void)
htsmsg_add_s32 (conf, "container", MC_MATROSKA);
htsmsg_add_u32 (conf, "resolution", 384);
htsmsg_add_u32 (conf, "channels", 2);
htsmsg_add_s32 (conf, "vcodec", SCT_H264);
htsmsg_add_s32 (conf, "acodec", SCT_AAC);
htsmsg_add_s32 (conf, "scodec", SCT_NONE);
htsmsg_add_str (conf, "vcodec", "libx264");
htsmsg_add_str (conf, "acodec", "aac");
htsmsg_add_bool(conf, "shield", 1);
(void)profile_create(NULL, conf, 1);
htsmsg_destroy(conf);