利用H264解码分为几个步骤:
注意一点在添加头文件的时候要添加extern "C",不然会出现错误
- extern "C"
- {
- #include <avcodec.h>
- #include <avformat.h>
- #include <avutil.h>
- #include <swscale.h>
- };
这里申明了几个全局变量
- AVCodec *pCodec = NULL;
- AVCodecContext *pCodecCtx = NULL;
- SwsContext *img_convert_ctx = NULL;
- AVFrame *pFrame = NULL;
- AVFrame *pFrameRGB = NULL;
1. 初始化
- int H264_Init(void)
- {
- /* must be called before using avcodec lib*/
- avcodec_init();
- /* register all the codecs */
- avcodec_register_all();
- /* find the h264 video decoder */
- pCodec = avcodec_find_decoder(CODEC_ID_H264);
- if (!pCodec) {
- fprintf(stderr, "codec not found\n");
- }
- pCodecCtx = avcodec_alloc_context();
- /* open the coderc */
- if (avcodec_open(pCodecCtx, pCodec) < 0) {
- fprintf(stderr, "could not open codec\n");
- }
- // Allocate video frame
- pFrame = avcodec_alloc_frame();
- if(pFrame == NULL)
- return -1;
- // Allocate an AVFrame structure
- pFrameRGB=avcodec_alloc_frame();
- if(pFrameRGB == NULL)
- return -1;
- return 0;
- }
在最早使用的时候没有使用全局变量,初始化中也就只有init和regisger这两个函数,而这样做的下场是,非关键帧全部无法解码,只有关键帧才有办法解码。
2. 解码
解码的时候avcodec_decode_video函数是进行解码操作,在外部定义outputbuf的大小时,pixes*3,outsize是返回的outputbuf的size,值也是pixes*3。
在解码的时候这几句话的意义是将YUV420P的数据倒置。在原先使用中,发现解出来的图像居然是中心旋转图,后面在网上找了些办法,觉得这个比较实用。解码实时是很重要的,图像转化完之后也可以讲RGB图再次转化,那样也能成为一个正的图,但是那样效率就明显低了。
- pFrame->data[0] += pFrame->linesize[0] * (pCodecCtx->height-1);
- pFrame->linesize[0] *= -1;
- pFrame->data[1] += pFrame->linesize[1] * (pCodecCtx->height/2 - 1);;
- pFrame->linesize[1] *= -1;
- pFrame->data[2] += pFrame->linesize[2] * (pCodecCtx->height/2 - 1);;
- pFrame->linesize[2] *= -1;
- int H264_2_RGB(unsigned char *inputbuf, int frame_size, unsigned char *outputbuf, unsigned int*outsize)
- {
- int decode_size;
- int numBytes;
- int av_result;
- uint8_t *buffer = NULL;
- printf("Video decoding\n");
- av_result = avcodec_decode_video(pCodecCtx, pFrame, &decode_size, inputbuf, frame_size);
- if (av_result < 0)
- {
- fprintf(stderr, "decode failed: inputbuf = 0x%x , input_framesize = %d\n", inputbuf, frame_size);
- return -1;
- }
- // Determine required buffer size and allocate buffer
- numBytes=avpicture_get_size(PIX_FMT_BGR24, pCodecCtx->width,
- pCodecCtx->height);
- buffer = (uint8_t*)malloc(numBytes * sizeof(uint8_t));
- // Assign appropriate parts of buffer to image planes in pFrameRGB
- avpicture_fill((AVPicture *)pFrameRGB, buffer, PIX_FMT_BGR24,
- pCodecCtx->width, pCodecCtx->height);
- img_convert_ctx = sws_getCachedContext(img_convert_ctx,pCodecCtx->width,pCodecCtx->height,
- //PIX_FMT_YUV420P,pCodecCtx->width,pCodecCtx->height,pCodecCtx->pix_fmt,
- pCodecCtx->pix_fmt,pCodecCtx->width,pCodecCtx->height,PIX_FMT_RGB24 ,
- SWS_X ,NULL,NULL,NULL) ;
- if (img_convert_ctx == NULL)
- {
- printf("can't init convert context!\n") ;
- return -1;
- }
- pFrame->data[0] += pFrame->linesize[0] * (pCodecCtx->height-1);
- pFrame->linesize[0] *= -1;
- pFrame->data[1] += pFrame->linesize[1] * (pCodecCtx->height/2 - 1);;
- pFrame->linesize[1] *= -1;
- pFrame->data[2] += pFrame->linesize[2] * (pCodecCtx->height/2 - 1);;
- pFrame->linesize[2] *= -1;
- sws_scale(img_convert_ctx, pFrame->data, pFrame->linesize,
- 0, 0 - pCodecCtx->width, pFrameRGB->data, pFrameRGB->linesize);
- if (decode_size)
- {
- *outsize = pCodecCtx->width * pCodecCtx->height * 3;
- memcpy(outputbuf, pFrameRGB->data[0], *outsize);
- }
- free(buffer);
- return 0;
- }
//解码yuv 修改 PIX_FMT_YUV420P memcpy(outputbuf, pFrameRGB->data[2], 720*576/4); memcpy(outputbuf, pFrameRGB->data[1], 720*576/4); memcpy(outputbuf, pFrameRGB->data[0], 720*576);3. 释放资源
资源的回收。
- void H264_Release(void)
- {
- avcodec_close(pCodecCtx);
- av_free(pCodecCtx);
- av_free(pFrame);
- av_free(pFrameRGB);
- }
版权声明:本文为博主原创文章,未经博主允许不得转载。