[关闭]
@ltlovezh 2020-11-05T10:43:08.000000Z 字数 1976 阅读 1695

视频SAR信息处理

ffmpeg 音视频


SAR存储和解析

SAR表示单个像素显示的宽高比,即像素不都是按照1:1显示。
SAR存储在Mp4的moov -> trak -> mdia -> minf -> stbl -> stsd -> avc1 -> avcc Box的SPS里面,如下图所示:
SPS-SAR

libavcodec/h264_ps.c文件中decode_vui_parameters函数负责解析出SAR,如下所示:
SPS-SAR-FFmpeg

SAR/PAR/DAR之间的关系

三者之间的关系:PAR * SAR = DAR

下面看一个例子,如下图所示:
每个方格代表一个像素,宽度为5像素,高度为4像素,即PAR=5 : 4。
假设图像的显示宽度为160,高度为120,即DAR=4 : 3。
那么可以计算出SAR = DAR / PAR = 16 : 15,表示像素方格是一个长方形。
dar

FFmpeg提供了多个SAR变量:

FFprobe显示的SAR是根据libavformat/utils.c文件中的av_guess_sample_aspect_ratio函数计算得来,其实就是按照优先级获取SAR,取到则返回,优先级从高到底分别是:AVStream->sample_aspect_ratio > AVFrame->sample_aspect_ratio > AVStream->codecpar->sample_aspect_ratio。

对于DAR,AVStream->display_aspect_ratio始终为0:0,参考ffprobe代码,可知DAR是通过av_reduce计算得到的,如下所示:

  1. AVRational sar, dar;
  2. // 流编码参数
  3. AVCodecParameters * codecpar = AVStream->codecpar;
  4. // 计算出sar
  5. sar = av_guess_sample_aspect_ratio(AVFormatContext, AVStream, NULL);
  6. // 根据视频帧宽高和sar计算出dar
  7. av_reduce(&dar.num, &dar.den, codecpar->width * sar.num, codecpar->height * sar.den, 1024*1024);

如何构造特殊SAR的视频

FFmpeg提供了Video AVFilter:setdar, setsar,可以修改视频的SAR和DAR。
例如:origin.mp4是一个1080*1920的视频,默认SAR是1 : 1,DAR是9:16。
现在我们把SAR设置为2 : 1,即单个像素是2 : 1的矩形,那么视频尺寸就是540*1920。

  1. ffmpeg -i origin.mp4 -vf scale=540:1920,setsar=2.0 output.mp4

output.mp4的信息如下所示:
setsar

兼容特殊SAR的视频

针对上述SAR是2:1的视频,若我们不处理SAR,直接按照视频帧宽高:540*1920来处理,那么正常的9:16视频,将会被显示成4.5:16,即整个视频上下拉伸了2倍。

兼容SAR也很简单,分为CPU和GPU处理(假设是YUV420P像素数据)。

CPU

通过libyuv函数(例如:libyuv::Scale),把540*1920的像素数据,缩放到9 : 16的任意尺寸,例如:540*960(宽度不变,按照DAR计算出高度)。

GPU

先按照540*1920的真实像素数据,上传到YUV纹理,然后按照9 : 16的原始比例计算MVP矩阵,即计算MVP矩阵时,源纹理不是按照4.5 : 16的宽高比,而是按照9 : 16的宽高比,最后渲染到目标FBO纹理。

旋转角度和SAR的问题

若一个视频既有旋转角度,又有SAR和DAR,哪里这里的SAR是旋转之前的像素宽高比还是旋转之后的像素宽高比那?或者说这里的DAR是旋转之前的显示高比还是旋转之后的显示宽高比那?
sar-rotation

这个问题在网上查了蛮久,都没有找到解答,最后从EXOPlayer源码MediaCodecVideoRenderer.onOutputFormatChangedPlayerView.onVideoSizeChanged中找到了答案。

SAR是旋转之前的像素宽高比,DAR是旋转之前的显示宽高比,旋转之后,SAR和DAR都要取倒数。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注