1. 程式人生 > >PS流解複用成H264和音訊流(ES提取)

PS流解複用成H264和音訊流(ES提取)

 

技術在於交流、溝通,轉載請註明出處並保持作品的完整性。

原文: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