音视频开发

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);
            }
        }
上一篇 下一篇

猜你喜欢

热点阅读