Changing subtitle selection for extraction

This commit is contained in:
bskjon 2025-03-09 20:36:19 +01:00
parent d9e9aa6a2f
commit 78d4014d77
3 changed files with 115 additions and 8 deletions

View File

@ -62,17 +62,18 @@ class SubtitleArguments(val subtitleStreams: List<SubtitleStream>) {
val languageGrouped = codecFiltered.groupBy { it.tags.language ?: "eng" } val languageGrouped = codecFiltered.groupBy { it.tags.language ?: "eng" }
val streamsToExtract = languageGrouped.mapNotNull { item -> val streamsToExtract = languageGrouped.mapNotNull { item ->
val types = item.value.map { getSubtitleType(it) } val itemToType = item.value.map { it to getSubtitleType(it) }
if (types.none { t -> t == SubtitleType.DEFAULT } || types.count { t -> t == SubtitleType.DEFAULT} > 1) { val usableSubtitles = itemToType.filter { it.second == SubtitleType.DEFAULT }.ifEmpty { itemToType }
excludeLowFrameCount(item.value).sortedBy { it.tags.NUMBER_OF_FRAMES }.firstOrNull() val excludedLowFrameCount = excludeLowFrameCount(usableSubtitles.map { it.first }).sortedByDescending { it.tags.NUMBER_OF_FRAMES }
} else { excludedLowFrameCount.firstOrNull() ?: run {
item.value.minByOrNull { s -> getSubtitleType(s) } usableSubtitles.map { it.first }.firstOrNull { it.disposition?.default == 1 } ?: usableSubtitles.firstOrNull()?.first
} }
} }
return streamsToExtract.mapNotNull { stream -> return streamsToExtract.mapNotNull { stream ->
getFormatToCodec(stream.codec_name)?.let { format -> getFormatToCodec(stream.codec_name)?.let { format ->
SubtitleArgumentsDto( SubtitleArgumentsDto(
mediaIndex = stream.index,
index = subtitleStreams.indexOf(stream), index = subtitleStreams.indexOf(stream),
language = stream.tags.language ?: "eng", language = stream.tags.language ?: "eng",
format = format format = format
@ -94,7 +95,7 @@ class SubtitleArguments(val subtitleStreams: List<SubtitleStream>) {
return usable.filter { return usable.filter {
val frameCount = it.tags.NUMBER_OF_FRAMES ?: 0 val frameCount = it.tags.NUMBER_OF_FRAMES ?: 0
frameCount.toDouble() in standardDeviation..upperBound frameCount.toDouble() in lowerBound..upperBound
} }
} }

View File

@ -31,7 +31,7 @@ class SubtitleArgumentsTest {
val data = Gson().fromJson<List<SubtitleStream>>(multipleSubtitleStreamsWithSameLanguage, type) val data = Gson().fromJson<List<SubtitleStream>>(multipleSubtitleStreamsWithSameLanguage, type)
val args = SubtitleArguments(data).getSubtitleArguments() val args = SubtitleArguments(data).getSubtitleArguments()
assertThat(args).hasSize(1) assertThat(args).hasSize(1)
assertThat(args.firstOrNull()?.index).isEqualTo(1) assertThat(args.firstOrNull()?.mediaIndex).isEqualTo(4)
} }
@Test @Test
@ -39,7 +39,15 @@ class SubtitleArgumentsTest {
val data = Gson().fromJson<List<SubtitleStream>>(multipleSubtitleStreamsWithSameLanguageWithDisposition, type) val data = Gson().fromJson<List<SubtitleStream>>(multipleSubtitleStreamsWithSameLanguageWithDisposition, type)
val args = SubtitleArguments(data).getSubtitleArguments() val args = SubtitleArguments(data).getSubtitleArguments()
assertThat(args).hasSize(1) assertThat(args).hasSize(1)
assertThat(args.firstOrNull()?.index).isEqualTo(1) assertThat(args.firstOrNull()?.mediaIndex).isEqualTo(4)
}
@Test
fun assertThatCorrectTrackIsSelected() {
val data = Gson().fromJson<List<SubtitleStream>>(selectCorrectTrack, type)
val args = SubtitleArguments(data).getSubtitleArguments()
assertThat(args).hasSize(1)
assertThat(args.firstOrNull()?.index).isEqualTo(0)
} }
@ -123,6 +131,7 @@ class SubtitleArgumentsTest {
}] }]
""".trimIndent() """.trimIndent()
//language=json
val multipleSubtitleStreamsWithSameLanguageWithDisposition = """ val multipleSubtitleStreamsWithSameLanguageWithDisposition = """
[{ [{
"index": 3, "index": 3,
@ -262,4 +271,100 @@ class SubtitleArgumentsTest {
} }
}] }]
""".trimIndent() """.trimIndent()
val selectCorrectTrack = """
[
{
"index": 2,
"codec_name": "ass",
"codec_long_name": "ASS (Advanced SSA) subtitle",
"codec_type": "subtitle",
"codec_tag_string": "[0][0][0][0]",
"codec_tag": "0x0000",
"r_frame_rate": "0/0",
"avg_frame_rate": "0/0",
"time_base": "1/1000",
"start_pts": 0,
"start_time": "0.000000",
"duration_ts": 1430048,
"duration": "1430.048000",
"extradata_size": 2185,
"disposition": {
"default": 1,
"dub": 0,
"original": 0,
"comment": 0,
"lyrics": 0,
"karaoke": 0,
"forced": 0,
"hearing_impaired": 0,
"visual_impaired": 0,
"clean_effects": 0,
"attached_pic": 0,
"timed_thumbnails": 0,
"non_diegetic": 0,
"captions": 0,
"descriptions": 0,
"metadata": 0,
"dependent": 0,
"still_image": 0
},
"tags": {
"language": "eng",
"BPS": "173",
"DURATION": "00:23:43.500000000",
"NUMBER_OF_FRAMES": "436",
"NUMBER_OF_BYTES": "30896",
"_STATISTICS_WRITING_APP": "mkvmerge v69.0.0 ('Day And Age') 64-bit",
"_STATISTICS_WRITING_DATE_UTC": "2025-01-03 02:19:23",
"_STATISTICS_TAGS": "BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES"
}
},
{
"index": 3,
"codec_name": "subrip",
"codec_long_name": "SubRip subtitle",
"codec_type": "subtitle",
"codec_tag_string": "[0][0][0][0]",
"codec_tag": "0x0000",
"r_frame_rate": "0/0",
"avg_frame_rate": "0/0",
"time_base": "1/1000",
"start_pts": 0,
"start_time": "0.000000",
"duration_ts": 1430048,
"duration": "1430.048000",
"disposition": {
"default": 0,
"dub": 0,
"original": 0,
"comment": 0,
"lyrics": 0,
"karaoke": 0,
"forced": 0,
"hearing_impaired": 0,
"visual_impaired": 0,
"clean_effects": 0,
"attached_pic": 0,
"timed_thumbnails": 0,
"non_diegetic": 0,
"captions": 0,
"descriptions": 0,
"metadata": 0,
"dependent": 0,
"still_image": 0
},
"tags": {
"language": "eng",
"BPS": "83",
"DURATION": "00:23:41.860000000",
"NUMBER_OF_FRAMES": "432",
"NUMBER_OF_BYTES": "14853",
"_STATISTICS_WRITING_APP": "mkvmerge v69.0.0 ('Day And Age') 64-bit",
"_STATISTICS_WRITING_DATE_UTC": "2025-01-03 02:19:23",
"_STATISTICS_TAGS": "BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES"
}
}
]
""".trimIndent()
} }

View File

@ -1,6 +1,7 @@
package no.iktdev.mediaprocessing.shared.common.contract.ffmpeg package no.iktdev.mediaprocessing.shared.common.contract.ffmpeg
data class SubtitleArgumentsDto( data class SubtitleArgumentsDto(
val mediaIndex: Int,
val index: Int, val index: Int,
val language: String, val language: String,
val format: String, // Extension as well val format: String, // Extension as well