PS流解複用成H264和音訊流(ES提取)
阿新 • • 發佈:2018-11-11
技術在於交流、溝通,轉載請註明出處並保持作品的完整性。
原文:https://blog.csdn.net/hiwubihe/article/details/80759142
[本系列相關文章]
- H264和音訊流打包成PS流 (MPEG2-PS)
- PS流解複用成H264和音訊流(ES提取)
- H264和音訊流打包成TS流 (MPEG2-TS)
- TS流解複用成H264和音訊流(ES提取)
- FLV檔案格式基礎
- 解複用FLV檔案(基於FFMPEG解析FLV(h264+aac))
- 解複用FLV檔案(不用FFMPEG,C++實現)
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解複用原理
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