diff --git a/talk/app/webrtc/java/jni/androidmediadecoder_jni.cc b/talk/app/webrtc/java/jni/androidmediadecoder_jni.cc index 49b84aa585..7ebcd203a1 100644 --- a/talk/app/webrtc/java/jni/androidmediadecoder_jni.cc +++ b/talk/app/webrtc/java/jni/androidmediadecoder_jni.cc @@ -95,6 +95,8 @@ class MediaCodecVideoDecoder : public webrtc::VideoDecoder, // rtc::MessageHandler implementation. void OnMessage(rtc::Message* msg) override; + const char* ImplementationName() const override; + private: // CHECK-fail if not running on |codec_thread_|. void CheckOnCodecThread(); @@ -906,5 +908,9 @@ void MediaCodecVideoDecoderFactory::DestroyVideoDecoder( delete decoder; } +const char* MediaCodecVideoDecoder::ImplementationName() const { + return "MediaCodec"; +} + } // namespace webrtc_jni diff --git a/talk/app/webrtc/java/jni/androidmediaencoder_jni.cc b/talk/app/webrtc/java/jni/androidmediaencoder_jni.cc index c6c7594d87..b36dc0bb34 100644 --- a/talk/app/webrtc/java/jni/androidmediaencoder_jni.cc +++ b/talk/app/webrtc/java/jni/androidmediaencoder_jni.cc @@ -109,6 +109,11 @@ class MediaCodecVideoEncoder : public webrtc::VideoEncoder, int GetTargetFramerate() override; bool SupportsNativeHandle() const override { return true; } + const char* ImplementationName() const override; + + private: + // CHECK-fail if not running on |codec_thread_|. + void CheckOnCodecThread(); private: // ResetCodecOnCodecThread() calls ReleaseOnCodecThread() and @@ -1068,8 +1073,12 @@ int MediaCodecVideoEncoder::GetTargetFramerate() { return scale_ ? quality_scaler_.GetTargetFramerate() : -1; } +const char* MediaCodecVideoEncoder::ImplementationName() const { + return "MediaCodec"; +} + MediaCodecVideoEncoderFactory::MediaCodecVideoEncoderFactory() - : egl_context_ (nullptr) { + : egl_context_(nullptr) { JNIEnv* jni = AttachCurrentThreadIfNeeded(); ScopedLocalRefFrame local_ref_frame(jni); jclass j_encoder_class = FindClass(jni, "org/webrtc/MediaCodecVideoEncoder"); diff --git a/talk/app/webrtc/statscollector.cc b/talk/app/webrtc/statscollector.cc index 893e5866b0..b514b42fee 100644 --- a/talk/app/webrtc/statscollector.cc +++ b/talk/app/webrtc/statscollector.cc @@ -201,6 +201,8 @@ void ExtractStats(const cricket::VoiceSenderInfo& info, StatsReport* report) { void ExtractStats(const cricket::VideoReceiverInfo& info, StatsReport* report) { ExtractCommonReceiveProperties(info, report); + report->AddString(StatsReport::kStatsValueNameCodecImplementationName, + info.decoder_implementation_name); report->AddInt64(StatsReport::kStatsValueNameBytesReceived, info.bytes_rcvd); report->AddInt64(StatsReport::kStatsValueNameCaptureStartNtpTimeMs, @@ -233,6 +235,8 @@ void ExtractStats(const cricket::VideoReceiverInfo& info, StatsReport* report) { void ExtractStats(const cricket::VideoSenderInfo& info, StatsReport* report) { ExtractCommonSendProperties(info, report); + report->AddString(StatsReport::kStatsValueNameCodecImplementationName, + info.encoder_implementation_name); report->AddBoolean(StatsReport::kStatsValueNameBandwidthLimitedResolution, (info.adapt_reason & 0x2) > 0); report->AddBoolean(StatsReport::kStatsValueNameCpuLimitedResolution, diff --git a/talk/app/webrtc/statstypes.cc b/talk/app/webrtc/statstypes.cc index e45833c668..19cb1f5d78 100644 --- a/talk/app/webrtc/statstypes.cc +++ b/talk/app/webrtc/statstypes.cc @@ -408,6 +408,8 @@ const char* StatsReport::Value::display_name() const { return "state"; case kStatsValueNameDataChannelId: return "datachannelid"; + case kStatsValueNameCodecImplementationName: + return "codecImplementationName"; // 'goog' prefixed constants. case kStatsValueNameAccelerateRate: @@ -592,9 +594,6 @@ const char* StatsReport::Value::display_name() const { return "googViewLimitedResolution"; case kStatsValueNameWritable: return "googWritable"; - default: - RTC_DCHECK(false); - break; } return nullptr; diff --git a/talk/app/webrtc/statstypes.h b/talk/app/webrtc/statstypes.h index 7fa9f3212d..60439b9bc8 100644 --- a/talk/app/webrtc/statstypes.h +++ b/talk/app/webrtc/statstypes.h @@ -120,6 +120,7 @@ class StatsReport { kStatsValueNameAudioOutputLevel, kStatsValueNameBytesReceived, kStatsValueNameBytesSent, + kStatsValueNameCodecImplementationName, kStatsValueNameDataChannelId, kStatsValueNamePacketsLost, kStatsValueNamePacketsReceived, diff --git a/talk/media/base/mediachannel.h b/talk/media/base/mediachannel.h index 0a59019256..f6fb77d8a6 100644 --- a/talk/media/base/mediachannel.h +++ b/talk/media/base/mediachannel.h @@ -783,6 +783,7 @@ struct VideoSenderInfo : public MediaSenderInfo { } std::vector ssrc_groups; + std::string encoder_implementation_name; int packets_cached; int firs_rcvd; int plis_rcvd; @@ -828,6 +829,7 @@ struct VideoReceiverInfo : public MediaReceiverInfo { } std::vector ssrc_groups; + std::string decoder_implementation_name; int packets_concealed; int firs_sent; int plis_sent; diff --git a/talk/media/webrtc/webrtcvideoengine2.cc b/talk/media/webrtc/webrtcvideoengine2.cc index 5deee96bfb..55c07426d0 100644 --- a/talk/media/webrtc/webrtcvideoengine2.cc +++ b/talk/media/webrtc/webrtcvideoengine2.cc @@ -2125,6 +2125,7 @@ WebRtcVideoChannel2::WebRtcVideoSendStream::GetVideoSenderInfo() { if (stats.bw_limited_resolution) info.adapt_reason |= CoordinatedVideoAdapter::ADAPTREASON_BANDWIDTH; + info.encoder_implementation_name = stats.encoder_implementation_name; info.ssrc_groups = ssrc_groups_; info.framerate_input = stats.input_frame_rate; info.framerate_sent = stats.encode_frame_rate; @@ -2517,6 +2518,7 @@ WebRtcVideoChannel2::WebRtcVideoReceiveStream::GetVideoReceiverInfo() { info.ssrc_groups = ssrc_groups_; info.add_ssrc(config_.rtp.remote_ssrc); webrtc::VideoReceiveStream::Stats stats = stream_->GetStats(); + info.decoder_implementation_name = stats.decoder_implementation_name; info.bytes_rcvd = stats.rtp_stats.transmitted.payload_bytes + stats.rtp_stats.transmitted.header_bytes + stats.rtp_stats.transmitted.padding_bytes; diff --git a/talk/media/webrtc/webrtcvideoengine2_unittest.cc b/talk/media/webrtc/webrtcvideoengine2_unittest.cc index bd88b9c8da..6aca2341fc 100644 --- a/talk/media/webrtc/webrtcvideoengine2_unittest.cc +++ b/talk/media/webrtc/webrtcvideoengine2_unittest.cc @@ -2445,6 +2445,18 @@ TEST_F(WebRtcVideoChannel2Test, GetStatsReportsSentCodecName) { EXPECT_EQ(kVp8Codec.name, info.senders[0].codec_name); } +TEST_F(WebRtcVideoChannel2Test, GetStatsReportsEncoderImplementationName) { + FakeVideoSendStream* stream = AddSendStream(); + webrtc::VideoSendStream::Stats stats; + stats.encoder_implementation_name = "encoder_implementation_name"; + stream->SetStats(stats); + + cricket::VideoMediaInfo info; + ASSERT_TRUE(channel_->GetStats(&info)); + EXPECT_EQ(stats.encoder_implementation_name, + info.senders[0].encoder_implementation_name); +} + TEST_F(WebRtcVideoChannel2Test, GetStatsReportsCpuOveruseMetrics) { FakeVideoSendStream* stream = AddSendStream(); webrtc::VideoSendStream::Stats stats; @@ -2677,6 +2689,7 @@ TEST_F(WebRtcVideoChannel2Test, TEST_F(WebRtcVideoChannel2Test, GetStatsTranslatesDecodeStatsCorrectly) { FakeVideoReceiveStream* stream = AddRecvStream(); webrtc::VideoReceiveStream::Stats stats; + stats.decoder_implementation_name = "decoder_implementation_name"; stats.decode_ms = 2; stats.max_decode_ms = 3; stats.current_delay_ms = 4; @@ -2688,6 +2701,8 @@ TEST_F(WebRtcVideoChannel2Test, GetStatsTranslatesDecodeStatsCorrectly) { cricket::VideoMediaInfo info; ASSERT_TRUE(channel_->GetStats(&info)); + EXPECT_EQ(stats.decoder_implementation_name, + info.receivers[0].decoder_implementation_name); EXPECT_EQ(stats.decode_ms, info.receivers[0].decode_ms); EXPECT_EQ(stats.max_decode_ms, info.receivers[0].max_decode_ms); EXPECT_EQ(stats.current_delay_ms, info.receivers[0].current_delay_ms); diff --git a/webrtc/modules/video_coding/codecs/h264/h264_video_toolbox_decoder.cc b/webrtc/modules/video_coding/codecs/h264/h264_video_toolbox_decoder.cc index 6d9a4c14c7..a0bbb9e55a 100644 --- a/webrtc/modules/video_coding/codecs/h264/h264_video_toolbox_decoder.cc +++ b/webrtc/modules/video_coding/codecs/h264/h264_video_toolbox_decoder.cc @@ -266,6 +266,10 @@ void H264VideoToolboxDecoder::SetVideoFormat( } } +const char* H264VideoToolboxDecoder::ImplementationName() const { + return "VideoToolbox"; +} + } // namespace webrtc #endif // defined(WEBRTC_VIDEO_TOOLBOX_SUPPORTED) diff --git a/webrtc/modules/video_coding/codecs/h264/h264_video_toolbox_decoder.h b/webrtc/modules/video_coding/codecs/h264/h264_video_toolbox_decoder.h index f54ddb9efd..6d64307a82 100644 --- a/webrtc/modules/video_coding/codecs/h264/h264_video_toolbox_decoder.h +++ b/webrtc/modules/video_coding/codecs/h264/h264_video_toolbox_decoder.h @@ -45,6 +45,8 @@ class H264VideoToolboxDecoder : public H264Decoder { int Reset() override; + const char* ImplementationName() const override; + private: int ResetDecompressionSession(); void ConfigureDecompressionSession(); diff --git a/webrtc/modules/video_coding/codecs/h264/h264_video_toolbox_encoder.cc b/webrtc/modules/video_coding/codecs/h264/h264_video_toolbox_encoder.cc index d677f8b812..f47f39c115 100644 --- a/webrtc/modules/video_coding/codecs/h264/h264_video_toolbox_encoder.cc +++ b/webrtc/modules/video_coding/codecs/h264/h264_video_toolbox_encoder.cc @@ -434,6 +434,10 @@ void H264VideoToolboxEncoder::DestroyCompressionSession() { } } +const char* H264VideoToolboxEncoder::ImplementationName() const { + return "VideoToolbox"; +} + } // namespace webrtc #endif // defined(WEBRTC_VIDEO_TOOLBOX_SUPPORTED) diff --git a/webrtc/modules/video_coding/codecs/h264/h264_video_toolbox_encoder.h b/webrtc/modules/video_coding/codecs/h264/h264_video_toolbox_encoder.h index f4fb86fa04..269e0411b2 100644 --- a/webrtc/modules/video_coding/codecs/h264/h264_video_toolbox_encoder.h +++ b/webrtc/modules/video_coding/codecs/h264/h264_video_toolbox_encoder.h @@ -48,6 +48,8 @@ class H264VideoToolboxEncoder : public H264Encoder { int Release() override; + const char* ImplementationName() const override; + private: int ResetCompressionSession(); void ConfigureCompressionSession(); diff --git a/webrtc/modules/video_coding/codecs/vp8/vp8_impl.cc b/webrtc/modules/video_coding/codecs/vp8/vp8_impl.cc index 605b4d16fe..a608c1025b 100644 --- a/webrtc/modules/video_coding/codecs/vp8/vp8_impl.cc +++ b/webrtc/modules/video_coding/codecs/vp8/vp8_impl.cc @@ -301,6 +301,10 @@ int VP8EncoderImpl::SetRates(uint32_t new_bitrate_kbit, return WEBRTC_VIDEO_CODEC_OK; } +const char* VP8EncoderImpl::ImplementationName() const { + return "libvpx"; +} + void VP8EncoderImpl::SetStreamState(bool send_stream, int stream_idx) { if (send_stream && !send_stream_[stream_idx]) { @@ -1398,6 +1402,10 @@ int VP8DecoderImpl::Release() { return WEBRTC_VIDEO_CODEC_OK; } +const char* VP8DecoderImpl::ImplementationName() const { + return "libvpx"; +} + int VP8DecoderImpl::CopyReference(VP8DecoderImpl* copy) { // The type of frame to copy should be set in ref_frame_->frame_type // before the call to this function. diff --git a/webrtc/modules/video_coding/codecs/vp8/vp8_impl.h b/webrtc/modules/video_coding/codecs/vp8/vp8_impl.h index 597fb77970..e673ad4e0a 100644 --- a/webrtc/modules/video_coding/codecs/vp8/vp8_impl.h +++ b/webrtc/modules/video_coding/codecs/vp8/vp8_impl.h @@ -58,6 +58,8 @@ class VP8EncoderImpl : public VP8Encoder { void OnDroppedFrame() override {} + const char* ImplementationName() const override; + private: void SetupTemporalLayers(int num_streams, int num_temporal_layers, const VideoCodec& codec); @@ -135,6 +137,8 @@ class VP8DecoderImpl : public VP8Decoder { int Release() override; int Reset() override; + const char* ImplementationName() const override; + private: // Copy reference image from this _decoder to the _decoder in copyTo. Set // which frame type to copy in _refFrame->frame_type before the call to diff --git a/webrtc/modules/video_coding/codecs/vp9/vp9_impl.cc b/webrtc/modules/video_coding/codecs/vp9/vp9_impl.cc index 21096bd82e..a00af6449d 100644 --- a/webrtc/modules/video_coding/codecs/vp9/vp9_impl.cc +++ b/webrtc/modules/video_coding/codecs/vp9/vp9_impl.cc @@ -809,6 +809,10 @@ int VP9EncoderImpl::RegisterEncodeCompleteCallback( return WEBRTC_VIDEO_CODEC_OK; } +const char* VP9EncoderImpl::ImplementationName() const { + return "libvpx"; +} + VP9Decoder* VP9Decoder::Create() { return new VP9DecoderImpl(); } @@ -980,4 +984,9 @@ int VP9DecoderImpl::Release() { inited_ = false; return WEBRTC_VIDEO_CODEC_OK; } + +const char* VP9DecoderImpl::ImplementationName() const { + return "libvpx"; +} + } // namespace webrtc diff --git a/webrtc/modules/video_coding/codecs/vp9/vp9_impl.h b/webrtc/modules/video_coding/codecs/vp9/vp9_impl.h index 9a48e74d3e..91475c9e82 100644 --- a/webrtc/modules/video_coding/codecs/vp9/vp9_impl.h +++ b/webrtc/modules/video_coding/codecs/vp9/vp9_impl.h @@ -47,6 +47,8 @@ class VP9EncoderImpl : public VP9Encoder { void OnDroppedFrame() override {} + const char* ImplementationName() const override; + struct LayerFrameRefSettings { int8_t upd_buf = -1; // -1 - no update, 0..7 - update buffer 0..7 int8_t ref_buf1 = -1; // -1 - no reference, 0..7 - reference buffer 0..7 @@ -148,6 +150,8 @@ class VP9DecoderImpl : public VP9Decoder { int Reset() override; + const char* ImplementationName() const override; + private: int ReturnFrame(const vpx_image_t* img, uint32_t timeStamp); diff --git a/webrtc/modules/video_coding/generic_decoder.cc b/webrtc/modules/video_coding/generic_decoder.cc index dc78ec21f2..3c72509c05 100644 --- a/webrtc/modules/video_coding/generic_decoder.cc +++ b/webrtc/modules/video_coding/generic_decoder.cc @@ -19,15 +19,12 @@ namespace webrtc { VCMDecodedFrameCallback::VCMDecodedFrameCallback(VCMTiming& timing, Clock* clock) -: -_critSect(CriticalSectionWrapper::CreateCriticalSection()), -_clock(clock), -_receiveCallback(NULL), -_timing(timing), -_timestampMap(kDecoderFrameMemoryLength), -_lastReceivedPictureID(0) -{ -} + : _critSect(CriticalSectionWrapper::CreateCriticalSection()), + _clock(clock), + _receiveCallback(NULL), + _timing(timing), + _timestampMap(kDecoderFrameMemoryLength), + _lastReceivedPictureID(0) {} VCMDecodedFrameCallback::~VCMDecodedFrameCallback() { @@ -115,6 +112,13 @@ uint64_t VCMDecodedFrameCallback::LastReceivedPictureID() const return _lastReceivedPictureID; } +void VCMDecodedFrameCallback::OnDecoderImplementationName( + const char* implementation_name) { + CriticalSectionScoped cs(_critSect); + if (_receiveCallback) + _receiveCallback->OnDecoderImplementationName(implementation_name); +} + void VCMDecodedFrameCallback::Map(uint32_t timestamp, VCMFrameInformation* frameInfo) { CriticalSectionScoped cs(_critSect); @@ -164,6 +168,7 @@ int32_t VCMGenericDecoder::Decode(const VCMEncodedFrame& frame, int64_t nowMs) { frame.FragmentationHeader(), frame.CodecSpecific(), frame.RenderTimeMs()); + _callback->OnDecoderImplementationName(_decoder->ImplementationName()); if (ret < WEBRTC_VIDEO_CODEC_OK) { LOG(LS_WARNING) << "Failed to decode frame with timestamp " diff --git a/webrtc/modules/video_coding/generic_decoder.h b/webrtc/modules/video_coding/generic_decoder.h index 40a9845c94..b23462ffee 100644 --- a/webrtc/modules/video_coding/generic_decoder.h +++ b/webrtc/modules/video_coding/generic_decoder.h @@ -46,6 +46,7 @@ public: virtual int32_t ReceivedDecodedFrame(const uint64_t pictureId); uint64_t LastReceivedPictureID() const; + void OnDecoderImplementationName(const char* implementation_name); void Map(uint32_t timestamp, VCMFrameInformation* frameInfo); int32_t Pop(uint32_t timestamp); @@ -54,9 +55,9 @@ private: // Protect |_receiveCallback| and |_timestampMap|. CriticalSectionWrapper* _critSect; Clock* _clock; - VCMReceiveCallback* _receiveCallback; // Guarded by |_critSect|. + VCMReceiveCallback* _receiveCallback GUARDED_BY(_critSect); VCMTiming& _timing; - VCMTimestampMap _timestampMap; // Guarded by |_critSect|. + VCMTimestampMap _timestampMap GUARDED_BY(_critSect); uint64_t _lastReceivedPictureID; }; diff --git a/webrtc/modules/video_coding/generic_encoder.cc b/webrtc/modules/video_coding/generic_encoder.cc index c8180f35a2..ae5284b9a5 100644 --- a/webrtc/modules/video_coding/generic_encoder.cc +++ b/webrtc/modules/video_coding/generic_encoder.cc @@ -150,6 +150,12 @@ int32_t VCMGenericEncoder::Encode(const VideoFrame& inputFrame, vcm_encoded_frame_callback_->SetRotation(rotation_); int32_t result = encoder_->Encode(inputFrame, codecSpecificInfo, &frameTypes); + + if (vcm_encoded_frame_callback_) { + vcm_encoded_frame_callback_->SignalLastEncoderImplementationUsed( + encoder_->ImplementationName()); + } + if (is_screenshare_ && result == WEBRTC_VIDEO_CODEC_TARGET_BITRATE_OVERSHOOT) { // Target bitrate exceeded, encoder state has been reset - try again. @@ -224,7 +230,7 @@ int VCMGenericEncoder::GetTargetFramerate() { ***************************/ VCMEncodedFrameCallback::VCMEncodedFrameCallback( EncodedImageCallback* post_encode_callback) - : _sendCallback(), + : send_callback_(), _mediaOpt(NULL), _payloadType(0), _internalSource(false), @@ -250,27 +256,25 @@ VCMEncodedFrameCallback::~VCMEncodedFrameCallback() int32_t VCMEncodedFrameCallback::SetTransportCallback(VCMPacketizationCallback* transport) { - _sendCallback = transport; + send_callback_ = transport; return VCM_OK; } int32_t VCMEncodedFrameCallback::Encoded( - const EncodedImage& encodedImage, + const EncodedImage& encoded_image, const CodecSpecificInfo* codecSpecificInfo, const RTPFragmentationHeader* fragmentationHeader) { TRACE_EVENT_INSTANT1("webrtc", "VCMEncodedFrameCallback::Encoded", - "timestamp", encodedImage._timeStamp); - RTC_DCHECK(encodedImage._frameType == kVideoFrameKey || - encodedImage._frameType == kVideoFrameDelta); - post_encode_callback_->Encoded(encodedImage, NULL, NULL); + "timestamp", encoded_image._timeStamp); + post_encode_callback_->Encoded(encoded_image, NULL, NULL); - if (_sendCallback == NULL) { + if (send_callback_ == NULL) { return VCM_UNINITIALIZED; } #ifdef DEBUG_ENCODER_BIT_STREAM if (_bitStreamAfterEncoder != NULL) { - fwrite(encodedImage._buffer, 1, encodedImage._length, + fwrite(encoded_image._buffer, 1, encoded_image._length, _bitStreamAfterEncoder); } #endif @@ -283,25 +287,29 @@ int32_t VCMEncodedFrameCallback::Encoded( } rtpVideoHeader.rotation = _rotation; - int32_t callbackReturn = _sendCallback->SendData( - _payloadType, encodedImage, *fragmentationHeader, rtpVideoHeaderPtr); + int32_t callbackReturn = send_callback_->SendData( + _payloadType, encoded_image, *fragmentationHeader, rtpVideoHeaderPtr); if (callbackReturn < 0) { return callbackReturn; } if (_mediaOpt != NULL) { - _mediaOpt->UpdateWithEncodedData(encodedImage); + _mediaOpt->UpdateWithEncodedData(encoded_image); if (_internalSource) return _mediaOpt->DropFrame(); // Signal to encoder to drop next frame. } return VCM_OK; } -void -VCMEncodedFrameCallback::SetMediaOpt( - media_optimization::MediaOptimization *mediaOpt) -{ - _mediaOpt = mediaOpt; +void VCMEncodedFrameCallback::SetMediaOpt( + media_optimization::MediaOptimization* mediaOpt) { + _mediaOpt = mediaOpt; +} + +void VCMEncodedFrameCallback::SignalLastEncoderImplementationUsed( + const char* implementation_name) { + if (send_callback_) + send_callback_->OnEncoderImplementationName(implementation_name); } } // namespace webrtc diff --git a/webrtc/modules/video_coding/generic_encoder.h b/webrtc/modules/video_coding/generic_encoder.h index 0d8ad50b5f..5346b638c3 100644 --- a/webrtc/modules/video_coding/generic_encoder.h +++ b/webrtc/modules/video_coding/generic_encoder.h @@ -62,9 +62,11 @@ public: void SetInternalSource(bool internalSource) { _internalSource = internalSource; }; void SetRotation(VideoRotation rotation) { _rotation = rotation; } + void SignalLastEncoderImplementationUsed( + const char* encoder_implementation_name); private: - VCMPacketizationCallback* _sendCallback; + VCMPacketizationCallback* send_callback_; media_optimization::MediaOptimization* _mediaOpt; uint8_t _payloadType; bool _internalSource; diff --git a/webrtc/modules/video_coding/include/video_coding_defines.h b/webrtc/modules/video_coding/include/video_coding_defines.h index 1b721441e2..d057b554cd 100644 --- a/webrtc/modules/video_coding/include/video_coding_defines.h +++ b/webrtc/modules/video_coding/include/video_coding_defines.h @@ -62,6 +62,8 @@ class VCMPacketizationCallback { const RTPFragmentationHeader& fragmentationHeader, const RTPVideoHeader* rtpVideoHdr) = 0; + virtual void OnEncoderImplementationName(const char* implementation_name) {} + protected: virtual ~VCMPacketizationCallback() { } @@ -77,6 +79,7 @@ class VCMReceiveCallback { } // Called when the current receive codec changes. virtual void OnIncomingPayloadType(int payload_type) {} + virtual void OnDecoderImplementationName(const char* implementation_name) {} protected: virtual ~VCMReceiveCallback() { diff --git a/webrtc/modules/video_coding/video_receiver.cc b/webrtc/modules/video_coding/video_receiver.cc index f7ac4bc862..f074832eff 100644 --- a/webrtc/modules/video_coding/video_receiver.cc +++ b/webrtc/modules/video_coding/video_receiver.cc @@ -287,43 +287,37 @@ int32_t VideoReceiver::Decode(uint16_t maxWaitTimeMs) { VCMEncodedFrame* frame = _receiver.FrameForDecoding( maxWaitTimeMs, nextRenderTimeMs, prefer_late_decoding); - if (frame == NULL) { + if (!frame) return VCM_FRAME_NOT_READY; - } else { - CriticalSectionScoped cs(_receiveCritSect); - // If this frame was too late, we should adjust the delay accordingly - _timing.UpdateCurrentDelay(frame->RenderTimeMs(), - clock_->TimeInMilliseconds()); + CriticalSectionScoped cs(_receiveCritSect); - if (pre_decode_image_callback_) { - EncodedImage encoded_image(frame->EncodedImage()); - int qp = -1; - if (qp_parser_.GetQp(*frame, &qp)) { - encoded_image.qp_ = qp; - } - pre_decode_image_callback_->Encoded( - encoded_image, frame->CodecSpecific(), NULL); + // If this frame was too late, we should adjust the delay accordingly + _timing.UpdateCurrentDelay(frame->RenderTimeMs(), + clock_->TimeInMilliseconds()); + + if (pre_decode_image_callback_) { + EncodedImage encoded_image(frame->EncodedImage()); + int qp = -1; + if (qp_parser_.GetQp(*frame, &qp)) { + encoded_image.qp_ = qp; } + pre_decode_image_callback_->Encoded(encoded_image, frame->CodecSpecific(), + NULL); + } #ifdef DEBUG_DECODER_BIT_STREAM - if (_bitStreamBeforeDecoder != NULL) { - // Write bit stream to file for debugging purposes - if (fwrite( - frame->Buffer(), 1, frame->Length(), _bitStreamBeforeDecoder) != - frame->Length()) { - return -1; - } - } -#endif - const int32_t ret = Decode(*frame); - _receiver.ReleaseFrame(frame); - frame = NULL; - if (ret != VCM_OK) { - return ret; + if (_bitStreamBeforeDecoder != NULL) { + // Write bit stream to file for debugging purposes + if (fwrite(frame->Buffer(), 1, frame->Length(), _bitStreamBeforeDecoder) != + frame->Length()) { + return -1; } } - return VCM_OK; +#endif + const int32_t ret = Decode(*frame); + _receiver.ReleaseFrame(frame); + return ret; } int32_t VideoReceiver::RequestSliceLossIndication( diff --git a/webrtc/test/fake_decoder.cc b/webrtc/test/fake_decoder.cc index 63316e0dab..dbdd580e88 100644 --- a/webrtc/test/fake_decoder.cc +++ b/webrtc/test/fake_decoder.cc @@ -53,10 +53,16 @@ int32_t FakeDecoder::RegisterDecodeCompleteCallback( int32_t FakeDecoder::Release() { return WEBRTC_VIDEO_CODEC_OK; } + int32_t FakeDecoder::Reset() { return WEBRTC_VIDEO_CODEC_OK; } +const char* FakeDecoder::kImplementationName = "fake_decoder"; +const char* FakeDecoder::ImplementationName() const { + return kImplementationName; +} + int32_t FakeH264Decoder::Decode(const EncodedImage& input, bool missing_frames, const RTPFragmentationHeader* fragmentation, diff --git a/webrtc/test/fake_decoder.h b/webrtc/test/fake_decoder.h index 20f6bbf4d0..0da961d9a0 100644 --- a/webrtc/test/fake_decoder.h +++ b/webrtc/test/fake_decoder.h @@ -39,6 +39,10 @@ class FakeDecoder : public VideoDecoder { int32_t Release() override; int32_t Reset() override; + const char* ImplementationName() const override; + + static const char* kImplementationName; + private: VideoCodec config_; VideoFrame frame_; diff --git a/webrtc/test/fake_encoder.cc b/webrtc/test/fake_encoder.cc index 165fd3e536..72df40f9a5 100644 --- a/webrtc/test/fake_encoder.cc +++ b/webrtc/test/fake_encoder.cc @@ -132,6 +132,11 @@ int32_t FakeEncoder::SetRates(uint32_t new_target_bitrate, uint32_t framerate) { return 0; } +const char* FakeEncoder::kImplementationName = "fake_encoder"; +const char* FakeEncoder::ImplementationName() const { + return kImplementationName; +} + FakeH264Encoder::FakeH264Encoder(Clock* clock) : FakeEncoder(clock), callback_(NULL), idr_counter_(0) { FakeEncoder::RegisterEncodeCompleteCallback(this); diff --git a/webrtc/test/fake_encoder.h b/webrtc/test/fake_encoder.h index 88ff9d40f3..6bff00e2a3 100644 --- a/webrtc/test/fake_encoder.h +++ b/webrtc/test/fake_encoder.h @@ -39,6 +39,9 @@ class FakeEncoder : public VideoEncoder { int32_t Release() override; int32_t SetChannelParameters(uint32_t packet_loss, int64_t rtt) override; int32_t SetRates(uint32_t new_target_bitrate, uint32_t framerate) override; + const char* ImplementationName() const override; + + static const char* kImplementationName; protected: Clock* const clock_; diff --git a/webrtc/video/end_to_end_tests.cc b/webrtc/video/end_to_end_tests.cc index 46741b0691..bd9c198aaa 100644 --- a/webrtc/video/end_to_end_tests.cc +++ b/webrtc/video/end_to_end_tests.cc @@ -2383,6 +2383,9 @@ TEST_F(EndToEndTest, GetStats) { receive_stats_filled_["IncomingRate"] |= stats.network_frame_rate != 0 || stats.total_bitrate_bps != 0; + send_stats_filled_["DecoderImplementationName"] |= + stats.decoder_implementation_name == + test::FakeDecoder::kImplementationName; receive_stats_filled_["RenderDelayAsHighAsExpected"] |= stats.render_delay_ms >= kExpectedRenderDelayMs; @@ -2438,6 +2441,10 @@ TEST_F(EndToEndTest, GetStats) { send_stats_filled_["CpuOveruseMetrics"] |= stats.avg_encode_time_ms != 0 || stats.encode_usage_percent != 0; + send_stats_filled_["EncoderImplementationName"] |= + stats.encoder_implementation_name == + test::FakeEncoder::kImplementationName; + for (std::map::const_iterator it = stats.substreams.begin(); it != stats.substreams.end(); ++it) { diff --git a/webrtc/video/receive_statistics_proxy.cc b/webrtc/video/receive_statistics_proxy.cc index 329905d0f8..c13c807fc4 100644 --- a/webrtc/video/receive_statistics_proxy.cc +++ b/webrtc/video/receive_statistics_proxy.cc @@ -80,6 +80,11 @@ void ReceiveStatisticsProxy::OnIncomingPayloadType(int payload_type) { stats_.current_payload_type = payload_type; } +void ReceiveStatisticsProxy::OnDecoderImplementationName( + const char* implementation_name) { + rtc::CritScope lock(&crit_); + stats_.decoder_implementation_name = implementation_name; +} void ReceiveStatisticsProxy::OnIncomingRate(unsigned int framerate, unsigned int bitrate_bps) { rtc::CritScope lock(&crit_); diff --git a/webrtc/video/receive_statistics_proxy.h b/webrtc/video/receive_statistics_proxy.h index 91f4105e1f..87cb9506a9 100644 --- a/webrtc/video/receive_statistics_proxy.h +++ b/webrtc/video/receive_statistics_proxy.h @@ -45,6 +45,7 @@ class ReceiveStatisticsProxy : public VCMReceiveStatisticsCallback, void OnDecodedFrame(); void OnRenderedFrame(int width, int height); void OnIncomingPayloadType(int payload_type); + void OnDecoderImplementationName(const char* implementation_name); void OnIncomingRate(unsigned int framerate, unsigned int bitrate_bps); void OnDecoderTiming(int decode_ms, int max_decode_ms, diff --git a/webrtc/video/send_statistics_proxy.cc b/webrtc/video/send_statistics_proxy.cc index f5e7e3d024..c198ad2f8a 100644 --- a/webrtc/video/send_statistics_proxy.cc +++ b/webrtc/video/send_statistics_proxy.cc @@ -161,6 +161,12 @@ void SendStatisticsProxy::SetContentType( } } +void SendStatisticsProxy::OnEncoderImplementationName( + const char* implementation_name) { + rtc::CritScope lock(&crit_); + stats_.encoder_implementation_name = implementation_name; +} + void SendStatisticsProxy::OnOutgoingRate(uint32_t framerate, uint32_t bitrate) { rtc::CritScope lock(&crit_); stats_.encode_frame_rate = framerate; diff --git a/webrtc/video/send_statistics_proxy.h b/webrtc/video/send_statistics_proxy.h index e9e89f64f5..7f6df06ad8 100644 --- a/webrtc/video/send_statistics_proxy.h +++ b/webrtc/video/send_statistics_proxy.h @@ -58,6 +58,7 @@ class SendStatisticsProxy : public CpuOveruseMetricsObserver, // From VideoEncoderRateObserver. void OnSetRates(uint32_t bitrate_bps, int framerate) override; + void OnEncoderImplementationName(const char* implementation_name); void OnOutgoingRate(uint32_t framerate, uint32_t bitrate); void OnSuspendChange(bool is_suspended); void OnInactiveSsrc(uint32_t ssrc); diff --git a/webrtc/video/video_decoder.cc b/webrtc/video/video_decoder.cc index 2a0151d750..d699175274 100644 --- a/webrtc/video/video_decoder.cc +++ b/webrtc/video/video_decoder.cc @@ -76,6 +76,9 @@ bool VideoDecoderSoftwareFallbackWrapper::InitFallbackDecoder() { } if (callback_ != nullptr) fallback_decoder_->RegisterDecodeCompleteCallback(callback_); + fallback_implementation_name_ = + std::string(fallback_decoder_->ImplementationName()) + + " (fallback from: " + decoder_->ImplementationName() + ")"; return true; } @@ -137,4 +140,10 @@ bool VideoDecoderSoftwareFallbackWrapper::PrefersLateDecoding() const { return decoder_->PrefersLateDecoding(); } +const char* VideoDecoderSoftwareFallbackWrapper::ImplementationName() const { + if (fallback_decoder_) + return fallback_implementation_name_.c_str(); + return decoder_->ImplementationName(); +} + } // namespace webrtc diff --git a/webrtc/video/video_decoder_unittest.cc b/webrtc/video/video_decoder_unittest.cc index 422aca0a2c..4d54a3e53f 100644 --- a/webrtc/video/video_decoder_unittest.cc +++ b/webrtc/video/video_decoder_unittest.cc @@ -53,6 +53,11 @@ class VideoDecoderSoftwareFallbackWrapperTest : public ::testing::Test { ++reset_count_; return WEBRTC_VIDEO_CODEC_OK; } + + const char* ImplementationName() const override { + return "fake-decoder"; + } + int init_decode_count_ = 0; int decode_count_ = 0; int32_t decode_return_code_ = WEBRTC_VIDEO_CODEC_OK; @@ -144,7 +149,7 @@ TEST_F(VideoDecoderSoftwareFallbackWrapperTest, ForwardsResetCall) { } // TODO(pbos): Fake a VP8 frame well enough to actually receive a callback from -// the software encoder. +// the software decoder. TEST_F(VideoDecoderSoftwareFallbackWrapperTest, ForwardsRegisterDecodeCompleteCallback) { class FakeDecodedImageCallback : public DecodedImageCallback { @@ -168,4 +173,19 @@ TEST_F(VideoDecoderSoftwareFallbackWrapperTest, EXPECT_EQ(&callback2, fake_decoder_.decode_complete_callback_); } +TEST_F(VideoDecoderSoftwareFallbackWrapperTest, + ReportsFallbackImplementationName) { + VideoCodec codec = {}; + fallback_wrapper_.InitDecode(&codec, 2); + + fake_decoder_.decode_return_code_ = WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE; + EncodedImage encoded_image; + fallback_wrapper_.Decode(encoded_image, false, nullptr, nullptr, -1); + // Hard coded expected value since libvpx is the software implementation name + // for VP8. Change accordingly if the underlying implementation does. + EXPECT_STREQ("libvpx (fallback from: fake-decoder)", + fallback_wrapper_.ImplementationName()); + fallback_wrapper_.Release(); +} + } // namespace webrtc diff --git a/webrtc/video/video_encoder.cc b/webrtc/video/video_encoder.cc index 6410e395fc..e85e3d97a7 100644 --- a/webrtc/video/video_encoder.cc +++ b/webrtc/video/video_encoder.cc @@ -76,6 +76,9 @@ bool VideoEncoderSoftwareFallbackWrapper::InitFallbackEncoder() { if (channel_parameters_set_) fallback_encoder_->SetChannelParameters(packet_loss_, rtt_); + fallback_implementation_name_ = + std::string(fallback_encoder_->ImplementationName()) + + " (fallback from: " + encoder_->ImplementationName() + ")"; // Since we're switching to the fallback encoder, Release the real encoder. It // may be re-initialized via InitEncode later, and it will continue to get // Set calls for rates and channel parameters in the meantime. @@ -182,6 +185,12 @@ bool VideoEncoderSoftwareFallbackWrapper::SupportsNativeHandle() const { return encoder_->SupportsNativeHandle(); } +const char* VideoEncoderSoftwareFallbackWrapper::ImplementationName() const { + if (fallback_encoder_) + return fallback_implementation_name_.c_str(); + return encoder_->ImplementationName(); +} + int VideoEncoderSoftwareFallbackWrapper::GetTargetFramerate() { if (fallback_encoder_) return fallback_encoder_->GetTargetFramerate(); diff --git a/webrtc/video/video_encoder_unittest.cc b/webrtc/video/video_encoder_unittest.cc index b800a74065..0f28f89163 100644 --- a/webrtc/video/video_encoder_unittest.cc +++ b/webrtc/video/video_encoder_unittest.cc @@ -67,6 +67,10 @@ class VideoEncoderSoftwareFallbackWrapperTest : public ::testing::Test { return false; } + const char* ImplementationName() const override { + return "fake-encoder"; + } + int init_encode_count_ = 0; int32_t init_encode_return_code_ = WEBRTC_VIDEO_CODEC_OK; int32_t encode_return_code_ = WEBRTC_VIDEO_CODEC_OK; @@ -259,4 +263,13 @@ TEST_F(VideoEncoderSoftwareFallbackWrapperTest, EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_.Release()); } +TEST_F(VideoEncoderSoftwareFallbackWrapperTest, + ReportsFallbackImplementationName) { + UtilizeFallbackEncoder(); + // Hard coded expected value since libvpx is the software implementation name + // for VP8. Change accordingly if the underlying implementation does. + EXPECT_STREQ("libvpx (fallback from: fake-encoder)", + fallback_wrapper_.ImplementationName()); +} + } // namespace webrtc diff --git a/webrtc/video/vie_channel.cc b/webrtc/video/vie_channel.cc index 6e2406a9bd..e39ffbf6a9 100644 --- a/webrtc/video/vie_channel.cc +++ b/webrtc/video/vie_channel.cc @@ -983,6 +983,12 @@ void ViEChannel::OnIncomingPayloadType(int payload_type) { receive_stats_callback_->OnIncomingPayloadType(payload_type); } +void ViEChannel::OnDecoderImplementationName(const char* implementation_name) { + CriticalSectionScoped cs(crit_.get()); + if (receive_stats_callback_) + receive_stats_callback_->OnDecoderImplementationName(implementation_name); +} + void ViEChannel::OnReceiveRatesUpdated(uint32_t bit_rate, uint32_t frame_rate) { CriticalSectionScoped cs(crit_.get()); if (receive_stats_callback_) diff --git a/webrtc/video/vie_channel.h b/webrtc/video/vie_channel.h index 8f99260bb3..25d06b9d00 100644 --- a/webrtc/video/vie_channel.h +++ b/webrtc/video/vie_channel.h @@ -230,6 +230,7 @@ class ViEChannel : public VCMFrameTypeCallback, // Implements VCMReceiveCallback. void OnIncomingPayloadType(int payload_type) override; + void OnDecoderImplementationName(const char* implementation_name) override; // Implements VCMReceiveStatisticsCallback. void OnReceiveRatesUpdated(uint32_t bit_rate, uint32_t frame_rate) override; diff --git a/webrtc/video/vie_encoder.cc b/webrtc/video/vie_encoder.cc index 803825c909..a147b2415c 100644 --- a/webrtc/video/vie_encoder.cc +++ b/webrtc/video/vie_encoder.cc @@ -472,6 +472,12 @@ int32_t ViEEncoder::SendData( : -1; } +void ViEEncoder::OnEncoderImplementationName( + const char* implementation_name) { + if (stats_proxy_) + stats_proxy_->OnEncoderImplementationName(implementation_name); +} + int32_t ViEEncoder::SendStatistics(const uint32_t bit_rate, const uint32_t frame_rate) { if (stats_proxy_) diff --git a/webrtc/video/vie_encoder.h b/webrtc/video/vie_encoder.h index b86287c129..a15fd8920b 100644 --- a/webrtc/video/vie_encoder.h +++ b/webrtc/video/vie_encoder.h @@ -112,6 +112,7 @@ class ViEEncoder : public RtcpIntraFrameObserver, const EncodedImage& encoded_image, const RTPFragmentationHeader& fragmentation_header, const RTPVideoHeader* rtp_video_hdr) override; + void OnEncoderImplementationName(const char* implementation_name) override; // Implements VideoSendStatisticsCallback. int32_t SendStatistics(const uint32_t bit_rate, diff --git a/webrtc/video_decoder.h b/webrtc/video_decoder.h index 30e27792e9..3cd94e8270 100644 --- a/webrtc/video_decoder.h +++ b/webrtc/video_decoder.h @@ -11,6 +11,7 @@ #ifndef WEBRTC_VIDEO_DECODER_H_ #define WEBRTC_VIDEO_DECODER_H_ +#include #include #include "webrtc/common_types.h" @@ -78,6 +79,8 @@ class VideoDecoder { // That is, it can not decode infinite number of frames before the decoded // frame is consumed. virtual bool PrefersLateDecoding() const { return true; } + + virtual const char* ImplementationName() const { return "unknown"; } }; // Class used to wrap external VideoDecoders to provide a fallback option on @@ -104,6 +107,8 @@ class VideoDecoderSoftwareFallbackWrapper : public webrtc::VideoDecoder { int32_t Reset() override; bool PrefersLateDecoding() const override; + const char* ImplementationName() const override; + private: bool InitFallbackDecoder(); @@ -112,6 +117,7 @@ class VideoDecoderSoftwareFallbackWrapper : public webrtc::VideoDecoder { VideoCodec codec_settings_; int32_t number_of_cores_; + std::string fallback_implementation_name_; rtc::scoped_ptr fallback_decoder_; DecodedImageCallback* callback_; }; diff --git a/webrtc/video_encoder.h b/webrtc/video_encoder.h index f255336a25..9e7e4d7040 100644 --- a/webrtc/video_encoder.h +++ b/webrtc/video_encoder.h @@ -11,6 +11,7 @@ #ifndef WEBRTC_VIDEO_ENCODER_H_ #define WEBRTC_VIDEO_ENCODER_H_ +#include #include #include "webrtc/common_types.h" @@ -124,6 +125,7 @@ class VideoEncoder { virtual void OnDroppedFrame() {} virtual int GetTargetFramerate() { return -1; } virtual bool SupportsNativeHandle() const { return false; } + virtual const char* ImplementationName() const { return "unknown"; } }; // Class used to wrap external VideoEncoders to provide a fallback option on @@ -151,6 +153,7 @@ class VideoEncoderSoftwareFallbackWrapper : public VideoEncoder { void OnDroppedFrame() override; int GetTargetFramerate() override; bool SupportsNativeHandle() const override; + const char* ImplementationName() const override; private: bool InitFallbackEncoder(); @@ -175,6 +178,7 @@ class VideoEncoderSoftwareFallbackWrapper : public VideoEncoder { webrtc::VideoEncoder* const encoder_; rtc::scoped_ptr fallback_encoder_; + std::string fallback_implementation_name_; EncodedImageCallback* callback_; }; } // namespace webrtc diff --git a/webrtc/video_receive_stream.h b/webrtc/video_receive_stream.h index cd1434caee..51d842616b 100644 --- a/webrtc/video_receive_stream.h +++ b/webrtc/video_receive_stream.h @@ -51,6 +51,7 @@ class VideoReceiveStream : public ReceiveStream { int render_frame_rate = 0; // Decoder stats. + std::string decoder_implementation_name = "unknown"; FrameCounts frame_counts; int decode_ms = 0; int max_decode_ms = 0; diff --git a/webrtc/video_send_stream.h b/webrtc/video_send_stream.h index b5f8c9ad1c..83a96d3fed 100644 --- a/webrtc/video_send_stream.h +++ b/webrtc/video_send_stream.h @@ -62,6 +62,7 @@ class VideoSendStream : public SendStream { }; struct Stats { + std::string encoder_implementation_name = "unknown"; int input_frame_rate = 0; int encode_frame_rate = 0; int avg_encode_time_ms = 0;