Expose codec implementation names in stats.

Used to distinguish between software/hardware encoders/decoders and
other implementation differences. Useful for tracking quality
regressions related to specific implementations.

BUG=webrtc:4897
R=hta@webrtc.org, mflodman@webrtc.org, stefan@webrtc.org

Review URL: https://codereview.webrtc.org/1406903002 .

Cr-Commit-Position: refs/heads/master@{#11084}
This commit is contained in:
Peter Boström 2015-12-18 16:01:11 +01:00
parent 6c6510afad
commit b7d9a97ce4
43 changed files with 266 additions and 63 deletions

View File

@ -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

View File

@ -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");

View File

@ -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,

View File

@ -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;

View File

@ -120,6 +120,7 @@ class StatsReport {
kStatsValueNameAudioOutputLevel,
kStatsValueNameBytesReceived,
kStatsValueNameBytesSent,
kStatsValueNameCodecImplementationName,
kStatsValueNameDataChannelId,
kStatsValueNamePacketsLost,
kStatsValueNamePacketsReceived,

View File

@ -783,6 +783,7 @@ struct VideoSenderInfo : public MediaSenderInfo {
}
std::vector<SsrcGroup> 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<SsrcGroup> ssrc_groups;
std::string decoder_implementation_name;
int packets_concealed;
int firs_sent;
int plis_sent;

View File

@ -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;

View File

@ -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);

View File

@ -266,6 +266,10 @@ void H264VideoToolboxDecoder::SetVideoFormat(
}
}
const char* H264VideoToolboxDecoder::ImplementationName() const {
return "VideoToolbox";
}
} // namespace webrtc
#endif // defined(WEBRTC_VIDEO_TOOLBOX_SUPPORTED)

View File

@ -45,6 +45,8 @@ class H264VideoToolboxDecoder : public H264Decoder {
int Reset() override;
const char* ImplementationName() const override;
private:
int ResetDecompressionSession();
void ConfigureDecompressionSession();

View File

@ -434,6 +434,10 @@ void H264VideoToolboxEncoder::DestroyCompressionSession() {
}
}
const char* H264VideoToolboxEncoder::ImplementationName() const {
return "VideoToolbox";
}
} // namespace webrtc
#endif // defined(WEBRTC_VIDEO_TOOLBOX_SUPPORTED)

View File

@ -48,6 +48,8 @@ class H264VideoToolboxEncoder : public H264Encoder {
int Release() override;
const char* ImplementationName() const override;
private:
int ResetCompressionSession();
void ConfigureCompressionSession();

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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 "

View File

@ -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;
};

View File

@ -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

View File

@ -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;

View File

@ -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() {

View File

@ -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(

View File

@ -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,

View File

@ -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_;

View File

@ -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);

View File

@ -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_;

View File

@ -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<uint32_t, VideoSendStream::StreamStats>::const_iterator it =
stats.substreams.begin();
it != stats.substreams.end(); ++it) {

View File

@ -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_);

View File

@ -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,

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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();

View File

@ -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

View File

@ -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_)

View File

@ -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;

View File

@ -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_)

View File

@ -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,

View File

@ -11,6 +11,7 @@
#ifndef WEBRTC_VIDEO_DECODER_H_
#define WEBRTC_VIDEO_DECODER_H_
#include <string>
#include <vector>
#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<VideoDecoder> fallback_decoder_;
DecodedImageCallback* callback_;
};

View File

@ -11,6 +11,7 @@
#ifndef WEBRTC_VIDEO_ENCODER_H_
#define WEBRTC_VIDEO_ENCODER_H_
#include <string>
#include <vector>
#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<webrtc::VideoEncoder> fallback_encoder_;
std::string fallback_implementation_name_;
EncodedImageCallback* callback_;
};
} // namespace webrtc

View File

@ -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;

View File

@ -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;