mirror of
https://github.com/JustinZeus/Wholphin.git
synced 2026-07-09 08:01:20 +02:00
Fix some track selection bugs (#649)
## Description Fixes track selection issues with MPV. This was especially focused on libraries that disable embedded subtitles, but also fixes issues where the audio streams are listed before video streams. Also includes test media source JSON and unit tests to verify many scenarios. ### Related issues Fixes #494
This commit is contained in:
parent
6906813bbc
commit
d2e0d527dd
7 changed files with 1278 additions and 28 deletions
9
app/src/test/java/android/text/TextUtils.java
Normal file
9
app/src/test/java/android/text/TextUtils.java
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
package android.text;
|
||||
|
||||
// Mocks static class for non-instrumented unit tests
|
||||
|
||||
public class TextUtils {
|
||||
public static boolean isEmpty(CharSequence str) {
|
||||
return str == null || str.length() == 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,591 @@
|
|||
package com.github.damontecres.wholphin.test
|
||||
|
||||
import androidx.media3.common.C
|
||||
import androidx.media3.common.Format
|
||||
import androidx.media3.common.TrackGroup
|
||||
import androidx.media3.common.TrackSelectionParameters
|
||||
import androidx.media3.common.Tracks
|
||||
import com.github.damontecres.wholphin.data.model.TrackIndex
|
||||
import com.github.damontecres.wholphin.preferences.PlayerBackend
|
||||
import com.github.damontecres.wholphin.ui.playback.TrackSelectionUtils
|
||||
import kotlinx.serialization.json.Json
|
||||
import org.jellyfin.sdk.model.api.MediaSourceInfo
|
||||
import org.junit.Assert
|
||||
import org.junit.Test
|
||||
import java.nio.file.Paths
|
||||
import kotlin.io.path.readText
|
||||
|
||||
class TestTrackSelection {
|
||||
/**
|
||||
* Builds the tracks for the `embedded_subs.json` for the given backend
|
||||
*
|
||||
* Note: This is manual based on observation & code review of the playback for that file
|
||||
*/
|
||||
private fun buildEmbeddedTracks(backend: PlayerBackend): Tracks {
|
||||
val formats =
|
||||
if (backend == PlayerBackend.MPV) {
|
||||
val video =
|
||||
Format
|
||||
.Builder()
|
||||
.setId("0:1")
|
||||
.setSampleMimeType("video/default")
|
||||
.build()
|
||||
val audios =
|
||||
(1..3).map {
|
||||
Format
|
||||
.Builder()
|
||||
.setId("$it:$it")
|
||||
.setSampleMimeType("audio/default")
|
||||
.build()
|
||||
}
|
||||
val subtitles =
|
||||
(1..3).map {
|
||||
Format
|
||||
.Builder()
|
||||
.setId("${it + 3}:$it")
|
||||
.setSampleMimeType("text/default")
|
||||
.build()
|
||||
}
|
||||
(listOf(video) + audios + subtitles)
|
||||
} else {
|
||||
val video =
|
||||
Format
|
||||
.Builder()
|
||||
.setId("1")
|
||||
.setSampleMimeType("video/default")
|
||||
.build()
|
||||
val audios =
|
||||
(2..4).map {
|
||||
Format
|
||||
.Builder()
|
||||
.setId("$it")
|
||||
.setSampleMimeType("audio/default")
|
||||
.build()
|
||||
}
|
||||
val subtitles =
|
||||
(5..7).map {
|
||||
Format
|
||||
.Builder()
|
||||
.setId("$it")
|
||||
.setSampleMimeType("text/default")
|
||||
.build()
|
||||
}
|
||||
(listOf(video) + audios + subtitles)
|
||||
}
|
||||
val groups =
|
||||
formats
|
||||
.map { TrackGroup(it) }
|
||||
.map { Tracks.Group(it, false, intArrayOf(C.FORMAT_HANDLED), booleanArrayOf(false)) }
|
||||
return Tracks(groups)
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the tracks for the `no_embedded_subs.json` for the given backend
|
||||
*
|
||||
* Note: This is manual based on observation & code review of the playback for that file
|
||||
*/
|
||||
private fun buildNoEmbeddedTracks(backend: PlayerBackend): Tracks {
|
||||
val formats =
|
||||
if (backend == PlayerBackend.MPV) {
|
||||
val video =
|
||||
Format
|
||||
.Builder()
|
||||
.setId("0:1")
|
||||
.setSampleMimeType("video/default")
|
||||
.build()
|
||||
val audios =
|
||||
(1..3).map {
|
||||
Format
|
||||
.Builder()
|
||||
.setId("$it:$it")
|
||||
.setSampleMimeType("audio/default")
|
||||
.build()
|
||||
}
|
||||
val subtitles =
|
||||
(1..3).map {
|
||||
Format
|
||||
.Builder()
|
||||
.setId("${it + 3}:$it")
|
||||
.setSampleMimeType("text/default")
|
||||
.build()
|
||||
} +
|
||||
listOf(
|
||||
Format
|
||||
.Builder()
|
||||
.setId("7:e:4")
|
||||
.setSampleMimeType("text/default")
|
||||
.build(),
|
||||
)
|
||||
(listOf(video) + audios + subtitles)
|
||||
} else {
|
||||
// ExoPlayer
|
||||
val video =
|
||||
Format
|
||||
.Builder()
|
||||
.setId("0:1")
|
||||
.setSampleMimeType("video/default")
|
||||
.build()
|
||||
val audios =
|
||||
(2..4).map {
|
||||
Format
|
||||
.Builder()
|
||||
.setId("0:$it")
|
||||
.setSampleMimeType("audio/default")
|
||||
.build()
|
||||
}
|
||||
val subtitles =
|
||||
(5..7).map {
|
||||
Format
|
||||
.Builder()
|
||||
.setId("0:$it")
|
||||
.setSampleMimeType("text/default")
|
||||
.build()
|
||||
} +
|
||||
listOf(
|
||||
Format
|
||||
.Builder()
|
||||
.setId("1:e:0")
|
||||
.setSampleMimeType("text/default")
|
||||
.build(),
|
||||
)
|
||||
(listOf(video) + audios + subtitles)
|
||||
}
|
||||
val groups =
|
||||
formats
|
||||
.map { TrackGroup(it) }
|
||||
.map { Tracks.Group(it, false, intArrayOf(C.FORMAT_HANDLED), booleanArrayOf(false)) }
|
||||
return Tracks(groups)
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the tracks for the `external_subs.json` for the given backend.
|
||||
*
|
||||
* Must supply the desired subtitle index because ExoPlayer uses it.
|
||||
*
|
||||
* Note: This is manual based on observation & code review of the playback for that file
|
||||
*/
|
||||
private fun buildExternalTracks(
|
||||
backend: PlayerBackend,
|
||||
selectedIndex: Int,
|
||||
): Tracks {
|
||||
val formats =
|
||||
if (backend == PlayerBackend.MPV) {
|
||||
val video =
|
||||
Format
|
||||
.Builder()
|
||||
.setId("1:1")
|
||||
.setSampleMimeType("video/default")
|
||||
.build()
|
||||
val audios =
|
||||
listOf(
|
||||
Format
|
||||
.Builder()
|
||||
.setId("0:1")
|
||||
.setSampleMimeType("audio/default")
|
||||
.build(),
|
||||
)
|
||||
val subtitles =
|
||||
listOf(
|
||||
Format
|
||||
.Builder()
|
||||
.setId("2:1")
|
||||
.setSampleMimeType("text/default")
|
||||
.build(),
|
||||
Format
|
||||
.Builder()
|
||||
.setId("3:e:2")
|
||||
.setSampleMimeType("text/default")
|
||||
.build(),
|
||||
)
|
||||
(listOf(video) + audios + subtitles)
|
||||
} else {
|
||||
val video =
|
||||
Format
|
||||
.Builder()
|
||||
.setId("0:2")
|
||||
.setSampleMimeType("video/default")
|
||||
.build()
|
||||
val audios =
|
||||
listOf(
|
||||
Format
|
||||
.Builder()
|
||||
.setId("0:1")
|
||||
.setSampleMimeType("audio/default")
|
||||
.build(),
|
||||
)
|
||||
val subtitles =
|
||||
listOf(
|
||||
Format
|
||||
.Builder()
|
||||
.setId("0:3") // Embedded
|
||||
.setSampleMimeType("text/default")
|
||||
.build(),
|
||||
Format
|
||||
.Builder()
|
||||
.setId("1:e:$selectedIndex") // External
|
||||
.setSampleMimeType("text/default")
|
||||
.build(),
|
||||
)
|
||||
(listOf(video) + audios + subtitles)
|
||||
}
|
||||
val groups =
|
||||
formats
|
||||
.map { TrackGroup(it) }
|
||||
.map { Tracks.Group(it, false, intArrayOf(C.FORMAT_HANDLED), booleanArrayOf(false)) }
|
||||
return Tracks(groups)
|
||||
}
|
||||
|
||||
private fun TrackSelectionParameters.getAudioOverride(): Format? {
|
||||
this.overrides.forEach { (trackGroup, trackSelectionOverride) ->
|
||||
if (trackGroup.type == C.TRACK_TYPE_AUDIO) {
|
||||
return trackGroup.getFormat(trackSelectionOverride.trackIndices.first())
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private fun TrackSelectionParameters.getSubtitleOverride(): Format? {
|
||||
this.overrides.forEach { (trackGroup, trackSelectionOverride) ->
|
||||
if (trackGroup.type == C.TRACK_TYPE_TEXT) {
|
||||
return trackGroup.getFormat(trackSelectionOverride.trackIndices.first())
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test MPV embedded`() {
|
||||
val resource = javaClass.classLoader?.getResource("embedded_subs.json")
|
||||
Assert.assertNotNull(resource)
|
||||
val fileContents = Paths.get(resource!!.toURI()).readText()
|
||||
val source = Json.decodeFromString<MediaSourceInfo>(fileContents)
|
||||
val tracks = buildEmbeddedTracks(PlayerBackend.MPV)
|
||||
Assert.assertEquals(7, source.mediaStreams?.size)
|
||||
|
||||
val trackSelectionParameters = TrackSelectionParameters.Builder().build()
|
||||
|
||||
TrackSelectionUtils
|
||||
.createTrackSelections(
|
||||
trackSelectionParams = trackSelectionParameters,
|
||||
tracks = tracks,
|
||||
playerBackend = PlayerBackend.MPV,
|
||||
supportsDirectPlay = true,
|
||||
audioIndex = 1,
|
||||
subtitleIndex = 4,
|
||||
source = source,
|
||||
).also { result ->
|
||||
Assert.assertTrue(result.bothSelected)
|
||||
Assert.assertEquals("1:1", result.trackSelectionParameters.getAudioOverride()?.id)
|
||||
Assert.assertEquals("4:1", result.trackSelectionParameters.getSubtitleOverride()?.id)
|
||||
}
|
||||
|
||||
TrackSelectionUtils
|
||||
.createTrackSelections(
|
||||
trackSelectionParams = trackSelectionParameters,
|
||||
tracks = tracks,
|
||||
playerBackend = PlayerBackend.MPV,
|
||||
supportsDirectPlay = true,
|
||||
audioIndex = 2,
|
||||
subtitleIndex = 4,
|
||||
source = source,
|
||||
).also { result ->
|
||||
Assert.assertTrue(result.bothSelected)
|
||||
Assert.assertEquals("2:2", result.trackSelectionParameters.getAudioOverride()?.id)
|
||||
Assert.assertEquals("4:1", result.trackSelectionParameters.getSubtitleOverride()?.id)
|
||||
}
|
||||
|
||||
TrackSelectionUtils
|
||||
.createTrackSelections(
|
||||
trackSelectionParams = trackSelectionParameters,
|
||||
tracks = tracks,
|
||||
playerBackend = PlayerBackend.MPV,
|
||||
supportsDirectPlay = true,
|
||||
audioIndex = 1,
|
||||
subtitleIndex = TrackIndex.DISABLED,
|
||||
source = source,
|
||||
).also { result ->
|
||||
Assert.assertTrue(result.bothSelected)
|
||||
Assert.assertEquals("1:1", result.trackSelectionParameters.getAudioOverride()?.id)
|
||||
Assert.assertEquals(null, result.trackSelectionParameters.getSubtitleOverride()?.id)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test ExoPlayer embedded`() {
|
||||
val resource = javaClass.classLoader?.getResource("embedded_subs.json")
|
||||
Assert.assertNotNull(resource)
|
||||
val fileContents = Paths.get(resource!!.toURI()).readText()
|
||||
val source = Json.decodeFromString<MediaSourceInfo>(fileContents)
|
||||
val tracks = buildEmbeddedTracks(PlayerBackend.EXO_PLAYER)
|
||||
Assert.assertEquals(7, source.mediaStreams?.size)
|
||||
|
||||
val trackSelectionParameters = TrackSelectionParameters.Builder().build()
|
||||
|
||||
TrackSelectionUtils
|
||||
.createTrackSelections(
|
||||
trackSelectionParams = trackSelectionParameters,
|
||||
tracks = tracks,
|
||||
playerBackend = PlayerBackend.EXO_PLAYER,
|
||||
supportsDirectPlay = true,
|
||||
audioIndex = 1,
|
||||
subtitleIndex = 4,
|
||||
source = source,
|
||||
).also { result ->
|
||||
Assert.assertTrue(result.bothSelected)
|
||||
Assert.assertEquals("2", result.trackSelectionParameters.getAudioOverride()?.id)
|
||||
Assert.assertEquals("5", result.trackSelectionParameters.getSubtitleOverride()?.id)
|
||||
}
|
||||
|
||||
TrackSelectionUtils
|
||||
.createTrackSelections(
|
||||
trackSelectionParams = trackSelectionParameters,
|
||||
tracks = tracks,
|
||||
playerBackend = PlayerBackend.EXO_PLAYER,
|
||||
supportsDirectPlay = true,
|
||||
audioIndex = 2,
|
||||
subtitleIndex = 4,
|
||||
source = source,
|
||||
).also { result ->
|
||||
Assert.assertTrue(result.bothSelected)
|
||||
Assert.assertEquals("3", result.trackSelectionParameters.getAudioOverride()?.id)
|
||||
Assert.assertEquals("5", result.trackSelectionParameters.getSubtitleOverride()?.id)
|
||||
}
|
||||
|
||||
TrackSelectionUtils
|
||||
.createTrackSelections(
|
||||
trackSelectionParams = trackSelectionParameters,
|
||||
tracks = tracks,
|
||||
playerBackend = PlayerBackend.EXO_PLAYER,
|
||||
supportsDirectPlay = true,
|
||||
audioIndex = 2,
|
||||
subtitleIndex = 6,
|
||||
source = source,
|
||||
).also { result ->
|
||||
Assert.assertTrue(result.bothSelected)
|
||||
Assert.assertEquals("3", result.trackSelectionParameters.getAudioOverride()?.id)
|
||||
Assert.assertEquals("7", result.trackSelectionParameters.getSubtitleOverride()?.id)
|
||||
}
|
||||
|
||||
TrackSelectionUtils
|
||||
.createTrackSelections(
|
||||
trackSelectionParams = trackSelectionParameters,
|
||||
tracks = tracks,
|
||||
playerBackend = PlayerBackend.EXO_PLAYER,
|
||||
supportsDirectPlay = true,
|
||||
audioIndex = 1,
|
||||
subtitleIndex = TrackIndex.DISABLED,
|
||||
source = source,
|
||||
).also { result ->
|
||||
Assert.assertTrue(result.bothSelected)
|
||||
Assert.assertEquals("2", result.trackSelectionParameters.getAudioOverride()?.id)
|
||||
Assert.assertEquals(null, result.trackSelectionParameters.getSubtitleOverride()?.id)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test MPV no embedded`() {
|
||||
val resource = javaClass.classLoader?.getResource("no_embedded_subs.json")
|
||||
Assert.assertNotNull(resource)
|
||||
val fileContents = Paths.get(resource!!.toURI()).readText()
|
||||
val source = Json.decodeFromString<MediaSourceInfo>(fileContents)
|
||||
val tracks = buildNoEmbeddedTracks(PlayerBackend.MPV)
|
||||
Assert.assertEquals(5, source.mediaStreams?.size)
|
||||
|
||||
val trackSelectionParameters = TrackSelectionParameters.Builder().build()
|
||||
|
||||
TrackSelectionUtils
|
||||
.createTrackSelections(
|
||||
trackSelectionParams = trackSelectionParameters,
|
||||
tracks = tracks,
|
||||
playerBackend = PlayerBackend.MPV,
|
||||
supportsDirectPlay = true,
|
||||
audioIndex = 2,
|
||||
subtitleIndex = 0,
|
||||
source = source,
|
||||
).also { result ->
|
||||
Assert.assertTrue(result.bothSelected)
|
||||
Assert.assertEquals("1:1", result.trackSelectionParameters.getAudioOverride()?.id)
|
||||
Assert.assertEquals("7:e:4", result.trackSelectionParameters.getSubtitleOverride()?.id)
|
||||
}
|
||||
|
||||
TrackSelectionUtils
|
||||
.createTrackSelections(
|
||||
trackSelectionParams = trackSelectionParameters,
|
||||
tracks = tracks,
|
||||
playerBackend = PlayerBackend.MPV,
|
||||
supportsDirectPlay = true,
|
||||
audioIndex = 3,
|
||||
subtitleIndex = 0,
|
||||
source = source,
|
||||
).also { result ->
|
||||
Assert.assertTrue(result.bothSelected)
|
||||
Assert.assertEquals("2:2", result.trackSelectionParameters.getAudioOverride()?.id)
|
||||
Assert.assertEquals("7:e:4", result.trackSelectionParameters.getSubtitleOverride()?.id)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test ExoPlayer no embedded`() {
|
||||
val resource = javaClass.classLoader?.getResource("no_embedded_subs.json")
|
||||
Assert.assertNotNull(resource)
|
||||
val fileContents = Paths.get(resource!!.toURI()).readText()
|
||||
val source = Json.decodeFromString<MediaSourceInfo>(fileContents)
|
||||
val tracks = buildNoEmbeddedTracks(PlayerBackend.EXO_PLAYER)
|
||||
Assert.assertEquals(5, source.mediaStreams?.size)
|
||||
|
||||
val trackSelectionParameters = TrackSelectionParameters.Builder().build()
|
||||
|
||||
TrackSelectionUtils
|
||||
.createTrackSelections(
|
||||
trackSelectionParams = trackSelectionParameters,
|
||||
tracks = tracks,
|
||||
playerBackend = PlayerBackend.EXO_PLAYER,
|
||||
supportsDirectPlay = true,
|
||||
audioIndex = 2,
|
||||
subtitleIndex = 0,
|
||||
source = source,
|
||||
).also { result ->
|
||||
Assert.assertTrue(result.bothSelected)
|
||||
Assert.assertEquals("0:2", result.trackSelectionParameters.getAudioOverride()?.id)
|
||||
Assert.assertEquals("1:e:0", result.trackSelectionParameters.getSubtitleOverride()?.id)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test MPV external`() {
|
||||
val resource = javaClass.classLoader?.getResource("external_subs.json")
|
||||
Assert.assertNotNull(resource)
|
||||
val fileContents = Paths.get(resource!!.toURI()).readText()
|
||||
val source = Json.decodeFromString<MediaSourceInfo>(fileContents)
|
||||
val tracks = buildExternalTracks(PlayerBackend.MPV, 0)
|
||||
Assert.assertEquals(6, source.mediaStreams?.size)
|
||||
|
||||
val trackSelectionParameters = TrackSelectionParameters.Builder().build()
|
||||
|
||||
TrackSelectionUtils
|
||||
.createTrackSelections(
|
||||
trackSelectionParams = trackSelectionParameters,
|
||||
tracks = tracks,
|
||||
playerBackend = PlayerBackend.MPV,
|
||||
supportsDirectPlay = true,
|
||||
audioIndex = 3,
|
||||
subtitleIndex = 0,
|
||||
source = source,
|
||||
).also { result ->
|
||||
Assert.assertTrue(result.audioSelected)
|
||||
Assert.assertTrue(result.subtitleSelected)
|
||||
Assert.assertEquals("0:1", result.trackSelectionParameters.getAudioOverride()?.id)
|
||||
Assert.assertEquals("3:e:2", result.trackSelectionParameters.getSubtitleOverride()?.id)
|
||||
}
|
||||
|
||||
// Select embedded subtitles
|
||||
TrackSelectionUtils
|
||||
.createTrackSelections(
|
||||
trackSelectionParams = trackSelectionParameters,
|
||||
tracks = tracks,
|
||||
playerBackend = PlayerBackend.MPV,
|
||||
supportsDirectPlay = true,
|
||||
audioIndex = 3,
|
||||
subtitleIndex = 5,
|
||||
source = source,
|
||||
).also { result ->
|
||||
Assert.assertTrue(result.audioSelected)
|
||||
Assert.assertTrue(result.subtitleSelected)
|
||||
Assert.assertEquals(
|
||||
"0:1",
|
||||
result.trackSelectionParameters.getAudioOverride()?.id,
|
||||
)
|
||||
Assert.assertEquals(
|
||||
"2:1",
|
||||
result.trackSelectionParameters.getSubtitleOverride()?.id,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test ExoPlayer external`() {
|
||||
val resource = javaClass.classLoader?.getResource("external_subs.json")
|
||||
Assert.assertNotNull(resource)
|
||||
val fileContents = Paths.get(resource!!.toURI()).readText()
|
||||
val source = Json.decodeFromString<MediaSourceInfo>(fileContents)
|
||||
|
||||
buildExternalTracks(PlayerBackend.EXO_PLAYER, 0).also { tracks ->
|
||||
Assert.assertEquals(6, source.mediaStreams?.size)
|
||||
|
||||
val trackSelectionParameters = TrackSelectionParameters.Builder().build()
|
||||
|
||||
TrackSelectionUtils
|
||||
.createTrackSelections(
|
||||
trackSelectionParams = trackSelectionParameters,
|
||||
tracks = tracks,
|
||||
playerBackend = PlayerBackend.EXO_PLAYER,
|
||||
supportsDirectPlay = true,
|
||||
audioIndex = 3,
|
||||
subtitleIndex = 0,
|
||||
source = source,
|
||||
).also { result ->
|
||||
Assert.assertTrue(result.audioSelected)
|
||||
Assert.assertTrue(result.subtitleSelected)
|
||||
Assert.assertEquals(
|
||||
"0:1",
|
||||
result.trackSelectionParameters.getAudioOverride()?.id,
|
||||
)
|
||||
Assert.assertEquals(
|
||||
"1:e:0",
|
||||
result.trackSelectionParameters.getSubtitleOverride()?.id,
|
||||
)
|
||||
}
|
||||
|
||||
// Select embedded subtitles
|
||||
TrackSelectionUtils
|
||||
.createTrackSelections(
|
||||
trackSelectionParams = trackSelectionParameters,
|
||||
tracks = tracks,
|
||||
playerBackend = PlayerBackend.EXO_PLAYER,
|
||||
supportsDirectPlay = true,
|
||||
audioIndex = 3,
|
||||
subtitleIndex = 5,
|
||||
source = source,
|
||||
).also { result ->
|
||||
Assert.assertTrue(result.audioSelected)
|
||||
Assert.assertTrue(result.subtitleSelected)
|
||||
Assert.assertEquals(
|
||||
"0:1",
|
||||
result.trackSelectionParameters.getAudioOverride()?.id,
|
||||
)
|
||||
Assert.assertEquals(
|
||||
"0:3",
|
||||
result.trackSelectionParameters.getSubtitleOverride()?.id,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
buildExternalTracks(PlayerBackend.EXO_PLAYER, 2).also { tracks ->
|
||||
Assert.assertEquals(6, source.mediaStreams?.size)
|
||||
|
||||
val trackSelectionParameters = TrackSelectionParameters.Builder().build()
|
||||
|
||||
TrackSelectionUtils
|
||||
.createTrackSelections(
|
||||
trackSelectionParams = trackSelectionParameters,
|
||||
tracks = tracks,
|
||||
playerBackend = PlayerBackend.EXO_PLAYER,
|
||||
supportsDirectPlay = true,
|
||||
audioIndex = 3,
|
||||
subtitleIndex = 2,
|
||||
source = source,
|
||||
).also { result ->
|
||||
Assert.assertTrue(result.audioSelected)
|
||||
Assert.assertTrue(result.subtitleSelected)
|
||||
Assert.assertEquals(
|
||||
"0:1",
|
||||
result.trackSelectionParameters.getAudioOverride()?.id,
|
||||
)
|
||||
Assert.assertEquals(
|
||||
"1:e:2",
|
||||
result.trackSelectionParameters.getSubtitleOverride()?.id,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
235
app/src/test/resources/embedded_subs.json
Normal file
235
app/src/test/resources/embedded_subs.json
Normal file
|
|
@ -0,0 +1,235 @@
|
|||
{
|
||||
"Protocol": "File",
|
||||
"Id": "",
|
||||
"Path": "",
|
||||
"Type": "Default",
|
||||
"Container": "mkv",
|
||||
"Size": 651217902,
|
||||
"Name": "",
|
||||
"IsRemote": false,
|
||||
"ETag": "",
|
||||
"RunTimeTicks": 14919360000,
|
||||
"ReadAtNativeFramerate": false,
|
||||
"IgnoreDts": false,
|
||||
"IgnoreIndex": false,
|
||||
"GenPtsInput": false,
|
||||
"SupportsTranscoding": true,
|
||||
"SupportsDirectStream": true,
|
||||
"SupportsDirectPlay": true,
|
||||
"IsInfiniteStream": false,
|
||||
"UseMostCompatibleTranscodingProfile": false,
|
||||
"RequiresOpening": false,
|
||||
"RequiresClosing": false,
|
||||
"RequiresLooping": false,
|
||||
"SupportsProbing": true,
|
||||
"VideoType": "VideoFile",
|
||||
"MediaStreams": [
|
||||
{
|
||||
"Codec": "hevc",
|
||||
"Language": "jpn",
|
||||
"TimeBase": "1/1000",
|
||||
"Title": "",
|
||||
"VideoRange": "SDR",
|
||||
"VideoRangeType": "SDR",
|
||||
"AudioSpatialFormat": "None",
|
||||
"DisplayTitle": "1080p - HEVC - SDR",
|
||||
"IsInterlaced": false,
|
||||
"IsAVC": false,
|
||||
"BitRate": 3491934,
|
||||
"BitDepth": 10,
|
||||
"RefFrames": 1,
|
||||
"IsDefault": true,
|
||||
"IsForced": false,
|
||||
"IsHearingImpaired": false,
|
||||
"Height": 1080,
|
||||
"Width": 1448,
|
||||
"AverageFrameRate": 23.809525,
|
||||
"RealFrameRate": 23.809525,
|
||||
"ReferenceFrameRate": 23.809525,
|
||||
"Profile": "Main 10",
|
||||
"Type": "Video",
|
||||
"AspectRatio": "4:3",
|
||||
"Index": 0,
|
||||
"IsExternal": false,
|
||||
"IsTextSubtitleStream": false,
|
||||
"SupportsExternalStream": false,
|
||||
"PixelFormat": "yuv420p10le",
|
||||
"Level": 120,
|
||||
"IsAnamorphic": false
|
||||
},
|
||||
{
|
||||
"Codec": "opus",
|
||||
"Language": "jpn",
|
||||
"TimeBase": "1/1000",
|
||||
"Title": "JAP Stereo (Opus 112Kbps)",
|
||||
"VideoRange": "Unknown",
|
||||
"VideoRangeType": "Unknown",
|
||||
"AudioSpatialFormat": "None",
|
||||
"LocalizedDefault": "Default",
|
||||
"LocalizedExternal": "External",
|
||||
"DisplayTitle": "JAP Stereo (Opus 112Kbps) - Japanese",
|
||||
"IsInterlaced": false,
|
||||
"IsAVC": false,
|
||||
"ChannelLayout": "stereo",
|
||||
"BitRate": 101618,
|
||||
"Channels": 2,
|
||||
"SampleRate": 48000,
|
||||
"IsDefault": false,
|
||||
"IsForced": false,
|
||||
"IsHearingImpaired": false,
|
||||
"Type": "Audio",
|
||||
"Index": 1,
|
||||
"IsExternal": false,
|
||||
"IsTextSubtitleStream": false,
|
||||
"SupportsExternalStream": false,
|
||||
"Level": 0
|
||||
},
|
||||
{
|
||||
"Codec": "aac",
|
||||
"Language": "por",
|
||||
"TimeBase": "1/1000",
|
||||
"Title": "",
|
||||
"VideoRange": "Unknown",
|
||||
"VideoRangeType": "Unknown",
|
||||
"AudioSpatialFormat": "None",
|
||||
"LocalizedDefault": "Default",
|
||||
"LocalizedExternal": "External",
|
||||
"DisplayTitle": "Portuguese - AAC - Stereo",
|
||||
"IsInterlaced": false,
|
||||
"IsAVC": false,
|
||||
"ChannelLayout": "stereo",
|
||||
"BitRate": 249225,
|
||||
"Channels": 2,
|
||||
"SampleRate": 44100,
|
||||
"IsDefault": false,
|
||||
"IsForced": false,
|
||||
"IsHearingImpaired": false,
|
||||
"Profile": "LC",
|
||||
"Type": "Audio",
|
||||
"Index": 2,
|
||||
"IsExternal": false,
|
||||
"IsTextSubtitleStream": false,
|
||||
"SupportsExternalStream": false,
|
||||
"Level": 0
|
||||
},
|
||||
{
|
||||
"Codec": "eac3",
|
||||
"Language": "por",
|
||||
"TimeBase": "1/1000",
|
||||
"Title": "",
|
||||
"VideoRange": "Unknown",
|
||||
"VideoRangeType": "Unknown",
|
||||
"AudioSpatialFormat": "None",
|
||||
"LocalizedDefault": "Default",
|
||||
"LocalizedExternal": "External",
|
||||
"DisplayTitle": "Portuguese - Dolby Digital+ - 5.1",
|
||||
"IsInterlaced": false,
|
||||
"IsAVC": false,
|
||||
"ChannelLayout": "5.1",
|
||||
"BitRate": 640000,
|
||||
"Channels": 6,
|
||||
"SampleRate": 48000,
|
||||
"IsDefault": false,
|
||||
"IsForced": false,
|
||||
"IsHearingImpaired": false,
|
||||
"Type": "Audio",
|
||||
"Index": 3,
|
||||
"IsExternal": false,
|
||||
"IsTextSubtitleStream": false,
|
||||
"SupportsExternalStream": false,
|
||||
"Level": 0
|
||||
},
|
||||
{
|
||||
"Codec": "ass",
|
||||
"Language": "por",
|
||||
"TimeBase": "1/1000",
|
||||
"Title": "ptBR",
|
||||
"VideoRange": "Unknown",
|
||||
"VideoRangeType": "Unknown",
|
||||
"AudioSpatialFormat": "None",
|
||||
"LocalizedUndefined": "Undefined",
|
||||
"LocalizedDefault": "Default",
|
||||
"LocalizedForced": "Forced",
|
||||
"LocalizedExternal": "External",
|
||||
"LocalizedHearingImpaired": "Hearing Impaired",
|
||||
"DisplayTitle": "ptBR - Portuguese - Default - ASS",
|
||||
"IsInterlaced": false,
|
||||
"IsAVC": false,
|
||||
"IsDefault": true,
|
||||
"IsForced": false,
|
||||
"IsHearingImpaired": false,
|
||||
"Height": 0,
|
||||
"Width": 0,
|
||||
"Type": "Subtitle",
|
||||
"Index": 4,
|
||||
"IsExternal": false,
|
||||
"IsTextSubtitleStream": true,
|
||||
"SupportsExternalStream": true,
|
||||
"Level": 0
|
||||
},
|
||||
{
|
||||
"Codec": "ass",
|
||||
"Language": "por",
|
||||
"TimeBase": "1/1000",
|
||||
"Title": "ptBR FORCED",
|
||||
"VideoRange": "Unknown",
|
||||
"VideoRangeType": "Unknown",
|
||||
"AudioSpatialFormat": "None",
|
||||
"LocalizedUndefined": "Undefined",
|
||||
"LocalizedDefault": "Default",
|
||||
"LocalizedForced": "Forced",
|
||||
"LocalizedExternal": "External",
|
||||
"LocalizedHearingImpaired": "Hearing Impaired",
|
||||
"DisplayTitle": "ptBR FORCED - Portuguese - ASS",
|
||||
"IsInterlaced": false,
|
||||
"IsAVC": false,
|
||||
"IsDefault": false,
|
||||
"IsForced": true,
|
||||
"IsHearingImpaired": false,
|
||||
"Height": 0,
|
||||
"Width": 0,
|
||||
"Type": "Subtitle",
|
||||
"Index": 5,
|
||||
"IsExternal": false,
|
||||
"IsTextSubtitleStream": true,
|
||||
"SupportsExternalStream": true,
|
||||
"Level": 0
|
||||
},
|
||||
{
|
||||
"Codec": "ass",
|
||||
"Language": "eng",
|
||||
"TimeBase": "1/1000",
|
||||
"Title": "enUS",
|
||||
"VideoRange": "Unknown",
|
||||
"VideoRangeType": "Unknown",
|
||||
"AudioSpatialFormat": "None",
|
||||
"LocalizedUndefined": "Undefined",
|
||||
"LocalizedDefault": "Default",
|
||||
"LocalizedForced": "Forced",
|
||||
"LocalizedExternal": "External",
|
||||
"LocalizedHearingImpaired": "Hearing Impaired",
|
||||
"DisplayTitle": "enUS - English - ASS",
|
||||
"IsInterlaced": false,
|
||||
"IsAVC": false,
|
||||
"IsDefault": false,
|
||||
"IsForced": false,
|
||||
"IsHearingImpaired": false,
|
||||
"Height": 0,
|
||||
"Width": 0,
|
||||
"Type": "Subtitle",
|
||||
"Index": 6,
|
||||
"IsExternal": false,
|
||||
"IsTextSubtitleStream": true,
|
||||
"SupportsExternalStream": true,
|
||||
"Level": 0
|
||||
}
|
||||
],
|
||||
"MediaAttachments": [],
|
||||
"Formats": [],
|
||||
"Bitrate": 4482777,
|
||||
"RequiredHttpHeaders": {},
|
||||
"TranscodingSubProtocol": "http",
|
||||
"DefaultAudioStreamIndex": 1,
|
||||
"DefaultSubtitleStreamIndex": 6,
|
||||
"HasSegments": true
|
||||
}
|
||||
208
app/src/test/resources/external_subs.json
Normal file
208
app/src/test/resources/external_subs.json
Normal file
|
|
@ -0,0 +1,208 @@
|
|||
{
|
||||
"Protocol": "File",
|
||||
"Id": "",
|
||||
"Path": "",
|
||||
"Type": "Default",
|
||||
"Container": "mkv",
|
||||
"Size": 2147179830,
|
||||
"Name": "",
|
||||
"IsRemote": false,
|
||||
"ETag": "",
|
||||
"RunTimeTicks": 12793200000,
|
||||
"ReadAtNativeFramerate": false,
|
||||
"IgnoreDts": false,
|
||||
"IgnoreIndex": false,
|
||||
"GenPtsInput": false,
|
||||
"SupportsTranscoding": true,
|
||||
"SupportsDirectStream": true,
|
||||
"SupportsDirectPlay": true,
|
||||
"IsInfiniteStream": false,
|
||||
"UseMostCompatibleTranscodingProfile": false,
|
||||
"RequiresOpening": false,
|
||||
"RequiresClosing": false,
|
||||
"RequiresLooping": false,
|
||||
"SupportsProbing": true,
|
||||
"VideoType": "VideoFile",
|
||||
"MediaStreams": [
|
||||
{
|
||||
"Codec": "subrip",
|
||||
"Language": "eng",
|
||||
"TimeBase": "1/1000",
|
||||
"VideoRange": "Unknown",
|
||||
"VideoRangeType": "Unknown",
|
||||
"AudioSpatialFormat": "None",
|
||||
"LocalizedUndefined": "Undefined",
|
||||
"LocalizedDefault": "Default",
|
||||
"LocalizedForced": "Forced",
|
||||
"LocalizedExternal": "External",
|
||||
"LocalizedHearingImpaired": "Hearing Impaired",
|
||||
"DisplayTitle": "English - SUBRIP - External",
|
||||
"IsInterlaced": false,
|
||||
"IsAVC": false,
|
||||
"IsDefault": false,
|
||||
"IsForced": false,
|
||||
"IsHearingImpaired": false,
|
||||
"Height": 0,
|
||||
"Width": 0,
|
||||
"Type": "Subtitle",
|
||||
"Index": 0,
|
||||
"IsExternal": true,
|
||||
"IsTextSubtitleStream": true,
|
||||
"SupportsExternalStream": true,
|
||||
"Path": "",
|
||||
"Level": 0
|
||||
},
|
||||
{
|
||||
"Codec": "subrip",
|
||||
"Language": "eng",
|
||||
"TimeBase": "1/1000",
|
||||
"Title": "0",
|
||||
"VideoRange": "Unknown",
|
||||
"VideoRangeType": "Unknown",
|
||||
"AudioSpatialFormat": "None",
|
||||
"LocalizedUndefined": "Undefined",
|
||||
"LocalizedDefault": "Default",
|
||||
"LocalizedForced": "Forced",
|
||||
"LocalizedExternal": "External",
|
||||
"LocalizedHearingImpaired": "Hearing Impaired",
|
||||
"DisplayTitle": "0 - English - SUBRIP - External",
|
||||
"IsInterlaced": false,
|
||||
"IsAVC": false,
|
||||
"IsDefault": false,
|
||||
"IsForced": false,
|
||||
"IsHearingImpaired": false,
|
||||
"Height": 0,
|
||||
"Width": 0,
|
||||
"Type": "Subtitle",
|
||||
"Index": 1,
|
||||
"IsExternal": true,
|
||||
"IsTextSubtitleStream": true,
|
||||
"SupportsExternalStream": true,
|
||||
"Path": "",
|
||||
"Level": 0
|
||||
},
|
||||
{
|
||||
"Codec": "subrip",
|
||||
"Language": "eng",
|
||||
"TimeBase": "1/1000",
|
||||
"VideoRange": "Unknown",
|
||||
"VideoRangeType": "Unknown",
|
||||
"AudioSpatialFormat": "None",
|
||||
"LocalizedUndefined": "Undefined",
|
||||
"LocalizedDefault": "Default",
|
||||
"LocalizedForced": "Forced",
|
||||
"LocalizedExternal": "External",
|
||||
"LocalizedHearingImpaired": "Hearing Impaired",
|
||||
"DisplayTitle": "English - SUBRIP - External",
|
||||
"IsInterlaced": false,
|
||||
"IsAVC": false,
|
||||
"IsDefault": false,
|
||||
"IsForced": false,
|
||||
"IsHearingImpaired": false,
|
||||
"Height": 0,
|
||||
"Width": 0,
|
||||
"Type": "Subtitle",
|
||||
"Index": 2,
|
||||
"IsExternal": true,
|
||||
"IsTextSubtitleStream": true,
|
||||
"SupportsExternalStream": true,
|
||||
"Path": "",
|
||||
"Level": 0
|
||||
},
|
||||
{
|
||||
"Codec": "eac3",
|
||||
"Language": "eng",
|
||||
"TimeBase": "1/1000",
|
||||
"VideoRange": "Unknown",
|
||||
"VideoRangeType": "Unknown",
|
||||
"AudioSpatialFormat": "None",
|
||||
"LocalizedDefault": "Default",
|
||||
"LocalizedExternal": "External",
|
||||
"DisplayTitle": "English - Dolby Digital+ - 5.1 - Default",
|
||||
"IsInterlaced": false,
|
||||
"IsAVC": false,
|
||||
"ChannelLayout": "5.1",
|
||||
"BitRate": 640000,
|
||||
"Channels": 6,
|
||||
"SampleRate": 48000,
|
||||
"IsDefault": true,
|
||||
"IsForced": false,
|
||||
"IsHearingImpaired": false,
|
||||
"Type": "Audio",
|
||||
"Index": 3,
|
||||
"IsExternal": false,
|
||||
"IsTextSubtitleStream": false,
|
||||
"SupportsExternalStream": false,
|
||||
"Level": 0
|
||||
},
|
||||
{
|
||||
"Codec": "h264",
|
||||
"ColorSpace": "bt709",
|
||||
"ColorTransfer": "bt709",
|
||||
"ColorPrimaries": "bt709",
|
||||
"TimeBase": "1/1000",
|
||||
"VideoRange": "SDR",
|
||||
"VideoRangeType": "SDR",
|
||||
"AudioSpatialFormat": "None",
|
||||
"DisplayTitle": "1080p H264 SDR",
|
||||
"NalLengthSize": "4",
|
||||
"IsInterlaced": false,
|
||||
"IsAVC": true,
|
||||
"BitRate": 13427007,
|
||||
"BitDepth": 8,
|
||||
"RefFrames": 1,
|
||||
"IsDefault": true,
|
||||
"IsForced": false,
|
||||
"IsHearingImpaired": false,
|
||||
"Height": 1080,
|
||||
"Width": 1920,
|
||||
"AverageFrameRate": 23.976025,
|
||||
"RealFrameRate": 23.976025,
|
||||
"ReferenceFrameRate": 23.976025,
|
||||
"Profile": "High",
|
||||
"Type": "Video",
|
||||
"AspectRatio": "16:9",
|
||||
"Index": 4,
|
||||
"IsExternal": false,
|
||||
"IsTextSubtitleStream": false,
|
||||
"SupportsExternalStream": false,
|
||||
"PixelFormat": "yuv420p",
|
||||
"Level": 40,
|
||||
"IsAnamorphic": false
|
||||
},
|
||||
{
|
||||
"Codec": "subrip",
|
||||
"TimeBase": "1/1000",
|
||||
"VideoRange": "Unknown",
|
||||
"VideoRangeType": "Unknown",
|
||||
"AudioSpatialFormat": "None",
|
||||
"LocalizedUndefined": "Undefined",
|
||||
"LocalizedDefault": "Default",
|
||||
"LocalizedForced": "Forced",
|
||||
"LocalizedExternal": "External",
|
||||
"LocalizedHearingImpaired": "Hearing Impaired",
|
||||
"DisplayTitle": "Undefined - Default - SUBRIP",
|
||||
"IsInterlaced": false,
|
||||
"IsAVC": false,
|
||||
"IsDefault": true,
|
||||
"IsForced": false,
|
||||
"IsHearingImpaired": false,
|
||||
"Height": 0,
|
||||
"Width": 0,
|
||||
"Type": "Subtitle",
|
||||
"Index": 5,
|
||||
"IsExternal": false,
|
||||
"IsTextSubtitleStream": true,
|
||||
"SupportsExternalStream": true,
|
||||
"Level": 0
|
||||
}
|
||||
],
|
||||
"MediaAttachments": [],
|
||||
"Formats": [],
|
||||
"Bitrate": 14067007,
|
||||
"RequiredHttpHeaders": {},
|
||||
"TranscodingSubProtocol": "http",
|
||||
"DefaultAudioStreamIndex": 3,
|
||||
"DefaultSubtitleStreamIndex": 0,
|
||||
"HasSegments": true
|
||||
}
|
||||
178
app/src/test/resources/no_embedded_subs.json
Normal file
178
app/src/test/resources/no_embedded_subs.json
Normal file
|
|
@ -0,0 +1,178 @@
|
|||
{
|
||||
"Protocol": "File",
|
||||
"Id": "",
|
||||
"Path": "",
|
||||
"Type": "Default",
|
||||
"Container": "mkv",
|
||||
"Size": 651217902,
|
||||
"Name": "",
|
||||
"IsRemote": false,
|
||||
"ETag": "",
|
||||
"RunTimeTicks": 14919360000,
|
||||
"ReadAtNativeFramerate": false,
|
||||
"IgnoreDts": false,
|
||||
"IgnoreIndex": false,
|
||||
"GenPtsInput": false,
|
||||
"SupportsTranscoding": true,
|
||||
"SupportsDirectStream": true,
|
||||
"SupportsDirectPlay": true,
|
||||
"IsInfiniteStream": false,
|
||||
"UseMostCompatibleTranscodingProfile": false,
|
||||
"RequiresOpening": false,
|
||||
"RequiresClosing": false,
|
||||
"RequiresLooping": false,
|
||||
"SupportsProbing": true,
|
||||
"VideoType": "VideoFile",
|
||||
"MediaStreams": [
|
||||
{
|
||||
"Codec": "subrip",
|
||||
"Language": "spa",
|
||||
"TimeBase": "1/1000",
|
||||
"VideoRange": "Unknown",
|
||||
"VideoRangeType": "Unknown",
|
||||
"AudioSpatialFormat": "None",
|
||||
"LocalizedUndefined": "Undefined",
|
||||
"LocalizedDefault": "Default",
|
||||
"LocalizedForced": "Forced",
|
||||
"LocalizedExternal": "External",
|
||||
"LocalizedHearingImpaired": "Hearing Impaired",
|
||||
"DisplayTitle": "Spanish - SUBRIP - External",
|
||||
"IsInterlaced": false,
|
||||
"IsAVC": false,
|
||||
"IsDefault": false,
|
||||
"IsForced": false,
|
||||
"IsHearingImpaired": false,
|
||||
"Height": 0,
|
||||
"Width": 0,
|
||||
"Type": "Subtitle",
|
||||
"Index": 0,
|
||||
"IsExternal": true,
|
||||
"IsTextSubtitleStream": true,
|
||||
"SupportsExternalStream": true,
|
||||
"Path": "",
|
||||
"Level": 0
|
||||
},
|
||||
{
|
||||
"Codec": "hevc",
|
||||
"Language": "jpn",
|
||||
"TimeBase": "1/1000",
|
||||
"Title": "",
|
||||
"VideoRange": "SDR",
|
||||
"VideoRangeType": "SDR",
|
||||
"AudioSpatialFormat": "None",
|
||||
"DisplayTitle": "1080p - HEVC - SDR",
|
||||
"IsInterlaced": false,
|
||||
"IsAVC": false,
|
||||
"BitRate": 3491934,
|
||||
"BitDepth": 10,
|
||||
"RefFrames": 1,
|
||||
"IsDefault": true,
|
||||
"IsForced": false,
|
||||
"IsHearingImpaired": false,
|
||||
"Height": 1080,
|
||||
"Width": 1448,
|
||||
"AverageFrameRate": 23.809525,
|
||||
"RealFrameRate": 23.809525,
|
||||
"ReferenceFrameRate": 23.809525,
|
||||
"Profile": "Main 10",
|
||||
"Type": "Video",
|
||||
"AspectRatio": "4:3",
|
||||
"Index": 1,
|
||||
"IsExternal": false,
|
||||
"IsTextSubtitleStream": false,
|
||||
"SupportsExternalStream": false,
|
||||
"PixelFormat": "yuv420p10le",
|
||||
"Level": 120,
|
||||
"IsAnamorphic": false
|
||||
},
|
||||
{
|
||||
"Codec": "opus",
|
||||
"Language": "jpn",
|
||||
"TimeBase": "1/1000",
|
||||
"Title": "Stereo (Opus 112Kbps)",
|
||||
"VideoRange": "Unknown",
|
||||
"VideoRangeType": "Unknown",
|
||||
"AudioSpatialFormat": "None",
|
||||
"LocalizedDefault": "Default",
|
||||
"LocalizedExternal": "External",
|
||||
"DisplayTitle": "Stereo (Opus 112Kbps) - Japanese",
|
||||
"IsInterlaced": false,
|
||||
"IsAVC": false,
|
||||
"ChannelLayout": "stereo",
|
||||
"BitRate": 101618,
|
||||
"Channels": 2,
|
||||
"SampleRate": 48000,
|
||||
"IsDefault": false,
|
||||
"IsForced": false,
|
||||
"IsHearingImpaired": false,
|
||||
"Type": "Audio",
|
||||
"Index": 2,
|
||||
"IsExternal": false,
|
||||
"IsTextSubtitleStream": false,
|
||||
"SupportsExternalStream": false,
|
||||
"Level": 0
|
||||
},
|
||||
{
|
||||
"Codec": "aac",
|
||||
"Language": "por",
|
||||
"TimeBase": "1/1000",
|
||||
"Title": "",
|
||||
"VideoRange": "Unknown",
|
||||
"VideoRangeType": "Unknown",
|
||||
"AudioSpatialFormat": "None",
|
||||
"LocalizedDefault": "Default",
|
||||
"LocalizedExternal": "External",
|
||||
"DisplayTitle": "Portuguese - AAC - Stereo",
|
||||
"IsInterlaced": false,
|
||||
"IsAVC": false,
|
||||
"ChannelLayout": "stereo",
|
||||
"BitRate": 249225,
|
||||
"Channels": 2,
|
||||
"SampleRate": 44100,
|
||||
"IsDefault": false,
|
||||
"IsForced": false,
|
||||
"IsHearingImpaired": false,
|
||||
"Profile": "LC",
|
||||
"Type": "Audio",
|
||||
"Index": 3,
|
||||
"IsExternal": false,
|
||||
"IsTextSubtitleStream": false,
|
||||
"SupportsExternalStream": false,
|
||||
"Level": 0
|
||||
},
|
||||
{
|
||||
"Codec": "eac3",
|
||||
"Language": "por",
|
||||
"TimeBase": "1/1000",
|
||||
"Title": "",
|
||||
"VideoRange": "Unknown",
|
||||
"VideoRangeType": "Unknown",
|
||||
"AudioSpatialFormat": "None",
|
||||
"LocalizedDefault": "Default",
|
||||
"LocalizedExternal": "External",
|
||||
"DisplayTitle": "Portuguese - Dolby Digital+ - 5.1",
|
||||
"IsInterlaced": false,
|
||||
"IsAVC": false,
|
||||
"ChannelLayout": "5.1",
|
||||
"BitRate": 640000,
|
||||
"Channels": 6,
|
||||
"SampleRate": 48000,
|
||||
"IsDefault": false,
|
||||
"IsForced": false,
|
||||
"IsHearingImpaired": false,
|
||||
"Type": "Audio",
|
||||
"Index": 4,
|
||||
"IsExternal": false,
|
||||
"IsTextSubtitleStream": false,
|
||||
"SupportsExternalStream": false,
|
||||
"Level": 0
|
||||
}
|
||||
],
|
||||
"MediaAttachments": [],
|
||||
"Formats": [],
|
||||
"Bitrate": 4482777,
|
||||
"RequiredHttpHeaders": {},
|
||||
"TranscodingSubProtocol": "http",
|
||||
"DefaultAudioStreamIndex": 2,
|
||||
"HasSegments": true
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue