⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mpeg_demux.cpp

📁 linux下实现视频播放的播放器
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/* *  Copyright (C) 2005-2007  gulikoza * *  PAT/PMT table parser for PID detection. *  Copyright (C) 2004, Donald A Graft, All Rights Reserved * *  This program is free software; you can redistribute it and/or modify *  it under the terms of the GNU General Public License as published by *  the Free Software Foundation; either version 2 of the License, or *  (at your option) any later version. * *  This program is distributed in the hope that it will be useful, *  but WITHOUT ANY WARRANTY; without even the implied warranty of *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *  GNU General Public License for more details. * *  You should have received a copy of the GNU General Public License *  along with this program; if not, write to the Free Software *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *//* $Id$ */#include "iptv.h"#define USES_BASECLASS#include "video.h"#include "wxgui/StreamInfo.h"//#define DEBUG#include "log.h"#define MODULE "mpeg_demux"int mpeg_demux::ProcessData(unsigned char *buffer, int size){    unsigned int pid;    unsigned int i = 0;    rdr.SetBuffer(buffer, size);    while((pkt=rdr.GetPacket())) {	// Get packet pid#ifdef DEBUG	static int pnum = 0;#endif	pid =((pkt[1] & 0x1F) << 8) | pkt[2];	DEBUG_MSG("packet no: %d, PID 0x%x%s", pnum++, pid, ((pkt[1] & 0x40) >> 6) ? ", start" : "");	// Check for valid PAT	if(!valid_pat) {	    if(pid == 0x0) {		ParsePAT();	    } else {		DEBUG_MSG("No valid PAT and PID not 0x0");	    }	    continue;	}	// Make sure all PMTs are valid	if(num_valid_pmts < num_pat_entries) {	    try {	    if(ParsePMT(pid)) {		// Set Audio and Video to the first program		for(i = 0; i < pat_entries[0].num_streams; i++) {		    if(!strcmp(pat_entries[0].streams[i].stream_type, "MPEG2 Video")) {			MPEG2_Transport_VideoPID = pat_entries[0].streams[i].pid;			ERROR_MSG("MPEG2_Transport_VideoPID set to 0x%x", MPEG2_Transport_VideoPID);			SeqHeader = MpegHDR;			// Create video decoder object#if 0			videodec = new libav_decoder(wait, CODEC_ID_MPEG2VIDEO, 2*1024*1024);			LOG_MSG("Created libav decoder at 0x%p", videodec);#else			videodec = new mpeg_decoder(wait, 2*1024*1024);			LOG_MSG("Created libmpeg2 decoder at 0x%p", videodec);#endif		    } else if(!strcmp(pat_entries[0].streams[i].stream_type, "h264 Video")) {			MPEG2_Transport_VideoPID = pat_entries[0].streams[i].pid;			ERROR_MSG("h264_Transport_VideoPID set to 0x%x", MPEG2_Transport_VideoPID);#if (C_HAS_DIRECTSHOW)			// Create video decoder object			// Try dshow first			try {			    videodec = new libds_decoder("CoreAVCDecoder.ax", wait, 4*1024*1024);			} catch(const char *e) {			    ERROR_MSG("%s", e);#endif#if (C_HAS_LIBAVCODEC)			    videodec = new libav_decoder(wait, CODEC_ID_H264, 4*1024*1024);#else			    ERROR_MSG("h264 decoder not available, aborting..");			    return 0;#endif#if (C_HAS_DIRECTSHOW)			}#endif			LOG_MSG("Created new decoder at 0x%p", videodec);		    }		    if(!strcmp(pat_entries[0].streams[i].stream_type, "MPEG1 Audio") ||		     !strcmp(pat_entries[0].streams[i].stream_type, "MPEG2 Audio")) {		        if(MPEG2_Transport_AudioPID == 0) {			    MPEG2_Transport_AudioPID = pat_entries[0].streams[i].pid;			    ERROR_MSG("MPEG2_Transport_AudioPID set to 0x%x", MPEG2_Transport_AudioPID);			    // Create audio decoder object			    audiodec = new mpeg_audio(wait);			    LOG_MSG("Created new decoder at 0x%p", audiodec);			} else {			    LOG_MSG("Additional audio on pid", pat_entries[0].streams[i].pid);			}		    }		}#if (C_HAVE_WXGUI)		if(gui.wxStreamInfo != NULL)		    gui.wxStreamInfo->UpdateStreamInfo(pat_entries, num_pat_entries, num_valid_pmts,							MPEG2_Transport_VideoPID, MPEG2_Transport_AudioPID);#endif	    }	    } catch (const char * c) {		fprintf(stderr, "[%d] EXCEPTION: %s\n", SDL_GetTicks(), c);		return 0;	    }	    continue;	}	// Capture Video or Audio packets	if(pid == MPEG2_Transport_VideoPID)	    ProcessVideoPacket();	else if(pid == MPEG2_Transport_AudioPID)	    ProcessAudioPacket();	else if((pat_entries[0].pcrpid != MPEG2_Transport_VideoPID)		    && (pid == pat_entries[0].pcrpid))	    ProcessHeader(false);	else	    DEBUG_MSG("Skip stream 0x%x", pid);    }    /* Some programs have bad program tables (evil?) */    if((m_video) && (pcr_count > 25)) {	ERROR_MSG("Evil program mode activated, set video PID to 0x%x", pat_entries[0].pcrpid);	MPEG2_Transport_VideoPID = pat_entries[0].pcrpid;    }    DEBUG_MSG("Done.");    return rdr.LeftBytes();}int mpeg_demux::ProcessHeader(bool first){    int offset;    if(pkt[0] != 0x47) {	ERROR_MSG("No sync byte in header");	return -1;    }    // Check error indicator.    if((pkt[1] & 0x80) >> 7) {	ERROR_MSG("Error in packet!");	return -1;    }    // Check for presence of a section start.    if((first == true) && (!((pkt[1] & 0x40) >> 6))) {	DEBUG_MSG("Packet fragment!");	return -1;    }    char adp = (pkt[3] & 0x30) >> 4;    // Use PCR in adaptation field to sync timer clock    if(adp & 0x2) {	// Get PID	unsigned int pid = ((pkt[1] & 0x1F) << 8) | pkt[2];	// If PCR is on this PID (assume channel 0 for now)	if(pat_entries[0].pcrpid == pid) {	    offset = 4;	    unsigned char flags = pkt[offset+1];	    DEBUG_MSG("Searching for PCR, adaptation field length %d, flags: 0x%x", pkt[offset], flags);	    if(flags & 0x80) {		LOG_MSG("Discontinuity flag present");	    } else	    if(flags & 0x10) {		// PCR is 42 bit, but only take 32-bits of upper 33-bits...blah :P		pid  = (pkt[offset+2] & 0x7f) << 25;		pid |= (pkt[offset+3]) << 17;		pid |= (pkt[offset+4]) << 9;		pid |= (pkt[offset+5]) << 1;		pid |= (pkt[offset+6] & 0x80) >> 7;		pid /= 90;		pcr_count++;		LOG_MSG("Current PCR: %u, pcr_count: %d", pid, pcr_count);		timer->SetPTS(pid);	    }	}    }    // Skip if there is no payload (adaptation field)    if(adp == 0 || adp == 2) {	LOG_MSG("Adaptation field w/o payload!");	return -1;    }    // Skip the adaptation field (if any).    offset = 4;    if(adp == 3) {	DEBUG_MSG("Skipping adaptation field (%d bytes)", pkt[offset]);	offset += pkt[offset] + 1;	if(offset == TS_PACKET_SIZE) {	    DEBUG_MSG("No payload in packet");	    return -1;	}    }    DEBUG_MSG("Payload offset %d", offset);    return offset;}bool mpeg_demux::ParsePAT(){    // Buffer offset    unsigned int ndx;    unsigned int length, number, last, program, pmtpid;    if((ndx = ProcessHeader(first_pat)) < 0)	return false;    // Skip to the start of the section.    ndx += pkt[ndx] + 1;    // Now pointing to the start of the section. Check the table id.    if(pkt[ndx++] != 0) {	ERROR_MSG("Table ID not null!");	return false;    }    // Check the section syntax indicator.    if((pkt[ndx] & 0xc0) != 0x80) {        ERROR_MSG("Invalid syntax indicator!");        return false;    }    // Check and get section length.    if((pkt[ndx] & 0x0c) != 0) {        ERROR_MSG("Section length invalid!");        return false;    }    length = ((pkt[ndx++] & 0x03) << 8);    length |= pkt[ndx++];    DEBUG_MSG("Detected length %d", length);    if(length > 0x3fd) {        ERROR_MSG("Length is too large!");        return false;    }    // Skip the transport stream id.    ndx += 2;    // We want only current tables.    if(!(pkt[ndx++] & 0x01)) {        ERROR_MSG("No current tables!");        return false;    }    // Get the number of this section.    number = pkt[ndx++];    DEBUG_MSG("Number of the current section %d", number);    // Get the number of the last section.    last = pkt[ndx++];    DEBUG_MSG("Number of the last section %d", last);    // Now we have the program/pid tuples.    for(unsigned int i = 0; i < length - 9;) {	program = pkt[ndx+i++] << 8;	program |= pkt[ndx+i++];	pmtpid = (pkt[ndx+i++] & 0x1f) << 8;	pmtpid |= pkt[ndx+i++];	ERROR_MSG("Found program %d with PID 0x%x", program, pmtpid);	// Skip the Network Information Table (NIT).	if(program != 0) {	    pat_entries[num_pat_entries].first_pmt = true;	    pat_entries[num_pat_entries].num_streams = 0;	    pat_entries[num_pat_entries].program = program;	    pat_entries[num_pat_entries++].pmtpid = pmtpid;	    if(num_pat_entries >= MAX_PAT_ENTRIES) {		ERROR_MSG("MAX_PAT_ENTRIES reached!");		num_pat_entries = MAX_PAT_ENTRIES - 1;	    }	}    }    first_pat = false;    LOG_MSG("num_pat_entries: %d", num_pat_entries);    // If this is the last section number, we're done.    if(number == last)	valid_pat = true;    return true;}bool mpeg_demux::ParsePMT(unsigned int pid){    unsigned int ndx, length, number, last, begin, num_streams;    unsigned int descriptors_length, es_descriptors_length;    // Now we have to get the PMT tables to retrieve the actual    // program PIDs.    for (unsigned int entry = 0; entry < num_pat_entries; entry++)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -