Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(187)

Side by Side Diff: talk/app/webrtc/java/src/org/webrtc/MediaCodecVideoDecoder.java

Issue 1343163003: Partial revert of r9936. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc@master
Patch Set: Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * libjingle 2 * libjingle
3 * Copyright 2014 Google Inc. 3 * Copyright 2014 Google Inc.
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met: 6 * modification, are permitted provided that the following conditions are met:
7 * 7 *
8 * 1. Redistributions of source code must retain the above copyright notice, 8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer. 9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice, 10 * 2. Redistributions in binary form must reproduce the above copyright notice,
(...skipping 15 matching lines...) Expand all
26 */ 26 */
27 27
28 package org.webrtc; 28 package org.webrtc;
29 29
30 import android.graphics.SurfaceTexture; 30 import android.graphics.SurfaceTexture;
31 import android.media.MediaCodec; 31 import android.media.MediaCodec;
32 import android.media.MediaCodecInfo; 32 import android.media.MediaCodecInfo;
33 import android.media.MediaCodecInfo.CodecCapabilities; 33 import android.media.MediaCodecInfo.CodecCapabilities;
34 import android.media.MediaCodecList; 34 import android.media.MediaCodecList;
35 import android.media.MediaFormat; 35 import android.media.MediaFormat;
36 import android.opengl.EGL14;
37 import android.opengl.EGLContext; 36 import android.opengl.EGLContext;
38 import android.opengl.GLES11Ext; 37 import android.opengl.GLES11Ext;
39 import android.opengl.GLES20; 38 import android.opengl.GLES20;
40 import android.os.Build; 39 import android.os.Build;
40 import android.util.Log;
41 import android.view.Surface; 41 import android.view.Surface;
42 42
43 import org.webrtc.Logging;
44
45 import java.nio.ByteBuffer; 43 import java.nio.ByteBuffer;
46 44
47 // Java-side of peerconnection_jni.cc:MediaCodecVideoDecoder. 45 // Java-side of peerconnection_jni.cc:MediaCodecVideoDecoder.
48 // This class is an implementation detail of the Java PeerConnection API. 46 // This class is an implementation detail of the Java PeerConnection API.
49 // MediaCodec is thread-hostile so this class must be operated on a single 47 // MediaCodec is thread-hostile so this class must be operated on a single
50 // thread. 48 // thread.
51 public class MediaCodecVideoDecoder { 49 public class MediaCodecVideoDecoder {
52 // This class is constructed, operated, and destroyed by its C++ incarnation, 50 // This class is constructed, operated, and destroyed by its C++ incarnation,
53 // so the class and its methods have non-public visibility. The API this 51 // so the class and its methods have non-public visibility. The API this
54 // class exposes aims to mimic the webrtc::VideoDecoder API as closely as 52 // class exposes aims to mimic the webrtc::VideoDecoder API as closely as
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
123 String name = null; 121 String name = null;
124 for (String mimeType : info.getSupportedTypes()) { 122 for (String mimeType : info.getSupportedTypes()) {
125 if (mimeType.equals(mime)) { 123 if (mimeType.equals(mime)) {
126 name = info.getName(); 124 name = info.getName();
127 break; 125 break;
128 } 126 }
129 } 127 }
130 if (name == null) { 128 if (name == null) {
131 continue; // No HW support in this codec; try the next one. 129 continue; // No HW support in this codec; try the next one.
132 } 130 }
133 Logging.v(TAG, "Found candidate decoder " + name); 131 Log.v(TAG, "Found candidate decoder " + name);
134 132
135 // Check if this is supported decoder. 133 // Check if this is supported decoder.
136 boolean supportedCodec = false; 134 boolean supportedCodec = false;
137 for (String codecPrefix : supportedCodecPrefixes) { 135 for (String codecPrefix : supportedCodecPrefixes) {
138 if (name.startsWith(codecPrefix)) { 136 if (name.startsWith(codecPrefix)) {
139 supportedCodec = true; 137 supportedCodec = true;
140 break; 138 break;
141 } 139 }
142 } 140 }
143 if (!supportedCodec) { 141 if (!supportedCodec) {
144 continue; 142 continue;
145 } 143 }
146 144
147 // Check if codec supports either yuv420 or nv12. 145 // Check if codec supports either yuv420 or nv12.
148 CodecCapabilities capabilities = 146 CodecCapabilities capabilities =
149 info.getCapabilitiesForType(mime); 147 info.getCapabilitiesForType(mime);
150 for (int colorFormat : capabilities.colorFormats) { 148 for (int colorFormat : capabilities.colorFormats) {
151 Logging.v(TAG, " Color: 0x" + Integer.toHexString(colorFormat)); 149 Log.v(TAG, " Color: 0x" + Integer.toHexString(colorFormat));
152 } 150 }
153 for (int supportedColorFormat : supportedColorList) { 151 for (int supportedColorFormat : supportedColorList) {
154 for (int codecColorFormat : capabilities.colorFormats) { 152 for (int codecColorFormat : capabilities.colorFormats) {
155 if (codecColorFormat == supportedColorFormat) { 153 if (codecColorFormat == supportedColorFormat) {
156 // Found supported HW decoder. 154 // Found supported HW decoder.
157 Logging.d(TAG, "Found target decoder " + name + 155 Log.d(TAG, "Found target decoder " + name +
158 ". Color: 0x" + Integer.toHexString(codecColorFormat)); 156 ". Color: 0x" + Integer.toHexString(codecColorFormat));
159 return new DecoderProperties(name, codecColorFormat); 157 return new DecoderProperties(name, codecColorFormat);
160 } 158 }
161 } 159 }
162 } 160 }
163 } 161 }
164 return null; // No HW decoder. 162 return null; // No HW decoder.
165 } 163 }
166 164
167 public static boolean isVp8HwSupported() { 165 public static boolean isVp8HwSupported() {
(...skipping 29 matching lines...) Expand all
197 } else if (type == VideoCodecType.VIDEO_CODEC_H264) { 195 } else if (type == VideoCodecType.VIDEO_CODEC_H264) {
198 mime = H264_MIME_TYPE; 196 mime = H264_MIME_TYPE;
199 supportedCodecPrefixes = supportedH264HwCodecPrefixes; 197 supportedCodecPrefixes = supportedH264HwCodecPrefixes;
200 } else { 198 } else {
201 throw new RuntimeException("Non supported codec " + type); 199 throw new RuntimeException("Non supported codec " + type);
202 } 200 }
203 DecoderProperties properties = findDecoder(mime, supportedCodecPrefixes); 201 DecoderProperties properties = findDecoder(mime, supportedCodecPrefixes);
204 if (properties == null) { 202 if (properties == null) {
205 throw new RuntimeException("Cannot find HW decoder for " + type); 203 throw new RuntimeException("Cannot find HW decoder for " + type);
206 } 204 }
207 Logging.d(TAG, "Java initDecode: " + type + " : "+ width + " x " + height + 205 Log.d(TAG, "Java initDecode: " + type + " : "+ width + " x " + height +
208 ". Color: 0x" + Integer.toHexString(properties.colorFormat) + 206 ". Color: 0x" + Integer.toHexString(properties.colorFormat) +
209 ". Use Surface: " + useSurface); 207 ". Use Surface: " + useSurface);
210 if (sharedContext != null) { 208 if (sharedContext != null) {
211 Logging.d(TAG, "Decoder shared EGL Context: " + sharedContext); 209 Log.d(TAG, "Decoder shared EGL Context: " + sharedContext);
212 } 210 }
213 mediaCodecThread = Thread.currentThread(); 211 mediaCodecThread = Thread.currentThread();
214 try { 212 try {
215 Surface decodeSurface = null; 213 Surface decodeSurface = null;
216 this.width = width; 214 this.width = width;
217 this.height = height; 215 this.height = height;
218 this.useSurface = useSurface; 216 this.useSurface = useSurface;
219 stride = width; 217 stride = width;
220 sliceHeight = height; 218 sliceHeight = height;
221 219
222 if (useSurface) { 220 if (useSurface) {
223 // Create shared EGL context. 221 // Create shared EGL context.
224 eglBase = new EglBase(sharedContext, EglBase.ConfigType.PIXEL_BUFFER); 222 eglBase = new EglBase(sharedContext, EglBase.ConfigType.PIXEL_BUFFER);
225 eglBase.createDummyPbufferSurface(); 223 eglBase.createDummyPbufferSurface();
226 eglBase.makeCurrent(); 224 eglBase.makeCurrent();
227 225
228 // Create output surface 226 // Create output surface
229 textureID = GlUtil.generateTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES); 227 textureID = GlUtil.generateTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES);
230 Logging.d(TAG, "Video decoder TextureID = " + textureID); 228 Log.d(TAG, "Video decoder TextureID = " + textureID);
231 surfaceTexture = new SurfaceTexture(textureID); 229 surfaceTexture = new SurfaceTexture(textureID);
232 surface = new Surface(surfaceTexture); 230 surface = new Surface(surfaceTexture);
233 decodeSurface = surface; 231 decodeSurface = surface;
234 } 232 }
235 233
236 MediaFormat format = MediaFormat.createVideoFormat(mime, width, height); 234 MediaFormat format = MediaFormat.createVideoFormat(mime, width, height);
237 if (!useSurface) { 235 if (!useSurface) {
238 format.setInteger(MediaFormat.KEY_COLOR_FORMAT, properties.colorFormat); 236 format.setInteger(MediaFormat.KEY_COLOR_FORMAT, properties.colorFormat);
239 } 237 }
240 Logging.d(TAG, " Format: " + format); 238 Log.d(TAG, " Format: " + format);
241 mediaCodec = 239 mediaCodec =
242 MediaCodecVideoEncoder.createByCodecName(properties.codecName); 240 MediaCodecVideoEncoder.createByCodecName(properties.codecName);
243 if (mediaCodec == null) { 241 if (mediaCodec == null) {
244 return false; 242 return false;
245 } 243 }
246 mediaCodec.configure(format, decodeSurface, null, 0); 244 mediaCodec.configure(format, decodeSurface, null, 0);
247 mediaCodec.start(); 245 mediaCodec.start();
248 colorFormat = properties.colorFormat; 246 colorFormat = properties.colorFormat;
249 outputBuffers = mediaCodec.getOutputBuffers(); 247 outputBuffers = mediaCodec.getOutputBuffers();
250 inputBuffers = mediaCodec.getInputBuffers(); 248 inputBuffers = mediaCodec.getInputBuffers();
251 Logging.d(TAG, "Input buffers: " + inputBuffers.length + 249 Log.d(TAG, "Input buffers: " + inputBuffers.length +
252 ". Output buffers: " + outputBuffers.length); 250 ". Output buffers: " + outputBuffers.length);
253 return true; 251 return true;
254 } catch (IllegalStateException e) { 252 } catch (IllegalStateException e) {
255 Logging.e(TAG, "initDecode failed", e); 253 Log.e(TAG, "initDecode failed", e);
256 return false; 254 return false;
257 } 255 }
258 } 256 }
259 257
260 private void release() { 258 private void release() {
261 Logging.d(TAG, "Java releaseDecoder"); 259 Log.d(TAG, "Java releaseDecoder");
262 checkOnMediaCodecThread(); 260 checkOnMediaCodecThread();
263 try { 261 try {
264 mediaCodec.stop(); 262 mediaCodec.stop();
265 mediaCodec.release(); 263 mediaCodec.release();
266 } catch (IllegalStateException e) { 264 } catch (IllegalStateException e) {
267 Logging.e(TAG, "release failed", e); 265 Log.e(TAG, "release failed", e);
268 } 266 }
269 mediaCodec = null; 267 mediaCodec = null;
270 mediaCodecThread = null; 268 mediaCodecThread = null;
271 if (useSurface) { 269 if (useSurface) {
272 surface.release(); 270 surface.release();
273 if (textureID != 0) { 271 if (textureID != 0) {
274 Logging.d(TAG, "Delete video decoder TextureID " + textureID); 272 Log.d(TAG, "Delete video decoder TextureID " + textureID);
275 GLES20.glDeleteTextures(1, new int[] {textureID}, 0); 273 GLES20.glDeleteTextures(1, new int[] {textureID}, 0);
276 textureID = 0; 274 textureID = 0;
277 } 275 }
278 eglBase.release(); 276 eglBase.release();
279 eglBase = null; 277 eglBase = null;
280 } 278 }
281 } 279 }
282 280
283 // Dequeue an input buffer and return its index, -1 if no input buffer is 281 // Dequeue an input buffer and return its index, -1 if no input buffer is
284 // available, or -2 if the codec is no longer operative. 282 // available, or -2 if the codec is no longer operative.
285 private int dequeueInputBuffer() { 283 private int dequeueInputBuffer() {
286 checkOnMediaCodecThread(); 284 checkOnMediaCodecThread();
287 try { 285 try {
288 return mediaCodec.dequeueInputBuffer(DEQUEUE_INPUT_TIMEOUT); 286 return mediaCodec.dequeueInputBuffer(DEQUEUE_INPUT_TIMEOUT);
289 } catch (IllegalStateException e) { 287 } catch (IllegalStateException e) {
290 Logging.e(TAG, "dequeueIntputBuffer failed", e); 288 Log.e(TAG, "dequeueIntputBuffer failed", e);
291 return -2; 289 return -2;
292 } 290 }
293 } 291 }
294 292
295 private boolean queueInputBuffer( 293 private boolean queueInputBuffer(
296 int inputBufferIndex, int size, long timestampUs) { 294 int inputBufferIndex, int size, long timestampUs) {
297 checkOnMediaCodecThread(); 295 checkOnMediaCodecThread();
298 try { 296 try {
299 inputBuffers[inputBufferIndex].position(0); 297 inputBuffers[inputBufferIndex].position(0);
300 inputBuffers[inputBufferIndex].limit(size); 298 inputBuffers[inputBufferIndex].limit(size);
301 mediaCodec.queueInputBuffer(inputBufferIndex, 0, size, timestampUs, 0); 299 mediaCodec.queueInputBuffer(inputBufferIndex, 0, size, timestampUs, 0);
302 return true; 300 return true;
303 } 301 }
304 catch (IllegalStateException e) { 302 catch (IllegalStateException e) {
305 Logging.e(TAG, "decode failed", e); 303 Log.e(TAG, "decode failed", e);
306 return false; 304 return false;
307 } 305 }
308 } 306 }
309 307
310 // Helper struct for dequeueOutputBuffer() below. 308 // Helper struct for dequeueOutputBuffer() below.
311 private static class DecoderOutputBufferInfo { 309 private static class DecoderOutputBufferInfo {
312 public DecoderOutputBufferInfo( 310 public DecoderOutputBufferInfo(
313 int index, int offset, int size, long presentationTimestampUs) { 311 int index, int offset, int size, long presentationTimestampUs) {
314 this.index = index; 312 this.index = index;
315 this.offset = offset; 313 this.offset = offset;
(...skipping 11 matching lines...) Expand all
327 // buffer available or -2 if error happened. 325 // buffer available or -2 if error happened.
328 private DecoderOutputBufferInfo dequeueOutputBuffer(int dequeueTimeoutUs) { 326 private DecoderOutputBufferInfo dequeueOutputBuffer(int dequeueTimeoutUs) {
329 checkOnMediaCodecThread(); 327 checkOnMediaCodecThread();
330 try { 328 try {
331 MediaCodec.BufferInfo info = new MediaCodec.BufferInfo(); 329 MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
332 int result = mediaCodec.dequeueOutputBuffer(info, dequeueTimeoutUs); 330 int result = mediaCodec.dequeueOutputBuffer(info, dequeueTimeoutUs);
333 while (result == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED || 331 while (result == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED ||
334 result == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { 332 result == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
335 if (result == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) { 333 if (result == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
336 outputBuffers = mediaCodec.getOutputBuffers(); 334 outputBuffers = mediaCodec.getOutputBuffers();
337 Logging.d(TAG, "Decoder output buffers changed: " + outputBuffers.leng th); 335 Log.d(TAG, "Decoder output buffers changed: " + outputBuffers.length);
338 } else if (result == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { 336 } else if (result == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
339 MediaFormat format = mediaCodec.getOutputFormat(); 337 MediaFormat format = mediaCodec.getOutputFormat();
340 Logging.d(TAG, "Decoder format changed: " + format.toString()); 338 Log.d(TAG, "Decoder format changed: " + format.toString());
341 width = format.getInteger(MediaFormat.KEY_WIDTH); 339 width = format.getInteger(MediaFormat.KEY_WIDTH);
342 height = format.getInteger(MediaFormat.KEY_HEIGHT); 340 height = format.getInteger(MediaFormat.KEY_HEIGHT);
343 if (!useSurface && format.containsKey(MediaFormat.KEY_COLOR_FORMAT)) { 341 if (!useSurface && format.containsKey(MediaFormat.KEY_COLOR_FORMAT)) {
344 colorFormat = format.getInteger(MediaFormat.KEY_COLOR_FORMAT); 342 colorFormat = format.getInteger(MediaFormat.KEY_COLOR_FORMAT);
345 Logging.d(TAG, "Color: 0x" + Integer.toHexString(colorFormat)); 343 Log.d(TAG, "Color: 0x" + Integer.toHexString(colorFormat));
346 // Check if new color space is supported. 344 // Check if new color space is supported.
347 boolean validColorFormat = false; 345 boolean validColorFormat = false;
348 for (int supportedColorFormat : supportedColorList) { 346 for (int supportedColorFormat : supportedColorList) {
349 if (colorFormat == supportedColorFormat) { 347 if (colorFormat == supportedColorFormat) {
350 validColorFormat = true; 348 validColorFormat = true;
351 break; 349 break;
352 } 350 }
353 } 351 }
354 if (!validColorFormat) { 352 if (!validColorFormat) {
355 Logging.e(TAG, "Non supported color format"); 353 Log.e(TAG, "Non supported color format");
356 return new DecoderOutputBufferInfo(-1, 0, 0, -1); 354 return new DecoderOutputBufferInfo(-1, 0, 0, -1);
357 } 355 }
358 } 356 }
359 if (format.containsKey("stride")) { 357 if (format.containsKey("stride")) {
360 stride = format.getInteger("stride"); 358 stride = format.getInteger("stride");
361 } 359 }
362 if (format.containsKey("slice-height")) { 360 if (format.containsKey("slice-height")) {
363 sliceHeight = format.getInteger("slice-height"); 361 sliceHeight = format.getInteger("slice-height");
364 } 362 }
365 Logging.d(TAG, "Frame stride and slice height: " 363 Log.d(TAG, "Frame stride and slice height: "
366 + stride + " x " + sliceHeight); 364 + stride + " x " + sliceHeight);
367 stride = Math.max(width, stride); 365 stride = Math.max(width, stride);
368 sliceHeight = Math.max(height, sliceHeight); 366 sliceHeight = Math.max(height, sliceHeight);
369 } 367 }
370 result = mediaCodec.dequeueOutputBuffer(info, dequeueTimeoutUs); 368 result = mediaCodec.dequeueOutputBuffer(info, dequeueTimeoutUs);
371 } 369 }
372 if (result >= 0) { 370 if (result >= 0) {
373 return new DecoderOutputBufferInfo(result, info.offset, info.size, 371 return new DecoderOutputBufferInfo(result, info.offset, info.size,
374 info.presentationTimeUs); 372 info.presentationTimeUs);
375 } 373 }
376 return null; 374 return null;
377 } catch (IllegalStateException e) { 375 } catch (IllegalStateException e) {
378 Logging.e(TAG, "dequeueOutputBuffer failed", e); 376 Log.e(TAG, "dequeueOutputBuffer failed", e);
379 return new DecoderOutputBufferInfo(-1, 0, 0, -1); 377 return new DecoderOutputBufferInfo(-1, 0, 0, -1);
380 } 378 }
381 } 379 }
382 380
383 // Release a dequeued output buffer back to the codec for re-use. Return 381 // Release a dequeued output buffer back to the codec for re-use. Return
384 // false if the codec is no longer operable. 382 // false if the codec is no longer operable.
385 private boolean releaseOutputBuffer(int index, boolean render) { 383 private boolean releaseOutputBuffer(int index, boolean render) {
386 checkOnMediaCodecThread(); 384 checkOnMediaCodecThread();
387 try { 385 try {
388 if (!useSurface) { 386 if (!useSurface) {
389 render = false; 387 render = false;
390 } 388 }
391 mediaCodec.releaseOutputBuffer(index, render); 389 mediaCodec.releaseOutputBuffer(index, render);
392 return true; 390 return true;
393 } catch (IllegalStateException e) { 391 } catch (IllegalStateException e) {
394 Logging.e(TAG, "releaseOutputBuffer failed", e); 392 Log.e(TAG, "releaseOutputBuffer failed", e);
395 return false; 393 return false;
396 } 394 }
397 } 395 }
398 } 396 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698