aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/java/de/pixart/messenger/utils/video/MediaController.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/de/pixart/messenger/utils/video/MediaController.java')
-rw-r--r--src/main/java/de/pixart/messenger/utils/video/MediaController.java633
1 files changed, 633 insertions, 0 deletions
diff --git a/src/main/java/de/pixart/messenger/utils/video/MediaController.java b/src/main/java/de/pixart/messenger/utils/video/MediaController.java
new file mode 100644
index 000000000..2f60310a8
--- /dev/null
+++ b/src/main/java/de/pixart/messenger/utils/video/MediaController.java
@@ -0,0 +1,633 @@
+package de.pixart.messenger.utils.video;
+
+import android.annotation.SuppressLint;
+import android.annotation.TargetApi;
+import android.media.MediaCodec;
+import android.media.MediaCodecInfo;
+import android.media.MediaCodecList;
+import android.media.MediaExtractor;
+import android.media.MediaFormat;
+import android.media.MediaMetadataRetriever;
+import android.os.Build;
+import android.util.Log;
+
+import java.io.File;
+import java.nio.ByteBuffer;
+
+import de.pixart.messenger.Config;
+
+@SuppressLint("NewApi")
+public class MediaController {
+
+ public final static String MIME_TYPE = "video/avc";
+ private final static int PROCESSOR_TYPE_OTHER = 0;
+ private final static int PROCESSOR_TYPE_QCOM = 1;
+ private final static int PROCESSOR_TYPE_INTEL = 2;
+ private final static int PROCESSOR_TYPE_MTK = 3;
+ private final static int PROCESSOR_TYPE_SEC = 4;
+ private final static int PROCESSOR_TYPE_TI = 5;
+ private static volatile MediaController Instance = null;
+ private boolean videoConvertFirstWrite = true;
+
+ public static MediaController getInstance() {
+ MediaController localInstance = Instance;
+ if (localInstance == null) {
+ synchronized (MediaController.class) {
+ localInstance = Instance;
+ if (localInstance == null) {
+ Instance = localInstance = new MediaController();
+ }
+ }
+ }
+ return localInstance;
+ }
+
+ @SuppressLint("NewApi")
+ public static int selectColorFormat(MediaCodecInfo codecInfo, String mimeType) {
+ MediaCodecInfo.CodecCapabilities capabilities = codecInfo.getCapabilitiesForType(mimeType);
+ int lastColorFormat = 0;
+ for (int i = 0; i < capabilities.colorFormats.length; i++) {
+ int colorFormat = capabilities.colorFormats[i];
+ if (isRecognizedFormat(colorFormat)) {
+ lastColorFormat = colorFormat;
+ if (!(codecInfo.getName().equals("OMX.SEC.AVC.Encoder") && colorFormat == 19)) {
+ return colorFormat;
+ }
+ }
+ }
+ return lastColorFormat;
+ }
+
+ private static boolean isRecognizedFormat(int colorFormat) {
+ switch (colorFormat) {
+ case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar:
+ case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420PackedPlanar:
+ case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar:
+ case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420PackedSemiPlanar:
+ case MediaCodecInfo.CodecCapabilities.COLOR_TI_FormatYUV420PackedSemiPlanar:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public native static int convertVideoFrame(ByteBuffer src, ByteBuffer dest, int destFormat, int width, int height, int padding, int swap);
+
+ private void didWriteData(final boolean last, final boolean error) {
+ final boolean firstWrite = videoConvertFirstWrite;
+ if (firstWrite) {
+ videoConvertFirstWrite = false;
+ }
+ }
+
+ public static MediaCodecInfo selectCodec(String mimeType) {
+ int numCodecs = MediaCodecList.getCodecCount();
+ MediaCodecInfo lastCodecInfo = null;
+ for (int i = 0; i < numCodecs; i++) {
+ MediaCodecInfo codecInfo = MediaCodecList.getCodecInfoAt(i);
+ if (!codecInfo.isEncoder()) {
+ continue;
+ }
+ String[] types = codecInfo.getSupportedTypes();
+ for (String type : types) {
+ if (type.equalsIgnoreCase(mimeType)) {
+ lastCodecInfo = codecInfo;
+ if (!lastCodecInfo.getName().equals("OMX.SEC.avc.enc")) {
+ return lastCodecInfo;
+ } else if (lastCodecInfo.getName().equals("OMX.SEC.AVC.Encoder")) {
+ return lastCodecInfo;
+ }
+ }
+ }
+ }
+ return lastCodecInfo;
+ }
+
+ @TargetApi(16)
+ private long readAndWriteTrack(MediaExtractor extractor, MP4Builder mediaMuxer, MediaCodec.BufferInfo info, long start, long end, File file, boolean isAudio) throws Exception {
+ int trackIndex = selectTrack(extractor, isAudio);
+ if (trackIndex >= 0) {
+ extractor.selectTrack(trackIndex);
+ MediaFormat trackFormat = extractor.getTrackFormat(trackIndex);
+ int muxerTrackIndex = mediaMuxer.addTrack(trackFormat, isAudio);
+ int maxBufferSize = trackFormat.getInteger(MediaFormat.KEY_MAX_INPUT_SIZE);
+ boolean inputDone = false;
+ if (start > 0) {
+ extractor.seekTo(start, MediaExtractor.SEEK_TO_PREVIOUS_SYNC);
+ } else {
+ extractor.seekTo(0, MediaExtractor.SEEK_TO_PREVIOUS_SYNC);
+ }
+ ByteBuffer buffer = ByteBuffer.allocateDirect(maxBufferSize);
+ long startTime = -1;
+
+ while (!inputDone) {
+
+ boolean eof = false;
+ int index = extractor.getSampleTrackIndex();
+ if (index == trackIndex) {
+ info.size = extractor.readSampleData(buffer, 0);
+
+ if (info.size < 0) {
+ info.size = 0;
+ eof = true;
+ } else {
+ info.presentationTimeUs = extractor.getSampleTime();
+ if (start > 0 && startTime == -1) {
+ startTime = info.presentationTimeUs;
+ }
+ if (end < 0 || info.presentationTimeUs < end) {
+ info.offset = 0;
+ info.flags = extractor.getSampleFlags();
+ if (mediaMuxer.writeSampleData(muxerTrackIndex, buffer, info, isAudio)) {
+ // didWriteData(messageObject, file, false, false);
+ }
+ extractor.advance();
+ } else {
+ eof = true;
+ }
+ }
+ } else if (index == -1) {
+ eof = true;
+ }
+ if (eof) {
+ inputDone = true;
+ }
+ }
+
+ extractor.unselectTrack(trackIndex);
+ return startTime;
+ }
+ return -1;
+ }
+
+ @TargetApi(16)
+ private int selectTrack(MediaExtractor extractor, boolean audio) {
+ int numTracks = extractor.getTrackCount();
+ for (int i = 0; i < numTracks; i++) {
+ MediaFormat format = extractor.getTrackFormat(i);
+ String mime = format.getString(MediaFormat.KEY_MIME);
+ if (audio) {
+ if (mime.startsWith("audio/")) {
+ return i;
+ }
+ } else {
+ if (mime.startsWith("video/")) {
+ return i;
+ }
+ }
+ }
+ return -5;
+ }
+
+ @TargetApi(16)
+ public boolean convertVideo(final String path, final String compressed_path) {
+
+ MediaMetadataRetriever retriever = new MediaMetadataRetriever();
+ retriever.setDataSource(path);
+ String height = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT);
+ String width = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH);
+ String rotation = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION);
+
+ int video_height = Integer.parseInt(height);
+ int video_width = Integer.parseInt(width);
+
+ Log.d(Config.LOGTAG, "Video dimensions: height: " + height + " width: " + width + "rotation: " + rotation);
+
+ long startTime = -1;
+ long endTime = -1;
+
+ int resultWidth = 640;
+ int resultHeight = 360;
+
+ int rotationValue = Integer.valueOf(rotation);
+ int originalWidth = Integer.valueOf(width);
+ int originalHeight = Integer.valueOf(height);
+ double ratio = video_width/video_height;
+
+ int bitrate = 50000; //450000
+ int rotateRender = 0;
+
+ File cacheFile = new File(compressed_path);
+
+ if (Build.VERSION.SDK_INT < 18 && resultHeight > resultWidth && resultWidth != originalWidth && resultHeight != originalHeight) {
+ int temp = resultHeight;
+ resultHeight = resultWidth;
+ resultWidth = temp;
+ rotationValue = 90;
+ rotateRender = 270;
+ } else if (Build.VERSION.SDK_INT > 20) {
+ if (rotationValue == 90) {
+ int temp = resultHeight;
+ resultHeight = resultWidth;
+ resultWidth = temp;
+ rotationValue = 0;
+ rotateRender = 270;
+ } else if (rotationValue == 180) {
+ rotateRender = 180;
+ rotationValue = 0;
+ } else if (rotationValue == 270) {
+ int temp = resultHeight;
+ resultHeight = resultWidth;
+ resultWidth = temp;
+ rotationValue = 0;
+ rotateRender = 90;
+ }
+ }
+
+
+ File inputFile = new File(path);
+ Log.d(Config.LOGTAG, "Input file is: " + inputFile.toString());
+ if (!inputFile.canRead()) {
+ didWriteData(true, true);
+ Log.d(Config.LOGTAG, "Compression failed. Input file could not be read.");
+ return false;
+ }
+
+ videoConvertFirstWrite = true;
+ boolean error = false;
+ long videoStartTime = startTime;
+
+ long time = System.currentTimeMillis();
+
+ if (resultWidth != 0 && resultHeight != 0) {
+ MP4Builder mediaMuxer = null;
+ MediaExtractor extractor = null;
+
+ try {
+ MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
+ Mp4Movie movie = new Mp4Movie();
+ movie.setCacheFile(cacheFile);
+ movie.setRotation(rotationValue);
+ movie.setSize(resultWidth, resultHeight);
+ mediaMuxer = new MP4Builder().createMovie(movie);
+ extractor = new MediaExtractor();
+ extractor.setDataSource(inputFile.toString());
+
+
+ if (resultWidth != originalWidth || resultHeight != originalHeight) {
+ int videoIndex;
+ videoIndex = selectTrack(extractor, false);
+
+ if (videoIndex >= 0) {
+ MediaCodec decoder = null;
+ MediaCodec encoder = null;
+ InputSurface inputSurface = null;
+ OutputSurface outputSurface = null;
+
+ try {
+ long videoTime = -1;
+ boolean outputDone = false;
+ boolean inputDone = false;
+ boolean decoderDone = false;
+ int swapUV = 0;
+ int videoTrackIndex = -5;
+
+ int colorFormat;
+ int processorType = PROCESSOR_TYPE_OTHER;
+ String manufacturer = Build.MANUFACTURER.toLowerCase();
+ if (Build.VERSION.SDK_INT < 18) {
+ MediaCodecInfo codecInfo = selectCodec(MIME_TYPE);
+ colorFormat = selectColorFormat(codecInfo, MIME_TYPE);
+ if (colorFormat == 0) {
+ throw new RuntimeException("no supported color format");
+ }
+ String codecName = codecInfo.getName();
+ if (codecName.contains("OMX.qcom.")) {
+ processorType = PROCESSOR_TYPE_QCOM;
+ if (Build.VERSION.SDK_INT == 16) {
+ if (manufacturer.equals("lge") || manufacturer.equals("nokia")) {
+ swapUV = 1;
+ }
+ }
+ } else if (codecName.contains("OMX.Intel.")) {
+ processorType = PROCESSOR_TYPE_INTEL;
+ } else if (codecName.equals("OMX.MTK.VIDEO.ENCODER.AVC")) {
+ processorType = PROCESSOR_TYPE_MTK;
+ } else if (codecName.equals("OMX.SEC.AVC.Encoder")) {
+ processorType = PROCESSOR_TYPE_SEC;
+ swapUV = 1;
+ } else if (codecName.equals("OMX.TI.DUCATI1.VIDEO.H264E")) {
+ processorType = PROCESSOR_TYPE_TI;
+ }
+ Log.d(Config.LOGTAG, "codec = " + codecInfo.getName() + " manufacturer = " + manufacturer + "device = " + Build.MODEL);
+ } else {
+ colorFormat = MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface;
+ }
+ Log.d(Config.LOGTAG, "colorFormat = " + colorFormat);
+
+ int resultHeightAligned = resultHeight;
+ int padding = 0;
+ int bufferSize = resultWidth * resultHeight * 3 / 2;
+ if (processorType == PROCESSOR_TYPE_OTHER) {
+ if (resultHeight % 16 != 0) {
+ resultHeightAligned += (16 - (resultHeight % 16));
+ padding = resultWidth * (resultHeightAligned - resultHeight);
+ bufferSize += padding * 5 / 4;
+ }
+ } else if (processorType == PROCESSOR_TYPE_QCOM) {
+ if (!manufacturer.toLowerCase().equals("lge")) {
+ int uvoffset = (resultWidth * resultHeight + 2047) & ~2047;
+ padding = uvoffset - (resultWidth * resultHeight);
+ bufferSize += padding;
+ }
+ } else if (processorType == PROCESSOR_TYPE_TI) {
+ resultHeightAligned = 368;
+ bufferSize = resultWidth * resultHeightAligned * 3 / 2;
+ resultHeightAligned += (16 - (resultHeight % 16));
+ padding = resultWidth * (resultHeightAligned - resultHeight);
+ bufferSize += padding * 5 / 4;
+ } else if (processorType == PROCESSOR_TYPE_MTK) {
+ if (manufacturer.equals("baidu")) {
+ resultHeightAligned += (16 - (resultHeight % 16));
+ padding = resultWidth * (resultHeightAligned - resultHeight);
+ bufferSize += padding * 5 / 4;
+ }
+ }
+
+ extractor.selectTrack(videoIndex);
+ if (startTime > 0) {
+ extractor.seekTo(startTime, MediaExtractor.SEEK_TO_PREVIOUS_SYNC);
+ } else {
+ extractor.seekTo(0, MediaExtractor.SEEK_TO_PREVIOUS_SYNC);
+ }
+ MediaFormat inputFormat = extractor.getTrackFormat(videoIndex);
+
+ MediaFormat outputFormat = MediaFormat.createVideoFormat(MIME_TYPE, resultWidth, resultHeight);
+ outputFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, colorFormat);
+ outputFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitrate != 0 ? bitrate : 921600);
+ outputFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 25);
+ outputFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 10);
+ if (Build.VERSION.SDK_INT < 18) {
+ outputFormat.setInteger("stride", resultWidth + 32);
+ outputFormat.setInteger("slice-height", resultHeight);
+ }
+
+ encoder = MediaCodec.createEncoderByType(MIME_TYPE);
+ encoder.configure(outputFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
+ if (Build.VERSION.SDK_INT >= 18) {
+ inputSurface = new InputSurface(encoder.createInputSurface());
+ inputSurface.makeCurrent();
+ }
+ encoder.start();
+
+ decoder = MediaCodec.createDecoderByType(inputFormat.getString(MediaFormat.KEY_MIME));
+ if (Build.VERSION.SDK_INT >= 18) {
+ outputSurface = new OutputSurface();
+ } else {
+ outputSurface = new OutputSurface(resultWidth, resultHeight, rotateRender);
+ }
+ decoder.configure(inputFormat, outputSurface.getSurface(), null, 0);
+ decoder.start();
+
+ final int TIMEOUT_USEC = 2500;
+ ByteBuffer[] decoderInputBuffers = null;
+ ByteBuffer[] encoderOutputBuffers = null;
+ ByteBuffer[] encoderInputBuffers = null;
+ if (Build.VERSION.SDK_INT < 21) {
+ decoderInputBuffers = decoder.getInputBuffers();
+ encoderOutputBuffers = encoder.getOutputBuffers();
+ if (Build.VERSION.SDK_INT < 18) {
+ encoderInputBuffers = encoder.getInputBuffers();
+ }
+ }
+
+ while (!outputDone) {
+ if (!inputDone) {
+ boolean eof = false;
+ int index = extractor.getSampleTrackIndex();
+ if (index == videoIndex) {
+ int inputBufIndex = decoder.dequeueInputBuffer(TIMEOUT_USEC);
+ if (inputBufIndex >= 0) {
+ ByteBuffer inputBuf;
+ if (Build.VERSION.SDK_INT < 21) {
+ inputBuf = decoderInputBuffers[inputBufIndex];
+ } else {
+ inputBuf = decoder.getInputBuffer(inputBufIndex);
+ }
+ int chunkSize = extractor.readSampleData(inputBuf, 0);
+ if (chunkSize < 0) {
+ decoder.queueInputBuffer(inputBufIndex, 0, 0, 0L, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
+ inputDone = true;
+ } else {
+ decoder.queueInputBuffer(inputBufIndex, 0, chunkSize, extractor.getSampleTime(), 0);
+ extractor.advance();
+ }
+ }
+ } else if (index == -1) {
+ eof = true;
+ }
+ if (eof) {
+ int inputBufIndex = decoder.dequeueInputBuffer(TIMEOUT_USEC);
+ if (inputBufIndex >= 0) {
+ decoder.queueInputBuffer(inputBufIndex, 0, 0, 0L, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
+ inputDone = true;
+ }
+ }
+ }
+
+ boolean decoderOutputAvailable = !decoderDone;
+ boolean encoderOutputAvailable = true;
+ while (decoderOutputAvailable || encoderOutputAvailable) {
+ int encoderStatus = encoder.dequeueOutputBuffer(info, TIMEOUT_USEC);
+ if (encoderStatus == MediaCodec.INFO_TRY_AGAIN_LATER) {
+ encoderOutputAvailable = false;
+ } else if (encoderStatus == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
+ if (Build.VERSION.SDK_INT < 21) {
+ encoderOutputBuffers = encoder.getOutputBuffers();
+ }
+ } else if (encoderStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
+ MediaFormat newFormat = encoder.getOutputFormat();
+ if (videoTrackIndex == -5) {
+ videoTrackIndex = mediaMuxer.addTrack(newFormat, false);
+ }
+ } else if (encoderStatus < 0) {
+ throw new RuntimeException("unexpected result from encoder.dequeueOutputBuffer: " + encoderStatus);
+ } else {
+ ByteBuffer encodedData;
+ if (Build.VERSION.SDK_INT < 21) {
+ encodedData = encoderOutputBuffers[encoderStatus];
+ } else {
+ encodedData = encoder.getOutputBuffer(encoderStatus);
+ }
+ if (encodedData == null) {
+ throw new RuntimeException("encoderOutputBuffer " + encoderStatus + " was null");
+ }
+ if (info.size > 1) {
+ if ((info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == 0) {
+ if (mediaMuxer.writeSampleData(videoTrackIndex, encodedData, info, false)) {
+ didWriteData(false, false);
+ }
+ } else if (videoTrackIndex == -5) {
+ byte[] csd = new byte[info.size];
+ encodedData.limit(info.offset + info.size);
+ encodedData.position(info.offset);
+ encodedData.get(csd);
+ ByteBuffer sps = null;
+ ByteBuffer pps = null;
+ for (int a = info.size - 1; a >= 0; a--) {
+ if (a > 3) {
+ if (csd[a] == 1 && csd[a - 1] == 0 && csd[a - 2] == 0 && csd[a - 3] == 0) {
+ sps = ByteBuffer.allocate(a - 3);
+ pps = ByteBuffer.allocate(info.size - (a - 3));
+ sps.put(csd, 0, a - 3).position(0);
+ pps.put(csd, a - 3, info.size - (a - 3)).position(0);
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+
+ MediaFormat newFormat = MediaFormat.createVideoFormat(MIME_TYPE, resultWidth, resultHeight);
+ if (sps != null && pps != null) {
+ newFormat.setByteBuffer("csd-0", sps);
+ newFormat.setByteBuffer("csd-1", pps);
+ }
+ videoTrackIndex = mediaMuxer.addTrack(newFormat, false);
+ }
+ }
+ outputDone = (info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0;
+ encoder.releaseOutputBuffer(encoderStatus, false);
+ }
+ if (encoderStatus != MediaCodec.INFO_TRY_AGAIN_LATER) {
+ continue;
+ }
+
+ if (!decoderDone) {
+ int decoderStatus = decoder.dequeueOutputBuffer(info, TIMEOUT_USEC);
+ if (decoderStatus == MediaCodec.INFO_TRY_AGAIN_LATER) {
+ decoderOutputAvailable = false;
+ } else if (decoderStatus == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
+
+ } else if (decoderStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
+ MediaFormat newFormat = decoder.getOutputFormat();
+ Log.d(Config.LOGTAG, "newFormat = " + newFormat);
+ } else if (decoderStatus < 0) {
+ throw new RuntimeException("unexpected result from decoder.dequeueOutputBuffer: " + decoderStatus);
+ } else {
+ boolean doRender;
+ if (Build.VERSION.SDK_INT >= 18) {
+ doRender = info.size != 0;
+ } else {
+ doRender = info.size != 0 || info.presentationTimeUs != 0;
+ }
+ if (endTime > 0 && info.presentationTimeUs >= endTime) {
+ inputDone = true;
+ decoderDone = true;
+ doRender = false;
+ info.flags |= MediaCodec.BUFFER_FLAG_END_OF_STREAM;
+ }
+ if (startTime > 0 && videoTime == -1) {
+ if (info.presentationTimeUs < startTime) {
+ doRender = false;
+ Log.d(Config.LOGTAG, "drop frame startTime = " + startTime + " present time = " + info.presentationTimeUs);
+ } else {
+ videoTime = info.presentationTimeUs;
+ }
+ }
+ decoder.releaseOutputBuffer(decoderStatus, doRender);
+ if (doRender) {
+ boolean errorWait = false;
+ try {
+ outputSurface.awaitNewImage();
+ } catch (Exception e) {
+ errorWait = true;
+ Log.d(Config.LOGTAG, e.getMessage());
+ }
+ if (!errorWait) {
+ if (Build.VERSION.SDK_INT >= 18) {
+ outputSurface.drawImage(false);
+ inputSurface.setPresentationTime(info.presentationTimeUs * 1000);
+ inputSurface.swapBuffers();
+ } else {
+ int inputBufIndex = encoder.dequeueInputBuffer(TIMEOUT_USEC);
+ if (inputBufIndex >= 0) {
+ outputSurface.drawImage(true);
+ ByteBuffer rgbBuf = outputSurface.getFrame();
+ ByteBuffer yuvBuf = encoderInputBuffers[inputBufIndex];
+ yuvBuf.clear();
+ convertVideoFrame(rgbBuf, yuvBuf, colorFormat, resultWidth, resultHeight, padding, swapUV);
+ encoder.queueInputBuffer(inputBufIndex, 0, bufferSize, info.presentationTimeUs, 0);
+ } else {
+ Log.d(Config.LOGTAG, "input buffer not available");
+ }
+ }
+ }
+ }
+ if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
+ decoderOutputAvailable = false;
+ Log.d(Config.LOGTAG, "decoder stream end");
+ if (Build.VERSION.SDK_INT >= 18) {
+ encoder.signalEndOfInputStream();
+ } else {
+ int inputBufIndex = encoder.dequeueInputBuffer(TIMEOUT_USEC);
+ if (inputBufIndex >= 0) {
+ encoder.queueInputBuffer(inputBufIndex, 0, 1, info.presentationTimeUs, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ if (videoTime != -1) {
+ videoStartTime = videoTime;
+ }
+ } catch (Exception e) {
+ Log.d(Config.LOGTAG, e.getMessage());
+ error = true;
+ }
+
+ extractor.unselectTrack(videoIndex);
+
+ if (outputSurface != null) {
+ outputSurface.release();
+ }
+ if (inputSurface != null) {
+ inputSurface.release();
+ }
+ if (decoder != null) {
+ decoder.stop();
+ decoder.release();
+ }
+ if (encoder != null) {
+ encoder.stop();
+ encoder.release();
+ }
+ }
+ } else {
+ long videoTime = readAndWriteTrack(extractor, mediaMuxer, info, startTime, endTime, cacheFile, false);
+ if (videoTime != -1) {
+ videoStartTime = videoTime;
+ }
+ }
+ if (!error) {
+ readAndWriteTrack(extractor, mediaMuxer, info, videoStartTime, endTime, cacheFile, true);
+ }
+ } catch (Exception e) {
+ error = true;
+ Log.d(Config.LOGTAG, e.getMessage());
+ } finally {
+ if (extractor != null) {
+ extractor.release();
+ }
+ if (mediaMuxer != null) {
+ try {
+ mediaMuxer.finishMovie(false);
+ } catch (Exception e) {
+ Log.d(Config.LOGTAG, e.getMessage());
+ }
+ }
+ Log.d(Config.LOGTAG, "time = " + (System.currentTimeMillis() - time));
+ }
+ } else {
+ didWriteData(true, true);
+ Log.d(Config.LOGTAG, "Compression failed.");
+ return false;
+ }
+ didWriteData(true, error);
+ Log.d(Config.LOGTAG, "Compression succeed. Save compressed video to " + cacheFile.toString());
+ //inputFile.delete();
+ return true;
+ }
+} \ No newline at end of file