?? mpeg2demux.cc
字號:
/* File: mpeg2demux.cc Description: The MPEG 2 demultiplexer class reads MPEG 2 TS, PS and PES data and demultiplexes a Transport Stream or Program Stream in its Packetized Elementary Streams. Elementary Streams are just passed through. Created: February 1996, Alex Theo de Jong, NIST*/#include "athread.hh"#include <stdio.h>#include <stdlib.h>#include <String.h>#include <fstream.h>#include <sys/errno.h>#ifdef IRIX#include <dmedia/audio.h>#endif#ifdef SOLARIS#include <sys/audioio.h>#endif// network stuff #include <sys/types.h>#include <sys/uio.h>#include <unistd.h>#include <errno.h>#include "error.hh"#include "debug.hh"#include "util.hh"#include "sync.hh"#include "mpeg2const.hh"#include "mpeg2buff.hh"#include "mpeg2audio.hh"#include "mpeg2video.hh"#include "mpeg2demux.hh"#include "network.hh"// Options for Audio and Video playerextern int audio_argc;extern char** audio_argv;extern int video_argc;extern char** video_argv;extern int time_stamp_qsize;extern int frame_stamp_qsize;extern int audio_buffer_size;extern int video_buffer_size;// Input socketextern SocketMulti* sock;#ifdef TRACEMpeg2Buffer* ab=0;Mpeg2Buffer* vb=0;Synchronization* ds=0;#endif#define DELIMITER 0x001B8/* * * De-multiplexor * */Mpeg2Demux::Mpeg2Demux(int pdu_size, int sel_vstream, int sel_astream, int a_on, int v_on, int s_on, int q) : pes_audio_bytes(0), pes_video_bytes(0), pes_audio_time(0.0), pes_video_time(0.0), audio_on(a_on), video_on(v_on), sync_on(s_on), quiet(q), vstream(sel_vstream), astream(sel_astream){ audio_buffer=new Mpeg2Buffer(audio_buffer_size); video_buffer=new Mpeg2Buffer(video_buffer_size);#ifdef TRACE ::ab=audio_buffer; ::vb=video_buffer;#endif aalpdu_size=pdu_size; aalpdu=new unsigned char[aalpdu_size+1]; aalpdu_max=aalpdu+aalpdu_size; // input counters bytecount=0; byteptr=0; pdu_mpeg_packet=aalpdu_max; // set to max for proper init // MPEG packet counters counter=0; transport_packets=0; transport_packet_errors=0; sync_byte_errors=0; lost_packets=0; adaptation_fields=0; program_association_tables=0; pes_packets=0; psi_packets=0; audio_packets=0; video_packets=0; // transport packet header information transport_error_indicator=0; payload_unit_start_indicator=0; pid=0; audio_pid=-1; video_pid=-1; adaptation_field_control=0; audio=0; video=0; sync=0; int err;#ifdef EOFEXIT Mpeg2Demux::init(this);#else if ((err=athr_create((void*(*)(void*))Mpeg2Demux::init, this, &thread_id))<0){ error("could not create thread"); } sched_param param; int policy; if ((err=athr_getschedparam(thread_id, &policy, ¶m))<0){ warning("could not get thread prio - ignored"); } else {#ifdef LINUX param.sched_priority+=1;// policy = SCHED_RR; TRACER("TIMERPRIORITY=" << param.sched_priority << "(" << param.sched_priority-1 << ")");#else param.prio+=1; TRACER("TIMERPRIORITY=" << param.prio << "(" << param.prio-1 << ")");#endif if ((err=athr_setschedparam(thread_id, policy, ¶m))<0){ warning("could not set thread prio - ignored"); } }// TRACER("DEMUXPRIORITY=" << param.prio);#endif terminated=0;}Mpeg2Demux::~Mpeg2Demux(){ TRACER("Mpeg2Demux::~Mpeg2Demux()"); if (!terminated){ // check if thread is still alive TRACER("waiting for demux thread to terminate ..."); athr_join(thread_id); } TRACER("delete video ..."); delete video; TRACER("video deleted\ndelete audio ..."); delete audio; TRACER("audio deleted\ndelete sync ..."); delete sync; TRACER("sync deleted\ndemux deleted"); delete aalpdu; delete audio_buffer; delete video_buffer;}int Mpeg2Demux::stop(){ terminate=1; if (!terminated){ // check to see if thread is available athr_join(thread_id); gettimeofday(&tstop,(struct timezone *)NULL); int runtime = 1000*(tstop.tv_sec-tstart.tv_sec) + (tstop.tv_usec-tstart.tv_usec)/1000; msg("Bitrate: "); msg(dtoa(counter*MPEG2_TS_Packet_size*8/runtime)); message(" Kbps"); } return terminated; }void* Mpeg2Demux::init(Mpeg2Demux* base){ TRACER("void* Mpeg2Demux::init(Mpeg2Demux* base)"); base->terminate=0; base->terminated=0; if (base->sync_on){ if (base->video_on && base->audio_on) base->sync=new Synchronization(0, time_stamp_qsize, frame_stamp_qsize); // sync video/audio if (base->video_on && !base->audio_on) base->sync=new Synchronization(1, time_stamp_qsize, frame_stamp_qsize); // just video if (!base->video_on && base->audio_on) base->sync=new Synchronization(2, time_stamp_qsize, frame_stamp_qsize); // just audio } else base->sync=0; if (base->video_on) base->video=new Mpeg2Video(base->video_buffer, base->sync, video_argc, video_argv); else base->video=0; if (base->audio_on) base->audio=new Mpeg2Audio(base->audio_buffer, base->sync, base->audio_on, audio_argc, audio_argv); else base->audio=0; // wait for network connection or file to be ready! sock->accept(); if (0){ error("could not receive connection!"); athr_exit(0); } if (base->nextpacket()<=0){ // init first pdu error("could not read first packet"); athr_exit(0); } unsigned int bits=base->nextbits32(); gettimeofday(&base->tstart,(struct timezone *)NULL); if (((bits >> 24) & 0xff)==Sync_byte){ message("Playing MPEG 2 TS Audio/Video");#ifdef TRACE ::ds=base->sync;#endif base->transport_stream(); } else if (bits == Pack_start_code){ // Create players and start message("Playing MPEG 2 PS Audio/Video"); base->program_stream(); } else if (base->audio_on && (bits & 0xfff00000)==0xfff00000){ // just plain audio message("Playing MPEG 2 PES Audio"); base->pes_stream_audio(); } else if (base->video_on && bits==Sequence_start_code){ // just video message("Playing MPEG 2 PES Video"); base->pes_stream_video(); } else error("Stream is not valid MPEG 2 Stream (TS, PS, Audio ES, Video ES)"); base->stop(); base->terminated=1; TRACER("demux thread done");#ifdef EOFEXIT exit(0); // stop everything right here (after EOF!)#else athr_exit(0);#endif return 0;}int Mpeg2Demux::copybytes(Mpeg2Buffer* output, int length){ if (bytecount+length>MPEG2_TS_Packet_size){ warning("copying bytes beyond transport packet length"); length=MPEG2_TS_Packet_size-bytecount; } if (output->write(byteptr, length)!=length){ error("failed to copy input to output"); // write to output } bytecount+=length; byteptr+=length; return length;}int Mpeg2Demux::skipbytes(int length){ int i = length; while(i--) getbits8(); return length; if (bytecount+length>MPEG2_TS_Packet_size){ warning("skipping bytes beyond transport packet length"); length=MPEG2_TS_Packet_size - bytecount; } bytecount+=length; byteptr+=length; return length;}int Mpeg2Demux::copy_ps_bytes(Mpeg2Buffer* output, unsigned int *header,int len){ unsigned char c;// if (video_on == 2) { if (output->write(byteptr, len)!=len){ error("failed to copy input to output"); // write to output } if (!nextpacket()) { *header = 0; return 1; } *header = getbits32();#if 0 } else { *header = getbits32(); while ((*header <= DELIMITER) || (*header > 0x1ff)) { c = *header >> 24; *header = (*header << 8) | getbits8(); if (output->write(&c, 1)!=1){ error("failed to copy input to output"); // write to output } } }#endif return 0;}int Mpeg2Demux::skip_ps_bytes(unsigned int *header){// if (video_on==2) { if (!nextpacket()) { *header = 0; return 1; } *header = getbits32(); return 0;#if 0 } else { *header = getbits32(); while ((*header <= DELIMITER) || (*header > 0x1ff)){ *header = (*header << 8) | getbits8(); } }#endif return 0;}int Mpeg2Demux::nextpacket(){ DEBUGGER("int Mpeg2Demux::nextpacket()"); if (pdu_mpeg_packet>=aalpdu_max){ DEBUGGER("sock->recv()"); if ((lastpdu_size=sock->recv(aalpdu, aalpdu_size))!=aalpdu_size){ if (lastpdu_size==0){ // if (audio_buffer)// while (audio_buffer->used() > 10000 ) sleep(1);// if (video_buffer) // while (video_buffer->used() > 30000 ) sleep(1); sleep(1); terminate=1; if (sync) sync->stop(); if (audio) audio->stop(); if (video) video->stop(); sleep(1); if (sync) sync->stop(); TRACER("EOF!"); return 0; // eof } error("invalid pdu size (" << itoa(lastpdu_size) << ")"); return -1; } byteptr=pdu_mpeg_packet=aalpdu; pdu_mpeg_packet+=MPEG2_TS_Packet_size; bytecount=0; } else { byteptr=pdu_mpeg_packet; pdu_mpeg_packet+=MPEG2_TS_Packet_size; bytecount=0; } return 1;}/* * * Mpeg Transport Stream * */int Mpeg2Demux::transport_stream(){ do { counter++; if (!get_transport_packet()){ if (!quiet){ String err("incorrect packet "); err+=itoa(counter); error(err.chars()); } } if (!quiet){ if ((counter % 100)==0) msg("."); if ((counter % 5000)==0){ message(itoa(counter)); athr_yield(); } } if (terminate){ if ((!sync || sync->stop()) && (!audio || audio->stop()) && (!video || video->stop())) break; // continue until all threads terminated } } while (nextpacket()); TRACER("closing audio buffer ..."); audio_buffer->close(); TRACER("closed audio buffer\nclosing video buffer ..."); video_buffer->close(); TRACER("closed video buffer"); file.close(); return (counter==0) ? 0 : 1;}int Mpeg2Demux::get_transport_packet(){ if (get_sync_byte()){ // align with sync transport_packets++; unsigned int bits=(getbits24() & 0x0000ffff); // drop sync byte // printf("First 2 bytes: %d\n", bits); // exit(0); transport_error_indicator=bits >> 15; payload_unit_start_indicator=(bits >> 14) & 1; pid=bits & 0x00001fff; transport_scrambling_control=(nextbits8() >> 6)&0x3; adaptation_field_control=(nextbits8() >> 4)&0x3; continuity_counter=(getbits8()&0xf); if (transport_error_indicator){ transport_packet_errors++; return 0; // error set! } if (pid==0x1fff){ return 1; // padding; just go to next } int i; for (i=0; pidtable[i]!=0 && pid!=pidtable[i]; i++); // get pid if (pidtable[i]==0){ // not in table yet pidtable[i]=pid; continuity_counters[i]=continuity_counter; // init pidtable[i+1]=0; } if (pid!=(int)Program_Association_Table && pid!=(int)Conditional_Access_Table && (adaptation_field_control==1 || adaptation_field_control==3)){ // Check counters if (continuity_counters[i]!=continuity_counter){ if (!quiet){ String err("lost MPEG "); err+=itoa(continuity_counter-continuity_counters[i]); err+=" packet(s)"; error(err.chars()); } continuity_counters[i]=continuity_counter; // reset lost_packets++; } if (++continuity_counters[i]>15) continuity_counters[i]=0; } if (adaptation_field_control==2 || adaptation_field_control==3) get_adaptation_field(); if (adaptation_field_control==1 || adaptation_field_control==3) get_payload(); } else { sync_byte_errors++; return 0; }
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -