?? mpeg_demux.cpp
字號:
/* * 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 { } } }#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 + -