iOS ijkPlayer改为p2p帧模式播放问题点
2020-06-03 本文已影响0人
Johnny_Wu
一、硬解不支持Hevc
开启硬解:
[options setPlayerOptionIntValue:1 forKey:@"videotoolbox"];
主要原因:
硬解annex-b格式的视频帧,需要把annex-b转换为Avcc格式。看ijkplayer源码,只有H264的转换函数:ff_isom_write_avcc
解决办法:
对于H265,需要把annex-b转换为Hvcc格式,发现有ff_isom_write_hvcc函数,只是没有公开函数。只需要加入hevc.h头文件就可以使用:
IJKVideoToolBoxSync.m 大概1047行
if(codecpar->codec_id==AV_CODEC_ID_HEVC)
ff_isom_write_hvcc(pb, extradata, extrasize,1);
else
ff_isom_write_avcc(pb, extradata, extrasize);
后面的validate_avcC_spc校验函数,可以校验H264的,但无法校验H265,可以注释掉,也可以控制只校验H264。
二、硬解不支持动态分辨率
开启硬解支持动态分辨率:
[options setPlayerOptionIntValue:1 forKey:@"videotoolbox-handle-resolution-change"];
IJKVideoToolBoxSync.m 大概690行 decode_video这个函数内
主要原因:av_packet_get_side_data这个无法从AVPacket获取到对应的extradata值,猜测这个函数只支持avcc格式,不支持annex-b。
解决办法:自己实现获取extradata功能
我项目的主帧的头部是带上sps,pps等信息的。所以我只需从第一个字节获取到主帧标志的前一个字节,就是对应的extradata。具体实现如下:
static uint8_t s_alBuf[300];
//by alex 读取extradata videoType:0:H264 1:H265
static uint8_t *al_packet_get_side_data(AVPacket *avpkt,int *size,int videoType){
uint8_t *ptr = avpkt->data;
uint8_t keyFlag = 0x05; //h264主帧
if(videoType==1)
keyFlag = 0x13; //h265主帧
int extraSize = 0;
for(int i=0;i<avpkt->size;i++){
uint8_t s = ptr[i];
if(videoType==1)
s = (s & 0x7E)>>1;
else
s = s & 0x1F;
if(s!=keyFlag){
continue;
}
if(i<=3){
continue;
}
//00000001
if(ptr[i-1]==1&&ptr[i-2]==0&&ptr[i-3]==0&&ptr[i-4]==0){
extraSize = i-4;
break;
}
//000001
if(ptr[i-1]==1&&ptr[i-2]==0&&ptr[i-3]==0){
extraSize = i-3;
break;
}
}
if(extraSize>0){
*size = extraSize;
int bufSize = sizeof(s_alBuf);
bufSize = MIN(bufSize, extraSize);
memset(s_alBuf, 0, sizeof(s_alBuf));
memcpy(s_alBuf, ptr, bufSize);
return s_alBuf;
}
return NULL;
}
IJKVideoToolBoxSync.m 的函数decode_video修改如下:
大概在decode_video函数下面10行
if (context->ffp->vtb_handle_resolution_change &&
(context->codecpar->codec_id == AV_CODEC_ID_H264||context->codecpar->codec_id == AV_CODEC_ID_HEVC)) {
//by alex
if(ff_avpacket_is_key(avpkt)){
size_data = av_packet_get_side_data(avpkt, AV_PKT_DATA_NEW_EXTRADATA, &size_data_size);
if(!size_data){
if(avctx->codec_id == AV_CODEC_ID_HEVC)
size_data = al_packet_get_side_data(avpkt, &size_data_size,1);
else
size_data = al_packet_get_side_data(avpkt, &size_data_size,0);
}
}