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

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

Powered by Google App Engine
This is Rietveld 408576698