]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
transcode: add language selection
authorJaroslav Kysela <perex@perex.cz>
Tue, 29 Aug 2017 16:08:23 +0000 (18:08 +0200)
committerJaroslav Kysela <perex@perex.cz>
Tue, 29 Aug 2017 16:08:23 +0000 (18:08 +0200)
src/transcoding/codec/internals.h
src/transcoding/codec/profile_audio_class.c
src/transcoding/transcode/transcoder.c

index 183805359d7a1e55bc3522fd887ca013084671a7..0f3faad31ec17c5f3c1a93f84e136f273402ae8a 100644 (file)
@@ -224,7 +224,9 @@ extern const codec_profile_class_t codec_profile_audio_class;
 
 typedef struct tvh_codec_profile_audio_t {
     TVHCodecProfile;
-    const char *language;
+    const char *language1;
+    const char *language2;
+    const char *language3;
     int sample_fmt;
     int sample_rate;
     int64_t channel_layout;
index 667ed6feb6d00e6aeb6e9e2967dcfd5d3b963e1b..01aa57367d823fac689b42d8fcc62f195d5b8793 100644 (file)
@@ -163,7 +163,6 @@ tvh_codec_profile_audio_open(TVHAudioCodecProfile *self, AVDictionary **opts)
 static htsmsg_t *
 codec_profile_audio_class_language_list(void *obj, const char *lang)
 {
-    // TODO: rewrite
     htsmsg_t *list = htsmsg_create_list();
     lang_code_t *lc = (lang_code_t *)lang_codes;
     static char lc_buf[128];
@@ -257,11 +256,31 @@ const codec_profile_class_t codec_profile_audio_class = {
         .ic_properties = (const property_t[]) {
             {
                 .type     = PT_STR,
-                .id       = "language",
-                .name     = N_("Language"),
+                .id       = "language1",
+                .name     = N_("1. Language"),
                 .desc     = N_("Preferred audio language."),
                 .group    = 2,
-                .off      = offsetof(TVHAudioCodecProfile, language),
+                .off      = offsetof(TVHAudioCodecProfile, language1),
+                .list     = codec_profile_audio_class_language_list,
+                .def.s    = "",
+            },
+            {
+                .type     = PT_STR,
+                .id       = "language2",
+                .name     = N_("2. Language"),
+                .desc     = N_("Preferred audio language."),
+                .group    = 2,
+                .off      = offsetof(TVHAudioCodecProfile, language2),
+                .list     = codec_profile_audio_class_language_list,
+                .def.s    = "",
+            },
+            {
+                .type     = PT_STR,
+                .id       = "language3",
+                .name     = N_("3. Language"),
+                .desc     = N_("Preferred audio language."),
+                .group    = 2,
+                .off      = offsetof(TVHAudioCodecProfile, language3),
                 .list     = codec_profile_audio_class_language_list,
                 .def.s    = "",
             },
index dea2952be52df9dea6727f62bcaab1b2b318e468..a739497da77791f03ea7714b8bcf1a0eabe1d23a 100644 (file)
@@ -19,6 +19,7 @@
 
 
 #include "internals.h"
+#include "../codec/internals.h"
 
 
 static TVHCodecProfile _codec_profile_copy = { .name = "copy" };
@@ -46,22 +47,6 @@ ssc_get_media_type(tvh_ssc_t *ssc)
 }
 
 
-static int
-stream_count(tvh_ss_t *ss, TVHCodecProfile **profiles)
-{
-    int i, count = 0;
-    tvh_ssc_t *ssc = NULL;
-
-    for (i = 0; i < ss->ss_num_components; i++) {
-        if ((ssc = &ss->ss_components[i]) &&
-             ssc_get_media_type(ssc) != AVMEDIA_TYPE_UNKNOWN) {
-            count++;
-        }
-    }
-    return count;
-}
-
-
 static TVHCodecProfile *
 _find_profile(const char *name)
 {
@@ -72,6 +57,19 @@ _find_profile(const char *name)
 }
 
 
+static int
+lang_match(const char *lang, tvh_ssc_t *ssc, int *index, int value)
+{
+    if (*index >= 0)
+        return 0;
+    if (lang && strcmp(lang, ssc->ssc_lang) == 0) {
+        *index = value;
+        return 1;
+    }
+    return 0;
+}
+
+
 /* TVHTranscoder ============================================================ */
 
 static void
@@ -93,14 +91,75 @@ tvh_transcoder_handle(TVHTranscoder *self, th_pkt_t *pkt)
 static tvh_ss_t *
 tvh_transcoder_start(TVHTranscoder *self, tvh_ss_t *ss_src)
 {
-    // TODO: rewrite, include language selection
-    tvh_ss_t *ss = NULL;
-    tvh_ssc_t *ssc_src = NULL, *ssc = NULL;
-    TVHCodecProfile *profile = NULL;
+    tvh_ss_t *ss;
+    tvh_ssc_t *ssc_src, *ssc;
+    const char *codecs;
+    TVHCodecProfile *profile;
+    TVHAudioCodecProfile *aprofile;
     TVHStream *stream = NULL;
-    int i, j, count = stream_count(ss_src, self->profiles);
+    int indexes[ss_src->ss_num_components];
+    int i, j, count;
+    int video_index = -1;
+    int audio_index = -1;
+    int audio_pindex[3] = { -1, -1, -1 };
+    int subtitle_index = -1;
     enum AVMediaType media_type;
 
+    for (i = 0; i < ss_src->ss_num_components; i++) {
+        if ((ssc = &ss_src->ss_components[i]) == NULL)
+            continue;
+        media_type = ssc_get_media_type(ssc);
+        if (media_type == AVMEDIA_TYPE_UNKNOWN)
+            continue;
+        switch (media_type) {
+        case AVMEDIA_TYPE_VIDEO:
+            if (video_index < 0)
+                video_index = i;
+            break;
+        case AVMEDIA_TYPE_AUDIO:
+            aprofile = (TVHAudioCodecProfile *)self->profiles[media_type];
+            if (lang_match(aprofile->language1, ssc, &audio_pindex[0], i) == 0 &&
+                lang_match(aprofile->language2, ssc, &audio_pindex[1], i) == 0)
+                lang_match(aprofile->language3, ssc, &audio_pindex[2], i);
+            break;
+        case AVMEDIA_TYPE_SUBTITLE:
+           if (subtitle_index < 0)
+                subtitle_index = i;
+            break;
+        default:
+            break;
+        }
+    }
+
+    /* select the preferred audio stream */
+    for (i = 0; i < ARRAY_SIZE(audio_pindex); i++) {
+        if (audio_pindex[i] >= 0) {
+            audio_index = audio_pindex[i];
+            break;
+        }
+    }
+
+    count = 0;
+    if (video_index >= 0) {
+        indexes[count++] = video_index;
+    }
+    if (audio_index >= 0) {
+        indexes[count++] = audio_index;
+    } else {
+        /* nothing is preferred, use all audio tracks */
+        for (i = 0; i < ss_src->ss_num_components; i++) {
+            if ((ssc = &ss_src->ss_components[i]) == NULL)
+                continue;
+            media_type = ssc_get_media_type(ssc);
+            if (media_type != AVMEDIA_TYPE_AUDIO)
+                continue;
+            indexes[count++] = i;
+        }
+    }
+    if (subtitle_index >= 0) {
+        indexes[count++] = subtitle_index;
+    }
+
     ss = calloc(1, (sizeof(tvh_ss_t) + (sizeof(tvh_ssc_t) * count)));
     if (ss) {
         ss->ss_refcount = 1;
@@ -108,35 +167,46 @@ tvh_transcoder_start(TVHTranscoder *self, tvh_ss_t *ss_src)
         ss->ss_pmt_pid = ss_src->ss_pmt_pid;
         service_source_info_copy(&ss->ss_si, &ss_src->ss_si);
         ss->ss_num_components = count;
-        for (i = j = 0; i < ss_src->ss_num_components && j < count; i++) {
+        for (j = 0; j < count; j++) {
+            i = indexes[j];
             ssc_src = &ss_src->ss_components[i];
             ssc = &ss->ss_components[j];
-            if (ssc) {
-                media_type = ssc_get_media_type(ssc_src);
-                if (media_type != AVMEDIA_TYPE_UNKNOWN) {
-                    profile = self->profiles[media_type];
-                    if (profile == NULL)
-                        goto fout;
-                    *ssc = *ssc_src;
-                    j++;
-                    if ((stream = tvh_stream_create(self, profile, ssc,
-                                                    self->src_codecs[media_type]))) {
-                        SLIST_INSERT_HEAD(&self->streams, stream, link);
-                    } else {
-                        goto fout;
-                    }
-                } else {
-fout:
-                    switch (ssc_src->ssc_type) {
-                    case SCT_CA:
-                    case SCT_HBBTV:
-                    case SCT_TELETEXT:
-                        break;
-                    default:
-                        tvh_ssc_log(ssc_src, LOG_INFO, "==> Filtered out", self);
-                        break;
-                    }
-                }
+            assert(ssc);
+            media_type = ssc_get_media_type(ssc_src);
+            assert(media_type != AVMEDIA_TYPE_UNKNOWN);
+            profile = self->profiles[media_type];
+            codecs = self->src_codecs[media_type];
+            if (profile == NULL) {
+                indexes[j] = -1;
+                continue;
+            }
+            *ssc = *ssc_src;
+            if ((stream = tvh_stream_create(self, profile, ssc, codecs))) {
+                tvh_ssc_log(ssc_src, LOG_INFO, "==> Using profile %s", self,
+                            tvh_codec_profile_get_name(profile));
+                SLIST_INSERT_HEAD(&self->streams, stream, link);
+            } else {
+                memset(ssc, 0, sizeof(*ssc));
+                indexes[j] = -1;
+                continue;
+            }
+        }
+        for (i = 0; i < ss_src->ss_num_components; i++) {
+            for (j = 0; j < count; j++) {
+                if (i == indexes[j])
+                    break;
+            }
+            if (j < count)
+                continue;
+            ssc_src = &ss_src->ss_components[i];
+            switch (ssc_src->ssc_type) {
+            case SCT_CA:
+            case SCT_HBBTV:
+            case SCT_TELETEXT:
+                break;
+            default:
+                tvh_ssc_log(ssc_src, LOG_INFO, "==> Filtered out", self);
+                break;
             }
         }
     }