示例#1
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;
  }
示例#2
0
  protected void createStsc(Track track, Map<Track, int[]> chunks, SampleTableBox stbl) {
    int[] tracksChunkSizes = chunks.get(track);

    SampleToChunkBox stsc = new SampleToChunkBox();
    stsc.setEntries(new LinkedList<SampleToChunkBox.Entry>());
    long lastChunkSize = Integer.MIN_VALUE; // to be sure the first chunks hasn't got the same size
    for (int i = 0; i < tracksChunkSizes.length; i++) {
      // The sample description index references the sample description box
      // that describes the samples of this chunk. My Tracks cannot have more
      // than one sample description box. Therefore 1 is always right
      // the first chunk has the number '1'
      if (lastChunkSize != tracksChunkSizes[i]) {
        stsc.getEntries().add(new SampleToChunkBox.Entry(i + 1, tracksChunkSizes[i], 1));
        lastChunkSize = tracksChunkSizes[i];
      }
    }
    stbl.addBox(stsc);
  }
示例#3
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;
  }
示例#4
0
    private InterleaveChunkMdat(Movie movie, Map<Track, int[]> chunks, long contentSize) {
      this.contentSize = contentSize;
      this.tracks = movie.getTracks();
      List<Track> tracks = new ArrayList<Track>(chunks.keySet());
      Collections.sort(
          tracks,
          new Comparator<Track>() {
            public int compare(Track o1, Track o2) {
              return l2i(o1.getTrackMetaData().getTrackId() - o2.getTrackMetaData().getTrackId());
            }
          });
      Map<Track, Integer> trackToChunk = new HashMap<Track, Integer>();
      Map<Track, Integer> trackToSample = new HashMap<Track, Integer>();
      Map<Track, Double> trackToTime = new HashMap<Track, Double>();
      for (Track track : tracks) {
        trackToChunk.put(track, 0);
        trackToSample.put(track, 0);
        trackToTime.put(track, 0.0);
      }

      while (true) {
        Track nextChunksTrack = null;
        for (Track track : tracks) {
          if ((nextChunksTrack == null || trackToTime.get(track) < trackToTime.get(nextChunksTrack))
              &&
              // either first OR track's next chunk's starttime is smaller than nextTrack's next
              // chunks starttime
              // AND their need to be chunks left!
              (trackToChunk.get(track) < chunks.get(track).length)) {
            nextChunksTrack = track;
          }
        }
        if (nextChunksTrack == null) {
          break;
        }
        // found the next one

        int nextChunksIndex = trackToChunk.get(nextChunksTrack);
        int numberOfSampleInNextChunk = chunks.get(nextChunksTrack)[nextChunksIndex];
        int startSample = trackToSample.get(nextChunksTrack);
        double time = trackToTime.get(nextChunksTrack);
        for (int j = startSample; j < startSample + numberOfSampleInNextChunk; j++) {
          time +=
              (double) nextChunksTrack.getSampleDurations()[j]
                  / nextChunksTrack.getTrackMetaData().getTimescale();
        }
        chunkList.add(
            nextChunksTrack
                .getSamples()
                .subList(startSample, startSample + numberOfSampleInNextChunk));

        trackToChunk.put(nextChunksTrack, nextChunksIndex + 1);
        trackToSample.put(nextChunksTrack, startSample + numberOfSampleInNextChunk);
        trackToTime.put(nextChunksTrack, time);
      }
    }
示例#5
0
  protected void createStco(
      Track targetTrack, Movie movie, Map<Track, int[]> chunks, SampleTableBox stbl) {
    if (chunkOffsetBoxes.get(targetTrack) == null) {
      // The ChunkOffsetBox we create here is just a stub
      // since we haven't created the whole structure we can't tell where the
      // first chunk starts (mdat box). So I just let the chunk offset
      // start at zero and I will add the mdat offset later.

      long offset = 0;
      // all tracks have the same number of chunks
      if (LOG.isLoggable(Level.FINE)) {
        LOG.fine(
            "Calculating chunk offsets for track_" + targetTrack.getTrackMetaData().getTrackId());
      }

      List<Track> tracks = new ArrayList<Track>(chunks.keySet());
      Collections.sort(
          tracks,
          new Comparator<Track>() {
            public int compare(Track o1, Track o2) {
              return l2i(o1.getTrackMetaData().getTrackId() - o2.getTrackMetaData().getTrackId());
            }
          });
      Map<Track, Integer> trackToChunk = new HashMap<Track, Integer>();
      Map<Track, Integer> trackToSample = new HashMap<Track, Integer>();
      Map<Track, Double> trackToTime = new HashMap<Track, Double>();
      for (Track track : tracks) {
        trackToChunk.put(track, 0);
        trackToSample.put(track, 0);
        trackToTime.put(track, 0.0);
        chunkOffsetBoxes.put(track, new StaticChunkOffsetBox());
      }

      while (true) {
        Track nextChunksTrack = null;
        for (Track track : tracks) {
          // This always chooses the least progressed track
          if ((nextChunksTrack == null || trackToTime.get(track) < trackToTime.get(nextChunksTrack))
              &&
              // either first OR track's next chunk's starttime is smaller than nextTrack's next
              // chunks starttime
              // AND their need to be chunks left!
              (trackToChunk.get(track) < chunks.get(track).length)) {
            nextChunksTrack = track;
          }
        }
        if (nextChunksTrack == null) {
          break; // no next
        }
        // found the next one
        ChunkOffsetBox chunkOffsetBox = chunkOffsetBoxes.get(nextChunksTrack);
        chunkOffsetBox.setChunkOffsets(
            Mp4Arrays.copyOfAndAppend(chunkOffsetBox.getChunkOffsets(), offset));

        int nextChunksIndex = trackToChunk.get(nextChunksTrack);

        int numberOfSampleInNextChunk = chunks.get(nextChunksTrack)[nextChunksIndex];
        int startSample = trackToSample.get(nextChunksTrack);
        double time = trackToTime.get(nextChunksTrack);

        for (int j = startSample; j < startSample + numberOfSampleInNextChunk; j++) {
          offset += track2SampleSizes.get(nextChunksTrack)[j];
          time +=
              (double) nextChunksTrack.getSampleDurations()[j]
                  / nextChunksTrack.getTrackMetaData().getTimescale();
        }
        trackToChunk.put(nextChunksTrack, nextChunksIndex + 1);
        trackToSample.put(nextChunksTrack, startSample + numberOfSampleInNextChunk);
        trackToTime.put(nextChunksTrack, time);
      }
    }

    stbl.addBox(chunkOffsetBoxes.get(targetTrack));
  }