FFmpeg解碼裸H264數據

項目地址源碼https://github.com/liluojun/PlayVideo

      之前弄了下Android硬解H264https://blog.csdn.net/hjt505694246/article/details/105046233,但是硬解多少還是受到硬件影響所有再折騰下ffmpeg軟解。

關於ffmpeg解碼的文章很多我也是業餘接觸下並且我對C語言也是個初學者,有不足的地方還請見諒。

先上代碼

先初始化解碼器

int FFmpegEncode::creatFFmpeg(AVCodecID id) {
    avcodec_register_all();
    mAVCodec = avcodec_find_decoder(id);
    if (mAVCodec == NULL) {
        printf("mAVCodec==NULL\n");
        return -1;
    }

    mAVCodecContext = avcodec_alloc_context3(mAVCodec);
    if (mAVCodecContext == NULL) {
        printf("mAVCodecContext==NULL\n");
        return -1;
    }
    if (avcodec_open2(mAVCodecContext, mAVCodec, NULL) < 0) {
        printf("avcodec_open2 error\n");
        return -1;
    }
    mAVFrame = av_frame_alloc();
    if (!mAVFrame) {
        printf("av_frame_alloc error\n");
        return -1;
    }
    mAVPacket = av_packet_alloc();
    if (!mAVPacket) {
        printf("av_packet_alloc error\n");
        return -1;
    }
    av_init_packet(mAVPacket);
    return 0;
}
設置解碼參數:寬高、幀率、數據類型
int FFmpegEncode::initAVCodecContext(int width, int heigth, int fps, AVPixelFormat pixFmt) {
    if (mAVCodecContext == NULL) {
        printf("initAVCodecContext NULL\n");
        return -1;
    }
    if (width <= 0 || heigth <= 0 || fps <= 10) {
        printf("initAVCodecContext Parameters of the abnormal\n");
        return -1;
    }
    mAVCodecContext->width = width;
    mAVCodecContext->height = heigth;
    mAVCodecContext->frame_bits = fps;
    mAVCodecContext->pix_fmt = pixFmt;
    return 0;
}
喂數據解碼:framedata是源數據,*outputY,*outputU,*outputV是解碼後的yuv三個分量數據,pixfmt數據類型。
這裏我有個拷貝的動作,據說有零拷貝的方式,有木有大佬知道的可以指點一下。
int FFmpegEncode::encodeFFmpeg(uint8_t *framedata, int framelen,//input
                               uint8_t *outputY, uint8_t *outputU, uint8_t *outputV, int *width,
                               int *height,
                               AVPixelFormat pixfmt) {
    if (mAVPacket == NULL) {
        printf("encodeFFmpeg NULL\n");
        return -1;
    }
    mAVPacket->data = framedata;
    mAVPacket->size = framelen;
    while (mAVPacket->size > 0) {
        if (avcodec_send_packet(mAVCodecContext, mAVPacket)) {
            printf("%s %d avcodec_send_packet fail\n", __func__, __LINE__);
            return -2;
        }
        if (avcodec_receive_frame(mAVCodecContext, mAVFrame)) {
            printf("%s %d avcodec_receive_frame fail\n", __func__, __LINE__);
            return -3;
        }

        switch (mAVCodecContext->pix_fmt) {
            case AV_PIX_FMT_YUV420P: {
                memcpy(outputY, mAVFrame->data[0], *width * *height);
                memcpy(outputU, mAVFrame->data[1], *width * *height / 4);
                memcpy(outputV, mAVFrame->data[2], *width * *height / 4);

                width = &(mAVCodecContext->width);
                height = &(mAVCodecContext->height);
                pixfmt = mAVCodecContext->pix_fmt;
                break;
            }
            case AV_PIX_FMT_NV21: {

                memcpy(outputY, mAVFrame->data[0], *width * *height);
                memcpy(outputU, mAVFrame->data[1], *width * *height / 4);
                memcpy(outputV, mAVFrame->data[2], *width * *height / 4);
                width = &(mAVCodecContext->width);
                height = &(mAVCodecContext->height);
                pixfmt = mAVCodecContext->pix_fmt;
                break;
            }
            default: {
                printf("mAVCodecContext->pix_fmt Failure to identify\n");
                return -4;
            }
        }

        return 0;
    }
}
釋放解碼器資源
void
FFmpegEncode::unEncode() {
    avcodec_close(mAVCodecContext);
    av_free(mAVCodecContext);
    av_frame_free(&mAVFrame);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章