Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 package org.chromium.media; | |
| 6 | |
| 7 import android.content.Context; | |
| 8 import android.media.AudioFormat; | |
| 9 import android.media.MediaCodec; | |
| 10 import android.media.MediaCodec.BufferInfo; | |
| 11 import android.media.MediaExtractor; | |
| 12 import android.media.MediaFormat; | |
| 13 import android.util.Log; | |
| 14 | |
| 15 import java.nio.ByteBuffer; | |
| 16 import android.os.ParcelFileDescriptor; | |
| 17 | |
| 18 import org.chromium.base.CalledByNative; | |
| 19 import org.chromium.base.JNINamespace; | |
| 20 | |
| 21 @JNINamespace("media") | |
| 22 class WebAudioMediaCodecBridge { | |
| 23 static final String LOG_TAG = "WebAudioMediaCodec"; | |
| 24 // TODO(rtoy): What is the correct timeout value for reading | |
| 25 // from a file in memory? | |
| 26 static final long TIMEOUT_MICROSECONDS = 500; | |
| 27 @CalledByNative | |
| 28 private static boolean decodeAudioFile(Context ctx, int nativeMediaCodecBrid ge, int inputFD) { | |
| 29 MediaExtractor extractor; | |
| 30 extractor = new MediaExtractor(); | |
| 31 | |
| 32 ParcelFileDescriptor encodedFD; | |
| 33 try { | |
| 34 encodedFD = ParcelFileDescriptor.adoptFd(inputFD); | |
| 35 extractor.setDataSource(encodedFD.getFileDescriptor()); | |
| 36 } catch (Exception e) { | |
| 37 e.printStackTrace(); | |
|
digit1
2013/04/04 15:56:47
I assume you would want to call encodedFD.detachFd
| |
| 38 return false; | |
| 39 } | |
| 40 | |
| 41 if (extractor.getTrackCount() <= 0) { | |
| 42 encodedFD.detachFd(); | |
| 43 return false; | |
| 44 } | |
| 45 | |
| 46 MediaFormat format = extractor.getTrackFormat(0); | |
| 47 | |
| 48 int channelCount = format.getInteger(MediaFormat.KEY_CHANNEL_COUNT); | |
| 49 int sampleRate = format.getInteger(MediaFormat.KEY_SAMPLE_RATE); | |
| 50 String mime = format.getString(MediaFormat.KEY_MIME); | |
| 51 | |
| 52 long duration_microseconds = 0; | |
| 53 if (format.containsKey(MediaFormat.KEY_DURATION)) { | |
| 54 try { | |
| 55 duration_microseconds = format.getLong(MediaFormat.KEY_DURATION) ; | |
| 56 } catch (Exception e) { | |
| 57 Log.d(LOG_TAG, "Cannot get duration"); | |
|
digit1
2013/04/04 15:56:47
should you exit here, or is it ok to keep duration
Raymond Toy (Google)
2013/04/04 17:47:35
I believe it's ok to keep going. MediaCodec will
| |
| 58 } | |
| 59 } | |
| 60 | |
| 61 Log.d(LOG_TAG, "Tracks: " + extractor.getTrackCount() | |
|
digit1
2013/04/04 15:56:47
This Log.d() call is really slow: it will create a
Raymond Toy (Google)
2013/04/04 17:47:35
Ok. I'll add this, but I do hope to remove this p
| |
| 62 + " Rate: " + sampleRate | |
| 63 + " Channels: " + channelCount | |
| 64 + " Mime: " + mime | |
| 65 + " Duration: " + duration_microseconds + " microsec"); | |
| 66 | |
| 67 // For audio/vorbis files, MediaFormat returns a really huge | |
| 68 // (multi-year) duration value even for short files. Tell | |
| 69 // nativeInitializeDestination that this is a vorbis file so | |
| 70 // it can handle it properly. | |
| 71 // | |
| 72 // See b/8528051 | |
| 73 nativeInitializeDestination(nativeMediaCodecBridge, | |
| 74 channelCount, | |
| 75 sampleRate, | |
| 76 duration_microseconds, | |
| 77 mime.equals("audio/vorbis")); | |
| 78 | |
| 79 // Create decoder | |
| 80 MediaCodec codec = MediaCodec.createDecoderByType(mime); | |
| 81 codec.configure(format, null /* surface */, null /* crypto */, 0 /* flag s */); | |
| 82 codec.start(); | |
| 83 | |
| 84 ByteBuffer[] codecInputBuffers = codec.getInputBuffers(); | |
| 85 ByteBuffer[] codecOutputBuffers = codec.getOutputBuffers(); | |
| 86 | |
| 87 // A track must be selected and will be used to read samples. | |
| 88 extractor.selectTrack(0); | |
| 89 | |
| 90 boolean sawInputEOS = false; | |
| 91 boolean sawOutputEOS = false; | |
| 92 | |
| 93 // Keep processing until the output is done. | |
| 94 while (!sawOutputEOS) { | |
| 95 int sampleSize = 0; | |
| 96 if (!sawInputEOS) { | |
| 97 // Input side | |
| 98 int inputBufIndex = codec.dequeueInputBuffer(TIMEOUT_MICROSECOND S); | |
| 99 | |
| 100 if (inputBufIndex >= 0) { | |
| 101 ByteBuffer dstBuf = codecInputBuffers[inputBufIndex]; | |
| 102 sampleSize = extractor.readSampleData(dstBuf, 0); | |
| 103 long presentationTimeMicroSec = 0; | |
| 104 | |
| 105 if (sampleSize < 0) { | |
| 106 sawInputEOS = true; | |
| 107 sampleSize = 0; | |
| 108 } else { | |
| 109 presentationTimeMicroSec = extractor.getSampleTime(); | |
| 110 } | |
| 111 | |
| 112 codec.queueInputBuffer(inputBufIndex, | |
| 113 0, /* offset */ | |
| 114 sampleSize, | |
| 115 presentationTimeMicroSec, | |
| 116 sawInputEOS ? MediaCodec.BUFFER_FLAG_ END_OF_STREAM : 0); | |
| 117 | |
| 118 if (!sawInputEOS) { | |
| 119 extractor.advance(); | |
| 120 } | |
| 121 } | |
| 122 } | |
| 123 | |
| 124 // Output side | |
| 125 MediaCodec.BufferInfo info = new BufferInfo(); | |
| 126 final int outputBufIndex = codec.dequeueOutputBuffer(info, TIMEOUT_M ICROSECONDS); | |
| 127 | |
| 128 if (outputBufIndex >= 0) { | |
|
digit1
2013/04/04 15:56:47
Shouldn't you also handle INFO_OUTPUT_BUFFERS_CHAN
Raymond Toy (Google)
2013/04/04 17:47:35
Oops. The case for INFO_OUTPUT_BUFFERS_CHANGED wa
| |
| 129 ByteBuffer buf = codecOutputBuffers[outputBufIndex]; | |
| 130 | |
| 131 if (info.size > 0) { | |
| 132 nativeOnChunkDecoded(nativeMediaCodecBridge, buf, info.size) ; | |
| 133 } | |
| 134 | |
| 135 buf.clear(); | |
| 136 codec.releaseOutputBuffer(outputBufIndex, false /* render */); | |
| 137 | |
| 138 if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) { | |
| 139 sawOutputEOS = true; | |
| 140 } | |
| 141 } | |
| 142 } | |
| 143 | |
| 144 encodedFD.detachFd(); | |
| 145 | |
| 146 codec.stop(); | |
| 147 codec.release(); | |
| 148 codec = null; | |
| 149 | |
| 150 return true; | |
| 151 } | |
| 152 | |
| 153 private static native void nativeOnChunkDecoded( | |
| 154 int nativeWebAudioMediaCodecBridge, ByteBuffer buf, int size); | |
| 155 | |
| 156 private static native void nativeInitializeDestination( | |
| 157 int nativeWebAudioMediaCodecBridge, | |
| 158 int channelCount, | |
| 159 int sampleRate, | |
| 160 long duration_microseconds, | |
| 161 boolean is_vorbis); | |
| 162 } | |
| OLD | NEW |