FFMPEG subtitle always delay 1 frame - ffmpeg

I encounter problems encoding video that I ripped from DVD, after ripping the video size is around 300MB and it plays well and subtitle sync well, then I want a smaller size for tablet and encode it using ffmpeg and the result is around 100MB but the subtitle will always late for 1 frame
# ffmpeg -i "Original.mkv" -level 5.1 -preset veryslow -tune animation -keyint_min 12 -sc_threshold 45 -bf 8 -b_strategy 2 -refs 16 -qmin 10 -qmax 51 -qcomp 0.6 -direct-pred auto -me_range 24 -me_method umh -subq 10 -trellis 2 -an -sn -vcodec libx264 -crf 28.0 output1.mkv
# ffmpeg -i "Original.mkv" -f wav -| neroAacEnc -ignorelength -lc -q 0.4 -if - -of output2.aac
# mkvmerge -o outputFF.mkv --language "0:jpn" --track-name "0:SmallAnime Encode # CRF 28.0" output1.mkv --no-chapters --language "0:jpn" --track-name "0:2.0 AAC-LC # 0.4" output2.aac -A -D --language "2:eng" --track-name "2:Styled Subtitle (.ass)" "Original.mkv"
In aegis sub, the video looks well which the subtitle appear normally, however when played using MPC, the subtitle always late 1 frame
Aegis show correctly screenshot : http://puu.sh/6N2gy
Play using MPC problems : http://puu.sh/6N38E.jpg
Anyone know why this happens? The ffmpeg uses libx264 video codec and it is configured using bit depth=10. The OS I am using is CentOS 6.4

It's likely a rounding error - it's something that I've encountered too. Aegisub saves subtitles with timecodes (not frame numbers), and it's possible that Aegisub's timecode does not match what FFMPEG considers to be the correct timecode, resulting in the off-by-one frames.
I've experimented with the -itsoffset flag, which allows you to adjust the input file's time offset. With a 23.98 fps input, I was able to find that a delay of 0.045 (using 1/23.98 == 0.0417014178, and some testing) would work with correcting my early subtitles. As a result, I added -itsoffset -0.045 right before my -i input_file to re-sync the subtitles.
For your case, assuming that you have a similar frame rate, you can try ffmpeg -itsoffset 0.045 -i "Original.mkv" ... and see if that prevents your subtitle delay. Note that -itsoffset 0.045 MUST come before the -i FILE argument since itsoffset DELAY argument modifies inputs after it.
More documentation about -itsoffset can be found here.
Alternatively, you can use the Shift Times tool in Aegisub (Timing > Shift Times) and specify a time of 0:00:01.05 to try and correct the timing there... though I just stuck with the -itsoffset flag since it's much easier to experiment on IMO.

Related

Timelapse (1/6 fps) from slo-mo (240 fps) with ffmpeg

I recorded slo-mo video on an iPhone SE (2) by mistake instead of timelapse.
I know there's a lot of answers to this question here, but I'm trying again and again and always something's wrong (like a video that has a correct total no. of frames, but lasts 3 hours and is basically a freeze :D )
My recent command was
ffmpeg -i IMG_2174.MOV -vf framestep=1440,setpts=N/120/TB -c:v libx264
-preset slow -crf 22 -an -r 30 IMG_2174.timelapse.MOV
but it resulted in a one-second-long video, so way over-timelapsed. Should be several seconds IINM. The source video is 30 minutes long #240fps, 17GB.
Thx.
This command seems to do the trick:
ffmpeg -i IMG_2174.MOV -vf framestep=1440,setpts=N/30/TB -c:v libx264 -preset slow -crf 22 -an -r 30 IMG_2174.timelapse.MOV
Here is the explanation for OP's self-answer.
ffmpeg -i IMG_2174.MOV
-vf framestep=1440,setpts=N/30/TB
-r 30 -c:v libx264 -preset slow -crf 22 -an IMG_2174.timelapse.MOV
Given input video at 240 fps cfr:
framestep=1440 keep every 1440th frame, yielding 240/1440 = 1/6 fps
setpts=N/30/TB speeds up the video by x180 (30 / 1/6)
-r 30 output option: match the new pts interval set above
For a vfr video, framestep=1440 likely results in incorrect timing (though on the average correct). For such video, replace the framestep filter with fps=1/6 filter so it picks the frames based on pts rather than frame count.
[edit note: iPhone's slo-mo recording does keep 240fps cfr so the OP's solution is 100% correct, edited down just to mention a vfr-correct approach]

FFMPEG: Youtube streaming quality and speed issues

