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

Side by Side Diff: talk/app/webrtc/java/jni/androidmediaencoder_jni.cc

Issue 1510913007: Send key frame if time difference between incoming frames exceeds a certain limit. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: rebase Created 4 years, 11 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 | « no previous file | 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 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
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698