protected static long getDuration(Track track) { long duration = 0; for (TimeToSampleBox.Entry entry : track.getDecodingTimeEntries()) { duration += entry.getCount() * entry.getDelta(); } return duration; }
/** * we try to get the nearest synchronized sample to our desired start time. Afterwards, we are * ready to crop each track of the video. */ private double correctTimeToNextSyncSample(Track track, double cropVidPlace, boolean nextPlace) { double[] timeOfSyncSamples = new double[track.getSyncSamples().length]; long currentSample = 0; double currentTime = 0; for (int i = 0; i < track.getDecodingTimeEntries().size(); i++) { TimeToSampleBox.Entry entry = track.getDecodingTimeEntries().get(i); for (int j = 0; j < entry.getCount(); j++) { if (Arrays.binarySearch(track.getSyncSamples(), currentSample + 1) >= 0) { // samples always start with 1 but we start with zero therefore +1 timeOfSyncSamples[Arrays.binarySearch(track.getSyncSamples(), currentSample + 1)] = currentTime; } currentTime += (double) entry.getDelta() / (double) track.getTrackMetaData().getTimescale(); currentSample++; } } double previous = 0; for (double timeOfSyncSample : timeOfSyncSamples) { if (timeOfSyncSample > cropVidPlace) { if (nextPlace) { return timeOfSyncSample; } else { return previous; } } previous = timeOfSyncSample; } return timeOfSyncSamples[timeOfSyncSamples.length - 1]; }
private static long[] getTimes(Movie m, Track track) { long[] syncSamples = track.getSyncSamples(); long[] syncSampleTimes = new long[syncSamples.length]; Queue<TimeToSampleBox.Entry> timeQueue = new LinkedList<TimeToSampleBox.Entry>(track.getDecodingTimeEntries()); int currentSample = 1; // first syncsample is 1 long currentDuration = 0; long currentDelta = 0; int currentSyncSampleIndex = 0; long left = 0; long timeScale = 1; for (Track track1 : m.getTracks()) { if (track1.getHandler().equals(track.getHandler())) { if (track1.getTrackMetaData().getTimescale() != track.getTrackMetaData().getTimescale()) { timeScale = lcm(timeScale, track1.getTrackMetaData().getTimescale()); } } } while (currentSample <= syncSamples[syncSamples.length - 1]) { if (currentSample++ == syncSamples[currentSyncSampleIndex]) { syncSampleTimes[currentSyncSampleIndex++] = currentDuration * timeScale; } if (left-- == 0) { TimeToSampleBox.Entry entry = timeQueue.poll(); left = entry.getCount() - 1; currentDelta = entry.getDelta(); } currentDuration += currentDelta; } return syncSampleTimes; }
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); }
/** * all the trimming happens in this method. * * <p>STEP A ==>> For each track in the video, we first get the start time for all the tracks. * * <p>STEP B ==>> For each track in the video, we crop the tracks with a 'start time' and 'end * time' and add it to the Movie object. * * <p>STEP C ==>> Finally write the newly created movie to the disk. */ private String cropSelectedVideo() { FileInputStream fileInputStream = null; FileChannel fileChannel = null; try { File videoFile = new File(mFullPathToVideoFile); fileInputStream = new FileInputStream(videoFile); fileChannel = fileInputStream.getChannel(); Movie movie = MovieCreator.build(fileChannel); if (movie == null) { return null; } else { List<Track> tracks = movie.getTracks(); movie.setTracks(new LinkedList<Track>()); boolean timeCorrected = false; if ((tracks == null) && (tracks.size() <= 0)) { return null; } else { /** * here we try to find a track that has sync samples. Since we can only start decoding at * such a sample we should make sure that the start of the fragment is exactly the such a * frame. */ for (Track track : tracks) { if (track.getSyncSamples() != null && track.getSyncSamples().length > 0) { if (timeCorrected) { /** * This exception here can be false position in case we have multiple tracks with * sync sample at exactly the same position. E.g. a single movie containing multiple * qualities of the same video. */ } else { mStartTime = correctTimeToNextSyncSample(track, mStartTime, false); mEndTime = correctTimeToNextSyncSample(track, mEndTime, true); timeCorrected = true; } } } for (Track track : tracks) { long currentVidSample = 0; double currentTime = 0; long startVidSample = -1; long endVidSample = -1; for (int i = 0; i < track.getDecodingTimeEntries().size(); i++) { TimeToSampleBox.Entry myEntry = track.getDecodingTimeEntries().get(i); for (int j = 0; j < myEntry.getCount(); j++) { // I am trying to find the start time and end time when the trimmimg occurs if (currentTime <= mStartTime) { // our current video sample is before the starting time for the crop // if the startVidSample is equal to the length of the video, // an error happened, and we should throw an exception startVidSample = currentVidSample; // the new begining of the video will be set to this place // of the video } else if (currentTime <= mEndTime) { // our current video sample is after the starting time for the crop // but before the end time of the crop endVidSample = currentVidSample; // the new end of the video will be set to this place of the // video } else { // our current video sample is after the end time of the cropping // we just stop this this loop break; } // getDelta() : the amount of time the current video sample covers currentTime += (double) myEntry.getDelta() / (double) track.getTrackMetaData().getTimescale(); currentVidSample++; } } movie.addTrack(new CroppedTrack(track, startVidSample, endVidSample)); } } } IsoFile isoFile = new DefaultMp4Builder().build(movie); /** STEP C ==>> After we created the Movie, we have to place it into a nonvolatile memory. */ return Util.placeFileInNonVolatileDrive(isoFile, mVideFolderPath, "trim_output"); } catch (Exception e) { Log.e(TAG, "IO ERROR: " + e); } finally { if (fileInputStream != null) { try { fileInputStream.close(); } catch (IOException e) { Log.e(TAG, "IO ERROR: " + e); } } if (fileChannel != null) { try { fileChannel.close(); } catch (IOException e) { Log.e(TAG, "IO ERROR: " + e); } } } return null; }