FFmpeg解码H264为YUV420

21 篇文章 24 订阅 ¥9.90 ¥99.00

在这里我们主要用到三个函数实现解码过程,首先是H264解码初期化,其次是进行H264解码,最后 H264解码销毁,具体代码实现如下。

H264Decoder.h

#pragma once
extern "C"{
#include <libavformat\avformat.h>

#include <libavutil\pixfmt.h>
#include <libavcodec\avcodec.h>


}
#define X264_DECODER_H long

typedef struct
{
    struct AVCodec *codec;// Codec
    struct AVCodecContext *c;// Codec Context
	AVCodecParserContext *pCodecParserCtx;
    int frame_count;
    struct AVFrame *picture;// Frame
    AVPacket avpkt;
    
    int iWidth;
    int iHeight;
    int comsumedSize;
    int got_picture;
} X264_Decoder_Handle;

class H264Decoder
{
public:
	H264Decoder(void);
	~H264Decoder(void);
	public:
    // H264解码初期化
    X264_DECODER_H X264Decoder_Init();
    
    /*
     H264数据解码,解码后的数据为yuv420格式
     dwHandle:初期化时返回的句柄
     pDataIn:待解码数据
     nInSize:待解码数据长度
     pDataOut:解码后的数据,存储空间由调用者申请
     nOutSize:存储空间大小
     
     nWidth:解码后的图像宽度
     nHeight:解码后的图像高度
     */
    int X264Decoder_Decode(X264_DECODER_H dwHandle, uint8_t *pDataIn, int nInSize, uint8_t *pDataOut, int *nOutSize, int *nWidth,int *nHeight);
	/*
     H264解码销毁
     dwHandle:初期化时返回的句柄
     */
    void X264Decoder_UnInit(X264_DECODER_H dwHandle);
    
protected:
    void pgm_save2(unsigned char *buf, int wrap, int xsize, int ysize, uint8_t *pDataOut)
    {
        int i;
        for(i = 0; i < ysize; i++)
        {
            memcpy(pDataOut+i*xsize, buf + /*(ysize-i)*/i * wrap, xsize);
        }
    }
};

H264Decoder.cpp

#include "stdafx.h"
#include "H264Decoder.h"

H264Decoder::H264Decoder(void)
{
}


H264Decoder::~H264Decoder(void)
{
}

X264_DECODER_H H264Decoder::X264Decoder_Init()
{
    X264_Decoder_Handle *pHandle = (X264_Decoder_Handle *)malloc(sizeof(X264_Decoder_Handle));
    if (pHandle == NULL)
    {
        return -1;
    }
    
    avcodec_register_all();
    
    
    
    pHandle->codec = avcodec_find_decoder(AV_CODEC_ID_H264);
    if (!pHandle->codec)
    {
        return -2;
    }
    
    pHandle->c = avcodec_alloc_context3(pHandle->codec);
    if (!pHandle->c)
    {
        return -3;
    }
    
    pHandle->c->codec_type = AVMEDIA_TYPE_VIDEO;
    pHandle->c->pix_fmt =AV_PIX_FMT_YUV420P;
	pHandle->c->flags2|=AV_CODEC_FLAG2_CHUNKS;

	pHandle->pCodecParserCtx=av_parser_init(AV_CODEC_ID_H264);  
    if (!pHandle->pCodecParserCtx){  
        printf("Could not allocate video parser context\n");  
        return -6;  
    }  

    if (avcodec_open2(pHandle->c, pHandle->codec, NULL) < 0)
    {
        return -4;
    }
    
    pHandle->picture =av_frame_alloc();
    if (!pHandle->picture)
    {
        return -5;
    }
    
    pHandle->frame_count = 0;
    
    return (X264_DECODER_H)pHandle;
}
void H264Decoder::X264Decoder_UnInit(X264_DECODER_H dwHandle)
{
    if (dwHandle <= 0)
    {
        return;
    }
    
    X264_Decoder_Handle *pHandle = (X264_Decoder_Handle *)dwHandle;
    
    avcodec_close(pHandle->c);
    av_free(pHandle->c);
	av_free(pHandle->picture->data[0]);
    av_free(pHandle->picture);
    
    free(pHandle);
}
int H264Decoder::X264Decoder_Decode(X264_DECODER_H dwHandle, uint8_t *pDataIn, int nInSize, uint8_t *pDataOut, int *nOutSize, int *nWidth, int *nHeight)
{
    if (dwHandle <= 0)
    {
        return -1;
    }
	unsigned char buf[20*1024]={0};
	
	
    X264_Decoder_Handle *pHandle = (X264_Decoder_Handle *)dwHandle;

	av_init_packet(&(pHandle->avpkt));

	pHandle->avpkt.size = nInSize;
	pHandle->avpkt.data = pDataIn;

    while (pHandle->avpkt.size > 0)
    {
        pHandle->comsumedSize = avcodec_decode_video2(pHandle->c, pHandle->picture, &pHandle->got_picture, &(pHandle->avpkt));
        if (pHandle->comsumedSize < 0)
        {
            return -2;
        }
        
        if (pHandle->got_picture)
        {
			
            *nWidth = pHandle->c->width;
			
            *nHeight = pHandle->c->height;
			
			if(pHandle->c->width!=0 && pHandle->c->height!=0)
				{*nOutSize=pHandle->c->width*pHandle->c->height*3/2;}
			else
			    {*nOutSize=0;}
			
            pgm_save2(pHandle->picture->data[0],
                      pHandle->picture->linesize[0],
                      pHandle->c->width,
                      pHandle->c->height,pDataOut);
            pgm_save2(pHandle->picture->data[1],
                      pHandle->picture->linesize[1],
                      pHandle->c->width/2,
                      pHandle->c->height/2,
                      pDataOut +pHandle->c->width * pHandle->c->height);
            pgm_save2(pHandle->picture->data[2],
                      pHandle->picture->linesize[2],
                      pHandle->c->width/2,
                      pHandle->c->height/2,
                      pDataOut +pHandle->c->width * pHandle->c->height*5/4);
        }
        
        if (pHandle->avpkt.data)
        {
            pHandle->avpkt.size -= pHandle->comsumedSize;
            pHandle->avpkt.data += pHandle->comsumedSize;
        }
    }
   
    return 0;
}


  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值