PS流解复用成H264和音频流(ES提取)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hiwubihe/article/details/80759142

技术在于交流、沟通,转载请注明出处并保持作品的完整性。

原文:https://blog.csdn.net/hiwubihe/article/details/80759142

[本系列相关文章]

PS流封装H264及音频的原理已经在“H264和音频流打包成PS流 (MPEG2-PS)”中进行了详细讲解,本篇不再赘述。知道怎么封装PS,解析自然不在话下,解析PS流其实已经没有H264什么事了,只要把PS中包含ES根据类型不同分别进行不同处理即可。如H264流根据stream_id把属于一路的流全送给H264解码器即可。"ISO13818-1中的解复用流程如下图所示:

本文将基于C/C++提供一个PS流的解复用库PsDmuxer.dll,并提供DEMO测试程序。打包程序包括一个PsDmuxerDemo和PsDmuxer库,文档包括主要参考的几篇文章"iso13818-1.pdf" "PS流和TS流介绍.docx","视音频数据PS封装-offset.doc"。

PS解复用原理

PS头表示一个PS打包单元,解析必须从PS开始,第一个PS头前面数据全部丢弃。找到PS头然后把PS头里面的子单元解析出来,子单元包括PS SYSTEM HEAD,PS MAP,PES等。PS SYSTEM HEAD,PS MAP解析作为该PS流的解码显示参考信息,再解析PES获取当前PS头里面的所有ES,送入不同解码处理单元即可,流程大致如下:

解复用库PsDmuxer.dll的头文件

/*******************************************************************************
Copyright (c) wubihe Tech. Co., Ltd. All rights reserved.
--------------------------------------------------------------------------------

Date Created:	2014-10-25
Author:			wubihe
Description:	PS流解复用 提取H264 ES流 头文件

--------------------------------------------------------------------------------
Modification History
DATE          AUTHOR          DESCRIPTION
--------------------------------------------------------------------------------

********************************************************************************/
#ifndef IPSDMUXER_H_
#define IPSDMUXER_H_

#ifdef WIN32
#include <windows.h>
#include <windef.h>
#ifdef PSDMUXER_EXPORTS
#define DLLEXPORT __declspec(dllexport)
//#define   DLLEXPORT
#else
#define DLLEXPORT
#endif
#else
#define DLLEXPORT
#define WINAPI
#endif //WIN32

#include <string>
///////////////////////////////////////////////////////////////////////////
#ifdef __cplusplus
extern "C"
{
#endif

/******************************************************************************
PsDmuxer.dll宏定义
*******************************************************************************/





/******************************************************************************
PsDmuxer.dll错误码定义,PsDmuxer.dll库错误码的范围:0-255
*******************************************************************************/



/******************************************************************************
PsDmuxer.dll数据结构定义
*******************************************************************************/
///日志级别类型
typedef enum _PDM_LOG_LEVEL
{
	PDM_LOG_TRACE =		0,
	PDM_LOG_DEBUG =		1,                      
	PDM_LOG_INFO  =		2,                      
	PDM_LOG_WARN  =		3,                      
	PDM_LOG_ERROR =		4, 
	PDM_LOG_FATAL =		5
} PDM_LOG_LEVEL;

//复合流类型
typedef enum _PDM_STREAM_TYPE
{
	MUXSER_VIDEO_TYPE_H264	=		0,
	MUXSER_VIDEO_TYPE_H265	=		1,                      
	MUXSER_AUDIO_TYPE_G711A =		2,   
	MUXSER_AUDIO_TYPE_AAC	=		3,
	MUXSER_AUDIO_TYPE_UNSUPPORT	=	4,
	MUXSER_SUPPORT_NUM		=       5
} PDM_STREAM_TYPE;

//帧信息
typedef struct tagPdmFrameInfo
{
	//流类型
	PDM_STREAM_TYPE eType		;
	//流ID
	int			    iStreamId	;
	//帧数据
	unsigned char * pFrame		;
	//帧大小
	int				iFrameLen	;
	//帧PTS
	LONG64			lPts		; 
	//帧DTS
	LONG64			lDts        ;           
} PdmFrameInfo;



/****************************************************************************
                        General Callback
                          通用回调接口
****************************************************************************/
typedef void(CALLBACK *PDM_LogCBFun)(PDM_LOG_LEVEL nLogLevel, const char *szMessage, void* pUserData );  
//回调函数中数据拷贝到用户自己的缓存中
typedef void(CALLBACK *PDM_ParserCBFun)(int iHandle, PdmFrameInfo stFrameInfo,void* pUserData ); 

/****************************************************************************
                        General System Interface
                            通用系统接口
****************************************************************************/

/**************************************************************************
* Function Name  : PDM_SetLogCallBack
* Description    : 设置库日志回调
* Parameters     : pLogFunc	(日志回调函数)	
* Parameters     : pUserData(日志回调用户数据)
* Return Type    : void
* Last Modified  : wubihe
***************************************************************************/

DLLEXPORT void  WINAPI PDM_SetLogCallBack(PDM_LogCBFun pLogFunc,	void* pUserData);


/**************************************************************************
* Function Name  : PDMCreateDMuxHandle
* Description    : 创建PS流解复用器句柄
* Parameters     : 
* Return Type    : int >1为合法句柄,<=0非法 最大支持299路
* Last Modified  : wubihe
***************************************************************************/
DLLEXPORT int  WINAPI  PDM_CreateDMuxHandle();


/**************************************************************************
* Function Name  : PDM_SetParserCallback
* Description    : PS流解复用器回调函数设置
* Parameters     : iHandle		   解复用器句柄
* Parameters     : pCallbackFunc   解析回调函数
* Parameters     : pUserData	   用户数据
* Return Type    : bool
* Last Modified  : wubihe
***************************************************************************/
DLLEXPORT bool  WINAPI  PDM_SetParserCallback(int iHandle,PDM_ParserCBFun pCallbackFunc,	void* pUserData);

/**************************************************************************
* Function Name  : PDM_DataInput
* Description    : PS流数据输入
* Parameters     : iHandle		解复用器句柄
* Parameters     : pDate		输入PS数据
* Parameters     : iLen			输入PS数据长度
* Return Type    : bool 
* Last Modified  : wubihe
***************************************************************************/
DLLEXPORT bool  WINAPI PDM_DataInput(int iHandle,unsigned char *pDate,int iLen);

/**************************************************************************
* Function Name  : PDM_GetParameter
* Description    : PS流解复用器获取解析综合参数
* Parameters     : iHandle		复用器句柄
* Return Type    : bool 
* Last Modified  : wubihe
***************************************************************************/
DLLEXPORT bool  WINAPI PDM_GetParameter(int iHandle);

/**************************************************************************
* Function Name  : PDM_DestroyDMuxHandle
* Description    : PS流解复用器销毁
* Parameters     : iHandle		复用器句柄
* Return Type    : void 
* Last Modified  : wubihe
***************************************************************************/
DLLEXPORT void WINAPI  PDM_DestroyDMuxHandle(int iHandle);
#ifdef __cplusplus
}
#endif



