Android获取 H264视频流中的SPS和PPS

代码其实很简单,主要是要知道H264帧数据结构。分析H264码流结构的文章一大把,自己网上搜索一下就知道了。

背景:

h264+aac封装mp4格式的时候,需要获取视频流的sps,pps。

封装mp4文件格式的大体方案

使用 MediaExtractor 和 MediaMuxer API 解析和封装 mp4 文件(硬解码的方式) (纯java)

使用MP4v2将H264/H265码流以及AAC音频封装成MP4格式(软解码的方式)(JNI+C)

使用FFmpeg将H264/H265码流以及AAC音频封装成MP4格式(软解码的方式)(JNI+C)
"csd-0" 和 "csd-1" 是什么,对于 H264 视频的话,它对应的是 sps 和 pps,对于 AAC 音频的话,对应的是 ADTS,做音视频开发的人应该都知道,它一般存在于编码器生成的 IDR 帧之中。

创建并配置 codec。配置 codec 时,若手动创建 MediaFormat 对象的话,一定要记得设置 "csd-0" 和 "csd-1" 这两个参数。 "csd-0" 和 "csd-1" 这两个参数一定要和接收到的帧对应上。

c 复制代码
   /**
    * 判断I针中有没有sps pps
    * @param type  0==264  1==265
    * @param data
    * @return
    */
   public static boolean ISIFrameData(int type, byte[] data) {
      int nalType;
      if (type == 0) {
         int FF_H264_SPS_NAL = 7;
         int FF_H264_PPS_NAL = 8;
         nalType = data[4] & 0x1f;
         XLog.e("","h264 nalType=== "+nalType);
         if (FF_H264_SPS_NAL == nalType ||
                 FF_H264_PPS_NAL == nalType
         ) {
            return true;
         }
      } else  if (type == 1){
         int FF_HEVC_VPS_NAL = 32;
         int FF_HEVC_PPS_NAL = 34;
         int FF_HEVC_SPS_NAL = 33;
         nalType = (data[4] & 0x7e) >> 1;
         XLog.e("","h265 nalType=== "+nalType);
         if (FF_HEVC_VPS_NAL == nalType ||
                 FF_HEVC_PPS_NAL == nalType ||
                 FF_HEVC_SPS_NAL == nalType){
            return true;
         }
      }
      return false;
   }



  /**
    * 获取I帧里面的 sps pps 信息
    * @param type  0==264  1==265
    * @param frame  帧数据
    * @return
    */
   public static List<byte []> getPPSByKeyFrameData(int type , byte[] frame){
      Map<Integer,Integer> map=new HashMap<>();
      int save_x=0;
      List<byte[]> list=new ArrayList<>(2);
      byte[]sps,pps;
      if(type==0){//h264
         int nalType=frame[4]&0x1f;//判断I帧,然后根据具体情况获取sps,pps
         if(nalType==7){
            //[Start Code]:Start Code 用于标示这是一个NALU 单元的开始(也称分隔符),必须是"00 00 00 01" 或"00 00 01"。
            //关键帧是00 00 00 01
            for (int i = 0; i < frame.length-3; i++) {
               if(frame[i]==0&&frame[i+1]==0&&frame[i+2]==0&&frame[i+3]==1){
                   map.put(save_x,i);
                   save_x++;
               }
            }
            int spsLength=map.get(1)-map.get(0)-4;
            int spsOffset=map.get(0)+3;
            sps=new byte[spsLength];
            System.arraycopy(frame,spsOffset,sps,0,spsLength);

            int ppsLength=map.get(2)-map.get(1)-4;
            int ppsOffset=map.get(1)+3;
            pps=new byte[ppsLength];
            System.arraycopy(frame,ppsOffset,pps,0,ppsLength);

            list.add(sps);
            list.add(pps);
         }
      }
      return list;
   }
相关推荐
沐怡旸18 小时前
【翻译】scrcpy(3.3.3)命令使用文档
android
沐怡旸18 小时前
【翻译】adb(Android Debug Bridge) 帮助文档
android
QING61818 小时前
Kotlin 协程中Job和SupervisorJob —— 新手指南
android·kotlin·android jetpack
lichong95118 小时前
android 使用 java 编写网络连通性检查
android·java·前端
Digitally18 小时前
如何从iPhone切换到Android
android·ios·iphone
2501_9160074718 小时前
苹果应用商店上架的系统逻辑,从产品开发到使用 开心上架 上架IPA 交付审核流程
android·ios·小程序·https·uni-app·iphone·webview
r***869818 小时前
搭建Golang gRPC环境:protoc、protoc-gen-go 和 protoc-gen-go-grpc 工具安装教程
android·前端·后端
e***753918 小时前
SQL Server 数据库迁移到 MySQL 的完整指南
android·数据库·mysql
他叫自己MR张18 小时前
Android 必知必会 - AndroidStudio、AGP、Gradle、Java、Kotlin版本对应关系(官方最新)
android·kotlin·android studio·agp
大雨淅淅18 小时前
【编程语言】Kotlin:从新手到大神的进阶之路
android·开发语言·kotlin