Skip to content

Commit

Permalink
Merge branch 'xerror' into 'master'
Browse files Browse the repository at this point in the history
add options for -xerror and other global params to EncodingProperties.

Fix tmpdir
  • Loading branch information
John Laurin (jola10) committed Apr 29, 2024
2 parents 5c14a5e + 6998b83 commit acd9d62
Show file tree
Hide file tree
Showing 8 changed files with 49 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,7 @@ data class EncodingProperties(
val audioMixPresets: Map<String, AudioMixPreset> = mapOf("default" to AudioMixPreset()),
@NestedConfigurationProperty
val defaultChannelLayouts: Map<Int, ChannelLayout> = emptyMap(),
val flipWidthHeightIfPortrait: Boolean = true
val flipWidthHeightIfPortrait: Boolean = true,
val exitOnError: Boolean = true,
val globalParams: LinkedHashMap<String, Any?> = linkedMapOf(),
)
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,5 @@ fun AudioFile.selectAudioStream(index: Int?): AudioFile {
fun Map<String, Any?>.toParams(): List<String> =
flatMap { entry ->
listOfNotNull("-${entry.key}", entry.value?.let { "$it" })
.filterNot { it.isEmpty() }
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ import se.svt.oss.encore.model.input.videoInput
import se.svt.oss.encore.model.mediafile.toParams
import se.svt.oss.encore.model.output.Output
import se.svt.oss.encore.model.output.VideoStreamEncode
import se.svt.oss.encore.process.createTempDir
import se.svt.oss.mediaanalyzer.file.stringValue
import kotlin.io.path.createTempDirectory

data class ThumbnailMapEncode(
val tileWidth: Int = 160,
Expand Down Expand Up @@ -53,7 +53,7 @@ data class ThumbnailMapEncode(
?.let { "gte(t\\,$it)*(isnan(prev_selected_t)+gt(floor((t-$it)/$interval)\\,floor((prev_selected_t-$it)/$interval)))" }
?: "isnan(prev_selected_t)+gt(floor(t/$interval)\\,floor(prev_selected_t/$interval))"

val tempFolder = createTempDirectory(suffix).toFile()
val tempFolder = createTempDir(suffix).toFile()
tempFolder.deleteOnExit()

val pad = "aspect=${Fraction(tileWidth, tileHeight).stringValue()}:x=(ow-iw)/2:y=(oh-ih)/2"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import se.svt.oss.encore.model.input.inputParams
import se.svt.oss.encore.model.mediafile.AudioLayout
import se.svt.oss.encore.model.mediafile.audioLayout
import se.svt.oss.encore.model.mediafile.channelLayout
import se.svt.oss.encore.model.mediafile.toParams
import se.svt.oss.encore.model.output.AudioStreamEncode
import se.svt.oss.encore.model.output.Output
import se.svt.oss.encore.model.output.VideoStreamEncode
Expand Down Expand Up @@ -165,13 +166,15 @@ class CommandBuilder(
val readDuration = encoreJob.duration?.let {
it + (encoreJob.seekTo ?: 0.0)
}
return listOf(
"ffmpeg",
"-hide_banner",
"-loglevel",
"+level",
"-y"
) + inputs.inputParams(readDuration)
return buildList {
add("ffmpeg")
if (encodingProperties.exitOnError) {
add("-xerror")
}
addAll(encodingProperties.globalParams.toParams())
addAll(listOf("-hide_banner", "-loglevel", "+level", "-y"))
addAll(inputs.inputParams(readDuration))
}
}

private fun globalVideoFilters(input: VideoIn, videoFile: VideoFile): List<String> {
Expand Down
10 changes: 10 additions & 0 deletions encore-common/src/main/kotlin/se/svt/oss/encore/process/TempDir.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package se.svt.oss.encore.process

import java.nio.file.Path
import kotlin.io.path.createTempDirectory

fun createTempDir(prefix: String): Path {
val tmpdir = System.getenv("ENCORE_TMPDIR")
?: System.getProperty("java.io.tmpdir")
return createTempDirectory(tmpdir?.let { Path.of(it) }, prefix)
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ import se.svt.oss.encore.model.EncoreJob
import se.svt.oss.encore.model.input.maxDuration
import se.svt.oss.encore.model.mediafile.toParams
import se.svt.oss.encore.process.CommandBuilder
import se.svt.oss.encore.process.createTempDir
import se.svt.oss.encore.service.profile.ProfileService
import se.svt.oss.mediaanalyzer.MediaAnalyzer
import se.svt.oss.mediaanalyzer.file.MediaFile
import java.io.File
import java.nio.file.Files
import java.util.concurrent.TimeUnit
import kotlin.math.min
import kotlin.math.round
Expand Down Expand Up @@ -57,7 +57,7 @@ class FfmpegExecutor(
val commands =
CommandBuilder(encoreJob, profile, outputFolder, encoreProperties.encoding).buildCommands(outputs)
log.info { "Start encoding ${encoreJob.baseName}..." }
val workDir = Files.createTempDirectory("encore_").toFile()
val workDir = createTempDir("encore_").toFile()
val duration = encoreJob.duration ?: encoreJob.inputs.maxDuration()
return try {
File(outputFolder).mkdirs()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@ package se.svt.oss.encore.service.localencode

import mu.KotlinLogging
import org.springframework.stereotype.Service
import se.svt.oss.encore.config.EncoreProperties
import se.svt.oss.encore.model.EncoreJob
import se.svt.oss.encore.process.createTempDir
import se.svt.oss.mediaanalyzer.file.AudioFile
import se.svt.oss.mediaanalyzer.file.ImageFile
import se.svt.oss.mediaanalyzer.file.MediaFile
import se.svt.oss.mediaanalyzer.file.VideoFile
import se.svt.oss.encore.config.EncoreProperties
import se.svt.oss.encore.model.EncoreJob
import java.io.File
import java.nio.file.Files
import java.nio.file.Path
Expand All @@ -28,7 +29,7 @@ class LocalEncodeService(
encoreJob: EncoreJob
): String {
return if (encoreProperties.localTemporaryEncode) {
Files.createTempDirectory("job_${encoreJob.id}").toString()
createTempDir("job_${encoreJob.id}").toString()
} else {
encoreJob.outputFolder
}
Expand Down Expand Up @@ -58,12 +59,7 @@ class LocalEncodeService(
}

private fun moveTempLocalFiles(destination: File, tempDirectory: String) {
val filesBeforeMove = File(tempDirectory).listFiles()
filesBeforeMove?.forEach { moveFile(it, destination) }
val fileCountAfterMove = destination.list()?.size
if (fileCountAfterMove != filesBeforeMove?.count()) {
throw RuntimeException("File count after moving files from temp to output folder differs.")
}
File(tempDirectory).listFiles()?.forEach { moveFile(it, destination) }
}

private fun moveFile(file: File, destination: File) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ internal class CommandBuilderTest {
val profile: Profile = mockk()
var videoFile = defaultVideoFile
var encoreJob = defaultEncoreJob()
val encodingProperties = mockk<EncodingProperties>()
val encodingProperties = EncodingProperties()

private lateinit var commandBuilder: CommandBuilder

Expand All @@ -38,7 +38,6 @@ internal class CommandBuilderTest {
@BeforeEach
internal fun setUp() {
commandBuilder = CommandBuilder(encoreJob, profile, encoreJob.outputFolder, encodingProperties)
every { encodingProperties.defaultChannelLayouts } returns emptyMap()
every { profile.scaling } returns "scaling"
every { profile.deinterlaceFilter } returns "yadif"
}
Expand All @@ -59,7 +58,7 @@ internal class CommandBuilderTest {
)
val buildCommands = commandBuilder.buildCommands(listOf(output))
val command = buildCommands.first().joinToString(" ")
assertThat(command).isEqualTo("ffmpeg -hide_banner -loglevel +level -y -i /input/test.mp4 -map 0:a -vn -c:a copy -metadata comment=Transcoded using Encore /output/path/out.mp4")
assertThat(command).isEqualTo("ffmpeg -xerror -hide_banner -loglevel +level -y -i /input/test.mp4 -map 0:a -vn -c:a copy -metadata comment=Transcoded using Encore /output/path/out.mp4")
}

@Test
Expand Down Expand Up @@ -88,7 +87,7 @@ internal class CommandBuilderTest {
)
val buildCommands = commandBuilder.buildCommands(listOf(output))
val command = buildCommands.first().joinToString(" ")
assertThat(command).isEqualTo("ffmpeg -hide_banner -loglevel +level -y -i /input/test.mp4 -filter_complex sws_flags=scaling;[0:a]join=inputs=3:channel_layout=3.0:map=0.0-FL|1.0-FR|2.0-FC,asplit=1[AUDIO-main-test-out-0];[AUDIO-main-test-out-0]aformat=channel_layouts=stereo[AUDIO-test-out-0] -map [AUDIO-test-out-0] -vn -c:a:0 aac -metadata comment=Transcoded using Encore /output/path/out.mp4")
assertThat(command).isEqualTo("ffmpeg -xerror -hide_banner -loglevel +level -y -i /input/test.mp4 -filter_complex sws_flags=scaling;[0:a]join=inputs=3:channel_layout=3.0:map=0.0-FL|1.0-FR|2.0-FC,asplit=1[AUDIO-main-test-out-0];[AUDIO-main-test-out-0]aformat=channel_layouts=stereo[AUDIO-test-out-0] -map [AUDIO-test-out-0] -vn -c:a:0 aac -metadata comment=Transcoded using Encore /output/path/out.mp4")
}

@Test
Expand All @@ -98,7 +97,7 @@ internal class CommandBuilderTest {
assertThat(buildCommands).hasSize(1)

val command = buildCommands.first().joinToString(" ")
assertThat(command).isEqualTo("ffmpeg -hide_banner -loglevel +level -y -i /input/test.mp4 -filter_complex sws_flags=scaling;[0:v]split=1[VIDEO-main-test-out];[VIDEO-main-test-out]video-filter[VIDEO-test-out];[0:a]join=inputs=8:channel_layout=7.1:map=0.0-FL|1.0-FR|2.0-FC|3.0-LFE|4.0-BL|5.0-BR|6.0-SL|7.0-SR,asplit=1[AUDIO-main-test-out-0];[AUDIO-main-test-out-0]audio-filter[AUDIO-test-out-0] -map [VIDEO-test-out] -map [AUDIO-test-out-0] video params audio params -metadata comment=Transcoded using Encore /output/path/out.mp4")
assertThat(command).isEqualTo("ffmpeg -xerror -hide_banner -loglevel +level -y -i /input/test.mp4 -filter_complex sws_flags=scaling;[0:v]split=1[VIDEO-main-test-out];[VIDEO-main-test-out]video-filter[VIDEO-test-out];[0:a]join=inputs=8:channel_layout=7.1:map=0.0-FL|1.0-FR|2.0-FC|3.0-LFE|4.0-BL|5.0-BR|6.0-SL|7.0-SR,asplit=1[AUDIO-main-test-out-0];[AUDIO-main-test-out-0]audio-filter[AUDIO-test-out-0] -map [VIDEO-test-out] -map [AUDIO-test-out-0] video params audio params -metadata comment=Transcoded using Encore /output/path/out.mp4")
}

@Test
Expand All @@ -109,8 +108,8 @@ internal class CommandBuilderTest {
val firstPass = buildCommands[0].joinToString(" ")
val secondPass = buildCommands[1].joinToString(" ")

assertThat(firstPass).isEqualTo("ffmpeg -hide_banner -loglevel +level -y -i ${defaultVideoFile.file} -filter_complex sws_flags=scaling;[0:v]split=1[VIDEO-main-test-out];[VIDEO-main-test-out]video-filter[VIDEO-test-out] -map [VIDEO-test-out] -an first pass -f mp4 /dev/null")
assertThat(secondPass).isEqualTo("ffmpeg -hide_banner -loglevel +level -y -i ${defaultVideoFile.file} -filter_complex sws_flags=scaling;[0:v]split=1[VIDEO-main-test-out];[VIDEO-main-test-out]video-filter[VIDEO-test-out];[0:a]join=inputs=8:channel_layout=7.1:map=0.0-FL|1.0-FR|2.0-FC|3.0-LFE|4.0-BL|5.0-BR|6.0-SL|7.0-SR,asplit=1[AUDIO-main-test-out-0];[AUDIO-main-test-out-0]audio-filter[AUDIO-test-out-0] -map [VIDEO-test-out] -map [AUDIO-test-out-0] video params audio params -metadata comment=$metadataComment /output/path/out.mp4")
assertThat(firstPass).isEqualTo("ffmpeg -xerror -hide_banner -loglevel +level -y -i ${defaultVideoFile.file} -filter_complex sws_flags=scaling;[0:v]split=1[VIDEO-main-test-out];[VIDEO-main-test-out]video-filter[VIDEO-test-out] -map [VIDEO-test-out] -an first pass -f mp4 /dev/null")
assertThat(secondPass).isEqualTo("ffmpeg -xerror -hide_banner -loglevel +level -y -i ${defaultVideoFile.file} -filter_complex sws_flags=scaling;[0:v]split=1[VIDEO-main-test-out];[VIDEO-main-test-out]video-filter[VIDEO-test-out];[0:a]join=inputs=8:channel_layout=7.1:map=0.0-FL|1.0-FR|2.0-FC|3.0-LFE|4.0-BL|5.0-BR|6.0-SL|7.0-SR,asplit=1[AUDIO-main-test-out-0];[AUDIO-main-test-out-0]audio-filter[AUDIO-test-out-0] -map [VIDEO-test-out] -map [AUDIO-test-out-0] video params audio params -metadata comment=$metadataComment /output/path/out.mp4")
}

@Test
Expand All @@ -132,8 +131,8 @@ internal class CommandBuilderTest {
val firstPass = buildCommands[0].joinToString(" ")
val secondPass = buildCommands[1].joinToString(" ")

assertThat(firstPass).isEqualTo("ffmpeg -hide_banner -loglevel +level -y -ss 47.11 -i ${videoFile.file} -filter_complex sws_flags=scaling;[0:v]split=1[VIDEO-main-test-out];[VIDEO-main-test-out]video-filter[VIDEO-test-out] -map [VIDEO-test-out] -an first pass -f mp4 /dev/null")
assertThat(secondPass).isEqualTo("ffmpeg -hide_banner -loglevel +level -y -ss 47.11 -i ${videoFile.file} -filter_complex sws_flags=scaling;[0:v]split=1[VIDEO-main-test-out];[VIDEO-main-test-out]video-filter[VIDEO-test-out];[0:a]join=inputs=8:channel_layout=7.1:map=0.0-FL|1.0-FR|2.0-FC|3.0-LFE|4.0-BL|5.0-BR|6.0-SL|7.0-SR,asplit=1[AUDIO-main-test-out-0];[AUDIO-main-test-out-0]audio-filter[AUDIO-test-out-0] -map [VIDEO-test-out] -map [AUDIO-test-out-0] video params audio params -metadata comment=$metadataComment /output/path/out.mp4")
assertThat(firstPass).isEqualTo("ffmpeg -xerror -hide_banner -loglevel +level -y -ss 47.11 -i ${videoFile.file} -filter_complex sws_flags=scaling;[0:v]split=1[VIDEO-main-test-out];[VIDEO-main-test-out]video-filter[VIDEO-test-out] -map [VIDEO-test-out] -an first pass -f mp4 /dev/null")
assertThat(secondPass).isEqualTo("ffmpeg -xerror -hide_banner -loglevel +level -y -ss 47.11 -i ${videoFile.file} -filter_complex sws_flags=scaling;[0:v]split=1[VIDEO-main-test-out];[VIDEO-main-test-out]video-filter[VIDEO-test-out];[0:a]join=inputs=8:channel_layout=7.1:map=0.0-FL|1.0-FR|2.0-FC|3.0-LFE|4.0-BL|5.0-BR|6.0-SL|7.0-SR,asplit=1[AUDIO-main-test-out-0];[AUDIO-main-test-out-0]audio-filter[AUDIO-test-out-0] -map [VIDEO-test-out] -map [AUDIO-test-out-0] video params audio params -metadata comment=$metadataComment /output/path/out.mp4")
}

@Test
Expand Down Expand Up @@ -196,7 +195,12 @@ internal class CommandBuilderTest {
inputs = inputs
)

commandBuilder = CommandBuilder(encoreJob, profile, "/tmp/123", encodingProperties)
commandBuilder = CommandBuilder(
encoreJob,
profile,
"/tmp/123",
encodingProperties.copy(exitOnError = false, globalParams = linkedMapOf("err_detect" to "explode"))
)

val buildCommands = commandBuilder.buildCommands(listOf(output(true), audioOutput("other", "extra")))

Expand All @@ -205,8 +209,8 @@ internal class CommandBuilderTest {
val firstPass = buildCommands[0].joinToString(" ")
val secondPass = buildCommands[1].joinToString(" ")

assertThat(firstPass).isEqualTo("ffmpeg -hide_banner -loglevel +level -y -f mp4 -t 22.5 -i /input/test.mp4 -filter_complex sws_flags=scaling;[0:v:1]yadif,setdar=16/9,scale=iw*sar:ih,crop=min(iw\\,ih*1/1):min(ih\\,iw/(1/1)),pad=aspect=16/9:x=(ow-iw)/2:y=(oh-ih)/2,video,filter,split=1[VIDEO-main-test-out];[VIDEO-main-test-out]video-filter[VIDEO-test-out] -map [VIDEO-test-out] -ss 12.1 -an -t 10.4 first pass -f mp4 /dev/null")
assertThat(secondPass).isEqualTo("ffmpeg -hide_banner -loglevel +level -y -f mp4 -t 22.5 -i /input/test.mp4 -ac 4 -t 22.5 -i /input/main-audio.mp4 -t 22.5 -i /input/other-audio.mp4 -filter_complex sws_flags=scaling;[0:v:1]yadif,setdar=16/9,scale=iw*sar:ih,crop=min(iw\\,ih*1/1):min(ih\\,iw/(1/1)),pad=aspect=16/9:x=(ow-iw)/2:y=(oh-ih)/2,video,filter,split=1[VIDEO-main-test-out];[VIDEO-main-test-out]video-filter[VIDEO-test-out];[1:a]join=inputs=4:channel_layout=4.0:map=0.0-FL|1.0-FR|2.0-FC|3.0-BC,audio-main,main-filter,asplit=1[AUDIO-main-test-out-0];[2:a:3]asplit=1[AUDIO-other-extra-0];[AUDIO-main-test-out-0]audio-filter[AUDIO-test-out-0];[AUDIO-other-extra-0]audio-filter-extra[AUDIO-extra-0] -map [VIDEO-test-out] -ss 12.1 -map [AUDIO-test-out-0] -ss 12.1 -t 10.4 video params audio params -metadata comment=Transcoded using Encore /tmp/123/out.mp4 -map [AUDIO-extra-0] -ss 12.1 -t 10.4 -vn audio extra -metadata comment=Transcoded using Encore /tmp/123/extra.mp4")
assertThat(firstPass).isEqualTo("ffmpeg -err_detect explode -hide_banner -loglevel +level -y -f mp4 -t 22.5 -i /input/test.mp4 -filter_complex sws_flags=scaling;[0:v:1]yadif,setdar=16/9,scale=iw*sar:ih,crop=min(iw\\,ih*1/1):min(ih\\,iw/(1/1)),pad=aspect=16/9:x=(ow-iw)/2:y=(oh-ih)/2,video,filter,split=1[VIDEO-main-test-out];[VIDEO-main-test-out]video-filter[VIDEO-test-out] -map [VIDEO-test-out] -ss 12.1 -an -t 10.4 first pass -f mp4 /dev/null")
assertThat(secondPass).isEqualTo("ffmpeg -err_detect explode -hide_banner -loglevel +level -y -f mp4 -t 22.5 -i /input/test.mp4 -ac 4 -t 22.5 -i /input/main-audio.mp4 -t 22.5 -i /input/other-audio.mp4 -filter_complex sws_flags=scaling;[0:v:1]yadif,setdar=16/9,scale=iw*sar:ih,crop=min(iw\\,ih*1/1):min(ih\\,iw/(1/1)),pad=aspect=16/9:x=(ow-iw)/2:y=(oh-ih)/2,video,filter,split=1[VIDEO-main-test-out];[VIDEO-main-test-out]video-filter[VIDEO-test-out];[1:a]join=inputs=4:channel_layout=4.0:map=0.0-FL|1.0-FR|2.0-FC|3.0-BC,audio-main,main-filter,asplit=1[AUDIO-main-test-out-0];[2:a:3]asplit=1[AUDIO-other-extra-0];[AUDIO-main-test-out-0]audio-filter[AUDIO-test-out-0];[AUDIO-other-extra-0]audio-filter-extra[AUDIO-extra-0] -map [VIDEO-test-out] -ss 12.1 -map [AUDIO-test-out-0] -ss 12.1 -t 10.4 video params audio params -metadata comment=Transcoded using Encore /tmp/123/out.mp4 -map [AUDIO-extra-0] -ss 12.1 -t 10.4 -vn audio extra -metadata comment=Transcoded using Encore /tmp/123/extra.mp4")
}

private fun output(twoPass: Boolean): Output {
Expand Down

0 comments on commit acd9d62

Please sign in to comment.