Upgrade to OPENRNDR 0.4 snapshot
This commit is contained in:
128
orx-jvm/orx-video-profiles/README.md
Normal file
128
orx-jvm/orx-video-profiles/README.md
Normal file
@@ -0,0 +1,128 @@
|
||||
# orx-video-profiles
|
||||
|
||||
A collection of `VideoWriterProfile` implementations that can be used with `ScreenRecorder` and `VideoWriter`
|
||||
|
||||
## Usage
|
||||
|
||||
### GIF
|
||||
|
||||
```
|
||||
import org.openrndr.application
|
||||
import org.openrndr.color.ColorRGBa
|
||||
import org.openrndr.extra.videoprofiles.*
|
||||
import org.openrndr.ffmpeg.ScreenRecorder
|
||||
|
||||
fun main() = application {
|
||||
program {
|
||||
extend(ScreenRecorder()) {
|
||||
profile = GIFProfile()
|
||||
}
|
||||
extend {
|
||||
drawer.clear(ColorRGBa.GREEN)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Later use `gifsicle` or similar to further reduce file size. For example:
|
||||
|
||||
```
|
||||
$ gifsicle --loop --delay=4 --colors 16 --optimize=2 heavy.gif >lessheavy.gif
|
||||
```
|
||||
|
||||
More about [gifsicle](http://www.lcdf.org/gifsicle/).
|
||||
|
||||
### PNG sequence
|
||||
|
||||
This profile requires specifying a file name: `outputFile = "frame-%05d.png"`,
|
||||
where `%05d` means "zero-padded five-digit frame number".
|
||||
The frame number format is not optional.
|
||||
|
||||
```
|
||||
import org.openrndr.application
|
||||
import org.openrndr.color.ColorRGBa
|
||||
import org.openrndr.extra.videoprofiles.*
|
||||
import org.openrndr.ffmpeg.ScreenRecorder
|
||||
|
||||
fun main() = application {
|
||||
program {
|
||||
extend(ScreenRecorder()) {
|
||||
profile = PNGProfile()
|
||||
outputFile = "frame-%05d.png"
|
||||
}
|
||||
extend {
|
||||
drawer.clear(ColorRGBa.GREEN)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Animated Webp
|
||||
|
||||
```
|
||||
import org.openrndr.application
|
||||
import org.openrndr.color.ColorRGBa
|
||||
import org.openrndr.extra.videoprofiles.*
|
||||
import org.openrndr.ffmpeg.ScreenRecorder
|
||||
|
||||
fun main() = application {
|
||||
program {
|
||||
extend(ScreenRecorder()) {
|
||||
profile = WebpProfile()
|
||||
}
|
||||
extend {
|
||||
drawer.clear(ColorRGBa.GREEN)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### Prores (large file, high quality video)
|
||||
|
||||
```
|
||||
import org.openrndr.application
|
||||
import org.openrndr.color.ColorRGBa
|
||||
import org.openrndr.extra.videoprofiles.*
|
||||
import org.openrndr.ffmpeg.ScreenRecorder
|
||||
|
||||
fun main() = application {
|
||||
program {
|
||||
extend(ScreenRecorder()) {
|
||||
// .apply is optional, for further configuration
|
||||
profile = ProresProfile().apply {
|
||||
profile = ProresProfile.Profile.HQ4444
|
||||
codec = "prores_ks"
|
||||
}
|
||||
}
|
||||
extend {
|
||||
drawer.clear(ColorRGBa.GREEN)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### X265
|
||||
|
||||
```
|
||||
import org.openrndr.application
|
||||
import org.openrndr.color.ColorRGBa
|
||||
import org.openrndr.extra.videoprofiles.*
|
||||
import org.openrndr.ffmpeg.ScreenRecorder
|
||||
|
||||
fun main() = application {
|
||||
program {
|
||||
extend(ScreenRecorder()) {
|
||||
// .apply is optional, for further configuration
|
||||
profile = X265Profile().apply {
|
||||
mode(X265Profile.WriterMode.Lossless)
|
||||
constantRateFactor(23)
|
||||
hlg = true
|
||||
}
|
||||
}
|
||||
extend {
|
||||
drawer.clear(ColorRGBa.GREEN)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
19
orx-jvm/orx-video-profiles/build.gradle
Normal file
19
orx-jvm/orx-video-profiles/build.gradle
Normal file
@@ -0,0 +1,19 @@
|
||||
sourceSets {
|
||||
demo {
|
||||
java {
|
||||
srcDirs = ["src/demo/kotlin"]
|
||||
compileClasspath += main.getCompileClasspath()
|
||||
runtimeClasspath += main.getRuntimeClasspath()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
demoImplementation("org.openrndr:openrndr-application:$openrndrVersion")
|
||||
demoImplementation("org.openrndr:openrndr-extensions:$openrndrVersion")
|
||||
demoImplementation("org.openrndr:openrndr-ffmpeg:$openrndrVersion")
|
||||
demoRuntimeOnly("org.openrndr:openrndr-gl3:$openrndrVersion")
|
||||
demoRuntimeOnly("org.openrndr:openrndr-gl3-natives-$openrndrOS:$openrndrVersion")
|
||||
implementation("org.openrndr:openrndr-ffmpeg:$openrndrVersion")
|
||||
demoImplementation(sourceSets.getByName("main").output)
|
||||
}
|
||||
16
orx-jvm/orx-video-profiles/src/demo/kotlin/DemoGIF01.kt
Normal file
16
orx-jvm/orx-video-profiles/src/demo/kotlin/DemoGIF01.kt
Normal file
@@ -0,0 +1,16 @@
|
||||
import org.openrndr.application
|
||||
import org.openrndr.color.ColorRGBa
|
||||
import org.openrndr.extra.videoprofiles.GIFProfile
|
||||
import org.openrndr.extra.videoprofiles.ProresProfile
|
||||
import org.openrndr.ffmpeg.ScreenRecorder
|
||||
|
||||
suspend fun main() = application {
|
||||
program {
|
||||
extend(ScreenRecorder()) {
|
||||
profile = GIFProfile()
|
||||
}
|
||||
extend {
|
||||
drawer.clear(ColorRGBa.GREEN)
|
||||
}
|
||||
}
|
||||
}
|
||||
15
orx-jvm/orx-video-profiles/src/demo/kotlin/DemoProres01.kt
Normal file
15
orx-jvm/orx-video-profiles/src/demo/kotlin/DemoProres01.kt
Normal file
@@ -0,0 +1,15 @@
|
||||
import org.openrndr.application
|
||||
import org.openrndr.color.ColorRGBa
|
||||
import org.openrndr.extra.videoprofiles.ProresProfile
|
||||
import org.openrndr.ffmpeg.ScreenRecorder
|
||||
|
||||
suspend fun main() = application {
|
||||
program {
|
||||
extend(ScreenRecorder()) {
|
||||
profile = ProresProfile()
|
||||
}
|
||||
extend {
|
||||
drawer.clear(ColorRGBa.GREEN)
|
||||
}
|
||||
}
|
||||
}
|
||||
19
orx-jvm/orx-video-profiles/src/demo/kotlin/DemoTIFF01.kt
Normal file
19
orx-jvm/orx-video-profiles/src/demo/kotlin/DemoTIFF01.kt
Normal file
@@ -0,0 +1,19 @@
|
||||
import org.openrndr.application
|
||||
import org.openrndr.color.ColorRGBa
|
||||
import org.openrndr.extra.videoprofiles.TIFFProfile
|
||||
import org.openrndr.ffmpeg.ScreenRecorder
|
||||
|
||||
suspend fun main() = application {
|
||||
program {
|
||||
extend(ScreenRecorder()) {
|
||||
profile = TIFFProfile()
|
||||
outputFile = "frame-%05d.tif"
|
||||
maximumFrames = 20
|
||||
}
|
||||
extend {
|
||||
drawer.clear(ColorRGBa.GREEN)
|
||||
drawer.fill = ColorRGBa.WHITE
|
||||
drawer.rectangle(frameCount / 20.0 * width, 0.0, 100.0, 100.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
10
orx-jvm/orx-video-profiles/src/main/kotlin/GIFProfile.kt
Normal file
10
orx-jvm/orx-video-profiles/src/main/kotlin/GIFProfile.kt
Normal file
@@ -0,0 +1,10 @@
|
||||
package org.openrndr.extra.videoprofiles
|
||||
import org.openrndr.ffmpeg.VideoWriterProfile
|
||||
|
||||
class GIFProfile : VideoWriterProfile() {
|
||||
override val fileExtension = "gif"
|
||||
|
||||
override fun arguments(): Array<String> {
|
||||
return arrayOf("-vf", "split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse=dither=none:diff_mode=rectangle,vflip")
|
||||
}
|
||||
}
|
||||
16
orx-jvm/orx-video-profiles/src/main/kotlin/PNGProfile.kt
Normal file
16
orx-jvm/orx-video-profiles/src/main/kotlin/PNGProfile.kt
Normal file
@@ -0,0 +1,16 @@
|
||||
package org.openrndr.extra.videoprofiles
|
||||
import org.openrndr.ffmpeg.VideoWriterProfile
|
||||
|
||||
/**
|
||||
* This profile requires specifying a file name like this
|
||||
* outputFile = "frame-%05d.png"
|
||||
* where `%05d` means "zero-padded five-digit frame number".
|
||||
* The frame number format is not optional.
|
||||
*/
|
||||
class PNGProfile : VideoWriterProfile() {
|
||||
override val fileExtension = "png"
|
||||
|
||||
override fun arguments(): Array<String> {
|
||||
return arrayOf("-vf", "vflip")
|
||||
}
|
||||
}
|
||||
25
orx-jvm/orx-video-profiles/src/main/kotlin/ProresProfile.kt
Normal file
25
orx-jvm/orx-video-profiles/src/main/kotlin/ProresProfile.kt
Normal file
@@ -0,0 +1,25 @@
|
||||
package org.openrndr.extra.videoprofiles
|
||||
|
||||
import org.openrndr.ffmpeg.VideoWriterProfile
|
||||
|
||||
class ProresProfile : VideoWriterProfile() {
|
||||
enum class Profile(val argument:String) {
|
||||
PROXY("0"),
|
||||
LT("1"),
|
||||
SQ("2"),
|
||||
HQ("3"),
|
||||
HQ4444("4444")
|
||||
}
|
||||
|
||||
override val fileExtension: String = "mov"
|
||||
var profile = Profile.SQ
|
||||
var codec = "prores_ks"
|
||||
|
||||
override fun arguments(): Array<String> {
|
||||
val vcodec = arrayOf("-vcodec", codec)
|
||||
val profile = arrayOf("-profile:v", profile.argument)
|
||||
val filters = arrayOf("-vf", "vflip")
|
||||
val audio = arrayOf("-an")
|
||||
return vcodec + profile + filters + audio
|
||||
}
|
||||
}
|
||||
16
orx-jvm/orx-video-profiles/src/main/kotlin/TIFFProfile.kt
Normal file
16
orx-jvm/orx-video-profiles/src/main/kotlin/TIFFProfile.kt
Normal file
@@ -0,0 +1,16 @@
|
||||
package org.openrndr.extra.videoprofiles
|
||||
import org.openrndr.ffmpeg.VideoWriterProfile
|
||||
|
||||
/**
|
||||
* This profile requires specifying a file name like this
|
||||
* outputFile = "frame-%05d.tif"
|
||||
* where `%05d` means "zero-padded five-digit frame number".
|
||||
* The frame number format is not optional.
|
||||
*/
|
||||
class TIFFProfile : VideoWriterProfile() {
|
||||
override val fileExtension = "tif"
|
||||
|
||||
override fun arguments(): Array<String> {
|
||||
return arrayOf("-vf", "vflip")
|
||||
}
|
||||
}
|
||||
10
orx-jvm/orx-video-profiles/src/main/kotlin/WebpProfile.kt
Normal file
10
orx-jvm/orx-video-profiles/src/main/kotlin/WebpProfile.kt
Normal file
@@ -0,0 +1,10 @@
|
||||
package org.openrndr.extra.videoprofiles
|
||||
import org.openrndr.ffmpeg.VideoWriterProfile
|
||||
|
||||
class WebpProfile : VideoWriterProfile() {
|
||||
override val fileExtension = "webp"
|
||||
|
||||
override fun arguments(): Array<String> {
|
||||
return arrayOf("-vf", "vflip")
|
||||
}
|
||||
}
|
||||
60
orx-jvm/orx-video-profiles/src/main/kotlin/X265Profile.kt
Normal file
60
orx-jvm/orx-video-profiles/src/main/kotlin/X265Profile.kt
Normal file
@@ -0,0 +1,60 @@
|
||||
package org.openrndr.extra.videoprofiles
|
||||
import org.openrndr.ffmpeg.VideoWriterProfile
|
||||
|
||||
class X265Profile : VideoWriterProfile() {
|
||||
internal var mode = WriterMode.Normal
|
||||
internal var constantRateFactor = 28
|
||||
var hlg = false
|
||||
|
||||
enum class WriterMode {
|
||||
Normal,
|
||||
Lossless
|
||||
}
|
||||
|
||||
fun mode(mode: WriterMode): X265Profile {
|
||||
this.mode = mode
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the constant rate factor
|
||||
* @param constantRateFactor the constant rate factor (default is 28)
|
||||
* @return
|
||||
*/
|
||||
fun constantRateFactor(constantRateFactor: Int): X265Profile {
|
||||
this.constantRateFactor = constantRateFactor
|
||||
return this
|
||||
}
|
||||
|
||||
override val fileExtension = "mp4"
|
||||
|
||||
|
||||
override fun arguments(): Array<String> {
|
||||
when (mode) {
|
||||
WriterMode.Normal -> {
|
||||
return if (!hlg) {
|
||||
arrayOf("-pix_fmt", "yuv420p", // this will produce videos that are playable by quicktime
|
||||
"-vf", "vflip",
|
||||
"-an", "-vcodec", "libx265", "-crf", "" + constantRateFactor)
|
||||
} else {
|
||||
arrayOf( // this will produce videos that are playable by quicktime
|
||||
"-an", "" +
|
||||
"-vcodec", "libx265",
|
||||
"-pix_fmt", "yuv420p10le",
|
||||
"-color_primaries", "bt2020",
|
||||
"-colorspace", "bt2020_ncl",
|
||||
"-color_trc", "arib-std-b67",
|
||||
"-crf", "" + constantRateFactor)
|
||||
// transfer=arib-std-b67
|
||||
}
|
||||
}
|
||||
WriterMode.Lossless -> {
|
||||
return arrayOf("-pix_fmt", "yuv420p10", // this will produce videos that are playable by quicktime
|
||||
"-an", "-vcodec", "libx265", "-preset", "ultrafast")
|
||||
}
|
||||
else -> {
|
||||
throw RuntimeException("unsupported write mode")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user