H264 数据提取sps 和 pps 信息

PS:在项目中运用到了硬件编码卡编H264 数据,由于解码需要sps和pps才能解除帧,那么就需要提取sps 和pps。

在使用x264 编码中 可以直接通过帧类型获取到。但是使用硬件编码则需要自己运算,下直接上代码。

软件编码x264 为例:

void encodeData(int8_t *data) {
//    long long int start =printtime();
    //编码
    pthread_mutex_lock(&mutex);
    memcpy(pic_in->img.plane[0], data, ySize);
    for (int i = 0; i < uvSize; ++i) {
        //间隔1个字节取一个数据
        //u数据
        *(pic_in->img.plane[1] + i) = *(data + ySize + i * 2 + 1);
        //v数据
        *(pic_in->img.plane[2] + i) = *(data + ySize + i * 2);
    }

    //编码出的数据
    x264_nal_t *pp_nal;
    //编码除了几个nalu
    int pi_nal;
    x264_picture_t pic_out;
    //编码
    int ret = x264_encoder_encode(videoCodec, &pp_nal, &pi_nal, pic_in, &pic_out);
    if (ret < 0) {
        pthread_mutex_unlock(&mutex);
        return;
    }
//    long long int curr=printtime();
//    LOGI("--------------->使用编码时长:%lld",(curr-start));
    LOGI("--------------->编出的帧数:%d,编码的类型 %d", pi_nal);
    int sps_len, pps_len;
    uint8_t sps[100];
    uint8_t pps[100];
    for (int i = 0; i < pi_nal; ++i) {
        //数据类型
        if (pp_nal[i].i_type == NAL_SPS) {
//            LOGI("--------------->编出的帧数 NAL_SPS");
            //去掉00 00 00 01
            sps_len = pp_nal[i].i_payload - 4;
            memcpy(sps, pp_nal[i].p_payload + 4, sps_len);
        } else if(pp_nal[i].i_type == NAL_PPS){
//            LOGI("--------------->编出的帧数 NAL_PPS");
            pps_len = pp_nal[i].i_payload - 4;
            memcpy(pps, pp_nal[i].p_payload + 4, pps_len);
            sendSpsPps(sps, pps, sps_len, pps_len);
        }else {
            //类型5是关键帧 , 编码后的data 数据   ,长度
            sendFrame(pp_nal[i].i_type, pp_nal[i].p_payload, pp_nal[i].i_payload);
        }
    }

    pthread_mutex_unlock(&mutex);

}

其中 pi_nal 为帧的个数,一般都是编一次出一个。

其中硬件编码:

void encodeData(int8_t *data) {



    lib_encode_inbuf_update(avc_en_t, reinterpret_cast<uint8_t *>(data), 0, 0, g_width, g_height,1);
    sem_wait_read(avc_en_t);
//   dump 出h264 数据 么问题
//    LOGI(" ------------>%p ,and ecvode lngth:%d ", data, avc_en_t->outlength);
//
//        int tmpFd = open("/sdcard/test.h264", O_WRONLY | O_APPEND);
//        if ( tmpFd < 0 ) {
//            LOGI("Creat AF dump file failed!");
//        } else {
//            write(tmpFd, avc_en_t->out_buf_enc ,  avc_en_t->outlength);
//            close(tmpFd);
//       }
    if (is_idr(avc_en_t->out_buf_enc)) {
        unsigned int sps_size, pps_size, sei_size;
        int nal_type = (avc_en_t->out_buf_enc)[4] & 0x1F;
        sps_size = h264_decode_get_frame_size(reinterpret_cast<char *>(avc_en_t->out_buf_enc),
                                              avc_en_t->outlength);
        //printf("sps_size = %d!\n",sps_size);
        pps_size = h264_decode_get_frame_size(
                reinterpret_cast<char *>(avc_en_t->out_buf_enc + sps_size),
                avc_en_t->outlength - sps_size);
        sendSpsPps(avc_en_t->out_buf_enc, avc_en_t->out_buf_enc + sps_size, sps_size, pps_size);
        //printf("pps_size = %d!\n",pps_size);
        sei_size = h264_decode_get_frame_size(
                reinterpret_cast<char *>(avc_en_t->out_buf_enc + sps_size + pps_size),
                avc_en_t->outlength - sps_size - pps_size);
        //printf("sei_size = %d!\n",sei_size);
        sendFrame(nal_type, avc_en_t->out_buf_enc + sps_size + pps_size + sei_size,
                  avc_en_t->outlength - sps_size - pps_size - sei_size);

    } else {
        int nal_type = (avc_en_t->out_buf_enc)[4] & 0x1F;
        sendFrame(nal_type, avc_en_t->out_buf_enc, avc_en_t->outlength);
        LOGE("发送关键帧了");
        file->Write_file("success\n", "/keyframe.txt");

    }

    sem_post_read(avc_en_t);//Can't be omitted

}

/***
*** 此方法可以判断帧的类型
**/
int is_idr(uint8_t *encode_card_out) {

    int nal_type = (encode_card_out)[4] & 0x1F;
    if (nal_type != 5 && nal_type != 7 && nal_type != 8 && nal_type != 2) {
        return 0;
    }
    return 1;
}

unsigned int h264_decode_get_frame_size(char *stream_buff, unsigned int len) {
    unsigned int i, sendlenth;
    unsigned int bFindStart = 0, bFindEnd = 0;
    unsigned int s32UsedBytes = 0;
    unsigned int s32ReadLen = 0;

    char *pu8Buf = stream_buff;

    for (i = 0; i < len / 2 - 4; i++) {
        //int tmp = pu8Buf[i+3] & 0x1F;
        if (pu8Buf[i] == 0 && pu8Buf[i + 1] == 0 && pu8Buf[i + 2] == 1) {
            bFindStart = 1;
            i += 4;
            break;
        }
    }

    for (; i < len / 2 - 4; i++) {
        //int tmp = pu8Buf[i+3] & 0x1F;
        if (pu8Buf[i] == 0 && pu8Buf[i + 1] == 0 && pu8Buf[i + 2] == 1) {
            bFindEnd = 1;
            break;
        }
    }

    if (i > 0)
        s32ReadLen = i - 1;


    if (bFindStart == 0) {
        //printf("SAMPLE_TEST: can not find start code!s32ReadLen %d, s32UsedBytes %d. \n", s32ReadLen, s32UsedBytes);
    } else if (bFindEnd == 0) {
        s32ReadLen = i + 8;
    }

    return s32ReadLen;

}

猜你喜欢

转载自blog.csdn.net/qq_33023933/article/details/111320860
今日推荐