Пример #1
0
  private void selectInner(List<Edit> edits, Slice cut, MovieBox movie, TrakBox trakBox) {
    long inMv = (long) (movie.getTimescale() * cut.inSec);
    long outMv = (long) (movie.getTimescale() * cut.outSec);

    long editStart = 0;
    ListIterator<Edit> lit = edits.listIterator();
    while (lit.hasNext()) {
      Edit edit = lit.next();
      if (editStart + edit.getDuration() <= inMv || editStart >= outMv) lit.remove();
      editStart += edit.getDuration();
    }
  }
Пример #2
0
 private void selectOuter(
     List<Edit> edits, List<Slice> commands, MovieBox movie, TrakBox trakBox) {
   long[] inMv = new long[commands.size()];
   long[] outMv = new long[commands.size()];
   for (int i = 0; i < commands.size(); i++) {
     inMv[i] = (long) (commands.get(i).inSec * movie.getTimescale());
     outMv[i] = (long) (commands.get(i).outSec * movie.getTimescale());
   }
   long editStartMv = 0;
   ListIterator<Edit> lit = edits.listIterator();
   while (lit.hasNext()) {
     Edit edit = lit.next();
     for (int i = 0; i < inMv.length; i++) {
       if (editStartMv + edit.getDuration() > inMv[i] && editStartMv < outMv[i]) lit.remove();
     }
     editStartMv += edit.getDuration();
   }
 }
Пример #3
0
 private int calcSpaceReq(MovieBox movie) {
   int sum = 0;
   TrakBox[] tracks = movie.getTracks();
   for (int i = 0; i < tracks.length; i++) {
     TrakBox trakBox = tracks[i];
     ChunkOffsetsBox stco = trakBox.getStco();
     if (stco != null) sum += stco.getChunkOffsets().length * 4;
   }
   return sum;
 }
Пример #4
0
  @Test
  public void testAVCClip() throws IOException {
    File f1 = new File("src/test/resources/AVCClipCatTest/seq_1.mp4");

    MovieBox m1 = MP4Util.parseMovie(f1);

    VirtualTrack t1 =
        new AVCClipTrack(new RealTrack(m1, m1.getVideoTrack(), new FilePool(f1, 10)), 60, 120);

    VirtualMovie vm = new VirtualMP4Movie(t1);

    MovieRange range = new MovieRange(vm, 0, vm.size());

    BufferedOutputStream out =
        new BufferedOutputStream(
            new FileOutputStream(
                new File(System.getProperty("user.home"), "Desktop/precise_clip.mp4")));
    IOUtils.copy(range, out);
    out.flush();
    out.close();
  }
Пример #5
0
  @Test
  public void testAVCClipCat() throws IOException {
    File f1 = new File("src/test/resources/AVCClipCatTest/seq_1.mp4");
    File f2 = new File("src/test/resources/AVCClipCatTest/seq_2.mp4");
    File f3 = new File("src/test/resources/AVCClipCatTest/seq_3.mp4");

    MovieBox m1 = MP4Util.parseMovie(f1);
    MovieBox m2 = MP4Util.parseMovie(f2);
    MovieBox m3 = MP4Util.parseMovie(f3);

    VirtualTrack t1 =
        new AVCClipTrack(new RealTrack(m1, m1.getVideoTrack(), new FilePool(f1, 10)), 60, 120);
    VirtualTrack t2 =
        new AVCClipTrack(new RealTrack(m2, m2.getVideoTrack(), new FilePool(f2, 10)), 60, 120);
    VirtualTrack t3 =
        new AVCClipTrack(new RealTrack(m3, m3.getVideoTrack(), new FilePool(f3, 10)), 60, 120);

    AVCConcatTrack ct = new AVCConcatTrack(t1, t2, t3);
    VirtualMovie vm = new VirtualMP4Movie(ct);

    MovieRange range = new MovieRange(vm, 0, vm.size());

    BufferedOutputStream out =
        new BufferedOutputStream(
            new FileOutputStream(
                new File(System.getProperty("user.home"), "Desktop/cat_avc_clip.mp4")));
    IOUtils.copy(range, out);
    out.flush();
    out.close();
  }
Пример #6
0
 protected SeekableByteChannel[][] getInputs(MovieBox movie) throws IOException {
   TrakBox[] tracks = movie.getTracks();
   SeekableByteChannel[][] result = new SeekableByteChannel[tracks.length][];
   for (int i = 0; i < tracks.length; i++) {
     DataRefBox drefs =
         NodeBox.findFirstPath(tracks[i], DataRefBox.class, Box.path("mdia.minf.dinf.dref"));
     if (drefs == null) {
       throw new RuntimeException("No data references");
     }
     List<Box> entries = drefs.getBoxes();
     SeekableByteChannel[] e = new SeekableByteChannel[entries.size()];
     SeekableByteChannel[] inputs = new SeekableByteChannel[entries.size()];
     for (int j = 0; j < e.length; j++) {
       inputs[j] = resolveDataRef(entries.get(j));
     }
     result[i] = inputs;
   }
   return result;
 }
