How can I generate a multiple period DASH manifest with ffmpeg? - ffmpeg

I am looking to encode a file and generate multiple periods rather than just one period. When I try to run ffmpeg with the below command, the result is a single period with multiple adaptation sets so clearly that is the wrong approach. I had thought by breaking the files by time this might work but apparently not. Any advice would be appreciated:
ffmpeg -i ~/Downloads/turkish-horses.mp4 \
-map 0:v:0 -b:v:1 1000k -ss 0 -t 5 -c:v:1 libx264 -filter:v:1 "scale=640:-1" \
-map 0:v:0 -b:v:2 1000k -ss 5 -c:v:2 libx264 -filter:v:2 "scale=640:-1" \
-map 0:v:0 -b:v:3 3000k -ss 0 -t 5 -c:v:3 libx264 -filter:v:3 "scale=1280:-1" \
-map 0:v:0 -b:v:4 3000k -ss 5 -c:v:4 libx264 -filter:v:4 "scale=1280:-1" \
-map 0:a\?:0 -ss 0 -t 5 -c:a aac -b:a 192k \
-map 0:a\?:0 -ss 5 -c:a aac -b:a 192k \
-use_timeline 1 -use_template 0 \
-adaptation_sets "id=0,streams=0,2 id=1,streams=4 id=2,streams=1,3 id=3,streams=5" \
-f dash output.mpd

Related

How do I enable gpu acceleration in ffmpeg?

my code:
sudo ffmpeg -i rtsp://rtsp.stream/pattern \
-map 0:v:0 -map 0:a:0 -map 0:v:0 -map 0:a:0 -map 0:v:0 -map 0:a:0 \
-c:v h264_cuvid -crf 22 -c:a aac -ar 48000 \
-filter:v:0 scale=w=480:h=360 -maxrate:v:0 600k -b:a:0 500k \
-filter:v:1 scale=w=640:h=480 -maxrate:v:1 1500k -b:a:1 1000k \
-filter:v:2 scale=w=1280:h=720 -maxrate:v:2 3000k -b:a:2 2000k \
-var_stream_map "v:0,a:0,name:360p v:1,a:1,name:480p v:2,a:2,name:720p" \
-preset fast -hls_list_size 10 -threads 0 -f hls \
-hls_time 3 -hls_flags independent_segments \
-master_pl_name "livestream.m3u8" \
-y -vsync 0 -hwaccel cuda "/var/www/livestream-%v.m3u8"
Option hwaccel (use HW accelerated decoding) cannot be applied to output url /var/www/livestream-%v.m3u8 -- you are trying to apply an input option to an output file or vice versa. Move this option before the file it belongs to.
Error parsing options for output file /var/www/livestream-%v.m3u8.
It doesn't work with the above error.
working cpu code:
sudo ffmpeg -i rtsp://rtsp.stream/pattern \
-map 0:v:0 -map 0:a:0 -map 0:v:0 -map 0:a:0 -map 0:v:0 -map 0:a:0 \
-c:v libx264 -crf 22 -c:a aac -ar 48000 \
-filter:v:0 scale=w=480:h=360 -maxrate:v:0 600k -b:a:0 500k \
-filter:v:1 scale=w=640:h=480 -maxrate:v:1 1500k -b:a:1 1000k \
-filter:v:2 scale=w=1280:h=720 -maxrate:v:2 3000k -b:a:2 2000k \
-var_stream_map "v:0,a:0,name:360p v:1,a:1,name:480p v:2,a:2,name:720p" \
-preset fast -hls_list_size 10 -threads 0 -f hls \
-hls_time 3 -hls_flags independent_segments \
-master_pl_name "livestream.m3u8" \
-y "/var/www/livestream-%v.m3u8"
The above operates as a cpu and annoys my cpu. I don't know how to write the command.=
Any ideas?

Video captured from x11grab is not playable in HLS format on Firefox/Safari