#endif /* IPSDMUXER_H_ */

PS解复用库PsDmuxer.dll调用流程

PS解复用库PsDmuxer.dll调用Demo

/*******************************************************************************
Copyright (c) wubihe Tech. Co., Ltd. All rights reserved.
--------------------------------------------------------------------------------

Date Created:	2014-10-25
Author:			wubihe QQ:1269122125 Email:[email protected]
Description:	PS流解封装库PsDmuxer使用Demo 试用版本Demo只能运行240S 需要授权库或者
全部源码请联系作者
--------------------------------------------------------------------------------
Modification History
DATE          AUTHOR          DESCRIPTION
--------------------------------------------------------------------------------

********************************************************************************/

#include <stdio.h>
#include <map>
#include "IPsDmuxer.h"


#define  MAX_BUFFER_SIZE     (1024*8)
#define  MAX_OUT_BUFFER_SIZE (1024*1024)

static FILE *gInputFile = NULL;


std::map<unsigned char,FILE*> mapFile;


//读取PS数据缓存
unsigned char		gszReadBuffer[MAX_BUFFER_SIZE];

void CALLBACK LogCBFun(PDM_LOG_LEVEL nLogLevel, const char *szMessage, void* pUserData )
{
	printf("%s\n",szMessage);
}

void CALLBACK ParserCBFun(int iHandle, PdmFrameInfo stFrameInfo,void* pUserData )
{
	std::map<unsigned char,FILE*>::iterator it = mapFile.find(stFrameInfo.iStreamId);
	if(it == mapFile.end())
	{
		char szOutFileName[256] = {0};
		sprintf(szOutFileName, "Output_%02x.h264", stFrameInfo.iStreamId);
		FILE *pOutputFile = fopen(szOutFileName, "wb");
		if (!pOutputFile)
		{
			printf("open output file failed!\n");
			return;
		}
		mapFile[stFrameInfo.iStreamId] = pOutputFile;
	}

	FILE *pOutFile = mapFile[stFrameInfo.iStreamId];
	fwrite(stFrameInfo.pFrame, stFrameInfo.iFrameLen, 1, pOutFile);
	fflush(pOutFile);

}

void show_usage(const char *name)
{
	printf("usage:\n");
	printf("  for test ps demuxer: %s input_file\n", name);
	getchar();
}

int main(int argc, char* argv[])
{
	if (argc != 2)
	{
		show_usage(argv[0]);
		return 0;
	}
	mapFile.clear();	

	


	gInputFile = fopen(argv[1], "rb");
	if (!gInputFile)
	{
		printf("read file failed!\n");
		return 0;
	}



	



	PDM_SetLogCallBack(LogCBFun,NULL);
	int iHandle = PDM_CreateDMuxHandle();
	if(iHandle<=0)
	{
		printf("PDM_CreateDMuxHandle\n");
		return 0;
	}

	if(!PDM_SetParserCallback(iHandle,ParserCBFun,	NULL))
	{
		printf("PDM_SetParserCallback\n");
		return 0;
	}




	int iReadSize = fread(gszReadBuffer, 1, MAX_BUFFER_SIZE, gInputFile);


	while(iReadSize > 0)
	{

		PDM_DataInput(iHandle,gszReadBuffer,iReadSize);
		//实际播放应该按照比特率播放
		iReadSize = fread(gszReadBuffer, 1, MAX_BUFFER_SIZE, gInputFile);
	}

	Sleep(3000);

	PDM_DestroyDMuxHandle(iHandle);

	fclose(gInputFile);
	
	std::map<unsigned char,FILE*>::iterator it = mapFile.begin();

	while(it != mapFile.end())
	{
		fclose(it->second);
		it++;
	}


	printf("H264 file: Generate Success!\n");
	printf("GetChar To Exit!\n");
	getchar();
	return 0;

}

编译环境:   Win7_64bit+VS2008

DEMO下载地址:https://download.csdn.net/download/hiwubihe/10487109

猜你喜欢

转载自blog.csdn.net/hiwubihe/article/details/80759142