diff --git a/apps/coordinator/src/main/kotlin/no/iktdev/mediaprocessing/coordinator/tasksV2/mapping/streams/SubtitleArguments.kt b/apps/coordinator/src/main/kotlin/no/iktdev/mediaprocessing/coordinator/tasksV2/mapping/streams/SubtitleArguments.kt index 2ccd43e0..75b55216 100644 --- a/apps/coordinator/src/main/kotlin/no/iktdev/mediaprocessing/coordinator/tasksV2/mapping/streams/SubtitleArguments.kt +++ b/apps/coordinator/src/main/kotlin/no/iktdev/mediaprocessing/coordinator/tasksV2/mapping/streams/SubtitleArguments.kt @@ -62,17 +62,18 @@ class SubtitleArguments(val subtitleStreams: List) { val languageGrouped = codecFiltered.groupBy { it.tags.language ?: "eng" } val streamsToExtract = languageGrouped.mapNotNull { item -> - val types = item.value.map { getSubtitleType(it) } - if (types.none { t -> t == SubtitleType.DEFAULT } || types.count { t -> t == SubtitleType.DEFAULT} > 1) { - excludeLowFrameCount(item.value).sortedBy { it.tags.NUMBER_OF_FRAMES }.firstOrNull() - } else { - item.value.minByOrNull { s -> getSubtitleType(s) } + val itemToType = item.value.map { it to getSubtitleType(it) } + val usableSubtitles = itemToType.filter { it.second == SubtitleType.DEFAULT }.ifEmpty { itemToType } + val excludedLowFrameCount = excludeLowFrameCount(usableSubtitles.map { it.first }).sortedByDescending { it.tags.NUMBER_OF_FRAMES } + excludedLowFrameCount.firstOrNull() ?: run { + usableSubtitles.map { it.first }.firstOrNull { it.disposition?.default == 1 } ?: usableSubtitles.firstOrNull()?.first } } return streamsToExtract.mapNotNull { stream -> getFormatToCodec(stream.codec_name)?.let { format -> SubtitleArgumentsDto( + mediaIndex = stream.index, index = subtitleStreams.indexOf(stream), language = stream.tags.language ?: "eng", format = format @@ -94,7 +95,7 @@ class SubtitleArguments(val subtitleStreams: List) { return usable.filter { val frameCount = it.tags.NUMBER_OF_FRAMES ?: 0 - frameCount.toDouble() in standardDeviation..upperBound + frameCount.toDouble() in lowerBound..upperBound } } diff --git a/apps/coordinator/src/test/kotlin/no/iktdev/mediaprocessing/coordinator/tasksV2/mapping/streams/SubtitleArgumentsTest.kt b/apps/coordinator/src/test/kotlin/no/iktdev/mediaprocessing/coordinator/tasksV2/mapping/streams/SubtitleArgumentsTest.kt index 2928e5ff..7fe7cd89 100644 --- a/apps/coordinator/src/test/kotlin/no/iktdev/mediaprocessing/coordinator/tasksV2/mapping/streams/SubtitleArgumentsTest.kt +++ b/apps/coordinator/src/test/kotlin/no/iktdev/mediaprocessing/coordinator/tasksV2/mapping/streams/SubtitleArgumentsTest.kt @@ -31,7 +31,7 @@ class SubtitleArgumentsTest { val data = Gson().fromJson>(multipleSubtitleStreamsWithSameLanguage, type) val args = SubtitleArguments(data).getSubtitleArguments() assertThat(args).hasSize(1) - assertThat(args.firstOrNull()?.index).isEqualTo(1) + assertThat(args.firstOrNull()?.mediaIndex).isEqualTo(4) } @Test @@ -39,7 +39,15 @@ class SubtitleArgumentsTest { val data = Gson().fromJson>(multipleSubtitleStreamsWithSameLanguageWithDisposition, type) val args = SubtitleArguments(data).getSubtitleArguments() assertThat(args).hasSize(1) - assertThat(args.firstOrNull()?.index).isEqualTo(1) + assertThat(args.firstOrNull()?.mediaIndex).isEqualTo(4) + } + + @Test + fun assertThatCorrectTrackIsSelected() { + val data = Gson().fromJson>(selectCorrectTrack, type) + val args = SubtitleArguments(data).getSubtitleArguments() + assertThat(args).hasSize(1) + assertThat(args.firstOrNull()?.index).isEqualTo(0) } @@ -123,6 +131,7 @@ class SubtitleArgumentsTest { }] """.trimIndent() + //language=json val multipleSubtitleStreamsWithSameLanguageWithDisposition = """ [{ "index": 3, @@ -262,4 +271,100 @@ class SubtitleArgumentsTest { } }] """.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() } \ No newline at end of file diff --git a/shared/common/src/main/kotlin/no/iktdev/mediaprocessing/shared/common/contract/ffmpeg/SubtitleArgumentsDto.kt b/shared/common/src/main/kotlin/no/iktdev/mediaprocessing/shared/common/contract/ffmpeg/SubtitleArgumentsDto.kt index c9e0491e..45e2a140 100644 --- a/shared/common/src/main/kotlin/no/iktdev/mediaprocessing/shared/common/contract/ffmpeg/SubtitleArgumentsDto.kt +++ b/shared/common/src/main/kotlin/no/iktdev/mediaprocessing/shared/common/contract/ffmpeg/SubtitleArgumentsDto.kt @@ -1,6 +1,7 @@ package no.iktdev.mediaprocessing.shared.common.contract.ffmpeg data class SubtitleArgumentsDto( + val mediaIndex: Int, val index: Int, val language: String, val format: String, // Extension as well