I'm trying to produce an HLS playlist from a video file.
It's a file captured from a virtual screen with ffmpeg and x11grab module:
ffmpeg -y -t 10 -copyts -draw_mouse 0 -framerate 24 -f x11grab -thread_queue_size 1024 -i :0 -f pulse -i default -acodec copy /tmp/test_preprocessed.mkv
But when I'm trying to produce HLS from this file, the output seems not correct, as it doesn't play in Firefox/Safari, but does play in Chrome (using hls.js or https://www.hlsplayer.net/ for example)
Original file: https://transfer.sh/y1a6Fv/735171b9-42a1-461a-a118-981119bdf74e_preprocessed.mkv
HLS Playlist generated from this file: https://video-staging-bucket.ams3.digitaloceanspaces.com/c08584ca-4731-4820-b5c7-71f12955c0b2/stackoverflow/playlist.m3u8
(Works in https://www.hlsplayer.net/ with chrome, doesn't works with Firefox/Safari)
How I'm producing the HLS:
ffmpeg -y \
-t 10 \
-i 735171b9-42a1-461a-a118-981119bdf74e_preprocessed.mkv \
-r 24 \
-filter_complex '[0:v]split=3[v1][v2][v3]; [v1]scale=w=1280:h=720[v1out]; [v2]scale=w=854:h=480[v2out]; [v3]scale=w=640:h=360[v3out]' \
-map '[v1out]' -c:v:0 libx264 -x264-params "nal-hrd=cbr:force-cfr=1" -b:v:0 3200k -maxrate:v:0 3200k -minrate:v:0 2500k -bufsize:v:0 3200k -preset slow -g 48 -sc_threshold 0 -keyint_min 48 \
-map '[v2out]' -c:v:1 libx264 -x264-params "nal-hrd=cbr:force-cfr=1" -b:v:1 1600k -maxrate:v:1 1600k -minrate:v:1 1250k -bufsize:v:1 1600k -preset slow -g 48 -sc_threshold 0 -keyint_min 48 \
-map '[v3out]' -c:v:2 libx264 -x264-params "nal-hrd=cbr:force-cfr=1" -b:v:2 900k -maxrate:v:2 900k -minrate:v:2 700k -bufsize:v:2 900k -preset slow -g 48 -sc_threshold 0 -keyint_min 48 \
-map a:0 -c:a:0 aac -b:a:0 96k \
-map a:0 -c:a:1 aac -b:a:1 128k \
-map a:0 -c:a:2 aac -b:a:2 128k \
-f hls \
-hls_time 4 \
-hls_playlist_type vod \
-hls_flags independent_segments \
-hls_segment_type mpegts \
-hls_segment_filename 'hls'/stream_%v_data%02d.ts \
-master_pl_name playlist.m3u8 \
-var_stream_map "v:0,a:0 v:1,a:1 v:2,a:2" \
-t 10 \
'hls'/stream_%v.m3u8
Is there something I missed ? Maybe a standard ? Or maybe problem is related to PTS/DTS of my file ?
Thanks !

Change ffmpeg input while streaming

Is there a way to change ffmpeg input while streaming to rtmp?
I have this bash script
#! /bin/bash
VBR="1500k"
FPS="24"
QUAL="superfast"
RTMP_URL="rtmp://live.live/live"
KEY="xxxxxxxxxxxxxxxxxxxxx"
VIDEO_SOURCE="video.mp4"
AUDIO_SOURCE="song.mp3"
NP_SOURCE="song.txt"
FONT="font.ttf"
ffmpeg \
-re -f lavfi -i "movie=filename=$VIDEO_SOURCE:loop=0, setpts=N/(FRAME_RATE*TB)" \
-thread_queue_size 512 -i "$AUDIO_SOURCE" \
-map 0:v:0 -map 1:a:0 \
-map_metadata:g 1:g \
-vf drawtext="fontsize=25: fontfile=$FONT: \
box=1: boxcolor=black#0.5: boxborderw=20: \
textfile=$NP_SOURCE: reload=1: fontcolor=white#0.8: x=50: y=50" \
-vcodec libx264 -pix_fmt yuv420p -preset $QUAL -r $FPS -g $(($FPS * 2)) -b:v $VBR \
-acodec libmp3lame -ar 44100 -threads 6 -qscale:v 3 -b:a 320000 -bufsize 512k \
-f flv "$RTMP_URL/$KEY"
What i want to do is to be able to change VIDEO_SOURCE on the fly, i was thinking if it's possible to make the input a directory then change the video in that directory on the fly, i'm new to dealing with scripts so i don't know how to do that
This is a complete guess, based on what little I know about how ffmpeg handles interactive input:
while :; do
ffmpeg \
-re -f lavfi -i "movie=filename=$VIDEO_SOURCE:loop=0, setpts=N/(FRAME_RATE*TB)" \
-thread_queue_size 512 -i "$AUDIO_SOURCE" \
-map 0:v:0 -map 1:a:0 \
-map_metadata:g 1:g \
-vf drawtext="fontsize=25: fontfile=$FONT: \
box=1: boxcolor=black#0.5: boxborderw=20: \
textfile=$NP_SOURCE: reload=1: fontcolor=white#0.8: x=50: y=50" \
-vcodec libx264 -pix_fmt yuv420p -preset $QUAL -r $FPS -g $(($FPS * 2)) -b:v $VBR \
-acodec libmp3lame -ar 44100 -threads 6 -qscale:v 3 -b:a 320000 -bufsize 512k \
-f flv "$RTMP_URL/$KEY"
read -p "Next movie?" VIDEO_SOURCE
[ "$VIDEO_SOURCE" = q ] && break
done
ffmpeg should(?) exit if you send q to standard input. Your script will then prompt you for a new value for VIDEO_SOURCE. If you type q again, the loop exits. Otherwise, it restarts ffmpeg with the new video source file.
If this works, you can perhaps adapt it for something closer to your needs.

Understanding ffmpeg map option

I came across the following command in a blog post which creates different quality video streams that are packaged into DASH format via the dash muxer.
ffmpeg -i $VIDEO_IN \
-preset $PRESET_P -keyint_min $GOP_SIZE -g $GOP_SIZE -sc_threshold 0 \
-r $FPS -c:v libx264 -pix_fmt yuv420p -c:a aac -b:a 128k -ac 1 -ar 44100 \
-map v:0 -s:0 $V_SIZE_1 -b:v:0 2M -maxrate:0 2.14M -bufsize:0 3.5M \
-map v:0 -s:1 $V_SIZE_2 -b:v:1 145k -maxrate:1 155k -bufsize:1 220k \
-map v:0 -s:2 $V_SIZE_3 -b:v:2 365k -maxrate:2 390k -bufsize:2 640k \
-map v:0 -s:3 $V_SIZE_4 -b:v:3 730k -maxrate:3 781k -bufsize:3 1278k \
-map v:0 -s:4 $V_SIZE_4 -b:v:4 1.1M -maxrate:4 1.17M -bufsize:4 2M \
-map v:0 -s:5 $V_SIZE_5 -b:v:5 3M -maxrate:5 3.21M -bufsize:5 5.5M \
-map v:0 -s:6 $V_SIZE_5 -b:v:6 4.5M -maxrate:6 4.8M -bufsize:6 8M \
-map v:0 -s:7 $V_SIZE_6 -b:v:7 6M -maxrate:7 6.42M -bufsize:7 11M \
-map v:0 -s:8 $V_SIZE_6 -b:v:8 7.8M -maxrate:8 8.3M -bufsize:8 14M \
-map 0:a \
-init_seg_name init\$RepresentationID\$.\$ext\$ -media_seg_name chunk\$RepresentationID\$-\$Number%05d\$.\$ext\$ \
-use_template 1 -use_timeline 1 \
-seg_duration 4 -adaptation_sets "id=0,streams=v id=1,streams=a" \
-f dash Dash/dash.mpd
The thing I'm struggling to understand is how the maps work. I've read the Map docs but they don't seem to have a comparable example.
Why is -map v:0 used for every video stream?
Why does the first map line operate on stream 0 (e.g. -b:v:0) and the next map line operates on stream 1 (e.g. -b:v:1), etc.
Would really appreciate a breakdown.
Why is -map v:0 used for every video stream?
The correct string should be -map 0:v:0. The file index was omitted and thus implicitly interpreted as file index 0. Such syntax is best avoided.
Why does the first map line operate on stream 0 (e.g. -b:v:0)
Don't think in terms of lines or proximity of options in relation to a map. The 0 in -b:v:0 is part of a stream specifier and targets which output stream to target.
See
What the different between -b:v <target bitrate> and -b <target bitrate> FFmpeg flags?
https://superuser.com/q/1219784/

How to scale and add correct a logo in ffmpeg command?

I am trying to apply a watermark and also to scale it to the current video size via ffmpeg command:
Here is my inital comand that works without watermark
ffmpeg -v 0 -vcodec h264_qsv -i 'udp://#some.ip:1234?fifo_size=1000000&overrun_nonfatal=1&buffer_size=1000000' -vf scale=iw:ih -profile baseline -acodec aac -ac 1 -ar 44100 -ab 64k -deinterlace -vcodec h264_qsv -bufsize 4000k -maxrate 3500k -preset veryfast -vb 2000k -f flv rtmp://127.0.0.1/app/720
Now I tried to add the picture as a watermark. There was a conflict while using with -vf scale=-1:ih*.5, in order to eliminate the problem I used -s 1280x720 to specify the resolution for the video stream, it worked but not properly.
ffmpeg -v 0 -vcodec h264_qsv -i 'udp://#some.ip:1234?fifo_size=1000000&overrun_nonfatal=1&buffer_size=1000000' -i logo.png -filter_complex "overlay=10:10" -s 1280x720 -profile baseline -acodec aac -ac 1 -ar 44100 -ab 64k -deinterlace -vcodec h264_qsv -bufsize 4000k -maxrate 3500k -preset veryfast -vb 2000k -f flv rtmp://some.ip/app/720
The problem:
How can I specify in the ffmpeg command the both sizes of video and logo(watermark) so they don't conflict with each other and they auto adjust like -vf scale=-1:ih*.5 dose.
Thank you!
The scale2ref filter allows one to a video/image stream with reference to the dimensions of another video or image stream
e.g.
ffmpeg -v 0 -vcodec h264_qsv -i 'udp://#some.ip:1234?fifo_size=1000000&overrun_nonfatal=1&buffer_size=1000000' \
-loop 1 -i logo.png \
-filter_complex "[1:v][0:v]scale2ref=iw/8:-1[logo][0v];[0v][logo]overlay=10:10[v]" \
-map "[v]" -map 0:a \
-profile baseline -acodec aac -ac 1 -ar 44100 -ab 64k \
-deinterlace -vcodec h264_qsv -bufsize 4000k -maxrate 3500k \
-preset veryfast -vb 2000k \
-f flv rtmp://some.ip/app/720
Here 1:v - the logo image - is being scaled to 1/8th the width of [0:v], the H.264 stream.
For the command given in the comments:
ffmpeg -v 0 -vcodec h264_qsv -i 'input' \
-loop 1 -i logo.png \
-filter_complex "[0:v]scale=iw:ih[v0]; \
[1:v][v0]scale2ref=iw/8:-1[logo][0v];[0v][logo]overlay=10:10[v]" \
-map "[v]" -map 0:a \
-profile baseline -acodec aac -ac 1 -ar 44100 -ab 64k \
-deinterlace -vcodec h264_qsv -bufsize 4000k -maxrate 3500k \
-preset veryfast -vb 2000k \
-f flv out1 \
-filter_complex "[0:v]scale=-1:ih/2[v0]; \
[1:v][v0]scale2ref=iw/8:-1[logo][0v];[0v][logo]overlay=10:10[v2]" \
-map "[v2]" -map 0:a \
-profile baseline -acodec aac -ac 1 -ar 44100 -ab 64k \
-deinterlace -vcodec h264_qsv -bufsize 4000k -maxrate 2000k \
-preset veryfast -vb 1000k \
-f flv out2 \
-filter_complex "[0:v]scale=-1:ih/4[v0]; \
[1:v][v0]scale2ref=iw/8:-1[logo][0v];[0v][logo]overlay=10:10[v3]" \
-map "[v3]" -map 0:a \
-profile baseline -acodec aac -ac 1 -ar 44100 -ab 64k \
-deinterlace -vcodec h264_qsv -bufsize 4000k -maxrate 1000k \
-preset veryfast -vb 512k \
-f flv out3 \

Resources