欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-07-06 12:57:30
...

 

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

原文: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中的解复用流程如下图所示:

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

本文将基于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,送入不同解码处理单元即可,流程大致如下:

PS流解复用成H264和音频流(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流解复用成H264和音频流(ES提取)

 

PS解复用库PsDmuxer.dll调用Demo

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

Date Created:	2014-10-25
Author:			wubihe QQ:1269122125 Email:aaa@qq.com
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