From fe017d18c56aabde9ab9250b48b78e26f6764cd8 Mon Sep 17 00:00:00 2001 From: Gustav Grusell Date: Thu, 16 Nov 2023 10:19:17 +0100 Subject: [PATCH] fix: fix profile deserialization in native compiled image Signed-off-by: Gustav Grusell --- .../svt/oss/encore/ReflectionConfiguration.kt | 33 +++++++++++ .../model/profile/GenericVideoEncode.kt | 2 +- .../oss/encore/model/profile/VideoEncode.kt | 26 ++++----- .../oss/encore/model/profile/X26XEncode.kt | 2 +- .../encore/model/profile/ProfileJsonTest.kt | 57 +++++++++++++++++++ 5 files changed, 105 insertions(+), 15 deletions(-) create mode 100644 encore-common/src/main/kotlin/se/svt/oss/encore/ReflectionConfiguration.kt create mode 100644 encore-common/src/test/kotlin/se/svt/oss/encore/model/profile/ProfileJsonTest.kt diff --git a/encore-common/src/main/kotlin/se/svt/oss/encore/ReflectionConfiguration.kt b/encore-common/src/main/kotlin/se/svt/oss/encore/ReflectionConfiguration.kt new file mode 100644 index 0000000..97c0758 --- /dev/null +++ b/encore-common/src/main/kotlin/se/svt/oss/encore/ReflectionConfiguration.kt @@ -0,0 +1,33 @@ +package se.svt.oss.encore + +import org.springframework.aot.hint.annotation.RegisterReflectionForBinding +import org.springframework.context.annotation.Configuration +import se.svt.oss.encore.model.profile.AudioEncode +import se.svt.oss.encore.model.profile.AudioEncoder +import se.svt.oss.encore.model.profile.GenericVideoEncode +import se.svt.oss.encore.model.profile.OutputProducer +import se.svt.oss.encore.model.profile.Profile +import se.svt.oss.encore.model.profile.SimpleAudioEncode +import se.svt.oss.encore.model.profile.ThumbnailEncode +import se.svt.oss.encore.model.profile.ThumbnailMapEncode +import se.svt.oss.encore.model.profile.VideoEncode +import se.svt.oss.encore.model.profile.X264Encode +import se.svt.oss.encore.model.profile.X265Encode +import se.svt.oss.encore.model.profile.X26XEncode + +@RegisterReflectionForBinding( + AudioEncode::class, + AudioEncoder::class, + GenericVideoEncode::class, + OutputProducer::class, + Profile::class, + SimpleAudioEncode::class, + ThumbnailEncode::class, + ThumbnailMapEncode::class, + VideoEncode::class, + X26XEncode::class, + X264Encode::class, + X265Encode::class +) +@Configuration +class ReflectionConfiguration diff --git a/encore-common/src/main/kotlin/se/svt/oss/encore/model/profile/GenericVideoEncode.kt b/encore-common/src/main/kotlin/se/svt/oss/encore/model/profile/GenericVideoEncode.kt index 1091def..ac43b17 100644 --- a/encore-common/src/main/kotlin/se/svt/oss/encore/model/profile/GenericVideoEncode.kt +++ b/encore-common/src/main/kotlin/se/svt/oss/encore/model/profile/GenericVideoEncode.kt @@ -18,7 +18,7 @@ data class GenericVideoEncode( override val format: String, override val codec: String, override val inputLabel: String = DEFAULT_VIDEO_LABEL -) : VideoEncode { +) : VideoEncode() { override val type: String get() = this.javaClass.simpleName } diff --git a/encore-common/src/main/kotlin/se/svt/oss/encore/model/profile/VideoEncode.kt b/encore-common/src/main/kotlin/se/svt/oss/encore/model/profile/VideoEncode.kt index 6a6cead..a99a2e9 100644 --- a/encore-common/src/main/kotlin/se/svt/oss/encore/model/profile/VideoEncode.kt +++ b/encore-common/src/main/kotlin/se/svt/oss/encore/model/profile/VideoEncode.kt @@ -14,18 +14,18 @@ import se.svt.oss.encore.model.output.Output import se.svt.oss.encore.model.output.VideoStreamEncode import se.svt.oss.mediaanalyzer.file.toFractionOrNull -interface VideoEncode : OutputProducer { - val width: Int? - val height: Int? - val twoPass: Boolean - val params: Map - val filters: List? - val audioEncode: AudioEncoder? - val audioEncodes: List - val suffix: String - val format: String - val codec: String - val inputLabel: String +abstract class VideoEncode : OutputProducer { + abstract val width: Int? + abstract val height: Int? + abstract val twoPass: Boolean + abstract val params: Map + abstract val filters: List? + abstract val audioEncode: AudioEncoder? + abstract val audioEncodes: List + abstract val suffix: String + abstract val format: String + abstract val codec: String + abstract val inputLabel: String override fun getOutput(job: EncoreJob, encodingProperties: EncodingProperties): Output? { val audioEncodesToUse = audioEncodes.ifEmpty { listOfNotNull(audioEncode) } @@ -62,7 +62,7 @@ interface VideoEncode : OutputProducer { } } - fun passParams(pass: Int): Map = + open fun passParams(pass: Int): Map = mapOf("pass" to pass.toString(), "passlogfile" to "log$suffix") private fun videoFilter( diff --git a/encore-common/src/main/kotlin/se/svt/oss/encore/model/profile/X26XEncode.kt b/encore-common/src/main/kotlin/se/svt/oss/encore/model/profile/X26XEncode.kt index 6836df6..7196c59 100644 --- a/encore-common/src/main/kotlin/se/svt/oss/encore/model/profile/X26XEncode.kt +++ b/encore-common/src/main/kotlin/se/svt/oss/encore/model/profile/X26XEncode.kt @@ -4,7 +4,7 @@ package se.svt.oss.encore.model.profile -abstract class X26XEncode : VideoEncode { +abstract class X26XEncode : VideoEncode() { abstract val ffmpegParams: LinkedHashMap diff --git a/encore-common/src/test/kotlin/se/svt/oss/encore/model/profile/ProfileJsonTest.kt b/encore-common/src/test/kotlin/se/svt/oss/encore/model/profile/ProfileJsonTest.kt new file mode 100644 index 0000000..875f756 --- /dev/null +++ b/encore-common/src/test/kotlin/se/svt/oss/encore/model/profile/ProfileJsonTest.kt @@ -0,0 +1,57 @@ +package se.svt.oss.encore.model.profile + +import com.fasterxml.jackson.databind.DeserializationFeature +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.dataformat.yaml.YAMLMapper +import com.fasterxml.jackson.module.kotlin.readValue +import org.junit.jupiter.api.Test +import se.svt.oss.encore.model.profile.ProfileAssert.assertThat + +class ProfileJsonTest { + + private val yamlMapper = YAMLMapper().findAndRegisterModules().disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES) + private val objectMapper = ObjectMapper().findAndRegisterModules().disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES) + + @Test + fun testSerializeProgramToJson() { + serializeDeserializeJson(readProfile("/profile/program.yml")) + } + + @Test + fun testSerializeProgramX265ToJson() { + serializeDeserializeJson(readProfile("/profile/program-x265.yml")) + } + + @Test + fun testSerializeProgramToYaml() { + serializeDeserializeYaml(readProfile("/profile/program.yml")) + } + + @Test + fun testSerializeProgramX265ToYaml() { + serializeDeserializeYaml(readProfile("/profile/program-x265.yml")) + } + + private fun serializeDeserializeJson(profile: Profile) { + val pretty = ObjectMapper().findAndRegisterModules().writerWithDefaultPrettyPrinter() + println(pretty.writeValueAsString(profile)) + val serialized = objectMapper.writeValueAsString(profile) + val deserialized: Profile = objectMapper.readValue(serialized, Profile::class.java) + assertThat(deserialized) + .isEqualTo(profile) + } + + private fun serializeDeserializeYaml(profile: Profile) { + val pretty = YAMLMapper().findAndRegisterModules().writerWithDefaultPrettyPrinter() + println(pretty.writeValueAsString(profile)) + val serialized = yamlMapper.writeValueAsString(profile) + val deserialized: Profile = yamlMapper.readValue(serialized, Profile::class.java) + assertThat(deserialized) + .isEqualTo(profile) + } + + private fun readProfile(path: String): Profile = + ProfileJsonTest::class.java.getResourceAsStream(path).use { + yamlMapper.readValue(it) + } +}