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

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: Created 5 years 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 16 matching lines...) Expand all
27 */ 27 */
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 "webrtc/base/bind.h" 32 #include "webrtc/base/bind.h"
33 #include "webrtc/base/checks.h" 33 #include "webrtc/base/checks.h"
34 #include "webrtc/base/logging.h" 34 #include "webrtc/base/logging.h"
35 #include "webrtc/base/thread.h" 35 #include "webrtc/base/thread.h"
36 #include "webrtc/base/thread_checker.h" 36 #include "webrtc/base/thread_checker.h"
37 #include "webrtc/common_types.h"
37 #include "webrtc/modules/rtp_rtcp/source/h264_bitstream_parser.h" 38 #include "webrtc/modules/rtp_rtcp/source/h264_bitstream_parser.h"
38 #include "webrtc/modules/video_coding/codecs/interface/video_codec_interface.h" 39 #include "webrtc/modules/video_coding/codecs/interface/video_codec_interface.h"
39 #include "webrtc/modules/video_coding/utility/include/quality_scaler.h" 40 #include "webrtc/modules/video_coding/utility/include/quality_scaler.h"
40 #include "webrtc/modules/video_coding/utility/include/vp8_header_parser.h" 41 #include "webrtc/modules/video_coding/utility/include/vp8_header_parser.h"
41 #include "webrtc/system_wrappers/include/field_trial.h" 42 #include "webrtc/system_wrappers/include/field_trial.h"
42 #include "webrtc/system_wrappers/include/logcat_trace_context.h" 43 #include "webrtc/system_wrappers/include/logcat_trace_context.h"
43 #include "third_party/libyuv/include/libyuv/convert.h" 44 #include "third_party/libyuv/include/libyuv/convert.h"
44 #include "third_party/libyuv/include/libyuv/convert_from.h" 45 #include "third_party/libyuv/include/libyuv/convert_from.h"
45 #include "third_party/libyuv/include/libyuv/video_common.h" 46 #include "third_party/libyuv/include/libyuv/video_common.h"
46 47
(...skipping 16 matching lines...) Expand all
63 // H.264 start code length. 64 // H.264 start code length.
64 #define H264_SC_LENGTH 4 65 #define H264_SC_LENGTH 4
65 // Maximum allowed NALUs in one output frame. 66 // Maximum allowed NALUs in one output frame.
66 #define MAX_NALUS_PERFRAME 32 67 #define MAX_NALUS_PERFRAME 32
67 // Maximum supported HW video encoder resolution. 68 // Maximum supported HW video encoder resolution.
68 #define MAX_VIDEO_WIDTH 1280 69 #define MAX_VIDEO_WIDTH 1280
69 #define MAX_VIDEO_HEIGHT 1280 70 #define MAX_VIDEO_HEIGHT 1280
70 // Maximum supported HW video encoder fps. 71 // Maximum supported HW video encoder fps.
71 #define MAX_VIDEO_FPS 30 72 #define MAX_VIDEO_FPS 30
72 73
74 namespace {
75 // Maximum time limit between incoming frames before requesting a key frame.
76 const size_t kFrameDiffThresholdMs = 1100;
77 const int kMinKeyFrameInterval = 2;
78 } // namespace
79
73 // MediaCodecVideoEncoder is a webrtc::VideoEncoder implementation that uses 80 // MediaCodecVideoEncoder is a webrtc::VideoEncoder implementation that uses
74 // Android's MediaCodec SDK API behind the scenes to implement (hopefully) 81 // Android's MediaCodec SDK API behind the scenes to implement (hopefully)
75 // HW-backed video encode. This C++ class is implemented as a very thin shim, 82 // HW-backed video encode. This C++ class is implemented as a very thin shim,
76 // delegating all of the interesting work to org.webrtc.MediaCodecVideoEncoder. 83 // delegating all of the interesting work to org.webrtc.MediaCodecVideoEncoder.
77 // MediaCodecVideoEncoder is created, operated, and destroyed on a single 84 // MediaCodecVideoEncoder is created, operated, and destroyed on a single
78 // thread, currently the libjingle Worker thread. 85 // thread, currently the libjingle Worker thread.
79 class MediaCodecVideoEncoder : public webrtc::VideoEncoder, 86 class MediaCodecVideoEncoder : public webrtc::VideoEncoder,
80 public rtc::MessageHandler { 87 public rtc::MessageHandler {
81 public: 88 public:
82 virtual ~MediaCodecVideoEncoder(); 89 virtual ~MediaCodecVideoEncoder();
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after
206 // and the next Encode() call being ignored. 213 // and the next Encode() call being ignored.
207 bool drop_next_input_frame_; 214 bool drop_next_input_frame_;
208 // Global references; must be deleted in Release(). 215 // Global references; must be deleted in Release().
209 std::vector<jobject> input_buffers_; 216 std::vector<jobject> input_buffers_;
210 webrtc::QualityScaler quality_scaler_; 217 webrtc::QualityScaler quality_scaler_;
211 // Dynamic resolution change, off by default. 218 // Dynamic resolution change, off by default.
212 bool scale_; 219 bool scale_;
213 220
214 // H264 bitstream parser, used to extract QP from encoded bitstreams. 221 // H264 bitstream parser, used to extract QP from encoded bitstreams.
215 webrtc::H264BitstreamParser h264_bitstream_parser_; 222 webrtc::H264BitstreamParser h264_bitstream_parser_;
223
224 // Temporary fix for VP8.
225 // Sends a key frame if frames are largely spaced apart (possibly
226 // corresponding to a large image change).
227 int64_t last_frame_received_ms_;
228 int frames_received_since_last_key_;
229 webrtc::VideoCodecMode codec_mode_;
216 }; 230 };
217 231
218 MediaCodecVideoEncoder::~MediaCodecVideoEncoder() { 232 MediaCodecVideoEncoder::~MediaCodecVideoEncoder() {
219 // Call Release() to ensure no more callbacks to us after we are deleted. 233 // Call Release() to ensure no more callbacks to us after we are deleted.
220 Release(); 234 Release();
221 } 235 }
222 236
223 MediaCodecVideoEncoder::MediaCodecVideoEncoder( 237 MediaCodecVideoEncoder::MediaCodecVideoEncoder(
224 JNIEnv* jni, VideoCodecType codecType) : 238 JNIEnv* jni, VideoCodecType codecType) :
225 codecType_(codecType), 239 codecType_(codecType),
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
300 if (codec_settings == NULL) { 314 if (codec_settings == NULL) {
301 ALOGE << "NULL VideoCodec instance"; 315 ALOGE << "NULL VideoCodec instance";
302 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; 316 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
303 } 317 }
304 // Factory should guard against other codecs being used with us. 318 // Factory should guard against other codecs being used with us.
305 RTC_CHECK(codec_settings->codecType == codecType_) 319 RTC_CHECK(codec_settings->codecType == codecType_)
306 << "Unsupported codec " << codec_settings->codecType << " for " 320 << "Unsupported codec " << codec_settings->codecType << " for "
307 << codecType_; 321 << codecType_;
308 322
309 ALOGD << "InitEncode request"; 323 ALOGD << "InitEncode request";
324 codec_mode_ = codec_settings->mode;
310 scale_ = webrtc::field_trial::FindFullName( 325 scale_ = webrtc::field_trial::FindFullName(
311 "WebRTC-MediaCodecVideoEncoder-AutomaticResize") == "Enabled"; 326 "WebRTC-MediaCodecVideoEncoder-AutomaticResize") == "Enabled";
312 ALOGD << "Encoder automatic resize " << (scale_ ? "enabled" : "disabled"); 327 ALOGD << "Encoder automatic resize " << (scale_ ? "enabled" : "disabled");
313 if (scale_) { 328 if (scale_) {
314 if (codecType_ == kVideoCodecVP8) { 329 if (codecType_ == kVideoCodecVP8) {
315 // QP is obtained from VP8-bitstream for HW, so the QP corresponds to the 330 // QP is obtained from VP8-bitstream for HW, so the QP corresponds to the
316 // (internal) range: [0, 127]. And we cannot change QP_max in HW, so it is 331 // (internal) range: [0, 127]. And we cannot change QP_max in HW, so it is
317 // always = 127. Note that in SW, QP is that of the user-level range [0, 332 // always = 127. Note that in SW, QP is that of the user-level range [0,
318 // 63]. 333 // 63].
319 const int kMaxQp = 127; 334 const int kMaxQp = 127;
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after
451 current_encoding_time_ms_ = 0; 466 current_encoding_time_ms_ = 0;
452 last_input_timestamp_ms_ = -1; 467 last_input_timestamp_ms_ = -1;
453 last_output_timestamp_ms_ = -1; 468 last_output_timestamp_ms_ = -1;
454 output_timestamp_ = 0; 469 output_timestamp_ = 0;
455 output_render_time_ms_ = 0; 470 output_render_time_ms_ = 0;
456 timestamps_.clear(); 471 timestamps_.clear();
457 render_times_ms_.clear(); 472 render_times_ms_.clear();
458 frame_rtc_times_ms_.clear(); 473 frame_rtc_times_ms_.clear();
459 drop_next_input_frame_ = false; 474 drop_next_input_frame_ = false;
460 picture_id_ = static_cast<uint16_t>(rand()) & 0x7FFF; 475 picture_id_ = static_cast<uint16_t>(rand()) & 0x7FFF;
476 last_frame_received_ms_ = -1;
477 frames_received_since_last_key_ = kMinKeyFrameInterval;
461 478
462 // We enforce no extra stride/padding in the format creation step. 479 // We enforce no extra stride/padding in the format creation step.
463 jobject j_video_codec_enum = JavaEnumFromIndex( 480 jobject j_video_codec_enum = JavaEnumFromIndex(
464 jni, "MediaCodecVideoEncoder$VideoCodecType", codecType_); 481 jni, "MediaCodecVideoEncoder$VideoCodecType", codecType_);
465 const bool encode_status = jni->CallBooleanMethod( 482 const bool encode_status = jni->CallBooleanMethod(
466 *j_media_codec_video_encoder_, j_init_encode_method_, 483 *j_media_codec_video_encoder_, j_init_encode_method_,
467 j_video_codec_enum, width, height, kbps, fps); 484 j_video_codec_enum, width, height, kbps, fps);
468 if (!encode_status) { 485 if (!encode_status) {
469 ALOGE << "Failed to configure encoder."; 486 ALOGE << "Failed to configure encoder.";
470 return WEBRTC_VIDEO_CODEC_ERROR; 487 return WEBRTC_VIDEO_CODEC_ERROR;
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
517 const webrtc::VideoFrame& frame, 534 const webrtc::VideoFrame& frame,
518 const std::vector<webrtc::FrameType>* frame_types) { 535 const std::vector<webrtc::FrameType>* frame_types) {
519 RTC_DCHECK(codec_thread_checker_.CalledOnValidThread()); 536 RTC_DCHECK(codec_thread_checker_.CalledOnValidThread());
520 JNIEnv* jni = AttachCurrentThreadIfNeeded(); 537 JNIEnv* jni = AttachCurrentThreadIfNeeded();
521 ScopedLocalRefFrame local_ref_frame(jni); 538 ScopedLocalRefFrame local_ref_frame(jni);
522 539
523 if (!inited_) { 540 if (!inited_) {
524 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; 541 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
525 } 542 }
526 543
544 bool send_key_frame = false;
545 if (codecType_ == kVideoCodecVP8 && codec_mode_ == webrtc::kRealtimeVideo) {
546 ++frames_received_since_last_key_;
547 int64_t now_ms = GetCurrentTimeMs();
548 if (last_frame_received_ms_ != -1 &&
549 (now_ms - last_frame_received_ms_) > kFrameDiffThresholdMs) {
550 if (frames_received_since_last_key_ > kMinKeyFrameInterval) {
stefan-webrtc 2016/01/18 20:02:36 What if there are two camera switches close to eac
åsapersson 2016/01/19 12:22:17 Yes will not work if there are two camera switches
551 ALOGD << "Send key, frame diff: " << (now_ms - last_frame_received_ms_);
552 send_key_frame = true;
553 }
554 frames_received_since_last_key_ = 0;
555 }
556 last_frame_received_ms_ = now_ms;
557 }
558
527 frames_received_++; 559 frames_received_++;
528 if (!DeliverPendingOutputs(jni)) { 560 if (!DeliverPendingOutputs(jni)) {
529 if (!ResetCodecOnCodecThread()) 561 if (!ResetCodecOnCodecThread())
530 return WEBRTC_VIDEO_CODEC_ERROR; 562 return WEBRTC_VIDEO_CODEC_ERROR;
531 } 563 }
532 564
533 if (drop_next_input_frame_) { 565 if (drop_next_input_frame_) {
534 ALOGW << "Encoder drop frame - failed callback."; 566 ALOGW << "Encoder drop frame - failed callback.";
535 drop_next_input_frame_ = false; 567 drop_next_input_frame_ = false;
536 return WEBRTC_VIDEO_CODEC_OK; 568 return WEBRTC_VIDEO_CODEC_OK;
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
582 614
583 last_input_timestamp_ms_ = 615 last_input_timestamp_ms_ =
584 current_timestamp_us_ / rtc::kNumMicrosecsPerMillisec; 616 current_timestamp_us_ / rtc::kNumMicrosecsPerMillisec;
585 frames_in_queue_++; 617 frames_in_queue_++;
586 618
587 // Save input image timestamps for later output 619 // Save input image timestamps for later output
588 timestamps_.push_back(input_frame.timestamp()); 620 timestamps_.push_back(input_frame.timestamp());
589 render_times_ms_.push_back(input_frame.render_time_ms()); 621 render_times_ms_.push_back(input_frame.render_time_ms());
590 frame_rtc_times_ms_.push_back(GetCurrentTimeMs()); 622 frame_rtc_times_ms_.push_back(GetCurrentTimeMs());
591 623
592 const bool key_frame = frame_types->front() != webrtc::kVideoFrameDelta; 624 const bool key_frame =
625 frame_types->front() != webrtc::kVideoFrameDelta || send_key_frame;
stefan-webrtc 2016/01/18 20:02:36 Why isn't this == kVideoFrameKey? Now we will gene
åsapersson 2016/01/19 12:22:17 Right seems a bit wrong, not sure about the reason
593 const bool encode_status = 626 const bool encode_status =
594 EncodeByteBufferOnCodecThread(jni, key_frame, input_frame, 627 EncodeByteBufferOnCodecThread(jni, key_frame, input_frame,
595 j_input_buffer_index); 628 j_input_buffer_index);
596 629
597 current_timestamp_us_ += rtc::kNumMicrosecsPerSec / last_set_fps_; 630 current_timestamp_us_ += rtc::kNumMicrosecsPerSec / last_set_fps_;
598 631
599 if (!encode_status || !DeliverPendingOutputs(jni)) { 632 if (!encode_status || !DeliverPendingOutputs(jni)) {
600 ALOGE << "Failed deliver pending outputs."; 633 ALOGE << "Failed deliver pending outputs.";
601 ResetCodecOnCodecThread(); 634 ResetCodecOnCodecThread();
602 return WEBRTC_VIDEO_CODEC_ERROR; 635 return WEBRTC_VIDEO_CODEC_ERROR;
(...skipping 405 matching lines...) Expand 10 before | Expand all | Expand 10 after
1008 } 1041 }
1009 1042
1010 void MediaCodecVideoEncoderFactory::DestroyVideoEncoder( 1043 void MediaCodecVideoEncoderFactory::DestroyVideoEncoder(
1011 webrtc::VideoEncoder* encoder) { 1044 webrtc::VideoEncoder* encoder) {
1012 ALOGD << "Destroy video encoder."; 1045 ALOGD << "Destroy video encoder.";
1013 delete encoder; 1046 delete encoder;
1014 } 1047 }
1015 1048
1016 } // namespace webrtc_jni 1049 } // namespace webrtc_jni
1017 1050
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