From: Jaroslav Kysela Date: Mon, 28 Aug 2017 15:41:29 +0000 (+0200) Subject: transcode: implement back the possibility to skip source codecs (from commit a334c453... X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=cf70b199f3c6b6a45bade3a634c41a8ef78826ec;p=thirdparty%2Ftvheadend.git transcode: implement back the possibility to skip source codecs (from commit a334c453cd36bb4b622a5a17e5349c1055143fe2) --- diff --git a/src/profile.c b/src/profile.c index abc53c53d..97f764d39 100644 --- a/src/profile.c +++ b/src/profile.c @@ -2007,8 +2007,11 @@ typedef struct profile_transcode { profile_t; int pro_mc; char *pro_vcodec; + char *pro_src_vcodec; char *pro_acodec; + char *pro_src_acodec; char *pro_scodec; + char *pro_src_scodec; } profile_transcode_t; @@ -2086,18 +2089,60 @@ profile_class_pro_vcodec_list(void *o, const char *lang) return profile_class_codec_profiles_list(AVMEDIA_TYPE_VIDEO, lang); } +static htsmsg_t * +profile_class_src_vcodec_list ( void *o, const char *lang ) +{ + static const struct strtab_str tab[] = { + { "-", "" }, + { "MPEG2VIDEO", "MPEG2VIDEO" }, + { "H264", "H264" }, + { "VP8", "VP8" }, + { "HEVC", "HEVC" }, + { "VP9", "VP9" }, + { "THEORA", "THEORA" }, + }; + return strtab2htsmsg_str(tab, 1, lang); +} + static htsmsg_t * profile_class_pro_acodec_list(void *o, const char *lang) { return profile_class_codec_profiles_list(AVMEDIA_TYPE_AUDIO, lang); } +static htsmsg_t * +profile_class_src_acodec_list ( void *o, const char *lang ) +{ + static const struct strtab_str tab[] = { + { "-", "" }, + { "MPEG2AUDIO", "MPEG2AUDIO" }, + { "AC3", "AC3" }, + { "AAC", "AAC" }, + { "MP4A", "MP4A" }, + { "EAC3", "EAC3" }, + { "VORBIS", "VORBIS" }, + { "OPUS", "OPUS" }, + }; + return strtab2htsmsg_str(tab, 1, lang); +} + static htsmsg_t * profile_class_pro_scodec_list(void *o, const char *lang) { return profile_class_codec_profiles_list(AVMEDIA_TYPE_SUBTITLE, lang); } +static htsmsg_t * +profile_class_src_scodec_list ( void *o, const char *lang ) +{ + static const struct strtab_str tab[] = { + { "-", "" }, + { "DVBSUB", "DVBSUB" }, + { "TEXTSUB", "TEXTSUB" }, + }; + return strtab2htsmsg_str(tab, 1, lang); +} + const idclass_t profile_transcode_class = { .ic_super = &profile_class, @@ -2135,6 +2180,21 @@ const idclass_t profile_transcode_class = .opts = PO_ADVANCED, .group = 2 }, + { + .type = PT_STR, + .id = "src_vcodec", + .name = N_("Source video codec"), + .desc = N_("Transcode video only if source video codec match. " + "Empty or minus string will ignore source video codec " + "check and continue with transcode. Separate codec names " + "with coma. If no codec match found - transcode with " + "\"copy\" codec, if match found - transcode with video " + "codec defined in this profile."), + .off = offsetof(profile_transcode_t, pro_src_vcodec), + .list = profile_class_src_vcodec_list, + .opts = PO_ADVANCED, + .group = 2 + }, { .type = PT_STR, .id = "pro_acodec", @@ -2145,6 +2205,21 @@ const idclass_t profile_transcode_class = .opts = PO_ADVANCED, .group = 2 }, + { + .type = PT_STR, + .id = "src_acodec", + .name = N_("Source audio codec"), + .desc = N_("Transcode audio only if source audio codec match. " + "Empty or minus string will ignore source audio codec " + "check and continue with transcode. Separate codec names " + "with coma. If no codec match found - transcode with " + "\"copy\" codec, if match found - transcode with audio " + "codec defined in this profile."), + .off = offsetof(profile_transcode_t, pro_src_acodec), + .list = profile_class_src_acodec_list, + .opts = PO_ADVANCED, + .group = 2 + }, { .type = PT_STR, .id = "pro_scodec", @@ -2155,6 +2230,21 @@ const idclass_t profile_transcode_class = .opts = PO_ADVANCED, .group = 2 }, + { + .type = PT_STR, + .id = "src_scodec", + .name = N_("Source subtitle codec"), + .desc = N_("Transcode subtitle only if source subtitle codec match. " + "Empty or minus string will ignore source subtitle codec " + "check and continue with transcode. Separate codec names " + "with coma. If no codec match found - transcode with " + "\"copy\" codec, if match found - transcode with subtitle " + "codec defined in this profile."), + .off = offsetof(profile_transcode_t, pro_src_acodec), + .list = profile_class_src_scodec_list, + .opts = PO_ADVANCED, + .group = 2 + }, { } } }; @@ -2175,10 +2265,16 @@ profile_transcode_can_share(profile_chain_t *prch, */ if (strcmp(pro1->pro_vcodec ?: "", pro2->pro_vcodec ?: "")) return 0; + if (strcmp(pro1->pro_src_vcodec ?: "", pro2->pro_src_vcodec ?: "")) + return 0; if (strcmp(pro1->pro_acodec ?: "", pro2->pro_acodec ?: "")) return 0; + if (strcmp(pro1->pro_src_acodec ?: "", pro2->pro_src_acodec ?: "")) + return 0; if (strcmp(pro1->pro_scodec ?: "", pro2->pro_scodec ?: "")) return 0; + if (strcmp(pro1->pro_src_scodec ?: "", pro2->pro_src_scodec ?: "")) + return 0; return 1; } @@ -2190,6 +2286,7 @@ profile_transcode_work(profile_chain_t *prch, profile_sharer_t *prsh; profile_transcode_t *pro = (profile_transcode_t *)prch->prch_pro; const char *profiles[AVMEDIA_TYPE_NB] = { NULL }; + const char *src_codecs[AVMEDIA_TYPE_NB] = { NULL }; prsh = profile_sharer_find(prch); if (!prsh) @@ -2201,6 +2298,10 @@ profile_transcode_work(profile_chain_t *prch, profiles[AVMEDIA_TYPE_AUDIO] = pro->pro_acodec ?: ""; profiles[AVMEDIA_TYPE_SUBTITLE] = pro->pro_scodec ?: ""; + src_codecs[AVMEDIA_TYPE_VIDEO] = pro->pro_src_vcodec ?: ""; + src_codecs[AVMEDIA_TYPE_AUDIO] = pro->pro_src_acodec ?: ""; + src_codecs[AVMEDIA_TYPE_SUBTITLE] = pro->pro_src_scodec ?: ""; + dst = prch->prch_gh = globalheaders_create(dst); #if ENABLE_TIMESHIFT @@ -2211,7 +2312,8 @@ profile_transcode_work(profile_chain_t *prch, goto fail; if (!prsh->prsh_transcoder) { assert(!prsh->prsh_tsfix); - dst = prsh->prsh_transcoder = transcoder_create(&prsh->prsh_input, profiles); + dst = prsh->prsh_transcoder = transcoder_create(&prsh->prsh_input, + profiles, src_codecs); if (!dst) goto fail; prsh->prsh_tsfix = tsfix_create(dst); diff --git a/src/transcoding/transcode.h b/src/transcoding/transcode.h index c842ebb9c..0d528f778 100644 --- a/src/transcoding/transcode.h +++ b/src/transcoding/transcode.h @@ -28,7 +28,9 @@ /* TVHTranscoder ============================================================ */ streaming_target_t * -transcoder_create(streaming_target_t *output, const char **profiles); +transcoder_create(streaming_target_t *output, + const char **profiles, + const char **src_codecs); void transcoder_destroy(streaming_target_t *st); diff --git a/src/transcoding/transcode/internals.h b/src/transcoding/transcode/internals.h index 2c5675405..cdc4714ef 100644 --- a/src/transcoding/transcode/internals.h +++ b/src/transcoding/transcode/internals.h @@ -76,13 +76,16 @@ typedef struct tvh_transcoder_t { uint32_t id; tvh_st_t *output; TVHCodecProfile *profiles[AVMEDIA_TYPE_NB]; + char *src_codecs[AVMEDIA_TYPE_NB]; } TVHTranscoder; int tvh_transcoder_deliver(TVHTranscoder *self, th_pkt_t *pkt); TVHTranscoder * -tvh_transcoder_create(tvh_st_t *output, const char **profiles); +tvh_transcoder_create(tvh_st_t *output, + const char **profiles, + const char **src_codecs); void tvh_transcoder_destroy(TVHTranscoder *self); @@ -110,7 +113,7 @@ tvh_stream_deliver(TVHStream *self, th_pkt_t *pkt); TVHStream * tvh_stream_create(TVHTranscoder *transcoder, TVHCodecProfile *profile, - tvh_ssc_t *ssc); + tvh_ssc_t *ssc, const char *src_codecs); void tvh_stream_destroy(TVHStream *self); diff --git a/src/transcoding/transcode/module.c b/src/transcoding/transcode/module.c index e0669790f..c41d2f9ae 100644 --- a/src/transcoding/transcode/module.c +++ b/src/transcoding/transcode/module.c @@ -29,9 +29,11 @@ /* TVHTranscoder ============================================================ */ streaming_target_t * -transcoder_create(streaming_target_t *output, const char **profiles) +transcoder_create(streaming_target_t *output, + const char **profiles, + const char **src_profiles) { - return (streaming_target_t *)tvh_transcoder_create(output, profiles); + return (streaming_target_t *)tvh_transcoder_create(output, profiles, src_profiles); } diff --git a/src/transcoding/transcode/stream.c b/src/transcoding/transcode/stream.c index 7afcdbe6f..ca4f3df47 100644 --- a/src/transcoding/transcode/stream.c +++ b/src/transcoding/transcode/stream.c @@ -24,8 +24,29 @@ /* TVHStream ================================================================ */ static int -tvh_stream_is_copy(TVHCodecProfile *profile, tvh_ssc_t *ssc) +tvh_stream_is_copy(TVHCodecProfile *profile, tvh_ssc_t *ssc, + const char *src_codecs) { + const char *txtname; + char *codecs, *str, *token, *saveptr; + + /* if the source codec is in the list, do the stream copy only */ + if (src_codecs && *src_codecs != '\0' && *src_codecs != '-') { + txtname = streaming_component_type2txt(ssc->ssc_type); + if (txtname == NULL) + goto cont; + codecs = tvh_strdupa(src_codecs); + if (codecs == NULL) + goto cont; + for (str = codecs; ; str = NULL) { + token = strtok_r(str," ,|;" , &saveptr); + if (token == NULL) + break; + if (!strcasecmp(token, txtname)) + return 0; /* copy */ + } + } +cont: if (profile == tvh_codec_profile_copy) { return 1; } @@ -105,7 +126,7 @@ tvh_stream_deliver(TVHStream *self, th_pkt_t *pkt) TVHStream * tvh_stream_create(TVHTranscoder *transcoder, TVHCodecProfile *profile, - tvh_ssc_t *ssc) + tvh_ssc_t *ssc, const char *src_codecs) { TVHStream *self = NULL; int is_copy = -1; @@ -117,7 +138,7 @@ tvh_stream_create(TVHTranscoder *transcoder, TVHCodecProfile *profile, self->transcoder = transcoder; self->id = self->index = ssc->ssc_index; self->type = ssc->ssc_type; - if ((is_copy = tvh_stream_is_copy(profile, ssc)) > 0) { + if ((is_copy = tvh_stream_is_copy(profile, ssc, src_codecs)) > 0) { if (ssc->ssc_gh) { pktbuf_ref_inc(ssc->ssc_gh); } diff --git a/src/transcoding/transcode/transcoder.c b/src/transcoding/transcode/transcoder.c index 794ba1e3d..b85054c98 100644 --- a/src/transcoding/transcode/transcoder.c +++ b/src/transcoding/transcode/transcoder.c @@ -30,6 +30,9 @@ TVHCodecProfile *tvh_codec_profile_copy = &_codec_profile_copy; static enum AVMediaType ssc_get_media_type(tvh_ssc_t *ssc) { + if (ssc->ssc_disabled) { + return AVMEDIA_TYPE_UNKNOWN; + } if (SCT_ISVIDEO(ssc->ssc_type)) { return AVMEDIA_TYPE_VIDEO; } @@ -43,19 +46,6 @@ ssc_get_media_type(tvh_ssc_t *ssc) } -static TVHCodecProfile * -ssc_is_stream(tvh_ssc_t *ssc, TVHCodecProfile **profiles) -{ - enum AVMediaType media_type = AVMEDIA_TYPE_UNKNOWN; - - if (!ssc->ssc_disabled && - (media_type = ssc_get_media_type(ssc)) != AVMEDIA_TYPE_UNKNOWN) { - return profiles[media_type]; - } - return NULL; -} - - static int stream_count(tvh_ss_t *ss, TVHCodecProfile **profiles) { @@ -63,7 +53,8 @@ stream_count(tvh_ss_t *ss, TVHCodecProfile **profiles) tvh_ssc_t *ssc = NULL; for (i = 0; i < ss->ss_num_components; i++) { - if ((ssc = &ss->ss_components[i]) && ssc_is_stream(ssc, profiles)) { + if ((ssc = &ss->ss_components[i]) && + ssc_get_media_type(ssc) != AVMEDIA_TYPE_UNKNOWN) { count++; } } @@ -108,6 +99,7 @@ tvh_transcoder_start(TVHTranscoder *self, tvh_ss_t *ss_src) TVHCodecProfile *profile = NULL; TVHStream *stream = NULL; int i, j, count = stream_count(ss_src, self->profiles); + enum AVMediaType media_type; ss = calloc(1, (sizeof(tvh_ss_t) + (sizeof(tvh_ssc_t) * count))); if (ss) { @@ -120,10 +112,13 @@ tvh_transcoder_start(TVHTranscoder *self, tvh_ss_t *ss_src) ssc_src = &ss_src->ss_components[i]; ssc = &ss->ss_components[j]; if (ssc) { - if ((profile = ssc_is_stream(ssc_src, self->profiles))) { + media_type = ssc_get_media_type(ssc_src); + if (media_type != AVMEDIA_TYPE_UNKNOWN) { + profile = self->profiles[media_type]; *ssc = *ssc_src; j++; - if ((stream = tvh_stream_create(self, profile, ssc))) { + if ((stream = tvh_stream_create(self, profile, ssc, + self->src_codecs[media_type]))) { SLIST_INSERT_HEAD(&self->streams, stream, link); } else { @@ -184,7 +179,9 @@ tvh_transcoder_stream(void *opaque, tvh_sm_t *msg) static int -tvh_transcoder_setup(TVHTranscoder *self, const char **profiles) +tvh_transcoder_setup(TVHTranscoder *self, + const char **profiles, + const char **src_codecs) { const char *profile = NULL; int i; @@ -196,6 +193,8 @@ tvh_transcoder_setup(TVHTranscoder *self, const char **profiles) "failed to find codec profile: '%s'", profile); return -1; } + if (src_codecs[i]) + self->src_codecs[i] = strdup(src_codecs[i]); } } return 0; @@ -235,7 +234,9 @@ static streaming_ops_t tvh_transcoder_ops = { TVHTranscoder * -tvh_transcoder_create(tvh_st_t *output, const char **profiles) +tvh_transcoder_create(tvh_st_t *output, + const char **profiles, + const char **src_codecs) { static uint32_t id = 0; TVHTranscoder *self = NULL; @@ -250,7 +251,7 @@ tvh_transcoder_create(tvh_st_t *output, const char **profiles) self->id = ++id; } self->output = output; - if (tvh_transcoder_setup(self, profiles)) { + if (tvh_transcoder_setup(self, profiles, src_codecs)) { tvh_transcoder_destroy(self); return NULL; } @@ -263,6 +264,7 @@ void tvh_transcoder_destroy(TVHTranscoder *self) { TVHStream *stream = NULL; + int i; if (self) { tvh_transcoder_stop(self, 0); @@ -272,6 +274,8 @@ tvh_transcoder_destroy(TVHTranscoder *self) SLIST_REMOVE_HEAD(&self->streams, link); tvh_stream_destroy(stream); } + for (i = 0; i < AVMEDIA_TYPE_NB; i++) + free(self->src_codecs[i]); free(self); self = NULL; }