168ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui/* 268ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui * Copyright (C) 2013 The Android Open Source Project 368ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui * 468ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui * Licensed under the Apache License, Version 2.0 (the "License"); 568ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui * you may not use this file except in compliance with the License. 668ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui * You may obtain a copy of the License at 768ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui * 868ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui * http://www.apache.org/licenses/LICENSE-2.0 968ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui * 1068ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui * Unless required by applicable law or agreed to in writing, software 1168ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui * distributed under the License is distributed on an "AS IS" BASIS, 1268ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1368ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui * See the License for the specific language governing permissions and 1468ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui * limitations under the License. 1568ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui */ 1668ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui 1768ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghuipackage android.media; 1868ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui 1999f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnarimport android.annotation.IntDef; 2099f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnarimport android.annotation.NonNull; 2199f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnarimport android.annotation.Nullable; 2299f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnarimport android.media.MediaCodec; 2368ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghuiimport android.media.MediaCodec.BufferInfo; 2468ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghuiimport dalvik.system.CloseGuard; 2568ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui 2668ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghuiimport java.io.FileDescriptor; 2768ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghuiimport java.io.IOException; 281797dc93fb203762eecbc9c026b77263e4e4a4f5Robert Shihimport java.io.RandomAccessFile; 2999f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnarimport java.lang.annotation.Retention; 3099f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnarimport java.lang.annotation.RetentionPolicy; 3168ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghuiimport java.nio.ByteBuffer; 3268ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghuiimport java.util.Map; 3368ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui 3468ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui/** 3589de5eb3461ab031be175ee751522c20f29806e0Hangyu Kuang * MediaMuxer facilitates muxing elementary streams. Currently supports mp4 or 3689de5eb3461ab031be175ee751522c20f29806e0Hangyu Kuang * webm file as the output and at most one audio and/or one video elementary 37d853da5425f616b96aa8f8106a802afd5bbae47aHangyu Kuang * stream. MediaMuxer does not support muxing B-frames. 3868ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui * <p> 3968ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui * It is generally used like this: 4068ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui * 4168ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui * <pre> 4234a5b011cd3fe3b231770a3bae984175d2c983e2ztenghui * MediaMuxer muxer = new MediaMuxer("temp.mp4", OutputFormat.MUXER_OUTPUT_MPEG_4); 4334a5b011cd3fe3b231770a3bae984175d2c983e2ztenghui * // More often, the MediaFormat will be retrieved from MediaCodec.getOutputFormat() 4434a5b011cd3fe3b231770a3bae984175d2c983e2ztenghui * // or MediaExtractor.getTrackFormat(). 4568ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui * MediaFormat audioFormat = new MediaFormat(...); 4668ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui * MediaFormat videoFormat = new MediaFormat(...); 4768ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui * int audioTrackIndex = muxer.addTrack(audioFormat); 4868ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui * int videoTrackIndex = muxer.addTrack(videoFormat); 4934a5b011cd3fe3b231770a3bae984175d2c983e2ztenghui * ByteBuffer inputBuffer = ByteBuffer.allocate(bufferSize); 5034a5b011cd3fe3b231770a3bae984175d2c983e2ztenghui * boolean finished = false; 5134a5b011cd3fe3b231770a3bae984175d2c983e2ztenghui * BufferInfo bufferInfo = new BufferInfo(); 5234a5b011cd3fe3b231770a3bae984175d2c983e2ztenghui * 5368ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui * muxer.start(); 5434a5b011cd3fe3b231770a3bae984175d2c983e2ztenghui * while(!finished) { 5534a5b011cd3fe3b231770a3bae984175d2c983e2ztenghui * // getInputBuffer() will fill the inputBuffer with one frame of encoded 5634a5b011cd3fe3b231770a3bae984175d2c983e2ztenghui * // sample from either MediaCodec or MediaExtractor, set isAudioSample to 5734a5b011cd3fe3b231770a3bae984175d2c983e2ztenghui * // true when the sample is audio data, set up all the fields of bufferInfo, 5834a5b011cd3fe3b231770a3bae984175d2c983e2ztenghui * // and return true if there are no more samples. 5934a5b011cd3fe3b231770a3bae984175d2c983e2ztenghui * finished = getInputBuffer(inputBuffer, isAudioSample, bufferInfo); 6034a5b011cd3fe3b231770a3bae984175d2c983e2ztenghui * if (!finished) { 6134a5b011cd3fe3b231770a3bae984175d2c983e2ztenghui * int currentTrackIndex = isAudioSample ? audioTrackIndex : videoTrackIndex; 6234a5b011cd3fe3b231770a3bae984175d2c983e2ztenghui * muxer.writeSampleData(currentTrackIndex, inputBuffer, bufferInfo); 6368ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui * } 6434a5b011cd3fe3b231770a3bae984175d2c983e2ztenghui * }; 6568ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui * muxer.stop(); 6668ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui * muxer.release(); 6768ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui * </pre> 6868ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui */ 6968ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui 7068ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghuifinal public class MediaMuxer { 7168ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui 7268ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui static { 7368ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui System.loadLibrary("media_jni"); 7468ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui } 7568ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui 7668ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui /** 7768ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui * Defines the output format. These constants are used with constructor. 7868ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui */ 7968ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui public static final class OutputFormat { 8068ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui /* Do not change these values without updating their counterparts 8168ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui * in include/media/stagefright/MediaMuxer.h! 8268ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui */ 8368ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui private OutputFormat() {} 8468ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui /** MPEG4 media file format*/ 8568ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui public static final int MUXER_OUTPUT_MPEG_4 = 0; 861797dc93fb203762eecbc9c026b77263e4e4a4f5Robert Shih public static final int MUXER_OUTPUT_WEBM = 1; 8768ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui }; 8868ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui 8999f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnar /** @hide */ 9099f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnar @IntDef({ 9199f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnar OutputFormat.MUXER_OUTPUT_MPEG_4, 9299f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnar OutputFormat.MUXER_OUTPUT_WEBM, 9399f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnar }) 9499f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnar @Retention(RetentionPolicy.SOURCE) 9599f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnar public @interface Format {} 9699f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnar 9768ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui // All the native functions are listed here. 9899f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnar private static native long nativeSetup(@NonNull FileDescriptor fd, int format); 99656fd0402613cec0196d5e2ae0a460d044d2805bAshok Bhat private static native void nativeRelease(long nativeObject); 100656fd0402613cec0196d5e2ae0a460d044d2805bAshok Bhat private static native void nativeStart(long nativeObject); 101656fd0402613cec0196d5e2ae0a460d044d2805bAshok Bhat private static native void nativeStop(long nativeObject); 10299f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnar private static native int nativeAddTrack( 10399f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnar long nativeObject, @NonNull String[] keys, @NonNull Object[] values); 10499f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnar private static native void nativeSetOrientationHint( 10599f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnar long nativeObject, int degrees); 106656fd0402613cec0196d5e2ae0a460d044d2805bAshok Bhat private static native void nativeSetLocation(long nativeObject, int latitude, int longitude); 10799f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnar private static native void nativeWriteSampleData( 10899f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnar long nativeObject, int trackIndex, @NonNull ByteBuffer byteBuf, 10999f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnar int offset, int size, long presentationTimeUs, @MediaCodec.BufferFlag int flags); 11068ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui 11168ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui // Muxer internal states. 11268ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui private static final int MUXER_STATE_UNINITIALIZED = -1; 11368ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui private static final int MUXER_STATE_INITIALIZED = 0; 11468ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui private static final int MUXER_STATE_STARTED = 1; 11568ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui private static final int MUXER_STATE_STOPPED = 2; 11668ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui 11768ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui private int mState = MUXER_STATE_UNINITIALIZED; 11868ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui 11968ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui private final CloseGuard mCloseGuard = CloseGuard.get(); 12068ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui private int mLastTrackIndex = -1; 12168ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui 122656fd0402613cec0196d5e2ae0a460d044d2805bAshok Bhat private long mNativeObject; 12368ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui 12468ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui /** 125effc9b4839f3cc109fe3d8244022f3c898cd080bztenghui * Constructor. 12668ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui * Creates a media muxer that writes to the specified path. 12768ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui * @param path The path of the output media file. 12868ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui * @param format The format of the output media file. 12968ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui * @see android.media.MediaMuxer.OutputFormat 13082a45249f626c36051c82c343ae9aa949aae0b11Hangyu Kuang * @throws IllegalArgumentException if path is invalid or format is not supported. 13182a45249f626c36051c82c343ae9aa949aae0b11Hangyu Kuang * @throws IOException if failed to open the file for write. 13268ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui */ 13399f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnar public MediaMuxer(@NonNull String path, @Format int format) throws IOException { 13468ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui if (path == null) { 13568ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui throw new IllegalArgumentException("path must not be null"); 13668ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui } 1371797dc93fb203762eecbc9c026b77263e4e4a4f5Robert Shih if (format != OutputFormat.MUXER_OUTPUT_MPEG_4 && 1381797dc93fb203762eecbc9c026b77263e4e4a4f5Robert Shih format != OutputFormat.MUXER_OUTPUT_WEBM) { 13968ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui throw new IllegalArgumentException("format is invalid"); 14068ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui } 1411797dc93fb203762eecbc9c026b77263e4e4a4f5Robert Shih // Use RandomAccessFile so we can open the file with RW access; 1421797dc93fb203762eecbc9c026b77263e4e4a4f5Robert Shih // RW access allows the native writer to memory map the output file. 1431797dc93fb203762eecbc9c026b77263e4e4a4f5Robert Shih RandomAccessFile file = null; 14468ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui try { 1451797dc93fb203762eecbc9c026b77263e4e4a4f5Robert Shih file = new RandomAccessFile(path, "rws"); 1461797dc93fb203762eecbc9c026b77263e4e4a4f5Robert Shih FileDescriptor fd = file.getFD(); 14768ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui mNativeObject = nativeSetup(fd, format); 14868ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui mState = MUXER_STATE_INITIALIZED; 14968ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui mCloseGuard.open("release"); 15068ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui } finally { 1511797dc93fb203762eecbc9c026b77263e4e4a4f5Robert Shih if (file != null) { 1521797dc93fb203762eecbc9c026b77263e4e4a4f5Robert Shih file.close(); 15368ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui } 15468ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui } 15568ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui } 15668ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui 15768ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui /** 158effc9b4839f3cc109fe3d8244022f3c898cd080bztenghui * Sets the orientation hint for output video playback. 159effc9b4839f3cc109fe3d8244022f3c898cd080bztenghui * <p>This method should be called before {@link #start}. Calling this 160effc9b4839f3cc109fe3d8244022f3c898cd080bztenghui * method will not rotate the video frame when muxer is generating the file, 161effc9b4839f3cc109fe3d8244022f3c898cd080bztenghui * but add a composition matrix containing the rotation angle in the output 162effc9b4839f3cc109fe3d8244022f3c898cd080bztenghui * video if the output format is 163effc9b4839f3cc109fe3d8244022f3c898cd080bztenghui * {@link OutputFormat#MUXER_OUTPUT_MPEG_4} so that a video player can 164effc9b4839f3cc109fe3d8244022f3c898cd080bztenghui * choose the proper orientation for playback. Note that some video players 165effc9b4839f3cc109fe3d8244022f3c898cd080bztenghui * may choose to ignore the composition matrix in a video during playback. 166effc9b4839f3cc109fe3d8244022f3c898cd080bztenghui * By default, the rotation degree is 0.</p> 167effc9b4839f3cc109fe3d8244022f3c898cd080bztenghui * @param degrees the angle to be rotated clockwise in degrees. 168effc9b4839f3cc109fe3d8244022f3c898cd080bztenghui * The supported angles are 0, 90, 180, and 270 degrees. 16982a45249f626c36051c82c343ae9aa949aae0b11Hangyu Kuang * @throws IllegalArgumentException if degree is not supported. 17082a45249f626c36051c82c343ae9aa949aae0b11Hangyu Kuang * @throws IllegalStateException If this method is called after {@link #start}. 171effc9b4839f3cc109fe3d8244022f3c898cd080bztenghui */ 172effc9b4839f3cc109fe3d8244022f3c898cd080bztenghui public void setOrientationHint(int degrees) { 173effc9b4839f3cc109fe3d8244022f3c898cd080bztenghui if (degrees != 0 && degrees != 90 && degrees != 180 && degrees != 270) { 174effc9b4839f3cc109fe3d8244022f3c898cd080bztenghui throw new IllegalArgumentException("Unsupported angle: " + degrees); 175effc9b4839f3cc109fe3d8244022f3c898cd080bztenghui } 176effc9b4839f3cc109fe3d8244022f3c898cd080bztenghui if (mState == MUXER_STATE_INITIALIZED) { 177effc9b4839f3cc109fe3d8244022f3c898cd080bztenghui nativeSetOrientationHint(mNativeObject, degrees); 178effc9b4839f3cc109fe3d8244022f3c898cd080bztenghui } else { 179effc9b4839f3cc109fe3d8244022f3c898cd080bztenghui throw new IllegalStateException("Can't set rotation degrees due" + 180effc9b4839f3cc109fe3d8244022f3c898cd080bztenghui " to wrong state."); 181effc9b4839f3cc109fe3d8244022f3c898cd080bztenghui } 182effc9b4839f3cc109fe3d8244022f3c898cd080bztenghui } 183effc9b4839f3cc109fe3d8244022f3c898cd080bztenghui 184effc9b4839f3cc109fe3d8244022f3c898cd080bztenghui /** 185cfd47481d1b375663d4e8e8d0c292d9001aa384bZhijun He * Set and store the geodata (latitude and longitude) in the output file. 186cfd47481d1b375663d4e8e8d0c292d9001aa384bZhijun He * This method should be called before {@link #start}. The geodata is stored 187cfd47481d1b375663d4e8e8d0c292d9001aa384bZhijun He * in udta box if the output format is 188cfd47481d1b375663d4e8e8d0c292d9001aa384bZhijun He * {@link OutputFormat#MUXER_OUTPUT_MPEG_4}, and is ignored for other output 189cfd47481d1b375663d4e8e8d0c292d9001aa384bZhijun He * formats. The geodata is stored according to ISO-6709 standard. 190cfd47481d1b375663d4e8e8d0c292d9001aa384bZhijun He * 191cfd47481d1b375663d4e8e8d0c292d9001aa384bZhijun He * @param latitude Latitude in degrees. Its value must be in the range [-90, 192cfd47481d1b375663d4e8e8d0c292d9001aa384bZhijun He * 90]. 193cfd47481d1b375663d4e8e8d0c292d9001aa384bZhijun He * @param longitude Longitude in degrees. Its value must be in the range 194cfd47481d1b375663d4e8e8d0c292d9001aa384bZhijun He * [-180, 180]. 195cfd47481d1b375663d4e8e8d0c292d9001aa384bZhijun He * @throws IllegalArgumentException If the given latitude or longitude is out 196cfd47481d1b375663d4e8e8d0c292d9001aa384bZhijun He * of range. 197cfd47481d1b375663d4e8e8d0c292d9001aa384bZhijun He * @throws IllegalStateException If this method is called after {@link #start}. 198cfd47481d1b375663d4e8e8d0c292d9001aa384bZhijun He */ 199cfd47481d1b375663d4e8e8d0c292d9001aa384bZhijun He public void setLocation(float latitude, float longitude) { 200cfd47481d1b375663d4e8e8d0c292d9001aa384bZhijun He int latitudex10000 = (int) (latitude * 10000 + 0.5); 201cfd47481d1b375663d4e8e8d0c292d9001aa384bZhijun He int longitudex10000 = (int) (longitude * 10000 + 0.5); 202cfd47481d1b375663d4e8e8d0c292d9001aa384bZhijun He 203cfd47481d1b375663d4e8e8d0c292d9001aa384bZhijun He if (latitudex10000 > 900000 || latitudex10000 < -900000) { 204cfd47481d1b375663d4e8e8d0c292d9001aa384bZhijun He String msg = "Latitude: " + latitude + " out of range."; 205cfd47481d1b375663d4e8e8d0c292d9001aa384bZhijun He throw new IllegalArgumentException(msg); 206cfd47481d1b375663d4e8e8d0c292d9001aa384bZhijun He } 207cfd47481d1b375663d4e8e8d0c292d9001aa384bZhijun He if (longitudex10000 > 1800000 || longitudex10000 < -1800000) { 208cfd47481d1b375663d4e8e8d0c292d9001aa384bZhijun He String msg = "Longitude: " + longitude + " out of range"; 209cfd47481d1b375663d4e8e8d0c292d9001aa384bZhijun He throw new IllegalArgumentException(msg); 210cfd47481d1b375663d4e8e8d0c292d9001aa384bZhijun He } 211cfd47481d1b375663d4e8e8d0c292d9001aa384bZhijun He 212cfd47481d1b375663d4e8e8d0c292d9001aa384bZhijun He if (mState == MUXER_STATE_INITIALIZED && mNativeObject != 0) { 213cfd47481d1b375663d4e8e8d0c292d9001aa384bZhijun He nativeSetLocation(mNativeObject, latitudex10000, longitudex10000); 214cfd47481d1b375663d4e8e8d0c292d9001aa384bZhijun He } else { 215cfd47481d1b375663d4e8e8d0c292d9001aa384bZhijun He throw new IllegalStateException("Can't set location due to wrong state."); 216cfd47481d1b375663d4e8e8d0c292d9001aa384bZhijun He } 217cfd47481d1b375663d4e8e8d0c292d9001aa384bZhijun He } 218cfd47481d1b375663d4e8e8d0c292d9001aa384bZhijun He 219cfd47481d1b375663d4e8e8d0c292d9001aa384bZhijun He /** 22068ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui * Starts the muxer. 22168ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui * <p>Make sure this is called after {@link #addTrack} and before 22268ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui * {@link #writeSampleData}.</p> 22382a45249f626c36051c82c343ae9aa949aae0b11Hangyu Kuang * @throws IllegalStateException If this method is called after {@link #start} 22482a45249f626c36051c82c343ae9aa949aae0b11Hangyu Kuang * or Muxer is released 22568ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui */ 22668ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui public void start() { 22768ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui if (mNativeObject == 0) { 22868ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui throw new IllegalStateException("Muxer has been released!"); 22968ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui } 23068ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui if (mState == MUXER_STATE_INITIALIZED) { 23168ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui nativeStart(mNativeObject); 23268ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui mState = MUXER_STATE_STARTED; 23368ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui } else { 23468ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui throw new IllegalStateException("Can't start due to wrong state."); 23568ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui } 23668ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui } 23768ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui 23868ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui /** 23968ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui * Stops the muxer. 24068ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui * <p>Once the muxer stops, it can not be restarted.</p> 24182a45249f626c36051c82c343ae9aa949aae0b11Hangyu Kuang * @throws IllegalStateException if muxer is in the wrong state. 24268ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui */ 24368ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui public void stop() { 24468ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui if (mState == MUXER_STATE_STARTED) { 24568ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui nativeStop(mNativeObject); 24668ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui mState = MUXER_STATE_STOPPED; 24768ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui } else { 24868ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui throw new IllegalStateException("Can't stop due to wrong state."); 24968ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui } 25068ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui } 25168ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui 25268ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui @Override 25368ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui protected void finalize() throws Throwable { 25468ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui try { 25568ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui if (mCloseGuard != null) { 25668ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui mCloseGuard.warnIfOpen(); 25768ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui } 25868ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui if (mNativeObject != 0) { 25968ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui nativeRelease(mNativeObject); 26068ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui mNativeObject = 0; 26168ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui } 26268ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui } finally { 26368ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui super.finalize(); 26468ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui } 26568ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui } 26668ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui 26768ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui /** 26868ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui * Adds a track with the specified format. 2695495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * <p> 2705495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * The following table summarizes support for specific format keys across android releases. 2715495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * Keys marked with '+:' are required. 2725495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * 2735495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * <table style="width: 0%"> 2745495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * <thead> 2755495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * <tr> 2765495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * <th rowspan=2>OS Version(s)</th> 2775495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * <td colspan=3>{@code MediaFormat} keys used for</th> 2785495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * </tr><tr> 2795495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * <th>All Tracks</th> 2805495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * <th>Audio Tracks</th> 2815495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * <th>Video Tracks</th> 2825495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * </tr> 2835495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * </thead> 2845495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * <tbody> 2855495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * <tr> 2865495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * <td>{@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}</td> 2875495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * <td rowspan=7>+: {@link MediaFormat#KEY_MIME}</td> 2885495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * <td rowspan=3>+: {@link MediaFormat#KEY_SAMPLE_RATE},<br> 2895495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * +: {@link MediaFormat#KEY_CHANNEL_COUNT},<br> 2905495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * +: <strong>codec-specific data<sup>AAC</sup></strong></td> 2915495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * <td rowspan=5>+: {@link MediaFormat#KEY_WIDTH},<br> 2925495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * +: {@link MediaFormat#KEY_HEIGHT},<br> 2935495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * no {@code KEY_ROTATION}, 2945495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * use {@link #setOrientationHint setOrientationHint()}<sup>.mp4</sup>,<br> 2955495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * +: <strong>codec-specific data<sup>AVC, MPEG4</sup></strong></td> 2965495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * </tr><tr> 2975495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * <td>{@link android.os.Build.VERSION_CODES#KITKAT}</td> 2985495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * </tr><tr> 2995495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * <td>{@link android.os.Build.VERSION_CODES#KITKAT_WATCH}</td> 3005495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * </tr><tr> 3015495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * <td>{@link android.os.Build.VERSION_CODES#LOLLIPOP}</td> 3025495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * <td rowspan=4>as above, plus<br> 3035495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * +: <strong>codec-specific data<sup>Vorbis & .webm</sup></strong></td> 3045495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * </tr><tr> 3055495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * <td>{@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1}</td> 3065495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * </tr><tr> 3075495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * <td>{@link android.os.Build.VERSION_CODES#M}</td> 3085495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * <td>as above, plus<br> 3095495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * {@link MediaFormat#KEY_BIT_RATE}<sup>AAC</sup></td> 3105495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * </tr><tr> 3115495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * <td>{@link android.os.Build.VERSION_CODES#N}</td> 3125495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * <td>as above, plus<br> 3135495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * <!-- {link MediaFormat#KEY_MAX_BIT_RATE}<sup>AAC, MPEG4</sup>,<br> --> 3145495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * {@link MediaFormat#KEY_BIT_RATE}<sup>MPEG4</sup>,<br> 3155495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * {@link MediaFormat#KEY_HDR_STATIC_INFO}<sup>#, .webm</sup>,<br> 3165495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * {@link MediaFormat#KEY_COLOR_STANDARD}<sup>#</sup>,<br> 3175495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * {@link MediaFormat#KEY_COLOR_TRANSFER}<sup>#</sup>,<br> 3185495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * {@link MediaFormat#KEY_COLOR_RANGE}<sup>#</sup>,<br> 3195495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * +: <strong>codec-specific data<sup>HEVC</sup></strong>,<br> 3205495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * codec-specific data<sup>VP9</sup></td> 3215495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * </tr> 3225495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * <tr> 3235495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * <td colspan=4> 3245495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * <p class=note><strong>Notes:</strong><br> 3255495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * #: storing into container metadata.<br> 3265495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * .mp4, .webm…: for listed containers<br> 3275495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * MPEG4, AAC…: for listed codecs 3285495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * </td> 3295495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * </tr><tr> 3305495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * <td colspan=4> 3315495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * <p class=note>Note that the codec-specific data for the track must be specified using 3325495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * this method. Furthermore, codec-specific data must not be passed/specified via the 3335495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * {@link #writeSampleData writeSampleData()} call. 3345495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * </td> 3355495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * </tr> 3365495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * </tbody> 3375495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * </table> 3385495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * 3395495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * <p> 3405495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * The following table summarizes codec support for containers across android releases: 3415495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * 3425495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * <table style="width: 0%"> 3435495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * <thead> 3445495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * <tr> 3455495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * <th rowspan=2>OS Version(s)</th> 3465495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * <td colspan=3>Codec support</th> 3475495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * </tr><tr> 3485495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * <th>{@linkplain OutputFormat#MUXER_OUTPUT_MPEG_4 MP4}</th> 3495495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * <th>{@linkplain OutputFormat#MUXER_OUTPUT_WEBM WEBM}</th> 3505495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * </tr> 3515495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * </thead> 3525495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * <tbody> 3535495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * <tr> 3545495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * <td>{@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}</td> 3555495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * <td rowspan=6>{@link MediaFormat#MIMETYPE_AUDIO_AAC AAC},<br> 3565495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * {@link MediaFormat#MIMETYPE_AUDIO_AMR_NB NB-AMR},<br> 3575495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * {@link MediaFormat#MIMETYPE_AUDIO_AMR_WB WB-AMR},<br> 3585495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * {@link MediaFormat#MIMETYPE_VIDEO_H263 H.263},<br> 3595495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * {@link MediaFormat#MIMETYPE_VIDEO_MPEG4 MPEG-4},<br> 3605495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * {@link MediaFormat#MIMETYPE_VIDEO_AVC AVC} (H.264)</td> 3615495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * <td rowspan=3>Not supported</td> 3625495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * </tr><tr> 3635495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * <td>{@link android.os.Build.VERSION_CODES#KITKAT}</td> 3645495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * </tr><tr> 3655495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * <td>{@link android.os.Build.VERSION_CODES#KITKAT_WATCH}</td> 3665495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * </tr><tr> 3675495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * <td>{@link android.os.Build.VERSION_CODES#LOLLIPOP}</td> 3685495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * <td rowspan=3>{@link MediaFormat#MIMETYPE_AUDIO_VORBIS Vorbis},<br> 3695495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * {@link MediaFormat#MIMETYPE_VIDEO_VP8 VP8}</td> 3705495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * </tr><tr> 3715495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * <td>{@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1}</td> 3725495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * </tr><tr> 3735495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * <td>{@link android.os.Build.VERSION_CODES#M}</td> 3745495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * </tr><tr> 3755495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * <td>{@link android.os.Build.VERSION_CODES#N}</td> 3765495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * <td>as above, plus<br> 3775495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * {@link MediaFormat#MIMETYPE_VIDEO_HEVC HEVC} (H.265)</td> 3785495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * <td>as above, plus<br> 3795495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * {@link MediaFormat#MIMETYPE_VIDEO_VP9 VP9}</td> 3805495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * </tr> 3815495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * </tbody> 3825495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * </table> 3835495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar * 38499f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnar * @param format The media format for the track. This must not be an empty 38599f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnar * MediaFormat. 38668ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui * @return The track index for this newly added track, and it should be used 38768ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui * in the {@link #writeSampleData}. 38882a45249f626c36051c82c343ae9aa949aae0b11Hangyu Kuang * @throws IllegalArgumentException if format is invalid. 38982a45249f626c36051c82c343ae9aa949aae0b11Hangyu Kuang * @throws IllegalStateException if muxer is in the wrong state. 39068ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui */ 39199f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnar public int addTrack(@NonNull MediaFormat format) { 39268ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui if (format == null) { 39368ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui throw new IllegalArgumentException("format must not be null."); 39468ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui } 39568ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui if (mState != MUXER_STATE_INITIALIZED) { 39668ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui throw new IllegalStateException("Muxer is not initialized."); 39768ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui } 39868ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui if (mNativeObject == 0) { 39968ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui throw new IllegalStateException("Muxer has been released!"); 40068ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui } 40168ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui int trackIndex = -1; 40268ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui // Convert the MediaFormat into key-value pairs and send to the native. 40368ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui Map<String, Object> formatMap = format.getMap(); 40468ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui 40568ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui String[] keys = null; 40668ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui Object[] values = null; 40768ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui int mapSize = formatMap.size(); 40868ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui if (mapSize > 0) { 40968ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui keys = new String[mapSize]; 41068ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui values = new Object[mapSize]; 41168ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui int i = 0; 41268ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui for (Map.Entry<String, Object> entry : formatMap.entrySet()) { 41368ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui keys[i] = entry.getKey(); 41468ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui values[i] = entry.getValue(); 41568ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui ++i; 41668ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui } 41768ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui trackIndex = nativeAddTrack(mNativeObject, keys, values); 41868ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui } else { 41968ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui throw new IllegalArgumentException("format must not be empty."); 42068ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui } 42168ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui 42268ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui // Track index number is expected to incremented as addTrack succeed. 42368ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui // However, if format is invalid, it will get a negative trackIndex. 42468ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui if (mLastTrackIndex >= trackIndex) { 42568ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui throw new IllegalArgumentException("Invalid format."); 42668ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui } 42768ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui mLastTrackIndex = trackIndex; 42868ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui return trackIndex; 42968ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui } 43068ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui 43168ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui /** 432f7d3aae32859a52c24713dba30e4d7ef779fdfb1ztenghui * Writes an encoded sample into the muxer. 433f7d3aae32859a52c24713dba30e4d7ef779fdfb1ztenghui * <p>The application needs to make sure that the samples are written into 434f7d3aae32859a52c24713dba30e4d7ef779fdfb1ztenghui * the right tracks. Also, it needs to make sure the samples for each track 435ecca7f60a69d99a9569c06bdf9c122f853e67d47Lajos Molnar * are written in chronological order (e.g. in the order they are provided 436ecca7f60a69d99a9569c06bdf9c122f853e67d47Lajos Molnar * by the encoder.)</p> 43768ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui * @param byteBuf The encoded sample. 43868ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui * @param trackIndex The track index for this sample. 43968ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui * @param bufferInfo The buffer information related to this sample. 44082a45249f626c36051c82c343ae9aa949aae0b11Hangyu Kuang * @throws IllegalArgumentException if trackIndex, byteBuf or bufferInfo is invalid. 44182a45249f626c36051c82c343ae9aa949aae0b11Hangyu Kuang * @throws IllegalStateException if muxer is in wrong state. 442ecca7f60a69d99a9569c06bdf9c122f853e67d47Lajos Molnar * MediaMuxer uses the flags provided in {@link MediaCodec.BufferInfo}, 443ecca7f60a69d99a9569c06bdf9c122f853e67d47Lajos Molnar * to signal sync frames. 44468ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui */ 44599f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnar public void writeSampleData(int trackIndex, @NonNull ByteBuffer byteBuf, 44699f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnar @NonNull BufferInfo bufferInfo) { 44768ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui if (trackIndex < 0 || trackIndex > mLastTrackIndex) { 44868ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui throw new IllegalArgumentException("trackIndex is invalid"); 44968ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui } 45068ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui 45168ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui if (byteBuf == null) { 45268ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui throw new IllegalArgumentException("byteBuffer must not be null"); 45368ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui } 45468ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui 45568ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui if (bufferInfo == null) { 45668ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui throw new IllegalArgumentException("bufferInfo must not be null"); 45768ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui } 45868ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui if (bufferInfo.size < 0 || bufferInfo.offset < 0 45968ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui || (bufferInfo.offset + bufferInfo.size) > byteBuf.capacity() 46068ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui || bufferInfo.presentationTimeUs < 0) { 46168ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui throw new IllegalArgumentException("bufferInfo must specify a" + 46268ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui " valid buffer offset, size and presentation time"); 46368ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui } 46468ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui 46568ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui if (mNativeObject == 0) { 46668ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui throw new IllegalStateException("Muxer has been released!"); 46768ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui } 46868ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui 46968ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui if (mState != MUXER_STATE_STARTED) { 47068ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui throw new IllegalStateException("Can't write, muxer is not started"); 47168ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui } 47268ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui 47368ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui nativeWriteSampleData(mNativeObject, trackIndex, byteBuf, 47468ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui bufferInfo.offset, bufferInfo.size, 47568ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui bufferInfo.presentationTimeUs, bufferInfo.flags); 47668ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui } 47768ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui 47868ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui /** 47968ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui * Make sure you call this when you're done to free up any resources 48068ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui * instead of relying on the garbage collector to do this for you at 48168ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui * some point in the future. 48268ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui */ 48368ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui public void release() { 48468ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui if (mState == MUXER_STATE_STARTED) { 485a83df76859f0af12105bcea27e2e8d9f0b4d2c31ztenghui stop(); 48668ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui } 48768ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui if (mNativeObject != 0) { 48868ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui nativeRelease(mNativeObject); 48968ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui mNativeObject = 0; 49068ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui mCloseGuard.close(); 49168ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui } 49268ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui mState = MUXER_STATE_UNINITIALIZED; 49368ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui } 49468ccf103a10c674f1db649bb15bb3e790bc6dad3ztenghui} 495