• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #include "webrtc/video_decoder.h"
12 
13 #include "testing/gtest/include/gtest/gtest.h"
14 #include "webrtc/base/checks.h"
15 #include "webrtc/modules/video_coding/include/video_error_codes.h"
16 
17 namespace webrtc {
18 
19 class VideoDecoderSoftwareFallbackWrapperTest : public ::testing::Test {
20  protected:
VideoDecoderSoftwareFallbackWrapperTest()21   VideoDecoderSoftwareFallbackWrapperTest()
22       : fallback_wrapper_(kVideoCodecVP8, &fake_decoder_) {}
23 
24   class CountingFakeDecoder : public VideoDecoder {
25    public:
InitDecode(const VideoCodec * codec_settings,int32_t number_of_cores)26     int32_t InitDecode(const VideoCodec* codec_settings,
27                        int32_t number_of_cores) override {
28       ++init_decode_count_;
29       return WEBRTC_VIDEO_CODEC_OK;
30     }
31 
Decode(const EncodedImage & input_image,bool missing_frames,const RTPFragmentationHeader * fragmentation,const CodecSpecificInfo * codec_specific_info,int64_t render_time_ms)32     int32_t Decode(const EncodedImage& input_image,
33                    bool missing_frames,
34                    const RTPFragmentationHeader* fragmentation,
35                    const CodecSpecificInfo* codec_specific_info,
36                    int64_t render_time_ms) override {
37       ++decode_count_;
38       return decode_return_code_;
39     }
40 
RegisterDecodeCompleteCallback(DecodedImageCallback * callback)41     int32_t RegisterDecodeCompleteCallback(
42         DecodedImageCallback* callback) override {
43       decode_complete_callback_ = callback;
44       return WEBRTC_VIDEO_CODEC_OK;
45     }
46 
Release()47     int32_t Release() override {
48       ++release_count_;
49       return WEBRTC_VIDEO_CODEC_OK;
50     }
51 
Reset()52     int32_t Reset() override {
53       ++reset_count_;
54       return WEBRTC_VIDEO_CODEC_OK;
55     }
56 
ImplementationName() const57     const char* ImplementationName() const override {
58       return "fake-decoder";
59     }
60 
61     int init_decode_count_ = 0;
62     int decode_count_ = 0;
63     int32_t decode_return_code_ = WEBRTC_VIDEO_CODEC_OK;
64     DecodedImageCallback* decode_complete_callback_ = nullptr;
65     int release_count_ = 0;
66     int reset_count_ = 0;
67   };
68   CountingFakeDecoder fake_decoder_;
69   VideoDecoderSoftwareFallbackWrapper fallback_wrapper_;
70 };
71 
TEST_F(VideoDecoderSoftwareFallbackWrapperTest,InitializesDecoder)72 TEST_F(VideoDecoderSoftwareFallbackWrapperTest, InitializesDecoder) {
73   VideoCodec codec = {};
74   fallback_wrapper_.InitDecode(&codec, 2);
75   EXPECT_EQ(1, fake_decoder_.init_decode_count_);
76 }
77 
TEST_F(VideoDecoderSoftwareFallbackWrapperTest,CanRecoverFromSoftwareFallback)78 TEST_F(VideoDecoderSoftwareFallbackWrapperTest,
79        CanRecoverFromSoftwareFallback) {
80   VideoCodec codec = {};
81   fallback_wrapper_.InitDecode(&codec, 2);
82   // Unfortunately faking a VP8 frame is hard. Rely on no Decode -> using SW
83   // decoder.
84   fake_decoder_.decode_return_code_ = WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
85   EncodedImage encoded_image;
86   fallback_wrapper_.Decode(encoded_image, false, nullptr, nullptr, -1);
87   EXPECT_EQ(1, fake_decoder_.decode_count_);
88 
89   // Fail -> fake_decoder shouldn't be used anymore.
90   fallback_wrapper_.Decode(encoded_image, false, nullptr, nullptr, -1);
91   EXPECT_EQ(1, fake_decoder_.decode_count_)
92       << "Decoder used even though fallback should be active.";
93 
94   // Should be able to recover on a keyframe.
95   encoded_image._frameType = kVideoFrameKey;
96   fake_decoder_.decode_return_code_ = WEBRTC_VIDEO_CODEC_OK;
97   fallback_wrapper_.Decode(encoded_image, false, nullptr, nullptr, -1);
98   EXPECT_EQ(2, fake_decoder_.decode_count_)
99       << "Wrapper did not try to decode a keyframe using registered decoder.";
100 
101   encoded_image._frameType = kVideoFrameDelta;
102   fallback_wrapper_.Decode(encoded_image, false, nullptr, nullptr, -1);
103   EXPECT_EQ(3, fake_decoder_.decode_count_)
104       << "Decoder not used on future delta frames.";
105 }
106 
TEST_F(VideoDecoderSoftwareFallbackWrapperTest,DoesNotFallbackOnEveryError)107 TEST_F(VideoDecoderSoftwareFallbackWrapperTest, DoesNotFallbackOnEveryError) {
108   VideoCodec codec = {};
109   fallback_wrapper_.InitDecode(&codec, 2);
110   fake_decoder_.decode_return_code_ = WEBRTC_VIDEO_CODEC_ERROR;
111   EncodedImage encoded_image;
112   EXPECT_EQ(
113       fake_decoder_.decode_return_code_,
114       fallback_wrapper_.Decode(encoded_image, false, nullptr, nullptr, -1));
115   EXPECT_EQ(1, fake_decoder_.decode_count_);
116 
117   fallback_wrapper_.Decode(encoded_image, false, nullptr, nullptr, -1);
118   EXPECT_EQ(2, fake_decoder_.decode_count_)
119       << "Decoder should be active even though previous decode failed.";
120 }
121 
TEST_F(VideoDecoderSoftwareFallbackWrapperTest,ForwardsReleaseCall)122 TEST_F(VideoDecoderSoftwareFallbackWrapperTest, ForwardsReleaseCall) {
123   VideoCodec codec = {};
124   fallback_wrapper_.InitDecode(&codec, 2);
125   fallback_wrapper_.Release();
126   EXPECT_EQ(1, fake_decoder_.release_count_);
127 
128   fake_decoder_.decode_return_code_ = WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
129   EncodedImage encoded_image;
130   fallback_wrapper_.Decode(encoded_image, false, nullptr, nullptr, -1);
131   EXPECT_EQ(1, fake_decoder_.release_count_)
132       << "Decoder should not be released during fallback.";
133   fallback_wrapper_.Release();
134   EXPECT_EQ(2, fake_decoder_.release_count_);
135 }
136 
TEST_F(VideoDecoderSoftwareFallbackWrapperTest,ForwardsResetCall)137 TEST_F(VideoDecoderSoftwareFallbackWrapperTest, ForwardsResetCall) {
138   VideoCodec codec = {};
139   fallback_wrapper_.InitDecode(&codec, 2);
140   fallback_wrapper_.Reset();
141   EXPECT_EQ(1, fake_decoder_.reset_count_);
142 
143   fake_decoder_.decode_return_code_ = WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
144   EncodedImage encoded_image;
145   fallback_wrapper_.Decode(encoded_image, false, nullptr, nullptr, -1);
146   fallback_wrapper_.Reset();
147   EXPECT_EQ(2, fake_decoder_.reset_count_)
148       << "Reset not forwarded during fallback.";
149 }
150 
151 // TODO(pbos): Fake a VP8 frame well enough to actually receive a callback from
152 // the software decoder.
TEST_F(VideoDecoderSoftwareFallbackWrapperTest,ForwardsRegisterDecodeCompleteCallback)153 TEST_F(VideoDecoderSoftwareFallbackWrapperTest,
154        ForwardsRegisterDecodeCompleteCallback) {
155   class FakeDecodedImageCallback : public DecodedImageCallback {
156     int32_t Decoded(VideoFrame& decodedImage) override { return 0; }
157     int32_t Decoded(
158         webrtc::VideoFrame& decodedImage, int64_t decode_time_ms) override {
159       RTC_NOTREACHED();
160       return -1;
161     }
162   } callback, callback2;
163 
164   VideoCodec codec = {};
165   fallback_wrapper_.InitDecode(&codec, 2);
166   fallback_wrapper_.RegisterDecodeCompleteCallback(&callback);
167   EXPECT_EQ(&callback, fake_decoder_.decode_complete_callback_);
168 
169   fake_decoder_.decode_return_code_ = WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
170   EncodedImage encoded_image;
171   fallback_wrapper_.Decode(encoded_image, false, nullptr, nullptr, -1);
172   fallback_wrapper_.RegisterDecodeCompleteCallback(&callback2);
173   EXPECT_EQ(&callback2, fake_decoder_.decode_complete_callback_);
174 }
175 
TEST_F(VideoDecoderSoftwareFallbackWrapperTest,ReportsFallbackImplementationName)176 TEST_F(VideoDecoderSoftwareFallbackWrapperTest,
177        ReportsFallbackImplementationName) {
178   VideoCodec codec = {};
179   fallback_wrapper_.InitDecode(&codec, 2);
180 
181   fake_decoder_.decode_return_code_ = WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
182   EncodedImage encoded_image;
183   fallback_wrapper_.Decode(encoded_image, false, nullptr, nullptr, -1);
184   // Hard coded expected value since libvpx is the software implementation name
185   // for VP8. Change accordingly if the underlying implementation does.
186   EXPECT_STREQ("libvpx (fallback from: fake-decoder)",
187                fallback_wrapper_.ImplementationName());
188   fallback_wrapper_.Release();
189 }
190 
191 }  // namespace webrtc
192