音视频开发之旅(64) - 部分android手机编码的视频在ios上无法播放

Posted 音视频开发之旅

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了音视频开发之旅(64) - 部分android手机编码的视频在ios上无法播放相关的知识,希望对你有一定的参考价值。

目录

  1. 问题描述

  2. 问题分析

  3. 问题原因

  4. 问题解决

  5. 资料

  6. 收获

一、问题描述

用小米11 录制视频上传后,在iPhone的Safari浏览器或者应用的H5中无法播放,而android设备上的确实可以正常播放。

同样的操作,在一些其他android的手机上传的视频,在ios端却可以正常播放。

二、问题分析

拿到(能播放和不能播放)两个视频。分析下这两个视频有什么差异。

通过MediaInfo查看两个视频的基本信息

不能播放的视频


"@type": "Video",
"StreamOrder": "1",
"ID": "2",
"Format": "AVC",
"Format_Profile": "High",
"Format_Level": "6",
"Format_Settings_CABAC": "Yes",
"Format_Settings_RefFrames": "1",

能播放的视频


"@type": "Video",
"Format": "AVC",
"Format_Profile": "Main",
"Format_Level": "3.1",
"Format_Settings_CABAC": "Yes",

可以很明显地看到两个视频的Profile和Level不同。

通过ffmpeg把不能播放的视频进行转码,修改profile和level的值,进行本地快速验证。

ffmpeg -i input.mp4 -profile:v main -level 4.2 output.mp4

ffmpeg -i input.mp4 -profile:v high -level 5.1 output.mp4

ffmpeg -i input.mp4 -profile:v high -level 6  output.mp4

发现只有level大于等于6,在ios上就不能播放。

三、问题原因

我们先来看下Profile和Level是什么?

3.1 Profile

H.264有四种画质级别,分别是baseline, extended, main, high:
  1、Baseline Profile:基本画质。支持I/P 帧,只支持无交错(Progressive)和CAVLC;
  2、Extended profile:进阶画质。支持I/P/B/SP/SI 帧,只支持无交错(Progressive)和CAVLC;(用的少) 
  3、Main profile:主流画质。提供I/P/B 帧,支持无交错(Progressive)和交错(Interlaced), 也支持CAVLC 和CABAC 的支持;
  4、High profile:高级画质。在main Profile 的基础上增加了8x8内部预测、自定义量化、 无损视频编码和更多的YUV 格式;
   
   H.264 Baseline profile、Extended profile和Main profile都是针对8位样本数据、4:2:0格式(YUV)的视频序列。
   
  在相同配置情况下,High profile(HP)可以比Main profile(MP)降低10%的码率。
  根据应用领域的不同,Baseline profile多应用于实时通信领域,Main profile多应用于流媒体领域,High profile则多应用于广电和存储领域。

维基百科上有对应的表:

3.2 level

level是一组特定的约束,表示一个profile所需的编解码性能。指定编解码器可能使用的最大图像分辨率、帧率和比特率。一个符合给定level的解码器必须能够解码为该level和所有低level编码的所有比特流。

在MediaCodecInfo中有定义各种类型的值

综上,我们可以知道Profile和Level是影响着视频编码的质量和效率。有些设备不支持高Profile、level的编码。所以需要综合考虑兼容性和视频质量。

通过查看代码发现,android端的视频编码时,仅对Profile做了阀值限制,Level没有判断处理,就像小米11手机对应解码器信息返回的Level是6,这样编码出来的视频在某些不支持的该level解码的设备上就无法解码播放。

3.3 扩展

另外通过查找资源,发现android在7.0之前的系统,编码时profile只能是Baseline,如果不是,系统会强制地设置为Baseline。猜测也是为了兼容性吧。虽然更高的压缩比带来很好的收益,但是兼容性(普适性)是优先考虑的点。

使用MediaCodec编码时,通常是这样设置的

先配置MediaCodecInfo的profile信息 然后赋给MediaFormat
codec.configure(format,null,null,MediaCodec.CONFIGURE_FLAG_ENCODE);
最后设置给MediaCodec

编码得到的码流都是baseline profile的

这是由于android sdk本身的限制导致的

ACodec.cpp里的对应处理如下:
if (h264type.eProfile != OMX_VIDEO_AVCProfileBaseline) 
        ALOGW("Use baseline profile instead of %d for AVC recording",
            h264type.eProfile);
        h264type.eProfile = OMX_VIDEO_AVCProfileBaseline;
    


在Android 7.0之后才移除了这段代码。也就是说要想使用MP要求Android系统版本在7.0及其以上。

四、问题解决方案

4.1 方案一:用户上传后先经过服务端的转码后,再下发给用户

用户上传的视频可能差别很大(封装格式、编码格式、采样率、码率、帧率、分辨率、YUV存储格式等等),有些播放器可能对某些视频支持的不太好。比如:有些设备不支持HEVC的解码、有些解码器不支持MPEG-4的编码格式、有些播放器只支持YUV420P的格式、有些播放器对于帧率很高的视频卡顿、有些播放器不支持播放4K等高清视频 等等
针对上述情况,一种比较通用的做法是。用户上传后先经过服务端的转码后,再下发给其他用户。进而保证视频在各种设备上的兼容性。

4.2 方案二、编码时的profie和level设置上线阀值

profile 最大值设置为 MediaCodecInfo.CodecProfileLevel.AVCProfileHigh
Level 最大值设置为 MediaCodecInfo.CodecProfileLevel.AVCLevel52
当从解码器中遍历的MediaCodecInfo.CodecProfileLevel的profie和level上述阀值时,用上述最大值。进而保证在各种设备的兼容性。

方案1是更加通用的解决方案,方案2则是脚痛医脚的方案。

五、 资料

  1. H.264 and H.265 (HEVC)(https://help.shopmoment.com/article/135-video-formats-for-ios)

  2. ffmpeg 常用命令(https://www.cnblogs.com/frost-yen/p/5848781.html)

  3. H264编码profile & level控制(https://www.cnblogs.com/tinywan/p/6402007.html)

  4. Using ffprobe to get info from a file in a nice JSON format(https://gist.github.com/nrk/2286511)

  5. Android MediaCodec参数笔记(https://blog.csdn.net/matrix_laboratory/article/details/80929845)

  6. Android MediaCodec h264编码无法设为high profile(https://www.codeleading.com/article/78273619345/)

六、收获

通过本篇的学习

  1. 分析解决部分android设备上编码的视频,ios不能播放的问题

  2. 进一步熟悉Profile、Level的意义

感谢你的阅读

欢迎关注公众号“音视频开发之旅”,一起学习成长。

欢迎交流

以上是关于音视频开发之旅(64) - 部分android手机编码的视频在ios上无法播放的主要内容,如果未能解决你的问题,请参考以下文章

音视频开发之旅(64) - 部分android手机编码的视频在ios上无法播放

Android NDK开发之旅38--FFmpeg视频添加水印

音视频开发之旅(61)- 分析FFmpeg (解码部分的)常用结构体

音视频开发之旅(61)- 分析FFmpeg (解码部分的)常用结构体

音视频开发之旅(61)- 分析FFmpeg (解码部分的)常用结构体

音视频开发之旅(60) -调试分析FFmpeg (解封装部分的)常用结构体