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:
parent
6c6510afad
commit
b7d9a97ce4
@ -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
|
||||
|
||||
|
||||
@ -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");
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -120,6 +120,7 @@ class StatsReport {
|
||||
kStatsValueNameAudioOutputLevel,
|
||||
kStatsValueNameBytesReceived,
|
||||
kStatsValueNameBytesSent,
|
||||
kStatsValueNameCodecImplementationName,
|
||||
kStatsValueNameDataChannelId,
|
||||
kStatsValueNamePacketsLost,
|
||||
kStatsValueNamePacketsReceived,
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -266,6 +266,10 @@ void H264VideoToolboxDecoder::SetVideoFormat(
|
||||
}
|
||||
}
|
||||
|
||||
const char* H264VideoToolboxDecoder::ImplementationName() const {
|
||||
return "VideoToolbox";
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // defined(WEBRTC_VIDEO_TOOLBOX_SUPPORTED)
|
||||
|
||||
@ -45,6 +45,8 @@ class H264VideoToolboxDecoder : public H264Decoder {
|
||||
|
||||
int Reset() override;
|
||||
|
||||
const char* ImplementationName() const override;
|
||||
|
||||
private:
|
||||
int ResetDecompressionSession();
|
||||
void ConfigureDecompressionSession();
|
||||
|
||||
@ -434,6 +434,10 @@ void H264VideoToolboxEncoder::DestroyCompressionSession() {
|
||||
}
|
||||
}
|
||||
|
||||
const char* H264VideoToolboxEncoder::ImplementationName() const {
|
||||
return "VideoToolbox";
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // defined(WEBRTC_VIDEO_TOOLBOX_SUPPORTED)
|
||||
|
||||
@ -48,6 +48,8 @@ class H264VideoToolboxEncoder : public H264Encoder {
|
||||
|
||||
int Release() override;
|
||||
|
||||
const char* ImplementationName() const override;
|
||||
|
||||
private:
|
||||
int ResetCompressionSession();
|
||||
void ConfigureCompressionSession();
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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 "
|
||||
|
||||
@ -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;
|
||||
};
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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() {
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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_;
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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_;
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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_);
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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_)
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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_)
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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_;
|
||||
};
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user