I am trying to make a reliable stream from my Icecast/Shoutcast servers to Youtube live. The command that I use is:
ffmpeg -v verbose -framerate 30 -loop 1 -i /var/image.jpg -re -i http://127.0.0.1:4700/radio -c:v libx264 -preset ultrafast -b:v 2250k -maxrate 6000k -bufsize 6000k -c:a copy -ab 128k -s 1920x1080 -framerate 30 -g 60 -keyint_min 60 -f flv rtmp://a.rtmp.youtube.com/live2/xxx
As you can see I am using recommended bitrate for Youtube, insert keyframes every 2 seconds and streaming at 30 frames per second.
The stream is working but after running for some time two thing are happening:
FFMPEG speed falls from 1x to something like 0.998x
Youtube starts complaining that video stream speed is slow, markes the quality as bad and sometimes video starts buffering.
Why is this happening? CPU load is normal, connectivity is ok (the stream is running on a 1Gg/s dedicated server).
Since in my example above I am streaming a single image as a logo of the stream I also tried to generate a short 30 seconds video with that image and broadcast that video instead of an image, but that did not help as well.
The command I used for conversion:
ffmpeg -framerate 30 -loop 1 -i /var/image.jpg -c:v libx264 -preset ultrafast -tune stillimage -b:v 2250k -minrate 2250k -maxrate 6000k -bufsize 6000k -framerate 30 -g 60 -keyint_min 60 -t 30 out4.mp4
And broadcast with
ffmpeg -stream_loop -1 -i out4.mp4 -re -i http://127.0.0.1:4700/radio -c:v copy -c:a copy -framerate 30 -g 60 -keyint_min 60 -f flv rtmp://a.rtmp.youtube.com/live2/xxx
ffmpeg version is 4.1.1
Are you sure that your original stream is really keeping up with the wall-clock?
Depending on how it's encoded there are possibilities that it gets heavily skewed. This ultimately leads to buffer under (or overruns if it's too fast) and the player complaining/skipping.
Can you try and dump several hours worth of stream to a file and then stream that with FFmpeg? If that works, then it's a strong indication that your original stream timing (sample rate) is off.
Getting the sample rate right is why professional/expensive sound cards use high precision Quartz-Crystal controlled oscillators. Purely virtual processing (e.g. files get encoded into a stream) can easily get skewed, especially inside virtual machines. Also, cheap USB sound cards are often among the worst offenders in terms of frequency accuracy and stability.
FFmpeg might have an option to deal with too slow input. Keywords could be 'padding' or 'missing samples'.
Youtube's error saying "...buffer....." is not a buffer issue on your PC, but simply data you are sending to youtube is too small.
1)note that [-preset ultrafast] and [-preset fast] does not make big difference.
2) change your ffmpeg comannd for broadcast one. like, [-b:v 2250k] to [-b:v 15000k],and set fps to 12→[-r 12] option.
I's gonna be.
ffmpeg -stream_loop -1 -i out4.mp4 -re -i http://127.0.0.1:4700/radio -preset fast -r 12 -framerate 30 -g 60 -video_track_timescale 1000 -b:v 15000k -f flv rtmp://a.rtmp.youtube.com/live2/xxx
I hope this will be good for you !!(^v^)Y

vframes option ignored in ffmpeg?

I have a directory that contains 2001 PNG files. I can convert all of the frames to an mp4 video using ffmpeg and the following command:
ffmpeg -framerate 60 -start_number 0 \
-i pic.comp2.%07d.png -c:v libx264 -r 30 \
-pix_fmt yuv420p input1ia.mp4
This works fine. However, I am creating a more complicated application that needs to read only the first 1020 files in the directory (specifically 0 thru 1019). Some googling around led me to the -vframes option. My problem is -- it seems to get ignored or at least interpreted differently than I expect.
My modified command looks like:
ffmpeg -framerate 60 -start_number 0 \
-i pic.comp2.%07d.png -vframes 1020 -c:v libx264
-r 30 -pix_fmt yuv420p input1.mp4
It seems like many other people doing the same thing as me do not encounter this issue. So I did some more digging. I tried changing vframes from 1020 to -vframes 20, and this seemed to work properly. So now I am thinking it might be some kind of mismatch between -framerate and -r?
The full resultant video is 33 sec long... which makes sense mathematically.
1 sec
--------- x 2001 frames = 33.35 seconds
60 frames
That's why I thought that specifying ~1/2 of the PNGs as the 'end point' would result in a video of the first ~16-17 seconds. But I always get the full length video from using the -vframes option.
I assume my input to -vframes must be incorrect mathematically, since a small number of frames seems to work. However, I do not understand why.
The most educated guess I can seem to make is that it is reading the PNGs as 60fps (-framerate), but the -r makes the output video 30fps or something? However, then I would assume that the full output video would not be 33 seconds long.
When the input and output rates don't match, ffmpeg drops or duplicate frames as per a regular scheme to achieve the output rate. So, for an input rate of 60 and an output rate of 30, half the frames are dropped. With the vframes option, 1020 frames at a output rate of 30 should produce a video of duration 1020/30 = 34 seconds.
To achieve what you want, use the t option
ffmpeg -framerate 60 -start_number 0 -t 17 \
-i pic.comp2.%07d.png -c:v libx264 -r 30 \
-pix_fmt yuv420p input1ia.mp4
where 17 is number of frames to be used / input rate

