How to correct for incorrect (?) SAR/PAR in FFMPEG?
August 3, 2018 3:49 AM   Subscribe

On our website, we take user video uploads (in a variety of formats/qualities, natch) and create an animated GIF by programatically extracting frames and recombining them using FFMPEG. We've got a few videos that are full HD (1920x1080), but the framegrabs coming out are 1440x1080, squished horizontally.

Further investigation reveals this from the video properties (via FFMPEG):
Stream #0:0(eng): Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, bt709), 1440x1080 [SAR 4:3 DAR 16:9]
Long question short, when extracting the frames via FFMPEG, how do we tell it to account for that incorrect (?) SAR and output the frames at the video's actual dimensions of 1920x1080?

Having the user correct the video file and re-upload it isn't an option, although "fixing" the video file on our end before we start creating the GIF would be a semi-acceptable last resort.

Thanks!
posted by sandra_s to Computers & Internet (5 answers total)
 
The video is actually stored at 1440x1080 (4:3 SAR - sample aspect ratio) not 1920x1080, but is supposed to be displayed at 16:9, so it has to be stretched for display (16:9 DAR - display aspect ratio).

im not an ffmpeg expert, but have some ideas from looking at the docs. you may want to look into the:

ffmpeg scale filter setting the out height/width. Although you may have to mess with the aspect ratio settings as well.

or

ffmpeg crop filter with keep-aspect=1 and out_w=1920

or ffmpeg zscale filter

you could probably also use ImageMagick or another image manipulation tool to stretch the 1440x1080 to 1920x1080.
posted by TheAdamist at 5:18 AM on August 3, 2018


Having a SAR (Stored Aspect Ratio) of 4:3 with a DAR (Display Aspect Ratio) of 16:9 is a piece of crazed nonsense that began with DVDs, whose SAR was fixed at 4:3 by standardisation before 16:9 televisions became a thing. The 4:3 SAR is not incorrect, it just means that the stored pixels are rectangularly spaced samples rather than square ones. The shape of the individual pixels is given by the PAR (Pixel Aspect Ratio) and you can work that out by dividing the DAR by the SAR.

For a SAR of 4:3 and a DAR of 16:9 the PAR also comes out to 4:3, but this is just because 16 happens to be 4 squared and 9 happens to be 3 squared; SAR and PAR will not, in general, be the same.

When you do your framegrabs, ffmpeg's default action is to copy all the pixels from the selected frame into the output still, so what you're getting is just the complete array of pixels for that frame without any resampling having been done.

But still-picture storage standards like JPEG and GIF and PNG never included any of this SAR vs DAR craziness. For a still picture in any of those formats, the SAR and DAR are identical and the PAR is always 1:1 i.e. the pixels are always square. So the pixels of the frame grab are a different shape from those of the video frame - square instead of 4:3 - making the picture appear to be squashed horizontally when displayed.

If you want ffmpeg to do the same kind of scaling for framegrabs that a TV would do on-the-fly when presented with a video stream containing non-square pixels, you can use its -vf scale option for that. This will be vastly faster than running frames through ImageMagick one at a time afterwards.
posted by flabdablet at 5:37 AM on August 3, 2018 [7 favorites]


In particular, the SAR, the DAR, the input width and the input height are available to ffmpeg's scale filter as variables, and can be used in expressions supplied as arguments to that filter.

The ffmpeg scale filter documentation provides a recipe for a -vf argument that preserves the input height and stretches the width enough to make the output pixels square, which I would think is probably what you want to do:
  • Make pixels square by combining scale and setsar:
    scale='trunc(ih*dar):ih',setsar=1/1
Note that as well as using the scale filter, this recipe uses the setsar filter as well to force a the output video stream to carry a new SAR value. This probably doesn't do anything when the output is destined for a still-picture file as it is for your use case, but it's good practice anyway.

Oh, and just to pile confusion on confusion, it appears that ffmpeg uses "SAR" to mean sample aspect ratio, not stored aspect ratio. In other words, what ffmpeg refers to as SAR is actually the PAR. Which is, as noted above, in this instance the same as the stored aspect ratio you mentioned - i.e. 1440/1080 = 4:3 - by sheer happenstance.

Even so, the recipe linked and quoted in this comment should be the one you need, because its formula uses only DAR and the meaning of "DAR" is uncontroversial.
posted by flabdablet at 6:10 AM on August 3, 2018 [3 favorites]


Thanks, gang! Everyone's was best, but flabdablet's was the bestest!
posted by sandra_s at 8:08 PM on August 4, 2018


JPEG and GIF and PNG never included any of this SAR vs DAR craziness

PNGs do include a DPI or DPM for both dimensions, which can be unequal. FFmpeg will induce stream SAR from those values. It will write these values when saving to PNG.

Oh, and just to pile confusion on confusion, it appears that ffmpeg uses "SAR" to mean sample aspect ratio, not stored aspect ratio. In other words, what ffmpeg refers to as SAR is actually the PAR.

FFmpeg is using standard MPEG terminology. MPEG-2 and onward video standards (H.262 +) define Sample Aspect Ratio and Display Aspect Ratio but no Storage Aspect Ratio. Which makes sense, as the last one conveys no independent information -- it is the ratio of two values, already available in the container/stream metadata. It seems to be used in web explanations and by a few media info s/w like the old GSpot..etc.

scale='trunc(ih*dar):ih',setsar=1/1

trunc is unnecessary here unless one wants to avoid rounding up.
posted by Gyan at 1:42 PM on August 13, 2018 [1 favorite]


« Older Numb torso: wtf   |   How do YOU take time off? Newer »
This thread is closed to new comments.