예제 #1
0
  protected FileTypeBox createFileTypeBox(Movie movie) {
    List<String> minorBrands = new LinkedList<String>();

    minorBrands.add("mp42");
    minorBrands.add("isom");

    return new FileTypeBox("mp42", 0, minorBrands);
  }
예제 #2
0
 protected void createCtts(Track track, SampleTableBox stbl) {
   List<CompositionTimeToSample.Entry> compositionTimeToSampleEntries =
       track.getCompositionTimeEntries();
   if (compositionTimeToSampleEntries != null && !compositionTimeToSampleEntries.isEmpty()) {
     CompositionTimeToSample ctts = new CompositionTimeToSample();
     ctts.setEntries(compositionTimeToSampleEntries);
     stbl.addBox(ctts);
   }
 }
예제 #3
0
  protected Box createStbl(Track track, Movie movie, Map<Track, int[]> chunks) {
    SampleTableBox stbl = new SampleTableBox();

    createStsd(track, stbl);
    createStts(track, stbl);
    createCtts(track, stbl);
    createStss(track, stbl);
    createSdtp(track, stbl);
    createStsc(track, chunks, stbl);
    createStsz(track, stbl);
    createStco(track, movie, chunks, stbl);

    Map<String, List<GroupEntry>> groupEntryFamilies = new HashMap<String, List<GroupEntry>>();
    for (Map.Entry<GroupEntry, long[]> sg : track.getSampleGroups().entrySet()) {
      String type = sg.getKey().getType();
      List<GroupEntry> groupEntries = groupEntryFamilies.get(type);
      if (groupEntries == null) {
        groupEntries = new ArrayList<GroupEntry>();
        groupEntryFamilies.put(type, groupEntries);
      }
      groupEntries.add(sg.getKey());
    }
    for (Map.Entry<String, List<GroupEntry>> sg : groupEntryFamilies.entrySet()) {
      SampleGroupDescriptionBox sgdb = new SampleGroupDescriptionBox();
      String type = sg.getKey();
      sgdb.setGroupEntries(sg.getValue());
      SampleToGroupBox sbgp = new SampleToGroupBox();
      sbgp.setGroupingType(type);
      SampleToGroupBox.Entry last = null;
      for (int i = 0; i < track.getSamples().size(); i++) {
        int index = 0;
        for (int j = 0; j < sg.getValue().size(); j++) {
          GroupEntry groupEntry = sg.getValue().get(j);
          long[] sampleNums = track.getSampleGroups().get(groupEntry);
          if (Arrays.binarySearch(sampleNums, i) >= 0) {
            index = j + 1;
          }
        }
        if (last == null || last.getGroupDescriptionIndex() != index) {
          last = new SampleToGroupBox.Entry(1, index);
          sbgp.getEntries().add(last);
        } else {
          last.setSampleCount(last.getSampleCount() + 1);
        }
      }
      stbl.addBox(sgdb);
      stbl.addBox(sbgp);
    }

    if (track instanceof CencEncryptedTrack) {
      createCencBoxes((CencEncryptedTrack) track, stbl, chunks.get(track));
    }
    createSubs(track, stbl);

    return stbl;
  }
예제 #4
0
  protected void createStts(Track track, SampleTableBox stbl) {
    TimeToSampleBox.Entry lastEntry = null;
    List<TimeToSampleBox.Entry> entries = new ArrayList<TimeToSampleBox.Entry>();

    for (long delta : track.getSampleDurations()) {
      if (lastEntry != null && lastEntry.getDelta() == delta) {
        lastEntry.setCount(lastEntry.getCount() + 1);
      } else {
        lastEntry = new TimeToSampleBox.Entry(1, delta);
        entries.add(lastEntry);
      }
    }
    TimeToSampleBox stts = new TimeToSampleBox();
    stts.setEntries(entries);
    stbl.addBox(stts);
  }
