package org.jcodec.movtool; import static org.jcodec.common.NIOUtils.readableFileChannel; import static org.jcodec.common.NIOUtils.writableFileChannel; import static org.jcodec.containers.mp4.TrackType.VIDEO; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.jcodec.common.NIOUtils; import org.jcodec.common.SeekableByteChannel; import org.jcodec.common.model.Rational; import org.jcodec.containers.mp4.Brand; import org.jcodec.containers.mp4.MP4Packet; import org.jcodec.containers.mp4.WebOptimizedMP4Muxer; import org.jcodec.containers.mp4.boxes.AudioSampleEntry; import org.jcodec.containers.mp4.boxes.Edit; import org.jcodec.containers.mp4.boxes.MovieBox; import org.jcodec.containers.mp4.demuxer.MP4Demuxer; import org.jcodec.containers.mp4.demuxer.AbstractMP4DemuxerTrack; import org.jcodec.containers.mp4.demuxer.TimecodeMP4DemuxerTrack; import org.jcodec.containers.mp4.muxer.AbstractMP4MuxerTrack; import org.jcodec.containers.mp4.muxer.FramesMP4MuxerTrack; import org.jcodec.containers.mp4.muxer.MP4Muxer; import org.jcodec.containers.mp4.muxer.PCMMP4MuxerTrack; /** * This class is part of JCodec ( www.jcodec.org ) This software is distributed * under FreeBSD License * * @author The JCodec project * */ public class Remux { public static void main1(String[] args) throws Exception { if (args.length < 1) { System.out.println("remux <movie>"); return; } File tgt = new File(args[0]); File src = hidFile(tgt); tgt.renameTo(src); try { new Remux().remux(tgt, src, null, null); } catch (Throwable t) { tgt.renameTo(new File(tgt.getParentFile(), tgt.getName() + ".error")); src.renameTo(tgt); } } public interface Handler { public void handle(MovieBox mov) throws IOException; } public void remux(File tgt, File src, File timecode, Handler handler) throws IOException { SeekableByteChannel input = null; SeekableByteChannel output = null; SeekableByteChannel tci = null; try { input = readableFileChannel(src); output = writableFileChannel(tgt); MP4Demuxer demuxer = new MP4Demuxer(input); TimecodeMP4DemuxerTrack tt = null; if (timecode != null) { tci = readableFileChannel(src); MP4Demuxer tcd = new MP4Demuxer(tci); tt = tcd.getTimecodeTrack(); } MP4Muxer muxer = WebOptimizedMP4Muxer.withOldHeader(output, Brand.MOV, demuxer.getMovie()); List<AbstractMP4DemuxerTrack> at = demuxer.getAudioTracks(); List<PCMMP4MuxerTrack> audioTracks = new ArrayList<PCMMP4MuxerTrack>(); for (AbstractMP4DemuxerTrack demuxerTrack : at) { PCMMP4MuxerTrack att = muxer.addPCMAudioTrack(((AudioSampleEntry) demuxerTrack .getSampleEntries()[0]).getFormat()); audioTracks.add(att); att.setEdits(demuxerTrack.getEdits()); att.setName(demuxerTrack.getName()); } AbstractMP4DemuxerTrack vt = demuxer.getVideoTrack(); FramesMP4MuxerTrack video = muxer.addTrack(VIDEO, (int) vt.getTimescale()); // vt.open(input); video.setTimecode(muxer.addTimecodeTrack((int) vt.getTimescale())); copyEdits(vt, video, new Rational((int)vt.getTimescale(), demuxer.getMovie().getTimescale())); video.addSampleEntries(vt.getSampleEntries()); MP4Packet pkt = null; while ((pkt = (MP4Packet)vt.nextFrame()) != null) { if (tt != null) pkt = tt.getTimecode(pkt); pkt = processFrame(pkt); video.addFrame(pkt); for (int i = 0; i < at.size(); i++) { AudioSampleEntry ase = (AudioSampleEntry) at.get(i).getSampleEntries()[0]; int frames = (int) (ase.getSampleRate() * pkt.getDuration() / vt.getTimescale()); MP4Packet apkt = (MP4Packet)at.get(i).nextFrame(); audioTracks.get(i).addSamples(apkt.getData()); } } MovieBox movie = muxer.finalizeHeader(); if (handler != null) handler.handle(movie); muxer.storeHeader(movie); } finally { NIOUtils.closeQuietly(input); NIOUtils.closeQuietly(output); NIOUtils.closeQuietly(tci); } } private void copyEdits(AbstractMP4DemuxerTrack from, AbstractMP4MuxerTrack two, Rational tsRatio) { List<Edit> edits = from.getEdits(), result = new ArrayList<Edit>(); if(edits == null) return; for (Edit edit : edits) { result.add(new Edit(tsRatio.multiply(edit.getDuration()), edit.getMediaTime(), edit.getRate())); } two.setEdits(result); } protected MP4Packet processFrame(MP4Packet pkt) { return pkt; } public static File hidFile(File tgt) { File src = new File(tgt.getParentFile(), "." + tgt.getName()); if (src.exists()) { int i = 1; do { src = new File(tgt.getParentFile(), "." + tgt.getName() + "." + (i++)); } while (src.exists()); } return src; } }