www.pudn.com > mediator15src.zip > asyncstream.cpp


/* 
 * asyncstream.cpp 
 * Copyright (C) 2001-2002 Arno Hornberger  
 * 
 * This file is part of MPEG Mediator, a free MPEG stream converter. 
 * 
 * MPEG Mediator 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. 
 * 
 * MPEG Mediator 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 
 */ 
 
#include  
#include "asyncstream.h" 
 
AsyncStream::AsyncStream() 
{ 
  bitbuffer = new unsigned char[BUFFERSIZE]; 
  for (int i = 0; i < MAXFILES; i++) 
    filehandles[i] = 0; 
  nfiles = 0; 
} 
 
AsyncStream::~AsyncStream() 
{ 
  if (nfiles > 0) 
    Close(); 
 
  if (bitbuffer) 
    delete []bitbuffer; 
} 
 
int AsyncStream::ReadBytes(unsigned char *buffer, int size, __int64 loc) 
{ 
  int bytes_read; 
  int bytes_to_read = size; 
  int file = WhichFile(loc); 
 
  if (end_of_stream) 
    return 0; 
 
  while (bytes_to_read > 0) 
  { 
//    bytes_read = fread(buffer, sizeof(unsigned char), 
//                       bytes_to_read, filehandles[file]); 
    bytes_read = _read(filehandles[file], buffer, bytes_to_read); 
 
    if (bytes_read == bytes_to_read) 
      return size; 
 
    if (bytes_read < 0) 
      bytes_read = 0; 
 
    bytes_to_read -= bytes_read; 
    if ((_eof(filehandles[file]) <= 0) || (file + 1 == nfiles)) { 
      end_of_stream = true;       // read error or end of stream 
      return size - bytes_to_read; 
    } 
    buffer += bytes_read; 
    file++; 
  } 
  return size; 
} 
 
int AsyncStream::ReadChunk() 
{ 
  int bytes; 
  int buffer_offset; 
 
  if (end_of_stream) 
    return 0; 
 
  if (stop - start + CHUNKSIZE > BUFFERSIZE) 
    start += CHUNKSIZE; 
 
  buffer_offset = (int)stop & BUFFERMASK; 
  if (buffer_offset + CHUNKSIZE > BUFFERSIZE) { 
    bytes = ReadBytes(&bitbuffer[buffer_offset], 
                      BUFFERSIZE - buffer_offset, stop); 
 
    bytes += ReadBytes(&bitbuffer[0], 
                       CHUNKSIZE - (BUFFERSIZE - buffer_offset), 
                       stop + (BUFFERSIZE - buffer_offset)); 
  } 
  else 
    bytes = ReadBytes(&bitbuffer[buffer_offset], CHUNKSIZE, stop); 
 
  stop += bytes; 
  return bytes; 
} 
 
void AsyncStream::Open(char **filenames, int count) 
{ 
//  fpos_t fpos; 
  int error = 0; 
 
  if (count > MAXFILES) 
    throw DemuxExcept(DemuxExcept::TOO_MANY_FILES); 
 
  nfiles = count; 
 
  for (int i = 0; i < nfiles; i++) 
  { 
//    filehandles[i] = fopen(filenames[i], "rb"); 
    filehandles[i] = _open(filenames[i], _O_BINARY | _O_RDONLY); 
 
    if (filehandles[i] == -1) { 
      error = DemuxExcept::FILE_OPEN_ERROR; 
      break; 
    } 
 
//    fseek(filehandles[i], 0, SEEK_END); 
    _lseeki64(filehandles[i], 0, SEEK_END); 
 
    filesizes[i] = _telli64(filehandles[i]); 
    if (filesizes[i] == -1) { 
      error = DemuxExcept::FILE_ACCESS_ERROR; 
      break; 
    } 
/* 
    if (fgetpos(filehandles[i], &fpos) == 0) 
      filesizes[i] = fpos; 
    else 
      error = DemuxExcept::FILE_ACCESS_ERROR; 
 
    rewind(filehandles[i]); 
*/ 
    _lseeki64(filehandles[i], 0, SEEK_SET); 
  } 
 
  if (error != 0) { 
    Close(); 
    throw DemuxExcept(error); 
  } 
 
  start = 0; 
  stop = 0; 
  pos = -1; 
  pos_bit = 0; 
  end_of_stream = false; 
} 
 
void AsyncStream::Close() 
{ 
  for (int i = 0; i < nfiles; i++) { 
    if (filehandles[i] != -1) 
      _close(filehandles[i]); 
//      fclose(filehandles[i]); 
 
    filehandles[i] = 0; 
  } 
  nfiles = 0; 
} 
 
__int64 AsyncStream::Size() 
{ 
  __int64 size = 0; 
   
  for (int i = 0; i < nfiles; i++) 
    size += filesizes[i]; 
 
  return size; 
} 
 
