項目地址源碼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); }