OLD | NEW |
1 /* | 1 /* |
2 * libjingle | 2 * libjingle |
3 * Copyright 2015 Google Inc. | 3 * Copyright 2015 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 222 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
233 jni, j_decoder_decoded_byte_buffer_class, "index", "I"); | 233 jni, j_decoder_decoded_byte_buffer_class, "index", "I"); |
234 j_info_offset_field_ = GetFieldID( | 234 j_info_offset_field_ = GetFieldID( |
235 jni, j_decoder_decoded_byte_buffer_class, "offset", "I"); | 235 jni, j_decoder_decoded_byte_buffer_class, "offset", "I"); |
236 j_info_size_field_ = GetFieldID( | 236 j_info_size_field_ = GetFieldID( |
237 jni, j_decoder_decoded_byte_buffer_class, "size", "I"); | 237 jni, j_decoder_decoded_byte_buffer_class, "size", "I"); |
238 j_info_presentation_timestamp_us_field_ = GetFieldID( | 238 j_info_presentation_timestamp_us_field_ = GetFieldID( |
239 jni, j_decoder_decoded_byte_buffer_class, "presentationTimestampUs", "J"); | 239 jni, j_decoder_decoded_byte_buffer_class, "presentationTimestampUs", "J"); |
240 | 240 |
241 CHECK_EXCEPTION(jni) << "MediaCodecVideoDecoder ctor failed"; | 241 CHECK_EXCEPTION(jni) << "MediaCodecVideoDecoder ctor failed"; |
242 use_surface_ = (render_egl_context_ != NULL); | 242 use_surface_ = (render_egl_context_ != NULL); |
243 ALOGD("MediaCodecVideoDecoder ctor. Use surface: %d", use_surface_); | 243 ALOGD << "MediaCodecVideoDecoder ctor. Use surface: " << use_surface_; |
244 memset(&codec_, 0, sizeof(codec_)); | 244 memset(&codec_, 0, sizeof(codec_)); |
245 AllowBlockingCalls(); | 245 AllowBlockingCalls(); |
246 } | 246 } |
247 | 247 |
248 MediaCodecVideoDecoder::~MediaCodecVideoDecoder() { | 248 MediaCodecVideoDecoder::~MediaCodecVideoDecoder() { |
249 // Call Release() to ensure no more callbacks to us after we are deleted. | 249 // Call Release() to ensure no more callbacks to us after we are deleted. |
250 Release(); | 250 Release(); |
251 } | 251 } |
252 | 252 |
253 int32_t MediaCodecVideoDecoder::InitDecode(const VideoCodec* inst, | 253 int32_t MediaCodecVideoDecoder::InitDecode(const VideoCodec* inst, |
254 int32_t numberOfCores) { | 254 int32_t numberOfCores) { |
255 ALOGD("InitDecode."); | 255 ALOGD << "InitDecode."; |
256 if (inst == NULL) { | 256 if (inst == NULL) { |
257 ALOGE("NULL VideoCodec instance"); | 257 ALOGE << "NULL VideoCodec instance"; |
258 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; | 258 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; |
259 } | 259 } |
260 // Factory should guard against other codecs being used with us. | 260 // Factory should guard against other codecs being used with us. |
261 RTC_CHECK(inst->codecType == codecType_) | 261 RTC_CHECK(inst->codecType == codecType_) |
262 << "Unsupported codec " << inst->codecType << " for " << codecType_; | 262 << "Unsupported codec " << inst->codecType << " for " << codecType_; |
263 | 263 |
264 if (sw_fallback_required_) { | 264 if (sw_fallback_required_) { |
265 ALOGE("InitDecode() - fallback to SW decoder"); | 265 ALOGE << "InitDecode() - fallback to SW decoder"; |
266 return WEBRTC_VIDEO_CODEC_OK; | 266 return WEBRTC_VIDEO_CODEC_OK; |
267 } | 267 } |
268 // Save VideoCodec instance for later. | 268 // Save VideoCodec instance for later. |
269 if (&codec_ != inst) { | 269 if (&codec_ != inst) { |
270 codec_ = *inst; | 270 codec_ = *inst; |
271 } | 271 } |
272 codec_.maxFramerate = (codec_.maxFramerate >= 1) ? codec_.maxFramerate : 1; | 272 codec_.maxFramerate = (codec_.maxFramerate >= 1) ? codec_.maxFramerate : 1; |
273 | 273 |
274 // Call Java init. | 274 // Call Java init. |
275 return codec_thread_->Invoke<int32_t>( | 275 return codec_thread_->Invoke<int32_t>( |
276 Bind(&MediaCodecVideoDecoder::InitDecodeOnCodecThread, this)); | 276 Bind(&MediaCodecVideoDecoder::InitDecodeOnCodecThread, this)); |
277 } | 277 } |
278 | 278 |
279 int32_t MediaCodecVideoDecoder::InitDecodeOnCodecThread() { | 279 int32_t MediaCodecVideoDecoder::InitDecodeOnCodecThread() { |
280 CheckOnCodecThread(); | 280 CheckOnCodecThread(); |
281 JNIEnv* jni = AttachCurrentThreadIfNeeded(); | 281 JNIEnv* jni = AttachCurrentThreadIfNeeded(); |
282 ScopedLocalRefFrame local_ref_frame(jni); | 282 ScopedLocalRefFrame local_ref_frame(jni); |
283 ALOGD("InitDecodeOnCodecThread Type: %d. %d x %d. Fps: %d.", | 283 ALOGD << "InitDecodeOnCodecThread Type: " << (int)codecType_ << ". " |
284 (int)codecType_, codec_.width, codec_.height, | 284 << codec_.width << " x " << codec_.height << ". Fps: " << |
285 codec_.maxFramerate); | 285 (int)codec_.maxFramerate; |
286 | 286 |
287 // Release previous codec first if it was allocated before. | 287 // Release previous codec first if it was allocated before. |
288 int ret_val = ReleaseOnCodecThread(); | 288 int ret_val = ReleaseOnCodecThread(); |
289 if (ret_val < 0) { | 289 if (ret_val < 0) { |
290 ALOGE("Release failure: %d - fallback to SW codec", ret_val); | 290 ALOGE << "Release failure: " << ret_val << " - fallback to SW codec"; |
291 sw_fallback_required_ = true; | 291 sw_fallback_required_ = true; |
292 return WEBRTC_VIDEO_CODEC_ERROR; | 292 return WEBRTC_VIDEO_CODEC_ERROR; |
293 } | 293 } |
294 | 294 |
295 // Always start with a complete key frame. | 295 // Always start with a complete key frame. |
296 key_frame_required_ = true; | 296 key_frame_required_ = true; |
297 frames_received_ = 0; | 297 frames_received_ = 0; |
298 frames_decoded_ = 0; | 298 frames_decoded_ = 0; |
299 | 299 |
300 if (use_surface_) { | 300 if (use_surface_) { |
301 surface_texture_helper_ = new rtc::RefCountedObject<SurfaceTextureHelper>( | 301 surface_texture_helper_ = new rtc::RefCountedObject<SurfaceTextureHelper>( |
302 jni, render_egl_context_); | 302 jni, render_egl_context_); |
303 } | 303 } |
304 | 304 |
305 jobject j_video_codec_enum = JavaEnumFromIndex( | 305 jobject j_video_codec_enum = JavaEnumFromIndex( |
306 jni, "MediaCodecVideoDecoder$VideoCodecType", codecType_); | 306 jni, "MediaCodecVideoDecoder$VideoCodecType", codecType_); |
307 bool success = jni->CallBooleanMethod( | 307 bool success = jni->CallBooleanMethod( |
308 *j_media_codec_video_decoder_, | 308 *j_media_codec_video_decoder_, |
309 j_init_decode_method_, | 309 j_init_decode_method_, |
310 j_video_codec_enum, | 310 j_video_codec_enum, |
311 codec_.width, | 311 codec_.width, |
312 codec_.height, | 312 codec_.height, |
313 use_surface_ ? surface_texture_helper_->GetJavaSurfaceTextureHelper() | 313 use_surface_ ? surface_texture_helper_->GetJavaSurfaceTextureHelper() |
314 : nullptr); | 314 : nullptr); |
315 if (CheckException(jni) || !success) { | 315 if (CheckException(jni) || !success) { |
316 ALOGE("Codec initialization error - fallback to SW codec."); | 316 ALOGE << "Codec initialization error - fallback to SW codec."; |
317 sw_fallback_required_ = true; | 317 sw_fallback_required_ = true; |
318 return WEBRTC_VIDEO_CODEC_ERROR; | 318 return WEBRTC_VIDEO_CODEC_ERROR; |
319 } | 319 } |
320 inited_ = true; | 320 inited_ = true; |
321 | 321 |
322 switch (codecType_) { | 322 switch (codecType_) { |
323 case kVideoCodecVP8: | 323 case kVideoCodecVP8: |
324 max_pending_frames_ = kMaxPendingFramesVp8; | 324 max_pending_frames_ = kMaxPendingFramesVp8; |
325 break; | 325 break; |
326 case kVideoCodecH264: | 326 case kVideoCodecH264: |
(...skipping 11 matching lines...) Expand all Loading... |
338 frame_rtc_times_ms_.clear(); | 338 frame_rtc_times_ms_.clear(); |
339 | 339 |
340 jobjectArray input_buffers = (jobjectArray)GetObjectField( | 340 jobjectArray input_buffers = (jobjectArray)GetObjectField( |
341 jni, *j_media_codec_video_decoder_, j_input_buffers_field_); | 341 jni, *j_media_codec_video_decoder_, j_input_buffers_field_); |
342 size_t num_input_buffers = jni->GetArrayLength(input_buffers); | 342 size_t num_input_buffers = jni->GetArrayLength(input_buffers); |
343 input_buffers_.resize(num_input_buffers); | 343 input_buffers_.resize(num_input_buffers); |
344 for (size_t i = 0; i < num_input_buffers; ++i) { | 344 for (size_t i = 0; i < num_input_buffers; ++i) { |
345 input_buffers_[i] = | 345 input_buffers_[i] = |
346 jni->NewGlobalRef(jni->GetObjectArrayElement(input_buffers, i)); | 346 jni->NewGlobalRef(jni->GetObjectArrayElement(input_buffers, i)); |
347 if (CheckException(jni)) { | 347 if (CheckException(jni)) { |
348 ALOGE("NewGlobalRef error - fallback to SW codec."); | 348 ALOGE << "NewGlobalRef error - fallback to SW codec."; |
349 sw_fallback_required_ = true; | 349 sw_fallback_required_ = true; |
350 return WEBRTC_VIDEO_CODEC_ERROR; | 350 return WEBRTC_VIDEO_CODEC_ERROR; |
351 } | 351 } |
352 } | 352 } |
353 | 353 |
354 codec_thread_->PostDelayed(kMediaCodecPollMs, this); | 354 codec_thread_->PostDelayed(kMediaCodecPollMs, this); |
355 | 355 |
356 return WEBRTC_VIDEO_CODEC_OK; | 356 return WEBRTC_VIDEO_CODEC_OK; |
357 } | 357 } |
358 | 358 |
359 int32_t MediaCodecVideoDecoder::Release() { | 359 int32_t MediaCodecVideoDecoder::Release() { |
360 ALOGD("DecoderRelease request"); | 360 ALOGD << "DecoderRelease request"; |
361 return codec_thread_->Invoke<int32_t>( | 361 return codec_thread_->Invoke<int32_t>( |
362 Bind(&MediaCodecVideoDecoder::ReleaseOnCodecThread, this)); | 362 Bind(&MediaCodecVideoDecoder::ReleaseOnCodecThread, this)); |
363 } | 363 } |
364 | 364 |
365 int32_t MediaCodecVideoDecoder::ReleaseOnCodecThread() { | 365 int32_t MediaCodecVideoDecoder::ReleaseOnCodecThread() { |
366 if (!inited_) { | 366 if (!inited_) { |
367 return WEBRTC_VIDEO_CODEC_OK; | 367 return WEBRTC_VIDEO_CODEC_OK; |
368 } | 368 } |
369 CheckOnCodecThread(); | 369 CheckOnCodecThread(); |
370 JNIEnv* jni = AttachCurrentThreadIfNeeded(); | 370 JNIEnv* jni = AttachCurrentThreadIfNeeded(); |
371 ALOGD("DecoderReleaseOnCodecThread: Frames received: %d.", frames_received_); | 371 ALOGD << "DecoderReleaseOnCodecThread: Frames received: " << frames_received_; |
372 ScopedLocalRefFrame local_ref_frame(jni); | 372 ScopedLocalRefFrame local_ref_frame(jni); |
373 for (size_t i = 0; i < input_buffers_.size(); i++) { | 373 for (size_t i = 0; i < input_buffers_.size(); i++) { |
374 jni->DeleteGlobalRef(input_buffers_[i]); | 374 jni->DeleteGlobalRef(input_buffers_[i]); |
375 } | 375 } |
376 input_buffers_.clear(); | 376 input_buffers_.clear(); |
377 jni->CallVoidMethod(*j_media_codec_video_decoder_, j_release_method_); | 377 jni->CallVoidMethod(*j_media_codec_video_decoder_, j_release_method_); |
378 surface_texture_helper_ = nullptr; | 378 surface_texture_helper_ = nullptr; |
379 inited_ = false; | 379 inited_ = false; |
380 rtc::MessageQueueManager::Clear(this); | 380 rtc::MessageQueueManager::Clear(this); |
381 if (CheckException(jni)) { | 381 if (CheckException(jni)) { |
382 ALOGE("Decoder release exception"); | 382 ALOGE << "Decoder release exception"; |
383 return WEBRTC_VIDEO_CODEC_ERROR; | 383 return WEBRTC_VIDEO_CODEC_ERROR; |
384 } | 384 } |
| 385 ALOGD << "DecoderReleaseOnCodecThread done"; |
385 return WEBRTC_VIDEO_CODEC_OK; | 386 return WEBRTC_VIDEO_CODEC_OK; |
386 } | 387 } |
387 | 388 |
388 void MediaCodecVideoDecoder::CheckOnCodecThread() { | 389 void MediaCodecVideoDecoder::CheckOnCodecThread() { |
389 RTC_CHECK(codec_thread_ == ThreadManager::Instance()->CurrentThread()) | 390 RTC_CHECK(codec_thread_ == ThreadManager::Instance()->CurrentThread()) |
390 << "Running on wrong thread!"; | 391 << "Running on wrong thread!"; |
391 } | 392 } |
392 | 393 |
393 int32_t MediaCodecVideoDecoder::ProcessHWErrorOnCodecThread() { | 394 int32_t MediaCodecVideoDecoder::ProcessHWErrorOnCodecThread() { |
394 CheckOnCodecThread(); | 395 CheckOnCodecThread(); |
395 int ret_val = ReleaseOnCodecThread(); | 396 int ret_val = ReleaseOnCodecThread(); |
396 if (ret_val < 0) { | 397 if (ret_val < 0) { |
397 ALOGE("ProcessHWError: Release failure"); | 398 ALOGE << "ProcessHWError: Release failure"; |
398 } | 399 } |
399 if (codecType_ == kVideoCodecH264) { | 400 if (codecType_ == kVideoCodecH264) { |
400 // For now there is no SW H.264 which can be used as fallback codec. | 401 // For now there is no SW H.264 which can be used as fallback codec. |
401 // So try to restart hw codec for now. | 402 // So try to restart hw codec for now. |
402 ret_val = InitDecodeOnCodecThread(); | 403 ret_val = InitDecodeOnCodecThread(); |
403 ALOGE("Reset H.264 codec done. Status: %d", ret_val); | 404 ALOGE << "Reset H.264 codec done. Status: " << ret_val; |
404 if (ret_val == WEBRTC_VIDEO_CODEC_OK) { | 405 if (ret_val == WEBRTC_VIDEO_CODEC_OK) { |
405 // H.264 codec was succesfully reset - return regular error code. | 406 // H.264 codec was succesfully reset - return regular error code. |
406 return WEBRTC_VIDEO_CODEC_ERROR; | 407 return WEBRTC_VIDEO_CODEC_ERROR; |
407 } else { | 408 } else { |
408 // Fail to restart H.264 codec - return error code which should stop the | 409 // Fail to restart H.264 codec - return error code which should stop the |
409 // call. | 410 // call. |
410 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE; | 411 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE; |
411 } | 412 } |
412 } else { | 413 } else { |
413 sw_fallback_required_ = true; | 414 sw_fallback_required_ = true; |
414 ALOGE("Return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE"); | 415 ALOGE << "Return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE"; |
415 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE; | 416 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE; |
416 } | 417 } |
417 } | 418 } |
418 | 419 |
419 int32_t MediaCodecVideoDecoder::Decode( | 420 int32_t MediaCodecVideoDecoder::Decode( |
420 const EncodedImage& inputImage, | 421 const EncodedImage& inputImage, |
421 bool missingFrames, | 422 bool missingFrames, |
422 const RTPFragmentationHeader* fragmentation, | 423 const RTPFragmentationHeader* fragmentation, |
423 const CodecSpecificInfo* codecSpecificInfo, | 424 const CodecSpecificInfo* codecSpecificInfo, |
424 int64_t renderTimeMs) { | 425 int64_t renderTimeMs) { |
425 if (sw_fallback_required_) { | 426 if (sw_fallback_required_) { |
426 ALOGE("Decode() - fallback to SW codec"); | 427 ALOGE << "Decode() - fallback to SW codec"; |
427 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE; | 428 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE; |
428 } | 429 } |
429 if (callback_ == NULL) { | 430 if (callback_ == NULL) { |
430 ALOGE("Decode() - callback_ is NULL"); | 431 ALOGE << "Decode() - callback_ is NULL"; |
431 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; | 432 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; |
432 } | 433 } |
433 if (inputImage._buffer == NULL && inputImage._length > 0) { | 434 if (inputImage._buffer == NULL && inputImage._length > 0) { |
434 ALOGE("Decode() - inputImage is incorrect"); | 435 ALOGE << "Decode() - inputImage is incorrect"; |
435 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; | 436 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; |
436 } | 437 } |
437 if (!inited_) { | 438 if (!inited_) { |
438 ALOGE("Decode() - decoder is not initialized"); | 439 ALOGE << "Decode() - decoder is not initialized"; |
439 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; | 440 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; |
440 } | 441 } |
441 | 442 |
442 // Check if encoded frame dimension has changed. | 443 // Check if encoded frame dimension has changed. |
443 if ((inputImage._encodedWidth * inputImage._encodedHeight > 0) && | 444 if ((inputImage._encodedWidth * inputImage._encodedHeight > 0) && |
444 (inputImage._encodedWidth != codec_.width || | 445 (inputImage._encodedWidth != codec_.width || |
445 inputImage._encodedHeight != codec_.height)) { | 446 inputImage._encodedHeight != codec_.height)) { |
446 codec_.width = inputImage._encodedWidth; | 447 codec_.width = inputImage._encodedWidth; |
447 codec_.height = inputImage._encodedHeight; | 448 codec_.height = inputImage._encodedHeight; |
448 int32_t ret = InitDecode(&codec_, 1); | 449 int32_t ret = InitDecode(&codec_, 1); |
449 if (ret < 0) { | 450 if (ret < 0) { |
450 ALOGE("InitDecode failure: %d - fallback to SW codec", ret); | 451 ALOGE << "InitDecode failure: " << ret << " - fallback to SW codec"; |
451 sw_fallback_required_ = true; | 452 sw_fallback_required_ = true; |
452 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE; | 453 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE; |
453 } | 454 } |
454 } | 455 } |
455 | 456 |
456 // Always start with a complete key frame. | 457 // Always start with a complete key frame. |
457 if (key_frame_required_) { | 458 if (key_frame_required_) { |
458 if (inputImage._frameType != webrtc::kKeyFrame) { | 459 if (inputImage._frameType != webrtc::kKeyFrame) { |
459 ALOGE("Decode() - key frame is required"); | 460 ALOGE << "Decode() - key frame is required"; |
460 return WEBRTC_VIDEO_CODEC_ERROR; | 461 return WEBRTC_VIDEO_CODEC_ERROR; |
461 } | 462 } |
462 if (!inputImage._completeFrame) { | 463 if (!inputImage._completeFrame) { |
463 ALOGE("Decode() - complete frame is required"); | 464 ALOGE << "Decode() - complete frame is required"; |
464 return WEBRTC_VIDEO_CODEC_ERROR; | 465 return WEBRTC_VIDEO_CODEC_ERROR; |
465 } | 466 } |
466 key_frame_required_ = false; | 467 key_frame_required_ = false; |
467 } | 468 } |
468 if (inputImage._length == 0) { | 469 if (inputImage._length == 0) { |
469 return WEBRTC_VIDEO_CODEC_ERROR; | 470 return WEBRTC_VIDEO_CODEC_ERROR; |
470 } | 471 } |
471 | 472 |
472 return codec_thread_->Invoke<int32_t>(Bind( | 473 return codec_thread_->Invoke<int32_t>(Bind( |
473 &MediaCodecVideoDecoder::DecodeOnCodecThread, this, inputImage)); | 474 &MediaCodecVideoDecoder::DecodeOnCodecThread, this, inputImage)); |
474 } | 475 } |
475 | 476 |
476 int32_t MediaCodecVideoDecoder::DecodeOnCodecThread( | 477 int32_t MediaCodecVideoDecoder::DecodeOnCodecThread( |
477 const EncodedImage& inputImage) { | 478 const EncodedImage& inputImage) { |
478 CheckOnCodecThread(); | 479 CheckOnCodecThread(); |
479 JNIEnv* jni = AttachCurrentThreadIfNeeded(); | 480 JNIEnv* jni = AttachCurrentThreadIfNeeded(); |
480 ScopedLocalRefFrame local_ref_frame(jni); | 481 ScopedLocalRefFrame local_ref_frame(jni); |
481 | 482 |
482 // Try to drain the decoder and wait until output is not too | 483 // Try to drain the decoder and wait until output is not too |
483 // much behind the input. | 484 // much behind the input. |
484 if (frames_received_ > frames_decoded_ + max_pending_frames_) { | 485 if (frames_received_ > frames_decoded_ + max_pending_frames_) { |
485 ALOGV("Received: %d. Decoded: %d. Wait for output...", | 486 ALOGV("Received: %d. Decoded: %d. Wait for output...", |
486 frames_received_, frames_decoded_); | 487 frames_received_, frames_decoded_); |
487 if (!DeliverPendingOutputs(jni, kMediaCodecTimeoutMs)) { | 488 if (!DeliverPendingOutputs(jni, kMediaCodecTimeoutMs)) { |
488 ALOGE("DeliverPendingOutputs error"); | 489 ALOGE << "DeliverPendingOutputs error"; |
489 return ProcessHWErrorOnCodecThread(); | 490 return ProcessHWErrorOnCodecThread(); |
490 } | 491 } |
491 if (frames_received_ > frames_decoded_ + max_pending_frames_) { | 492 if (frames_received_ > frames_decoded_ + max_pending_frames_) { |
492 ALOGE("Output buffer dequeue timeout"); | 493 ALOGE << "Output buffer dequeue timeout"; |
493 return ProcessHWErrorOnCodecThread(); | 494 return ProcessHWErrorOnCodecThread(); |
494 } | 495 } |
495 } | 496 } |
496 | 497 |
497 // Get input buffer. | 498 // Get input buffer. |
498 int j_input_buffer_index = jni->CallIntMethod(*j_media_codec_video_decoder_, | 499 int j_input_buffer_index = jni->CallIntMethod(*j_media_codec_video_decoder_, |
499 j_dequeue_input_buffer_method_); | 500 j_dequeue_input_buffer_method_); |
500 if (CheckException(jni) || j_input_buffer_index < 0) { | 501 if (CheckException(jni) || j_input_buffer_index < 0) { |
501 ALOGE("dequeueInputBuffer error"); | 502 ALOGE << "dequeueInputBuffer error"; |
502 return ProcessHWErrorOnCodecThread(); | 503 return ProcessHWErrorOnCodecThread(); |
503 } | 504 } |
504 | 505 |
505 // Copy encoded data to Java ByteBuffer. | 506 // Copy encoded data to Java ByteBuffer. |
506 jobject j_input_buffer = input_buffers_[j_input_buffer_index]; | 507 jobject j_input_buffer = input_buffers_[j_input_buffer_index]; |
507 uint8_t* buffer = | 508 uint8_t* buffer = |
508 reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress(j_input_buffer)); | 509 reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress(j_input_buffer)); |
509 RTC_CHECK(buffer) << "Indirect buffer??"; | 510 RTC_CHECK(buffer) << "Indirect buffer??"; |
510 int64_t buffer_capacity = jni->GetDirectBufferCapacity(j_input_buffer); | 511 int64_t buffer_capacity = jni->GetDirectBufferCapacity(j_input_buffer); |
511 if (CheckException(jni) || buffer_capacity < inputImage._length) { | 512 if (CheckException(jni) || buffer_capacity < inputImage._length) { |
512 ALOGE("Input frame size %d is bigger than buffer size %d.", | 513 ALOGE << "Input frame size "<< inputImage._length << |
513 inputImage._length, buffer_capacity); | 514 " is bigger than buffer size " << buffer_capacity; |
514 return ProcessHWErrorOnCodecThread(); | 515 return ProcessHWErrorOnCodecThread(); |
515 } | 516 } |
516 jlong timestamp_us = (frames_received_ * 1000000) / codec_.maxFramerate; | 517 jlong timestamp_us = (frames_received_ * 1000000) / codec_.maxFramerate; |
517 ALOGV("Decoder frame in # %d. Type: %d. Buffer # %d. TS: %lld. Size: %d", | 518 ALOGV("Decoder frame in # %d. Type: %d. Buffer # %d. TS: %lld. Size: %d", |
518 frames_received_, inputImage._frameType, j_input_buffer_index, | 519 frames_received_, inputImage._frameType, j_input_buffer_index, |
519 timestamp_us / 1000, inputImage._length); | 520 timestamp_us / 1000, inputImage._length); |
520 memcpy(buffer, inputImage._buffer, inputImage._length); | 521 memcpy(buffer, inputImage._buffer, inputImage._length); |
521 | 522 |
522 // Save input image timestamps for later output. | 523 // Save input image timestamps for later output. |
523 frames_received_++; | 524 frames_received_++; |
524 current_bytes_ += inputImage._length; | 525 current_bytes_ += inputImage._length; |
525 timestamps_.push_back(inputImage._timeStamp); | 526 timestamps_.push_back(inputImage._timeStamp); |
526 ntp_times_ms_.push_back(inputImage.ntp_time_ms_); | 527 ntp_times_ms_.push_back(inputImage.ntp_time_ms_); |
527 frame_rtc_times_ms_.push_back(GetCurrentTimeMs()); | 528 frame_rtc_times_ms_.push_back(GetCurrentTimeMs()); |
528 | 529 |
529 // Feed input to decoder. | 530 // Feed input to decoder. |
530 bool success = jni->CallBooleanMethod(*j_media_codec_video_decoder_, | 531 bool success = jni->CallBooleanMethod(*j_media_codec_video_decoder_, |
531 j_queue_input_buffer_method_, | 532 j_queue_input_buffer_method_, |
532 j_input_buffer_index, | 533 j_input_buffer_index, |
533 inputImage._length, | 534 inputImage._length, |
534 timestamp_us); | 535 timestamp_us); |
535 if (CheckException(jni) || !success) { | 536 if (CheckException(jni) || !success) { |
536 ALOGE("queueInputBuffer error"); | 537 ALOGE << "queueInputBuffer error"; |
537 return ProcessHWErrorOnCodecThread(); | 538 return ProcessHWErrorOnCodecThread(); |
538 } | 539 } |
539 | 540 |
540 // Try to drain the decoder | 541 // Try to drain the decoder |
541 if (!DeliverPendingOutputs(jni, 0)) { | 542 if (!DeliverPendingOutputs(jni, 0)) { |
542 ALOGE("DeliverPendingOutputs error"); | 543 ALOGE << "DeliverPendingOutputs error"; |
543 return ProcessHWErrorOnCodecThread(); | 544 return ProcessHWErrorOnCodecThread(); |
544 } | 545 } |
545 | 546 |
546 return WEBRTC_VIDEO_CODEC_OK; | 547 return WEBRTC_VIDEO_CODEC_OK; |
547 } | 548 } |
548 | 549 |
549 bool MediaCodecVideoDecoder::DeliverPendingOutputs( | 550 bool MediaCodecVideoDecoder::DeliverPendingOutputs( |
550 JNIEnv* jni, int dequeue_timeout_ms) { | 551 JNIEnv* jni, int dequeue_timeout_ms) { |
551 if (frames_received_ <= frames_decoded_) { | 552 if (frames_received_ <= frames_decoded_) { |
552 // No need to query for output buffers - decoder is drained. | 553 // No need to query for output buffers - decoder is drained. |
553 return true; | 554 return true; |
554 } | 555 } |
555 // Get decoder output. | 556 // Get decoder output. |
556 jobject j_decoder_output_buffer = jni->CallObjectMethod( | 557 jobject j_decoder_output_buffer = jni->CallObjectMethod( |
557 *j_media_codec_video_decoder_, | 558 *j_media_codec_video_decoder_, |
558 j_dequeue_output_buffer_method_, | 559 j_dequeue_output_buffer_method_, |
559 dequeue_timeout_ms); | 560 dequeue_timeout_ms); |
560 if (CheckException(jni)) { | 561 if (CheckException(jni)) { |
561 ALOGE("dequeueOutputBuffer() error"); | 562 ALOGE << "dequeueOutputBuffer() error"; |
562 return false; | 563 return false; |
563 } | 564 } |
564 if (IsNull(jni, j_decoder_output_buffer)) { | 565 if (IsNull(jni, j_decoder_output_buffer)) { |
565 // No decoded frame ready. | 566 // No decoded frame ready. |
566 return true; | 567 return true; |
567 } | 568 } |
568 | 569 |
569 // Get decoded video frame properties. | 570 // Get decoded video frame properties. |
570 int color_format = GetIntField(jni, *j_media_codec_video_decoder_, | 571 int color_format = GetIntField(jni, *j_media_codec_video_decoder_, |
571 j_color_format_field_); | 572 j_color_format_field_); |
(...skipping 25 matching lines...) Expand all Loading... |
597 GetIntField(jni, j_decoder_output_buffer, j_info_index_field_); | 598 GetIntField(jni, j_decoder_output_buffer, j_info_index_field_); |
598 const int output_buffer_offset = | 599 const int output_buffer_offset = |
599 GetIntField(jni, j_decoder_output_buffer, j_info_offset_field_); | 600 GetIntField(jni, j_decoder_output_buffer, j_info_offset_field_); |
600 const int output_buffer_size = | 601 const int output_buffer_size = |
601 GetIntField(jni, j_decoder_output_buffer, j_info_size_field_); | 602 GetIntField(jni, j_decoder_output_buffer, j_info_size_field_); |
602 const int64_t timestamp_us = GetLongField( | 603 const int64_t timestamp_us = GetLongField( |
603 jni, j_decoder_output_buffer, j_info_presentation_timestamp_us_field_); | 604 jni, j_decoder_output_buffer, j_info_presentation_timestamp_us_field_); |
604 output_timestamps_ms = timestamp_us / rtc::kNumMicrosecsPerMillisec; | 605 output_timestamps_ms = timestamp_us / rtc::kNumMicrosecsPerMillisec; |
605 | 606 |
606 if (output_buffer_size < width * height * 3 / 2) { | 607 if (output_buffer_size < width * height * 3 / 2) { |
607 ALOGE("Insufficient output buffer size: %d", output_buffer_size); | 608 ALOGE << "Insufficient output buffer size: " << output_buffer_size; |
608 return false; | 609 return false; |
609 } | 610 } |
610 jobjectArray output_buffers = reinterpret_cast<jobjectArray>(GetObjectField( | 611 jobjectArray output_buffers = reinterpret_cast<jobjectArray>(GetObjectField( |
611 jni, *j_media_codec_video_decoder_, j_output_buffers_field_)); | 612 jni, *j_media_codec_video_decoder_, j_output_buffers_field_)); |
612 jobject output_buffer = | 613 jobject output_buffer = |
613 jni->GetObjectArrayElement(output_buffers, output_buffer_index); | 614 jni->GetObjectArrayElement(output_buffers, output_buffer_index); |
614 uint8_t* payload = reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress( | 615 uint8_t* payload = reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress( |
615 output_buffer)); | 616 output_buffer)); |
616 if (CheckException(jni)) { | 617 if (CheckException(jni)) { |
617 return false; | 618 return false; |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
652 frame_buffer->MutableData(webrtc::kVPlane), | 653 frame_buffer->MutableData(webrtc::kVPlane), |
653 frame_buffer->stride(webrtc::kVPlane), | 654 frame_buffer->stride(webrtc::kVPlane), |
654 width, height); | 655 width, height); |
655 } | 656 } |
656 // Return output byte buffer back to codec. | 657 // Return output byte buffer back to codec. |
657 jni->CallVoidMethod( | 658 jni->CallVoidMethod( |
658 *j_media_codec_video_decoder_, | 659 *j_media_codec_video_decoder_, |
659 j_return_decoded_byte_buffer_method_, | 660 j_return_decoded_byte_buffer_method_, |
660 output_buffer_index); | 661 output_buffer_index); |
661 if (CheckException(jni)) { | 662 if (CheckException(jni)) { |
662 ALOGE("returnDecodedByteBuffer error"); | 663 ALOGE << "returnDecodedByteBuffer error"; |
663 return false; | 664 return false; |
664 } | 665 } |
665 } | 666 } |
666 VideoFrame decoded_frame(frame_buffer, 0, 0, webrtc::kVideoRotation_0); | 667 VideoFrame decoded_frame(frame_buffer, 0, 0, webrtc::kVideoRotation_0); |
667 | 668 |
668 // Get frame timestamps from a queue. | 669 // Get frame timestamps from a queue. |
669 if (timestamps_.size() > 0) { | 670 if (timestamps_.size() > 0) { |
670 decoded_frame.set_timestamp(timestamps_.front()); | 671 decoded_frame.set_timestamp(timestamps_.front()); |
671 timestamps_.erase(timestamps_.begin()); | 672 timestamps_.erase(timestamps_.begin()); |
672 } | 673 } |
(...skipping 10 matching lines...) Expand all Loading... |
683 " DecTime: %lld", frames_decoded_, width, height, stride, slice_height, | 684 " DecTime: %lld", frames_decoded_, width, height, stride, slice_height, |
684 color_format, output_timestamps_ms, frame_decoding_time_ms); | 685 color_format, output_timestamps_ms, frame_decoding_time_ms); |
685 | 686 |
686 // Calculate and print decoding statistics - every 3 seconds. | 687 // Calculate and print decoding statistics - every 3 seconds. |
687 frames_decoded_++; | 688 frames_decoded_++; |
688 current_frames_++; | 689 current_frames_++; |
689 current_decoding_time_ms_ += frame_decoding_time_ms; | 690 current_decoding_time_ms_ += frame_decoding_time_ms; |
690 int statistic_time_ms = GetCurrentTimeMs() - start_time_ms_; | 691 int statistic_time_ms = GetCurrentTimeMs() - start_time_ms_; |
691 if (statistic_time_ms >= kMediaCodecStatisticsIntervalMs && | 692 if (statistic_time_ms >= kMediaCodecStatisticsIntervalMs && |
692 current_frames_ > 0) { | 693 current_frames_ > 0) { |
693 ALOGD("Decoder bitrate: %d kbps, fps: %d, decTime: %d for last %d ms", | 694 ALOGD << "Decoded frames: " << frames_decoded_ << ". Bitrate: " << |
694 current_bytes_ * 8 / statistic_time_ms, | 695 (current_bytes_ * 8 / statistic_time_ms) << " kbps, fps: " << |
695 (current_frames_ * 1000 + statistic_time_ms / 2) / statistic_time_ms, | 696 ((current_frames_ * 1000 + statistic_time_ms / 2) / statistic_time_ms) |
696 current_decoding_time_ms_ / current_frames_, statistic_time_ms); | 697 << ". decTime: " << (current_decoding_time_ms_ / current_frames_) << |
| 698 " for last " << statistic_time_ms << " ms."; |
697 start_time_ms_ = GetCurrentTimeMs(); | 699 start_time_ms_ = GetCurrentTimeMs(); |
698 current_frames_ = 0; | 700 current_frames_ = 0; |
699 current_bytes_ = 0; | 701 current_bytes_ = 0; |
700 current_decoding_time_ms_ = 0; | 702 current_decoding_time_ms_ = 0; |
701 } | 703 } |
702 | 704 |
703 // Callback - output decoded frame. | 705 // Callback - output decoded frame. |
704 const int32_t callback_status = callback_->Decoded(decoded_frame); | 706 const int32_t callback_status = callback_->Decoded(decoded_frame); |
705 if (callback_status > 0) { | 707 if (callback_status > 0) { |
706 ALOGE("callback error"); | 708 ALOGE << "callback error"; |
707 } | 709 } |
708 | 710 |
709 return true; | 711 return true; |
710 } | 712 } |
711 | 713 |
712 int32_t MediaCodecVideoDecoder::RegisterDecodeCompleteCallback( | 714 int32_t MediaCodecVideoDecoder::RegisterDecodeCompleteCallback( |
713 DecodedImageCallback* callback) { | 715 DecodedImageCallback* callback) { |
714 callback_ = callback; | 716 callback_ = callback; |
715 return WEBRTC_VIDEO_CODEC_OK; | 717 return WEBRTC_VIDEO_CODEC_OK; |
716 } | 718 } |
717 | 719 |
718 int32_t MediaCodecVideoDecoder::Reset() { | 720 int32_t MediaCodecVideoDecoder::Reset() { |
719 ALOGD("DecoderReset"); | 721 ALOGD << "DecoderReset"; |
720 if (!inited_) { | 722 if (!inited_) { |
721 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; | 723 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; |
722 } | 724 } |
723 return InitDecode(&codec_, 1); | 725 return InitDecode(&codec_, 1); |
724 } | 726 } |
725 | 727 |
726 void MediaCodecVideoDecoder::OnMessage(rtc::Message* msg) { | 728 void MediaCodecVideoDecoder::OnMessage(rtc::Message* msg) { |
727 JNIEnv* jni = AttachCurrentThreadIfNeeded(); | 729 JNIEnv* jni = AttachCurrentThreadIfNeeded(); |
728 ScopedLocalRefFrame local_ref_frame(jni); | 730 ScopedLocalRefFrame local_ref_frame(jni); |
729 if (!inited_) { | 731 if (!inited_) { |
730 return; | 732 return; |
731 } | 733 } |
732 // We only ever send one message to |this| directly (not through a Bind()'d | 734 // We only ever send one message to |this| directly (not through a Bind()'d |
733 // functor), so expect no ID/data. | 735 // functor), so expect no ID/data. |
734 RTC_CHECK(!msg->message_id) << "Unexpected message!"; | 736 RTC_CHECK(!msg->message_id) << "Unexpected message!"; |
735 RTC_CHECK(!msg->pdata) << "Unexpected message!"; | 737 RTC_CHECK(!msg->pdata) << "Unexpected message!"; |
736 CheckOnCodecThread(); | 738 CheckOnCodecThread(); |
737 | 739 |
738 if (!DeliverPendingOutputs(jni, 0)) { | 740 if (!DeliverPendingOutputs(jni, 0)) { |
739 ALOGE("OnMessage: DeliverPendingOutputs error"); | 741 ALOGE << "OnMessage: DeliverPendingOutputs error"; |
740 ProcessHWErrorOnCodecThread(); | 742 ProcessHWErrorOnCodecThread(); |
741 return; | 743 return; |
742 } | 744 } |
743 codec_thread_->PostDelayed(kMediaCodecPollMs, this); | 745 codec_thread_->PostDelayed(kMediaCodecPollMs, this); |
744 } | 746 } |
745 | 747 |
746 MediaCodecVideoDecoderFactory::MediaCodecVideoDecoderFactory() : | 748 MediaCodecVideoDecoderFactory::MediaCodecVideoDecoderFactory() : |
747 render_egl_context_(NULL) { | 749 render_egl_context_(NULL) { |
748 ALOGD("MediaCodecVideoDecoderFactory ctor"); | 750 ALOGD << "MediaCodecVideoDecoderFactory ctor"; |
749 JNIEnv* jni = AttachCurrentThreadIfNeeded(); | 751 JNIEnv* jni = AttachCurrentThreadIfNeeded(); |
750 ScopedLocalRefFrame local_ref_frame(jni); | 752 ScopedLocalRefFrame local_ref_frame(jni); |
751 jclass j_decoder_class = FindClass(jni, "org/webrtc/MediaCodecVideoDecoder"); | 753 jclass j_decoder_class = FindClass(jni, "org/webrtc/MediaCodecVideoDecoder"); |
752 supported_codec_types_.clear(); | 754 supported_codec_types_.clear(); |
753 | 755 |
754 bool is_vp8_hw_supported = jni->CallStaticBooleanMethod( | 756 bool is_vp8_hw_supported = jni->CallStaticBooleanMethod( |
755 j_decoder_class, | 757 j_decoder_class, |
756 GetStaticMethodID(jni, j_decoder_class, "isVp8HwSupported", "()Z")); | 758 GetStaticMethodID(jni, j_decoder_class, "isVp8HwSupported", "()Z")); |
757 if (CheckException(jni)) { | 759 if (CheckException(jni)) { |
758 is_vp8_hw_supported = false; | 760 is_vp8_hw_supported = false; |
759 } | 761 } |
760 if (is_vp8_hw_supported) { | 762 if (is_vp8_hw_supported) { |
761 ALOGD("VP8 HW Decoder supported."); | 763 ALOGD << "VP8 HW Decoder supported."; |
762 supported_codec_types_.push_back(kVideoCodecVP8); | 764 supported_codec_types_.push_back(kVideoCodecVP8); |
763 } | 765 } |
764 | 766 |
765 bool is_h264_hw_supported = jni->CallStaticBooleanMethod( | 767 bool is_h264_hw_supported = jni->CallStaticBooleanMethod( |
766 j_decoder_class, | 768 j_decoder_class, |
767 GetStaticMethodID(jni, j_decoder_class, "isH264HwSupported", "()Z")); | 769 GetStaticMethodID(jni, j_decoder_class, "isH264HwSupported", "()Z")); |
768 if (CheckException(jni)) { | 770 if (CheckException(jni)) { |
769 is_h264_hw_supported = false; | 771 is_h264_hw_supported = false; |
770 } | 772 } |
771 if (is_h264_hw_supported) { | 773 if (is_h264_hw_supported) { |
772 ALOGD("H264 HW Decoder supported."); | 774 ALOGD << "H264 HW Decoder supported."; |
773 supported_codec_types_.push_back(kVideoCodecH264); | 775 supported_codec_types_.push_back(kVideoCodecH264); |
774 } | 776 } |
775 } | 777 } |
776 | 778 |
777 MediaCodecVideoDecoderFactory::~MediaCodecVideoDecoderFactory() { | 779 MediaCodecVideoDecoderFactory::~MediaCodecVideoDecoderFactory() { |
778 ALOGD("MediaCodecVideoDecoderFactory dtor"); | 780 ALOGD << "MediaCodecVideoDecoderFactory dtor"; |
779 if (render_egl_context_) { | 781 if (render_egl_context_) { |
780 JNIEnv* jni = AttachCurrentThreadIfNeeded(); | 782 JNIEnv* jni = AttachCurrentThreadIfNeeded(); |
781 jni->DeleteGlobalRef(render_egl_context_); | 783 jni->DeleteGlobalRef(render_egl_context_); |
782 render_egl_context_ = NULL; | 784 render_egl_context_ = NULL; |
783 } | 785 } |
784 } | 786 } |
785 | 787 |
786 void MediaCodecVideoDecoderFactory::SetEGLContext( | 788 void MediaCodecVideoDecoderFactory::SetEGLContext( |
787 JNIEnv* jni, jobject render_egl_context) { | 789 JNIEnv* jni, jobject render_egl_context) { |
788 ALOGD("MediaCodecVideoDecoderFactory::SetEGLContext"); | 790 ALOGD << "MediaCodecVideoDecoderFactory::SetEGLContext"; |
789 if (render_egl_context_) { | 791 if (render_egl_context_) { |
790 jni->DeleteGlobalRef(render_egl_context_); | 792 jni->DeleteGlobalRef(render_egl_context_); |
791 render_egl_context_ = NULL; | 793 render_egl_context_ = NULL; |
792 } | 794 } |
793 if (!IsNull(jni, render_egl_context)) { | 795 if (!IsNull(jni, render_egl_context)) { |
794 render_egl_context_ = jni->NewGlobalRef(render_egl_context); | 796 render_egl_context_ = jni->NewGlobalRef(render_egl_context); |
795 if (CheckException(jni)) { | 797 if (CheckException(jni)) { |
796 ALOGE("error calling NewGlobalRef for EGL Context."); | 798 ALOGE << "error calling NewGlobalRef for EGL Context."; |
797 render_egl_context_ = NULL; | 799 render_egl_context_ = NULL; |
798 } else { | 800 } else { |
799 jclass j_egl_context_class = FindClass(jni, "android/opengl/EGLContext"); | 801 jclass j_egl_context_class = FindClass(jni, "android/opengl/EGLContext"); |
800 if (!jni->IsInstanceOf(render_egl_context_, j_egl_context_class)) { | 802 if (!jni->IsInstanceOf(render_egl_context_, j_egl_context_class)) { |
801 ALOGE("Wrong EGL Context."); | 803 ALOGE << "Wrong EGL Context."; |
802 jni->DeleteGlobalRef(render_egl_context_); | 804 jni->DeleteGlobalRef(render_egl_context_); |
803 render_egl_context_ = NULL; | 805 render_egl_context_ = NULL; |
804 } | 806 } |
805 } | 807 } |
806 } | 808 } |
807 if (render_egl_context_ == NULL) { | 809 if (render_egl_context_ == NULL) { |
808 ALOGW("NULL VideoDecoder EGL context - HW surface decoding is disabled."); | 810 ALOGW << "NULL VideoDecoder EGL context - HW surface decoding is disabled."; |
809 } | 811 } |
810 } | 812 } |
811 | 813 |
812 webrtc::VideoDecoder* MediaCodecVideoDecoderFactory::CreateVideoDecoder( | 814 webrtc::VideoDecoder* MediaCodecVideoDecoderFactory::CreateVideoDecoder( |
813 VideoCodecType type) { | 815 VideoCodecType type) { |
814 if (supported_codec_types_.empty()) { | 816 if (supported_codec_types_.empty()) { |
815 ALOGE("No HW video decoder for type %d.", (int)type); | 817 ALOGE << "No HW video decoder for type " << (int)type; |
816 return NULL; | 818 return NULL; |
817 } | 819 } |
818 for (VideoCodecType codec_type : supported_codec_types_) { | 820 for (VideoCodecType codec_type : supported_codec_types_) { |
819 if (codec_type == type) { | 821 if (codec_type == type) { |
820 ALOGD("Create HW video decoder for type %d.", (int)type); | 822 ALOGD << "Create HW video decoder for type " << (int)type; |
821 return new MediaCodecVideoDecoder( | 823 return new MediaCodecVideoDecoder( |
822 AttachCurrentThreadIfNeeded(), type, render_egl_context_); | 824 AttachCurrentThreadIfNeeded(), type, render_egl_context_); |
823 } | 825 } |
824 } | 826 } |
825 ALOGE("Can not find HW video decoder for type %d.", (int)type); | 827 ALOGE << "Can not find HW video decoder for type " << (int)type; |
826 return NULL; | 828 return NULL; |
827 } | 829 } |
828 | 830 |
829 void MediaCodecVideoDecoderFactory::DestroyVideoDecoder( | 831 void MediaCodecVideoDecoderFactory::DestroyVideoDecoder( |
830 webrtc::VideoDecoder* decoder) { | 832 webrtc::VideoDecoder* decoder) { |
| 833 ALOGD << "Destroy video decoder."; |
831 delete decoder; | 834 delete decoder; |
832 } | 835 } |
833 | 836 |
834 } // namespace webrtc_jni | 837 } // namespace webrtc_jni |
835 | 838 |
OLD | NEW |