FFmpeg开发笔记(二十二)FFmpeg中SAR与DAR的显示宽高比

打印 上一主题 下一主题

主题 866|帖子 866|积分 2600

​《FFmpeg开发实战:从零基础到短视频上线》一书提到:通常情况下,在视频流解析之后,从AVCodecContext布局得到的宽高就是视频画面的宽高。然而有的视频文件并非云云,假如按照AVCodecContext设定的宽高展示视频,会发现画面被压扁或者拉长了。比如该书第10章源码playsync.c在播放meg.vob时的视频画面如下图所示:

可见按照现有方式展示的话,视频画面被拉长了。这是因为视频尺寸有三种宽高概念,说明如下:
1、采样宽高比,指的是摄像头在采集画面时,方格内部的宽度与高度的采样点数量比例。采样宽高比的英文叫做“Sample Aspect Ratio”,简称SAR。
2、像素宽高比,指的是视频画面保存到文件时,宽度和高度各占据多少像素。像素宽高比的英文叫做“Pixel Aspect Ratio”,简称PAR。
3、显示宽高比,指的是视频画面渲染到屏幕时,显示出来的宽度与高度比例。显示宽高比的英文叫做“Display Aspect Ratio”,简称DAR。
采样宽高比对应AVCodecParameters布局的sample_aspect_ratio字段,该字段为分数类型AVRational。
像素宽高比对应AVCodecContext布局的width与height两个字段,比例值等于width/height。
显示宽高比对应最终要显示的画面尺寸,该值须要额外计算。多数时候sample_aspect_ratio的num与den均为1,表现宽高两个方向的采样点比例为1:1,此时像素宽高比等于显示宽高比。
由此可见,当sample_aspect_ratio的num与den均为1时,表现像素点是个正方形,此时AVCodecContext布局的宽高就是视频的宽高,无需别的处理。只有sample_aspect_ratio的num不等于den时,表现像素点是个长方形,才须要别的计算显示宽高比,并根据视频高度计算视频的现实宽度。
已知三个宽高比的转换式子如下:
  1. DAR = PAR x SAR
复制代码
令DAR=现实宽度/现实高度,则代入具体的字段,可得具体的转换式子如下:
  1. 实际宽度   width    sample_aspect_ratio.num
  2. ——————— = —————— X —————————————————————————
  3. 实际高度   height   sample_aspect_ratio.den
复制代码
当现实高度为height时,表现保持原画面尺寸,则现实的画面宽度计算式子如下。
  1.              sample_aspect_ratio.num
  2. 实际宽度 = width X —————————————————————————
  3.              sample_aspect_ratio.den
复制代码
假如​已经求得DAR值并保存在变量display_aspect_ratio中,那么现实宽度 = 现实高度 * PAR = 现实高度 * display_aspect_ratio.num / display_aspect_ratio.den。
根据上述所列的几个计算式子,编写如下的宽高比以及现实宽度的求解代码如下所示。
  1. int origin_width = video_decode_ctx->width;
  2. int origin_height = video_decode_ctx->height;
  3. AVRational aspect_ratio = src_video->codecpar->sample_aspect_ratio;
  4. AVRational display_aspect_ratio;
  5. av_reduce(&display_aspect_ratio.num, &display_aspect_ratio.den,
  6.           origin_width  * aspect_ratio.num,
  7.           origin_height * aspect_ratio.den,
  8.           1024 * 1024);
  9. av_log(NULL, AV_LOG_INFO, "origin size is %dx%d, SAR %d:%d, DAR %d:%d\n",
  10.        origin_width, origin_height,
  11.        aspect_ratio.num, aspect_ratio.den,
  12.        display_aspect_ratio.num, display_aspect_ratio.den);
  13. int real_width = origin_width;
  14. // 第一种方式:根据SAR的采样宽高比,由原始的宽度算出实际的宽度
  15. if (aspect_ratio.num!=0 && aspect_ratio.den!=0 && aspect_ratio.num!=aspect_ratio.den) {
  16.     real_width = origin_width * aspect_ratio.num / aspect_ratio.den;
  17. }
  18. int target_height = 270;
  19. int target_width = target_height*origin_width/origin_height;
  20. // 第二种方式:根据DAR的显示宽高比,由目标的高度算出目标的宽度
  21. if (aspect_ratio.num!=0 && aspect_ratio.den!=0 && aspect_ratio.num!=aspect_ratio.den) {
  22.     target_width = target_height * display_aspect_ratio.num / display_aspect_ratio.den;
  23. }
  24. av_log(NULL, AV_LOG_INFO, "real size is %dx%d, target_width=%d, target_height=%d\n",
  25.     real_width, origin_height, target_width, target_height);
复制代码
上述修改后的代码已经附在了《FFmpeg开发实战:从零基础到短视频上线》一书第10章的源码chapter10/playsync2.c中,这个c代码是playsync.c的改进版,可以大概根据sample_aspect_ratio的宽高比例调整目标视频的画面尺寸。
接着执行下面的编译命令。
  1. gcc playsync2.c -o playsync2 -I/usr/local/ffmpeg/include -L/usr/local/ffmpeg/lib -I/usr/local/sdl2/include -L/usr/local/sdl2/lib -lsdl2 -lavformat -lavdevice -lavfilter -lavcodec -lavutil -lswscale -lswresample -lpostproc -lm
复制代码
编译完成后执行以下命令启动测试程序,盼望播放视频文件meg.vob。
  1. ./playsync2 ../meg.vob
复制代码
程序运行完毕,发现控制台输出以下的日记信息。
  1. Success open input_file ../meg.vob.
  2. origin size is 720x576, SAR 64:45, DAR 16:9
  3. real size is 1024x576, target_width=480, target_height=270
  4. ……
复制代码
同时弹出SDL窗口播放视频画面,如下图所示:

可见画面尺寸符合该视频的现实宽高比例,表现上述代码正确实现了调整视频尺寸的功能。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

用多少眼泪才能让你相信

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表