16ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko/*
26ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko * Copyright (C) 2017 The Android Open Source Project
36ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko *
46ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko * Licensed under the Apache License, Version 2.0 (the "License");
56ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko * you may not use this file except in compliance with the License.
66ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko * You may obtain a copy of the License at
76ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko *
86ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko *      http://www.apache.org/licenses/LICENSE-2.0
96ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko *
106ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko * Unless required by applicable law or agreed to in writing, software
116ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko * distributed under the License is distributed on an "AS IS" BASIS,
126ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko * See the License for the specific language governing permissions and
146ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko * limitations under the License.
156ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko */
166ebde20b03db4c0d57f67acaac11832b610b966bNick Chalkopackage com.google.android.exoplayer2.ext.ffmpeg;
176ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko
186ebde20b03db4c0d57f67acaac11832b610b966bNick Chalkoimport android.content.Context;
196ebde20b03db4c0d57f67acaac11832b610b966bNick Chalkoimport android.content.pm.PackageManager;
206ebde20b03db4c0d57f67acaac11832b610b966bNick Chalkoimport com.google.android.exoplayer2.decoder.DecoderInputBuffer;
216ebde20b03db4c0d57f67acaac11832b610b966bNick Chalkoimport com.google.android.exoplayer2.decoder.SimpleOutputBuffer;
226ebde20b03db4c0d57f67acaac11832b610b966bNick Chalkoimport com.google.android.exoplayer2.util.MimeTypes;
236ebde20b03db4c0d57f67acaac11832b610b966bNick Chalkoimport com.android.tv.common.SoftPreconditions;
246ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko
256ebde20b03db4c0d57f67acaac11832b610b966bNick Chalkoimport java.nio.ByteBuffer;
266ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko
276ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko/**
286ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko * Audio decoder which uses ffmpeg extension of ExoPlayer2. Since {@link FfmpegDecoder} is package
296ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko * private, expose the decoder via this class. Supported formats are AC3 and MP2.
306ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko */
316ebde20b03db4c0d57f67acaac11832b610b966bNick Chalkopublic class FfmpegAudioDecoder {
326ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    private static final int NUM_DECODER_BUFFERS = 1;
336ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko
346ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    // The largest AC3 sample size. This is bigger than the largest MP2 sample size (1729).
356ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    private static final int INITIAL_INPUT_BUFFER_SIZE = 2560;
366ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    private static boolean AVAILABLE;
376ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko
386ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    static {
396ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        AVAILABLE =
406ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko                FfmpegLibrary.supportsFormat(MimeTypes.AUDIO_AC3)
416ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko                        && FfmpegLibrary.supportsFormat(MimeTypes.AUDIO_MPEG_L2);
426ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    }
436ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko
446ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    private FfmpegDecoder mDecoder;
456ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    private DecoderInputBuffer mInputBuffer;
466ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    private SimpleOutputBuffer mOutputBuffer;
476ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    private boolean mStarted;
486ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko
496ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    /** Return whether Ffmpeg based software audio decoder is available. */
506ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    public static boolean isAvailable() {
516ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        return AVAILABLE;
526ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    }
536ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko
546ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    /** Creates an Ffmpeg based software audio decoder. */
556ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    public FfmpegAudioDecoder(Context context) {
566ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        if (context.checkSelfPermission("android.permission.INTERNET")
576ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko                == PackageManager.PERMISSION_GRANTED) {
586ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            throw new IllegalStateException("This code should run in an isolated process");
596ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        }
606ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    }
616ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko
626ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    /**
636ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko     * Decodes an audio sample.
646ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko     *
656ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko     * @param timeUs presentation timestamp of the sample
666ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko     * @param sample data
676ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko     */
686ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    public void decode(long timeUs, byte[] sample) {
696ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        SoftPreconditions.checkState(AVAILABLE);
706ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        mInputBuffer.data.clear();
716ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        mInputBuffer.data.put(sample);
726ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        mInputBuffer.data.flip();
736ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        mInputBuffer.timeUs = timeUs;
746ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        mDecoder.decode(mInputBuffer, mOutputBuffer, !mStarted);
756ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        if (!mStarted) {
766ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            mStarted = true;
776ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        }
786ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    }
796ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko
806ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    /** Returns a decoded sample from decoder. */
816ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    public ByteBuffer getDecodedSample() {
826ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        return mOutputBuffer.data;
836ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    }
846ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko
856ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    /** Returns the presentation time for the decoded sample. */
866ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    public long getDecodedTimeUs() {
876ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        return mOutputBuffer.timeUs;
886ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    }
896ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko
906ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    /**
916ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko     * Clear previous decode state if any. Prepares to decode samples of the specified encoding.
926ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko     * This method should be called before using decode.
936ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko     *
946ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko     * @param mime audio encoding
956ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko     */
966ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    public void resetDecoderState(String mime) {
976ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        SoftPreconditions.checkState(AVAILABLE);
986ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        release();
996ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        try {
1006ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            mDecoder =
1016ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko                    new FfmpegDecoder(
1026ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko                            NUM_DECODER_BUFFERS,
1036ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko                            NUM_DECODER_BUFFERS,
1046ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko                            INITIAL_INPUT_BUFFER_SIZE,
1056ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko                            mime,
1066ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko                            null);
1076ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            mStarted = false;
1086ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            mInputBuffer = mDecoder.createInputBuffer();
1096ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            // Since native JNI requires direct buffer, we should allocate it by #allocateDirect.
1106ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            mInputBuffer.data = ByteBuffer.allocateDirect(INITIAL_INPUT_BUFFER_SIZE);
1116ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            mOutputBuffer = mDecoder.createOutputBuffer();
1126ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        } catch (FfmpegDecoderException e) {
1136ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            // if AVAILABLE is {@code true}, this will not happen.
1146ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        }
1156ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    }
1166ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko
1176ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    /** Releases all the resource. */
1186ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    public void release() {
1196ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        SoftPreconditions.checkState(AVAILABLE);
1206ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        if (mDecoder != null) {
1216ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            mDecoder.release();
1226ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            mInputBuffer = null;
1236ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            mOutputBuffer = null;
1246ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko            mDecoder = null;
1256ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko        }
1266ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko    }
1276ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko}
128