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

📄 mpegsystem.cpp

📁 This code is based on mpeg_play, available from: http://bmrc.berkeley.edu/frame/research/mpeg/
💻 CPP
📖 第 1 页 / 共 3 页
字号:
#include <stdlib.h>        /* for realloc() */#include <string.h>        /* for memmove() */#include <errno.h>#include <assert.h>#ifdef WIN32#include <sys/types.h>#include <io.h>#include <winsock.h>#else#include <unistd.h>#include <sys/types.h>#include <sys/stat.h>#include <sys/time.h>#include <sys/select.h>#endif#include "MPEGsystem.h"#include "MPEGstream.h"/* Define this if you want to use a separate thread for stream decoding *///#define USE_SYSTEM_THREADUint8 const PACKET_CODE[]       = { 0x00, 0x00, 0x01, 0xba };Uint8 const PACKET_MASK[]       = { 0xff, 0xff, 0xff, 0xff };Uint8 const END_CODE[]          = { 0x00, 0x00, 0x01, 0xb9 };Uint8 const END_MASK[]          = { 0xff, 0xff, 0xff, 0xff };Uint8 const END2_CODE[]         = { 0x00, 0x00, 0x01, 0xb7 };Uint8 const END2_MASK[]         = { 0xff, 0xff, 0xff, 0xff };Uint8 const VIDEOSTREAM_CODE[]  = { 0x00, 0x00, 0x01, 0xe0 };Uint8 const VIDEOSTREAM_MASK[]  = { 0xff, 0xff, 0xff, 0xe0 };Uint8 const AUDIOSTREAM_CODE[]  = { 0x00, 0x00, 0x01, 0xc0 };Uint8 const AUDIOSTREAM_MASK[]  = { 0xff, 0xff, 0xff, 0xc0 };Uint8 const PADSTREAM_CODE[]    = { 0x00, 0x00, 0x01, 0xbe };Uint8 const PADSTREAM_MASK[]    = { 0xff, 0xff, 0xff, 0xff };Uint8 const SYSTEMSTREAM_CODE[] = { 0x00, 0x00, 0x01, 0xbb };Uint8 const SYSTEMSTREAM_MASK[] = { 0xff, 0xff, 0xff, 0xff };Uint8 const USERSTREAM_CODE[]   = { 0x00, 0x00, 0x01, 0xb2 };Uint8 const USERSTREAM_MASK[]   = { 0xff, 0xff, 0xff, 0xff };Uint8 const VIDEO_CODE[]        = { 0x00, 0x00, 0x01, 0xb3 };Uint8 const VIDEO_MASK[]        = { 0xff, 0xff, 0xff, 0xff };Uint8 const AUDIO_CODE[]        = { 0xff, 0xf0, 0x00, 0x00 };Uint8 const AUDIO_MASK[]        = { 0xff, 0xf0, 0x00, 0x00 };Uint8 const GOP_CODE[]          = { 0x00, 0x00, 0x01, 0xb8 };Uint8 const GOP_MASK[]          = { 0xff, 0xff, 0xff, 0xff };Uint8 const PICTURE_CODE[]      = { 0x00, 0x00, 0x01, 0x00 };Uint8 const PICTURE_MASK[]      = { 0xff, 0xff, 0xff, 0xff };Uint8 const SLICE_CODE[]        = { 0x00, 0x00, 0x01, 0x01 };Uint8 const SLICE_MASK[]        = { 0xff, 0xff, 0xff, 0x00 };Uint8 const ZERO_CODE[]         = { 0x00, 0x00, 0x00, 0x00 };Uint8 const FULL_MASK[]         = { 0xff, 0xff, 0xff, 0xff };/* The size is arbitrary but should be sufficient to contain *//* two MPEG packets and reduce disk (or network) access.     */// Hiroshi Yamashita notes that the original size was too large#define MPEG_BUFFER_SIZE (16 * 1024)/* The granularity (2^LG2_GRANULARITY) determine what length of read data *//* will be a multiple of, e.g. setting LG2_GRANULARITY to 12 will make    *//* read size (when calling the read function in Read method) to be a      *//* multiple of 4096                                                       */#define LG2_GRANULARITY 12#define READ_ALIGN(x) (((x) >> LG2_GRANULARITY) << LG2_GRANULARITY)/* This defines the maximum number of buffers that can be preread *//* It is to prevent filling the whole memory with buffers on systems *//* where read is immediate such as in the case of files */#define MPEG_BUFFER_MAX 16/* Timeout before read fails */#define READ_TIME_OUT 1000000/* timestamping */#define FLOAT_0x10000 (double)((Uint32)1 << 16)#define STD_SYSTEM_CLOCK_FREQ 90000L/* This work only on little endian systems *//*#define REV(x) ((((x)&0x000000FF)<<24)| \                (((x)&0x0000FF00)<< 8)| \                (((x)&0x00FF0000)>> 8)| \                (((x)&0xFF000000)>>24))#define MATCH4(x, y, m) (((x) & REV(m)) == REV(y))*/const int audio_frequencies[2][3]={  {44100,48000,32000}, // MPEG 1  {22050,24000,16000}  // MPEG 2};const int audio_bitrate[2][3][15]={  // MPEG 1  {{0,32,64,96,128,160,192,224,256,288,320,352,384,416,448},   {0,32,48,56,64,80,96,112,128,160,192,224,256,320,384},   {0,32,40,48,56,64,80,96,112,128,160,192,224,256,320}},  // MPEG 2  {{0,32,48,56,64,80,96,112,128,144,160,176,192,224,256},   {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160},   {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160}}};/* Match two 4-byte codes */static inline bool Match4(Uint8 const code1[4], Uint8 const code2[4], Uint8 const mask[4]){  return( ((code1[0] & mask[0]) == (code2[0] & mask[0])) &&	  ((code1[1] & mask[1]) == (code2[1] & mask[1])) &&	  ((code1[2] & mask[2]) == (code2[2] & mask[2])) &&	  ((code1[3] & mask[3]) == (code2[3] & mask[3])) );}static inline double read_time_code(Uint8 *pointer){   double timestamp;  Uint8 hibit; Uint32 lowbytes;  hibit = (pointer[0]>>3)&0x01;  lowbytes = (((Uint32)pointer[0] >> 1) & 0x03) << 30;  lowbytes |= (Uint32)pointer[1] << 22;  lowbytes |= ((Uint32)pointer[2] >> 1) << 15;  lowbytes |= (Uint32)pointer[3] << 7;  lowbytes |= ((Uint32)pointer[4]) >> 1;  timestamp = (double)hibit*FLOAT_0x10000*FLOAT_0x10000+(double)lowbytes;  timestamp /= STD_SYSTEM_CLOCK_FREQ;  return timestamp;}/* Return true if there is a valid audio header at the beginning of pointer */static inline Uint32 audio_header(Uint8 * pointer, Uint32 * framesize, double * frametime){  Uint32 layer, version, frequency, bitrate, mode, padding, size;  if(((pointer[0] & 0xff) != 0xff) || // No sync bits     ((pointer[1] & 0xf0) != 0xf0) || //     ((pointer[2] & 0xf0) == 0x00) || // Bitrate is 0     ((pointer[2] & 0xf0) == 0xf0) || // Bitrate is 15     ((pointer[2] & 0x0c) == 0x0c) || // Frequency is 3     ((pointer[1] & 0x06) == 0x00))   // Layer is 4     return(0);  layer = 4 - (((pointer)[1] >> 1) & 3);  version = (((pointer)[1] >> 3) & 1) ^ 1;  padding = ((pointer)[2] >> 1) & 1;  frequency = audio_frequencies[version][(((pointer)[2] >> 2) & 3)];  bitrate = audio_bitrate[version][layer-1][(((pointer)[2] >> 4) & 15)];  mode = ((pointer)[3] >> 6) & 3;  if(layer==1)  {      size = 12000 * bitrate / frequency;      if(frequency==0 && padding) size++;      size <<= 2;  }  else  {      size = 144000 * bitrate / (frequency<<version);      if(padding) size++;  }  if(framesize) *framesize = size;  if(frametime) *frametime = 8.0 * size / (1000. * bitrate);    return(4); /* Audio header size */}/* Search the next valid audio header */static inline bool audio_aligned(Uint8 *pointer, Uint32 size){    Uint32 i, s;#if 1 // Sam 10/27 - Don't choke on partially corrupt data    size = 4;#endif    /* Check on all data available that next headers are aligned too */    for(i = 0; i + 3 < size && audio_header(pointer+i, &s, 0); i+=s);    if(i + 3 < size)	return(false);    else	return(true);}/* Return true if there is a valid sequence header at the beginning of pointer */static inline Uint32 sequence_header(Uint8 * pointer, Uint32 size, double * _frametime){  double frametime;  Uint32 header_size;  header_size = 0;  if((header_size+=4) >= size) return(0);  if(!Match4(pointer, VIDEO_CODE, VIDEO_MASK))     return(0); /* Not a sequence start code */    /* Parse the sequence header information */  if((header_size+=8) >= size) return(0);  switch(pointer[7]&0xF)                /*  4 bits of fps */  {    case 1: frametime = 1.0/23.97; break;    case 2: frametime = 1.0/24.00; break;    case 3: frametime = 1.0/25.00; break;    case 4: frametime = 1.0/29.97; break;    case 5: frametime = 1.0/30.00; break;    case 6: frametime = 1.0/50.00; break;    case 7: frametime = 1.0/59.94; break;    case 8: frametime = 1.0/60.00; break;    case 9: frametime = 1.0/15.00; break;    default: frametime = 1.0/30.00; break;  }  if(_frametime) *_frametime = frametime;    return(header_size); /* sequence header size */}/* Return true if there is a valid gop header at the beginning of pointer */static inline Uint32 gop_header(Uint8 * pointer, Uint32 size, double * timestamp){  Uint32 header_size;  Uint32 hour, min, sec, frame;  header_size = 0;  if((header_size+=4) >= size) return(0);  if(!Match4(pointer, GOP_CODE, GOP_MASK))     return(0); /* Not a gop start code */    /* Parse the gop header information */  hour = (pointer[4] >> 2) & 31;  min = ((pointer[4] & 3) << 4) | ((pointer[5] >> 4) & 15);  sec = ((pointer[5] & 7) << 3) | ((pointer[6] >> 5) & 7);  frame = ((pointer[6] & 31) << 1) | ((pointer[7] >> 7) & 1);  if((header_size+=4) >= size) return(0);  if(timestamp) *timestamp = sec + 60.*min + 3600.*hour;    return(header_size); /* gop header size */}/* Return true if there is a valid picture header at the beginning of pointer */static inline Uint32 picture_header(Uint8 * pointer, Uint32 size){  Uint32 header_size;  header_size = 0;  if((header_size+=4) >= size) return(0);  if(!Match4(pointer, PICTURE_CODE, PICTURE_MASK))     return(0); /* Not a picture start code */    /* Parse the picture header information */  if((header_size+=4) >= size) return(0);    return(header_size); /* picture header size */}/* Return true if there is a valid slice header at the beginning of pointer */static inline Uint32 slice_header(Uint8 * pointer, Uint32 size){  Uint32 header_size;  header_size = 0;  if((header_size+=4) >= size) return(0);  if(!(Match4(pointer, SLICE_CODE, SLICE_MASK) &&        pointer[3] >= 0x01 && pointer[3] <= 0xaf))     return(0); /* Not a slice start code */    return(header_size); /* slice header size */}/* Return true if there is a valid packet header at the beginning of pointer */static inline Uint32 packet_header(Uint8 * pointer, Uint32 size, double * _timestamp){  double timestamp;  Uint32 header_size;  header_size = 0;  if((header_size+=4) >= size) return(0);  if(!Match4(pointer, PACKET_CODE, PACKET_MASK))     return(0); /* Not a packet start code */  /* Parse the packet information */  if((header_size+=8) >= size) return(0);  timestamp = read_time_code(pointer+4);  if(_timestamp) *_timestamp = timestamp;    return(header_size); /* packet header size */}/* Return true if there is a valid stream header at the beginning of pointer */static inline Uint32 stream_header(Uint8 * pointer, Uint32 size, Uint32 * _packet_size, Uint8 * _stream_id, double * _stream_timestamp, double timestamp){  Uint32 header_size, packet_size;  Uint8 stream_id;  double stream_timestamp;  header_size = 0;  if((header_size += 4) >= size) return(0);   if(!Match4(pointer, SYSTEMSTREAM_CODE, SYSTEMSTREAM_MASK) &&     !Match4(pointer, AUDIOSTREAM_CODE, AUDIOSTREAM_MASK)   &&     !Match4(pointer, VIDEOSTREAM_CODE, VIDEOSTREAM_MASK)   &&     !Match4(pointer, PADSTREAM_CODE, PADSTREAM_MASK)       &&     !Match4(pointer, USERSTREAM_CODE, USERSTREAM_MASK))    return(0); /* Unknown encapsulated stream */  /* Parse the stream packet */  /* Get the stream id, and packet length */  stream_id = pointer[3];  pointer += 4;  if((header_size += 2) >= size) return(0);   packet_size = (((unsigned short) pointer[0] << 8) | pointer[1]);  pointer += 2;  /* Skip stuffing bytes */  while ( pointer[0] == 0xff ) {      ++pointer;      if((++header_size) >= size) return(0);       --packet_size;  }  if ( (pointer[0] & 0x40) == 0x40 ) {      pointer += 2;      if((header_size += 2) >= size) return(0);       packet_size -= 2;  }  if ( (pointer[0] & 0x20) == 0x20 ) {      /* get the PTS */      stream_timestamp = read_time_code(pointer);      /* we don't care about DTS */      if ( (pointer[0] & 0x30) == 0x30 ){	pointer += 5;	if((header_size += 5) >= size) return(0); 	packet_size -= 5;      }      pointer += 4;      if((header_size += 4) >= size) return(0);       packet_size -= 4;  }  else if ( pointer[0] != 0x0f && pointer[0] != 0x80)      return(0);      /* not a valid header */  else      stream_timestamp = timestamp;      if((++header_size) >= size) return(0);   --packet_size;  if(_packet_size) *_packet_size = packet_size;  if(_stream_id) *_stream_id = stream_id;  if(_stream_timestamp) *_stream_timestamp = stream_timestamp;    return(header_size);}/* Search the next valid audio header */static inline bool system_aligned(Uint8 *pointer, Uint32 size){    Uint32 i, s;    /* Check that packet contains at least one stream */    i = 0;    while((s = packet_header(pointer+i, size-i, 0)) != 0)      if((i+=s) >= size) return(true);    if((s = stream_header(pointer+i, size-i, 0, 0, 0, 0)) != 0)      return(true);    else      return(false);}/* Skip possible zeros at the beggining of the packet */Uint32 skip_zeros(Uint8 * pointer, Uint32 size){  Uint32 header_size;  Uint8 const one[4]  = {0x00,0x00,0x00,0x01};  if(!size) return(0);  header_size = 0;  while(Match4(pointer, ZERO_CODE, FULL_MASK))  {    pointer++;    if((++header_size) >= size - 4) return(0);     if(Match4(pointer, one, FULL_MASK))    {      pointer++;      if((++header_size) >= size - 4) return(0);     }  }  return(header_size);}MPEGsystem::MPEGsystem(SDL_RWops *mpeg_source){  source = mpeg_source;  /* Create a new buffer for reading */  read_buffer = new Uint8[MPEG_BUFFER_SIZE];  /* Create a mutex to avoid concurrent access to the stream */  system_mutex = SDL_CreateMutex();  request_wait = SDL_CreateSemaphore(0);  /* Invalidate the read buffer */  pointer = read_buffer;  read_size = 0;  read_total = 0;  packet_total = 0;  endofstream = errorstream = false;  looping = false;  frametime = 0.0;  stream_timestamp = 0.0;  /* Create an empty stream list */  stream_list =     (MPEGstream **) malloc(sizeof(MPEGstream *));  stream_list[0] = 0;  /* Create the system stream and add it to the list */  if(!get_stream(SYSTEM_STREAMID))    add_stream(new MPEGstream(this, SYSTEM_STREAMID));  timestamp = 0.0;  timedrift = 0.0;  skip_timestamp = -1;  system_thread_running = false;  system_thread = 0;  /* Search the MPEG for the first header */  if(!seek_first_header())  {    errorstream = true;    SetError("Could not find the beginning of MPEG data\n");    return;  }#ifdef USE_SYSTEM_THREAD  /* Start the system thread */  system_thread = SDL_CreateThread(SystemThread, this);  /* Wait for the thread to start */  while(!system_thread_running && !Eof())    SDL_Delay(1);#else  system_thread_running = true;#endif  /* Look for streams */  int tries = 0;  do  {    RequestBuffer();    Wait();    if ( tries++ < 10 ) {      if ( exist_stream(VIDEO_STREAMID, 0xF0) &&	   exist_stream(AUDIO_STREAMID, 0xF0) ) {        break;      }    } else {      if ( exist_stream(VIDEO_STREAMID, 0xF0) ||	   exist_stream(AUDIO_STREAMID, 0xF0) ) {        break;      }    }  }  while(!Eof());}MPEGsystem::~MPEGsystem(){  MPEGstream ** list;  /* Kill the system thread */  Stop();  SDL_DestroySemaphore(request_wait);  SDL_DestroyMutex(system_mutex);  /* Delete the streams */  for(list = stream_list; *list; list ++)    delete *list;  free(stream_list);  /* Delete the read buffer */  delete[] read_buffer;}MPEGstream ** MPEGsystem::GetStreamList(){  return(stream_list);

⌨️ 快捷键说明

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