Use ffmpeg to watermark and scale an image on video - ffmpeg

I want to be able to watermark videos with a logo image, which contains a website url.
The videos can be of different formats and dimension.
I'm trying to figure out a generic ffmpeg command to achieve it, so that i don't have to tweak the command depending on the video i have to process.
So far i got:
ffmpeg -i sample.mov -sameq -acodec copy -vf 'movie=logo.png [watermark]; [in][watermark] overlay=main_w-overlay_w-10:main_h-overlay_h-10 [out]' sample2.mov
In this way though the logo will look too big or too small with video of different size.
I've seen there is a scale option for avfilter, but I haven't figure out whether it's possible to resize the image logo based on the dimension of the input video, so that I can say to scale the logo to 1/3 of the video length for example, and keep the image ratio.
Any idea? doesn't need to be done in a single command, could even be a script.
thanks in advance.

In the meantime i came up with this script that does the job:
#!/bin/bash
VIDEO=$1
LOGO=$2
VIDEO_WATERMARKED=w_${VIDEO}
VIDEO_WIDTH=`ffprobe -show_streams $VIDEO 2>&1 | grep ^width | sed s/width=//`
echo The video width is $VIDEO_WIDTH
cp $LOGO logo.png
IMAGE_WIDTH=$((VIDEO_WIDTH/3))
echo The image width will be $IMAGE_WIDTH
mogrify -resize $IMAGE_WIDTH logo.png
echo logo.png resized
echo Starting watermarking
ffmpeg -i $VIDEO -sameq -acodec copy -vf 'movie=logo.png [watermark]; [in][watermark] overlay=main_w-overlay_w-10:main_h-overlay_h-10 [out]' $VIDEO_WATERMARKED
echo Video watermarked
The only thing i'm not certain about is how to keep the same video quality. I thought that "-sameq" would keep the same video quality, but the resulting video size is smaller.
I've noticed this:
INPUT
Duration: 00:01:25.53, start: 0.000000, bitrate: 307 kb/s
Stream #0:0(eng): Video: mpeg4 (Simple Profile) (mp4v / 0x7634706D),
yuv420p, 640x480 [SAR 1:1 DAR 4:3], 261 kb/s, 10 fps, 10 tbr, 3k tbn, 25 tbc
OUTPUT
encoder : Lavf53.20.0
Stream #0:0(eng): Video: h264 (avc1 / 0x31637661), yuv420p, 640x480 [SAR 1:
1 DAR 4:3], q=-1--1, 10 tbn, 10 tbc
whereas the audio information are identical.
Any advice on how to keep the original video quality?
thanks

Thanks for idea, Ae.!
Same thing using powershell:
$videoFilename = "..."
$logoFilename = "..."
$videoInfo = (& "$($ffmpeg)ffprobe.exe" -show_streams -of xml -loglevel quiet $videoFilename) | Out-String
$videoStreamInfo = Select-Xml -Content $videoInfo -XPath "/ffprobe/streams/stream[#codec_type='video' and #width and #height][1]"
$videoWidth = $videoStreamInfo.Node.width
$videoHeight = $videoStreamInfo.Node.height
# logo will be 10% orginal video width
$logoWidth = $videoWidth/10
# preparing arguments
$a = "-i", $videoFilename, "-i", $logoFilename, "-filter_complex", "[1]scale=$($logoWidth):$($logoWidth)/a [logo]; [0][logo]overlay=main_w-overlay_w-10:10", "-ss", "-y", "-loglevel", "error", $node.output
# logo actual height is cumputed by ffdshow`s scale filter at "$($logoWidth)/a". a - original video aspect ratio
# clear error stream for clear error handling
$error.Clear()
# execute ffmpeg
(& "$($ffmpeg)ffmpeg.exe" $a)
if($error.Count -gt 0){
Write-Output "error! $error"
}
here a can go without using 'mogrify' tool, only ffmpeg distribution.

Related

How to concat MTS videos and apply filters without re-encoding using FFmpeg?

I have a txt file with many MTS video files. I want to merge them all together using FFmpeg and get one big MTS file. But I want to apply fade-in and fade-out to the final video. Can I do it without re-encoding? Because re-encoding takes a lot of time, but I need to do it fast.
Edit
Here is the output when I run
ffmpeg -i C:/Users/aleks/Downloads/IMPORTANT/MTS_videos/my.MTS
Output:
Input #0, mpegts, from 'C:/Users/aleks/Downloads/IMPORTANT/MTS_videos/my.MTS':
Duration: 00:00:08.51, start: 1.433367, bitrate: 5275 kb/s
Program 1
Metadata:
service_name : Service01
service_provider: FFmpeg
Stream #0:0[0x100]: Video: h264 (High) ([27][0][0][0] / 0x001B), yuv420p(tv, bt709, progressive), 1920x1080, 59.94 fps, 59.94 tbr, 90k tbn, 120k tbc
Edit 2
ok, I think I figured it out. The problem was in audio codec, I added -c:a mp3 and it seems to be working. However now I have the second problem. I have 3 videos. I apply fade in to the first one, fade out to the third one and nothing to the second one. I get them from one video by slicing using this command 3 times
ffmpeg -i 'C:/Users/aleks/Downloads/video.MTS' -ss 20 -t 5 -c copy 'C:/Users/aleks/Downloads/third.MTS'
But when I run it my video is 2 seconds long (it must be 5 seconds long). Can you help me with fixing this problem.
PS. i have seen similar question and there was a suggestion to add -async 1. It didn't help. And moving -t 5 to the position before -i didn't help as well.
Also if I delete -c copy everything works fine. But I need to keep it because I don't want to re-encode.

Is there a function to add a title to multiple videos? FFMPEG

I'm getting started with FFMPEG to add a title video to a few dozen videos I have. What would be the proper command to do this?
Use the concat demuxer
There are several methods to join/merge/concatenate one video to another. This method uses the concat demuxer in ffmpeg to join the title video to the main video. Although there are several steps, it has the advantage that it does not re-encode the video you are adding a title to. So the process is quick and the quality is preserved.
Example
See the attributes of the video you want to add a title video to. In this example it is named main.mp4. When making the title video you will need to ensure that it matches the attributes of the video you want to add a title to.
ffmpeg -i main.mp4
...
Stream #0:0(und): Video: h264 (Main) (avc1 / 0x31637661), yuv420p(tv, bt709), 1280x720 [SAR 1:1 DAR 16:9], 988 kb/s, 29.97 fps, 29.97 tbr, 30k tbn, 59.94 tbc (default)
Stream #0:1(eng): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 128 kb/s (default)
Generate the title video. Make sure the title video matches the attributes of the main file so it can concatenate properly. This example uses the color and anullsrc source filters to make 5 seconds of black video and silent audio, and the drawtext filter to make text:
ffmpeg -f lavfi -i color=size=1280x720:rate=30000/1001:duration=5:color=black -f lavfi -i anullsrc=sample_rate=44100:channel_layout=stereo -vf "drawtext=text='your title':fontcolor=white:fontsize=48:x=(w-text_w)/2:y=(h-text_h)/2" -c:v libx264 -profile:v main -c:a aac -shortest title.mp4
Make a text file named input.txt. This will be used by the concat demuxer and lists the files that you want to concatenate.
file 'title.mp4'
file 'main.mp4'
Finally, concatenate the title video to the main video with the concat demuxer:
ffmpeg -f concat -i input.txt -c copy output.mp4
Batch mode
ffmpeg does not have a batch mode to automatically do this for a folder of videos. However, it can be done with shell scripting but that is a whole new topic that deserves its own question. See How do you convert an entire directory with ffmpeg? for some examples.

Output image with correct aspect with ffmpeg

I have a mkv video with the following properties (obtained with mediainfo):
Width : 718 pixels
Height : 432 pixels
Display aspect ratio : 2.35:1
Original display aspect ratio : 2.35:1
I'd like to take screenshots of it at certain times:
ffmpeg -ss 4212 -i filename.mkv -frames:v 1 -q:v 2 out.jpg
This will produce a 718x432 jpg image, but the aspect ratio is wrong (the image is "squeezed" horizontally). AFAIK, the output image should be 1015*432 (with width=height * DAR). Is this calculation correct?
Is there a way to have ffmpeg output images with the correct size/AR for all videos (i.e. no "hardcoded" values)? I tried playing with the setdar/setsar filters without success.
Also, out of curiosity, trying to obtain SAR and DAR with ffmpeg produces:
Stream #0:0(eng): Video: h264 (High), yuv420p(tv, smpte170m/smpte170m/bt709, progressive),
718x432 [SAR 64:45 DAR 2872:1215], SAR 155:109 DAR 55645:23544, 24.99 fps, 24.99 tbr, 1k tbn, 49.98 tbc (default)
2872/1215 is 2.363, so a slightly different value than what mediainfo reported. Anyone knows why?
Without looking at the file, can't diagnose the reason for the distinct readings, but the generic method to get a square pixel result is
ffmpeg -ss 4212 -i filename.mkv -vf scale=iw*sar:ih -frames:v 1 -q:v 2 out.jpg
Accordin to the doc of FFmpeg
ffmpeg -ss 4212 -i filename.mkv -vf scale='trunc(ih*dar):ih',setsar=1/1 \
-frames:v 1 -q:v 2 out.jpg
making sure the resulting resolution is even (required by some codecs)