void AsyncStream::Seek(__int64 loc) 
{ 
//  fpos_t fpos; 
  int i = 0; 
 
  pos = loc - 1; 
  pos_bit = 0; 
  if (loc < start || loc > stop) { 
    end_of_stream = false; 
    start = loc; 
    stop = loc; 
    while (i < nfiles) { 
      if (loc < filesizes[i]) 
        break; 
      loc -= filesizes[i++]; 
    } 
    if (i == nfiles) 
      throw DemuxExcept(DemuxExcept::END_OF_STREAM); 
 
//    fpos = loc; 
//    fsetpos(filehandles[i++], &fpos); 
    _lseeki64(filehandles[i++], loc, SEEK_SET); 
 
    while (i < nfiles) 
      _lseeki64(filehandles[i++], 0, SEEK_SET); 
//      rewind(filehandles[i++]); 
  } 
} 
 
unsigned long AsyncStream::GetBits(int nbits) 
{ 
  unsigned long bits = 0; 
 
  while (nbits > 0) { 
    if (pos_bit == 0) { 
      pos++; 
      if (pos == stop) { 
        if (end_of_stream) 
          throw DemuxExcept(DemuxExcept::END_OF_STREAM); 
        if (ReadChunk() == 0)  
          throw DemuxExcept(DemuxExcept::END_OF_STREAM); 
      } 
      pos_bit = 8; 
    } 
    if (pos_bit >= nbits) {   // all bits present in current byte? 
      bits = (bits << nbits) | 
             ((bitbuffer[(int)pos & BUFFERMASK] >> (pos_bit - nbits)) & 
              ((1L << nbits) - 1)); 
      pos_bit -= nbits; 
      return bits; 
    } 
    else { 
      bits =  (bits << pos_bit) | 
              (bitbuffer[(int)pos & BUFFERMASK] & ((1L << pos_bit) - 1)); 
      nbits -= pos_bit; 
      pos_bit = 0; 
    } 
  } 
  return bits; 
} 
 
unsigned long AsyncStream::GetBit() 
{ 
  if (pos_bit == 0) { 
    pos++; 
    if (pos == stop) { 
      if (end_of_stream) 
        throw DemuxExcept(DemuxExcept::END_OF_STREAM); 
      if (ReadChunk() == 0)  
        throw DemuxExcept(DemuxExcept::END_OF_STREAM); 
    } 
    pos_bit = 8; 
  } 
  pos_bit--; 
  return (bitbuffer[(int)pos & BUFFERMASK] >> pos_bit) & 1L; 
} 
 
void AsyncStream::CopyBlock(unsigned char *dest, int nbytes) 
{ 
  int remainder = 0; 
 
  if (nbytes == 0) 
    return; 
 
  if (((int)(pos + nbytes - 1) & BUFFERMASK) < ((int)pos & BUFFERMASK)) { 
    remainder = BUFFERSIZE - ((int)pos & BUFFERMASK); 
    memcpy(dest, &bitbuffer[(int)pos & BUFFERMASK], remainder); 
    dest += remainder; 
    nbytes -= remainder; 
  } 
  if (nbytes) 
    memcpy(dest, &bitbuffer[(int)(pos + remainder) & BUFFERMASK], nbytes); 
} 
 
void AsyncStream::GetBytes(unsigned char *dest, int nbytes) 
{ 
  int bytes_left; 
 
  pos_bit = 0; 
  while (nbytes > 0) { 
    if (++pos == stop) { 
      if (end_of_stream) 
        throw DemuxExcept(DemuxExcept::END_OF_STREAM); 
      ReadChunk(); 
    } 
    bytes_left = (int)(stop - pos); 
    if (bytes_left >= nbytes) { 
      CopyBlock(dest, nbytes); 
      pos += nbytes - 1; 
      return; 
    } 
    CopyBlock(dest, bytes_left); 
    dest += bytes_left; 
    nbytes -= bytes_left; 
    pos = stop - 1; 
  } 
} 
 
void AsyncStream::FlushBytes(int nbytes) 
{ 
  int bytes_left; 
 
  pos_bit = 0; 
  while (nbytes > 0) { 
    if (++pos == stop) { 
      if (end_of_stream) 
        throw DemuxExcept(DemuxExcept::END_OF_STREAM); 
      ReadChunk(); 
    } 
    bytes_left = (int)(stop - pos); 
    if (bytes_left >= nbytes) { 
      pos += nbytes - 1; 
      return; 
    } 
    nbytes -= bytes_left; 
    pos = stop - 1; 
  } 
} 
 
unsigned long AsyncStream::LookAhead(int nbits) 
{ 
  unsigned long bits; 
  __int64 pos_save; 
  int pos_bit_save; 
   
  pos_save = pos; 
  pos_bit_save = pos_bit; 
  bits = GetBits(nbits); 
  pos = pos_save; 
  pos_bit = pos_bit_save; 
 
  return bits; 
}