احصل على وتبديل ترجمات WebVTT في ExoPlayer

تحية للجميع.

قبل يومين ، كانت هناك مهمة لتبديل ترجمات WebVTT في تدفق HLS.
نشغل الفيديو باستخدام ExoPlayer ، وبدا في البداية أنه سيتعين على Google and Co. توفير حل من مربع "أخذها وفعلها". لكن الواقع لم يتزامن مع التوقعات :)

لم يؤد Googling و Habring إلى نتيجة ، وكل ذلك جاء لاختيار التطبيق التجريبي الرسمي ExoPlayer.

لان نظرًا لأن المقالة تفترض بعض الإلمام ببنية HLS ووجود بعض الخبرة في ExoPlayer ، فإننا نصل إلى هذه النقطة.

هذا ما تخبرنا به الوثائق حول تبديل التدفقات (الفيديو والصوت والترجمات). ولا تخبرنا بأي شيء تقريبًا - قم بتهيئة اللاعب باستخدام DefaultTrackSelector واستخدمه. هذا كل شيء ، حسنًا :)

يتم تخزين جميع الترجمات من أي نوع (CEA-608 ، WebVtt) مثل أي مسارات أخرى داخل DefaultTrackSelector ويجب أن تكون قادرًا على الوصول إليها. ينقسم كل شيء إلى مجموعات ومجموعات فرعية ، وباختصار ، تبدو البنية الداخلية على النحو التالي:


الآن دعنا نحاول الحصول على ترجمات من نوع WebVTT ، يجب تخزينها داخل Renderer بنوع "3" (C.TRACK_TYPE_TEXT - ثابت في Exo):

fun getVttSubtitles(): List<String> {
        val tracks = mutableListOf<String>()
        //  MappedTrackInfo
        defaultTrackSelector.currentMappedTrackInfo?.let { mappedTrackInfo ->
            val renderCount = mappedTrackInfo.rendererCount
            for (renderIndex in 0 until renderCount) {
                //    renderer'    TEXT
                val renderType = mappedTrackInfo.getRendererType(renderIndex)
                if (renderType == C.TRACK_TYPE_TEXT) {
                    val trackGroupArray = mappedTrackInfo.getTrackGroups(renderIndex)
                    //    
                    for (trackGroupArrayIndex in 0 until trackGroupArray.length) {
                        val trackGroup = trackGroupArray[trackGroupArrayIndex]
                        for (trackGroupIndex in 0 until trackGroup.length) {
                            //       TEXT_VTT
                            val format = trackGroup.getFormat(trackGroupIndex)
                            if (format.sampleMimeType == MimeTypes.TEXT_VTT) {
                                tracks += format.language.orEmpty()
                            }
                        }
                    }
                }
            }
        }

        return tracks
    }

كما ترون ، لا يتم توفير بعض الطرق المناسبة للتكرار والبحث ويجب عليك القيام بكل الحلقات باستخدام الأقلام.

لكننا بحاجة إلى معرفة ليس فقط عن القائمة نفسها ، ولكن أيضًا عن الخيارات المحددة (التي سنختارها في المستقبل). لسبب ما ، لا يمكنك الحصول على المسارات المحددة من DefaultTrackSelector ، ولكن يمكنك استخدام ExoPlayer نفسه. مخطط الحصول هو نفسه تقريبًا ، نتعمق ، ولكن هنا نتخطى الممر من خلال العارضين:

fun getSelectedVttSubtitles(): List<String> {
        val selectedLangs = mutableListOf<String>()
        val currentTrackSelections = exoPlayer.currentTrackSelections
        for (selectionIndex in 0 until currentTrackSelections.length) {
            val trackSelection = currentTrackSelections[selectionIndex]
            if (trackSelection != null) {
                //     
                val length = trackSelection.length()
                for (trackIndex in 0 until length) {
                    //      
                    val format = trackSelection.getFormat(trackIndex)
                    if (format.sampleMimeType == MimeTypes.TEXT_VTT) {
                        selectedLangs += format.language.orEmpty()
                    }
                }
            }
        }

        return selectedLangs
    }

حسنًا ، لدينا قائمة مشتركة وقائمة مختارة. كيفية الجمع والعرض على واجهة المستخدم ليس الغرض من هذه المقالة. هناك عدة طرق. علينا فقط أن نتعلم كيفية ضبط المسار.

من أجل الوضوح ، سنقوم بذلك بطريقة جبينية ، بحيث تكون جميع الدورات والمؤشرات واضحة.

تركيب مسار برمز لغته ("ru" ، "en" ، ...):

fun selectTrackByIsoCodeAndType(langCode: String) {
        defaultTrackSelector.currentMappedTrackInfo?.let { mappedTrackInfo ->
            //         
            val renderCount = mappedTrackInfo.rendererCount
            for (renderIndex in 0 until renderCount) {
                //    renderer'    TEXT
                val renderType = mappedTrackInfo.getRendererType(renderIndex)
                if (renderType == C.TRACK_TYPE_TEXT) {
                    val trackGroupArray = mappedTrackInfo.getTrackGroups(renderIndex)
                    //    
                    for (trackGroupArrayIndex in 0 until trackGroupArray.length) {
                        val trackGroup = trackGroupArray[trackGroupArrayIndex]
                        for (trackGroupIndex in 0 until trackGroup.length) {
                            val format = trackGroup.getFormat(trackGroupIndex)
                            //       
                            if (format.sampleMimeType == MimeTypes.TEXT_VTT
                                && format.language == langCode
                            ) {
                                //    
                                val currentParams = defaultTrackSelector.buildUponParameters()
                                //   ( )
                                //  
                                currentParams.clearSelectionOverride(
                                    renderIndex, trackGroupArray
                                )

                                // ,    
                                //       

                                //       
                                val override = DefaultTrackSelector.SelectionOverride(
                                    trackGroupArrayIndex, trackGroupIndex
                                )

                                //     
                                currentParams.setSelectionOverride(
                                    renderIndex,
                                    trackGroupArray,
                                    override
                                )

                                //     
                                defaultTrackSelector.setParameters(currentParams)

                                return
                            }
                        }
                    }
                }
            }
        }
    }

استنتاج


لقد قمنا بتغطية أساسيات كيفية الحصول على ترجمات WebVTT وتبديلها في ExoPlayer.
في الواقع ، يمكن أن تعمل الطريقة نفسها بسهولة مع الأنواع الأخرى من الترجمات - يكفي تحديد الأساليب بالنوع. بنفس الطريقة ، لن يكون من الصعب العمل مع المسارات الصوتية. بالطبع ، من الصعب جدًا استخدام الحل في هذا النموذج ويتطلب إحضاره إلى شكل أكثر ملاءمة.

شكرا للانتباه.

All Articles