ffmpeg from pngs... Error with subset of PNGS?

I have about 1200 pngs that I'm converting into a movie. Some of them are missing: i.e. - _00003.png, _00005.png exist, but 1, 2, and 4 do not.
The following command works for other datasets, but not my current set of pngs:
ffmpeg -i pngs/_*.png -y -vcodec mpeg4 -pix_fmt yuv420p -r 25 -filter:v 'setpts=1.2*PTS' p3SN.mp4
I get this error:
Output #61, image2, to 'pngs/_00096.png':
Metadata:
encoder : Lavf57.83.100
Stream #61:0: Video: png, rgba, 3240x2160 [SAR 3937:3937 DAR 3:2], q=2-31, 200 kb/s, 25 fps, 25 tbn, 25 tbc
Metadata:
encoder : Lavc57.107.100 png
Output #62, image2, to 'pngs/_00097.png':
Metadata:
encoder : Lavf57.83.100
Stream #62:0: Video: png, rgba, 3240x2160 [SAR 3937:3937 DAR 3:2], q=2-31, 200 kb/s, 25 fps, 25 tbn, 25 tbc
Metadata:
encoder : Lavc57.107.100 png
[png # 0x7fae93170e00] ff_frame_thread_encoder_init failed
Error initializing output stream 63:0 -- Error while opening encoder for output stream #63:0 - maybe incorrect parameters such as bit_rate, rate, width or height
Conversion failed!
at image _00097.png. If I remove it, it just happens a little later (105).
I've checked the images by looking at their dimensions, etc. and all of them in this range look the same (I checked all those with _0009?.png).
Any idea why this is happening?
Here's the offending file (middle) and the one before/after:
Your command will overwrite all of the input files with the first input. This is an example of why to use caution when using -y which will automatically overwrite files without asking you.
You need to tell ffmpeg to use the glob pattern:
ffmpeg -y -pattern_type glob -framerate 25/1.2 -i "pngs/_*.png" -vcodec mpeg4 -pix_fmt yuv420p -r 25 p3SN.mp4
I believe the glob pattern option does not work on Windows, but if it has an equivalent to the Linux cat command you can pipe the output: cat *.png | ffmpeg -i - output.mp4
You can use -framerate and -r instead of setpts if desired.

Trying to tonemap 14-bit grayscale video

I'm trying to generate h.264 video from raw 2-byte gray video (14-bit range encoded in 16-bit values). I can do something like:
ffmpeg -f rawvideo -pix_fmt gray16le -s:v 1280x720 -r 60 -i input.raw -c:v libx264 output.mp4
And I get video but it's pretty dark, not sure if it's clipping, doing a linear remap, or storing the 16-bit data and VLC is doing the remap. ffprobe is reporting Video: h264 (High 4:4:4 Predictive) (avc1 / 0x31637661), yuvj444p(pc), 1280x720, 108 kb/s, 60 fps, 60 tbr, 15360 tbn, 120 tbc
I was figuring I'd use the tonemap filter to make a better mapping. I added a filter before the output file with -vf.
tonemap=hable errors Impossible to convert between the formats supported by the filter 'graph 0 input from stream 0:0' and the filter 'auto_scaler_0'
zscale=transfer=linear,tonemap=hable errors Impossible to convert between the formats supported by the filter 'Parsed_tonemap_1' and the filter 'auto_scaler_1'
zscale=transfer=linear,tonemap=hable,zscale=transfer=bt709,format=yuvj444p errors code 3074: no path between colorspaces
I'm not sure where to proceed from here...

Resources