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