FFMPEG: Add FrameRate Option Seconds Stream - ffmpeg

I am trying to Copy Two H264 stream into One MP4 File. But I want to set the Framerate for Both H264 stream before copying into One MP4 File. I am able to set FrameRate for First Video H264 Stream. But not able to able to set FrameRate for Seconds Video H264 Stream.
Here are my attempts.
ffmpeg -r:v:0 15 -i 15FPS.h264 -r:v:1 30 -i 30FPS.h264 -c:v:0 copy -c:v:1 copy -map 0 -map 1 hello.mp4
ffmpeg -r:v:0 15 -i 15FPS.h264 -r:v:1 30 -i 30FPS.h264 -c copy -map 0 -map 1 hello.mp4
First H264 Stream in MP4 File is with 15 FPS but For Second Stream FFMPEG takes by default FPS setting with 25 even I specified 30 explicitly.
Can Someone Point me which part is wrong in my command. It would be appreciated.

Your 2nd stream specifier is wrong. It should also be -r:v:0 since -r is a per-file option and raw .h264 can contain only one stream. (So you can drop the specifier altogether)
ffmpeg -r 15 -i 15FPS.h264 -r 30 -i 30FPS.h264 -c copy -map 0 -map 1 hello.mp4

Related

FFMPEG vsync drop and regeneration

According to the ffmpeg documentation
-vsync parameter
Video sync method. For compatibility reasons old values can be specified as numbers. Newly added values will have to be
specified as strings always.
drop
As passthrough but destroys all timestamps, making the muxer
generate fresh timestamps based on frame-rate.
It appears that the mpegts mux does not regenerate the timestamps correctly (PTS/DTS); however, piping the output after vsync drop to a second process as raw h264 does force mpegts to regenerate the PTS.
Generate test stream
ffmpeg -f lavfi -i testsrc=duration=20:size=1280x720:rate=50 -pix_fmt yuv420p -c:v libx264 -b:v 4000000 -x264-params ref=1:bframes=0:vbv-maxrate=4500:vbv-bufsize=4000:nal-hrd=cbr:aud=1:bframes=0:intra-refresh=1:keyint=30:min-keyint=30:scenecut=0 -f mpegts -muxrate 5985920 -pcr_period 20 video.ts -y
Generate output ts that has correctly spaced PTS values
ffmpeg -i video.ts -vsync drop -c:v copy -bsf:v h264_mp4toannexb -f h264 - | ffmpeg -fflags +igndts -fflags +nofillin -fflags +genpts -r 50 -i - -c:v copy -f mpegts -muxrate 5985920 video_all_pts_ok.ts -y
Generate output ts where all PTS are zero
ffmpeg -i video.ts -vsync drop -c:v copy -bsf:v h264_mp4toannexb -f mpegts - | ffmpeg -fflags +igndts -fflags +nofillin -fflags +genpts -r 50 -i - -c:v copy -f mpegts -muxrate 5985920 video_all_pts_zero.ts -y
It appears that vsync drop does destroy them but the mpegts doesn't regenerate them? Any ideas on what needs adding to get it to work as a single ffmpeg command?
Tested on both Linux and Windows with the same result
Try recoding the video just using -vsync 1, without -fflags +genpts. I found some good information here. This guy talking about streaming video. So highest quality isn't his objective. But there is useful info.
https://videoblerg.wordpress.com/2017/11/10/ffmpeg-and-how-to-use-it-wrong/
Section one – Constant frame rate
"-r is used to specify the output frame rate. This must be the same as the input frame rate to eliminate judder. This is used in conjunction with the -vsync parameter using the 1 option which will retime the PTS/DTS timestamps accordingly"
Section six – Audio [Has some good advice too]
"-af "aresample=async=1:min_hard_comp=0.100000:first_pts=0" helps to keep your audio lined up with the beginning of your video. It is common for a container to have the beginning of the video and the beginning of the audio start at different points. By using this your container should have little to no audio drift or offset as it will pad the audio with silence or trim audio with negative PTS timestamps if the audio does not actually start at the beginning of the video."
I haven't tried this yet, no videos with sync problems at the moment.

Convert x265 Video to x264 and copy all audio tracks and subtitles

