From: Dan Minor Date: Mon, 22 Jan 2018 13:31:00 -0500 Subject: Bug 1376873 - Rollup of local modifications; r=ng MozReview-Commit-ID: 2euYzBEvuNb Differential Revision: https://phabricator.services.mozilla.com/D7425 Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/28b57e3ba51de982a4663801a3935580114b5477 Bug 1376873 - Rollup conflict fixes for audio/video code; r=pehrsons MozReview-Commit-ID: 1T8mgqdkzq3 Differential Revision: https://phabricator.services.mozilla.com/D7427 Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/93eec571640ee0810da8475ee37e417b88045574 Bug 1376873 - Rollup conflict fixes for rtp_rtcp module; r=ng MozReview-Commit-ID: D09534DOVLj Differential Revision: https://phabricator.services.mozilla.com/D7428 Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/50f89f4e45b0af87fd6aa45aed60f02f3e69b951 Bug 1497552 - Remove support for 44100 Hz in dtmf_tone_generator; r=padenot Assertions in NetEqImpl::SetSampleRateAndChannels prevent us from requesting tones at 44100 Hz, so this code can be safely removed. Differential Revision: https://phabricator.services.mozilla.com/D12982 Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/8ea04ec01e9905d4714aa01ade891d552c56a3a6 Bug 1497577 - Remove code to detect zero size windows; r=ng This code was added by Bug 1196542 to fix a permanently failing test on our Windows test machines. After this landed, upstream added a check for empty windows in window_captuer_win.cc, so this should no longer be a problem on Windows. As far as I know, this was never a problem on the other platforms, so this code can be safely removed. Differential Revision: https://phabricator.services.mozilla.com/D13448 Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/647ade4da0fba74a268aab079677cb47f20f036e Bug 1509994 - Move video_engine from webrtc to systemservices; r=pehrsons Historically this code was part of webrtc.org but has since been removed from upstream. Rather than maintaining it as a local diff against upstream, we should just move it to where it is used. Differential Revision: https://phabricator.services.mozilla.com/D13092 Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/0fd399c6caabff60ac0fe53b920b7d26a9806750 Bug 1497606 - Remove disable_composition_ in screen_capturer_win_gdi; r=ng This removes disable_composition_ and instead uses the value of composition_func_ to determine whether or not composition is disabled. This is what is done by upstream webrtc.org. We call options.set_disable_effects(false) in desktop_capture_impl.cc. Differential Revision: https://phabricator.services.mozilla.com/D13839 Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/b3f5cca4be44c01024b1ef7b5d4951c7297a112a Bug 1497974 - Remove local changes to jitter_buffer.cc; r=pehrsons These modifications are made to code which we do not use and so can be removed. Differential Revision: https://phabricator.services.mozilla.com/D13989 Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/2fb1dd0d8344ef24e2e0fca94725bbfaf59aa257 Bug 1512459 - Remove webrtc sndio audio device; r=padenot This code is unused and can be removed. Differential Revision: https://phabricator.services.mozilla.com/D13929 Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/fa0a179388e96b1a47eeef2fda9676812c244d3b Bug 1497650 - Remove 100 bytes added to CalcBufferSize in vp8_impl.cc; r=ng In Bug 919979 we added 100 bytes to the size returned by CalcBufferSize to work around an error with the calculated buffer size with small resolutions. I verified that this extra buffer is no longer required with a modified mochitest. Given the age of the bug this was working around, I don't think a permanent test is required to prevent regressions from upstream. Differential Revision: https://phabricator.services.mozilla.com/D14076 Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/b20329b1ec0565b3b94db73e13a9c49e43c418c3 Bug 1368816 - Enable VideoCaptureExternalTest Rotation gtest; r=ng This test started failing after the 57 update and started passing again after the 64 update, so we might as well enable it. Differential Revision: https://phabricator.services.mozilla.com/D13803 Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/65a44b43b7b69c066abcb864076003252abc475e Bug 1497573 - Remove DesktopCapturer::Stop; r=ng Differential Revision: https://phabricator.services.mozilla.com/D14066 Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/0d9c607f26195b7f63cca847224bcd137f73720d Bug 1497619 - Restore thread check in process_thread_impl.cc; r=ng Not not really needed. Differential Revision: https://phabricator.services.mozilla.com/D14097 Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/923373fdf5e50d44c895141dc1db74709d6610fe Bug 1497992 - Remove VideoReceiver::Reset; r=pehrsons This ends up calling VCMReceiver::Reset() which resets the state of the VCMJitterBuffer. We no longer use VCMJitterBuffer, which is the old jitter buffer implementation, so this code no longer has any effect and can be removed. Differential Revision: https://phabricator.services.mozilla.com/D14185 Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/9e526b3093ee60791cf9c436ea06b6665eb5ef74 Bug 1497610 - Remove IsNewerOrSameTimestamp; r=bwc The affected functions are only used by VCMJitterBuffer, which is the older jitter buffer that is no longer in use. We can safely remove these modifications. Differential Revision: https://phabricator.services.mozilla.com/D14485 Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/5ed0ed11b23d82ee026244a9a48e522fe38335e2 Bug 1498253 - Remove mozAvSyncDelay and mozJitterBufferDelay; r=ng The value for mozAvSyncDelay has been broken since the branch 57 update (Bug 1341285). We added SetCurrentSyncOffset() but never called it from anywhere. In the future we should be getting stats from AudioReceiveStream rather than modifying the channel code, the delay_estimate_ms field provides almost the same information. Since we're attempting to get rid of moz prefixed stats, it makes sense to just remove this code rather than fix it. The associated telemetry code has been broken since Bug 1341285 as well so I think it is safe to remove. Differential Revision: https://phabricator.services.mozilla.com/D14462 Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/80e86c169d202e724cda74bbd9535b2d5236305b Bug 1498205 - Move PlatformUIThread from rtc_base to video_engine; r=pehrsons PlatformUIThread is only used by the video_engine code, so it makes sense to move it there rather than maintain it as a diff against upstream webrtc.org. Differential Revision: https://phabricator.services.mozilla.com/D13531 Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/65bf3e37a4409f3ca0350366d7be19368adfa21b Bug 1497602 - Enable DirectX screen capturer on Windows; r=pehrsons This enables support for the DirectX screen capturer. We use the default DesktopCaptureOptions which do not set the option to use the DirectX screen capturer so this change will have no effect with the current code. For what it's worth, I tested enabling the DirectX option and it worked fine on my system, but I don't see any reason to not follow the defaults provided by webrtc.org in this case. Differential Revision: https://phabricator.services.mozilla.com/D13303 Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/eb07312cfbe868780ebed84fc83e5a5470e81fb4 Bug 1439997 - Remove old mac video capture code; r=jib This code is no longer used and has been removed upstream. We can remove it as well. Differential Revision: https://phabricator.services.mozilla.com/D15196 Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/e79251fa381cfc9f3425f6a746ac8d8c22046d6b Bug 1376873 - Updates to Android video capture; r=pehrsons Differential Revision: https://phabricator.services.mozilla.com/D7452 Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/1e6d72de0587d24c20fefc142591d8b47c363f89 Bug 1578073 - Move android video capture code to dom/media/systemservices; r=jib Although originally part of webrtc.org, this code has subsequently been removed by upstream. Moving it to under dom/media should make it clearer that this is code that we are maintaining and simplify future upstream merges. Differential Revision: https://phabricator.services.mozilla.com/D61850 Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/46c21affcbc14da30abb03b10573076aee6341c0 Bug 1652552 - Remove remaining application capture code; r=jib Differential Revision: https://phabricator.services.mozilla.com/D83491 Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/26eee332d844bd3f9479d1db92d2f000255664c1 --- api/rtp_headers.cc | 3 +- api/rtp_headers.h | 17 +- api/rtp_parameters.cc | 3 +- call/BUILD.gn | 4 +- call/video_receive_stream.h | 2 + modules/audio_coding/acm2/acm_receiver.h | 12 +- modules/audio_coding/neteq/dtmf_buffer.cc | 6 +- modules/audio_coding/neteq/merge.cc | 6 + .../logging/apm_data_dumper.cc | 23 ++- .../logging/apm_data_dumper.h | 67 ++++-- modules/desktop_capture/desktop_capturer.h | 1 + .../desktop_capture/fake_desktop_capturer.cc | 4 +- .../linux/x11/mouse_cursor_monitor_x11.cc | 4 +- .../linux/x11/screen_capturer_x11.cc | 2 +- .../linux/x11/window_capturer_x11.cc | 12 +- .../linux/x11/window_capturer_x11.h | 4 + .../desktop_capture/linux/x11/x_error_trap.cc | 70 ++++--- .../desktop_capture/linux/x11/x_error_trap.h | 29 ++- .../mouse_cursor_monitor_win.cc | 7 +- .../win/screen_capture_utils.cc | 3 +- .../win/screen_capturer_win_gdi.cc | 1 + .../win/screen_capturer_win_magnifier.cc | 16 +- modules/rtp_rtcp/source/rtcp_sender.cc | 2 +- .../rtp_rtcp/source/rtp_header_extensions.cc | 39 ++++ .../rtp_rtcp/source/rtp_header_extensions.h | 15 ++ modules/rtp_rtcp/source/rtp_packet.cc | 4 + .../rtp_rtcp/source/rtp_packet_unittest.cc | 30 +++ modules/rtp_rtcp/source/rtp_rtcp_config.h | 2 + modules/rtp_rtcp/source/rtp_sender.cc | 4 + modules/utility/source/jvm_android.cc | 28 ++- modules/video_capture/device_info_impl.cc | 2 +- modules/video_capture/device_info_impl.h | 1 + .../video_capture/linux/device_info_v4l2.cc | 193 +++++++++++++++++- .../video_capture/linux/device_info_v4l2.h | 18 +- .../video_capture/linux/video_capture_v4l2.cc | 7 + modules/video_capture/video_capture.h | 45 +++- .../video_capture/video_capture_factory.cc | 8 - modules/video_capture/video_capture_impl.cc | 36 +++- modules/video_capture/video_capture_impl.h | 6 +- .../codecs/vp9/libvpx_vp9_encoder.cc | 2 + .../codecs/vp9/libvpx_vp9_encoder.h | 4 + modules/video_coding/generic_decoder.cc | 5 +- modules/video_coding/session_info.cc | 32 ++- test/fuzzers/rtp_packet_fuzzer.cc | 5 + test/vcm_capturer.cc | 2 +- 45 files changed, 652 insertions(+), 134 deletions(-) diff --git a/api/rtp_headers.cc b/api/rtp_headers.cc index e0ad9eb26e..8e1efc7262 100644 --- a/api/rtp_headers.cc +++ b/api/rtp_headers.cc @@ -26,7 +26,8 @@ RTPHeaderExtension::RTPHeaderExtension() videoRotation(kVideoRotation_0), hasVideoContentType(false), videoContentType(VideoContentType::UNSPECIFIED), - has_video_timing(false) {} + has_video_timing(false), + csrcAudioLevels() {} RTPHeaderExtension::RTPHeaderExtension(const RTPHeaderExtension& other) = default; diff --git a/api/rtp_headers.h b/api/rtp_headers.h index 743fd6d1b6..261c984d05 100644 --- a/api/rtp_headers.h +++ b/api/rtp_headers.h @@ -89,6 +89,19 @@ inline bool operator!=(const AbsoluteCaptureTime& lhs, return !(lhs == rhs); } +enum { kRtpCsrcSize = 15 }; // RFC 3550 page 13 + +// Audio level of CSRCs See: +// https://tools.ietf.org/html/rfc6465 +struct CsrcAudioLevelList { + CsrcAudioLevelList() : numAudioLevels(0) { } + CsrcAudioLevelList(const CsrcAudioLevelList&) = default; + CsrcAudioLevelList& operator=(const CsrcAudioLevelList&) = default; + uint8_t numAudioLevels; + // arrOfAudioLevels has the same ordering as RTPHeader.arrOfCSRCs + uint8_t arrOfAudioLevels[kRtpCsrcSize]; +}; + struct RTPHeaderExtension { RTPHeaderExtension(); RTPHeaderExtension(const RTPHeaderExtension& other); @@ -144,9 +157,9 @@ struct RTPHeaderExtension { std::string mid; absl::optional color_space; -}; -enum { kRtpCsrcSize = 15 }; // RFC 3550 page 13 + CsrcAudioLevelList csrcAudioLevels; +}; struct RTC_EXPORT RTPHeader { RTPHeader(); diff --git a/api/rtp_parameters.cc b/api/rtp_parameters.cc index c48b8da02c..c1d12e5d8d 100644 --- a/api/rtp_parameters.cc +++ b/api/rtp_parameters.cc @@ -148,7 +148,8 @@ bool RtpExtension::IsSupportedForAudio(absl::string_view uri) { uri == webrtc::RtpExtension::kTransportSequenceNumberV2Uri || uri == webrtc::RtpExtension::kMidUri || uri == webrtc::RtpExtension::kRidUri || - uri == webrtc::RtpExtension::kRepairedRidUri; + uri == webrtc::RtpExtension::kRepairedRidUri || + uri == webrtc::RtpExtension::kCsrcAudioLevelsUri; } bool RtpExtension::IsSupportedForVideo(absl::string_view uri) { diff --git a/call/BUILD.gn b/call/BUILD.gn index f4c3295ff5..0e52e8fb3f 100644 --- a/call/BUILD.gn +++ b/call/BUILD.gn @@ -20,6 +20,7 @@ rtc_library("call_interfaces") { sources = [ "audio_receive_stream.cc", "audio_receive_stream.h", + "audio_send_stream.cc", "audio_send_stream.h", "audio_state.cc", "audio_state.h", @@ -32,9 +33,6 @@ rtc_library("call_interfaces") { "syncable.cc", "syncable.h", ] - if (!build_with_mozilla) { - sources += [ "audio_send_stream.cc" ] - } deps = [ ":audio_sender_interface", diff --git a/call/video_receive_stream.h b/call/video_receive_stream.h index 0fa257e5ba..15b313a3b9 100644 --- a/call/video_receive_stream.h +++ b/call/video_receive_stream.h @@ -199,6 +199,8 @@ class VideoReceiveStreamInterface : public MediaReceiveStreamInterface { // disabled. KeyFrameReqMethod keyframe_method = KeyFrameReqMethod::kPliRtcp; + bool tmmbr = false; + // See LntfConfig for description. LntfConfig lntf; diff --git a/modules/audio_coding/acm2/acm_receiver.h b/modules/audio_coding/acm2/acm_receiver.h index 18b662aed0..a61247627f 100644 --- a/modules/audio_coding/acm2/acm_receiver.h +++ b/modules/audio_coding/acm2/acm_receiver.h @@ -18,6 +18,7 @@ #include #include #include +#include #include "absl/types/optional.h" #include "api/array_view.h" @@ -215,12 +216,15 @@ class AcmReceiver { mutable Mutex mutex_; absl::optional last_decoder_ RTC_GUARDED_BY(mutex_); - ACMResampler resampler_ RTC_GUARDED_BY(mutex_); - std::unique_ptr last_audio_buffer_ RTC_GUARDED_BY(mutex_); - CallStatistics call_stats_ RTC_GUARDED_BY(mutex_); + ACMResampler resampler_; + + // After construction, this is only ever touched on the thread that calls + // AcmReceiver::GetAudio, and only modified in this method. + std::unique_ptr last_audio_buffer_; + CallStatistics call_stats_; const std::unique_ptr neteq_; // NetEq is thread-safe; no lock needed. Clock* const clock_; - bool resampled_last_output_frame_ RTC_GUARDED_BY(mutex_); + std::atomic resampled_last_output_frame_; }; } // namespace acm2 diff --git a/modules/audio_coding/neteq/dtmf_buffer.cc b/modules/audio_coding/neteq/dtmf_buffer.cc index 9f78aca6e2..115bfcf97b 100644 --- a/modules/audio_coding/neteq/dtmf_buffer.cc +++ b/modules/audio_coding/neteq/dtmf_buffer.cc @@ -193,7 +193,11 @@ bool DtmfBuffer::Empty() const { } int DtmfBuffer::SetSampleRate(int fs_hz) { - if (fs_hz != 8000 && fs_hz != 16000 && fs_hz != 32000 && fs_hz != 48000) { + if (fs_hz != 8000 && + fs_hz != 16000 && + fs_hz != 32000 && + fs_hz != 44100 && + fs_hz != 48000) { return kInvalidSampleRate; } max_extrapolation_samples_ = 7 * fs_hz / 100; diff --git a/modules/audio_coding/neteq/merge.cc b/modules/audio_coding/neteq/merge.cc index 22cf6a7754..0aec6d2597 100644 --- a/modules/audio_coding/neteq/merge.cc +++ b/modules/audio_coding/neteq/merge.cc @@ -213,6 +213,12 @@ int16_t Merge::SignalScaling(const int16_t* input, // Adjust muting factor if new vector is more or less of the BGN energy. const auto mod_input_length = rtc::SafeMin( 64 * rtc::dchecked_cast(fs_mult_), input_length); + + // Missing input, do no muting + if (mod_input_length == 0) { + return 16384; + } + const int16_t expanded_max = WebRtcSpl_MaxAbsValueW16(expanded_signal, mod_input_length); int32_t factor = diff --git a/modules/audio_processing/logging/apm_data_dumper.cc b/modules/audio_processing/logging/apm_data_dumper.cc index 65d2167d37..f787b65604 100644 --- a/modules/audio_processing/logging/apm_data_dumper.cc +++ b/modules/audio_processing/logging/apm_data_dumper.cc @@ -35,14 +35,20 @@ std::string FormFileName(absl::string_view output_dir, int instance_index, int reinit_index, absl::string_view suffix) { - char buf[1024]; - rtc::SimpleStringBuilder ss(buf); - if (!output_dir.empty()) { - ss << output_dir; - if (output_dir.back() != kPathDelimiter) { - ss << kPathDelimiter; - } +#ifdef WEBRTC_WIN + char sep = '\\'; +#else + char sep = '/'; +#endif + + std::stringstream ss; + std::string base = webrtc::Trace::aec_debug_filename(); + ss << base; + + if (base.length() && base.back() != sep) { + ss << sep; } + ss << name << "_" << instance_index << "-" << reinit_index << suffix; return ss.str(); } @@ -52,7 +58,8 @@ std::string FormFileName(absl::string_view output_dir, #if WEBRTC_APM_DEBUG_DUMP == 1 ApmDataDumper::ApmDataDumper(int instance_index) - : instance_index_(instance_index) {} + : instance_index_(instance_index) + , debug_written_(0) {} #else ApmDataDumper::ApmDataDumper(int instance_index) {} #endif diff --git a/modules/audio_processing/logging/apm_data_dumper.h b/modules/audio_processing/logging/apm_data_dumper.h index 4ab6baad83..aa8496819b 100644 --- a/modules/audio_processing/logging/apm_data_dumper.h +++ b/modules/audio_processing/logging/apm_data_dumper.h @@ -41,7 +41,7 @@ namespace webrtc { // Functor used to use as a custom deleter in the map of file pointers to raw // files. struct RawFileCloseFunctor { - void operator()(FILE* f) const { fclose(f); } + void operator()(FILE* f) const { if (f) fclose(f); } }; #endif @@ -100,6 +100,7 @@ class ApmDataDumper { void InitiateNewSetOfRecordings() { #if WEBRTC_APM_DEBUG_DUMP == 1 ++recording_set_index_; + debug_written_ = 0; #endif } @@ -114,7 +115,9 @@ class ApmDataDumper { if (recording_activated_) { FILE* file = GetRawFile(name); - fwrite(&v, sizeof(v), 1, file); + if (file) { + fwrite(&v, sizeof(v), 1, file); + } } #endif } @@ -129,7 +132,9 @@ class ApmDataDumper { if (recording_activated_) { FILE* file = GetRawFile(name); - fwrite(v, sizeof(v[0]), v_length, file); + if (file) { + fwrite(v, sizeof(v[0]), v_length, file); + } } #endif } @@ -156,7 +161,9 @@ class ApmDataDumper { if (recording_activated_) { FILE* file = GetRawFile(name); - fwrite(&v, sizeof(v), 1, file); + if (file) { + fwrite(&v, sizeof(v), 1, file); + } } #endif } @@ -171,7 +178,9 @@ class ApmDataDumper { if (recording_activated_) { FILE* file = GetRawFile(name); - fwrite(v, sizeof(v[0]), v_length, file); + if (file) { + fwrite(v, sizeof(v[0]), v_length, file); + } } #endif } @@ -210,9 +219,11 @@ class ApmDataDumper { if (recording_activated_) { FILE* file = GetRawFile(name); - for (size_t k = 0; k < v_length; ++k) { - int16_t value = static_cast(v[k]); - fwrite(&value, sizeof(value), 1, file); + if (file) { + for (size_t k = 0; k < v_length; ++k) { + int16_t value = static_cast(v[k]); + fwrite(&value, sizeof(value), 1, file); + } } } #endif @@ -240,7 +251,9 @@ class ApmDataDumper { if (recording_activated_) { FILE* file = GetRawFile(name); - fwrite(&v, sizeof(v), 1, file); + if (file) { + fwrite(&v, sizeof(v), 1, file); + } } #endif } @@ -255,7 +268,9 @@ class ApmDataDumper { if (recording_activated_) { FILE* file = GetRawFile(name); - fwrite(v, sizeof(v[0]), v_length, file); + if (file) { + fwrite(v, sizeof(v[0]), v_length, file); + } } #endif } @@ -282,7 +297,9 @@ class ApmDataDumper { if (recording_activated_) { FILE* file = GetRawFile(name); - fwrite(&v, sizeof(v), 1, file); + if (file) { + fwrite(&v, sizeof(v), 1, file); + } } #endif } @@ -297,7 +314,9 @@ class ApmDataDumper { if (recording_activated_) { FILE* file = GetRawFile(name); - fwrite(v, sizeof(v[0]), v_length, file); + if (file) { + fwrite(v, sizeof(v[0]), v_length, file); + } } #endif } @@ -311,7 +330,9 @@ class ApmDataDumper { if (recording_activated_) { FILE* file = GetRawFile(name); - fwrite(&v, sizeof(v), 1, file); + if (file) { + fwrite(&v, sizeof(v), 1, file); + } } #endif } @@ -326,7 +347,9 @@ class ApmDataDumper { if (recording_activated_) { FILE* file = GetRawFile(name); - fwrite(v, sizeof(v[0]), v_length, file); + if (file) { + fwrite(v, sizeof(v[0]), v_length, file); + } } #endif } @@ -369,6 +392,12 @@ class ApmDataDumper { WavWriter* file = GetWavFile(name, sample_rate_hz, num_channels, WavFile::SampleFormat::kFloat); file->WriteSamples(v, v_length); + // Cheat and use aec_near as a stand-in for "size of the largest file" + // in the dump. We're looking to limit the total time, and that's a + // reasonable stand-in. + if (strcmp(name, "aec_near") == 0) { + updateDebugWritten(v_length * sizeof(float)); + } } #endif } @@ -405,6 +434,16 @@ class ApmDataDumper { int sample_rate_hz, int num_channels, WavFile::SampleFormat format); + + uint32_t debug_written_ = 0; + + void updateDebugWritten(uint32_t amount) { + debug_written_ += amount; + if (debug_written_ >= webrtc::Trace::aec_debug_size()) { + SetActivated(false); + } + } + #endif }; diff --git a/modules/desktop_capture/desktop_capturer.h b/modules/desktop_capture/desktop_capturer.h index d336723f18..6909a57891 100644 --- a/modules/desktop_capture/desktop_capturer.h +++ b/modules/desktop_capture/desktop_capturer.h @@ -79,6 +79,7 @@ class RTC_EXPORT DesktopCapturer { struct Source { // The unique id to represent a Source of current DesktopCapturer. SourceId id; + pid_t pid; // Title of the window or screen in UTF-8 encoding, maybe empty. This field // should not be used to identify a source. diff --git a/modules/desktop_capture/fake_desktop_capturer.cc b/modules/desktop_capture/fake_desktop_capturer.cc index f9d9dbd2c4..67149bfcb9 100644 --- a/modules/desktop_capture/fake_desktop_capturer.cc +++ b/modules/desktop_capture/fake_desktop_capturer.cc @@ -72,8 +72,8 @@ void FakeDesktopCapturer::SetSharedMemoryFactory( } bool FakeDesktopCapturer::GetSourceList(DesktopCapturer::SourceList* sources) { - sources->push_back({kWindowId, "A-Fake-DesktopCapturer-Window"}); - sources->push_back({kScreenId}); + sources->push_back({kWindowId, 1, "A-Fake-DesktopCapturer-Window"}); + sources->push_back({kScreenId, 1}); return true; } diff --git a/modules/desktop_capture/linux/x11/mouse_cursor_monitor_x11.cc b/modules/desktop_capture/linux/x11/mouse_cursor_monitor_x11.cc index d9c7635c1d..d4b85af6bd 100644 --- a/modules/desktop_capture/linux/x11/mouse_cursor_monitor_x11.cc +++ b/modules/desktop_capture/linux/x11/mouse_cursor_monitor_x11.cc @@ -38,6 +38,7 @@ namespace { // searches up the list of the windows to find the root child that corresponds // to `window`. Window GetTopLevelWindow(Display* display, Window window) { + webrtc::XErrorTrap error_trap(display); while (true) { // If the window is in WithdrawnState then look at all of its children. ::Window root, parent; @@ -104,7 +105,7 @@ MouseCursorMonitorX11::~MouseCursorMonitorX11() { } void MouseCursorMonitorX11::Init(Callback* callback, Mode mode) { - // Init can be called only once per instance of MouseCursorMonitor. + // Init can be called only if not started RTC_DCHECK(!callback_); RTC_DCHECK(callback); @@ -116,6 +117,7 @@ void MouseCursorMonitorX11::Init(Callback* callback, Mode mode) { if (have_xfixes_) { // Register for changes to the cursor shape. + XErrorTrap error_trap(display()); XFixesSelectCursorInput(display(), window_, XFixesDisplayCursorNotifyMask); x_display_->AddEventHandler(xfixes_event_base_ + XFixesCursorNotify, this); diff --git a/modules/desktop_capture/linux/x11/screen_capturer_x11.cc b/modules/desktop_capture/linux/x11/screen_capturer_x11.cc index d5dcd7af86..fa6334e8ba 100644 --- a/modules/desktop_capture/linux/x11/screen_capturer_x11.cc +++ b/modules/desktop_capture/linux/x11/screen_capturer_x11.cc @@ -302,7 +302,7 @@ bool ScreenCapturerX11::GetSourceList(SourceList* sources) { char* monitor_title = XGetAtomName(display(), m.name); // Note name is an X11 Atom used to id the monitor. - sources->push_back({static_cast(m.name), monitor_title}); + sources->push_back({static_cast(m.name), 0, monitor_title}); XFree(monitor_title); } diff --git a/modules/desktop_capture/linux/x11/window_capturer_x11.cc b/modules/desktop_capture/linux/x11/window_capturer_x11.cc index b55f7e8fa9..2e17d44c0a 100644 --- a/modules/desktop_capture/linux/x11/window_capturer_x11.cc +++ b/modules/desktop_capture/linux/x11/window_capturer_x11.cc @@ -57,6 +57,7 @@ bool WindowCapturerX11::GetSourceList(SourceList* sources) { return GetWindowList(&atom_cache_, [this, sources](::Window window) { Source w; w.id = window; + w.pid = (pid_t)GetWindowProcessID(window); if (this->GetWindowTitle(window, &w.title)) { sources->push_back(w); } @@ -140,6 +141,7 @@ void WindowCapturerX11::Start(Callback* callback) { void WindowCapturerX11::CaptureFrame() { TRACE_EVENT0("webrtc", "WindowCapturerX11::CaptureFrame"); + x_display_->ProcessPendingXEvents(); if (!x_server_pixel_buffer_.IsWindowValid()) { RTC_LOG(LS_ERROR) << "The window is no longer valid."; @@ -147,8 +149,6 @@ void WindowCapturerX11::CaptureFrame() { return; } - x_display_->ProcessPendingXEvents(); - if (!has_composite_extension_) { // Without the Xcomposite extension we capture when the whole window is // visible on screen and not covered by any other window. This is not @@ -237,6 +237,14 @@ bool WindowCapturerX11::GetWindowTitle(::Window window, std::string* title) { return result; } +int WindowCapturerX11::GetWindowProcessID(::Window window) { + // Get _NET_WM_PID property of the window. + Atom process_atom = XInternAtom(display(), "_NET_WM_PID", True); + XWindowProperty process_id(display(), window, process_atom); + + return process_id.is_valid() ? *process_id.data() : 0; +} + // static std::unique_ptr WindowCapturerX11::CreateRawWindowCapturer( const DesktopCaptureOptions& options) { diff --git a/modules/desktop_capture/linux/x11/window_capturer_x11.h b/modules/desktop_capture/linux/x11/window_capturer_x11.h index ac591c272e..cfd29eca66 100644 --- a/modules/desktop_capture/linux/x11/window_capturer_x11.h +++ b/modules/desktop_capture/linux/x11/window_capturer_x11.h @@ -22,6 +22,7 @@ #include "modules/desktop_capture/desktop_capturer.h" #include "modules/desktop_capture/desktop_geometry.h" #include "modules/desktop_capture/linux/x11/shared_x_display.h" +#include "modules/desktop_capture/linux/x11/x_window_property.h" #include "modules/desktop_capture/linux/x11/window_finder_x11.h" #include "modules/desktop_capture/linux/x11/x_atom_cache.h" #include "modules/desktop_capture/linux/x11/x_server_pixel_buffer.h" @@ -57,6 +58,9 @@ class WindowCapturerX11 : public DesktopCapturer, // Returns window title for the specified X `window`. bool GetWindowTitle(::Window window, std::string* title); + // Returns the id of the owning process. + int GetWindowProcessID(::Window window); + Callback* callback_ = nullptr; rtc::scoped_refptr x_display_; diff --git a/modules/desktop_capture/linux/x11/x_error_trap.cc b/modules/desktop_capture/linux/x11/x_error_trap.cc index 94e3a03c73..3314dd286c 100644 --- a/modules/desktop_capture/linux/x11/x_error_trap.cc +++ b/modules/desktop_capture/linux/x11/x_error_trap.cc @@ -10,50 +10,60 @@ #include "modules/desktop_capture/linux/x11/x_error_trap.h" -#include - #include -#include "rtc_base/checks.h" - -namespace webrtc { +#include -namespace { +#include "rtc_base/checks.h" -static int g_last_xserver_error_code = 0; -static std::atomic g_display_for_error_handler = nullptr; -Mutex* AcquireMutex() { - static Mutex* mutex = new Mutex(); - return mutex; -} +namespace webrtc { -int XServerErrorHandler(Display* display, XErrorEvent* error_event) { - RTC_DCHECK_EQ(display, g_display_for_error_handler.load()); - g_last_xserver_error_code = error_event->error_code; - return 0; +Bool XErrorTrap::XServerErrorHandler(Display* display, xReply* rep, + char* /* buf */, int /* len */, + XPointer data) { + XErrorTrap* self = reinterpret_cast(data); + if (rep->generic.type != X_Error || + // Overflow-safe last_request_read <= last_ignored_request_ for skipping + // async replies from requests before XErrorTrap was created. + self->last_ignored_request_ - display->last_request_read < + std::numeric_limits::max() >> 1) + return False; + self->last_xserver_error_code_ = rep->error.errorCode; + return True; } -} // namespace - -XErrorTrap::XErrorTrap(Display* display) : mutex_lock_(AcquireMutex()) { - // We don't expect this class to be used in a nested fashion so therefore - // g_display_for_error_handler should never be valid here. - RTC_DCHECK(!g_display_for_error_handler.load()); - RTC_DCHECK(display); - g_display_for_error_handler.store(display); - g_last_xserver_error_code = 0; - original_error_handler_ = XSetErrorHandler(&XServerErrorHandler); +XErrorTrap::XErrorTrap(Display* display) + : display_(display), + last_xserver_error_code_(0), + enabled_(true) { + // Use async_handlers instead of XSetErrorHandler(). async_handlers can + // remain in place and then be safely removed at the right time even if a + // handler change happens concurrently on another thread. async_handlers + // are processed first and so can prevent errors reaching the global + // XSetErrorHandler handler. They also will not see errors from or affect + // handling of errors on other Displays, which may be processed on other + // threads. + LockDisplay(display); + async_handler_.next = display->async_handlers; + async_handler_.handler = XServerErrorHandler; + async_handler_.data = reinterpret_cast(this); + display->async_handlers = &async_handler_; + last_ignored_request_ = display->request; + UnlockDisplay(display); } int XErrorTrap::GetLastErrorAndDisable() { - g_display_for_error_handler.store(nullptr); - XSetErrorHandler(original_error_handler_); - return g_last_xserver_error_code; + assert(enabled_); + enabled_ = false; + LockDisplay(display_); + DeqAsyncHandler(display_, &async_handler_); + UnlockDisplay(display_); + return last_xserver_error_code_; } XErrorTrap::~XErrorTrap() { - if (g_display_for_error_handler.load() != nullptr) + if (enabled_) GetLastErrorAndDisable(); } diff --git a/modules/desktop_capture/linux/x11/x_error_trap.h b/modules/desktop_capture/linux/x11/x_error_trap.h index 1f21ab969c..df7e86bf03 100644 --- a/modules/desktop_capture/linux/x11/x_error_trap.h +++ b/modules/desktop_capture/linux/x11/x_error_trap.h @@ -11,30 +11,39 @@ #ifndef MODULES_DESKTOP_CAPTURE_LINUX_X11_X_ERROR_TRAP_H_ #define MODULES_DESKTOP_CAPTURE_LINUX_X11_X_ERROR_TRAP_H_ -#include - -#include "rtc_base/synchronization/mutex.h" +#include +#undef max // Xlibint.h defines this and it breaks std::max +#undef min // Xlibint.h defines this and it breaks std::min namespace webrtc { -// Helper class that registers an X Window error handler. Caller can use +// Helper class that registers X Window error handler. Caller can use // GetLastErrorAndDisable() to get the last error that was caught, if any. +// An XErrorTrap may be constructed on any thread, but errors are collected +// from all threads and so |display| should be used only on one thread. +// Other Displays are unaffected. class XErrorTrap { public: explicit XErrorTrap(Display* display); + ~XErrorTrap(); XErrorTrap(const XErrorTrap&) = delete; XErrorTrap& operator=(const XErrorTrap&) = delete; - ~XErrorTrap(); - - // Returns the last error if one was caught, otherwise 0. Also unregisters the - // error handler and replaces it with `original_error_handler_`. + // Returns last error and removes unregisters the error handler. + // Must not be called more than once. int GetLastErrorAndDisable(); private: - MutexLock mutex_lock_; - XErrorHandler original_error_handler_ = nullptr; + static Bool XServerErrorHandler(Display* display, xReply* rep, + char* /* buf */, int /* len */, + XPointer data); + + _XAsyncHandler async_handler_; + Display* display_; + unsigned long last_ignored_request_; + int last_xserver_error_code_; + bool enabled_; }; } // namespace webrtc diff --git a/modules/desktop_capture/mouse_cursor_monitor_win.cc b/modules/desktop_capture/mouse_cursor_monitor_win.cc index c892d59955..18ef43eeb4 100644 --- a/modules/desktop_capture/mouse_cursor_monitor_win.cc +++ b/modules/desktop_capture/mouse_cursor_monitor_win.cc @@ -88,6 +88,7 @@ MouseCursorMonitorWin::~MouseCursorMonitorWin() { void MouseCursorMonitorWin::Init(Callback* callback, Mode mode) { RTC_DCHECK(!callback_); RTC_DCHECK(callback); + RTC_DCHECK(IsGUIThread(false)); callback_ = callback; mode_ = mode; @@ -96,6 +97,8 @@ void MouseCursorMonitorWin::Init(Callback* callback, Mode mode) { } void MouseCursorMonitorWin::Capture() { +// TODO: Bug 1666266. Commented out to pass new tests added in bug 1634044. +// RTC_DCHECK(IsGUIThread(false)); RTC_DCHECK(callback_); CURSORINFO cursor_info; @@ -107,7 +110,8 @@ void MouseCursorMonitorWin::Capture() { } if (!IsSameCursorShape(cursor_info, last_cursor_)) { - if (cursor_info.flags == CURSOR_SUPPRESSED) { + // Mozilla - CURSOR_SUPPRESSED is win8 and above; so we seem not to be able to see the symbol + if (cursor_info.flags != CURSOR_SHOWING) { // The cursor is intentionally hidden now, send an empty bitmap. last_cursor_ = cursor_info; callback_->OnMouseCursor(new MouseCursor( @@ -168,6 +172,7 @@ void MouseCursorMonitorWin::Capture() { } DesktopRect MouseCursorMonitorWin::GetScreenRect() { + RTC_DCHECK(IsGUIThread(false)); RTC_DCHECK_NE(screen_, kInvalidScreenId); if (screen_ == kFullDesktopScreenId) { return DesktopRect::MakeXYWH(GetSystemMetrics(SM_XVIRTUALSCREEN), diff --git a/modules/desktop_capture/win/screen_capture_utils.cc b/modules/desktop_capture/win/screen_capture_utils.cc index 3d4aecf14d..1dc2918d08 100644 --- a/modules/desktop_capture/win/screen_capture_utils.cc +++ b/modules/desktop_capture/win/screen_capture_utils.cc @@ -51,7 +51,7 @@ bool GetScreenList(DesktopCapturer::SourceList* screens, continue; } - screens->push_back({device_index, std::string()}); + screens->push_back({device_index, 0, std::string()}); if (device_names) { device_names->push_back(rtc::ToUtf8(device.DeviceName)); } @@ -147,6 +147,7 @@ DesktopRect GetFullscreenRect() { DesktopRect GetScreenRect(const DesktopCapturer::SourceId screen, const std::wstring& device_key) { + RTC_DCHECK(IsGUIThread(false)); if (screen == kFullDesktopScreenId) { return GetFullscreenRect(); } diff --git a/modules/desktop_capture/win/screen_capturer_win_gdi.cc b/modules/desktop_capture/win/screen_capturer_win_gdi.cc index 57b1f71b0d..c6d4a75931 100644 --- a/modules/desktop_capture/win/screen_capturer_win_gdi.cc +++ b/modules/desktop_capture/win/screen_capturer_win_gdi.cc @@ -186,6 +186,7 @@ void ScreenCapturerWinGdi::PrepareCaptureResources() { } bool ScreenCapturerWinGdi::CaptureImage() { + RTC_DCHECK(IsGUIThread(false)); DesktopRect screen_rect = GetScreenRect(current_screen_id_, current_device_key_); if (screen_rect.is_empty()) { diff --git a/modules/desktop_capture/win/screen_capturer_win_magnifier.cc b/modules/desktop_capture/win/screen_capturer_win_magnifier.cc index 214eb0e463..ce747e0141 100644 --- a/modules/desktop_capture/win/screen_capturer_win_magnifier.cc +++ b/modules/desktop_capture/win/screen_capturer_win_magnifier.cc @@ -49,17 +49,25 @@ ScreenCapturerWinMagnifier::ScreenCapturerWinMagnifier() = default; ScreenCapturerWinMagnifier::~ScreenCapturerWinMagnifier() { // DestroyWindow must be called before MagUninitialize. magnifier_window_ is // destroyed automatically when host_window_ is destroyed. - if (host_window_) + if (host_window_) { DestroyWindow(host_window_); + host_window_ = NULL; + } - if (magnifier_initialized_) + if (magnifier_initialized_) { mag_uninitialize_func_(); + magnifier_initialized_ = false; + } - if (mag_lib_handle_) + if (mag_lib_handle_) { FreeLibrary(mag_lib_handle_); + mag_lib_handle_ = NULL; + } - if (desktop_dc_) + if (desktop_dc_) { ReleaseDC(NULL, desktop_dc_); + desktop_dc_ = NULL; + } } void ScreenCapturerWinMagnifier::Start(Callback* callback) { diff --git a/modules/rtp_rtcp/source/rtcp_sender.cc b/modules/rtp_rtcp/source/rtcp_sender.cc index 7983371097..983851a55b 100644 --- a/modules/rtp_rtcp/source/rtcp_sender.cc +++ b/modules/rtp_rtcp/source/rtcp_sender.cc @@ -201,7 +201,7 @@ void RTCPSender::SetRTCPStatus(RtcpMode new_method) { next_time_to_send_rtcp_ = absl::nullopt; } else if (method_ == RtcpMode::kOff) { // When switching on, reschedule the next packet - SetNextRtcpSendEvaluationDuration(report_interval_ / 2); + SetNextRtcpSendEvaluationDuration(RTCP_INTERVAL_RAPID_SYNC_MS / 2); } method_ = new_method; } diff --git a/modules/rtp_rtcp/source/rtp_header_extensions.cc b/modules/rtp_rtcp/source/rtp_header_extensions.cc index 81961c69aa..a57d9e7f62 100644 --- a/modules/rtp_rtcp/source/rtp_header_extensions.cc +++ b/modules/rtp_rtcp/source/rtp_header_extensions.cc @@ -446,6 +446,45 @@ bool PlayoutDelayLimits::Write(rtc::ArrayView data, return true; } +// CSRCAudioLevel +// Sample Audio Level Encoding Using the One-Byte Header Format +// Note that the range of len is 1 to 15 which is encoded as 0 to 14 +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | ID | len=2 |0| level 1 |0| level 2 |0| level 3 | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + +constexpr RTPExtensionType CsrcAudioLevel::kId; +constexpr const char* CsrcAudioLevel::kUri; + +bool CsrcAudioLevel::Parse(rtc::ArrayView data, + CsrcAudioLevelList* csrcAudioLevels) { + if (data.size() < 1 || data.size() > kRtpCsrcSize) + return false; + csrcAudioLevels->numAudioLevels = data.size(); + for(uint8_t i = 0; i < csrcAudioLevels->numAudioLevels; i++) { + // Ensure range is 0 to 127 inclusive + csrcAudioLevels->arrOfAudioLevels[i] = 0x7f & data[i]; + } + return true; +} + +size_t CsrcAudioLevel::ValueSize(const CsrcAudioLevelList& csrcAudioLevels) { + return csrcAudioLevels.numAudioLevels; +} + +bool CsrcAudioLevel::Write(rtc::ArrayView data, + const CsrcAudioLevelList& csrcAudioLevels) { + RTC_DCHECK_GE(csrcAudioLevels.numAudioLevels, 0); + for(uint8_t i = 0; i < csrcAudioLevels.numAudioLevels; i++) { + data[i] = csrcAudioLevels.arrOfAudioLevels[i] & 0x7f; + } + // This extension if used must have at least one audio level + return csrcAudioLevels.numAudioLevels; +} + // Video Content Type. // // E.g. default video or screenshare. diff --git a/modules/rtp_rtcp/source/rtp_header_extensions.h b/modules/rtp_rtcp/source/rtp_header_extensions.h index d80e0da4f8..89c73955a2 100644 --- a/modules/rtp_rtcp/source/rtp_header_extensions.h +++ b/modules/rtp_rtcp/source/rtp_header_extensions.h @@ -292,6 +292,21 @@ class ColorSpaceExtension { static size_t WriteLuminance(uint8_t* data, float f, int denominator); }; +class CsrcAudioLevel { + public: + static constexpr RTPExtensionType kId = kRtpExtensionCsrcAudioLevel; + static constexpr absl::string_view Uri() { + return RtpExtension::kCsrcAudioLevelsUri; + } + static constexpr const char* kUri = + "urn:ietf:params:rtp-hdrext:csrc-audio-level"; + + static bool Parse(rtc::ArrayView data, + CsrcAudioLevelList* csrcAudioLevels); + static size_t ValueSize(const CsrcAudioLevelList& csrcAudioLevels); + static bool Write(rtc::ArrayView data, const CsrcAudioLevelList& csrcAudioLevels); +}; + // Base extension class for RTP header extensions which are strings. // Subclasses must defined kId and kUri static constexpr members. class BaseRtpStringExtension { diff --git a/modules/rtp_rtcp/source/rtp_packet.cc b/modules/rtp_rtcp/source/rtp_packet.cc index 6c7dff322b..9495841984 100644 --- a/modules/rtp_rtcp/source/rtp_packet.cc +++ b/modules/rtp_rtcp/source/rtp_packet.cc @@ -205,6 +205,10 @@ void RtpPacket::ZeroMutableExtensions() { // Non-mutable extension. Don't change it. break; } + case RTPExtensionType::kRtpExtensionCsrcAudioLevel: { + // TODO: This is a Mozilla addition, we need to add a handler for this. + RTC_CHECK(false); + } } } } diff --git a/modules/rtp_rtcp/source/rtp_packet_unittest.cc b/modules/rtp_rtcp/source/rtp_packet_unittest.cc index 1d51d75662..41bc114efb 100644 --- a/modules/rtp_rtcp/source/rtp_packet_unittest.cc +++ b/modules/rtp_rtcp/source/rtp_packet_unittest.cc @@ -121,6 +121,18 @@ constexpr uint8_t kPacketWithMid[] = { 0xbe, 0xde, 0x00, 0x01, 0xb2, 'm', 'i', 'd'}; +constexpr uint8_t kCsrcAudioLevelExtensionId = 0xc; +constexpr uint8_t kCsrcAudioLevelsSize = 4; +constexpr uint8_t kCsrcAudioLevels[] = {0x7f, 0x00, 0x10, 0x08}; +constexpr uint8_t kPacketWithCsrcAudioLevels[] = { + 0x90, kPayloadType, kSeqNumFirstByte, kSeqNumSecondByte, + 0x65, 0x43, 0x12, 0x78, + 0x12, 0x34, 0x56, 0x78, + 0xbe, 0xde, 0x00, 0x02, + (kCsrcAudioLevelExtensionId << 4) | (kCsrcAudioLevelsSize - 1), + 0x7f, 0x00, 0x10, + 0x08, 0x00, 0x00, 0x00}; + constexpr uint32_t kCsrcs[] = {0x34567890, 0x32435465}; constexpr uint8_t kPayload[] = {'p', 'a', 'y', 'l', 'o', 'a', 'd'}; constexpr uint8_t kPacketPaddingSize = 8; @@ -385,6 +397,24 @@ TEST(RtpPacketTest, FailsToSetUnregisteredExtension) { EXPECT_EQ(packet.GetExtension(), absl::nullopt); } +TEST(RtpPacketTest, CreateWithDynamicSizedExtensionCsrcAudioLevel) { + RtpPacketToSend::ExtensionManager extensions; + extensions.Register(kCsrcAudioLevelExtensionId); + RtpPacketToSend packet(&extensions); + packet.SetPayloadType(kPayloadType); + packet.SetSequenceNumber(kSeqNum); + packet.SetTimestamp(kTimestamp); + packet.SetSsrc(kSsrc); + CsrcAudioLevelList levels; + levels.numAudioLevels = kCsrcAudioLevelsSize; + for (uint8_t i = 0; i < kCsrcAudioLevelsSize; i++) { + levels.arrOfAudioLevels[i] = kCsrcAudioLevels[i]; + } + packet.SetExtension(levels); + EXPECT_THAT(kPacketWithCsrcAudioLevels, + ElementsAreArray(packet.data(), packet.size())); +} + TEST(RtpPacketTest, SetReservedExtensionsAfterPayload) { const size_t kPayloadSize = 4; RtpPacketToSend::ExtensionManager extensions; diff --git a/modules/rtp_rtcp/source/rtp_rtcp_config.h b/modules/rtp_rtcp/source/rtp_rtcp_config.h index 3e6aa3baae..9ac7696ce9 100644 --- a/modules/rtp_rtcp/source/rtp_rtcp_config.h +++ b/modules/rtp_rtcp/source/rtp_rtcp_config.h @@ -18,6 +18,8 @@ namespace webrtc { constexpr int kDefaultMaxReorderingThreshold = 50; // In sequence numbers. constexpr int kRtcpMaxNackFields = 253; +constexpr TimeDelta RTCP_INTERVAL_RAPID_SYNC_MS = + TimeDelta::Millis(100); // RFX 6051 constexpr TimeDelta RTCP_SEND_BEFORE_KEY_FRAME = TimeDelta::Millis(100); constexpr int RTCP_MAX_REPORT_BLOCKS = 31; // RFC 3550 page 37 } // namespace webrtc diff --git a/modules/rtp_rtcp/source/rtp_sender.cc b/modules/rtp_rtcp/source/rtp_sender.cc index ac3bd55e05..0ed7243d0a 100644 --- a/modules/rtp_rtcp/source/rtp_sender.cc +++ b/modules/rtp_rtcp/source/rtp_sender.cc @@ -132,6 +132,10 @@ bool IsNonVolatile(RTPExtensionType type) { case kRtpExtensionNumberOfExtensions: RTC_DCHECK_NOTREACHED(); return false; + case kRtpExtensionCsrcAudioLevel: + // TODO: Mozilla implement for CsrcAudioLevel + RTC_CHECK(false); + return false; } RTC_CHECK_NOTREACHED(); } diff --git a/modules/utility/source/jvm_android.cc b/modules/utility/source/jvm_android.cc index ee9930bcaa..39ef12f428 100644 --- a/modules/utility/source/jvm_android.cc +++ b/modules/utility/source/jvm_android.cc @@ -18,6 +18,16 @@ #include "rtc_base/logging.h" #include "rtc_base/platform_thread.h" +namespace mozilla { +namespace jni { +jclass GetClassRef(JNIEnv* aEnv, const char* aClassName); +} +} + +#define TAG "JVM" +#define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__) +#define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__) + namespace webrtc { JVM* g_jvm; @@ -40,14 +50,11 @@ struct { void LoadClasses(JNIEnv* jni) { RTC_LOG(LS_INFO) << "LoadClasses:"; for (auto& c : loaded_classes) { - jclass localRef = FindClass(jni, c.name); - RTC_LOG(LS_INFO) << "name: " << c.name; - CHECK_EXCEPTION(jni) << "Error during FindClass: " << c.name; - RTC_CHECK(localRef) << c.name; - jclass globalRef = reinterpret_cast(jni->NewGlobalRef(localRef)); - CHECK_EXCEPTION(jni) << "Error during NewGlobalRef: " << c.name; - RTC_CHECK(globalRef) << c.name; - c.clazz = globalRef; + ALOGD("name: %s", c.name); + jclass clsRef = mozilla::jni::GetClassRef(jni, c.name); + RTC_CHECK(clsRef) << c.name; + c.clazz = static_cast(jni->NewGlobalRef(clsRef)); + jni->DeleteLocalRef(clsRef); } } @@ -216,8 +223,9 @@ std::string JNIEnvironment::JavaToStdString(const jstring& j_string) { // static void JVM::Initialize(JavaVM* jvm) { - RTC_LOG(LS_INFO) << "JVM::Initialize"; - RTC_CHECK(!g_jvm); + if (g_jvm) { + return; + } g_jvm = new JVM(jvm); } diff --git a/modules/video_capture/device_info_impl.cc b/modules/video_capture/device_info_impl.cc index ff32a78580..7cccdb51a7 100644 --- a/modules/video_capture/device_info_impl.cc +++ b/modules/video_capture/device_info_impl.cc @@ -65,7 +65,7 @@ int32_t DeviceInfoImpl::GetCapability(const char* deviceUniqueIdUTF8, // Make sure the number is valid if (deviceCapabilityNumber >= (unsigned int)_captureCapabilities.size()) { - RTC_LOG(LS_ERROR) << "Invalid deviceCapabilityNumber " + RTC_LOG(LS_ERROR) << deviceUniqueIdUTF8 << " Invalid deviceCapabilityNumber " << deviceCapabilityNumber << ">= number of capabilities (" << _captureCapabilities.size() << ")."; return -1; diff --git a/modules/video_capture/device_info_impl.h b/modules/video_capture/device_info_impl.h index 546265049c..8acbef6d69 100644 --- a/modules/video_capture/device_info_impl.h +++ b/modules/video_capture/device_info_impl.h @@ -42,6 +42,7 @@ class DeviceInfoImpl : public VideoCaptureModule::DeviceInfo { /* Initialize this object*/ virtual int32_t Init() = 0; + int32_t Refresh() override { return 0; } /* * Fills the member variable _captureCapabilities with capabilities for the * given device name. diff --git a/modules/video_capture/linux/device_info_v4l2.cc b/modules/video_capture/linux/device_info_v4l2.cc index 5af58015a7..28395a5a05 100644 --- a/modules/video_capture/linux/device_info_v4l2.cc +++ b/modules/video_capture/linux/device_info_v4l2.cc @@ -27,15 +27,187 @@ #include "modules/video_capture/video_capture_impl.h" #include "rtc_base/logging.h" +#ifdef WEBRTC_LINUX +#define EVENT_SIZE ( sizeof (struct inotify_event) ) +#define BUF_LEN ( 1024 * ( EVENT_SIZE + 16 ) ) +#endif + namespace webrtc { namespace videocapturemodule { -DeviceInfoV4l2::DeviceInfoV4l2() : DeviceInfoImpl() {} +#ifdef WEBRTC_LINUX +void DeviceInfoV4l2::HandleEvent(inotify_event* event, int fd) +{ + if (event->mask & IN_CREATE) { + if (fd == _fd_v4l || fd == _fd_snd) { + DeviceChange(); + } else if ((event->mask & IN_ISDIR) && (fd == _fd_dev)) { + if (_wd_v4l < 0) { + // Sometimes inotify_add_watch failed if we call it immediately after receiving this event + // Adding 5ms delay to let file system settle down + usleep(5*1000); + _wd_v4l = inotify_add_watch(_fd_v4l, "/dev/v4l/by-path/", IN_CREATE | IN_DELETE | IN_DELETE_SELF); + if (_wd_v4l >= 0) { + DeviceChange(); + } + } + if (_wd_snd < 0) { + usleep(5*1000); + _wd_snd = inotify_add_watch(_fd_snd, "/dev/snd/by-path/", IN_CREATE | IN_DELETE | IN_DELETE_SELF); + if (_wd_snd >= 0) { + DeviceChange(); + } + } + } + } else if (event->mask & IN_DELETE) { + if (fd == _fd_v4l || fd == _fd_snd) { + DeviceChange(); + } + } else if (event->mask & IN_DELETE_SELF) { + if (fd == _fd_v4l) { + inotify_rm_watch(_fd_v4l, _wd_v4l); + _wd_v4l = -1; + } else if (fd == _fd_snd) { + inotify_rm_watch(_fd_snd, _wd_snd); + _wd_snd = -1; + } else { + assert(false); + } + } +} + +int DeviceInfoV4l2::EventCheck(int fd) +{ + struct timeval timeout; + fd_set rfds; + + timeout.tv_sec = 0; + timeout.tv_usec = 100000; + + FD_ZERO(&rfds); + FD_SET(fd, &rfds); + + return select(fd+1, &rfds, NULL, NULL, &timeout); +} + +int DeviceInfoV4l2::HandleEvents(int fd) +{ + char buffer[BUF_LEN]; + + ssize_t r = read(fd, buffer, BUF_LEN); + + if (r <= 0) { + return r; + } + + ssize_t buffer_i = 0; + inotify_event* pevent; + size_t eventSize; + int count = 0; + + while (buffer_i < r) + { + pevent = (inotify_event *) (&buffer[buffer_i]); + eventSize = sizeof(inotify_event) + pevent->len; + char event[sizeof(inotify_event) + FILENAME_MAX + 1] // null-terminated + __attribute__ ((aligned(__alignof__(struct inotify_event)))); + + memcpy(event, pevent, eventSize); + + HandleEvent((inotify_event*)(event), fd); + + buffer_i += eventSize; + count++; + } + + return count; +} + +int DeviceInfoV4l2::ProcessInotifyEvents() +{ + while (!_isShutdown) { + if (EventCheck(_fd_dev) > 0) { + if (HandleEvents(_fd_dev) < 0) { + break; + } + } + if (EventCheck(_fd_v4l) > 0) { + if (HandleEvents(_fd_v4l) < 0) { + break; + } + } + if (EventCheck(_fd_snd) > 0) { + if (HandleEvents(_fd_snd) < 0) { + break; + } + } + } + return 0; +} + +void DeviceInfoV4l2::InotifyEventThread(void* obj) +{ + static_cast (obj)->InotifyProcess(); +} + +void DeviceInfoV4l2::InotifyProcess() +{ + _fd_v4l = inotify_init(); + _fd_snd = inotify_init(); + _fd_dev = inotify_init(); + if (_fd_v4l >= 0 && _fd_snd >= 0 && _fd_dev >= 0) { + _wd_v4l = inotify_add_watch(_fd_v4l, "/dev/v4l/by-path/", IN_CREATE | IN_DELETE | IN_DELETE_SELF); + _wd_snd = inotify_add_watch(_fd_snd, "/dev/snd/by-path/", IN_CREATE | IN_DELETE | IN_DELETE_SELF); + _wd_dev = inotify_add_watch(_fd_dev, "/dev/", IN_CREATE); + ProcessInotifyEvents(); + + if (_wd_v4l >= 0) { + inotify_rm_watch(_fd_v4l, _wd_v4l); + } + + if (_wd_snd >= 0) { + inotify_rm_watch(_fd_snd, _wd_snd); + } + + if (_wd_dev >= 0) { + inotify_rm_watch(_fd_dev, _wd_dev); + } + + close(_fd_v4l); + close(_fd_snd); + close(_fd_dev); + } +} +#endif + +DeviceInfoV4l2::DeviceInfoV4l2() : DeviceInfoImpl() +#ifdef WEBRTC_LINUX + , _inotifyEventThread(new rtc::PlatformThread( + InotifyEventThread, this, "InotifyEventThread")) + , _isShutdown(false) +#endif +{ +#ifdef WEBRTC_LINUX + if (_inotifyEventThread) + { + _inotifyEventThread->Start(); + } +} +#endif int32_t DeviceInfoV4l2::Init() { return 0; } -DeviceInfoV4l2::~DeviceInfoV4l2() {} +DeviceInfoV4l2::~DeviceInfoV4l2() { +#ifdef WEBRTC_LINUX + _isShutdown = true; + + if (_inotifyEventThread) { + _inotifyEventThread->Stop(); + _inotifyEventThread = nullptr; + } +#endif +} uint32_t DeviceInfoV4l2::NumberOfDevices() { uint32_t count = 0; @@ -68,15 +240,17 @@ int32_t DeviceInfoV4l2::GetDeviceName(uint32_t deviceNumber, char* deviceUniqueIdUTF8, uint32_t deviceUniqueIdUTF8Length, char* /*productUniqueIdUTF8*/, - uint32_t /*productUniqueIdUTF8Length*/) { + uint32_t /*productUniqueIdUTF8Length*/, + pid_t* /*pid*/) { // Travel through /dev/video [0-63] uint32_t count = 0; char device[20]; int fd = -1; bool found = false; struct v4l2_capability cap; - for (int n = 0; n < 64; n++) { - snprintf(device, sizeof(device), "/dev/video%d", n); + int device_index; + for (device_index = 0; device_index < 64; device_index++) { + sprintf(device, "/dev/video%d", device_index); if ((fd = open(device, O_RDONLY)) != -1) { // query device capabilities and make sure this is a video capture device if (ioctl(fd, VIDIOC_QUERYCAP, &cap) < 0 || @@ -129,8 +303,15 @@ int32_t DeviceInfoV4l2::GetDeviceName(uint32_t deviceNumber, RTC_LOG(LS_INFO) << "buffer passed is too small"; return -1; } + } else { + // if there's no bus info to use for uniqueId, invent one - and it has to be repeatable + if (snprintf(deviceUniqueIdUTF8, + deviceUniqueIdUTF8Length, "fake_%u", device_index) >= + (int) deviceUniqueIdUTF8Length) + { + return -1; + } } - return 0; } diff --git a/modules/video_capture/linux/device_info_v4l2.h b/modules/video_capture/linux/device_info_v4l2.h index fb95a6020d..95432a509d 100644 --- a/modules/video_capture/linux/device_info_v4l2.h +++ b/modules/video_capture/linux/device_info_v4l2.h @@ -15,6 +15,9 @@ #include "modules/video_capture/device_info_impl.h" +#include "rtc_base/platform_thread.h" +#include + namespace webrtc { namespace videocapturemodule { class DeviceInfoV4l2 : public DeviceInfoImpl { @@ -28,7 +31,8 @@ class DeviceInfoV4l2 : public DeviceInfoImpl { char* deviceUniqueIdUTF8, uint32_t deviceUniqueIdUTF8Length, char* productUniqueIdUTF8 = 0, - uint32_t productUniqueIdUTF8Length = 0) override; + uint32_t productUniqueIdUTF8Length = 0, + pid_t* pid=0) override; /* * Fills the membervariable _captureCapabilities with capabilites for the * given device name. @@ -45,6 +49,18 @@ class DeviceInfoV4l2 : public DeviceInfoImpl { private: bool IsDeviceNameMatches(const char* name, const char* deviceUniqueIdUTF8); + +#ifdef WEBRTC_LINUX + void HandleEvent(inotify_event* event, int fd); + int EventCheck(int fd); + int HandleEvents(int fd); + int ProcessInotifyEvents(); + std::unique_ptr _inotifyEventThread; + static void InotifyEventThread(void*); + void InotifyProcess(); + int _fd_v4l, _fd_dev, _wd_v4l, _wd_dev; /* accessed on InotifyEventThread thread */ + std::atomic _isShutdown; +#endif }; } // namespace videocapturemodule } // namespace webrtc diff --git a/modules/video_capture/linux/video_capture_v4l2.cc b/modules/video_capture/linux/video_capture_v4l2.cc index 5101a67e0c..1dc13b01aa 100644 --- a/modules/video_capture/linux/video_capture_v4l2.cc +++ b/modules/video_capture/linux/video_capture_v4l2.cc @@ -50,6 +50,13 @@ int32_t VideoCaptureModuleV4L2::Init(const char* deviceUniqueIdUTF8) { memcpy(_deviceUniqueId, deviceUniqueIdUTF8, len + 1); } + int device_index; + if (sscanf(deviceUniqueIdUTF8,"fake_%d", &device_index) == 1) + { + _deviceId = device_index; + return 0; + } + int fd; char device[32]; bool found = false; diff --git a/modules/video_capture/video_capture.h b/modules/video_capture/video_capture.h index eddc31414a..187eba76a0 100644 --- a/modules/video_capture/video_capture.h +++ b/modules/video_capture/video_capture.h @@ -15,15 +15,48 @@ #include "api/video/video_sink_interface.h" #include "modules/video_capture/raw_video_sink_interface.h" #include "modules/video_capture/video_capture_defines.h" +#include + +#if defined(ANDROID) +#include +#endif namespace webrtc { +class VideoInputFeedBack +{ +public: + virtual void OnDeviceChange() = 0; +protected: + virtual ~VideoInputFeedBack(){} +}; + +#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD) + int32_t SetCaptureAndroidVM(JavaVM* javaVM); +#endif + class VideoCaptureModule : public rtc::RefCountInterface { public: // Interface for receiving information about available camera devices. class DeviceInfo { public: virtual uint32_t NumberOfDevices() = 0; + virtual int32_t Refresh() = 0; + virtual void DeviceChange() { + for (auto inputCallBack : _inputCallBacks) { + inputCallBack->OnDeviceChange(); + } + } + virtual void RegisterVideoInputFeedBack(VideoInputFeedBack* callBack) { + _inputCallBacks.insert(callBack); + } + + virtual void DeRegisterVideoInputFeedBack(VideoInputFeedBack* callBack) { + auto it = _inputCallBacks.find(callBack); + if (it != _inputCallBacks.end()) { + _inputCallBacks.erase(it); + } + } // Returns the available capture devices. // deviceNumber - Index of capture device. @@ -38,7 +71,8 @@ class VideoCaptureModule : public rtc::RefCountInterface { char* deviceUniqueIdUTF8, uint32_t deviceUniqueIdUTF8Length, char* productUniqueIdUTF8 = 0, - uint32_t productUniqueIdUTF8Length = 0) = 0; + uint32_t productUniqueIdUTF8Length = 0, + pid_t* pid = 0) = 0; // Returns the number of capabilities this device. virtual int32_t NumberOfCapabilities(const char* deviceUniqueIdUTF8) = 0; @@ -70,6 +104,8 @@ class VideoCaptureModule : public rtc::RefCountInterface { uint32_t positionY) = 0; virtual ~DeviceInfo() {} + private: + std::set _inputCallBacks; }; // Register capture data callback @@ -79,11 +115,16 @@ class VideoCaptureModule : public rtc::RefCountInterface { RawVideoSinkInterface* dataCallback) = 0; // Remove capture data callback - virtual void DeRegisterCaptureDataCallback() = 0; + virtual void DeRegisterCaptureDataCallback( + rtc::VideoSinkInterface *dataCallback) = 0; // Start capture device virtual int32_t StartCapture(const VideoCaptureCapability& capability) = 0; + virtual int32_t StopCaptureIfAllClientsClose() = 0; + + virtual bool FocusOnSelectedSource() { return false; } + virtual int32_t StopCapture() = 0; // Returns the name of the device used by this module. diff --git a/modules/video_capture/video_capture_factory.cc b/modules/video_capture/video_capture_factory.cc index c0e1479caf..e4a46902e0 100644 --- a/modules/video_capture/video_capture_factory.cc +++ b/modules/video_capture/video_capture_factory.cc @@ -16,19 +16,11 @@ namespace webrtc { rtc::scoped_refptr VideoCaptureFactory::Create( const char* deviceUniqueIdUTF8) { -#if defined(WEBRTC_ANDROID) || defined(WEBRTC_MAC) - return nullptr; -#else return videocapturemodule::VideoCaptureImpl::Create(deviceUniqueIdUTF8); -#endif } VideoCaptureModule::DeviceInfo* VideoCaptureFactory::CreateDeviceInfo() { -#if defined(WEBRTC_ANDROID) || defined(WEBRTC_MAC) - return nullptr; -#else return videocapturemodule::VideoCaptureImpl::CreateDeviceInfo(); -#endif } } // namespace webrtc diff --git a/modules/video_capture/video_capture_impl.cc b/modules/video_capture/video_capture_impl.cc index d539b38264..d5ec4daae1 100644 --- a/modules/video_capture/video_capture_impl.cc +++ b/modules/video_capture/video_capture_impl.cc @@ -76,7 +76,6 @@ VideoCaptureImpl::VideoCaptureImpl() _requestedCapability(), _lastProcessTimeNanos(rtc::TimeNanos()), _lastFrameRateCallbackTimeNanos(rtc::TimeNanos()), - _dataCallBack(NULL), _rawDataCallBack(NULL), _lastProcessFrameTimeNanos(rtc::TimeNanos()), _rotateFrame(kVideoRotation_0), @@ -89,7 +88,6 @@ VideoCaptureImpl::VideoCaptureImpl() } VideoCaptureImpl::~VideoCaptureImpl() { - DeRegisterCaptureDataCallback(); if (_deviceUniqueId) delete[] _deviceUniqueId; } @@ -98,26 +96,39 @@ void VideoCaptureImpl::RegisterCaptureDataCallback( rtc::VideoSinkInterface* dataCallBack) { MutexLock lock(&api_lock_); RTC_DCHECK(!_rawDataCallBack); - _dataCallBack = dataCallBack; + _dataCallBacks.insert(dataCallBack); } void VideoCaptureImpl::RegisterCaptureDataCallback( RawVideoSinkInterface* dataCallBack) { MutexLock lock(&api_lock_); - RTC_DCHECK(!_dataCallBack); + RTC_DCHECK(_dataCallBacks.empty()); _rawDataCallBack = dataCallBack; } -void VideoCaptureImpl::DeRegisterCaptureDataCallback() { +void VideoCaptureImpl::DeRegisterCaptureDataCallback( + rtc::VideoSinkInterface* dataCallBack) { MutexLock lock(&api_lock_); - _dataCallBack = NULL; + auto it = _dataCallBacks.find(dataCallBack); + if (it != _dataCallBacks.end()) { + _dataCallBacks.erase(it); + } _rawDataCallBack = NULL; } + +int32_t VideoCaptureImpl::StopCaptureIfAllClientsClose() { + if (_dataCallBacks.empty()) { + return StopCapture(); + } else { + return 0; + } +} + int32_t VideoCaptureImpl::DeliverCapturedFrame(VideoFrame& captureFrame) { UpdateFrameCount(); // frame count used for local frame rate callback. - if (_dataCallBack) { - _dataCallBack->OnFrame(captureFrame); + for (auto dataCallBack : _dataCallBacks) { + dataCallBack->OnFrame(captureFrame); } return 0; @@ -204,7 +215,7 @@ int32_t VideoCaptureImpl::IncomingFrame(uint8_t* videoFrame, buffer.get()->StrideV(), 0, 0, // No Cropping width, height, target_width, target_height, rotation_mode, ConvertVideoType(frameInfo.videoType)); - if (conversionResult < 0) { + if (conversionResult != 0) { RTC_LOG(LS_ERROR) << "Failed to convert capture frame from type " << static_cast(frameInfo.videoType) << "to I420."; return -1; @@ -219,6 +230,13 @@ int32_t VideoCaptureImpl::IncomingFrame(uint8_t* videoFrame, .build(); captureFrame.set_ntp_time_ms(captureTime); + // This is one ugly hack to let CamerasParent know what rotation + // the frame was captured at. Note that this goes against the intended + // meaning of rotation of the frame (how to rotate it before rendering). + // We do this so CamerasChild can scale to the proper dimensions + // later on in the pipe. + captureFrame.set_rotation(_rotateFrame); + DeliverCapturedFrame(captureFrame); return 0; diff --git a/modules/video_capture/video_capture_impl.h b/modules/video_capture/video_capture_impl.h index fee93396d3..f874580471 100644 --- a/modules/video_capture/video_capture_impl.h +++ b/modules/video_capture/video_capture_impl.h @@ -55,8 +55,10 @@ class VideoCaptureImpl : public VideoCaptureModule { rtc::VideoSinkInterface* dataCallback) override; virtual void RegisterCaptureDataCallback( RawVideoSinkInterface* dataCallback) override; - void DeRegisterCaptureDataCallback() override; + void DeRegisterCaptureDataCallback( + rtc::VideoSinkInterface* dataCallback) override; + int32_t StopCaptureIfAllClientsClose() override; int32_t SetCaptureRotation(VideoRotation rotation) override; bool SetApplyRotation(bool enable) override; bool GetApplyRotation() override; @@ -98,7 +100,7 @@ class VideoCaptureImpl : public VideoCaptureModule { // last time the frame rate callback function was called. int64_t _lastFrameRateCallbackTimeNanos; - rtc::VideoSinkInterface* _dataCallBack; + std::set*> _dataCallBacks; RawVideoSinkInterface* _rawDataCallBack; int64_t _lastProcessFrameTimeNanos; diff --git a/modules/video_coding/codecs/vp9/libvpx_vp9_encoder.cc b/modules/video_coding/codecs/vp9/libvpx_vp9_encoder.cc index c2884c0395..35b13058a2 100644 --- a/modules/video_coding/codecs/vp9/libvpx_vp9_encoder.cc +++ b/modules/video_coding/codecs/vp9/libvpx_vp9_encoder.cc @@ -254,6 +254,7 @@ LibvpxVp9Encoder::LibvpxVp9Encoder(const cricket::VideoCodec& codec, first_frame_in_picture_(true), ss_info_needed_(false), force_all_active_layers_(false), + num_cores_(0), is_flexible_mode_(false), variable_framerate_experiment_(ParseVariableFramerateConfig(trials)), variable_framerate_controller_( @@ -577,6 +578,7 @@ int LibvpxVp9Encoder::InitEncode(const VideoCodec* inst, force_key_frame_ = true; pics_since_key_ = 0; + num_cores_ = settings.number_of_cores; scalability_mode_ = inst->GetScalabilityMode(); if (scalability_mode_.has_value()) { diff --git a/modules/video_coding/codecs/vp9/libvpx_vp9_encoder.h b/modules/video_coding/codecs/vp9/libvpx_vp9_encoder.h index 6b662ae8f9..bb871f8498 100644 --- a/modules/video_coding/codecs/vp9/libvpx_vp9_encoder.h +++ b/modules/video_coding/codecs/vp9/libvpx_vp9_encoder.h @@ -67,6 +67,9 @@ class LibvpxVp9Encoder : public VP9Encoder { // Call encoder initialize function and set control settings. int InitAndSetControlSettings(const VideoCodec* inst); + // Update frame size for codec. + int UpdateCodecFrameSize(const VideoFrame& input_image); + bool PopulateCodecSpecific(CodecSpecificInfo* codec_specific, absl::optional* spatial_idx, absl::optional* temporal_idx, @@ -150,6 +153,7 @@ class LibvpxVp9Encoder : public VP9Encoder { VideoBitrateAllocation current_bitrate_allocation_; bool ss_info_needed_; bool force_all_active_layers_; + uint8_t num_cores_; std::unique_ptr svc_controller_; absl::optional scalability_mode_; diff --git a/modules/video_coding/generic_decoder.cc b/modules/video_coding/generic_decoder.cc index b660e02b72..54467d1477 100644 --- a/modules/video_coding/generic_decoder.cc +++ b/modules/video_coding/generic_decoder.cc @@ -32,7 +32,10 @@ namespace webrtc { namespace { -constexpr size_t kDecoderFrameMemoryLength = 10; +// Changed from 10 to 30 in Mozilla Bug 989944: Increase decode +// timestamp map to handle delayed decode on 8x10. The map is +// now a deque (as of libwebrtc upstream commit 1c51ec4d74). +constexpr size_t kDecoderFrameMemoryLength = 30; } diff --git a/modules/video_coding/session_info.cc b/modules/video_coding/session_info.cc index 854230ae0a..e31b8b1d25 100644 --- a/modules/video_coding/session_info.cc +++ b/modules/video_coding/session_info.cc @@ -210,16 +210,26 @@ size_t VCMSessionInfo::InsertBuffer(uint8_t* frame_buffer, if (h264 && h264->packetization_type == kH264StapA) { size_t required_length = 0; const uint8_t* nalu_ptr = packet_buffer + kH264NALHeaderLengthInBytes; - while (nalu_ptr < packet_buffer + packet.sizeBytes) { + // Must check that incoming data length doesn't extend past end of buffer. + // We allow for 100 bytes of expansion due to startcodes being longer than + // length fields. + while (nalu_ptr + kLengthFieldLength <= packet_buffer + packet.sizeBytes) { size_t length = BufferToUWord16(nalu_ptr); - required_length += + if (nalu_ptr + kLengthFieldLength + length <= packet_buffer + packet.sizeBytes) { + required_length += length + (packet.insertStartCode ? kH264StartCodeLengthBytes : 0); - nalu_ptr += kLengthFieldLength + length; + nalu_ptr += kLengthFieldLength + length; + } else { + // Something is very wrong! + RTC_LOG(LS_ERROR) << "Failed to insert packet due to corrupt H264 STAP-A"; + return 0; + } } ShiftSubsequentPackets(packet_it, required_length); nalu_ptr = packet_buffer + kH264NALHeaderLengthInBytes; uint8_t* frame_buffer_ptr = frame_buffer + offset; - while (nalu_ptr < packet_buffer + packet.sizeBytes) { + // we already know we won't go past end-of-buffer + while (nalu_ptr + kLengthFieldLength <= packet_buffer + packet.sizeBytes) { size_t length = BufferToUWord16(nalu_ptr); nalu_ptr += kLengthFieldLength; frame_buffer_ptr += Insert(nalu_ptr, length, packet.insertStartCode, @@ -447,12 +457,23 @@ int VCMSessionInfo::InsertPacket(const VCMPacket& packet, return -2; if (packet.codec() == kVideoCodecH264) { - frame_type_ = packet.video_header.frame_type; + // H.264 can have leading or trailing non-VCL (Video Coding Layer) + // NALUs, such as SPS/PPS/SEI and others. Also, the RTP marker bit is + // not reliable for the last packet of a frame (RFC 6184 5.1 - "Decoders + // [] MUST NOT rely on this property"), so allow out-of-order packets to + // update the first and last seq# range. Also mark as a key frame if + // any packet is of that type. + if (frame_type_ != VideoFrameType::kVideoFrameKey) { + frame_type_ = packet.video_header.frame_type; + } if (packet.is_first_packet_in_frame() && (first_packet_seq_num_ == -1 || IsNewerSequenceNumber(first_packet_seq_num_, packet.seqNum))) { first_packet_seq_num_ = packet.seqNum; } + // Note: the code does *not* currently handle the Marker bit being totally + // absent from a frame. It does not, however, depend on it being on the last + // packet of the 'frame'/'session'. if (packet.markerBit && (last_packet_seq_num_ == -1 || IsNewerSequenceNumber(packet.seqNum, last_packet_seq_num_))) { @@ -499,7 +520,6 @@ int VCMSessionInfo::InsertPacket(const VCMPacket& packet, size_t returnLength = InsertBuffer(frame_buffer, packet_list_it); UpdateCompleteSession(); - return static_cast(returnLength); } diff --git a/test/fuzzers/rtp_packet_fuzzer.cc b/test/fuzzers/rtp_packet_fuzzer.cc index 60afb986de..0e10a8fa3a 100644 --- a/test/fuzzers/rtp_packet_fuzzer.cc +++ b/test/fuzzers/rtp_packet_fuzzer.cc @@ -164,6 +164,11 @@ void FuzzOneInput(const uint8_t* data, size_t size) { // This extension requires state to read and so complicated that // deserves own fuzzer. break; + case kRtpExtensionCsrcAudioLevel: { + CsrcAudioLevelList levels; + packet.GetExtension(&levels); + break; + } } } diff --git a/test/vcm_capturer.cc b/test/vcm_capturer.cc index a037f9eff6..e02fc722b2 100644 --- a/test/vcm_capturer.cc +++ b/test/vcm_capturer.cc @@ -81,7 +81,7 @@ void VcmCapturer::Destroy() { return; vcm_->StopCapture(); - vcm_->DeRegisterCaptureDataCallback(); + vcm_->DeRegisterCaptureDataCallback(this); // Release reference to VCM. vcm_ = nullptr; } -- 2.34.1