PS流解复用成H264和音频流(ES提取)
技术在于交流、沟通,转载请注明出处并保持作品的完整性。
原文: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流和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: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
上一篇: Gb28181之Ps流解析H264
下一篇: kvm虚拟机nat模式下上不了网