From 6ff34e0ddb1940aeb7b69e4d6b6f35b348a6f541 Mon Sep 17 00:00:00 2001 From: jb-alvarado Date: Sun, 4 Sep 2022 17:07:16 +0200 Subject: [PATCH 1/7] replace timezone with utc offset --- Cargo.lock | 2 +- docs/api.md | 8 ++++---- ffplayout-api/Cargo.toml | 2 +- ffplayout-api/src/utils/handles.rs | 25 ++++++++++++++----------- ffplayout-api/src/utils/mod.rs | 17 +++++++++++++++++ ffplayout-api/src/utils/models.rs | 5 ++++- ffplayout-api/src/utils/routes.rs | 8 ++++---- 7 files changed, 45 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 41911677..f672e953 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -960,7 +960,7 @@ dependencies = [ [[package]] name = "ffplayout-api" -version = "0.5.4" +version = "0.6.0" dependencies = [ "actix-files", "actix-multipart", diff --git a/docs/api.md b/docs/api.md index 020ddcaf..d2b21627 100644 --- a/docs/api.md +++ b/docs/api.md @@ -70,8 +70,8 @@ curl -X GET http://127.0.0.1:8787/api/channel/1 -H "Authorization: Bearer ```BASH curl -X PATCH http://127.0.0.1:8787/api/channel/1 -H "Content-Type: application/json" \ -d '{ "id": 1, "name": "Channel 1", "preview_url": "http://localhost/live/stream.m3u8", \ -"config_path": "/etc/ffplayout/ffplayout.yml", "extra_extensions": "jpg,jpeg,png", "timezone": "Europe/Berlin"}' \ +"config_path": "/etc/ffplayout/ffplayout.yml", "extra_extensions": "jpg,jpeg,png"}' \ -H "Authorization: Bearer " ``` @@ -96,7 +96,7 @@ curl -X PATCH http://127.0.0.1:8787/api/channel/1 -H "Content-Type: application/ curl -X POST http://127.0.0.1:8787/api/channel/ -H "Content-Type: application/json" \ -d '{ "name": "Channel 2", "preview_url": "http://localhost/live/channel2.m3u8", \ "config_path": "/etc/ffplayout/channel2.yml", "extra_extensions": "jpg,jpeg,png", -"timezone": "Europe/Berlin", "service": "ffplayout@channel2.service" }' \ +"service": "ffplayout@channel2.service" }' \ -H "Authorization: Bearer " ``` diff --git a/ffplayout-api/Cargo.toml b/ffplayout-api/Cargo.toml index a3cd863c..b89eb28e 100644 --- a/ffplayout-api/Cargo.toml +++ b/ffplayout-api/Cargo.toml @@ -4,7 +4,7 @@ description = "Rest API for ffplayout" license = "GPL-3.0" authors = ["Jonathan Baecker jonbae77@gmail.com"] readme = "README.md" -version = "0.5.4" +version = "0.6.0" edition = "2021" [dependencies] diff --git a/ffplayout-api/src/utils/handles.rs b/ffplayout-api/src/utils/handles.rs index 6ab132e0..f505b5de 100644 --- a/ffplayout-api/src/utils/handles.rs +++ b/ffplayout-api/src/utils/handles.rs @@ -8,7 +8,7 @@ use simplelog::*; use sqlx::{migrate::MigrateDatabase, sqlite::SqliteQueryResult, Pool, Sqlite, SqlitePool}; use crate::utils::{ - db_path, + db_path, local_utc_offset, models::{Channel, TextPreset, User}, GlobalSettings, }; @@ -40,7 +40,6 @@ async fn create_schema() -> Result { preview_url TEXT NOT NULL, config_path TEXT NOT NULL, extra_extensions TEXT NOT NULL, - timezone TEXT NOT NULL, service TEXT NOT NULL, UNIQUE(name, service) ); @@ -111,8 +110,8 @@ pub async fn db_init(domain: Option) -> Result<&'static str, Box Result { pub async fn db_get_channel(id: &i64) -> Result { let conn = db_connection().await?; let query = "SELECT * FROM channels WHERE id = $1"; - let result: Channel = sqlx::query_as(query).bind(id).fetch_one(&conn).await?; + let mut result: Channel = sqlx::query_as(query).bind(id).fetch_one(&conn).await?; conn.close().await; + result.utc_offset = local_utc_offset(); + Ok(result) } pub async fn db_get_all_channels() -> Result, sqlx::Error> { let conn = db_connection().await?; let query = "SELECT * FROM channels"; - let result: Vec = sqlx::query_as(query).fetch_all(&conn).await?; + let mut results: Vec = sqlx::query_as(query).fetch_all(&conn).await?; conn.close().await; - Ok(result) + for result in results.iter_mut() { + result.utc_offset = local_utc_offset(); + } + + Ok(results) } pub async fn db_update_channel( @@ -171,14 +176,13 @@ pub async fn db_update_channel( ) -> Result { let conn = db_connection().await?; - let query = "UPDATE channels SET name = $2, preview_url = $3, config_path = $4, extra_extensions = $5, timezone = $6 WHERE id = $1"; + let query = "UPDATE channels SET name = $2, preview_url = $3, config_path = $4, extra_extensions = $5 WHERE id = $1"; let result: SqliteQueryResult = sqlx::query(query) .bind(id) .bind(channel.name) .bind(channel.preview_url) .bind(channel.config_path) .bind(channel.extra_extensions) - .bind(channel.timezone) .execute(&conn) .await?; conn.close().await; @@ -189,13 +193,12 @@ pub async fn db_update_channel( pub async fn db_add_channel(channel: Channel) -> Result { let conn = db_connection().await?; - let query = "INSERT INTO channels (name, preview_url, config_path, extra_extensions, timezone, service) VALUES($1, $2, $3, $4, $5, $6)"; + let query = "INSERT INTO channels (name, preview_url, config_path, extra_extensions, service) VALUES($1, $2, $3, $4, $5)"; let result = sqlx::query(query) .bind(channel.name) .bind(channel.preview_url) .bind(channel.config_path) .bind(channel.extra_extensions) - .bind(channel.timezone) .bind(channel.service) .execute(&conn) .await?; diff --git a/ffplayout-api/src/utils/mod.rs b/ffplayout-api/src/utils/mod.rs index 00386ca3..e60ed063 100644 --- a/ffplayout-api/src/utils/mod.rs +++ b/ffplayout-api/src/utils/mod.rs @@ -5,6 +5,7 @@ use std::{ path::Path, }; +use chrono::prelude::*; use faccess::PathExt; use once_cell::sync::OnceCell; use rpassword::read_password; @@ -222,3 +223,19 @@ pub async fn read_log_file(channel_id: &i64, date: &str) -> Result i32 { + let mut offset = Local::now().format("%:z").to_string(); + let operator = offset.remove(0); + let mut utc_offset = 0; + + if let Some((r, f)) = offset.split_once(':') { + utc_offset = r.parse::().unwrap_or(0) * 60 + f.parse::().unwrap_or(0); + + if operator == '-' && utc_offset > 0 { + utc_offset = -utc_offset; + } + } + + utc_offset +} diff --git a/ffplayout-api/src/utils/models.rs b/ffplayout-api/src/utils/models.rs index 0e8fdd1d..df57b73e 100644 --- a/ffplayout-api/src/utils/models.rs +++ b/ffplayout-api/src/utils/models.rs @@ -66,6 +66,9 @@ pub struct Channel { pub preview_url: String, pub config_path: String, pub extra_extensions: String, - pub timezone: String, pub service: String, + + #[sqlx(default)] + #[serde(default)] + pub utc_offset: i32, } diff --git a/ffplayout-api/src/utils/routes.rs b/ffplayout-api/src/utils/routes.rs index 28a41b09..da750d4c 100644 --- a/ffplayout-api/src/utils/routes.rs +++ b/ffplayout-api/src/utils/routes.rs @@ -235,8 +235,8 @@ async fn add_user(data: web::Json) -> Result /// "preview_url": "http://localhost/live/preview.m3u8", /// "config_path": "/etc/ffplayout/ffplayout.yml", /// "extra_extensions": "jpg,jpeg,png", -/// "timezone": "UTC", -/// "service": "ffplayout.service" +/// "service": "ffplayout.service", +/// "utc_offset": "+120" /// } /// ``` #[get("/channel/{id}")] @@ -269,7 +269,7 @@ async fn get_all_channels() -> Result { /// ```BASH /// curl -X PATCH http://127.0.0.1:8787/api/channel/1 -H "Content-Type: application/json" \ /// -d '{ "id": 1, "name": "Channel 1", "preview_url": "http://localhost/live/stream.m3u8", \ -/// "config_path": "/etc/ffplayout/ffplayout.yml", "extra_extensions": "jpg,jpeg,png", "timezone": "Europe/Berlin"}' \ +/// "config_path": "/etc/ffplayout/ffplayout.yml", "extra_extensions": "jpg,jpeg,png"}' \ /// -H "Authorization: Bearer " /// ``` #[patch("/channel/{id}")] @@ -291,7 +291,7 @@ async fn patch_channel( /// curl -X POST http://127.0.0.1:8787/api/channel/ -H "Content-Type: application/json" \ /// -d '{ "name": "Channel 2", "preview_url": "http://localhost/live/channel2.m3u8", \ /// "config_path": "/etc/ffplayout/channel2.yml", "extra_extensions": "jpg,jpeg,png", -/// "timezone": "Europe/Berlin", "service": "ffplayout@channel2.service" }' \ +/// "service": "ffplayout@channel2.service" }' \ /// -H "Authorization: Bearer " /// ``` #[post("/channel/")] From 03aa2f3b01a79c93f650eeba6830be85d1293fec Mon Sep 17 00:00:00 2001 From: jb-alvarado Date: Sun, 4 Sep 2022 17:09:22 +0200 Subject: [PATCH 2/7] update frontend - remove timezone and replace it with utc offset from system - fix bugs related to time and playlist save - add edit button to playlist items - add custom filter to playlist item --- ffplayout-frontend | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ffplayout-frontend b/ffplayout-frontend index 2bc6ce9c..37ccb38b 160000 --- a/ffplayout-frontend +++ b/ffplayout-frontend @@ -1 +1 @@ -Subproject commit 2bc6ce9c32dd2c3bf44b6c174ad78318b26a6531 +Subproject commit 37ccb38b91b34095d06673952a913be3cf79eb0a From a80f474de5f1db08e83f997ab496c95caff8a59f Mon Sep 17 00:00:00 2001 From: jb-alvarado Date: Mon, 5 Sep 2022 17:35:12 +0200 Subject: [PATCH 3/7] update readme --- assets/ffplayout.yml | 11 +++++++---- docs/custom_filters.md | 23 +++++++++++++++++++++++ ffplayout-frontend | 2 +- 3 files changed, 31 insertions(+), 5 deletions(-) diff --git a/assets/ffplayout.yml b/assets/ffplayout.yml index d67e89f7..3191a48e 100644 --- a/assets/ffplayout.yml +++ b/assets/ffplayout.yml @@ -117,10 +117,13 @@ text: out: help_text: The final playout compression. Set the settings to your needs. 'mode' - has the options 'desktop', 'hls', 'null', 'stream'. Use 'stream' and adjust - 'output_param:' settings when you want to stream to a rtmp/rtsp/srt/... server. - In production don't serve hls playlist with ffpapi, use nginx or another web server! - mode: hls + has the options 'desktop', 'hls', 'null', 'stream'. In 'custom_filter' it is possible + to define custom ffmpeg filters. They need to end with [c_v_out] for video filter, + and [c_a_out] for audio filter. Use 'stream' and adjust 'output_param:' settings when + you want to stream to a rtmp/rtsp/srt/... server. In production don't serve hls + playlist with ffpapi, use nginx or another web server! + mode: desktop + custom_filter: output_param: >- -c:v libx264 -crf 23 diff --git a/docs/custom_filters.md b/docs/custom_filters.md index 6a8c9b10..e45e6896 100644 --- a/docs/custom_filters.md +++ b/docs/custom_filters.md @@ -28,3 +28,26 @@ custom_filter: edgedetect=mode=colormix:high=0[c_v_out] Check ffmpeg [filters](https://ffmpeg.org/ffmpeg-filters.html) documentation, and find out which other filters ffmpeg has. +### Where the filters applied in stream mode + +The **custom filter** from **config -> processing** and from **playlist** got applied in the _decoder_ instance on every file: + +``` + +-------------------------------------+ PIPE +------------------------+ +File -> | Decoder / Filtering / custom filter |------------| Encoder / text overlay | -> Output +Loop +-------------------------------------+ +------------------------+ +``` + +The **custom filter** from **config -> out** got applied on the encoder side: + +``` + +---------------------+ PIPE +----------------------------------------+ +File -> | Decoder / Filtering |------------| Encoder / text overlay / custom filter | -> Output +Loop +---------------------+ +----------------------------------------+ +``` + +#### When which one to take + +* If you want to use for every clip a different filter chain, you should use the custom filter parameter from **playlist**. +* When you want to use the same filter for every clip you can use the custom filter from **config -> processing**. +* If you need a global filter for all clips, which has movements, like a animated logo, or different lower thirds, you should use the custom filter from **config -> out**. diff --git a/ffplayout-frontend b/ffplayout-frontend index 37ccb38b..cb208173 160000 --- a/ffplayout-frontend +++ b/ffplayout-frontend @@ -1 +1 @@ -Subproject commit 37ccb38b91b34095d06673952a913be3cf79eb0a +Subproject commit cb20817330c5fd837eec1ae5716aa60f28f2b973 From 09a31cd06be0ac914f41a8c12c617b698c3348fb Mon Sep 17 00:00:00 2001 From: jb-alvarado Date: Mon, 5 Sep 2022 21:32:30 +0200 Subject: [PATCH 4/7] remove info about custom filter in output It works not good together with desktop mode, so it is skipped at the moment. --- assets/ffplayout.yml | 9 +++------ docs/custom_filters.md | 9 --------- ffplayout-frontend | 2 +- 3 files changed, 4 insertions(+), 16 deletions(-) diff --git a/assets/ffplayout.yml b/assets/ffplayout.yml index 3191a48e..573ea462 100644 --- a/assets/ffplayout.yml +++ b/assets/ffplayout.yml @@ -117,13 +117,10 @@ text: out: help_text: The final playout compression. Set the settings to your needs. 'mode' - has the options 'desktop', 'hls', 'null', 'stream'. In 'custom_filter' it is possible - to define custom ffmpeg filters. They need to end with [c_v_out] for video filter, - and [c_a_out] for audio filter. Use 'stream' and adjust 'output_param:' settings when - you want to stream to a rtmp/rtsp/srt/... server. In production don't serve hls - playlist with ffpapi, use nginx or another web server! + has the options 'desktop', 'hls', 'null', 'stream'. Use 'stream' and adjust + 'output_param:' settings when you want to stream to a rtmp/rtsp/srt/... server. + In production don't serve hls playlist with ffpapi, use nginx or another web server! mode: desktop - custom_filter: output_param: >- -c:v libx264 -crf 23 diff --git a/docs/custom_filters.md b/docs/custom_filters.md index e45e6896..fa0b7000 100644 --- a/docs/custom_filters.md +++ b/docs/custom_filters.md @@ -38,16 +38,7 @@ File -> | Decoder / Filtering / custom filter |------------| Encoder / text over Loop +-------------------------------------+ +------------------------+ ``` -The **custom filter** from **config -> out** got applied on the encoder side: - -``` - +---------------------+ PIPE +----------------------------------------+ -File -> | Decoder / Filtering |------------| Encoder / text overlay / custom filter | -> Output -Loop +---------------------+ +----------------------------------------+ -``` - #### When which one to take * If you want to use for every clip a different filter chain, you should use the custom filter parameter from **playlist**. * When you want to use the same filter for every clip you can use the custom filter from **config -> processing**. -* If you need a global filter for all clips, which has movements, like a animated logo, or different lower thirds, you should use the custom filter from **config -> out**. diff --git a/ffplayout-frontend b/ffplayout-frontend index cb208173..37ccb38b 160000 --- a/ffplayout-frontend +++ b/ffplayout-frontend @@ -1 +1 @@ -Subproject commit cb20817330c5fd837eec1ae5716aa60f28f2b973 +Subproject commit 37ccb38b91b34095d06673952a913be3cf79eb0a From 7e3626728cd711e4bc95559a5ef12d12f8dfbf86 Mon Sep 17 00:00:00 2001 From: jb-alvarado Date: Tue, 6 Sep 2022 14:13:20 +0200 Subject: [PATCH 5/7] add complex example --- docs/custom_filters.md | 62 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 56 insertions(+), 6 deletions(-) diff --git a/docs/custom_filters.md b/docs/custom_filters.md index fa0b7000..4a1736b8 100644 --- a/docs/custom_filters.md +++ b/docs/custom_filters.md @@ -26,19 +26,69 @@ Pay attention to the filter prefix `[v_in];`, this is necessary to get the outpu custom_filter: edgedetect=mode=colormix:high=0[c_v_out] ``` -Check ffmpeg [filters](https://ffmpeg.org/ffmpeg-filters.html) documentation, and find out which other filters ffmpeg has. - ### Where the filters applied in stream mode The **custom filter** from **config -> processing** and from **playlist** got applied in the _decoder_ instance on every file: ``` - +-------------------------------------+ PIPE +------------------------+ -File -> | Decoder / Filtering / custom filter |------------| Encoder / text overlay | -> Output -Loop +-------------------------------------+ +------------------------+ + +-------------------------------------------------- + + | file loop | + | +-------------------------------------+ | PIPE +------------------------+ + | input -> | decoder / filtering / custom filter |-------------| encoder / text overlay | -> output + | +-------------------------------------+ | +------------------------+ + | start new on file change | constant output + +---------------------------------------------------+ ``` -#### When which one to take +#### When take which * If you want to use for every clip a different filter chain, you should use the custom filter parameter from **playlist**. * When you want to use the same filter for every clip you can use the custom filter from **config -> processing**. + +### Complex example + +This example takes a image and a animated mov clip with alpha and overlays them two times on different positions in time: + +```YAML +custom_filter: [v_in];movie=image_input.png:s=v,loop=loop=250.0:size=1:start=0,split=2[lower_1_out_1][lower_1_out_2];[lower_1_out_1]fifo,fade=in:duration=0.5:alpha=1,fade=out:start_time=9.5:duration=0.5:alpha=1,setpts=PTS+5.0/TB[fade_1];[v_in][fade_1]overlay=enable=between(t\,5.0\,15.0)[base_1];[lower_1_out_2]fifo,fade=in:duration=0.5:alpha=1,fade=out:start_time=9.5:duration=0.5:alpha=1,setpts=PTS+30.0/TB[fade_2];[base_1][fade_2]overlay=enable=between(t\,30.0\,40.0)[base_2];movie=animated_input.mov:s=v,split=2[lower_2_out_1][lower_2_out_2];[lower_2_out_1]fifo,setpts=PTS+20.0/TB[layer_1];[base_2][layer_1]overlay=repeatlast=0[base_3];[lower_2_out_2]fifo,setpts=PTS+50.0/TB[layer_2];[base_3][layer_2]overlay=repeatlast=0[c_v_out] +``` + +And here are the explanation for each filter: + +```PYTHON + +# get input from video +[v_in]; + +# load the image, loops it for 10 seconds (25 FPS * 10), and splits it into two outputs +movie=image_input.png:s=v,loop=loop=250.0:size=1:start=0,split=2[lower_1_out_1][lower_1_out_2]; + +# take output one from image, fades it in for 0.5 seconds, fades it out for 0.5 seconds, shift the start time to 00:00:05 (5 seconds) +[lower_1_out_1]fifo,fade=in:duration=0.5:alpha=1,fade=out:start_time=9.5:duration=0.5:alpha=1,setpts=PTS+5.0/TB[fade_1]; + +# overlay first output on top of the video, between second 5 and 15 +[v_in][fade_1]overlay=enable=between(t\,5.0\,15.0)[base_1]; + +# take output two from image, fades it in for 0.5 seconds, fades it out for 0.5 seconds, shift the start time to 00:00:30 (30 seconds) +[lower_1_out_2]fifo,fade=in:duration=0.5:alpha=1,fade=out:start_time=9.5:duration=0.5:alpha=1,setpts=PTS+30.0/TB[fade_2]; + +# overlay second output on top of output from last overlay, between second 30 and 40 +[base_1][fade_2]overlay=enable=between(t\,30.0\,40.0)[base_2]; + +# load the animated clip with alpha, splits it into two outputs +movie=animated_input.mov:s=v,split=2[lower_2_out_1][lower_2_out_2]; + +# shift the start from first animated clip to second 20 +[lower_2_out_1]fifo,setpts=PTS+20.0/TB[layer_1]; + +# overlay the shifted animation on top of the last image overlay +[base_2][layer_1]overlay=repeatlast=0[base_3]; + +# shift the start from second animated clip to second 50 +[lower_2_out_2]fifo,setpts=PTS+50.0/TB[layer_2]; + +# overlay the second shifted animation on top of the last overlay +[base_3][layer_2]overlay=repeatlast=0[c_v_out] +``` + +Check ffmpeg [filters](https://ffmpeg.org/ffmpeg-filters.html) documentation, and find out which other filters ffmpeg has and how to apply. From dd161533e1dab86dacdf963ae97abc98d34c5d47 Mon Sep 17 00:00:00 2001 From: jb-alvarado Date: Tue, 6 Sep 2022 14:17:51 +0200 Subject: [PATCH 6/7] add quots --- docs/custom_filters.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/custom_filters.md b/docs/custom_filters.md index 4a1736b8..bdfe549b 100644 --- a/docs/custom_filters.md +++ b/docs/custom_filters.md @@ -50,7 +50,7 @@ The **custom filter** from **config -> processing** and from **playlist** got ap This example takes a image and a animated mov clip with alpha and overlays them two times on different positions in time: ```YAML -custom_filter: [v_in];movie=image_input.png:s=v,loop=loop=250.0:size=1:start=0,split=2[lower_1_out_1][lower_1_out_2];[lower_1_out_1]fifo,fade=in:duration=0.5:alpha=1,fade=out:start_time=9.5:duration=0.5:alpha=1,setpts=PTS+5.0/TB[fade_1];[v_in][fade_1]overlay=enable=between(t\,5.0\,15.0)[base_1];[lower_1_out_2]fifo,fade=in:duration=0.5:alpha=1,fade=out:start_time=9.5:duration=0.5:alpha=1,setpts=PTS+30.0/TB[fade_2];[base_1][fade_2]overlay=enable=between(t\,30.0\,40.0)[base_2];movie=animated_input.mov:s=v,split=2[lower_2_out_1][lower_2_out_2];[lower_2_out_1]fifo,setpts=PTS+20.0/TB[layer_1];[base_2][layer_1]overlay=repeatlast=0[base_3];[lower_2_out_2]fifo,setpts=PTS+50.0/TB[layer_2];[base_3][layer_2]overlay=repeatlast=0[c_v_out] +custom_filter: '[v_in];movie=image_input.png:s=v,loop=loop=250.0:size=1:start=0,split=2[lower_1_out_1][lower_1_out_2];[lower_1_out_1]fifo,fade=in:duration=0.5:alpha=1,fade=out:start_time=9.5:duration=0.5:alpha=1,setpts=PTS+5.0/TB[fade_1];[v_in][fade_1]overlay=enable=between(t\,5.0\,15.0)[base_1];[lower_1_out_2]fifo,fade=in:duration=0.5:alpha=1,fade=out:start_time=9.5:duration=0.5:alpha=1,setpts=PTS+30.0/TB[fade_2];[base_1][fade_2]overlay=enable=between(t\,30.0\,40.0)[base_2];movie=animated_input.mov:s=v,split=2[lower_2_out_1][lower_2_out_2];[lower_2_out_1]fifo,setpts=PTS+20.0/TB[layer_1];[base_2][layer_1]overlay=repeatlast=0[base_3];[lower_2_out_2]fifo,setpts=PTS+50.0/TB[layer_2];[base_3][layer_2]overlay=repeatlast=0[c_v_out]' ``` And here are the explanation for each filter: From 4fdb84614e134f15069922ef1aa956385077f329 Mon Sep 17 00:00:00 2001 From: jb-alvarado Date: Tue, 6 Sep 2022 14:28:28 +0200 Subject: [PATCH 7/7] add scale to filter example --- docs/custom_filters.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/custom_filters.md b/docs/custom_filters.md index bdfe549b..ef3a8717 100644 --- a/docs/custom_filters.md +++ b/docs/custom_filters.md @@ -50,7 +50,7 @@ The **custom filter** from **config -> processing** and from **playlist** got ap This example takes a image and a animated mov clip with alpha and overlays them two times on different positions in time: ```YAML -custom_filter: '[v_in];movie=image_input.png:s=v,loop=loop=250.0:size=1:start=0,split=2[lower_1_out_1][lower_1_out_2];[lower_1_out_1]fifo,fade=in:duration=0.5:alpha=1,fade=out:start_time=9.5:duration=0.5:alpha=1,setpts=PTS+5.0/TB[fade_1];[v_in][fade_1]overlay=enable=between(t\,5.0\,15.0)[base_1];[lower_1_out_2]fifo,fade=in:duration=0.5:alpha=1,fade=out:start_time=9.5:duration=0.5:alpha=1,setpts=PTS+30.0/TB[fade_2];[base_1][fade_2]overlay=enable=between(t\,30.0\,40.0)[base_2];movie=animated_input.mov:s=v,split=2[lower_2_out_1][lower_2_out_2];[lower_2_out_1]fifo,setpts=PTS+20.0/TB[layer_1];[base_2][layer_1]overlay=repeatlast=0[base_3];[lower_2_out_2]fifo,setpts=PTS+50.0/TB[layer_2];[base_3][layer_2]overlay=repeatlast=0[c_v_out]' +custom_filter: '[v_in];movie=image_input.png:s=v,loop=loop=250.0:size=1:start=0,scale=1024:576,split=2[lower_1_out_1][lower_1_out_2];[lower_1_out_1]fifo,fade=in:duration=0.5:alpha=1,fade=out:start_time=9.5:duration=0.5:alpha=1,setpts=PTS+5.0/TB[fade_1];[v_in][fade_1]overlay=enable=between(t\,5.0\,15.0)[base_1];[lower_1_out_2]fifo,fade=in:duration=0.5:alpha=1,fade=out:start_time=9.5:duration=0.5:alpha=1,setpts=PTS+30.0/TB[fade_2];[base_1][fade_2]overlay=enable=between(t\,30.0\,40.0)[base_2];movie=animated_input.mov:s=v,scale=1024:576,split=2[lower_2_out_1][lower_2_out_2];[lower_2_out_1]fifo,setpts=PTS+20.0/TB[layer_1];[base_2][layer_1]overlay=repeatlast=0[base_3];[lower_2_out_2]fifo,setpts=PTS+50.0/TB[layer_2];[base_3][layer_2]overlay=repeatlast=0[c_v_out]' ``` And here are the explanation for each filter: @@ -60,8 +60,8 @@ And here are the explanation for each filter: # get input from video [v_in]; -# load the image, loops it for 10 seconds (25 FPS * 10), and splits it into two outputs -movie=image_input.png:s=v,loop=loop=250.0:size=1:start=0,split=2[lower_1_out_1][lower_1_out_2]; +# load the image, loops it for 10 seconds (25 FPS * 10), scale it to the target resolution, splits it into two outputs +movie=image_input.png:s=v,loop=loop=250.0:size=1:start=0,scale=1024:576,split=2[lower_1_out_1][lower_1_out_2]; # take output one from image, fades it in for 0.5 seconds, fades it out for 0.5 seconds, shift the start time to 00:00:05 (5 seconds) [lower_1_out_1]fifo,fade=in:duration=0.5:alpha=1,fade=out:start_time=9.5:duration=0.5:alpha=1,setpts=PTS+5.0/TB[fade_1]; @@ -75,8 +75,8 @@ movie=image_input.png:s=v,loop=loop=250.0:size=1:start=0,split=2[lower_1_out_1][ # overlay second output on top of output from last overlay, between second 30 and 40 [base_1][fade_2]overlay=enable=between(t\,30.0\,40.0)[base_2]; -# load the animated clip with alpha, splits it into two outputs -movie=animated_input.mov:s=v,split=2[lower_2_out_1][lower_2_out_2]; +# load the animated clip with alpha, scale it to the target resolution, splits it into two outputs +movie=animated_input.mov:s=v,scale=1024:576,split=2[lower_2_out_1][lower_2_out_2]; # shift the start from first animated clip to second 20 [lower_2_out_1]fifo,setpts=PTS+20.0/TB[layer_1];