Home | History | Annotate | Download | only in decoder
      1 /*
      2  * Copyright (C) 2012 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package androidx.media.filterfw.decoder;
     18 
     19 import android.annotation.TargetApi;
     20 import android.media.MediaCodec;
     21 import android.media.MediaCodec.BufferInfo;
     22 import android.media.MediaFormat;
     23 
     24 import androidx.media.filterfw.FrameValue;
     25 
     26 import java.io.ByteArrayOutputStream;
     27 import java.io.IOException;
     28 import java.nio.ByteBuffer;
     29 
     30 /**
     31  * {@link TrackDecoder} for decoding audio tracks.
     32  *
     33  * TODO: find out if we always get 16 bits per channel and document.
     34  */
     35 @TargetApi(16)
     36 public class AudioTrackDecoder extends TrackDecoder {
     37 
     38     private final ByteArrayOutputStream mAudioByteStream; // Guarded by mAudioByteStreamLock.
     39     private final Object mAudioByteStreamLock;
     40 
     41     private int mAudioSampleRate;
     42     private int mAudioChannelCount;
     43     private long mAudioPresentationTimeUs;
     44 
     45     public AudioTrackDecoder(int trackIndex, MediaFormat format, Listener listener) {
     46         super(trackIndex, format, listener);
     47 
     48         if (!DecoderUtil.isAudioFormat(format)) {
     49             throw new IllegalArgumentException(
     50                     "AudioTrackDecoder can only be used with audio formats");
     51         }
     52 
     53         mAudioByteStream = new ByteArrayOutputStream();
     54         mAudioByteStreamLock = new Object();
     55 
     56         mAudioSampleRate = format.getInteger(MediaFormat.KEY_SAMPLE_RATE);
     57         mAudioChannelCount = format.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
     58     }
     59 
     60     @Override
     61     protected MediaCodec initMediaCodec(MediaFormat format) {
     62         MediaCodec mediaCodec = MediaCodec.createDecoderByType(
     63                 format.getString(MediaFormat.KEY_MIME));
     64         mediaCodec.configure(format, null, null, 0);
     65         return mediaCodec;
     66     }
     67 
     68     @Override
     69     protected boolean onDataAvailable(
     70             MediaCodec codec, ByteBuffer[] buffers, int bufferIndex, BufferInfo info) {
     71         ByteBuffer buffer = buffers[bufferIndex];
     72         byte[] data = new byte[info.size];
     73         buffer.position(info.offset);
     74         buffer.get(data, 0, info.size);
     75 
     76         synchronized (mAudioByteStreamLock) {
     77             try {
     78                 if (mAudioByteStream.size() == 0 && data.length > 0) {
     79                     mAudioPresentationTimeUs = info.presentationTimeUs;
     80                 }
     81 
     82                 mAudioByteStream.write(data);
     83             } catch (IOException e) {
     84                 // Just drop the audio sample.
     85             }
     86         }
     87 
     88         buffer.clear();
     89         codec.releaseOutputBuffer(bufferIndex, false);
     90         notifyListener();
     91         return true;
     92     }
     93 
     94     /**
     95      * Fills the argument {@link FrameValue} with an audio sample containing the audio that was
     96      * decoded since the last call of this method. The decoder's buffer is cleared as a result.
     97      */
     98     public void grabSample(FrameValue audioFrame) {
     99         synchronized (mAudioByteStreamLock) {
    100             if (audioFrame != null) {
    101                 AudioSample sample = new AudioSample(
    102                         mAudioSampleRate, mAudioChannelCount, mAudioByteStream.toByteArray());
    103                 audioFrame.setValue(sample);
    104                 audioFrame.setTimestamp(mAudioPresentationTimeUs * 1000);
    105             }
    106             clearBuffer();
    107         }
    108     }
    109 
    110     /**
    111      * Clears the decoder's buffer.
    112      */
    113     public void clearBuffer() {
    114         synchronized (mAudioByteStreamLock) {
    115             mAudioByteStream.reset();
    116         }
    117     }
    118 
    119 }
    120