| 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 17 matching lines...) Expand all Loading... |
| 28 | 28 |
| 29 #include "talk/app/webrtc/java/jni/androidmediaencoder_jni.h" | 29 #include "talk/app/webrtc/java/jni/androidmediaencoder_jni.h" |
| 30 #include "talk/app/webrtc/java/jni/classreferenceholder.h" | 30 #include "talk/app/webrtc/java/jni/classreferenceholder.h" |
| 31 #include "talk/app/webrtc/java/jni/androidmediacodeccommon.h" | 31 #include "talk/app/webrtc/java/jni/androidmediacodeccommon.h" |
| 32 #include "talk/app/webrtc/java/jni/native_handle_impl.h" | 32 #include "talk/app/webrtc/java/jni/native_handle_impl.h" |
| 33 #include "webrtc/base/bind.h" | 33 #include "webrtc/base/bind.h" |
| 34 #include "webrtc/base/checks.h" | 34 #include "webrtc/base/checks.h" |
| 35 #include "webrtc/base/logging.h" | 35 #include "webrtc/base/logging.h" |
| 36 #include "webrtc/base/thread.h" | 36 #include "webrtc/base/thread.h" |
| 37 #include "webrtc/base/thread_checker.h" | 37 #include "webrtc/base/thread_checker.h" |
| 38 #include "webrtc/common_types.h" |
| 38 #include "webrtc/modules/rtp_rtcp/source/h264_bitstream_parser.h" | 39 #include "webrtc/modules/rtp_rtcp/source/h264_bitstream_parser.h" |
| 39 #include "webrtc/modules/video_coding/include/video_codec_interface.h" | 40 #include "webrtc/modules/video_coding/include/video_codec_interface.h" |
| 40 #include "webrtc/modules/video_coding/utility/quality_scaler.h" | 41 #include "webrtc/modules/video_coding/utility/quality_scaler.h" |
| 41 #include "webrtc/modules/video_coding/utility/vp8_header_parser.h" | 42 #include "webrtc/modules/video_coding/utility/vp8_header_parser.h" |
| 42 #include "webrtc/system_wrappers/include/field_trial.h" | 43 #include "webrtc/system_wrappers/include/field_trial.h" |
| 43 #include "webrtc/system_wrappers/include/logcat_trace_context.h" | 44 #include "webrtc/system_wrappers/include/logcat_trace_context.h" |
| 44 #include "third_party/libyuv/include/libyuv/convert.h" | 45 #include "third_party/libyuv/include/libyuv/convert.h" |
| 45 #include "third_party/libyuv/include/libyuv/convert_from.h" | 46 #include "third_party/libyuv/include/libyuv/convert_from.h" |
| 46 #include "third_party/libyuv/include/libyuv/video_common.h" | 47 #include "third_party/libyuv/include/libyuv/video_common.h" |
| 47 | 48 |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 84 #ifdef TRACK_BUFFER_TIMING | 85 #ifdef TRACK_BUFFER_TIMING |
| 85 #define ALOGV(...) | 86 #define ALOGV(...) |
| 86 __android_log_print(ANDROID_LOG_VERBOSE, TAG_ENCODER, __VA_ARGS__) | 87 __android_log_print(ANDROID_LOG_VERBOSE, TAG_ENCODER, __VA_ARGS__) |
| 87 #else | 88 #else |
| 88 #define ALOGV(...) | 89 #define ALOGV(...) |
| 89 #endif | 90 #endif |
| 90 #define ALOGD LOG_TAG(rtc::LS_INFO, TAG_ENCODER) | 91 #define ALOGD LOG_TAG(rtc::LS_INFO, TAG_ENCODER) |
| 91 #define ALOGW LOG_TAG(rtc::LS_WARNING, TAG_ENCODER) | 92 #define ALOGW LOG_TAG(rtc::LS_WARNING, TAG_ENCODER) |
| 92 #define ALOGE LOG_TAG(rtc::LS_ERROR, TAG_ENCODER) | 93 #define ALOGE LOG_TAG(rtc::LS_ERROR, TAG_ENCODER) |
| 93 | 94 |
| 95 namespace { |
| 96 // Maximum time limit between incoming frames before requesting a key frame. |
| 97 const size_t kFrameDiffThresholdMs = 1100; |
| 98 const int kMinKeyFrameInterval = 2; |
| 99 } // namespace |
| 100 |
| 94 // MediaCodecVideoEncoder is a webrtc::VideoEncoder implementation that uses | 101 // MediaCodecVideoEncoder is a webrtc::VideoEncoder implementation that uses |
| 95 // Android's MediaCodec SDK API behind the scenes to implement (hopefully) | 102 // Android's MediaCodec SDK API behind the scenes to implement (hopefully) |
| 96 // HW-backed video encode. This C++ class is implemented as a very thin shim, | 103 // HW-backed video encode. This C++ class is implemented as a very thin shim, |
| 97 // delegating all of the interesting work to org.webrtc.MediaCodecVideoEncoder. | 104 // delegating all of the interesting work to org.webrtc.MediaCodecVideoEncoder. |
| 98 // MediaCodecVideoEncoder is created, operated, and destroyed on a single | 105 // MediaCodecVideoEncoder is created, operated, and destroyed on a single |
| 99 // thread, currently the libjingle Worker thread. | 106 // thread, currently the libjingle Worker thread. |
| 100 class MediaCodecVideoEncoder : public webrtc::VideoEncoder, | 107 class MediaCodecVideoEncoder : public webrtc::VideoEncoder, |
| 101 public rtc::MessageHandler { | 108 public rtc::MessageHandler { |
| 102 public: | 109 public: |
| 103 virtual ~MediaCodecVideoEncoder(); | 110 virtual ~MediaCodecVideoEncoder(); |
| (...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 252 | 259 |
| 253 // VP9 variables to populate codec specific structure. | 260 // VP9 variables to populate codec specific structure. |
| 254 webrtc::GofInfoVP9 gof_; // Contains each frame's temporal information for | 261 webrtc::GofInfoVP9 gof_; // Contains each frame's temporal information for |
| 255 // non-flexible VP9 mode. | 262 // non-flexible VP9 mode. |
| 256 uint8_t tl0_pic_idx_; | 263 uint8_t tl0_pic_idx_; |
| 257 size_t gof_idx_; | 264 size_t gof_idx_; |
| 258 | 265 |
| 259 // EGL context - owned by factory, should not be allocated/destroyed | 266 // EGL context - owned by factory, should not be allocated/destroyed |
| 260 // by MediaCodecVideoEncoder. | 267 // by MediaCodecVideoEncoder. |
| 261 jobject egl_context_; | 268 jobject egl_context_; |
| 269 |
| 270 // Temporary fix for VP8. |
| 271 // Sends a key frame if frames are largely spaced apart (possibly |
| 272 // corresponding to a large image change). |
| 273 int64_t last_frame_received_ms_; |
| 274 int frames_received_since_last_key_; |
| 275 webrtc::VideoCodecMode codec_mode_; |
| 262 }; | 276 }; |
| 263 | 277 |
| 264 MediaCodecVideoEncoder::~MediaCodecVideoEncoder() { | 278 MediaCodecVideoEncoder::~MediaCodecVideoEncoder() { |
| 265 // Call Release() to ensure no more callbacks to us after we are deleted. | 279 // Call Release() to ensure no more callbacks to us after we are deleted. |
| 266 Release(); | 280 Release(); |
| 267 } | 281 } |
| 268 | 282 |
| 269 MediaCodecVideoEncoder::MediaCodecVideoEncoder( | 283 MediaCodecVideoEncoder::MediaCodecVideoEncoder( |
| 270 JNIEnv* jni, VideoCodecType codecType, jobject egl_context) : | 284 JNIEnv* jni, VideoCodecType codecType, jobject egl_context) : |
| 271 codecType_(codecType), | 285 codecType_(codecType), |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 353 if (codec_settings == NULL) { | 367 if (codec_settings == NULL) { |
| 354 ALOGE << "NULL VideoCodec instance"; | 368 ALOGE << "NULL VideoCodec instance"; |
| 355 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; | 369 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; |
| 356 } | 370 } |
| 357 // Factory should guard against other codecs being used with us. | 371 // Factory should guard against other codecs being used with us. |
| 358 RTC_CHECK(codec_settings->codecType == codecType_) | 372 RTC_CHECK(codec_settings->codecType == codecType_) |
| 359 << "Unsupported codec " << codec_settings->codecType << " for " | 373 << "Unsupported codec " << codec_settings->codecType << " for " |
| 360 << codecType_; | 374 << codecType_; |
| 361 | 375 |
| 362 ALOGD << "InitEncode request"; | 376 ALOGD << "InitEncode request"; |
| 377 codec_mode_ = codec_settings->mode; |
| 363 scale_ = (codecType_ != kVideoCodecVP9) && (webrtc::field_trial::FindFullName( | 378 scale_ = (codecType_ != kVideoCodecVP9) && (webrtc::field_trial::FindFullName( |
| 364 "WebRTC-MediaCodecVideoEncoder-AutomaticResize") == "Enabled"); | 379 "WebRTC-MediaCodecVideoEncoder-AutomaticResize") == "Enabled"); |
| 365 ALOGD << "Encoder automatic resize " << (scale_ ? "enabled" : "disabled"); | 380 ALOGD << "Encoder automatic resize " << (scale_ ? "enabled" : "disabled"); |
| 366 if (scale_) { | 381 if (scale_) { |
| 367 if (codecType_ == kVideoCodecVP8) { | 382 if (codecType_ == kVideoCodecVP8) { |
| 368 // QP is obtained from VP8-bitstream for HW, so the QP corresponds to the | 383 // QP is obtained from VP8-bitstream for HW, so the QP corresponds to the |
| 369 // (internal) range: [0, 127]. And we cannot change QP_max in HW, so it is | 384 // (internal) range: [0, 127]. And we cannot change QP_max in HW, so it is |
| 370 // always = 127. Note that in SW, QP is that of the user-level range [0, | 385 // always = 127. Note that in SW, QP is that of the user-level range [0, |
| 371 // 63]. | 386 // 63]. |
| 372 const int kMaxQp = 127; | 387 const int kMaxQp = 127; |
| (...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 511 output_render_time_ms_ = 0; | 526 output_render_time_ms_ = 0; |
| 512 timestamps_.clear(); | 527 timestamps_.clear(); |
| 513 render_times_ms_.clear(); | 528 render_times_ms_.clear(); |
| 514 frame_rtc_times_ms_.clear(); | 529 frame_rtc_times_ms_.clear(); |
| 515 drop_next_input_frame_ = false; | 530 drop_next_input_frame_ = false; |
| 516 use_surface_ = use_surface; | 531 use_surface_ = use_surface; |
| 517 picture_id_ = static_cast<uint16_t>(rand()) & 0x7FFF; | 532 picture_id_ = static_cast<uint16_t>(rand()) & 0x7FFF; |
| 518 gof_.SetGofInfoVP9(webrtc::TemporalStructureMode::kTemporalStructureMode1); | 533 gof_.SetGofInfoVP9(webrtc::TemporalStructureMode::kTemporalStructureMode1); |
| 519 tl0_pic_idx_ = static_cast<uint8_t>(rand()); | 534 tl0_pic_idx_ = static_cast<uint8_t>(rand()); |
| 520 gof_idx_ = 0; | 535 gof_idx_ = 0; |
| 536 last_frame_received_ms_ = -1; |
| 537 frames_received_since_last_key_ = kMinKeyFrameInterval; |
| 521 | 538 |
| 522 // We enforce no extra stride/padding in the format creation step. | 539 // We enforce no extra stride/padding in the format creation step. |
| 523 jobject j_video_codec_enum = JavaEnumFromIndex( | 540 jobject j_video_codec_enum = JavaEnumFromIndex( |
| 524 jni, "MediaCodecVideoEncoder$VideoCodecType", codecType_); | 541 jni, "MediaCodecVideoEncoder$VideoCodecType", codecType_); |
| 525 const bool encode_status = jni->CallBooleanMethod( | 542 const bool encode_status = jni->CallBooleanMethod( |
| 526 *j_media_codec_video_encoder_, j_init_encode_method_, | 543 *j_media_codec_video_encoder_, j_init_encode_method_, |
| 527 j_video_codec_enum, width, height, kbps, fps, | 544 j_video_codec_enum, width, height, kbps, fps, |
| 528 (use_surface ? egl_context_ : nullptr)); | 545 (use_surface ? egl_context_ : nullptr)); |
| 529 if (!encode_status) { | 546 if (!encode_status) { |
| 530 ALOGE << "Failed to configure encoder."; | 547 ALOGE << "Failed to configure encoder."; |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 578 const webrtc::VideoFrame& frame, | 595 const webrtc::VideoFrame& frame, |
| 579 const std::vector<webrtc::FrameType>* frame_types) { | 596 const std::vector<webrtc::FrameType>* frame_types) { |
| 580 RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); | 597 RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); |
| 581 JNIEnv* jni = AttachCurrentThreadIfNeeded(); | 598 JNIEnv* jni = AttachCurrentThreadIfNeeded(); |
| 582 ScopedLocalRefFrame local_ref_frame(jni); | 599 ScopedLocalRefFrame local_ref_frame(jni); |
| 583 | 600 |
| 584 if (!inited_) { | 601 if (!inited_) { |
| 585 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; | 602 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; |
| 586 } | 603 } |
| 587 | 604 |
| 605 bool send_key_frame = false; |
| 606 if (codecType_ == kVideoCodecVP8 && codec_mode_ == webrtc::kRealtimeVideo) { |
| 607 ++frames_received_since_last_key_; |
| 608 int64_t now_ms = GetCurrentTimeMs(); |
| 609 if (last_frame_received_ms_ != -1 && |
| 610 (now_ms - last_frame_received_ms_) > kFrameDiffThresholdMs) { |
| 611 // Add limit to prevent triggering a key for every frame for very low |
| 612 // framerates (e.g. if frame diff > kFrameDiffThresholdMs). |
| 613 if (frames_received_since_last_key_ > kMinKeyFrameInterval) { |
| 614 ALOGD << "Send key, frame diff: " << (now_ms - last_frame_received_ms_); |
| 615 send_key_frame = true; |
| 616 } |
| 617 frames_received_since_last_key_ = 0; |
| 618 } |
| 619 last_frame_received_ms_ = now_ms; |
| 620 } |
| 621 |
| 588 frames_received_++; | 622 frames_received_++; |
| 589 if (!DeliverPendingOutputs(jni)) { | 623 if (!DeliverPendingOutputs(jni)) { |
| 590 if (!ResetCodecOnCodecThread()) | 624 if (!ResetCodecOnCodecThread()) |
| 591 return WEBRTC_VIDEO_CODEC_ERROR; | 625 return WEBRTC_VIDEO_CODEC_ERROR; |
| 592 } | 626 } |
| 593 if (frames_encoded_ < kMaxEncodedLogFrames) { | 627 if (frames_encoded_ < kMaxEncodedLogFrames) { |
| 594 ALOGD << "Encoder frame in # " << (frames_received_ - 1) << ". TS: " << | 628 ALOGD << "Encoder frame in # " << (frames_received_ - 1) << ". TS: " << |
| 595 (int)(current_timestamp_us_ / 1000) << ". Q: " << frames_in_queue_ << | 629 (int)(current_timestamp_us_ / 1000) << ". Q: " << frames_in_queue_ << |
| 596 ". Fps: " << last_set_fps_ << ". Kbps: " << last_set_bitrate_kbps_; | 630 ". Fps: " << last_set_fps_ << ". Kbps: " << last_set_bitrate_kbps_; |
| 597 } | 631 } |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 644 } | 678 } |
| 645 | 679 |
| 646 if (!MaybeReconfigureEncoderOnCodecThread(input_frame)) { | 680 if (!MaybeReconfigureEncoderOnCodecThread(input_frame)) { |
| 647 ALOGE << "Failed to reconfigure encoder."; | 681 ALOGE << "Failed to reconfigure encoder."; |
| 648 return WEBRTC_VIDEO_CODEC_ERROR; | 682 return WEBRTC_VIDEO_CODEC_ERROR; |
| 649 } | 683 } |
| 650 | 684 |
| 651 // Save time when input frame is sent to the encoder input. | 685 // Save time when input frame is sent to the encoder input. |
| 652 frame_rtc_times_ms_.push_back(GetCurrentTimeMs()); | 686 frame_rtc_times_ms_.push_back(GetCurrentTimeMs()); |
| 653 | 687 |
| 654 const bool key_frame = frame_types->front() != webrtc::kVideoFrameDelta; | 688 const bool key_frame = |
| 689 frame_types->front() != webrtc::kVideoFrameDelta || send_key_frame; |
| 655 bool encode_status = true; | 690 bool encode_status = true; |
| 656 if (!input_frame.native_handle()) { | 691 if (!input_frame.native_handle()) { |
| 657 int j_input_buffer_index = jni->CallIntMethod(*j_media_codec_video_encoder_, | 692 int j_input_buffer_index = jni->CallIntMethod(*j_media_codec_video_encoder_, |
| 658 j_dequeue_input_buffer_method_); | 693 j_dequeue_input_buffer_method_); |
| 659 CHECK_EXCEPTION(jni); | 694 CHECK_EXCEPTION(jni); |
| 660 if (j_input_buffer_index == -1) { | 695 if (j_input_buffer_index == -1) { |
| 661 // Video codec falls behind - no input buffer available. | 696 // Video codec falls behind - no input buffer available. |
| 662 ALOGW << "Encoder drop frame - no input buffers available"; | 697 ALOGW << "Encoder drop frame - no input buffers available"; |
| 663 current_timestamp_us_ += rtc::kNumMicrosecsPerSec / last_set_fps_; | 698 current_timestamp_us_ += rtc::kNumMicrosecsPerSec / last_set_fps_; |
| 664 frame_rtc_times_ms_.erase(frame_rtc_times_ms_.begin()); | 699 frame_rtc_times_ms_.erase(frame_rtc_times_ms_.begin()); |
| (...skipping 541 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1206 } | 1241 } |
| 1207 | 1242 |
| 1208 void MediaCodecVideoEncoderFactory::DestroyVideoEncoder( | 1243 void MediaCodecVideoEncoderFactory::DestroyVideoEncoder( |
| 1209 webrtc::VideoEncoder* encoder) { | 1244 webrtc::VideoEncoder* encoder) { |
| 1210 ALOGD << "Destroy video encoder."; | 1245 ALOGD << "Destroy video encoder."; |
| 1211 delete encoder; | 1246 delete encoder; |
| 1212 } | 1247 } |
| 1213 | 1248 |
| 1214 } // namespace webrtc_jni | 1249 } // namespace webrtc_jni |
| 1215 | 1250 |
| OLD | NEW |