ijkplayer上iOS根据AVPacket动态刷新VideoToolBox

背景

项目中有一个切换分辨率的需求,但是服务器更新sps,pps后,并没有在SDP报文中更新sprop-paraemter-sets字段导致VideoToolBox无法解码视频文件

解决思路

在av_read_frame后判断nalu_type,如果是7并包含8的话(我们sps,pps是同一个包),刷新VideoToolBox,实现动态码率的效果

解决方法

  1. 在ff_ffplay.c文件中
    read_thread方法中,找到av_read_frame
  av_read_frame
 //中间是av_read_frame返回结果的判断,在if代码块后添加代码
  .....
  // 00 00 01 的情况在我们的业务中不考虑
   if((pkt->data[4] & 0xF) == 7) {
                    int extradata_size = 0;
                    uint8_t* extradata = NULL;
                    int findpps = 0;
                    for(int index = 4; index < pkt->size ; index++) {
                        //代码比较扭曲,具体就是找到pps后面那个nalu的分隔符
                        if(pkt->data[index] == 0 && pkt->data[index + 1] == 0 && pkt->data[index + 2] == 0){
                            if(!findpps) {
                                findpps = 1;
                                continue;
                            }
                            if(findpps) {
                                extradata_size = index;
                                extradata = malloc(extradata_size * sizeof(uint8_t));
                                memcpy(extradata, pkt->data, extradata_size * sizeof(uint8_t));
                                if(is->video_st->codecpar->extradata) {
                                    free(is->video_st->codecpar->extradata);
                                }
                                //拷贝到codecpar中这个两个参数需要在解码器中使用
                                is->video_st->codecpar->extradata = extradata;
                                is->video_st->codecpar->extradata_size = extradata_size;
                                //flush_pkt会激活VideoToolBoxContext的refresh_request
                                packet_queue_put(&is->videoq, &flush_pkt);
                                break;
                            }
                        }
                    }
                }
  1. 在IJKVideoToolBox.m中
    在上面已经拿到sps, pps但是在VideoToolBoxContext的codecpar中extradata和extradata_size仍然是旧的,需要主动更新
static int decode_video_internal(...) {
  ....
  //想看refresh_request什么情况为ture? 直接全局搜 refresh_request = true
  //中间的代码确实没有啥好贴上来的
  if(context->refresh_request) { 
      .....
       if(context->codecpar->extradata) {
            av_free(context->codecpar->extradata);
        }
        context->codecpar->extradata_size = ffp->is->video_st->codecpar->extradata_size;
         //context->extradata和ffp中的extradata都会在shutdown时会释放,所以传指针context->extradata就是成为野指针然后crash
        context->codecpar->extradata = av_memdup(ffp->is->video_st->codecpar->extradata, context->codecpar->extradata_size);
        context->vt_session = vtbsession_create(context);
      .....
  }
  ....
}

你可能感兴趣的:(ijkplayer上iOS根据AVPacket动态刷新VideoToolBox)