summaryrefslogtreecommitdiffstats
path: root/src/com/android/gallery3d/app/ShortenExample.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/gallery3d/app/ShortenExample.java')
-rw-r--r--src/com/android/gallery3d/app/ShortenExample.java156
1 files changed, 156 insertions, 0 deletions
diff --git a/src/com/android/gallery3d/app/ShortenExample.java b/src/com/android/gallery3d/app/ShortenExample.java
new file mode 100644
index 000000000..0ac78d935
--- /dev/null
+++ b/src/com/android/gallery3d/app/ShortenExample.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Modified example based on mp4parser google code open source project.
+// http://code.google.com/p/mp4parser/source/browse/trunk/examples/src/main/java/com/googlecode/mp4parser/ShortenExample.java
+
+package com.android.gallery3d.app;
+
+import com.coremedia.iso.IsoFile;
+import com.coremedia.iso.boxes.TimeToSampleBox;
+import com.googlecode.mp4parser.authoring.Movie;
+import com.googlecode.mp4parser.authoring.Track;
+import com.googlecode.mp4parser.authoring.builder.DefaultMp4Builder;
+import com.googlecode.mp4parser.authoring.container.mp4.MovieCreator;
+import com.googlecode.mp4parser.authoring.tracks.CroppedTrack;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.channels.FileChannel;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Shortens/Crops a track
+ */
+public class ShortenExample {
+
+ public static void main(String[] args, File src, File dst, int startMs, int endMs) throws IOException {
+ RandomAccessFile randomAccessFile = new RandomAccessFile(src, "r");
+ Movie movie = MovieCreator.build(randomAccessFile.getChannel());
+
+ // remove all tracks we will create new tracks from the old
+ List<Track> tracks = movie.getTracks();
+ movie.setTracks(new LinkedList<Track>());
+
+ double startTime = startMs/1000;
+ double endTime = endMs/1000;
+
+ boolean timeCorrected = false;
+
+ // 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 new fragment is exactly
+ // such a frame
+ for (Track track : tracks) {
+ if (track.getSyncSamples() != null && track.getSyncSamples().length > 0) {
+ if (timeCorrected) {
+ // This exception here could be a false positive in case we have multiple tracks
+ // with sync samples at exactly the same positions. E.g. a single movie containing
+ // multiple qualities of the same video (Microsoft Smooth Streaming file)
+
+ throw new RuntimeException("The startTime has already been corrected by another track with SyncSample. Not Supported.");
+ }
+ startTime = correctTimeToSyncSample(track, startTime, false);
+ endTime = correctTimeToSyncSample(track, endTime, true);
+ timeCorrected = true;
+ }
+ }
+
+ for (Track track : tracks) {
+ long currentSample = 0;
+ double currentTime = 0;
+ long startSample = -1;
+ long endSample = -1;
+
+ for (int i = 0; i < track.getDecodingTimeEntries().size(); i++) {
+ TimeToSampleBox.Entry entry = track.getDecodingTimeEntries().get(i);
+ for (int j = 0; j < entry.getCount(); j++) {
+ // entry.getDelta() is the amount of time the current sample covers.
+
+ if (currentTime <= startTime) {
+ // current sample is still before the new starttime
+ startSample = currentSample;
+ }
+ if (currentTime <= endTime) {
+ // current sample is after the new start time and still before the new endtime
+ endSample = currentSample;
+ } else {
+ // current sample is after the end of the cropped video
+ break;
+ }
+ currentTime += (double) entry.getDelta() / (double) track.getTrackMetaData().getTimescale();
+ currentSample++;
+ }
+ }
+ movie.addTrack(new CroppedTrack(track, startSample, endSample));
+ }
+ IsoFile out = new DefaultMp4Builder().build(movie);
+
+ if (!dst.exists()) {
+ dst.createNewFile();
+ }
+
+ FileOutputStream fos = new FileOutputStream(dst);
+ FileChannel fc = fos.getChannel();
+ out.getBox(fc); // This one build up the memory.
+
+ fc.close();
+ fos.close();
+ randomAccessFile.close();
+ }
+
+ protected static long getDuration(Track track) {
+ long duration = 0;
+ for (TimeToSampleBox.Entry entry : track.getDecodingTimeEntries()) {
+ duration += entry.getCount() * entry.getDelta();
+ }
+ return duration;
+ }
+
+ private static double correctTimeToSyncSample(Track track, double cutHere, boolean next) {
+ 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 > cutHere) {
+ if (next) {
+ return timeOfSyncSample;
+ } else {
+ return previous;
+ }
+ }
+ previous = timeOfSyncSample;
+ }
+ return timeOfSyncSamples[timeOfSyncSamples.length - 1];
+ }
+
+
+}