Пример #7
0
  public List<MovieBox> cut(MovieBox movie, List<Slice> commands) {

    TrakBox videoTrack = movie.getVideoTrack();
    if (videoTrack != null && videoTrack.getTimescale() != movie.getTimescale())
      movie.fixTimescale(videoTrack.getTimescale());

    TrakBox[] tracks = movie.getTracks();
    for (int i = 0; i < tracks.length; i++) {
      TrakBox trakBox = tracks[i];
      forceEditList(movie, trakBox);
      List<Edit> edits = trakBox.getEdits();
      for (Slice cut : commands) {
        split(edits, cut.inSec, movie, trakBox);
        split(edits, cut.outSec, movie, trakBox);
      }
    }
    ArrayList<MovieBox> result = new ArrayList<MovieBox>();
    for (Slice cut : commands) {
      MovieBox clone =
          (MovieBox) NodeBox.cloneBox(movie, 16 * 1024 * 1024, BoxFactory.getDefault());
      for (TrakBox trakBox : clone.getTracks()) {
        selectInner(trakBox.getEdits(), cut, movie, trakBox);
      }
      result.add(clone);
    }

    long movDuration = 0;
    for (TrakBox trakBox : movie.getTracks()) {
      selectOuter(trakBox.getEdits(), commands, movie, trakBox);
      trakBox.setEdits(trakBox.getEdits());
      movDuration = max(movDuration, trakBox.getDuration());
    }
    movie.setDuration(movDuration);

    return result;
  }
Пример #8
0
  public void flatternChannel(MovieBox movie, SeekableByteChannel out) throws IOException {
    if (!movie.isPureRefMovie(movie))
      throw new IllegalArgumentException("movie should be reference");
    ByteBuffer buf = ByteBuffer.allocate(16 * 1024 * 1024);
    FileTypeBox ftyp =
        FileTypeBox.createFileTypeBox("qt  ", 0x20050300, Arrays.asList(new String[] {"qt  "}));
    ftyp.write(buf);
    long movieOff = buf.position();
    movie.write(buf);

    int extraSpace = calcSpaceReq(movie);
    Header.createHeader("free", 8 + extraSpace).write(buf);
    NIOUtils.skip(buf, extraSpace);

    long mdatOff = buf.position();
    Header.createHeader("mdat", 0x100000001L).write(buf);
    buf.flip();
    out.write(buf);

    SeekableByteChannel[][] inputs = getInputs(movie);

    TrakBox[] tracks = movie.getTracks();
    ChunkReader[] readers = new ChunkReader[tracks.length];
    ChunkWriter[] writers = new ChunkWriter[tracks.length];
    Chunk[] head = new Chunk[tracks.length];
    int totalChunks = 0, writtenChunks = 0, lastProgress = 0;
    long[] off = new long[tracks.length];
    for (int i = 0; i < tracks.length; i++) {
      readers[i] = new ChunkReader(tracks[i]);
      totalChunks += readers[i].size();

      writers[i] = new ChunkWriter(tracks[i], inputs[i], out);
      head[i] = readers[i].next();
      if (tracks[i].isVideo()) off[i] = 2 * movie.getTimescale();
    }

    while (true) {
      int min = -1;
      for (int i = 0; i < readers.length; i++) {
        if (head[i] == null) continue;

        if (min == -1) min = i;
        else {
          long iTv = movie.rescale(head[i].getStartTv(), tracks[i].getTimescale()) + off[i];
          long minTv = movie.rescale(head[min].getStartTv(), tracks[min].getTimescale()) + off[min];
          if (iTv < minTv) min = i;
        }
      }
      if (min == -1) break;
      writers[min].write(head[min]);
      head[min] = readers[min].next();
      writtenChunks++;

      lastProgress = calcProgress(totalChunks, writtenChunks, lastProgress);
    }
    long mdatSize = out.position() - mdatOff;

    for (int i = 0; i < tracks.length; i++) {
      writers[i].apply();
    }
    out.setPosition(movieOff);
    MP4Util.writeMovie(out, movie);

    long extra = mdatOff - out.position();
    if (extra < 0) throw new RuntimeException("Not enough space to write the header");
    out.write(
        (ByteBuffer)
            ByteBuffer.allocate(8).putInt((int) extra).put(new byte[] {'f', 'r', 'e', 'e'}).flip());

    out.setPosition(mdatOff + 8);
    out.write(ByteBuffer.allocate(8).putLong(mdatSize));
  }
Пример #9
0
 private void split(List<Edit> edits, double sec, MovieBox movie, TrakBox trakBox) {
   Util.split(movie, trakBox, (long) (sec * movie.getTimescale()));
 }