예제 #1
0
bool
MP4::File::checkValid(const MP4::AtomList &list)
{
  for(uint i = 0; i < list.size(); i++) {
    if(list[i]->length == 0)
      return false;
    if(!checkValid(list[i]->children))
      return false;
  }
  return true;
}
예제 #2
0
void
MP4::Tag::updateOffsets(long delta, long offset)
{
  MP4::Atom *moov = d->atoms->find("moov");
  if(moov) {
    MP4::AtomList stco = moov->findall("stco", true);
    for(unsigned int i = 0; i < stco.size(); i++) {
      MP4::Atom *atom = stco[i];
      if(atom->offset > offset) {
        atom->offset += delta;
      }
      d->file->seek(atom->offset + 12);
      ByteVector data = d->file->readBlock(atom->length - 12);
      unsigned int count = data.toUInt();
      d->file->seek(atom->offset + 16);
      uint pos = 4;
      while(count--) {
        long o = static_cast<long>(data.toUInt(pos));
        if(o > offset) {
          o += delta;
        }
        d->file->writeBlock(ByteVector::fromUInt(o));
        pos += 4;
      }
    }

    MP4::AtomList co64 = moov->findall("co64", true);
    for(unsigned int i = 0; i < co64.size(); i++) {
      MP4::Atom *atom = co64[i];
      if(atom->offset > offset) {
        atom->offset += delta;
      }
      d->file->seek(atom->offset + 12);
      ByteVector data = d->file->readBlock(atom->length - 12);
      unsigned int count = data.toUInt();
      d->file->seek(atom->offset + 16);
      uint pos = 4;
      while(count--) {
        long long o = data.toLongLong(pos);
        if(o > offset) {
          o += delta;
        }
        d->file->writeBlock(ByteVector::fromLongLong(o));
        pos += 8;
      }
    }
  }

  MP4::Atom *moof = d->atoms->find("moof");
  if(moof) {
    MP4::AtomList tfhd = moof->findall("tfhd", true);
    for(unsigned int i = 0; i < tfhd.size(); i++) {
      MP4::Atom *atom = tfhd[i];
      if(atom->offset > offset) {
        atom->offset += delta;
      }
      d->file->seek(atom->offset + 9);
      ByteVector data = d->file->readBlock(atom->length - 9);
      const unsigned int flags = data.toUInt(0, 3, true);
      if(flags & 1) {
        long long o = data.toLongLong(7U);
        if(o > offset) {
          o += delta;
        }
        d->file->seek(atom->offset + 16);
        d->file->writeBlock(ByteVector::fromLongLong(o));
      }
    }
  }
}
예제 #3
0
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);
	if(data[8] == 0) {
		unsigned int unit = data.mid(20, 4).toUInt();
		unsigned int length = data.mid(24, 4).toUInt();
		if (unit == 0) {
			debug("MP4: No valid data");
			d->length = 0;
		} else {
			d->length = length / unit;
		}
	}
	else {
		long long unit = data.mid(28, 8).toLongLong();
		long long length = data.mid(36, 8).toLongLong();
		if (unit == 0) {
			debug("MP4: No valid data");
			d->length = 0;
		} else {
			d->length = int(length / unit);
		}
	}

  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.mid(40, 2).toShort();
    d->bitsPerSample = data.mid(42, 2).toShort();
    d->sampleRate = data.mid(46, 4).toUInt();
    if(data.mid(56, 4) == "esds" && data[64] == 0x03) {
      long 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.mid(pos, 4).toUInt() + 500) / 1000;
      }
    }
  }
}
예제 #4
0
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;
  }
}