i am converting x265 video having two audio streams and sutitles too, I am using this command but it create output file without video stream and with one audio stream and one sutitle, so what i am missing here
!ffmpeg -ss 00:03:00 -i "input file x265.mkv" -t 00:00:50 -c:v libx264 -crf 18 -map 0:a -map 0:s -c copy "output file x264.mkv"
You only told it to copy audio and subtitles. Assuming you want all video, audio, and subtitle streams use:
ffmpeg -ss 00:03:00 -i "input file x265.mkv" -t 00:00:50 -map 0 -c copy -c:v libx264 -crf 18 "output file x264.mkv"
-map 0 selects all streams from input file x265.mkv.
-c copy sets stream copy mode for all selected streams.
-c:v libx264 overrides -c copy for all video streams, and encodes all video with libx264.
Result: Stream copy all stream types except video. Encode video to H.264 using encoder libx264.
See FFmpeg Wiki: Map.

FFMPEG reduce fps for live h264 stream with direct copy

I found different articles on changing the fps with ffmpeg but none of them is matching for my exact purposes.
There is an ffmpeg command like below:
ffmpeg -i RTSPCAMERAPRODUCEH264 -c:v copy -an -movflags +frag_keyframe+empty_moov -f mp4
This will remux my camerastream to fragmented mp4 perfectly.
Is there a way to force ffmpeg to lower the FPS to save bandwidth?
I.e. camera streams 30fps, it needs 1Mbps for fmp4 (sample numbers!):
I'd like to know if it's possible to lower the FPS and get an output stream for which 500kbps (50% of original is enough) without re-encoding.
ffmpeg -r 1 -i RTSPCAMERAPRODUCEH264 -c:v copy -an -movflags +frag_keyframe+empty_moov -f mp4
and
ffmpeg -i RTSPCAMERAPRODUCEH264 -c:v copy -an -movflags +frag_keyframe+empty_moov -r 1 -f mp4
do not seem to work.
A temporally coded video stream (like one with H264 codec) cannot arbitrarily drop intermediate packets, so this is not possible. Only whole or trailing part of GOPs may be dropped.

Combine video segments and stream with ffmpeg

FFmpeg can save a video stream to disc as video segments with the following command (source)
ffmpeg -rtsp_transport tcp -reorder_queue_size 8000 -i rtsp://192.168.10.203:554/11 -r 25 -vcodec copy -acodec copy -map 0 -f segment -segment_time 60 -reset_timestamps 1 -segment_format avi "/vidcam2cont/ffmpeg_capture-%03d.avi"
Is there a way to achieve the reverse of this (using FFmpeg or anything else), where I want to merge the video segments and get a continuous video stream?

How can I place a still image before the first frame of a video?

