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&hellip;: for listed containers<br>
3275495adca3aae8f6cf91ea3ae58324cd3b0c60bbcLajos Molnar     *      MPEG4, AAC&hellip;: 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