/*******************************************************} { } { File: demuxer.cpp } { Created by Tsviatko Jongov } { http://tsviatko.jongov.com } { Date : 25.01.2007 } { } { CMpeg2Demux class. } { } {*******************************************************/ #include "assert.h" #include #include "demuxer.h" #include "Pack_Header_Def.h" #include "time.h" #include #ifdef _WIN32 #include "Winsock2.h" #pragma comment(lib, "ws2_32.lib") #endif #ifdef __linux__ #include "arpa/inet.h" #endif using namespace std; static /*_inline*/ unsigned int asm_swap32(unsigned int x) { return ntohl(x); } static /*_inline*/ unsigned short asm_swap16(unsigned short x) { return ntohs(x); } CMpeg2Demux::CMpeg2Demux() : m_streamType(STREAM_TYPE_UNKNOWN) ,m_userdata(NULL) ,m_userdata2(NULL) ,m_lastiskeyfram(false) { try { fBuffer = new CBuffer(1024 * 1024); if (fBuffer == NULL) { } m_lastpts = 0; fReceiveFunction = 0; fReceiveFunction2 = 0; m_psvideo= new CBuffer(1024*50); m_esvideo= new CBuffer(1024*50); m_psaudio= new CBuffer(1024*50); m_esaudio= new CBuffer(1024*50); } catch (...) { } }; CMpeg2Demux::~CMpeg2Demux() { try { if (fBuffer != NULL) { delete fBuffer; fBuffer = NULL; } if (NULL != m_psvideo) { delete m_psvideo; m_psvideo = NULL; } if (NULL != m_esvideo) { delete m_esvideo; m_esvideo = NULL; } if (NULL != m_psaudio) { delete m_psaudio; m_psaudio = NULL; } if (NULL != m_esaudio) { delete m_esaudio; m_esaudio = NULL; } } catch (...) { } }; int CMpeg2Demux::AddData(void * Data, int Size/*, DWORD pts*/) { try { if ((Data == NULL) || (Size <= 0)) { return (-1); } /*m_timeStamp = pts;*/ fBuffer->add((char *)Data, Size); if (!Demultiplex()) { return (-1); } return (0); } catch (...) { return (-1); } } void CMpeg2Demux::SetReceiveFunction(ReceiveFunction * func, void* userdata) { try { fReceiveFunction = func; m_userdata = userdata; } catch (...) { } } void CMpeg2Demux::SetReceiveFunction2(ReceiveFunction2 * func2, void* userdata2) { fReceiveFunction2 = func2; m_userdata2 = userdata2; } uint64_t GetLocalTimeOfMicroSecond() { chrono::time_point tpMicro = chrono::time_point_cast(chrono::system_clock::now()); return tpMicro.time_since_epoch().count(); } int CMpeg2Demux::Demultiplex() { try { unsigned char * PDW {}; unsigned int Code {}; int Processed = 0; int StreamID {}; int PES_packet_length {}; int PES_header_data_length {}; int Val {}; if (fBuffer->len() <= 0) { return (0); } PDW = (unsigned char *)fBuffer->head(); while (fBuffer->len() - Processed > 140) { if ((*(unsigned int *)PDW & 0x00FFFFFF) != 0x00010000) { PDW++; Processed++; continue; } Code = asm_swap32(*(unsigned int *)PDW); StreamID = (Code & 0xFF); if (PACK_START_CODE != Code) { unsigned short pespacklen = asm_swap16(*(unsigned short *)(PDW + 4)) + 6; if (fBuffer->len() - Processed < pespacklen + 6) { break; } } if (PACK_START_CODE == Code)//前一个pspack完或下一个pspack开始 { if (fReceiveFunction != NULL && m_esvideo->len())//视频es { PS_HEADER_tag* pshead = (PS_HEADER_tag*)m_psvideo->head(); uint64_t pts = 0; pshead->getSystem_clock_reference_base(pts); pts = pts/90; int64_t localPts = GetLocalTimeOfMicroSecond(); fReceiveFunction(m_streamType, m_esvideo->head(), m_esvideo->len(), pts, localPts, m_lastiskeyfram, m_userdata); } m_esvideo->fFirst = m_esvideo->len(); m_esvideo->compact(); if (fReceiveFunction != NULL && m_esaudio->len())//音频es { int64_t localPts = GetLocalTimeOfMicroSecond(); fReceiveFunction(0xC0, m_esaudio->head(), m_esaudio->len(), m_lastpts, localPts, 0, m_userdata); } m_esaudio->fFirst = m_esaudio->len(); m_esaudio->compact(); if (fReceiveFunction2 != NULL && m_psvideo->len())//视频ps { fReceiveFunction2(STREAM_TYPE_VIDEO,m_psvideo->head(),m_psvideo->len(),m_lastpts,m_lastiskeyfram,m_userdata2); } m_psvideo->fFirst = m_psvideo->len(); m_psvideo->compact(); if (fReceiveFunction2 != NULL && m_psaudio->len())//音频 { fReceiveFunction2(STREAM_TYPE_AUDIO,m_psaudio->head(),m_psaudio->len(),m_lastpts,0,m_userdata2); } m_psaudio->fFirst = m_psaudio->len(); m_psaudio->compact(); PS_HEADER_tag* ppshead = (PS_HEADER_tag*)PDW; unsigned long psheadlen = sizeof(PS_HEADER_tag) + ppshead->pack_stuffing_length; if (fBuffer->len() - Processed < (int)psheadlen) { break; } // m_lastiskeyfram = false; if ((*(unsigned int *)(PDW+psheadlen)&0x00FFFFFF) != 0x00010000) { } else { m_psvideo->add((char*)PDW,psheadlen);//ps头写入视频数据中 PDW += psheadlen; Processed += psheadlen; continue; } } else if (SYSTEM_START_CODE == Code)//system_header { unsigned short pespacklen = asm_swap16(*(unsigned short *)(PDW + 4)) + 6; if ((*(unsigned int *)(PDW+pespacklen)&0x00FFFFFF) != 0x00010000) { printf("SYSTEM_START_CODE: Warning in CMpeg2Demux::Demultiplex - ((*PDW & 0x00FFFFFF) != 0x00010000).\n"); } else { m_psvideo->add((char*)PDW,pespacklen);//ps头写入视频数据中 PDW += pespacklen; Processed +=pespacklen; m_lastiskeyfram = true; continue; } } else if (PROGRAM_STREAM_MAP == StreamID)//psm { unsigned short pespacklen = asm_swap16(*(unsigned short *)(PDW + 4)) + 6; if ((*(unsigned int *)(PDW+pespacklen)&0x00FFFFFF) != 0x00010000) { } else { unsigned short program_stream_info_length; //unsigned short elementary_stream_map_length; unsigned short* plen = (unsigned short*)(PDW + 8); program_stream_info_length = ntohs(*plen); int test = *(PDW + 8 + program_stream_info_length + 5);//192 //assert(*(PDW+8+program_stream_info_length+5) == 0xe0); //if(*(PDW + 8 + program_stream_info_length + 5) != 0xe0) //{ // continue; //} //printf("0xe0=%d, 0x1b=%d\n", *(PDW + 8 + program_stream_info_length + 5), *(PDW + 8 + program_stream_info_length + 4)); if (m_pserror > 5 && (*(PDW + 8 + program_stream_info_length + 5) != 0xe0 && *(PDW + 8 + program_stream_info_length + 5) != 0xc0))//判断c0是为了兼容枢纽引擎名叫博士的垃圾小厂家 { printf("--------------------------------2 error:{%d}\n", m_pserror); return -1; } if (*(PDW + 8 + program_stream_info_length + 5) != 0xe0 && *(PDW + 8 + program_stream_info_length + 5) != 0xc0) { //printf("--------------------------------1\n"); ++m_pserror; continue; } m_lastiskeyfram = true; if (*(PDW + 8 + program_stream_info_length + 4) == 0x1b || *(PDW + 8 + program_stream_info_length + 4) == 0x03) { m_streamType = VIDEO_TYPE_H264; // H264 } else if (*(PDW + 8 + program_stream_info_length + 4) == 0x24) { m_streamType = VIDEO_TYPE_H265; // H265 } else if (*(PDW+8+program_stream_info_length+4) == 0x10) { m_streamType = VIDEO_TYPE_MPEG4; // MPEG4 } else { m_streamType = STREAM_TYPE_UNKNOWN; } m_pserror = 0; m_psvideo->add((char*)PDW,pespacklen);//ps头写入视频数据中 PDW += pespacklen; Processed +=pespacklen; continue; } } else if (0xBD == StreamID)//私有数据 { unsigned short pespacklen = asm_swap16(*(unsigned short *)(PDW + 4)) + 6; if ((*(unsigned int *)(PDW+pespacklen)&0x00FFFFFF) != 0x00010000) { } else { m_psvideo->add((char*)PDW,pespacklen);//ps头写入视频数据中 PDW += pespacklen; Processed +=pespacklen; continue; } } if ((Code >= SYSTEM_START_CODE_MIN) && (Code <= SYSTEM_START_CODE_MAX) && (Code != PACK_START_CODE) && (Code != SYSTEM_START_CODE) && (StreamID != PROGRAM_STREAM_MAP) && (StreamID != PADDING_STREAM) && (StreamID != PRIVATE_STREAM_2) && (StreamID != ECM_STREAM) && (StreamID != EMM_STREAM) && (StreamID != PROGRAM_STREAM_DIRECTORY) && (StreamID != DSM_CC_STREAM) && (StreamID != ITU_T_STREAM_E)) { PES_packet_length = asm_swap16(*(unsigned short *)(PDW + 4)); PES_header_data_length = *(PDW + 8); if (PES_packet_length == 0) PES_packet_length = fBuffer->len() - Processed/* - 4*/; else PES_packet_length += 6; if (fBuffer->len() - Processed >= PES_packet_length/* + 4*/) { PES_HEADER_tag* peshead = (PES_HEADER_tag*)PDW; uint64_t pts = 0; if (peshead->PTS_DTS_flags&0x3) { PTS_tag* ptstag = (PTS_tag*)(PDW + 9); ptstag->getPTS(pts); m_lastpts = pts/90; } Val = 6 + 3 + PES_header_data_length; if (0xE0 == StreamID) { m_esvideo->add((char*)PDW + Val, PES_packet_length - Val); m_psvideo->add((char*)PDW, PES_packet_length); } else if (0xC0 == StreamID) { if (PES_packet_length + 6 - Val > 0) { m_esaudio->add((char*)PDW + Val,PES_packet_length - Val); } else { m_esaudio->add((char*)PDW + Val,PES_packet_length - 19); } m_psaudio->add((char*)PDW,PES_packet_length+6); } fBuffer->fFirst += Processed + PES_packet_length; fBuffer->compact(); Processed = 0; PDW = (unsigned char *)fBuffer->head(); } else { break; } } else { PDW++; Processed++; } }; if (Processed) { fBuffer->fFirst += Processed; fBuffer->compact(); Processed = 0; } return (true); } catch (...) { return (-1); } }