I have a requirement to take a video, add some plain text, and then add some rotated text at different times, locations, and durations. I want to use processor power in the most efficient way this will run 20,000 times (yes, really, we're personalizing a video for students at a U.)This is what I finally came up with:
ffmpeg -y -i INPUT.mp4 -filter_complex
"drawtext=enable='between(t,14,16)':fontfile=tahoma.ttf:fontsize=54:fontcolor=green:x=10:y=text_h + 10:text='Dana Scully',
drawtext=enable='between(t,19,23)':fontfile=tahoma.ttf:fontsize=16:fontcolor=red:x=150:y=220:text='Dana Scully \<Dana.Scully\#fbi.gov\>',
drawtext=enable='between(t,99,104)':fontfile=tahoma.ttf:fontsize=28:fontcolor=green:x=480:y=text_h + 160:text='Dana Scully',
drawtext=enable='between(t,14,16)':fontfile=tahoma.ttf:fontsize=16:fontcolor=yellow:x=40:y=25:text='Dana Scully \<Dana.Scully\#fbi.gov\>',
drawtext=enable='between(t,180,186)':fontfile=tahoma.ttf:fontsize=88:fontcolor=green:x=20:y=430:text='Dana Scully'[text];
color=c=#111111:s=1280x720:d=1,format=yuv444p[colorbk];
[colorbk]drawtext=fontfile=tahoma.ttf:fontsize=16:fontcolor=purple:x=(w-text_w)/2:y=(h-text_h)/2:text='by',drawtext=fontfile=tahoma.ttf:fontsize=32:fontcolor=green:x=(w-text_w)/2:y=((h-text_h)/2)+50:text='Dana Scully',rotate=(-.5):ow=1280:oh=720:c=#111111,chromakey=#111111:similarity=0.01,format=yuva444p,colorkey=#111111:0.1[rotated];
[text][rotated]overlay=eval=frame:x='if(gte(t,134),(if(lte(t,137),20,NAN)), NAN)':y=100[out];[out]scale=iw*.25:-1"
-crf 20 test.mp4
Is that about as optimized as it is going to get? I thought ffmpeg would already handle the threads based on the computer's processor, so no real need to mess with it. The processing will all be done on AWS VMs.
Rotating the text is what really slows it down.
Any ideas?
Related
I am making a datamoshing program in C++, and I need to find a way to remove one frame from a video (specifically, the p-frame right after a sequence jump) without re-encoding the video. I am currently using h.264 but would like to be able to do this with VP9 and AV1 as well.
I have one way of going about it, but it doesn't work for one frustrating reason (mentioned later). I can turn the original video into two intermediate videos - one with just the i-frame before the sequence jump, and one with the p-frame that was two frames later. I then create a concat.txt file with the following contents:
file video.mkv
file video1.mkv
And run ffmpeg -y -f concat -i concat.txt -c copy output.mp4. This produces the expected output, although is of course not as efficient as I would like since it requires creating intermediate files and reading the .txt file from disk (performance is very important in this project).
But worse yet, I couldn't generate the intermediate videos with ffmpeg, I had to use avidemux. I tried all sorts of variations on ffmpeg -y -ss 00:00:00 -i video.mp4 -t 0.04 -codec copy video.mkv, but that command seems to really bug out with videos of length 1-2 frames - while it works for longer videos no problem. My best guess is that there is some internal checker to ensure the output video is not corrupt (which, unfortunately, is exactly what I want it to be!).
Maybe there's a way to do it this way that gets around that problem, or better yet, a more elegant solution to the problem in the first place.
Thanks!
If you know the PTS or data offset or packet index of the target frame, then you can use the noise bitstream filter. This is codec-agnostic.
ffmpeg -copyts -i input -c copy -enc_time_base -1 -bsf:v:0 noise=drop=eq(pos\,11291) out
This will drop the packet from the first video stream stored at offset 11291 in the input file. See other available variables at http://www.ffmpeg.org/ffmpeg-bitstream-filters.html#noise
I am having an image sequence input of webp-s concatenated (for various reasons) in a single file. I have a full control over the single file format and can potentially reformat it as a container (IVF etc.) if a proper exists.
I would like ffmpeg to consume this input and time properly each individual frame (consider first displayed for 5 seconds, next 3 seconds, 7, 12 etc.) and output a video (mp4).
My current approach is using image2pipe or webp_pipe followed by a list of loop filters, but I am curious if there are any solid alternatives potentially a simple format/container I could use in order to reduce or completely avoid ffmpeg filter instructions as there might be hundreds or more in total.
ffmpeg -filter_complex "...movie=input.webps:f=webp_pipe,loop=10:1:20,loop=10:1:10..." -y out.mp4
I am aware of concat demuxer but having a separate file for each input image is not an option in my case.
I have tried IVF format which works ok for vp8 frames, but doesnt seem to accept webp. An alternative would be welcomed, but way too many exists for me to study each single one and help would be appreciated.
Alright, real simple here. I'm rendering some fractal flames I've created over the years. Which makes the math on all of this really simple.. lol.
I'm trying to generate a 5 second video at 60fps that when played continuously makes a perfect loop.
So I sequence and render exactly 300 frames numbered 000.png through 299.png for one loop. I then send this into FFMpeg with the following command:
ffmpeg -f image2 -framerate 60 -start_number 0 -i '%03d.png' -r 60
-crf 10 output.webm
No matter what, it kills the last 12-18 frames depending on the run and creates a video that players recognize as 4 seconds only.
Here is a snippet of the processing output (Take note that 300 frames at 60fps no matter what you do comes out at 04.66 seconds - but it does claim there are exactly 5 seconds on the input side)
I have tried replacing -crf setting with just -quality good, I have tried moving around where I state the framerate. I have tried removing the -r from the output and putting it in there. I have tried building out this call to be as specific as possible such as the strictly specifying the encoder and options. Oh I have tried other encoders and get the same result. I have even tried -hwaccell using NVEC and CUVID respectively.
Nothing I do works..
Any thoughts here? Maybe alternatives to FFMpeg? Maybe difference versions of FFMpeg? I don't know what I should do next and thought I would ask.
Diagnostic output on a finished file for reference this one actually got close with 294 frames and a 4.9 second runtime it is much higher res though:
I've decided for some reason to upscale an entire 90-minute movie using AI. Problem is, I have several demo scenes that have already been upscaled, and I want to keep those frames rather than upscaling them again. Basically I want to export frames starting at a specific number, like ffmpeg -i scene1.mp4 scene1/%10d+[starting number].jpg. If the specified number were 1550, for example, the first frame it would export would be 0000001550.jpg. I still want it to start at the first frame of the input video, though; the only things I want to change are the names of the output files. Is there a way to do this?
Use the -start_number option for image2 muxer.
Use
ffmpeg -i scene1.mp4 -start_number 1550 scene1/%10d.jpg
I am currently seeing an issue where FFMPEG seems to write my images in bursts. When I run the following command:
ffmpeg -i <URL> -vf fps=fps=1 -f image2 image-%d.png
I get progress updates every two seconds, at which point immediately image-(n).png and image-(n+1).png are written in quick succession.
Is it possible to have these images output more consistently? I would prefer to have the output speed be the same as the designated FPS (so one image per second).
I am using a Python script to do some processing on these images and I am able to better maximize my throughput if these images came more consistently.
You can add -re before -i to operate in real time. However I suspect the frames are being written regularly, just whatever method you are using to get fs updates is polled or coalesced