大家都知道ffmpeg的avformat_open_input()函数可以直接打开本地文件或网络流进行解码,我们不用关心分析视频的数据,但是对于加密的视频就无法进行播放,于是就需要对源数据进行处理后,组包成标准的H264格式流,再进行解码。本解码库支持标准的H264格式解码,支持流式解码,不用进行NALU分割,直接将获取到的UDP流送入解码函数即可。  

        H264DecFrame函数的内部我做了缓存组包处理,ffmpeg有av_parser_parse2函数实现这个功能,但是实际使用中发现有问题,包长度总数不对,导致解码出来的视频画面异常,于是自己写了组包的部分。

       本API仅可解码H264裸流,不可以播放封装的格式如MP4、AVI等。

   

        API函数如下:

* 功能描述:创建解码器
    * @param width:输入图像宽
    * @param height:输入图像高
    * @param picFormat:输入图像格式 0:YUV420
    * @param decThread:输入 解码线程数
    *
    * @return true:成功  false:失败
    */
    bool H264DecCreate(int width, int height, int picFormat = 0, int decThread = 4);


    /**
    * 功能描述:销毁解码器
    */
    void H264DecDestroy();


    /**
    * 功能描述:对输入的一段码流进行解码并按帧输出图像
      本函数仅支持流式解码,对于以“00 00 01”为 nalu 分隔符的连续、线性 H.264 码流,
      用户可从任意起始地址、任意长度配置给解码器解码。
      在调用本函数过程中需要注意以下两点:
        −  在解码过程中,用户应该将码流分段,并依次配置给解码器。当用户调用此函
        数,将一段码流配置给解码器之后,应对函数的参数做如下配置:
        pStream=NULL;iStreamLen=0 然后循环调用此函数,直到函数返
        回 H264DEC_NEED_MORE_BITS 时才能再次配置一段新的码流。
        在上述循环调用的过程中,如果函数返回 H264DEC_OK 则表明有一帧图像
        输出,用户必须在循环调用内部及时处理存储在 pDecFrame 中的图像。
        在上述循环调用的过程中,如果函数返回 H264DEC_OK 则表明有一帧图像输
        出,用户必须在循环调用内部及时处理存储在 pDecFrame 中的图像
    * @param pStream:输入 码流起始地址
    * @param streamLen: 输入  码流长度
    * @param pY: 输出 Y分量
    * @param pU: 输出 U分量
    * @param pV: 输出 V分量
    * @param yStride: 输出 Y分量的Stride
    * @param uvStride: 输出 U/V分量的Stride
    * @param flag: 
    *
    * @return 
    */
    int H264DecFrame(unsigned char* pStream, int streamLen, Dec_Frame_S* decFrame, int flag);

调用方法:

struct frameStruct
{
	UCHAR* data;
	int length;
};


FILE* h264;
int decode(void* para)
{ 
	bool res = false;
	res = yhDecoder->H264DecCreate(width,height,0);  
	dec_frame = new Dec_Frame_S;
	dec_frame->pY = new UCHAR[1920*1080];
	dec_frame->pU = new UCHAR[1920*1080];
	dec_frame->pV = new UCHAR[1920*1080];
	dec_frame->yStride = 0;
	dec_frame->uvStride = 0;
 
	while (len>0)
	{
           char data[1024];
		   h264 = fopen("F:\\Video\\blackissue.264", "rb");
           int len = (int)fread(data, 1, 1024, h264);
           if(len<=0)
                break;
            frameStruct* dataFrame = new frameStruct;
            dataFrame->data= data;
            dataFrame->length =1024;
			result = yhDecoder->H264DecFrame(dataFrame->data, dataFrame>length,dec_frame, 0);			
			delete[] dataFrame->data;
			dataFrame->data = NULL;
			delete dataFrame;
			dataFrame = NULL;
	 
			while (H264DEC_NEED_MORE_BITS != result)  //满足一帧
			{
				if (H264DEC_NO_PICTURE == result) /* 解码器中已经没有残留图像 */
				{
					break;
				}
				if (H264DEC_OK == result) /* 输出一帧图像 */
				{			
					canShow = true;	
					//int ret = sdlDisplay->UpdateSDLWindowYUV(dec_frame->pY, dec_frame->pU, dec_frame->pV, width, height, dec_frame->yStride, dec_frame->uvStride);

					if (!isUDPStream)
					  SDL_Delay(10);
				}
				/* 继续解码剩余H.264码流 */
				result = yhDecoder->H264DecFrame(NULL, 0, dec_frame, 0);
			}			
		 
	}
 

	yhDecoder->H264DecDestroy();
	//sdlDisplay->CloseSDL();

	delete[] effictiveData;
	effictiveData = NULL;
	delete dec_frame->pY;
	dec_frame->pY = NULL;
	delete dec_frame->pU;
	dec_frame->pU = NULL;
	delete dec_frame->pV;
	dec_frame->pV = NULL;
	delete dec_frame;
	dec_frame = nullptr;
	
	return 0;
}