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

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

Issue 1396073003: Prepare MediaCodecVideoEncoder for surface textures. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Self review 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 106
107 // Helper struct for findHwEncoder() below. 107 // Helper struct for findHwEncoder() below.
108 private static class EncoderProperties { 108 private static class EncoderProperties {
109 public EncoderProperties(String codecName, int colorFormat) { 109 public EncoderProperties(String codecName, int colorFormat) {
110 this.codecName = codecName; 110 this.codecName = codecName;
111 this.colorFormat = colorFormat; 111 this.colorFormat = colorFormat;
112 } 112 }
113 public final String codecName; // OpenMax component name for HW codec. 113 public final String codecName; // OpenMax component name for HW codec.
114 public final int colorFormat; // Color format supported by codec. 114 public final int colorFormat; // Color format supported by codec.
115 } 115 }
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
200 static MediaCodec createByCodecName(String codecName) { 200 static MediaCodec createByCodecName(String codecName) {
201 try { 201 try {
202 // In the L-SDK this call can throw IOException so in order to work in 202 // In the L-SDK this call can throw IOException so in order to work in
203 // both cases catch an exception. 203 // both cases catch an exception.
204 return MediaCodec.createByCodecName(codecName); 204 return MediaCodec.createByCodecName(codecName);
205 } catch (Exception e) { 205 } catch (Exception e) {
206 return null; 206 return null;
207 } 207 }
208 } 208 }
209 209
210 // Return the array of input buffers, or null on failure. 210 boolean initEncode(VideoCodecType type, int width, int height, int kbps, int f ps) {
magjed_webrtc 2015/10/12 08:22:53 Add short comment about return value, e.g. "Return
perkj_webrtc 2015/10/12 09:16:06 Done.
211 private ByteBuffer[] initEncode(
212 VideoCodecType type, int width, int height, int kbps, int fps) {
213 Logging.d(TAG, "Java initEncode: " + type + " : " + width + " x " + height + 211 Logging.d(TAG, "Java initEncode: " + type + " : " + width + " x " + height +
214 ". @ " + kbps + " kbps. Fps: " + fps + 212 ". @ " + kbps + " kbps. Fps: " + fps + ".");
215 ". Color: 0x" + Integer.toHexString(colorFormat)); 213
216 if (mediaCodecThread != null) { 214 if (mediaCodecThread != null) {
217 throw new RuntimeException("Forgot to release()?"); 215 throw new RuntimeException("Forgot to release()?");
218 } 216 }
219 this.type = type;
220 EncoderProperties properties = null; 217 EncoderProperties properties = null;
221 String mime = null; 218 String mime = null;
222 int keyFrameIntervalSec = 0; 219 int keyFrameIntervalSec = 0;
223 if (type == VideoCodecType.VIDEO_CODEC_VP8) { 220 if (type == VideoCodecType.VIDEO_CODEC_VP8) {
224 mime = VP8_MIME_TYPE; 221 mime = VP8_MIME_TYPE;
225 properties = findHwEncoder(VP8_MIME_TYPE, supportedVp8HwCodecPrefixes); 222 properties = findHwEncoder(VP8_MIME_TYPE, supportedVp8HwCodecPrefixes);
226 keyFrameIntervalSec = 100; 223 keyFrameIntervalSec = 100;
227 } else if (type == VideoCodecType.VIDEO_CODEC_H264) { 224 } else if (type == VideoCodecType.VIDEO_CODEC_H264) {
228 mime = H264_MIME_TYPE; 225 mime = H264_MIME_TYPE;
229 properties = findHwEncoder(H264_MIME_TYPE, supportedH264HwCodecPrefixes); 226 properties = findHwEncoder(H264_MIME_TYPE, supportedH264HwCodecPrefixes);
230 keyFrameIntervalSec = 20; 227 keyFrameIntervalSec = 20;
231 } 228 }
232 if (properties == null) { 229 if (properties == null) {
233 throw new RuntimeException("Can not find HW encoder for " + type); 230 throw new RuntimeException("Can not find HW encoder for " + type);
234 } 231 }
232 colorFormat = properties.colorFormat;
235 mediaCodecThread = Thread.currentThread(); 233 mediaCodecThread = Thread.currentThread();
236 try { 234 try {
237 MediaFormat format = MediaFormat.createVideoFormat(mime, width, height); 235 MediaFormat format = MediaFormat.createVideoFormat(mime, width, height);
238 format.setInteger(MediaFormat.KEY_BIT_RATE, 1000 * kbps); 236 format.setInteger(MediaFormat.KEY_BIT_RATE, 1000 * kbps);
239 format.setInteger("bitrate-mode", VIDEO_ControlRateConstant); 237 format.setInteger("bitrate-mode", VIDEO_ControlRateConstant);
240 format.setInteger(MediaFormat.KEY_COLOR_FORMAT, properties.colorFormat); 238 format.setInteger(MediaFormat.KEY_COLOR_FORMAT, properties.colorFormat);
241 format.setInteger(MediaFormat.KEY_FRAME_RATE, fps); 239 format.setInteger(MediaFormat.KEY_FRAME_RATE, fps);
242 format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, keyFrameIntervalSec); 240 format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, keyFrameIntervalSec);
243 Logging.d(TAG, " Format: " + format); 241 Logging.d(TAG, " Format: " + format);
244 mediaCodec = createByCodecName(properties.codecName); 242 mediaCodec = createByCodecName(properties.codecName);
243 this.type = type;
245 if (mediaCodec == null) { 244 if (mediaCodec == null) {
246 return null; 245 return false;
247 } 246 }
248 mediaCodec.configure( 247 mediaCodec.configure(
249 format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE); 248 format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
249
250 mediaCodec.start(); 250 mediaCodec.start();
251 colorFormat = properties.colorFormat;
252 outputBuffers = mediaCodec.getOutputBuffers(); 251 outputBuffers = mediaCodec.getOutputBuffers();
253 ByteBuffer[] inputBuffers = mediaCodec.getInputBuffers(); 252
254 Logging.d(TAG, "Input buffers: " + inputBuffers.length +
255 ". Output buffers: " + outputBuffers.length);
256 return inputBuffers;
257 } catch (IllegalStateException e) { 253 } catch (IllegalStateException e) {
258 Logging.e(TAG, "initEncode failed", e); 254 Logging.e(TAG, "initEncode failed", e);
259 return null; 255 return false;
260 } 256 }
257 return true;
261 } 258 }
262 259
263 private boolean encode( 260 ByteBuffer[] getInputBuffers() {
261 ByteBuffer[] inputBuffers = mediaCodec.getInputBuffers();
262 Logging.d(TAG, "Input buffers: " + inputBuffers.length);
263 return inputBuffers;
264 }
265
266 boolean encodeBuffer(
264 boolean isKeyframe, int inputBuffer, int size, 267 boolean isKeyframe, int inputBuffer, int size,
265 long presentationTimestampUs) { 268 long presentationTimestampUs) {
266 checkOnMediaCodecThread(); 269 checkOnMediaCodecThread();
267 try { 270 try {
268 if (isKeyframe) { 271 if (isKeyframe) {
269 // Ideally MediaCodec would honor BUFFER_FLAG_SYNC_FRAME so we could 272 // Ideally MediaCodec would honor BUFFER_FLAG_SYNC_FRAME so we could
270 // indicate this in queueInputBuffer() below and guarantee _this_ frame 273 // indicate this in queueInputBuffer() below and guarantee _this_ frame
271 // be encoded as a key frame, but sadly that flag is ignored. Instead, 274 // be encoded as a key frame, but sadly that flag is ignored. Instead,
272 // we request a key frame "soon". 275 // we request a key frame "soon".
273 Logging.d(TAG, "Sync frame request"); 276 Logging.d(TAG, "Sync frame request");
274 Bundle b = new Bundle(); 277 Bundle b = new Bundle();
275 b.putInt(MediaCodec.PARAMETER_KEY_REQUEST_SYNC_FRAME, 0); 278 b.putInt(MediaCodec.PARAMETER_KEY_REQUEST_SYNC_FRAME, 0);
276 mediaCodec.setParameters(b); 279 mediaCodec.setParameters(b);
277 } 280 }
278 mediaCodec.queueInputBuffer( 281 mediaCodec.queueInputBuffer(
279 inputBuffer, 0, size, presentationTimestampUs, 0); 282 inputBuffer, 0, size, presentationTimestampUs, 0);
280 return true; 283 return true;
281 } 284 }
282 catch (IllegalStateException e) { 285 catch (IllegalStateException e) {
283 Logging.e(TAG, "encode failed", e); 286 Logging.e(TAG, "encodeBuffer failed", e);
284 return false; 287 return false;
285 } 288 }
286 } 289 }
287 290
288 private void release() { 291 void release() {
289 Logging.d(TAG, "Java releaseEncoder"); 292 Logging.d(TAG, "Java releaseEncoder");
290 checkOnMediaCodecThread(); 293 checkOnMediaCodecThread();
291 try { 294 try {
292 mediaCodec.stop(); 295 mediaCodec.stop();
293 mediaCodec.release(); 296 mediaCodec.release();
294 } catch (IllegalStateException e) { 297 } catch (IllegalStateException e) {
295 Logging.e(TAG, "release failed", e); 298 Logging.e(TAG, "release failed", e);
296 } 299 }
297 mediaCodec = null; 300 mediaCodec = null;
298 mediaCodecThread = null; 301 mediaCodecThread = null;
(...skipping 10 matching lines...) Expand all
309 mediaCodec.setParameters(params); 312 mediaCodec.setParameters(params);
310 return true; 313 return true;
311 } catch (IllegalStateException e) { 314 } catch (IllegalStateException e) {
312 Logging.e(TAG, "setRates failed", e); 315 Logging.e(TAG, "setRates failed", e);
313 return false; 316 return false;
314 } 317 }
315 } 318 }
316 319
317 // Dequeue an input buffer and return its index, -1 if no input buffer is 320 // Dequeue an input buffer and return its index, -1 if no input buffer is
318 // available, or -2 if the codec is no longer operative. 321 // available, or -2 if the codec is no longer operative.
319 private int dequeueInputBuffer() { 322 int dequeueInputBuffer() {
320 checkOnMediaCodecThread(); 323 checkOnMediaCodecThread();
321 try { 324 try {
322 return mediaCodec.dequeueInputBuffer(DEQUEUE_TIMEOUT); 325 return mediaCodec.dequeueInputBuffer(DEQUEUE_TIMEOUT);
323 } catch (IllegalStateException e) { 326 } catch (IllegalStateException e) {
324 Logging.e(TAG, "dequeueIntputBuffer failed", e); 327 Logging.e(TAG, "dequeueIntputBuffer failed", e);
325 return -2; 328 return -2;
326 } 329 }
327 } 330 }
328 331
329 // Helper struct for dequeueOutputBuffer() below. 332 // Helper struct for dequeueOutputBuffer() below.
330 private static class OutputBufferInfo { 333 static class OutputBufferInfo {
331 public OutputBufferInfo( 334 public OutputBufferInfo(
332 int index, ByteBuffer buffer, 335 int index, ByteBuffer buffer,
333 boolean isKeyFrame, long presentationTimestampUs) { 336 boolean isKeyFrame, long presentationTimestampUs) {
334 this.index = index; 337 this.index = index;
335 this.buffer = buffer; 338 this.buffer = buffer;
336 this.isKeyFrame = isKeyFrame; 339 this.isKeyFrame = isKeyFrame;
337 this.presentationTimestampUs = presentationTimestampUs; 340 this.presentationTimestampUs = presentationTimestampUs;
338 } 341 }
339 342
340 private final int index; 343 public final int index;
341 private final ByteBuffer buffer; 344 public final ByteBuffer buffer;
342 private final boolean isKeyFrame; 345 public final boolean isKeyFrame;
343 private final long presentationTimestampUs; 346 public final long presentationTimestampUs;
344 } 347 }
345 348
346 // Dequeue and return an output buffer, or null if no output is ready. Return 349 // Dequeue and return an output buffer, or null if no output is ready. Return
347 // a fake OutputBufferInfo with index -1 if the codec is no longer operable. 350 // a fake OutputBufferInfo with index -1 if the codec is no longer operable.
348 private OutputBufferInfo dequeueOutputBuffer() { 351 OutputBufferInfo dequeueOutputBuffer() {
349 checkOnMediaCodecThread(); 352 checkOnMediaCodecThread();
350 try { 353 try {
351 MediaCodec.BufferInfo info = new MediaCodec.BufferInfo(); 354 MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
352 int result = mediaCodec.dequeueOutputBuffer(info, DEQUEUE_TIMEOUT); 355 int result = mediaCodec.dequeueOutputBuffer(info, DEQUEUE_TIMEOUT);
353 // Check if this is config frame and save configuration data. 356 // Check if this is config frame and save configuration data.
354 if (result >= 0) { 357 if (result >= 0) {
355 boolean isConfigFrame = 358 boolean isConfigFrame =
356 (info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0; 359 (info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0;
357 if (isConfigFrame) { 360 if (isConfigFrame) {
358 Logging.d(TAG, "Config frame generated. Offset: " + info.offset + 361 Logging.d(TAG, "Config frame generated. Offset: " + info.offset +
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
407 } 410 }
408 throw new RuntimeException("dequeueOutputBuffer: " + result); 411 throw new RuntimeException("dequeueOutputBuffer: " + result);
409 } catch (IllegalStateException e) { 412 } catch (IllegalStateException e) {
410 Logging.e(TAG, "dequeueOutputBuffer failed", e); 413 Logging.e(TAG, "dequeueOutputBuffer failed", e);
411 return new OutputBufferInfo(-1, null, false, -1); 414 return new OutputBufferInfo(-1, null, false, -1);
412 } 415 }
413 } 416 }
414 417
415 // Release a dequeued output buffer back to the codec for re-use. Return 418 // Release a dequeued output buffer back to the codec for re-use. Return
416 // false if the codec is no longer operable. 419 // false if the codec is no longer operable.
417 private boolean releaseOutputBuffer(int index) { 420 boolean releaseOutputBuffer(int index) {
418 checkOnMediaCodecThread(); 421 checkOnMediaCodecThread();
419 try { 422 try {
420 mediaCodec.releaseOutputBuffer(index, false); 423 mediaCodec.releaseOutputBuffer(index, false);
421 return true; 424 return true;
422 } catch (IllegalStateException e) { 425 } catch (IllegalStateException e) {
423 Logging.e(TAG, "releaseOutputBuffer failed", e); 426 Logging.e(TAG, "releaseOutputBuffer failed", e);
424 return false; 427 return false;
425 } 428 }
426 } 429 }
427 } 430 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698