예제 #5
0
  protected void createCencBoxes(CencEncryptedTrack track, SampleTableBox stbl, int[] chunkSizes) {

    SampleAuxiliaryInformationSizesBox saiz = new SampleAuxiliaryInformationSizesBox();

    saiz.setAuxInfoType("cenc");
    saiz.setFlags(1);
    List<CencSampleAuxiliaryDataFormat> sampleEncryptionEntries =
        track.getSampleEncryptionEntries();
    if (track.hasSubSampleEncryption()) {
      short[] sizes = new short[sampleEncryptionEntries.size()];
      for (int i = 0; i < sizes.length; i++) {
        sizes[i] = (short) sampleEncryptionEntries.get(i).getSize();
      }
      saiz.setSampleInfoSizes(sizes);
    } else {
      saiz.setDefaultSampleInfoSize(8); // 8 bytes iv
      saiz.setSampleCount(track.getSamples().size());
    }

    SampleAuxiliaryInformationOffsetsBox saio = new SampleAuxiliaryInformationOffsetsBox();
    SampleEncryptionBox senc = new SampleEncryptionBox();
    senc.setSubSampleEncryption(track.hasSubSampleEncryption());
    senc.setEntries(sampleEncryptionEntries);

    long offset = senc.getOffsetToFirstIV();
    int index = 0;
    long[] offsets = new long[chunkSizes.length];

    for (int i = 0; i < chunkSizes.length; i++) {
      offsets[i] = offset;
      for (int j = 0; j < chunkSizes[i]; j++) {
        offset += sampleEncryptionEntries.get(index++).getSize();
      }
    }
    saio.setOffsets(offsets);

    stbl.addBox(saiz);
    stbl.addBox(saio);
    stbl.addBox(senc);
    sampleAuxiliaryInformationOffsetsBoxes.add(saio);
  }
예제 #6
0
  protected Box createEdts(Track track, Movie movie) {
    if (track.getEdits() != null && track.getEdits().size() > 0) {
      EditListBox elst = new EditListBox();
      elst.setVersion(0); // quicktime won't play file when version = 1
      List<EditListBox.Entry> entries = new ArrayList<EditListBox.Entry>();

      for (Edit edit : track.getEdits()) {
        entries.add(
            new EditListBox.Entry(
                elst,
                Math.round(edit.getSegmentDuration() * movie.getTimescale()),
                edit.getMediaTime() * track.getTrackMetaData().getTimescale() / edit.getTimeScale(),
                edit.getMediaRate()));
      }

      elst.setEntries(entries);
      EditBox edts = new EditBox();
      edts.addBox(elst);
      return edts;
    } else {
      return null;
    }
  }
예제 #7
0
  /** {@inheritDoc} */
  public Container build(Movie movie) {
    if (fragmenter == null) {
      fragmenter = new TimeBasedFragmenter(2);
    }
    LOG.fine("Creating movie " + movie);
    for (Track track : movie.getTracks()) {
      // getting the samples may be a time consuming activity
      List<Sample> samples = track.getSamples();
      putSamples(track, samples);
      long[] sizes = new long[samples.size()];
      for (int i = 0; i < sizes.length; i++) {
        Sample b = samples.get(i);
        sizes[i] = b.getSize();
      }
      track2SampleSizes.put(track, sizes);
    }

    BasicContainer isoFile = new BasicContainer();

    isoFile.addBox(createFileTypeBox(movie));

    Map<Track, int[]> chunks = new HashMap<Track, int[]>();
    for (Track track : movie.getTracks()) {
      chunks.put(track, getChunkSizes(track));
    }
    Box moov = createMovieBox(movie, chunks);
    isoFile.addBox(moov);
    List<SampleSizeBox> stszs = Path.getPaths(moov, "trak/mdia/minf/stbl/stsz");

    long contentSize = 0;
    for (SampleSizeBox stsz : stszs) {
      contentSize += sum(stsz.getSampleSizes());
    }

    InterleaveChunkMdat mdat = new InterleaveChunkMdat(movie, chunks, contentSize);
    isoFile.addBox(mdat);

    /*
    dataOffset is where the first sample starts. In this special mdat the samples always start
    at offset 16 so that we can use the same offset for large boxes and small boxes
     */
    long dataOffset = mdat.getDataOffset();
    for (StaticChunkOffsetBox chunkOffsetBox : chunkOffsetBoxes.values()) {
      long[] offsets = chunkOffsetBox.getChunkOffsets();
      for (int i = 0; i < offsets.length; i++) {
        offsets[i] += dataOffset;
      }
    }
    for (SampleAuxiliaryInformationOffsetsBox saio : sampleAuxiliaryInformationOffsetsBoxes) {
      long offset =
          saio.getSize(); // the calculation is systematically wrong by 4, I don't want to debug
      // why. Just a quick correction --san 14.May.13
      offset += 4 + 4 + 4 + 4 + 4 + 24;
      // size of all header we were missing otherwise (moov, trak, mdia, minf, stbl)
      Object b = saio;
      do {
        Object current = b;
        b = ((Box) b).getParent();

        for (Box box : ((Container) b).getBoxes()) {
          if (box == current) {
            break;
          }
          offset += box.getSize();
        }

      } while (b instanceof Box);

      long[] saioOffsets = saio.getOffsets();
      for (int i = 0; i < saioOffsets.length; i++) {
        saioOffsets[i] = saioOffsets[i] + offset;
      }
      saio.setOffsets(saioOffsets);
    }

    return isoFile;
  }