OLD | NEW |
---|---|
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 package org.chromium.media; | 5 package org.chromium.media; |
6 | 6 |
7 import android.media.AudioFormat; | 7 import android.media.AudioFormat; |
8 import android.media.AudioManager; | 8 import android.media.AudioManager; |
9 import android.media.AudioTrack; | 9 import android.media.AudioTrack; |
10 import android.media.MediaCodec; | 10 import android.media.MediaCodec; |
11 import android.media.MediaCodecInfo; | 11 import android.media.MediaCodecInfo; |
12 import android.media.MediaCodecList; | 12 import android.media.MediaCodecList; |
13 import android.media.MediaCrypto; | 13 import android.media.MediaCrypto; |
14 import android.media.MediaFormat; | 14 import android.media.MediaFormat; |
15 import android.os.Build; | 15 import android.os.Build; |
16 import android.os.Bundle; | |
16 import android.util.Log; | 17 import android.util.Log; |
17 import android.view.Surface; | 18 import android.view.Surface; |
18 | 19 |
19 import java.io.IOException; | 20 import java.io.IOException; |
20 import java.nio.ByteBuffer; | 21 import java.nio.ByteBuffer; |
21 import java.util.ArrayList; | 22 import java.util.ArrayList; |
23 import java.util.Collection; | |
22 import java.util.HashMap; | 24 import java.util.HashMap; |
23 import java.util.Map; | 25 import java.util.Map; |
24 | 26 |
25 import org.chromium.base.CalledByNative; | 27 import org.chromium.base.CalledByNative; |
26 import org.chromium.base.JNINamespace; | 28 import org.chromium.base.JNINamespace; |
27 | 29 |
28 /** | 30 /** |
29 * A wrapper of the MediaCodec class to facilitate exception capturing and | 31 * A wrapper of the MediaCodec class to facilitate exception capturing and |
30 * audio rendering. | 32 * audio rendering. |
31 */ | 33 */ |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
77 @CalledByNative("DequeueInputResult") | 79 @CalledByNative("DequeueInputResult") |
78 private int index() { return mIndex; } | 80 private int index() { return mIndex; } |
79 } | 81 } |
80 | 82 |
81 /** | 83 /** |
82 * This class represents supported android codec information. | 84 * This class represents supported android codec information. |
83 */ | 85 */ |
84 private static class CodecInfo { | 86 private static class CodecInfo { |
85 private final String mCodecType; // e.g. "video/x-vnd.on2.vp8". | 87 private final String mCodecType; // e.g. "video/x-vnd.on2.vp8". |
86 private final String mCodecName; // e.g. "OMX.google.vp8.decoder". | 88 private final String mCodecName; // e.g. "OMX.google.vp8.decoder". |
89 private final boolean mIsEncoder; | |
87 | 90 |
88 private CodecInfo(String codecType, String codecName) { | 91 private CodecInfo(String codecType, String codecName, |
92 boolean isEncoder) { | |
89 mCodecType = codecType; | 93 mCodecType = codecType; |
90 mCodecName = codecName; | 94 mCodecName = codecName; |
95 mIsEncoder = isEncoder; | |
91 } | 96 } |
92 | 97 |
93 @CalledByNative("CodecInfo") | 98 @CalledByNative("CodecInfo") |
94 private String codecType() { return mCodecType; } | 99 private String codecType() { return mCodecType; } |
95 | 100 |
96 @CalledByNative("CodecInfo") | 101 @CalledByNative("CodecInfo") |
97 private String codecName() { return mCodecName; } | 102 private String codecName() { return mCodecName; } |
103 | |
104 @CalledByNative("CodecInfo") | |
105 private boolean isEncoder() { return mIsEncoder; } | |
98 } | 106 } |
99 | 107 |
100 private static class DequeueOutputResult { | 108 private static class DequeueOutputResult { |
101 private final int mStatus; | 109 private final int mStatus; |
102 private final int mIndex; | 110 private final int mIndex; |
103 private final int mFlags; | 111 private final int mFlags; |
104 private final int mOffset; | 112 private final int mOffset; |
105 private final long mPresentationTimeMicroseconds; | 113 private final long mPresentationTimeMicroseconds; |
106 private final int mNumBytes; | 114 private final int mNumBytes; |
107 | 115 |
(...skipping 24 matching lines...) Expand all Loading... | |
132 | 140 |
133 @CalledByNative("DequeueOutputResult") | 141 @CalledByNative("DequeueOutputResult") |
134 private int numBytes() { return mNumBytes; } | 142 private int numBytes() { return mNumBytes; } |
135 } | 143 } |
136 | 144 |
137 /** | 145 /** |
138 * Get a list of supported android codec mimes. | 146 * Get a list of supported android codec mimes. |
139 */ | 147 */ |
140 @CalledByNative | 148 @CalledByNative |
141 private static CodecInfo[] getCodecsInfo() { | 149 private static CodecInfo[] getCodecsInfo() { |
142 Map<String, CodecInfo> CodecInfoMap = new HashMap<String, CodecInfo>(); | 150 Map<String, CodecInfo> encoderInfoMap = new HashMap<String, CodecInfo>() ; |
151 Map<String, CodecInfo> decoderInfoMap = new HashMap<String, CodecInfo>() ; | |
xhwang
2013/11/19 00:11:25
It's a bit odd to have two maps here then merge th
Ami GONE FROM CHROMIUM
2013/11/21 22:59:07
Agreed.
| |
143 int count = MediaCodecList.getCodecCount(); | 152 int count = MediaCodecList.getCodecCount(); |
144 for (int i = 0; i < count; ++i) { | 153 for (int i = 0; i < count; ++i) { |
145 MediaCodecInfo info = MediaCodecList.getCodecInfoAt(i); | 154 MediaCodecInfo info = MediaCodecList.getCodecInfoAt(i); |
146 if (info.isEncoder()) { | 155 boolean isEncoder = info.isEncoder(); |
147 continue; | |
148 } | |
149 | |
150 String codecString = info.getName(); | 156 String codecString = info.getName(); |
151 String[] supportedTypes = info.getSupportedTypes(); | 157 String[] supportedTypes = info.getSupportedTypes(); |
152 for (int j = 0; j < supportedTypes.length; ++j) { | 158 for (int j = 0; j < supportedTypes.length; ++j) { |
153 if (!CodecInfoMap.containsKey(supportedTypes[j])) { | 159 Map<String, CodecInfo> map = isEncoder ? encoderInfoMap : decode rInfoMap; |
154 CodecInfoMap.put(supportedTypes[j], new CodecInfo( | 160 if (!map.containsKey(supportedTypes[j])) { |
155 supportedTypes[j], codecString)); | 161 map.put(supportedTypes[j], new CodecInfo( |
162 supportedTypes[j], codecString, isEncoder)); | |
156 } | 163 } |
157 } | 164 } |
158 } | 165 } |
159 return CodecInfoMap.values().toArray( | 166 ArrayList<CodecInfo> codecInfos = new ArrayList<CodecInfo>( |
160 new CodecInfo[CodecInfoMap.size()]); | 167 decoderInfoMap.size() + encoderInfoMap.size()); |
168 codecInfos.addAll(encoderInfoMap.values()); | |
169 codecInfos.addAll(decoderInfoMap.values()); | |
170 return codecInfos.toArray(new CodecInfo[codecInfos.size()]); | |
161 } | 171 } |
162 | 172 |
163 private static String getSecureDecoderNameForMime(String mime) { | 173 private static String getSecureDecoderNameForMime(String mime) { |
164 int count = MediaCodecList.getCodecCount(); | 174 int count = MediaCodecList.getCodecCount(); |
165 for (int i = 0; i < count; ++i) { | 175 for (int i = 0; i < count; ++i) { |
166 MediaCodecInfo info = MediaCodecList.getCodecInfoAt(i); | 176 MediaCodecInfo info = MediaCodecList.getCodecInfoAt(i); |
167 if (info.isEncoder()) { | 177 if (info.isEncoder()) { |
168 continue; | 178 continue; |
169 } | 179 } |
170 | 180 |
171 String[] supportedTypes = info.getSupportedTypes(); | 181 String[] supportedTypes = info.getSupportedTypes(); |
172 for (int j = 0; j < supportedTypes.length; ++j) { | 182 for (int j = 0; j < supportedTypes.length; ++j) { |
173 if (supportedTypes[j].equalsIgnoreCase(mime)) { | 183 if (supportedTypes[j].equalsIgnoreCase(mime)) { |
174 return info.getName() + ".secure"; | 184 return info.getName() + ".secure"; |
175 } | 185 } |
176 } | 186 } |
177 } | 187 } |
178 | 188 |
179 return null; | 189 return null; |
180 } | 190 } |
181 | 191 |
182 private MediaCodecBridge(MediaCodec mediaCodec) { | 192 private MediaCodecBridge(MediaCodec mediaCodec) { |
183 assert(mediaCodec != null); | 193 assert(mediaCodec != null); |
184 mMediaCodec = mediaCodec; | 194 mMediaCodec = mediaCodec; |
185 mLastPresentationTimeUs = 0; | 195 mLastPresentationTimeUs = 0; |
186 mFlushed = true; | 196 mFlushed = true; |
187 } | 197 } |
188 | 198 |
189 @CalledByNative | 199 @CalledByNative |
190 private static MediaCodecBridge create(String mime, boolean isSecure) { | 200 private static MediaCodecBridge create(String mime, boolean isSecure, boolea n isEncoder) { |
191 // Creation of ".secure" codecs sometimes crash instead of throwing exce ptions | 201 // Creation of ".secure" codecs sometimes crash instead of throwing exce ptions |
192 // on pre-JBMR2 devices. | 202 // on pre-JBMR2 devices. |
193 if (isSecure && Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_M R2) { | 203 if (isSecure && Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_M R2) { |
194 return null; | 204 return null; |
195 } | 205 } |
196 MediaCodec mediaCodec = null; | 206 MediaCodec mediaCodec = null; |
197 try { | 207 try { |
198 // |isSecure| only applies to video decoders. | 208 // |isSecure| only applies to video decoders. |
199 if (mime.startsWith("video") && isSecure) { | 209 if (mime.startsWith("video") && isSecure && !isEncoder) { |
200 mediaCodec = MediaCodec.createByCodecName(getSecureDecoderNameFo rMime(mime)); | 210 mediaCodec = MediaCodec.createByCodecName(getSecureDecoderNameFo rMime(mime)); |
201 } else { | 211 } else { |
202 mediaCodec = MediaCodec.createDecoderByType(mime); | 212 if (isEncoder) { |
213 mediaCodec = MediaCodec.createEncoderByType(mime); | |
214 } else { | |
215 mediaCodec = MediaCodec.createDecoderByType(mime); | |
216 } | |
203 } | 217 } |
204 } catch (Exception e) { | 218 } catch (Exception e) { |
205 Log.e(TAG, "Failed to create MediaCodec: " + mime + ", isSecure: " | 219 Log.e(TAG, "Failed to create MediaCodec: " + mime + ", isSecure: " |
206 + isSecure + ", " + e.toString()); | 220 + isSecure + ", isEncoder: " + isEncoder, e); |
207 } | 221 } |
208 | 222 |
209 if (mediaCodec == null) { | 223 if (mediaCodec == null) { |
210 return null; | 224 return null; |
211 } | 225 } |
212 | 226 |
213 return new MediaCodecBridge(mediaCodec); | 227 return new MediaCodecBridge(mediaCodec); |
214 } | 228 } |
215 | 229 |
216 @CalledByNative | 230 @CalledByNative |
217 private void release() { | 231 private void release() { |
232 String name = mMediaCodec.getName(); | |
233 mMediaCodec.stop(); | |
218 mMediaCodec.release(); | 234 mMediaCodec.release(); |
235 mMediaCodec = null; | |
219 if (mAudioTrack != null) { | 236 if (mAudioTrack != null) { |
220 mAudioTrack.release(); | 237 mAudioTrack.release(); |
221 } | 238 } |
222 } | 239 } |
223 | 240 |
224 @CalledByNative | 241 @CalledByNative |
225 private boolean start() { | 242 private boolean start() { |
226 try { | 243 try { |
227 mMediaCodec.start(); | 244 mMediaCodec.start(); |
228 mInputBuffers = mMediaCodec.getInputBuffers(); | 245 mInputBuffers = mMediaCodec.getInputBuffers(); |
229 } catch (IllegalStateException e) { | 246 } catch (IllegalStateException e) { |
230 Log.e(TAG, "Cannot start the media codec " + e.toString()); | 247 Log.e(TAG, "Cannot start the media codec", e); |
231 return false; | 248 return false; |
232 } | 249 } |
233 return true; | 250 return true; |
234 } | 251 } |
235 | 252 |
236 @CalledByNative | 253 @CalledByNative |
237 private DequeueInputResult dequeueInputBuffer(long timeoutUs) { | 254 private DequeueInputResult dequeueInputBuffer(long timeoutUs) { |
238 int status = MEDIA_CODEC_ERROR; | 255 int status = MEDIA_CODEC_ERROR; |
239 int index = -1; | 256 int index = -1; |
240 try { | 257 try { |
241 int index_or_status = mMediaCodec.dequeueInputBuffer(timeoutUs); | 258 int index_or_status = mMediaCodec.dequeueInputBuffer(timeoutUs); |
242 if (index_or_status >= 0) { // index! | 259 if (index_or_status >= 0) { // index! |
243 status = MEDIA_CODEC_OK; | 260 status = MEDIA_CODEC_OK; |
244 index = index_or_status; | 261 index = index_or_status; |
245 } else if (index_or_status == MediaCodec.INFO_TRY_AGAIN_LATER) { | 262 } else if (index_or_status == MediaCodec.INFO_TRY_AGAIN_LATER) { |
246 Log.e(TAG, "dequeueInputBuffer: MediaCodec.INFO_TRY_AGAIN_LATER" ); | 263 Log.e(TAG, "dequeueInputBuffer: MediaCodec.INFO_TRY_AGAIN_LATER" ); |
247 status = MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER; | 264 status = MEDIA_CODEC_DEQUEUE_INPUT_AGAIN_LATER; |
248 } else { | 265 } else { |
266 Log.e(TAG, "Unexpected index_or_status: " + index_or_status); | |
249 assert(false); | 267 assert(false); |
250 } | 268 } |
251 } catch(Exception e) { | 269 } catch(Exception e) { |
252 Log.e(TAG, "Failed to dequeue input buffer: " + e.toString()); | 270 Log.e(TAG, "Failed to dequeue input buffer", e); |
253 } | 271 } |
254 return new DequeueInputResult(status, index); | 272 return new DequeueInputResult(status, index); |
255 } | 273 } |
256 | 274 |
257 @CalledByNative | 275 @CalledByNative |
258 private int flush() { | 276 private int flush() { |
259 try { | 277 try { |
260 mFlushed = true; | 278 mFlushed = true; |
261 if (mAudioTrack != null) { | 279 if (mAudioTrack != null) { |
262 mAudioTrack.flush(); | 280 mAudioTrack.flush(); |
263 } | 281 } |
264 mMediaCodec.flush(); | 282 mMediaCodec.flush(); |
265 } catch(IllegalStateException e) { | 283 } catch(IllegalStateException e) { |
266 Log.e(TAG, "Failed to flush MediaCodec " + e.toString()); | 284 Log.e(TAG, "Failed to flush MediaCodec", e); |
267 return MEDIA_CODEC_ERROR; | 285 return MEDIA_CODEC_ERROR; |
268 } | 286 } |
269 return MEDIA_CODEC_OK; | 287 return MEDIA_CODEC_OK; |
270 } | 288 } |
271 | 289 |
272 @CalledByNative | 290 @CalledByNative |
273 private void stop() { | 291 private void stop() { |
274 mMediaCodec.stop(); | 292 mMediaCodec.stop(); |
275 if (mAudioTrack != null) { | 293 if (mAudioTrack != null) { |
276 mAudioTrack.pause(); | 294 mAudioTrack.pause(); |
(...skipping 20 matching lines...) Expand all Loading... | |
297 return mOutputBuffers[index]; | 315 return mOutputBuffers[index]; |
298 } | 316 } |
299 | 317 |
300 @CalledByNative | 318 @CalledByNative |
301 private int queueInputBuffer( | 319 private int queueInputBuffer( |
302 int index, int offset, int size, long presentationTimeUs, int flags) { | 320 int index, int offset, int size, long presentationTimeUs, int flags) { |
303 resetLastPresentationTimeIfNeeded(presentationTimeUs); | 321 resetLastPresentationTimeIfNeeded(presentationTimeUs); |
304 try { | 322 try { |
305 mMediaCodec.queueInputBuffer(index, offset, size, presentationTimeUs , flags); | 323 mMediaCodec.queueInputBuffer(index, offset, size, presentationTimeUs , flags); |
306 } catch(Exception e) { | 324 } catch(Exception e) { |
307 Log.e(TAG, "Failed to queue input buffer: " + e.toString()); | 325 Log.e(TAG, "Failed to queue input buffer", e); |
308 return MEDIA_CODEC_ERROR; | 326 return MEDIA_CODEC_ERROR; |
309 } | 327 } |
310 return MEDIA_CODEC_OK; | 328 return MEDIA_CODEC_OK; |
311 } | 329 } |
312 | 330 |
313 @CalledByNative | 331 @CalledByNative |
332 private void setVideoBitrate(int bps) { | |
333 Bundle b = new Bundle(); | |
334 b.putInt(MediaCodec.PARAMETER_KEY_VIDEO_BITRATE, bps); | |
335 mMediaCodec.setParameters(b); | |
336 } | |
337 | |
338 @CalledByNative | |
339 private void requestKeyFrameSoon() { | |
340 Bundle b = new Bundle(); | |
341 b.putInt(MediaCodec.PARAMETER_KEY_REQUEST_SYNC_FRAME, 0); | |
342 mMediaCodec.setParameters(b); | |
343 } | |
344 | |
345 @CalledByNative | |
314 private int queueSecureInputBuffer( | 346 private int queueSecureInputBuffer( |
315 int index, int offset, byte[] iv, byte[] keyId, int[] numBytesOfClea rData, | 347 int index, int offset, byte[] iv, byte[] keyId, int[] numBytesOfClea rData, |
316 int[] numBytesOfEncryptedData, int numSubSamples, long presentationT imeUs) { | 348 int[] numBytesOfEncryptedData, int numSubSamples, long presentationT imeUs) { |
317 resetLastPresentationTimeIfNeeded(presentationTimeUs); | 349 resetLastPresentationTimeIfNeeded(presentationTimeUs); |
318 try { | 350 try { |
319 MediaCodec.CryptoInfo cryptoInfo = new MediaCodec.CryptoInfo(); | 351 MediaCodec.CryptoInfo cryptoInfo = new MediaCodec.CryptoInfo(); |
320 cryptoInfo.set(numSubSamples, numBytesOfClearData, numBytesOfEncrypt edData, | 352 cryptoInfo.set(numSubSamples, numBytesOfClearData, numBytesOfEncrypt edData, |
321 keyId, iv, MediaCodec.CRYPTO_MODE_AES_CTR); | 353 keyId, iv, MediaCodec.CRYPTO_MODE_AES_CTR); |
322 mMediaCodec.queueSecureInputBuffer(index, offset, cryptoInfo, presen tationTimeUs, 0); | 354 mMediaCodec.queueSecureInputBuffer(index, offset, cryptoInfo, presen tationTimeUs, 0); |
323 } catch (MediaCodec.CryptoException e) { | 355 } catch (MediaCodec.CryptoException e) { |
324 Log.e(TAG, "Failed to queue secure input buffer: " + e.toString()); | 356 Log.e(TAG, "Failed to queue secure input buffer", e); |
325 // TODO(xhwang): Replace hard coded value with constant/enum. | 357 // TODO(xhwang): Replace hard coded value with constant/enum. |
326 if (e.getErrorCode() == 1) { | 358 if (e.getErrorCode() == 1) { |
327 Log.e(TAG, "No key available."); | 359 Log.e(TAG, "No key available."); |
328 return MEDIA_CODEC_NO_KEY; | 360 return MEDIA_CODEC_NO_KEY; |
329 } | 361 } |
330 return MEDIA_CODEC_ERROR; | 362 return MEDIA_CODEC_ERROR; |
331 } catch(IllegalStateException e) { | 363 } catch(IllegalStateException e) { |
332 Log.e(TAG, "Failed to queue secure input buffer: " + e.toString()); | 364 Log.e(TAG, "Failed to queue secure input buffer", e); |
333 return MEDIA_CODEC_ERROR; | 365 return MEDIA_CODEC_ERROR; |
334 } | 366 } |
335 return MEDIA_CODEC_OK; | 367 return MEDIA_CODEC_OK; |
336 } | 368 } |
337 | 369 |
338 @CalledByNative | 370 @CalledByNative |
339 private void releaseOutputBuffer(int index, boolean render) { | 371 private void releaseOutputBuffer(int index, boolean render) { |
340 mMediaCodec.releaseOutputBuffer(index, render); | 372 mMediaCodec.releaseOutputBuffer(index, render); |
341 } | 373 } |
342 | 374 |
343 @CalledByNative | 375 @CalledByNative |
376 private int getInputBuffersCount() { | |
377 return mInputBuffers.length; | |
378 } | |
379 | |
380 @CalledByNative | |
381 private int getOutputBuffersCount() { | |
382 return mOutputBuffers != null ? mOutputBuffers.length : -1; | |
383 } | |
384 | |
385 @CalledByNative | |
386 private int getOutputBuffersCapacity() { | |
387 return mOutputBuffers != null ? mOutputBuffers[0].capacity() : -1; | |
388 } | |
389 | |
390 @CalledByNative | |
344 private boolean getOutputBuffers() { | 391 private boolean getOutputBuffers() { |
345 try { | 392 try { |
346 mOutputBuffers = mMediaCodec.getOutputBuffers(); | 393 mOutputBuffers = mMediaCodec.getOutputBuffers(); |
347 } catch (IllegalStateException e) { | 394 } catch (IllegalStateException e) { |
348 Log.e(TAG, "Cannot get output buffers " + e.toString()); | 395 Log.e(TAG, "Cannot get output buffers", e); |
349 return false; | 396 return false; |
350 } | 397 } |
351 return true; | 398 return true; |
352 } | 399 } |
xhwang
2013/11/19 00:11:25
Move l.375-l.399 to l.317?
Ami GONE FROM CHROMIUM
2013/11/21 22:59:07
Done.
| |
353 | 400 |
354 @CalledByNative | 401 @CalledByNative |
355 private DequeueOutputResult dequeueOutputBuffer(long timeoutUs) { | 402 private DequeueOutputResult dequeueOutputBuffer(long timeoutUs) { |
356 MediaCodec.BufferInfo info = new MediaCodec.BufferInfo(); | 403 MediaCodec.BufferInfo info = new MediaCodec.BufferInfo(); |
357 int status = MEDIA_CODEC_ERROR; | 404 int status = MEDIA_CODEC_ERROR; |
358 int index = -1; | 405 int index = -1; |
359 try { | 406 try { |
360 int index_or_status = mMediaCodec.dequeueOutputBuffer(info, timeoutU s); | 407 int index_or_status = mMediaCodec.dequeueOutputBuffer(info, timeoutU s); |
361 if (info.presentationTimeUs < mLastPresentationTimeUs) { | 408 if (info.presentationTimeUs < mLastPresentationTimeUs) { |
362 // TODO(qinmin): return a special code through DequeueOutputResu lt | 409 // TODO(qinmin): return a special code through DequeueOutputResu lt |
363 // to notify the native code the the frame has a wrong presentat ion | 410 // to notify the native code the the frame has a wrong presentat ion |
364 // timestamp and should be skipped. | 411 // timestamp and should be skipped. |
365 info.presentationTimeUs = mLastPresentationTimeUs; | 412 info.presentationTimeUs = mLastPresentationTimeUs; |
366 } | 413 } |
367 mLastPresentationTimeUs = info.presentationTimeUs; | 414 mLastPresentationTimeUs = info.presentationTimeUs; |
368 | 415 |
369 if (index_or_status >= 0) { // index! | 416 if (index_or_status >= 0) { // index! |
370 status = MEDIA_CODEC_OK; | 417 status = MEDIA_CODEC_OK; |
371 index = index_or_status; | 418 index = index_or_status; |
372 } else if (index_or_status == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED ) { | 419 } else if (index_or_status == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED ) { |
373 status = MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED; | 420 status = MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED; |
374 } else if (index_or_status == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { | 421 } else if (index_or_status == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { |
375 status = MEDIA_CODEC_OUTPUT_FORMAT_CHANGED; | 422 status = MEDIA_CODEC_OUTPUT_FORMAT_CHANGED; |
376 } else if (index_or_status == MediaCodec.INFO_TRY_AGAIN_LATER) { | 423 } else if (index_or_status == MediaCodec.INFO_TRY_AGAIN_LATER) { |
377 status = MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER; | 424 status = MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER; |
378 } else { | 425 } else { |
426 Log.e(TAG, "Unexpected index_or_status: " + index_or_status); | |
379 assert(false); | 427 assert(false); |
380 } | 428 } |
381 } catch (IllegalStateException e) { | 429 } catch (IllegalStateException e) { |
382 Log.e(TAG, "Failed to dequeue output buffer: " + e.toString()); | 430 Log.e(TAG, "Failed to dequeue output buffer", e); |
383 } | 431 } |
384 | 432 |
385 return new DequeueOutputResult( | 433 return new DequeueOutputResult( |
386 status, index, info.flags, info.offset, info.presentationTimeUs, info.size); | 434 status, index, info.flags, info.offset, info.presentationTimeUs, info.size); |
387 } | 435 } |
388 | 436 |
389 @CalledByNative | 437 @CalledByNative |
390 private boolean configureVideo(MediaFormat format, Surface surface, MediaCry pto crypto, | 438 private boolean configureVideo(MediaFormat format, Surface surface, MediaCry pto crypto, |
391 int flags) { | 439 int flags) { |
392 try { | 440 try { |
393 mMediaCodec.configure(format, surface, crypto, flags); | 441 mMediaCodec.configure(format, surface, crypto, flags); |
394 return true; | 442 return true; |
395 } catch (IllegalStateException e) { | 443 } catch (IllegalStateException e) { |
396 Log.e(TAG, "Cannot configure the video codec " + e.toString()); | 444 Log.e(TAG, "Cannot configure the video codec", e); |
397 } | 445 } |
398 return false; | 446 return false; |
399 } | 447 } |
400 | 448 |
401 @CalledByNative | 449 @CalledByNative |
402 private static MediaFormat createAudioFormat(String mime, int SampleRate, in t ChannelCount) { | 450 private static MediaFormat createAudioFormat(String mime, int SampleRate, in t ChannelCount) { |
403 return MediaFormat.createAudioFormat(mime, SampleRate, ChannelCount); | 451 return MediaFormat.createAudioFormat(mime, SampleRate, ChannelCount); |
404 } | 452 } |
405 | 453 |
406 @CalledByNative | 454 @CalledByNative |
407 private static MediaFormat createVideoFormat(String mime, int width, int hei ght) { | 455 private static MediaFormat createVideoDecoderFormat(String mime, int width, int height) { |
408 return MediaFormat.createVideoFormat(mime, width, height); | 456 return MediaFormat.createVideoFormat(mime, width, height); |
409 } | 457 } |
410 | 458 |
411 @CalledByNative | 459 @CalledByNative |
460 private static MediaFormat createVideoEncoderFormat(String mime, int width, int height, | |
461 int bitRate, int frameRate, int iFrameInterval, int colorFormat) { | |
462 MediaFormat format = MediaFormat.createVideoFormat(mime, width, height); | |
463 format.setInteger(MediaFormat.KEY_BIT_RATE, bitRate); | |
464 format.setInteger(MediaFormat.KEY_FRAME_RATE, frameRate); | |
465 format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, iFrameInterval); | |
466 format.setInteger(MediaFormat.KEY_COLOR_FORMAT, colorFormat); | |
467 return format; | |
468 } | |
469 | |
470 @CalledByNative | |
412 private static void setCodecSpecificData(MediaFormat format, int index, byte [] bytes) { | 471 private static void setCodecSpecificData(MediaFormat format, int index, byte [] bytes) { |
413 String name = null; | 472 String name = null; |
414 if (index == 0) { | 473 if (index == 0) { |
415 name = "csd-0"; | 474 name = "csd-0"; |
416 } else if (index == 1) { | 475 } else if (index == 1) { |
417 name = "csd-1"; | 476 name = "csd-1"; |
418 } | 477 } |
419 if (name != null) { | 478 if (name != null) { |
420 format.setByteBuffer(name, ByteBuffer.wrap(bytes)); | 479 format.setByteBuffer(name, ByteBuffer.wrap(bytes)); |
421 } | 480 } |
(...skipping 16 matching lines...) Expand all Loading... | |
438 AudioFormat.CHANNEL_OUT_STEREO; | 497 AudioFormat.CHANNEL_OUT_STEREO; |
439 // Using 16bit PCM for output. Keep this value in sync with | 498 // Using 16bit PCM for output. Keep this value in sync with |
440 // kBytesPerAudioOutputSample in media_codec_bridge.cc. | 499 // kBytesPerAudioOutputSample in media_codec_bridge.cc. |
441 int minBufferSize = AudioTrack.getMinBufferSize(sampleRate, chan nelConfig, | 500 int minBufferSize = AudioTrack.getMinBufferSize(sampleRate, chan nelConfig, |
442 AudioFormat.ENCODING_PCM_16BIT); | 501 AudioFormat.ENCODING_PCM_16BIT); |
443 mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRa te, channelConfig, | 502 mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRa te, channelConfig, |
444 AudioFormat.ENCODING_PCM_16BIT, minBufferSize, AudioTrac k.MODE_STREAM); | 503 AudioFormat.ENCODING_PCM_16BIT, minBufferSize, AudioTrac k.MODE_STREAM); |
445 } | 504 } |
446 return true; | 505 return true; |
447 } catch (IllegalStateException e) { | 506 } catch (IllegalStateException e) { |
448 Log.e(TAG, "Cannot configure the audio codec " + e.toString()); | 507 Log.e(TAG, "Cannot configure the audio codec", e); |
449 } | 508 } |
450 return false; | 509 return false; |
451 } | 510 } |
452 | 511 |
453 @CalledByNative | 512 @CalledByNative |
454 private void playOutputBuffer(byte[] buf) { | 513 private void playOutputBuffer(byte[] buf) { |
455 if (mAudioTrack != null) { | 514 if (mAudioTrack != null) { |
456 if (AudioTrack.PLAYSTATE_PLAYING != mAudioTrack.getPlayState()) { | 515 if (AudioTrack.PLAYSTATE_PLAYING != mAudioTrack.getPlayState()) { |
457 mAudioTrack.play(); | 516 mAudioTrack.play(); |
458 } | 517 } |
(...skipping 13 matching lines...) Expand all Loading... | |
472 } | 531 } |
473 | 532 |
474 private void resetLastPresentationTimeIfNeeded(long presentationTimeUs) { | 533 private void resetLastPresentationTimeIfNeeded(long presentationTimeUs) { |
475 if (mFlushed) { | 534 if (mFlushed) { |
476 mLastPresentationTimeUs = | 535 mLastPresentationTimeUs = |
477 Math.max(presentationTimeUs - MAX_PRESENTATION_TIMESTAMP_SHI FT_US, 0); | 536 Math.max(presentationTimeUs - MAX_PRESENTATION_TIMESTAMP_SHI FT_US, 0); |
478 mFlushed = false; | 537 mFlushed = false; |
479 } | 538 } |
480 } | 539 } |
481 } | 540 } |
OLD | NEW |