一.背景
1.问题视频在iphone7p等机型上:视频无法正常播放(黑屏),音频正常播放。
2.问题视频在iphone XR机型上:音视频均能正常播放。
二.断点分析
1.问题视频在iphone7p上创建VideoToolBox
解码器成功,解码失败(解码中失败IJKPlayer
不能自动切换FFmpeg
软解码),视频画面无法正常播放。
解码失败错误码:
kVTVideoDecoderBadDataErr = -12909
。
2.问题视频在iphone XR上创建VideoToolBox
解码器失败,IJKPlayer
自动切换FFmpeg
软解码,软解码成功,视频画面正常播放。
解码器创建失败错误码:
kVTVideoDecoderMalfunctionErr = -12911
3.以上现象说明此视频无法使用VideoToolBox
硬解码。
VideoToolBox
为苹果官方提供的编解码库,使用GPU硬编解码。官方文档对错误码未提供更详细的信息。
三.格式分析
1.使用ffprobe
分析问题视频的码流格式,包完整性等均未发现问题。
2.使用ffprobe
分析问题视频与正常视频格式,对比发现,正常视频为帧编码,扫描方式为逐行扫描。问题视频为场编码,扫描方式为隔行扫描。
逐行扫描视频的表示方法为:720p,1080p,p是progressive“逐行”的缩写。
隔行扫描视频的表示方法为:720i,1080i,i是interlace“交错”的缩写。
四.验证VideoToolBox
是否支持场编码
1.测试一:将帧编码视频转码为场编码格式视频(逐行转隔行)。
测试二:将问题视频转码为帧编码视频(隔行转逐行)。
使用
FFmpeg
命令行:
逐行转隔行:
ffmpeg -i input.mp4 -aspect 16:9 -c:v h264 -b:v 4000k -minrate 4000k -maxrate 4000k -bufsize 2000k -dc 9 -flags +ilme+ildct -alternate_scan 1 -top 0 output.mp4隔行转逐行:
ffmpeg -i input.mp4 -aspect 16:9 -c:v h264 -b:v 4000k -minrate 1000k -maxrate 2000k -bufsize 2000k -dc 9 -deinterlace output.mp4
2.转码后使用MediaInfo
工具检查是否转码成功。
逐行视频在“扫描方式”处显示“逐行扫描”或“progressive”。
隔行视频在“扫描方式”处显示“MBAFF”或“interlace”等。“扫描顺序”为“奇数场优先”等(逐行扫描无奇偶场概念)。
3.导入IJKPlayer
验证,帧编码(逐行扫描)视频硬解码成功。场编码(隔行扫描)视频解码失败。
(后续会增加测试视频样本量,确保验证的可靠性)
五.解决方案
1.iOS端解决方案:在VideoToolBox
解码器创建前判断视频为场编码还是帧编码,若为场编码,则直接走硬解码器创建失败流程,切换为FFmpeg
软解码,避免出现硬解码创建成功而解码失败的问题。
判断方法:提取H264
中的SPS
序列参数集信息。根据SPS
的句法,通过frame_mbs_only_flag
,mb_adaptive_frame_field_flag
,field_pic_flag
三个字段判断。
2.服务端解决方案:将场编码视频转码为帧编码。
实际上,如果是会议或培训等画面内容变动不大的视频,使用帧编码更为合适,可有效去除空间冗余,画面更清晰。