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

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

Issue 1406203002: Reland "Prepare MediaCodecVideoEncoder for surface textures."" (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Moved getting inputbuffer to before storing pending frames. Created 5 years, 2 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 2013 Google Inc. 3 * Copyright 2013 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 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
89 // see /hardware/qcom/media/mm-core/inc/OMX_QCOMExtns.h 89 // see /hardware/qcom/media/mm-core/inc/OMX_QCOMExtns.h
90 private static final int 90 private static final int
91 COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m = 0x7FA30C04; 91 COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m = 0x7FA30C04;
92 // Allowable color formats supported by codec - in order of preference. 92 // Allowable color formats supported by codec - in order of preference.
93 private static final int[] supportedColorList = { 93 private static final int[] supportedColorList = {
94 CodecCapabilities.COLOR_FormatYUV420Planar, 94 CodecCapabilities.COLOR_FormatYUV420Planar,
95 CodecCapabilities.COLOR_FormatYUV420SemiPlanar, 95 CodecCapabilities.COLOR_FormatYUV420SemiPlanar,
96 CodecCapabilities.COLOR_QCOM_FormatYUV420SemiPlanar, 96 CodecCapabilities.COLOR_QCOM_FormatYUV420SemiPlanar,
97 COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m 97 COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m
98 }; 98 };
99 private int colorFormat;
100 // Video encoder type.
101 private VideoCodecType type; 99 private VideoCodecType type;
100 private int colorFormat; // Used by native code.
101
102 // SPS and PPS NALs (Config frame) for H.264. 102 // SPS and PPS NALs (Config frame) for H.264.
103 private ByteBuffer configData = null; 103 private ByteBuffer configData = null;
104 104
105 private MediaCodecVideoEncoder() { 105 MediaCodecVideoEncoder() {
106 instance = this; 106 instance = this;
107 } 107 }
108 108
109 // Helper struct for findHwEncoder() below. 109 // Helper struct for findHwEncoder() below.
110 private static class EncoderProperties { 110 private static class EncoderProperties {
111 public EncoderProperties(String codecName, int colorFormat) { 111 public EncoderProperties(String codecName, int colorFormat) {
112 this.codecName = codecName; 112 this.codecName = codecName;
113 this.colorFormat = colorFormat; 113 this.colorFormat = colorFormat;
114 } 114 }
115 public final String codecName; // OpenMax component name for HW codec. 115 public final String codecName; // OpenMax component name for HW codec.
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after
214 static MediaCodec createByCodecName(String codecName) { 214 static MediaCodec createByCodecName(String codecName) {
215 try { 215 try {
216 // In the L-SDK this call can throw IOException so in order to work in 216 // In the L-SDK this call can throw IOException so in order to work in
217 // both cases catch an exception. 217 // both cases catch an exception.
218 return MediaCodec.createByCodecName(codecName); 218 return MediaCodec.createByCodecName(codecName);
219 } catch (Exception e) { 219 } catch (Exception e) {
220 return null; 220 return null;
221 } 221 }
222 } 222 }
223 223
224 // Return the array of input buffers, or null on failure. 224 // Returns false if the hardware encoder currently can't be used.
225 private ByteBuffer[] initEncode( 225 boolean initEncode(VideoCodecType type, int width, int height, int kbps, int f ps) {
226 VideoCodecType type, int width, int height, int kbps, int fps) {
227 Logging.d(TAG, "Java initEncode: " + type + " : " + width + " x " + height + 226 Logging.d(TAG, "Java initEncode: " + type + " : " + width + " x " + height +
228 ". @ " + kbps + " kbps. Fps: " + fps + 227 ". @ " + kbps + " kbps. Fps: " + fps + ".");
229 ". Color: 0x" + Integer.toHexString(colorFormat)); 228
230 if (mediaCodecThread != null) { 229 if (mediaCodecThread != null) {
231 throw new RuntimeException("Forgot to release()?"); 230 throw new RuntimeException("Forgot to release()?");
232 } 231 }
233 this.type = type;
234 EncoderProperties properties = null; 232 EncoderProperties properties = null;
235 String mime = null; 233 String mime = null;
236 int keyFrameIntervalSec = 0; 234 int keyFrameIntervalSec = 0;
237 if (type == VideoCodecType.VIDEO_CODEC_VP8) { 235 if (type == VideoCodecType.VIDEO_CODEC_VP8) {
238 mime = VP8_MIME_TYPE; 236 mime = VP8_MIME_TYPE;
239 properties = findHwEncoder(VP8_MIME_TYPE, supportedVp8HwCodecPrefixes); 237 properties = findHwEncoder(VP8_MIME_TYPE, supportedVp8HwCodecPrefixes);
240 keyFrameIntervalSec = 100; 238 keyFrameIntervalSec = 100;
241 } else if (type == VideoCodecType.VIDEO_CODEC_H264) { 239 } else if (type == VideoCodecType.VIDEO_CODEC_H264) {
242 mime = H264_MIME_TYPE; 240 mime = H264_MIME_TYPE;
243 properties = findHwEncoder(H264_MIME_TYPE, supportedH264HwCodecPrefixes); 241 properties = findHwEncoder(H264_MIME_TYPE, supportedH264HwCodecPrefixes);
244 keyFrameIntervalSec = 20; 242 keyFrameIntervalSec = 20;
245 } 243 }
246 if (properties == null) { 244 if (properties == null) {
247 throw new RuntimeException("Can not find HW encoder for " + type); 245 throw new RuntimeException("Can not find HW encoder for " + type);
248 } 246 }
247 colorFormat = properties.colorFormat;
AlexG 2015/10/19 23:38:45 Print color format in the log for debug purposes?
249 mediaCodecThread = Thread.currentThread(); 248 mediaCodecThread = Thread.currentThread();
250 try { 249 try {
251 MediaFormat format = MediaFormat.createVideoFormat(mime, width, height); 250 MediaFormat format = MediaFormat.createVideoFormat(mime, width, height);
252 format.setInteger(MediaFormat.KEY_BIT_RATE, 1000 * kbps); 251 format.setInteger(MediaFormat.KEY_BIT_RATE, 1000 * kbps);
253 format.setInteger("bitrate-mode", VIDEO_ControlRateConstant); 252 format.setInteger("bitrate-mode", VIDEO_ControlRateConstant);
254 format.setInteger(MediaFormat.KEY_COLOR_FORMAT, properties.colorFormat); 253 format.setInteger(MediaFormat.KEY_COLOR_FORMAT, properties.colorFormat);
255 format.setInteger(MediaFormat.KEY_FRAME_RATE, fps); 254 format.setInteger(MediaFormat.KEY_FRAME_RATE, fps);
256 format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, keyFrameIntervalSec); 255 format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, keyFrameIntervalSec);
257 Logging.d(TAG, " Format: " + format); 256 Logging.d(TAG, " Format: " + format);
258 mediaCodec = createByCodecName(properties.codecName); 257 mediaCodec = createByCodecName(properties.codecName);
258 this.type = type;
259 if (mediaCodec == null) { 259 if (mediaCodec == null) {
260 Logging.e(TAG, "Can not create media encoder"); 260 Logging.e(TAG, "Can not create media encoder");
261 return null; 261 return false;
262 } 262 }
263 mediaCodec.configure( 263 mediaCodec.configure(
264 format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE); 264 format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
265
265 mediaCodec.start(); 266 mediaCodec.start();
266 colorFormat = properties.colorFormat;
267 outputBuffers = mediaCodec.getOutputBuffers(); 267 outputBuffers = mediaCodec.getOutputBuffers();
AlexG 2015/10/19 23:38:45 Print outputBuffers.length for debug purposes?
268 ByteBuffer[] inputBuffers = mediaCodec.getInputBuffers(); 268
269 Logging.d(TAG, "Input buffers: " + inputBuffers.length +
270 ". Output buffers: " + outputBuffers.length);
271 return inputBuffers;
272 } catch (IllegalStateException e) { 269 } catch (IllegalStateException e) {
273 Logging.e(TAG, "initEncode failed", e); 270 Logging.e(TAG, "initEncode failed", e);
274 return null; 271 return false;
275 } 272 }
273 return true;
276 } 274 }
277 275
278 private boolean encode( 276 ByteBuffer[] getInputBuffers() {
277 ByteBuffer[] inputBuffers = mediaCodec.getInputBuffers();
278 Logging.d(TAG, "Input buffers: " + inputBuffers.length);
279 return inputBuffers;
280 }
281
282 boolean encodeBuffer(
279 boolean isKeyframe, int inputBuffer, int size, 283 boolean isKeyframe, int inputBuffer, int size,
280 long presentationTimestampUs) { 284 long presentationTimestampUs) {
281 checkOnMediaCodecThread(); 285 checkOnMediaCodecThread();
282 try { 286 try {
283 if (isKeyframe) { 287 if (isKeyframe) {
284 // Ideally MediaCodec would honor BUFFER_FLAG_SYNC_FRAME so we could 288 // Ideally MediaCodec would honor BUFFER_FLAG_SYNC_FRAME so we could
285 // indicate this in queueInputBuffer() below and guarantee _this_ frame 289 // indicate this in queueInputBuffer() below and guarantee _this_ frame
286 // be encoded as a key frame, but sadly that flag is ignored. Instead, 290 // be encoded as a key frame, but sadly that flag is ignored. Instead,
287 // we request a key frame "soon". 291 // we request a key frame "soon".
288 Logging.d(TAG, "Sync frame request"); 292 Logging.d(TAG, "Sync frame request");
289 Bundle b = new Bundle(); 293 Bundle b = new Bundle();
290 b.putInt(MediaCodec.PARAMETER_KEY_REQUEST_SYNC_FRAME, 0); 294 b.putInt(MediaCodec.PARAMETER_KEY_REQUEST_SYNC_FRAME, 0);
291 mediaCodec.setParameters(b); 295 mediaCodec.setParameters(b);
292 } 296 }
293 mediaCodec.queueInputBuffer( 297 mediaCodec.queueInputBuffer(
294 inputBuffer, 0, size, presentationTimestampUs, 0); 298 inputBuffer, 0, size, presentationTimestampUs, 0);
295 return true; 299 return true;
296 } 300 }
297 catch (IllegalStateException e) { 301 catch (IllegalStateException e) {
298 Logging.e(TAG, "encode failed", e); 302 Logging.e(TAG, "encodeBuffer failed", e);
299 return false; 303 return false;
300 } 304 }
301 } 305 }
302 306
303 private void release() { 307 void release() {
304 Logging.d(TAG, "Java releaseEncoder"); 308 Logging.d(TAG, "Java releaseEncoder");
305 checkOnMediaCodecThread(); 309 checkOnMediaCodecThread();
306 try { 310 try {
307 mediaCodec.stop(); 311 mediaCodec.stop();
308 mediaCodec.release(); 312 mediaCodec.release();
309 } catch (IllegalStateException e) { 313 } catch (IllegalStateException e) {
310 Logging.e(TAG, "release failed", e); 314 Logging.e(TAG, "release failed", e);
311 } 315 }
312 mediaCodec = null; 316 mediaCodec = null;
313 mediaCodecThread = null; 317 mediaCodecThread = null;
(...skipping 12 matching lines...) Expand all
326 mediaCodec.setParameters(params); 330 mediaCodec.setParameters(params);
327 return true; 331 return true;
328 } catch (IllegalStateException e) { 332 } catch (IllegalStateException e) {
329 Logging.e(TAG, "setRates failed", e); 333 Logging.e(TAG, "setRates failed", e);
330 return false; 334 return false;
331 } 335 }
332 } 336 }
333 337
334 // Dequeue an input buffer and return its index, -1 if no input buffer is 338 // Dequeue an input buffer and return its index, -1 if no input buffer is
335 // available, or -2 if the codec is no longer operative. 339 // available, or -2 if the codec is no longer operative.
336 private int dequeueInputBuffer() { 340 int dequeueInputBuffer() {
337 checkOnMediaCodecThread(); 341 checkOnMediaCodecThread();
338 try { 342 try {
339 return mediaCodec.dequeueInputBuffer(DEQUEUE_TIMEOUT); 343 return mediaCodec.dequeueInputBuffer(DEQUEUE_TIMEOUT);
340 } catch (IllegalStateException e) { 344 } catch (IllegalStateException e) {
341 Logging.e(TAG, "dequeueIntputBuffer failed", e); 345 Logging.e(TAG, "dequeueIntputBuffer failed", e);
342 return -2; 346 return -2;
343 } 347 }
344 } 348 }
345 349
346 // Helper struct for dequeueOutputBuffer() below. 350 // Helper struct for dequeueOutputBuffer() below.
347 private static class OutputBufferInfo { 351 static class OutputBufferInfo {
348 public OutputBufferInfo( 352 public OutputBufferInfo(
349 int index, ByteBuffer buffer, 353 int index, ByteBuffer buffer,
350 boolean isKeyFrame, long presentationTimestampUs) { 354 boolean isKeyFrame, long presentationTimestampUs) {
351 this.index = index; 355 this.index = index;
352 this.buffer = buffer; 356 this.buffer = buffer;
353 this.isKeyFrame = isKeyFrame; 357 this.isKeyFrame = isKeyFrame;
354 this.presentationTimestampUs = presentationTimestampUs; 358 this.presentationTimestampUs = presentationTimestampUs;
355 } 359 }
356 360
357 private final int index; 361 public final int index;
358 private final ByteBuffer buffer; 362 public final ByteBuffer buffer;
359 private final boolean isKeyFrame; 363 public final boolean isKeyFrame;
360 private final long presentationTimestampUs; 364 public final long presentationTimestampUs;
361 } 365 }
362 366
363 // Dequeue and return an output buffer, or null if no output is ready. Return 367 // Dequeue and return an output buffer, or null if no output is ready. Return
364 // a fake OutputBufferInfo with index -1 if the codec is no longer operable. 368 // a fake OutputBufferInfo with index -1 if the codec is no longer operable.
365 private OutputBufferInfo dequeueOutputBuffer() { 369 OutputBufferInfo dequeueOutputBuffer() {
366 checkOnMediaCodecThread(); 370 checkOnMediaCodecThread();
367 try { 371 try {
368 MediaCodec.BufferInfo info = new MediaCodec.BufferInfo(); 372 MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
369 int result = mediaCodec.dequeueOutputBuffer(info, DEQUEUE_TIMEOUT); 373 int result = mediaCodec.dequeueOutputBuffer(info, DEQUEUE_TIMEOUT);
370 // Check if this is config frame and save configuration data. 374 // Check if this is config frame and save configuration data.
371 if (result >= 0) { 375 if (result >= 0) {
372 boolean isConfigFrame = 376 boolean isConfigFrame =
373 (info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0; 377 (info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0;
374 if (isConfigFrame) { 378 if (isConfigFrame) {
375 Logging.d(TAG, "Config frame generated. Offset: " + info.offset + 379 Logging.d(TAG, "Config frame generated. Offset: " + info.offset +
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
424 } 428 }
425 throw new RuntimeException("dequeueOutputBuffer: " + result); 429 throw new RuntimeException("dequeueOutputBuffer: " + result);
426 } catch (IllegalStateException e) { 430 } catch (IllegalStateException e) {
427 Logging.e(TAG, "dequeueOutputBuffer failed", e); 431 Logging.e(TAG, "dequeueOutputBuffer failed", e);
428 return new OutputBufferInfo(-1, null, false, -1); 432 return new OutputBufferInfo(-1, null, false, -1);
429 } 433 }
430 } 434 }
431 435
432 // Release a dequeued output buffer back to the codec for re-use. Return 436 // Release a dequeued output buffer back to the codec for re-use. Return
433 // false if the codec is no longer operable. 437 // false if the codec is no longer operable.
434 private boolean releaseOutputBuffer(int index) { 438 boolean releaseOutputBuffer(int index) {
435 checkOnMediaCodecThread(); 439 checkOnMediaCodecThread();
436 try { 440 try {
437 mediaCodec.releaseOutputBuffer(index, false); 441 mediaCodec.releaseOutputBuffer(index, false);
438 return true; 442 return true;
439 } catch (IllegalStateException e) { 443 } catch (IllegalStateException e) {
440 Logging.e(TAG, "releaseOutputBuffer failed", e); 444 Logging.e(TAG, "releaseOutputBuffer failed", e);
441 return false; 445 return false;
442 } 446 }
443 } 447 }
444 } 448 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698