ffmpeg strftime no effect on windows - ffmpeg

I'm trying to auto mark the output file with timestamps with ffmpeg. Here's my test cmd:
.\ffmpeg.exe -y -loglevel 99 -i test.mp3 -strftime 1 %Y.ogg
I expected a file named 2020.ogg, however only got %Y.ogg. In another word, output filename is not processed by strftime(). I'm using powershell so there should be no relation with cmd's %% escaping.
Here's the output: https://pastebin.com/LUVh2kFA I'm using static builds from https://ffmpeg.zeranoe.com (Thanks Zeranoe!) I confirmed that the problem exists in v4.2.2 and git-20200515. Is there any chance to fix it or am I doing it wrong?

-strftime is not a general option and is only supported by certain muxers. A workaround is to use the segment muxer and to provide a -segment_time longer than the expected output duration:
ffmpeg -i input.mp3 -f segment -strftime 1 -segment_time 10:00:00 %Y.ogg

Related

Calculate VMAF score while encoding a video with FFmpeg

I have an ffmpeg version built with VMAF library. I can use it to calculate the VMAF scores of a distorted video against a reference video using commands like this:
ffmpeg -i distorted.mp4 -i original.mp4 -filter_complex "[0:v]scale=640:480:flags=bicubic[main];[main][1:v]libvmaf=model_path=model/vmaf_v0.6.1.json:log_path=log.json" -f null -
Now, I remember there was a way to get VMAF scores while performing regular ffmpeg encoding. How can I do that at the same time?
I want to encode a video like this, while also calulate the VMAF of the output file:
ffmpeg -i original.mp4 -crf 27 -s 640x480 out.mp4
[edited]
Alright, scratch what I said earlier...
You should be able to use [the `tee` muxer](http://ffmpeg.org/ffmpeg-formats.html#tee-1) to save the file and pipe the encoded frames to another ffmpeg process. Something like this should work for you:
ffmpeg -i original.mp4 -crf 27 -s 640x480 -f tee "out.mp4 | [f=mp4]-" \
| ffmpeg -i - -i original.mp4 -filter_complex ...
(make them into 2 lines and remove \ for Windows)
Here is what works on my Windows PC (thanks to #Rotem for his help)
ffmpeg -i in.mp4 -vcodec libx264 -crf 27 -f nut pipe:
|
ffmpeg -i in.mp4 -f nut -i pipe:
-filter_complex "[0:v][1:v]libvmaf=log_fmt=json:log_path=log.json,nullsink"
-map 1 -c copy out.mp4
The main issue that #Rotem and I missed is that we need to terminate the libvmaf's output. Also, h264 raw format does not carry header info, and using `nut alleviates that issue.
There are a couple caveats:
testing with the testsrc example that #Rotem suggested in the comment below does not produce any libvmaf log, at least as far as I can see, but in debug mode, you can see the filter is getting initialized.
You'll likely see [nut # 0000026b123afb80] Thread message queue blocking; consider raising the thread_queue_size option (current value: 8) message in the log. This just means that the frames are piped in faster than the 2nd ffmpeg is processing. FFmpeg does block on both ends, so no info should be lost.
For the full disclosure, I posted my Python test script on GitHub. It just runs the shell command, so it should be easy to follow even if you don't do Python.

ffmpeg -ss then apply filter then concat producing timestamp errors

Using ffmpeg, I have split a file into multiple parts using -ss. Then I apply a filter to some of the files, then concat the files back together. When I do that, I get: Non-monotonous DTS in output stream 0:0; previous: 341334, current: 340526; changing to 341335. This may result in incorrect timestamps in the output file. The output file plays, but there are noticeable skips where the files are joined.
Here's how I am splitting the file:
ffmpeg -i full_source.mp4 -ss 0 -to 14.264250 -c copy 01-plain.mp4
ffmpeg -i full_source.mp4 -ss 14.264250 -to 18.435083 -c copy 01-filtered.mp4
ffmpeg -i full_source.mp4 -ss 18.435083 -to 29.988292 -c copy 02-plain.mp4
ffmpeg -i full_source.mp4 -ss 29.988292 -to 31.865167 -c copy 02-filtered.mp4
...
ffmpeg -i full_source.mp4 -ss 0 -to 14.264250 -c copy 10-plain.mp4
ffmpeg -i full_source.mp4 -ss 234.484203 -to 300.000 -c copy 10-filtered.mp4
Then I apply a different drawtext filter on each of the 10 filtered files and save them with a new name, like:
ffmpeg -hide_banner -loglevel warning -y -i 01-filtered.mp4 -filter_complex "drawtext=fontfile=calibri.ttf:fontsize=24:fontcolor=white:x=300:y=500:text='hello world'" -crf 15 01-filtered-complete.mp4
Finally, I join all of the plain and complete files back together like this:
ffmpeg -f concat -safe 0 -i mylist.txt -c:a copy -c:v copy outfile.mp4
And that's where the timing error comes in. I've tried adding -vsync drop in the concat command, but that didn't really work either. Same version of ffmpeg does the split, the filter, and the concat. I've tried different versions, everything from 20170519 to one from May 2020 with the same result. Always making sure that all three steps are done by the same version of ffmpeg.
The only thing I can see is that ffprobe shows a duration of 14.27 for 01-plain.mp4 when it should be 14.264250. All of the other files show a similar rounding difference. The files are 23.98 fps. If I do all of my filters in really long command without splitting the file, I can use the more precise numbers with no problem. It just takes 10 times as long. This is all scripted, it happens a couple of hundred times a day and time is money, so I can't take 10 times as long to do each file.
Any ideas? Thanks in advance!

How to automatically add date to output file generated in ffmpeg?

I am using Terminal to run ffmpeg commands (Mac OS) in order to record radio shows streamed online. The stream is in m3u8 I want to output it in mp3. So far so good, I am able to achieve that. However, I'd like the output file to read YYYYMMDD-fm93-segal.mp3 where YYYYMMMDD are the date the recording was made.
I am not able to achieve this using -strftime 1 for some reason. When using my code, the output file reads %Y%m&d-fm93-segal.mp3 instead of replacing the strings by the real date.
Here is the line I'm using:
ffmpeg -i "https://cogecomedia.leanstream.co/cogecomedia/CJMFFM.stream/playlist.m3u8" -acodec mp3 -strftime 1 "%Y%m%d-fm93-segal.mp3"
Anyone knows why and could help me with that?
-strftime is not a generic option, but is only supported by some muxers: hls, image, segment.
One method is to use the segment muxer and give it a big -segment_time value if desired:
ffmpeg -i "https://cogecomedia.leanstream.co/cogecomedia/CJMFFM.stream/playlist.m3u8" -f segment -segment_time 24:00:00 -acodec mp3 -strftime 1 "%Y%m%d-fm93-segal.mp3"

ffmpeg capture current frame and overwrite the image output file

I am trying to extract the image file from a RTSP stream url every second (could be every 1 min also) and overwrite this image file.
my below code works but it outputs to multiple image jpg files: img1.jpg, img2.jpg, img3.jpg...
ffmpeg -i rtsp://IP_ADDRESS/live.sdp -f image2 -r 1 img%01d.jpg
How to use ffmpeg or perhaps bash scripts in Linux to overwrite the same image file while continuously extract the image at a NOT high frequecy, say 1 min or 10 sec?
To elaborate a bit on the already accepted answer from pragnesh,
FFmpeg
As stated in the ffmpeg documentation:
ffmpeg command line options are specified as
ffmpeg [global_options] {[input_options] -i input_file} ... {[output_options] output_file} ...
So
ffmpeg -i rtsp://<rtsp_source_addr> -f image2 -update 1 img.jpg
Uses output option -f image2 , force output format to image2 format, as part of the muxer stage.
Note that in ffmpeg, if the output file name specifies an image format the image2 muxer will be used by default, so the command could be shortened to:
ffmpeg -i rtsp://<rtsp_source_addr> -update 1 img.jpg
The image2 format muxer expects a filename pattern, such as img%01d.jpg to produce a sequentially numbered series of files. If the update option is set to 1, the filename will be interpreted as just a filename, not a pattern, thereby overwriting the same file.
Using the -r , set frame rate, video option works, but generated me a whole lot of dropping frame messages which was bugging me.
Thanks to another answer on the same topic, I found the fps Video Filter to do a better job.
So my version of the working command is
ffmpeg -i rtsp://<rtsp_source_addr> -vf fps=fps=1/20 -update 1 img.jpg
For some reason still unkown to me the minimum framerate I can achieve from my feed is 1/20 or 0.05.
There also exists the video filter thumbnail, which selects an image from a series of frames but this is more processing intensive and therefore I would not recommend it.
Most of this and more I found on the FFMpeg Online Documentation
AVconv
For those of you who use avconv it is very similar. They are after all forks of what was once a common library. The AVconv image2 documentation is found here.
avconv -i rtsp://<rtsp_source_addr> -vf fps=fps=1/20 -update 1 img.jpg
As Xianlin pointed out there may be a couple other interesting options to use:
-an : Disables audio recording.
Found in Audio Options Section
-r < fps > : sets frame rate
Found in the Video Options Section
used as an output option is actually a a substitute for the fps filter
leading to an alternate version :
avconv -i rtsp://<rtsp_source_addr> -r 1/20 -an -update 1 img.jpg
Hope it helps understand for possible further tweaking ;)
Following command line should work for you.
ffmpeg -i rtsp://IP_ADDRESS/live.sdp -f image2 -updatefirst 1 img.jpg
I couldn't get the option -update working to overwrite the .jpg. Doing some experiments resulted in a working solution (at least for me) with the option -y at the end (upper-case is not working). I also needed http:// instead of rstp:// for this camera.
ffmpeg -i http://xx:yy#192.168.1.xx:yyy/snapshot.cgi /tmp/Capture2.jpg -y
Grab a snapshot from an RTSP video stream every 10 seconds.
#!/bin/bash
#fetch-snapshots.sh
url='rtsp://IP_ADDRESS/live.sdp'
avconv -i $url -r 0.1 -vsync 1 -qscale 1 -f image2 images%09d.jpg
-r rate set frame rate to 0.1 frames a second (this equals to 1 frame every 10 seconds).
Thanks to westonruter, see https://gist.github.com/westonruter/4508842
Furthermore have a look at FFMPEG: Extracting 20 images from a video of variable length
ffmpeg -i rtsp://root:password#192.168.1.1/mpeg4 -ss 00:00:01 -f image2 -vframes 1 thumb.jpg
replace with your rtsp protocol url
make sure 00:00:01
if you put other numbers, the image will be crashed

how to get the timestamp of the image extracted using ffmpeg

How to get the time stamp of the extracted image obtained by using ffmpeg? What option is to be passed to the ffmpeg command?
The current command that i am using is:
ffmpeg -i video.mp4 -vf select='gt(scene\,0.3)' -vsync 0 -an keyframes%03d.jpg
Extracting frame while scene change and get time for particular frame . May following line might helps:
ffmpeg -i image.mp4 -filter:v "select='gt(scene,0.1)',showinfo" -vsync 0 frames%05d.jpg >& output.txt
You will get output like: [Parsed_showinfo_1 # 0x25bf900] n: 0 pts: 119357 pts_time:9.95637 pos: 676702..... You need to extract pts_time for that run following command.
grep showinfo ffout | grep pts_time:[0-9.]* -o | grep '[0-9]*\.[0-9]*' -o > timestamps
Using above command you will find following:
9.95637
9.98974
15.0281
21.8016
28.208
28.4082
An option could be to write timestamps directly over each frame, using drawtext video filter.
On a Windows machine, using Zeranoe ffmpeg package you can type:
ffmpeg -i video.mp4 -vf "drawtext=fontfile=/Windows/Fonts/Arial.ttf: timecode='00\:00\:00\:00': r=25: x=(w-tw)/2: y=h-(2*lh): fontcolor=white: box=1: boxcolor=0x00000000#1: fontsize=30" tmp/frame%05d.jpg" -vsync 0 -an keyframes%03d.jpg
The command will dump frame timestamps in the lower part of each frame, with seconds resolution.
Please have a look here to get informations how to setup fonts enviroment variables for ffmpeg.
As this question is tagged in python, I would like to add the following solution for Python developers:
from subprocess import check_output
import re
pts = str(check_output('ffmpeg -i video.mp4 -vf select="eq(pict_type\,I)" -an -vsync 0 keyframes%03d.jpg -loglevel debug 2>&1 |findstr select:1 ',shell=True),'utf-8') #replace findstr with grep on Linux
pts = [float(i) for i in re.findall(r"\bpts:(\d+\.\d)", pts)] # Find pattern that starts with "pts:"
print(pts)
A small update to #DeWil's answer (sorry could not comment as I do not have enough reputations).
The below answer gives the appropriate timestamp by matching with the regular expresion for timestamp "t:" not "pts:".
from subprocess import check_output
import re
pts = str(check_output('ffmpeg -i input.mp4 -vf select="eq(pict_type\,I)" -an -vsync 0 keyframes%03d.jpg -loglevel debug 2>&1 |findstr select:1 ',shell=True),'utf-8') #replace findstr with grep on Linux
pts = [float(i) for i in re.findall(r"\bt:(\d+\.\d)", pts)] # Find pattern that starts with "t:"
print(pts)

Resources