]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
transcode: implement back the possibility to skip source codecs (from commit a334c453...
authorJaroslav Kysela <perex@perex.cz>
Mon, 28 Aug 2017 15:41:29 +0000 (17:41 +0200)
committerJaroslav Kysela <perex@perex.cz>
Mon, 28 Aug 2017 15:41:29 +0000 (17:41 +0200)
src/profile.c
src/transcoding/transcode.h
src/transcoding/transcode/internals.h
src/transcoding/transcode/module.c
src/transcoding/transcode/stream.c
src/transcoding/transcode/transcoder.c

index abc53c53dcc0bb1294cc31239c180535c18c3e01..97f764d39560c6dc3486a9ecb7236a0c91bc07c0 100644 (file)
@@ -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);
index c842ebb9c5d7569bbe5ec41255e295571d185665..0d528f7781938d3f84b6139e239f77c0d0e49a39 100644 (file)
@@ -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);
index 2c5675405ce85549356ccd4fa0bd8300df18d09d..cdc4714efc7bc5f5c9299f2fa9be18b97d84d27f 100644 (file)
@@ -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);
index e0669790f35930f58be0a242e87c14638f4979ea..c41d2f9ae7bc2adaeac5da6288c9896a9d543445 100644 (file)
 /* 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);
 }
 
 
index 7afcdbe6f08242ebcc3e52c595e4b9382f6b40ae..ca4f3df4726ccc9e680f25b21f30c24bf6dd7ef8 100644 (file)
 /* 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);
         }
index 794ba1e3d811057c8b36d69b4cec976ce7e8fa1a..b85054c98af23e6f2bbb56534fd83775988f13bf 100644 (file)
@@ -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;
     }