Beispiel #1
0
void APE::Properties::analyzeCurrent(File *file)
{
  // Read the descriptor
  file->seek(2, File::Current);
  const ByteVector descriptor = file->readBlock(44);
  if(descriptor.size() < 44) {
    debug("APE::Properties::analyzeCurrent() -- descriptor is too short.");
    return;
  }

  const unsigned int descriptorBytes = descriptor.toUInt(0, false);

  if((descriptorBytes - 52) > 0)
    file->seek(descriptorBytes - 52, File::Current);

  // Read the header
  const ByteVector header = file->readBlock(24);
  if(header.size() < 24) {
    debug("APE::Properties::analyzeCurrent() -- MAC header is too short.");
    return;
  }

  // Get the APE info
  d->channels      = header.toShort(18, false);
  d->sampleRate    = header.toUInt(20, false);
  d->bitsPerSample = header.toShort(16, false);

  const unsigned int totalFrames = header.toUInt(12, false);
  if(totalFrames == 0)
    return;

  const unsigned int blocksPerFrame   = header.toUInt(4, false);
  const unsigned int finalFrameBlocks = header.toUInt(8, false);
  d->sampleFrames = (totalFrames - 1) * blocksPerFrame + finalFrameBlocks;
}
Beispiel #2
0
void RIFF::AIFF::Properties::read(const ByteVector &data)
{
  d->channels       = data.toShort(0U);
  d->sampleFrames   = data.toUInt(2U);
  d->sampleWidth    = data.toShort(6U);
  double sampleRate = ConvertFromIeeeExtended(reinterpret_cast<const uchar *>(data.data() + 8));
  d->sampleRate     = (int)sampleRate;
  d->bitrate        = (int)((sampleRate * d->sampleWidth * d->channels) / 1000.0);
  d->length         = d->sampleRate > 0 ? d->sampleFrames / d->sampleRate : 0;
}
Beispiel #3
0
void RIFF::WAV::Properties::read(const ByteVector &data)
{
  d->format      = data.toShort(0, false);
  d->channels    = data.toShort(2, false);
  d->sampleRate  = data.toUInt(4, false);
  d->sampleWidth = data.toShort(14, false);

  const uint byteRate = data.toUInt(8, false);
  d->bitrate = byteRate * 8 / 1000;

  d->length = byteRate > 0 ? d->streamLength / byteRate : 0;
  if(d->channels > 0 && d->sampleWidth > 0)
    d->sampleFrames = d->streamLength / (d->channels * ((d->sampleWidth + 7) / 8));
}
Beispiel #4
0
void RelativeVolumeFrame::parseFields(const ByteVector &data)
{
  int pos = 0;
  d->identification = readStringField(data, String::Latin1, &pos);

  // Each channel is at least 4 bytes.

  while(pos <= (int)data.size() - 4) {


    ChannelType type = ChannelType(data[pos]);
    pos += 1;

    ChannelData &channel = d->channels[type];

    channel.volumeAdjustment = data.toShort(static_cast<uint>(pos));
    pos += 2;

    channel.peakVolume.bitsRepresentingPeak = data[pos];
    pos += 1;

    int bytes = bitsToBytes(channel.peakVolume.bitsRepresentingPeak);
    channel.peakVolume.peakVolume = data.mid(pos, bytes);
    pos += bytes;
  }
}
Beispiel #5
0
void APE::Properties::analyzeOld(File *file)
{
  const ByteVector header = file->readBlock(26);
  if(header.size() < 26) {
    debug("APE::Properties::analyzeOld() -- MAC header is too short.");
    return;
  }

  const unsigned int totalFrames = header.toUInt(18, false);

  // Fail on 0 length APE files (catches non-finalized APE files)
  if(totalFrames == 0)
    return;

  const short compressionLevel = header.toShort(0, false);
  unsigned int blocksPerFrame;
  if(d->version >= 3950)
    blocksPerFrame = 73728 * 4;
  else if(d->version >= 3900 || (d->version >= 3800 && compressionLevel == 4000))
    blocksPerFrame = 73728;
  else
    blocksPerFrame = 9216;

  // Get the APE info
  d->channels   = header.toShort(4, false);
  d->sampleRate = header.toUInt(6, false);

  const unsigned int finalFrameBlocks = header.toUInt(22, false);
  d->sampleFrames = (totalFrames - 1) * blocksPerFrame + finalFrameBlocks;

  // Get the bit depth from the RIFF-fmt chunk.
  file->seek(16, File::Current);
  const ByteVector fmt = file->readBlock(28);
  if(fmt.size() < 28 || !fmt.startsWith("WAVEfmt ")) {
    debug("APE::Properties::analyzeOld() -- fmt header is too short.");
    return;
  }

  d->bitsPerSample = fmt.toShort(26, false);
}
MP4::Properties::Properties(File *file, MP4::Atoms *atoms, ReadStyle style)
  : AudioProperties(style)
{
  d = new PropertiesPrivate;

  MP4::Atom *moov = atoms->find("moov");
  if(!moov) {
    debug("MP4: Atom 'moov' not found");
    return;
  }

  MP4::Atom *trak = 0;
  ByteVector data;

  MP4::AtomList trakList = moov->findall("trak");
  for (unsigned int i = 0; i < trakList.size(); i++) {
    trak = trakList[i];
    MP4::Atom *hdlr = trak->find("mdia", "hdlr");
    if(!hdlr) {
      debug("MP4: Atom 'trak.mdia.hdlr' not found");
      return;
    }
    file->seek(hdlr->offset);
    data = file->readBlock(hdlr->length);
    if(data.mid(16, 4) == "soun") {
      break;
    }
    trak = 0;
  }
  if (!trak) {
    debug("MP4: No audio tracks");
    return;
  }

  MP4::Atom *mdhd = trak->find("mdia", "mdhd");
  if(!mdhd) {
    debug("MP4: Atom 'trak.mdia.mdhd' not found");
    return;
  }

  file->seek(mdhd->offset);
  data = file->readBlock(mdhd->length);
  uint version = data[8];
  if(version == 1) {
    if (data.size() < 36 + 8) {
      debug("MP4: Atom 'trak.mdia.mdhd' is smaller than expected");
      return;
    }
    const long long unit   = data.toLongLong(28U);
    const long long length = data.toLongLong(36U);
    d->length = unit ? int(length / unit) : 0;
  }
  else {
    if (data.size() < 24 + 4) {
      debug("MP4: Atom 'trak.mdia.mdhd' is smaller than expected");
      return;
    }
    const unsigned int unit   = data.toUInt(20U);
    const unsigned int length = data.toUInt(24U);
    d->length = unit ? length / unit : 0;
  }

  MP4::Atom *atom = trak->find("mdia", "minf", "stbl", "stsd");
  if(!atom) {
    return;
  }

  file->seek(atom->offset);
  data = file->readBlock(atom->length);
  if(data.mid(20, 4) == "mp4a") {
    d->channels      = data.toShort(40U);
    d->bitsPerSample = data.toShort(42U);
    d->sampleRate    = data.toUInt(46U);
    if(data.mid(56, 4) == "esds" && data[64] == 0x03) {
      uint pos = 65;
      if(data.mid(pos, 3) == "\x80\x80\x80") {
        pos += 3;
      }
      pos += 4;
      if(data[pos] == 0x04) {
        pos += 1;
        if(data.mid(pos, 3) == "\x80\x80\x80") {
          pos += 3;
        }
        pos += 10;
        d->bitrate = (data.toUInt(pos) + 500) / 1000;
      }
    }
  }
  else if (data.mid(20, 4) == "alac") {
    if (atom->length == 88 && data.mid(56, 4) == "alac") {
      d->bitsPerSample = data.at(69);
      d->channels   = data.at(73);
      d->bitrate    = data.toUInt(80U) / 1000;
      d->sampleRate = data.toUInt(84U);
    }
  }

  MP4::Atom *drms = atom->find("drms");
  if(drms) {
    d->encrypted = true;
  }
}
void RIFF::WAV::Properties::read(File *file)
{
  ByteVector data;
  uint streamLength = 0;
  uint totalSamples = 0;

  for(uint i = 0; i < file->chunkCount(); ++i) {
    const ByteVector name = file->chunkName(i);
    if(name == "fmt ") {
      if(data.isEmpty())
        data = file->chunkData(i);
      else
        debug("RIFF::WAV::Properties::read() - Duplicate 'fmt ' chunk found.");
    }
    else if(name == "data") {
      if(streamLength == 0)
        streamLength = file->chunkDataSize(i) + file->chunkPadding(i);
      else
        debug("RIFF::WAV::Properties::read() - Duplicate 'data' chunk found.");
    }
    else if(name == "fact") {
      if(totalSamples == 0)
        totalSamples = file->chunkData(i).toUInt(0, false);
      else
        debug("RIFF::WAV::Properties::read() - Duplicate 'fact' chunk found.");
    }
  }

  if(data.size() < 16) {
    debug("RIFF::WAV::Properties::read() - 'fmt ' chunk not found or too short.");
    return;
  }

  if(streamLength == 0) {
    debug("RIFF::WAV::Properties::read() - 'data' chunk not found.");
    return;
  }

  d->format = data.toShort(0, false);
  if(d->format != FORMAT_PCM && totalSamples == 0) {
    debug("RIFF::WAV::Properties::read() - Non-PCM format, but 'fact' chunk not found.");
    return;
  }

  d->channels      = data.toShort(2, false);
  d->sampleRate    = data.toUInt(4, false);
  d->bitsPerSample = data.toShort(14, false);

  if(totalSamples > 0)
    d->sampleFrames = totalSamples;
  else if(d->channels > 0 && d->bitsPerSample > 0)
    d->sampleFrames = streamLength / (d->channels * ((d->bitsPerSample + 7) / 8));

  if(d->sampleFrames > 0 && d->sampleRate > 0) {
    const double length = d->sampleFrames * 1000.0 / d->sampleRate;
    d->length  = static_cast<int>(length + 0.5);
    d->bitrate = static_cast<int>(streamLength * 8.0 / length + 0.5);
  }
  else {
    const uint byteRate = data.toUInt(8, false);
    if(byteRate > 0) {
      d->length  = static_cast<int>(streamLength * 1000.0 / byteRate + 0.5);
      d->bitrate = static_cast<int>(byteRate * 8.0 / 1000.0 + 0.5);
    }
  }
}
Beispiel #8
0
int ASF::File::readWORD()
{
  ByteVector v = readBlock(2);
  return v.toShort(false);
}
Beispiel #9
0
void
MP4::Properties::read(File *file, Atoms *atoms)
{
  MP4::Atom *moov = atoms->find("moov");
  if(!moov) {
    debug("MP4: Atom 'moov' not found");
    return;
  }

  MP4::Atom *trak = 0;
  ByteVector data;

  const MP4::AtomList trakList = moov->findall("trak");
  for(MP4::AtomList::ConstIterator it = trakList.begin(); it != trakList.end(); ++it) {
    trak = *it;
    MP4::Atom *hdlr = trak->find("mdia", "hdlr");
    if(!hdlr) {
      debug("MP4: Atom 'trak.mdia.hdlr' not found");
      return;
    }
    file->seek(hdlr->offset);
    data = file->readBlock(hdlr->length);
    if(data.containsAt("soun", 16)) {
      break;
    }
    trak = 0;
  }
  if(!trak) {
    debug("MP4: No audio tracks");
    return;
  }

  MP4::Atom *mdhd = trak->find("mdia", "mdhd");
  if(!mdhd) {
    debug("MP4: Atom 'trak.mdia.mdhd' not found");
    return;
  }

  file->seek(mdhd->offset);
  data = file->readBlock(mdhd->length);

  const unsigned int version = data[8];
  long long unit;
  long long length;
  if(version == 1) {
    if(data.size() < 36 + 8) {
      debug("MP4: Atom 'trak.mdia.mdhd' is smaller than expected");
      return;
    }
    unit   = data.toUInt(28U);
    length = data.toLongLong(32U);
  }
  else {
    if(data.size() < 24 + 8) {
      debug("MP4: Atom 'trak.mdia.mdhd' is smaller than expected");
      return;
    }
    unit   = data.toUInt(20U);
    length = data.toUInt(24U);
  }
  if(unit > 0 && length > 0)
    d->length = static_cast<int>(length * 1000.0 / unit + 0.5);

  MP4::Atom *atom = trak->find("mdia", "minf", "stbl", "stsd");
  if(!atom) {
    return;
  }

  file->seek(atom->offset);
  data = file->readBlock(atom->length);
  if(data.containsAt("mp4a", 20)) {
    d->codec         = AAC;
    d->channels      = data.toShort(40U);
    d->bitsPerSample = data.toShort(42U);
    d->sampleRate    = data.toUInt(46U);
    if(data.containsAt("esds", 56) && data[64] == 0x03) {
      unsigned int pos = 65;
      if(data.containsAt("\x80\x80\x80", pos)) {
        pos += 3;
      }
      pos += 4;
      if(data[pos] == 0x04) {
        pos += 1;
        if(data.containsAt("\x80\x80\x80", pos)) {
          pos += 3;
        }
        pos += 10;
        d->bitrate = static_cast<int>((data.toUInt(pos) + 500) / 1000.0 + 0.5);
      }
    }
  }
  else if(data.containsAt("alac", 20)) {
    if(atom->length == 88 && data.containsAt("alac", 56)) {
      d->codec         = ALAC;
      d->bitsPerSample = data.at(69);
      d->channels      = data.at(73);
      d->bitrate       = static_cast<int>(data.toUInt(80U) / 1000.0 + 0.5);
      d->sampleRate    = data.toUInt(84U);
    }
  }

  MP4::Atom *drms = atom->find("drms");
  if(drms) {
    d->encrypted = true;
  }
}