示例#1
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));
  }
示例#2
0
  public SampleList(TrackBox trackBox) {
    this.isoFile = trackBox.getIsoFile(); // where are we?
    offsets2Sizes = new HashMap<Long, Long>();

    // find all mdats first to be able to use them later with explicitly looking them up
    long currentOffset = 0;
    for (Box b : isoFile.getBoxes()) {
      long currentSize = b.getSize();
      if ("mdat".equals(b.getType())) {
        if (b instanceof MediaDataBox) {
          long contentOffset = currentOffset + ((MediaDataBox) b).getHeader().limit();
          mdatStartCache.put((MediaDataBox) b, contentOffset);
          mdatEndCache.put((MediaDataBox) b, contentOffset + currentSize);
          mdats.add((MediaDataBox) b);
        } else {
          throw new RuntimeException(
              "Sample need to be in mdats and mdats need to be instanceof MediaDataBox");
        }
      }
      currentOffset += currentSize;
    }

    // first we get all sample from the 'normal' MP4 part.
    // if there are none - no problem.

    SampleSizeBox sampleSizeBox = trackBox.getSampleTableBox().getSampleSizeBox();
    ChunkOffsetBox chunkOffsetBox = trackBox.getSampleTableBox().getChunkOffsetBox();
    SampleToChunkBox sampleToChunkBox = trackBox.getSampleTableBox().getSampleToChunkBox();

    if (sampleToChunkBox != null
        && sampleToChunkBox.getEntries().size() > 0
        && chunkOffsetBox != null
        && chunkOffsetBox.getChunkOffsets().length > 0
        && sampleSizeBox != null
        && sampleSizeBox.getSampleCount() > 0) {
      long[] numberOfSamplesInChunk =
          sampleToChunkBox.blowup(chunkOffsetBox.getChunkOffsets().length);
      if (sampleSizeBox.getSampleSize() > 0) {
        // Every sample has the same size!
        // no need to store each size separately
        // this happens when people use raw audio formats in MP4 (are you stupid guys???)
        offsets2Sizes = new DummyMap<Long, Long>(sampleSizeBox.getSampleSize());
        long sampleSize = sampleSizeBox.getSampleSize();
        for (int i = 0; i < numberOfSamplesInChunk.length; i++) {
          long thisChunksNumberOfSamples = numberOfSamplesInChunk[i];
          long sampleOffset = chunkOffsetBox.getChunkOffsets()[i];
          for (int j = 0; j < thisChunksNumberOfSamples; j++) {
            offsets2Sizes.put(sampleOffset, sampleSize);
            sampleOffset += sampleSize;
          }
        }
      } else {
        // the normal case where all samples have different sizes
        int sampleIndex = 0;
        long sampleSizes[] = sampleSizeBox.getSampleSizes();
        for (int i = 0; i < numberOfSamplesInChunk.length; i++) {
          long thisChunksNumberOfSamples = numberOfSamplesInChunk[i];
          long sampleOffset = chunkOffsetBox.getChunkOffsets()[i];
          for (int j = 0; j < thisChunksNumberOfSamples; j++) {
            long sampleSize = sampleSizes[sampleIndex];
            offsets2Sizes.put(sampleOffset, sampleSize);
            sampleOffset += sampleSize;
            sampleIndex++;
          }
        }
      }
    }

    // Next we add all samples from the fragments
    // in most cases - I've never seen it different it's either normal or fragmented.

    List<MovieExtendsBox> movieExtendsBoxes = trackBox.getParent().getBoxes(MovieExtendsBox.class);

    if (movieExtendsBoxes.size() > 0) {
      List<TrackExtendsBox> trackExtendsBoxes =
          movieExtendsBoxes.get(0).getBoxes(TrackExtendsBox.class);
      for (TrackExtendsBox trackExtendsBox : trackExtendsBoxes) {
        if (trackExtendsBox.getTrackId() == trackBox.getTrackHeaderBox().getTrackId()) {
          for (MovieFragmentBox movieFragmentBox :
              trackBox.getIsoFile().getBoxes(MovieFragmentBox.class)) {
            offsets2Sizes.putAll(
                getOffsets(movieFragmentBox, trackBox.getTrackHeaderBox().getTrackId()));
          }
        }
      }
    }

    // We have now a map from all sample offsets to their sizes
  }