When I encode videos by FFMpeg I would like to put a jpg image before the very first video frame, because when I embed the video on a webpage with "video" html5 tag, it shows the very first picture as a splash image. Alternatively I want to encode an image to an 1 frame video and concatenate it to my encoded video. I don't want to use the "poster" property of the "video" html5 element.
You can use the concat filter to do that. The exact command depends on how long you want your splash screen to be. I am pretty sure you don't want an 1-frame splash screen, which is about 1/25 to 1/30 seconds, depending on the video ;)
The Answer
First, you need to get the frame rate of the video. Try ffmpeg -i INPUT and find the tbr value. E.g.
$ ffmpeg -i a.mkv
ffmpeg version N-62860-g9173602 Copyright (c) 2000-2014 the FFmpeg developers
built on Apr 30 2014 21:42:15 with gcc 4.8 (Ubuntu 4.8.2-19ubuntu1)
[...]
Input #0, matroska,webm, from 'a.mkv':
Metadata:
ENCODER : Lavf55.37.101
Duration: 00:00:10.08, start: 0.080000, bitrate: 23 kb/s
Stream #0:0: Video: h264 (High 4:4:4 Predictive), yuv444p, 320x240 [SAR 1:1 DAR 4:3], 25 fps, 25 tbr, 1k tbn, 50 tbc (default)
At least one output file must be specified
In the above example, it shows 25 tbr. Remember this number.
Second, you need to concatenate the image with the video. Try this command:
ffmpeg -loop 1 -framerate FPS -t SECONDS -i IMAGE \
-t SECONDS -f lavfi -i aevalsrc=0 \
-i INPUTVIDEO \
-filter_complex '[0:0] [1:0] [2:0] [2:1] concat=n=2:v=1:a=1' \
[OPTIONS] OUTPUT
If your video doesn't have audio, try this:
ffmpeg -loop 1 -framerate FPS -t SECONDS -i IMAGE \
-i INPUTVIDEO \
-filter_complex '[0:0] [1:0] concat=n=2:v=1:a=0' \
[OPTIONS] OUTPUT
FPS = tbr value got from step 1
SECONDS = duration you want the image to be shown.
IMAGE = the image name
INPUTVIDEO = the original video name
[OPTIONS] = optional encoding parameters (such as -vcodec libx264 or -b:a 160k)
OUTPUT = the output video file name
How Does This Work?
Let's split the command line I used:
-loop 1 -framerate FPS -t SECONDS -i IMAGE: this basically means: open the image, and loop over it to make it a video with SECONDS seconds with FPS frames per second. The reason you need it to have the same FPS as the input video is because the concat filter we will use later has a restriction on it.
-t SECONDS -f lavfi -i aevalsrc=0: this means: generate silence for SECONDS (0 means silence). You need silence to fill up the time for the splash image. This isn't needed if the original video doesn't have audio.
-i INPUTVIDEO: open the video itself.
-filter_complex '[0:0] [1:0] [2:0] [2:1] concat=n=2:v=1:a=1': this is the best part. You open file 0 stream 0 (the image-video), file 1 stream 0 (the silence audio), file 2 streams 0 and 1 (the real input audio and video), and concatenate them together. The options n, v, and a mean that there are 2 segments, 1 output video, and 1 output audio.
[OPTIONS] OUTPUT: this just means to encode the video to the output file name. If you are using HTML5 streaming, you'd probably want to use -c:v libx264 -crf 23 -c:a libfdk_aac (or -c:a libfaac) -b:a 128k for H.264 video and AAC audio.
Further information
You can check out the documentation for the image2 demuxer which is the core of the magic behind -loop 1.
Documentation for concat filter is also helpful.
Another good source of information is the FFmpeg wiki on concatenation.
The answer above works for me but in my case it took too much time to execute (perhaps because it re-encodes the entire video). I found another solution that's much faster. The basic idea is:
Create a "video" that only has the image.
Concatenate the above video with the original one, without re-encoding.
Create a video that only has the image:
ffmpeg -loop 1 -framerate 30 -i image.jpg -c:v libx264 -t 3 -pix_fmt yuv420p image.mp4
Note the -framerate 30 option. It has to be the same with the main video. Also, the image should have the same dimension with the main video. The -t 3 specifies the length of the video in seconds.
Convert the videos to MPEG-2 transport stream
According to the ffmpeg official documentation, only certain files can be concatenated using the concat protocal, this includes the MPEG-2 transport streams. And since we have 2 MP4 videos, they can be losslessly converted to MPEG-2 TS:
ffmpeg -i image.mp4 -c copy -bsf:v h264_mp4toannexb -f mpegts image.ts
and for the main video:
ffmpeg -i video.mp4 -c copy -bsf:v h264_mp4toannexb -f mpegts video.ts
Concatenate the MPEG-2 TS files
Now use the following command to concatenate the above intermediate files:
ffmpeg -i "concat:image.ts|video.ts" -c copy -bsf:a aac_adtstoasc output.mp4
Although there are 4 commands to run, combined they're still much faster then re-encoding the entire video.
My solution. It sets an image with duration of 5 sec before the video along with aligning video to be 1280x720. Image should have 16/9 aspect ratio.
ffmpeg -i video.mp4 -i image.png -filter_complex '
color=c=black:size=1280x720 [temp]; \
[temp][1:v] overlay=x=0:y=0:enable='between(t,0,5)' [temp]; \
[0:v] setpts=PTS+5/TB, scale=1280x720:force_original_aspect_ratio=decrease, pad=1280:720:-1:-1:color=black [v:0]; \
[temp][v:0] overlay=x=0:y=0:shortest=1:enable='gt(t,5)' [v]; \
[0:a] asetpts=PTS+5/TB [a]'
-map [v] -map [a] -preset veryfast output.mp4

Resources