背景
项目中有一个切换分辨率的需求,但是服务器更新sps,pps后,并没有在SDP报文中更新sprop-paraemter-sets字段导致VideoToolBox无法解码视频文件
解决思路
在av_read_frame后判断nalu_type,如果是7并包含8的话(我们sps,pps是同一个包),刷新VideoToolBox,实现动态码率的效果
解决方法
- 在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;
}
}
}
}
- 在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);
.....
}
....
}
网友评论