ffmpeg keyframe extraction

I have been trying to extract keyframes from video using ffmpeg 0.11.1 . So far all the commands I have tried do not extract keyframes but return all the frames ie 25fps*total time number of frames in the output.
I tried setting the keyint_min as 25 to make sure there is a amximum of 1 keyframe per second.
ffmpeg -vf select="eq(pict_type\,PICT_TYPE_I)" -g 250 -keyint_min 25 -i C:\test.mp4 -vsync 2 -f image2 C:\testTemp\thumbnails-%02d.jpeg
But still all the frames are returned.
Then i tried, to separate the keyframes by 20 seconds.
ffmpeg -i C:\test.mp4 -vf select='eq(pict_type\,I)*(isnan(prev_selected_t)+gte(t-prev_selected_t\,20))' -vsync 0 -f image2 C:\testTemp\%09d.jpg
Again same result, all the frames are returned.
What should I do?
In your first command you are using the filter as an input option. I don't know how ffmpeg will interpret that.
Try this:
ffmpeg -i C:\test.mp4 -vf select='eq(pict_type\,I)',setpts='N/(25*TB)' C:\testTemp\%09d.jpg
Change 25 to the frame rate of your source: 30000/1001 for NTSC video, 24000/1001 for NTSC film, 25 for PAL, etc.
Control output quality with the -q:v or -qscale:v option (just called -qscale in old ffmpeg). Range for mpeg* is 1-31 where 31 is the worst quality.
Next time remember that ffmpeg usage questions are to be asked at superuser.com since stackoverflow is specifically for programming.

Why the converted videos file size is greater than original file size?

I am using ffmpeg to convert the videos into mp4.Its working fine and its playing with high quality.No problem.But the worst case is I uploaded 14Mb file and after converting it goes to 30 Mb file.I am using the following the script to convert
exec("ffmpeg -i videowithaudio.flv -vcodec libx264 -vpre hq -vpre ipod640 -b 250k -bt 50k -acodec libfaac -ab 56k -ac 2 -s 480x320 video_out_file.mp4 > output1.txt 2> apperror1.txt"); //webkit compatible
I am using PHP for executing this command.Could you please help me how to reduce the file size from this 30Mb (nearly to uploaded file size is ok) with same quality.
Files converted from flv to mp4 will always have greater size than the source file. Generally flv files are smaller than other formats, thats why youtube converts all files to flv.
you can use -sameq parameter to retain the quality of video and lesser file size of resulting output file.
Example 1:
ffmpeg -i input.flv -sameq -ar 22050 output.mp4
Example 2:
exec("/usr/bin/ffmpeg -y -i input.flv -acodec libfaac -sameq -ar 44100 -ab 96k -coder ac -me_range 16 -subq 5 -sc_threshold 40 -b 1600k -cmp +chroma -partitions +parti4x4+partp8x8+partb8x8 -i_qfactor 0.71 -keyint_min 25 -b_strategy 1 -g 250 -r 20 output.mp4");
I created this command by searching alot and this fulfills my requirements, using this you can get a bit less file size but with same quality.
Hope this works for you also.
You should try playing around with your key frames rate (-g). Frames between key frames have only the pixels different from the previous key frame. If your key frames are too far apart, all pixels are present in middle frames (increasing size), too close and the number of key frames increases the file size.
Note that the optimal key frame rate will be different for each video, so you need to find a middle ground.
exec("ffmpeg -i videowithaudio.flv -vcodec libx264 -vpre hq -vpre ipod640 -b 250k -bt 50k -acodec libfaac -ab 56k -ac 2 -s 480x320 video_out_file.mp4 > output1.txt 2> apperror1.txt"); //webkit compatible
Important for the filesize, is the bitrate. The bitrate specifies how many bytes to use per second video. If you decrease the bitrate, the filesize will also become smaller.
You are currently using 250kbit/s video (-b 250k) and 56kbit/s audio (-ab 56k), so you have to decrease those numbers. For example you can try :-b 100k -ab 32k. But keep in mind that the quality will also decrease when you decrease the bitrate. If the quality becomes too bad, you can also decrease the framerate or frame size to increase the quality.

Resources