OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright 2015 The WebRTC project authors. All Rights Reserved. | 2 * Copyright 2015 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
92 // rtc::MessageHandler implementation. | 92 // rtc::MessageHandler implementation. |
93 void OnMessage(rtc::Message* msg) override; | 93 void OnMessage(rtc::Message* msg) override; |
94 | 94 |
95 const char* ImplementationName() const override; | 95 const char* ImplementationName() const override; |
96 | 96 |
97 private: | 97 private: |
98 // CHECK-fail if not running on |codec_thread_|. | 98 // CHECK-fail if not running on |codec_thread_|. |
99 void CheckOnCodecThread(); | 99 void CheckOnCodecThread(); |
100 | 100 |
101 int32_t InitDecodeOnCodecThread(); | 101 int32_t InitDecodeOnCodecThread(); |
102 int32_t ResetDecodeOnCodecThread(); | |
102 int32_t ReleaseOnCodecThread(); | 103 int32_t ReleaseOnCodecThread(); |
103 int32_t DecodeOnCodecThread(const EncodedImage& inputImage); | 104 int32_t DecodeOnCodecThread(const EncodedImage& inputImage); |
104 // Deliver any outputs pending in the MediaCodec to our |callback_| and return | 105 // Deliver any outputs pending in the MediaCodec to our |callback_| and return |
105 // true on success. | 106 // true on success. |
106 bool DeliverPendingOutputs(JNIEnv* jni, int dequeue_timeout_us); | 107 bool DeliverPendingOutputs(JNIEnv* jni, int dequeue_timeout_us); |
107 int32_t ProcessHWErrorOnCodecThread(); | 108 int32_t ProcessHWErrorOnCodecThread(); |
108 void EnableFrameLogOnWarning(); | 109 void EnableFrameLogOnWarning(); |
110 void ResetVariables(); | |
109 | 111 |
110 // Type of video codec. | 112 // Type of video codec. |
111 VideoCodecType codecType_; | 113 VideoCodecType codecType_; |
112 | 114 |
113 // Render EGL context - owned by factory, should not be allocated/destroyed | 115 // Render EGL context - owned by factory, should not be allocated/destroyed |
114 // by VideoDecoder. | 116 // by VideoDecoder. |
115 jobject render_egl_context_; | 117 jobject render_egl_context_; |
116 | 118 |
117 bool key_frame_required_; | 119 bool key_frame_required_; |
118 bool inited_; | 120 bool inited_; |
(...skipping 13 matching lines...) Expand all Loading... | |
132 int current_decoding_time_ms_; // Overall decoding time in the current second | 134 int current_decoding_time_ms_; // Overall decoding time in the current second |
133 int current_delay_time_ms_; // Overall delay time in the current second. | 135 int current_delay_time_ms_; // Overall delay time in the current second. |
134 uint32_t max_pending_frames_; // Maximum number of pending input frames. | 136 uint32_t max_pending_frames_; // Maximum number of pending input frames. |
135 | 137 |
136 // State that is constant for the lifetime of this object once the ctor | 138 // State that is constant for the lifetime of this object once the ctor |
137 // returns. | 139 // returns. |
138 scoped_ptr<Thread> codec_thread_; // Thread on which to operate MediaCodec. | 140 scoped_ptr<Thread> codec_thread_; // Thread on which to operate MediaCodec. |
139 ScopedGlobalRef<jclass> j_media_codec_video_decoder_class_; | 141 ScopedGlobalRef<jclass> j_media_codec_video_decoder_class_; |
140 ScopedGlobalRef<jobject> j_media_codec_video_decoder_; | 142 ScopedGlobalRef<jobject> j_media_codec_video_decoder_; |
141 jmethodID j_init_decode_method_; | 143 jmethodID j_init_decode_method_; |
144 jmethodID j_reset_method_; | |
142 jmethodID j_release_method_; | 145 jmethodID j_release_method_; |
143 jmethodID j_dequeue_input_buffer_method_; | 146 jmethodID j_dequeue_input_buffer_method_; |
144 jmethodID j_queue_input_buffer_method_; | 147 jmethodID j_queue_input_buffer_method_; |
145 jmethodID j_dequeue_byte_buffer_method_; | 148 jmethodID j_dequeue_byte_buffer_method_; |
146 jmethodID j_dequeue_texture_buffer_method_; | 149 jmethodID j_dequeue_texture_buffer_method_; |
147 jmethodID j_return_decoded_byte_buffer_method_; | 150 jmethodID j_return_decoded_byte_buffer_method_; |
148 // MediaCodecVideoDecoder fields. | 151 // MediaCodecVideoDecoder fields. |
149 jfieldID j_input_buffers_field_; | 152 jfieldID j_input_buffers_field_; |
150 jfieldID j_output_buffers_field_; | 153 jfieldID j_output_buffers_field_; |
151 jfieldID j_color_format_field_; | 154 jfieldID j_color_format_field_; |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
193 "<init>", | 196 "<init>", |
194 "()V"))) { | 197 "()V"))) { |
195 ScopedLocalRefFrame local_ref_frame(jni); | 198 ScopedLocalRefFrame local_ref_frame(jni); |
196 codec_thread_->SetName("MediaCodecVideoDecoder", NULL); | 199 codec_thread_->SetName("MediaCodecVideoDecoder", NULL); |
197 RTC_CHECK(codec_thread_->Start()) << "Failed to start MediaCodecVideoDecoder"; | 200 RTC_CHECK(codec_thread_->Start()) << "Failed to start MediaCodecVideoDecoder"; |
198 | 201 |
199 j_init_decode_method_ = GetMethodID( | 202 j_init_decode_method_ = GetMethodID( |
200 jni, *j_media_codec_video_decoder_class_, "initDecode", | 203 jni, *j_media_codec_video_decoder_class_, "initDecode", |
201 "(Lorg/webrtc/MediaCodecVideoDecoder$VideoCodecType;" | 204 "(Lorg/webrtc/MediaCodecVideoDecoder$VideoCodecType;" |
202 "IILorg/webrtc/SurfaceTextureHelper;)Z"); | 205 "IILorg/webrtc/SurfaceTextureHelper;)Z"); |
206 j_reset_method_ = | |
207 GetMethodID(jni, *j_media_codec_video_decoder_class_, "reset", "(II)V"); | |
203 j_release_method_ = | 208 j_release_method_ = |
204 GetMethodID(jni, *j_media_codec_video_decoder_class_, "release", "()V"); | 209 GetMethodID(jni, *j_media_codec_video_decoder_class_, "release", "()V"); |
205 j_dequeue_input_buffer_method_ = GetMethodID( | 210 j_dequeue_input_buffer_method_ = GetMethodID( |
206 jni, *j_media_codec_video_decoder_class_, "dequeueInputBuffer", "()I"); | 211 jni, *j_media_codec_video_decoder_class_, "dequeueInputBuffer", "()I"); |
207 j_queue_input_buffer_method_ = GetMethodID( | 212 j_queue_input_buffer_method_ = GetMethodID( |
208 jni, *j_media_codec_video_decoder_class_, "queueInputBuffer", "(IIJJJ)Z"); | 213 jni, *j_media_codec_video_decoder_class_, "queueInputBuffer", "(IIJJJ)Z"); |
209 j_dequeue_byte_buffer_method_ = GetMethodID( | 214 j_dequeue_byte_buffer_method_ = GetMethodID( |
210 jni, *j_media_codec_video_decoder_class_, "dequeueOutputBuffer", | 215 jni, *j_media_codec_video_decoder_class_, "dequeueOutputBuffer", |
211 "(I)Lorg/webrtc/MediaCodecVideoDecoder$DecodedOutputBuffer;"); | 216 "(I)Lorg/webrtc/MediaCodecVideoDecoder$DecodedOutputBuffer;"); |
212 j_dequeue_texture_buffer_method_ = GetMethodID( | 217 j_dequeue_texture_buffer_method_ = GetMethodID( |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
299 codec_ = *inst; | 304 codec_ = *inst; |
300 } | 305 } |
301 // If maxFramerate is not set then assume 30 fps. | 306 // If maxFramerate is not set then assume 30 fps. |
302 codec_.maxFramerate = (codec_.maxFramerate >= 1) ? codec_.maxFramerate : 30; | 307 codec_.maxFramerate = (codec_.maxFramerate >= 1) ? codec_.maxFramerate : 30; |
303 | 308 |
304 // Call Java init. | 309 // Call Java init. |
305 return codec_thread_->Invoke<int32_t>( | 310 return codec_thread_->Invoke<int32_t>( |
306 Bind(&MediaCodecVideoDecoder::InitDecodeOnCodecThread, this)); | 311 Bind(&MediaCodecVideoDecoder::InitDecodeOnCodecThread, this)); |
307 } | 312 } |
308 | 313 |
314 void MediaCodecVideoDecoder::ResetVariables() { | |
315 key_frame_required_ = true; | |
pbos-webrtc
2016/03/04 10:23:13
CheckOnCodecThread?
AlexG
2016/03/04 18:44:12
Done.
| |
316 frames_received_ = 0; | |
317 frames_decoded_ = 0; | |
318 frames_decoded_logged_ = kMaxDecodedLogFrames; | |
319 start_time_ms_ = GetCurrentTimeMs(); | |
320 current_frames_ = 0; | |
321 current_bytes_ = 0; | |
322 current_decoding_time_ms_ = 0; | |
323 current_delay_time_ms_ = 0; | |
324 } | |
325 | |
309 int32_t MediaCodecVideoDecoder::InitDecodeOnCodecThread() { | 326 int32_t MediaCodecVideoDecoder::InitDecodeOnCodecThread() { |
310 CheckOnCodecThread(); | 327 CheckOnCodecThread(); |
311 JNIEnv* jni = AttachCurrentThreadIfNeeded(); | 328 JNIEnv* jni = AttachCurrentThreadIfNeeded(); |
312 ScopedLocalRefFrame local_ref_frame(jni); | 329 ScopedLocalRefFrame local_ref_frame(jni); |
313 ALOGD << "InitDecodeOnCodecThread Type: " << (int)codecType_ << ". " | 330 ALOGD << "InitDecodeOnCodecThread Type: " << (int)codecType_ << ". " |
314 << codec_.width << " x " << codec_.height << ". Fps: " << | 331 << codec_.width << " x " << codec_.height << ". Fps: " << |
315 (int)codec_.maxFramerate; | 332 (int)codec_.maxFramerate; |
316 | 333 |
317 // Release previous codec first if it was allocated before. | 334 // Release previous codec first if it was allocated before. |
318 int ret_val = ReleaseOnCodecThread(); | 335 int ret_val = ReleaseOnCodecThread(); |
319 if (ret_val < 0) { | 336 if (ret_val < 0) { |
320 ALOGE << "Release failure: " << ret_val << " - fallback to SW codec"; | 337 ALOGE << "Release failure: " << ret_val << " - fallback to SW codec"; |
321 sw_fallback_required_ = true; | 338 sw_fallback_required_ = true; |
322 return WEBRTC_VIDEO_CODEC_ERROR; | 339 return WEBRTC_VIDEO_CODEC_ERROR; |
323 } | 340 } |
324 | 341 |
325 // Always start with a complete key frame. | 342 ResetVariables(); |
326 key_frame_required_ = true; | |
327 frames_received_ = 0; | |
328 frames_decoded_ = 0; | |
329 frames_decoded_logged_ = kMaxDecodedLogFrames; | |
330 | 343 |
331 jobject java_surface_texture_helper_ = nullptr; | 344 jobject java_surface_texture_helper_ = nullptr; |
332 if (use_surface_) { | 345 if (use_surface_) { |
333 java_surface_texture_helper_ = jni->CallStaticObjectMethod( | 346 java_surface_texture_helper_ = jni->CallStaticObjectMethod( |
334 FindClass(jni, "org/webrtc/SurfaceTextureHelper"), | 347 FindClass(jni, "org/webrtc/SurfaceTextureHelper"), |
335 GetStaticMethodID(jni, | 348 GetStaticMethodID(jni, |
336 FindClass(jni, "org/webrtc/SurfaceTextureHelper"), | 349 FindClass(jni, "org/webrtc/SurfaceTextureHelper"), |
337 "create", | 350 "create", |
338 "(Lorg/webrtc/EglBase$Context;)" | 351 "(Lorg/webrtc/EglBase$Context;)" |
339 "Lorg/webrtc/SurfaceTextureHelper;"), | 352 "Lorg/webrtc/SurfaceTextureHelper;"), |
340 render_egl_context_); | 353 render_egl_context_); |
341 RTC_CHECK(java_surface_texture_helper_ != nullptr); | 354 RTC_CHECK(java_surface_texture_helper_ != nullptr); |
342 surface_texture_helper_ = new rtc::RefCountedObject<SurfaceTextureHelper>( | 355 surface_texture_helper_ = new rtc::RefCountedObject<SurfaceTextureHelper>( |
343 jni, java_surface_texture_helper_); | 356 jni, java_surface_texture_helper_); |
344 } | 357 } |
345 | 358 |
346 jobject j_video_codec_enum = JavaEnumFromIndexAndClassName( | 359 jobject j_video_codec_enum = JavaEnumFromIndexAndClassName( |
347 jni, "MediaCodecVideoDecoder$VideoCodecType", codecType_); | 360 jni, "MediaCodecVideoDecoder$VideoCodecType", codecType_); |
348 bool success = jni->CallBooleanMethod( | 361 bool success = jni->CallBooleanMethod( |
349 *j_media_codec_video_decoder_, | 362 *j_media_codec_video_decoder_, |
350 j_init_decode_method_, | 363 j_init_decode_method_, |
351 j_video_codec_enum, | 364 j_video_codec_enum, |
352 codec_.width, | 365 codec_.width, |
353 codec_.height, | 366 codec_.height, |
354 java_surface_texture_helper_); | 367 java_surface_texture_helper_); |
368 | |
355 if (CheckException(jni) || !success) { | 369 if (CheckException(jni) || !success) { |
356 ALOGE << "Codec initialization error - fallback to SW codec."; | 370 ALOGE << "Codec initialization error - fallback to SW codec."; |
357 sw_fallback_required_ = true; | 371 sw_fallback_required_ = true; |
358 return WEBRTC_VIDEO_CODEC_ERROR; | 372 return WEBRTC_VIDEO_CODEC_ERROR; |
359 } | 373 } |
360 inited_ = true; | 374 inited_ = true; |
361 | 375 |
362 switch (codecType_) { | 376 switch (codecType_) { |
363 case kVideoCodecVP8: | 377 case kVideoCodecVP8: |
364 max_pending_frames_ = kMaxPendingFramesVp8; | 378 max_pending_frames_ = kMaxPendingFramesVp8; |
365 break; | 379 break; |
366 case kVideoCodecVP9: | 380 case kVideoCodecVP9: |
367 max_pending_frames_ = kMaxPendingFramesVp9; | 381 max_pending_frames_ = kMaxPendingFramesVp9; |
368 break; | 382 break; |
369 case kVideoCodecH264: | 383 case kVideoCodecH264: |
370 max_pending_frames_ = kMaxPendingFramesH264; | 384 max_pending_frames_ = kMaxPendingFramesH264; |
371 break; | 385 break; |
372 default: | 386 default: |
373 max_pending_frames_ = 0; | 387 max_pending_frames_ = 0; |
374 } | 388 } |
375 start_time_ms_ = GetCurrentTimeMs(); | 389 ALOGD << "Maximum amount of pending frames: " << max_pending_frames_; |
376 current_frames_ = 0; | |
377 current_bytes_ = 0; | |
378 current_decoding_time_ms_ = 0; | |
379 current_delay_time_ms_ = 0; | |
380 | 390 |
381 jobjectArray input_buffers = (jobjectArray)GetObjectField( | 391 jobjectArray input_buffers = (jobjectArray)GetObjectField( |
382 jni, *j_media_codec_video_decoder_, j_input_buffers_field_); | 392 jni, *j_media_codec_video_decoder_, j_input_buffers_field_); |
383 size_t num_input_buffers = jni->GetArrayLength(input_buffers); | 393 size_t num_input_buffers = jni->GetArrayLength(input_buffers); |
384 ALOGD << "Maximum amount of pending frames: " << max_pending_frames_; | |
385 input_buffers_.resize(num_input_buffers); | 394 input_buffers_.resize(num_input_buffers); |
386 for (size_t i = 0; i < num_input_buffers; ++i) { | 395 for (size_t i = 0; i < num_input_buffers; ++i) { |
387 input_buffers_[i] = | 396 input_buffers_[i] = |
388 jni->NewGlobalRef(jni->GetObjectArrayElement(input_buffers, i)); | 397 jni->NewGlobalRef(jni->GetObjectArrayElement(input_buffers, i)); |
389 if (CheckException(jni)) { | 398 if (CheckException(jni)) { |
390 ALOGE << "NewGlobalRef error - fallback to SW codec."; | 399 ALOGE << "NewGlobalRef error - fallback to SW codec."; |
391 sw_fallback_required_ = true; | 400 sw_fallback_required_ = true; |
392 return WEBRTC_VIDEO_CODEC_ERROR; | 401 return WEBRTC_VIDEO_CODEC_ERROR; |
393 } | 402 } |
394 } | 403 } |
395 | 404 |
396 codec_thread_->PostDelayed(kMediaCodecPollMs, this); | 405 codec_thread_->PostDelayed(kMediaCodecPollMs, this); |
397 | 406 |
398 return WEBRTC_VIDEO_CODEC_OK; | 407 return WEBRTC_VIDEO_CODEC_OK; |
399 } | 408 } |
400 | 409 |
410 int32_t MediaCodecVideoDecoder::ResetDecodeOnCodecThread() { | |
411 CheckOnCodecThread(); | |
412 JNIEnv* jni = AttachCurrentThreadIfNeeded(); | |
413 ScopedLocalRefFrame local_ref_frame(jni); | |
414 ALOGD << "ResetDecodeOnCodecThread Type: " << (int)codecType_ << ". " | |
415 << codec_.width << " x " << codec_.height; | |
416 ALOGD << " Frames received: " << frames_received_ << | |
417 ". Frames decoded: " << frames_decoded_; | |
418 | |
419 inited_ = false; | |
420 rtc::MessageQueueManager::Clear(this); | |
421 ResetVariables(); | |
422 | |
423 jni->CallVoidMethod( | |
424 *j_media_codec_video_decoder_, | |
425 j_reset_method_, | |
426 codec_.width, | |
427 codec_.height); | |
428 | |
429 if (CheckException(jni)) { | |
430 ALOGE << "Soft reset error - fallback to SW codec."; | |
431 sw_fallback_required_ = true; | |
432 return WEBRTC_VIDEO_CODEC_ERROR; | |
433 } | |
434 inited_ = true; | |
435 | |
436 codec_thread_->PostDelayed(kMediaCodecPollMs, this); | |
437 | |
438 return WEBRTC_VIDEO_CODEC_OK; | |
439 } | |
440 | |
401 int32_t MediaCodecVideoDecoder::Release() { | 441 int32_t MediaCodecVideoDecoder::Release() { |
402 ALOGD << "DecoderRelease request"; | 442 ALOGD << "DecoderRelease request"; |
403 return codec_thread_->Invoke<int32_t>( | 443 return codec_thread_->Invoke<int32_t>( |
404 Bind(&MediaCodecVideoDecoder::ReleaseOnCodecThread, this)); | 444 Bind(&MediaCodecVideoDecoder::ReleaseOnCodecThread, this)); |
405 } | 445 } |
406 | 446 |
407 int32_t MediaCodecVideoDecoder::ReleaseOnCodecThread() { | 447 int32_t MediaCodecVideoDecoder::ReleaseOnCodecThread() { |
408 if (!inited_) { | 448 if (!inited_) { |
409 return WEBRTC_VIDEO_CODEC_OK; | 449 return WEBRTC_VIDEO_CODEC_OK; |
410 } | 450 } |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
486 } | 526 } |
487 if (!inited_) { | 527 if (!inited_) { |
488 ALOGE << "Decode() - decoder is not initialized"; | 528 ALOGE << "Decode() - decoder is not initialized"; |
489 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; | 529 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; |
490 } | 530 } |
491 | 531 |
492 // Check if encoded frame dimension has changed. | 532 // Check if encoded frame dimension has changed. |
493 if ((inputImage._encodedWidth * inputImage._encodedHeight > 0) && | 533 if ((inputImage._encodedWidth * inputImage._encodedHeight > 0) && |
494 (inputImage._encodedWidth != codec_.width || | 534 (inputImage._encodedWidth != codec_.width || |
495 inputImage._encodedHeight != codec_.height)) { | 535 inputImage._encodedHeight != codec_.height)) { |
536 ALOGW << "Input resolution changed from " << | |
537 codec_.width << " x " << codec_.height << " to " << | |
538 inputImage._encodedWidth << " x " << inputImage._encodedHeight; | |
496 codec_.width = inputImage._encodedWidth; | 539 codec_.width = inputImage._encodedWidth; |
497 codec_.height = inputImage._encodedHeight; | 540 codec_.height = inputImage._encodedHeight; |
498 int32_t ret = InitDecode(&codec_, 1); | 541 int32_t ret; |
542 if (use_surface_ && codecType_ == kVideoCodecVP8) { | |
543 // Soft codec reset - only for VP8 and surface decoding. | |
544 // TODO(glaznev): try to use similar approach for H.264. | |
pbos-webrtc
2016/03/04 10:23:13
(and buffer decoding?)
AlexG
2016/03/04 18:44:12
Done.
| |
545 ret = codec_thread_->Invoke<int32_t>(Bind( | |
546 &MediaCodecVideoDecoder::ResetDecodeOnCodecThread, this)); | |
547 } else { | |
548 // Hard codec reset. | |
549 ret = InitDecode(&codec_, 1); | |
550 } | |
499 if (ret < 0) { | 551 if (ret < 0) { |
500 ALOGE << "InitDecode failure: " << ret << " - fallback to SW codec"; | 552 ALOGE << "InitDecode failure: " << ret << " - fallback to SW codec"; |
501 sw_fallback_required_ = true; | 553 sw_fallback_required_ = true; |
502 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE; | 554 return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE; |
503 } | 555 } |
504 } | 556 } |
505 | 557 |
506 // Always start with a complete key frame. | 558 // Always start with a complete key frame. |
507 if (key_frame_required_) { | 559 if (key_frame_required_) { |
508 if (inputImage._frameType != webrtc::kVideoFrameKey) { | 560 if (inputImage._frameType != webrtc::kVideoFrameKey) { |
(...skipping 419 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
928 ALOGD << "Destroy video decoder."; | 980 ALOGD << "Destroy video decoder."; |
929 delete decoder; | 981 delete decoder; |
930 } | 982 } |
931 | 983 |
932 const char* MediaCodecVideoDecoder::ImplementationName() const { | 984 const char* MediaCodecVideoDecoder::ImplementationName() const { |
933 return "MediaCodec"; | 985 return "MediaCodec"; |
934 } | 986 } |
935 | 987 |
936 } // namespace webrtc_jni | 988 } // namespace webrtc_jni |
937 | 989 |
OLD | NEW |