1 /*
2  * Copyright 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "CCodecConfig.h"
18 
19 #include <set>
20 
21 #include <gtest/gtest.h>
22 
23 #include <codec2/hidl/1.0/Configurable.h>
24 #include <codec2/hidl/client.h>
25 #include <util/C2InterfaceHelper.h>
26 
27 #include <media/stagefright/MediaCodecConstants.h>
28 
29 namespace {
30 
31 enum ExtendedC2ParamIndexKind : C2Param::type_index_t {
32     kParamIndexVendorInt32 = C2Param::TYPE_INDEX_VENDOR_START,
33     kParamIndexVendorInt64,
34     kParamIndexVendorString,
35 };
36 
37 typedef C2PortParam<C2Info, C2Int32Value, kParamIndexVendorInt32> C2PortVendorInt32Info;
38 constexpr char C2_PARAMKEY_VENDOR_INT32[] = "example.int32";
39 constexpr char KEY_VENDOR_INT32[] = "vendor.example.int32.value";
40 
41 typedef C2StreamParam<C2Info, C2Int64Value, kParamIndexVendorInt64> C2StreamVendorInt64Info;
42 constexpr char C2_PARAMKEY_VENDOR_INT64[] = "example.int64";
43 constexpr char KEY_VENDOR_INT64[] = "vendor.example.int64.value";
44 
45 typedef C2PortParam<C2Info, C2StringValue, kParamIndexVendorString> C2PortVendorStringInfo;
46 constexpr char C2_PARAMKEY_VENDOR_STRING[] = "example.string";
47 constexpr char KEY_VENDOR_STRING[] = "vendor.example.string.value";
48 
49 }  // namespace
50 
51 namespace android {
52 
53 class CCodecConfigTest : public ::testing::Test {
54 public:
55     constexpr static int32_t kCodec2Int32 = 0xC0DEC2;
56     constexpr static int64_t kCodec2Int64 = 0xC0DEC2C0DEC2ll;
57     constexpr static char kCodec2Str[] = "codec2";
58 
CCodecConfigTest()59     CCodecConfigTest()
60         : mReflector{std::make_shared<C2ReflectorHelper>()} {
61     }
62 
init(C2Component::domain_t domain,C2Component::kind_t kind,const char * mediaType)63     void init(
64             C2Component::domain_t domain,
65             C2Component::kind_t kind,
66             const char *mediaType) {
67         sp<hardware::media::c2::V1_0::utils::CachedConfigurable> cachedConfigurable =
68             new hardware::media::c2::V1_0::utils::CachedConfigurable(
69                     std::make_unique<Configurable>(mReflector, domain, kind, mediaType));
70         cachedConfigurable->init(std::make_shared<Cache>());
71         mConfigurable = std::make_shared<Codec2Client::Configurable>(cachedConfigurable);
72     }
73 
74     struct Cache : public hardware::media::c2::V1_0::utils::ParameterCache {
validateandroid::CCodecConfigTest::Cache75         c2_status_t validate(const std::vector<std::shared_ptr<C2ParamDescriptor>>&) override {
76             return C2_OK;
77         }
78     };
79 
80     class Configurable : public hardware::media::c2::V1_0::utils::ConfigurableC2Intf {
81     public:
Configurable(const std::shared_ptr<C2ReflectorHelper> & reflector,C2Component::domain_t domain,C2Component::kind_t kind,const char * mediaType)82         Configurable(
83                 const std::shared_ptr<C2ReflectorHelper> &reflector,
84                 C2Component::domain_t domain,
85                 C2Component::kind_t kind,
86                 const char *mediaType)
87             : ConfigurableC2Intf("name", 0u),
88               mImpl(reflector, domain, kind, mediaType) {
89         }
90 
query(const std::vector<C2Param::Index> & indices,c2_blocking_t mayBlock,std::vector<std::unique_ptr<C2Param>> * const params) const91         c2_status_t query(
92                 const std::vector<C2Param::Index> &indices,
93                 c2_blocking_t mayBlock,
94                 std::vector<std::unique_ptr<C2Param>>* const params) const override {
95             return mImpl.query({}, indices, mayBlock, params);
96         }
97 
config(const std::vector<C2Param * > & params,c2_blocking_t mayBlock,std::vector<std::unique_ptr<C2SettingResult>> * const failures)98         c2_status_t config(
99                 const std::vector<C2Param*> &params,
100                 c2_blocking_t mayBlock,
101                 std::vector<std::unique_ptr<C2SettingResult>>* const failures) override {
102             return mImpl.config(params, mayBlock, failures);
103         }
104 
querySupportedParams(std::vector<std::shared_ptr<C2ParamDescriptor>> * const params) const105         c2_status_t querySupportedParams(
106                 std::vector<std::shared_ptr<C2ParamDescriptor>>* const params) const override {
107             return mImpl.querySupportedParams(params);
108         }
109 
querySupportedValues(std::vector<C2FieldSupportedValuesQuery> & fields,c2_blocking_t mayBlock) const110         c2_status_t querySupportedValues(
111                 std::vector<C2FieldSupportedValuesQuery>& fields,
112                 c2_blocking_t mayBlock) const override {
113             return mImpl.querySupportedValues(fields, mayBlock);
114         }
115 
116     private:
117         class Impl : public C2InterfaceHelper {
118         public:
Impl(const std::shared_ptr<C2ReflectorHelper> & reflector,C2Component::domain_t domain,C2Component::kind_t kind,const char * mediaType)119             Impl(const std::shared_ptr<C2ReflectorHelper> &reflector,
120                     C2Component::domain_t domain,
121                     C2Component::kind_t kind,
122                     const char *mediaType)
123                 : C2InterfaceHelper{reflector} {
124 
125                 setDerivedInstance(this);
126 
127                 addParameter(
128                         DefineParam(mDomain, C2_PARAMKEY_COMPONENT_DOMAIN)
129                         .withConstValue(new C2ComponentDomainSetting(domain))
130                         .build());
131 
132                 addParameter(
133                         DefineParam(mKind, C2_PARAMKEY_COMPONENT_KIND)
134                         .withConstValue(new C2ComponentKindSetting(kind))
135                         .build());
136 
137                 addParameter(
138                         DefineParam(mInputStreamCount, C2_PARAMKEY_INPUT_STREAM_COUNT)
139                         .withConstValue(new C2PortStreamCountTuning::input(1))
140                         .build());
141 
142                 addParameter(
143                         DefineParam(mOutputStreamCount, C2_PARAMKEY_OUTPUT_STREAM_COUNT)
144                         .withConstValue(new C2PortStreamCountTuning::output(1))
145                         .build());
146 
147                 const char *rawMediaType = "";
148                 switch (domain) {
149                     case C2Component::DOMAIN_IMAGE: [[fallthrough]];
150                     case C2Component::DOMAIN_VIDEO:
151                         rawMediaType = MIMETYPE_VIDEO_RAW;
152                         break;
153                     case C2Component::DOMAIN_AUDIO:
154                         rawMediaType = MIMETYPE_AUDIO_RAW;
155                         break;
156                     default:
157                         break;
158                 }
159                 bool isEncoder = kind == C2Component::KIND_ENCODER;
160                 std::string inputMediaType{isEncoder ? rawMediaType : mediaType};
161                 std::string outputMediaType{isEncoder ? mediaType : rawMediaType};
162 
__anon8d80e32f0202(const auto &param, const std::string &str) 163                 auto allocSharedString = [](const auto &param, const std::string &str) {
164                     typedef typename std::remove_reference<decltype(param)>::type::element_type T;
165                     std::shared_ptr<T> ret = T::AllocShared(str.length() + 1);
166                     strcpy(ret->m.value, str.c_str());
167                     return ret;
168                 };
169 
170                 addParameter(
171                         DefineParam(mInputMediaType, C2_PARAMKEY_INPUT_MEDIA_TYPE)
172                         .withConstValue(allocSharedString(mInputMediaType, inputMediaType))
173                         .build());
174 
175                 addParameter(
176                         DefineParam(mOutputMediaType, C2_PARAMKEY_OUTPUT_MEDIA_TYPE)
177                         .withConstValue(allocSharedString(mOutputMediaType, outputMediaType))
178                         .build());
179 
180                 addParameter(
181                         DefineParam(mInt32Input, C2_PARAMKEY_VENDOR_INT32)
182                         .withDefault(new C2PortVendorInt32Info::input(0))
183                         .withFields({C2F(mInt32Input, value).any()})
184                         .withSetter(Setter<decltype(mInt32Input)::element_type>)
185                         .build());
186 
187                 addParameter(
188                         DefineParam(mInt64Output, C2_PARAMKEY_VENDOR_INT64)
189                         .withDefault(new C2StreamVendorInt64Info::output(0u, 0))
190                         .withFields({C2F(mInt64Output, value).any()})
191                         .withSetter(Setter<decltype(mInt64Output)::element_type>)
192                         .build());
193 
194                 addParameter(
195                         DefineParam(mStringInput, C2_PARAMKEY_VENDOR_STRING)
196                         .withDefault(decltype(mStringInput)::element_type::AllocShared(1, ""))
197                         .withFields({C2F(mStringInput, m.value).any()})
198                         .withSetter(Setter<decltype(mStringInput)::element_type>)
199                         .build());
200 
201                 addParameter(
202                         DefineParam(mPixelAspectRatio, C2_PARAMKEY_PIXEL_ASPECT_RATIO)
203                         .withDefault(new C2StreamPixelAspectRatioInfo::output(0u, 1, 1))
204                         .withFields({
205                             C2F(mPixelAspectRatio, width).any(),
206                             C2F(mPixelAspectRatio, height).any(),
207                         })
208                         .withSetter(Setter<C2StreamPixelAspectRatioInfo::output>)
209                         .build());
210 
211                 if (isEncoder) {
212                     addParameter(
213                             DefineParam(mInputBitrate, C2_PARAMKEY_BITRATE)
214                             .withDefault(new C2StreamBitrateInfo::input(0u))
215                             .withFields({C2F(mInputBitrate, value).any()})
216                             .withSetter(Setter<C2StreamBitrateInfo::input>)
217                             .build());
218 
219                     addParameter(
220                             DefineParam(mOutputBitrate, C2_PARAMKEY_BITRATE)
221                             .withDefault(new C2StreamBitrateInfo::output(0u))
222                             .withFields({C2F(mOutputBitrate, value).any()})
223                             .calculatedAs(
224                                 Copy<C2StreamBitrateInfo::output, C2StreamBitrateInfo::input>,
225                                 mInputBitrate)
226                             .build());
227                 }
228 
229                 // TODO: more SDK params
230             }
231         private:
232             std::shared_ptr<C2ComponentDomainSetting> mDomain;
233             std::shared_ptr<C2ComponentKindSetting> mKind;
234             std::shared_ptr<C2PortStreamCountTuning::input> mInputStreamCount;
235             std::shared_ptr<C2PortStreamCountTuning::output> mOutputStreamCount;
236             std::shared_ptr<C2PortMediaTypeSetting::input> mInputMediaType;
237             std::shared_ptr<C2PortMediaTypeSetting::output> mOutputMediaType;
238             std::shared_ptr<C2PortVendorInt32Info::input> mInt32Input;
239             std::shared_ptr<C2StreamVendorInt64Info::output> mInt64Output;
240             std::shared_ptr<C2PortVendorStringInfo::input> mStringInput;
241             std::shared_ptr<C2StreamPixelAspectRatioInfo::output> mPixelAspectRatio;
242             std::shared_ptr<C2StreamBitrateInfo::input> mInputBitrate;
243             std::shared_ptr<C2StreamBitrateInfo::output> mOutputBitrate;
244 
245             template<typename T>
Setter(bool,C2P<T> &)246             static C2R Setter(bool, C2P<T> &) {
247                 return C2R::Ok();
248             }
249 
250             template<typename ME, typename DEP>
Copy(bool,C2P<ME> & me,const C2P<DEP> & dep)251             static C2R Copy(bool, C2P<ME> &me, const C2P<DEP> &dep) {
252                 me.set().value = dep.v.value;
253                 return C2R::Ok();
254             }
255         };
256 
257         Impl mImpl;
258     };
259 
260     std::shared_ptr<C2ReflectorHelper> mReflector;
261     std::shared_ptr<Codec2Client::Configurable> mConfigurable;
262     CCodecConfig mConfig;
263 };
264 
265 using D = CCodecConfig::Domain;
266 
267 template<typename T>
FindParam(const std::vector<std::unique_ptr<C2Param>> & vec)268 T *FindParam(const std::vector<std::unique_ptr<C2Param>> &vec) {
269     for (const std::unique_ptr<C2Param> &param : vec) {
270         if (param->coreIndex() == T::CORE_INDEX) {
271             return static_cast<T *>(param.get());
272         }
273     }
274     return nullptr;
275 }
276 
TEST_F(CCodecConfigTest,SetVendorParam)277 TEST_F(CCodecConfigTest, SetVendorParam) {
278     // Test at audio domain, as video domain has a few local parameters that
279     // interfere with the testing.
280     init(C2Component::DOMAIN_AUDIO, C2Component::KIND_DECODER, MIMETYPE_AUDIO_AAC);
281 
282     ASSERT_EQ(OK, mConfig.initialize(mReflector, mConfigurable));
283 
284     sp<AMessage> format{new AMessage};
285     format->setInt32(KEY_VENDOR_INT32, kCodec2Int32);
286     format->setInt64(KEY_VENDOR_INT64, kCodec2Int64);
287     format->setString(KEY_VENDOR_STRING, kCodec2Str);
288 
289     std::vector<std::unique_ptr<C2Param>> configUpdate;
290     ASSERT_EQ(OK, mConfig.getConfigUpdateFromSdkParams(
291             mConfigurable, format, D::ALL, C2_MAY_BLOCK, &configUpdate));
292 
293     ASSERT_EQ(3u, configUpdate.size());
294     C2PortVendorInt32Info::input *i32 =
295         FindParam<std::remove_pointer<decltype(i32)>::type>(configUpdate);
296     ASSERT_NE(nullptr, i32);
297     ASSERT_EQ(kCodec2Int32, i32->value);
298 
299     C2StreamVendorInt64Info::output *i64 =
300         FindParam<std::remove_pointer<decltype(i64)>::type>(configUpdate);
301     ASSERT_NE(nullptr, i64);
302     ASSERT_EQ(kCodec2Int64, i64->value);
303 
304     C2PortVendorStringInfo::input *str =
305         FindParam<std::remove_pointer<decltype(str)>::type>(configUpdate);
306     ASSERT_NE(nullptr, str);
307     ASSERT_STREQ(kCodec2Str, str->m.value);
308 }
309 
TEST_F(CCodecConfigTest,VendorParamUpdate_Unsubscribed)310 TEST_F(CCodecConfigTest, VendorParamUpdate_Unsubscribed) {
311     // Test at audio domain, as video domain has a few local parameters that
312     // interfere with the testing.
313     init(C2Component::DOMAIN_AUDIO, C2Component::KIND_DECODER, MIMETYPE_AUDIO_AAC);
314 
315     ASSERT_EQ(OK, mConfig.initialize(mReflector, mConfigurable));
316 
317     std::vector<std::unique_ptr<C2Param>> configUpdate;
318     C2PortVendorInt32Info::input i32(kCodec2Int32);
319     C2StreamVendorInt64Info::output i64(0u, kCodec2Int64);
320     std::unique_ptr<C2PortVendorStringInfo::input> str =
321         C2PortVendorStringInfo::input::AllocUnique(strlen(kCodec2Str) + 1, kCodec2Str);
322     configUpdate.push_back(C2Param::Copy(i32));
323     configUpdate.push_back(C2Param::Copy(i64));
324     configUpdate.push_back(std::move(str));
325 
326     // The vendor parameters are not yet subscribed
327     ASSERT_FALSE(mConfig.updateConfiguration(configUpdate, D::ALL));
328 
329     int32_t vendorInt32{0};
330     ASSERT_FALSE(mConfig.mInputFormat->findInt32(KEY_VENDOR_INT32, &vendorInt32))
331             << "mInputFormat = " << mConfig.mInputFormat->debugString().c_str();
332     ASSERT_FALSE(mConfig.mOutputFormat->findInt32(KEY_VENDOR_INT32, &vendorInt32))
333             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
334 
335     int64_t vendorInt64{0};
336     ASSERT_FALSE(mConfig.mInputFormat->findInt64(KEY_VENDOR_INT64, &vendorInt64))
337             << "mInputFormat = " << mConfig.mInputFormat->debugString().c_str();
338     ASSERT_FALSE(mConfig.mOutputFormat->findInt64(KEY_VENDOR_INT64, &vendorInt64))
339             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
340 
341     AString vendorString;
342     ASSERT_FALSE(mConfig.mInputFormat->findString(KEY_VENDOR_STRING, &vendorString))
343             << "mInputFormat = " << mConfig.mInputFormat->debugString().c_str();
344     ASSERT_FALSE(mConfig.mOutputFormat->findString(KEY_VENDOR_STRING, &vendorString))
345             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
346 }
347 
TEST_F(CCodecConfigTest,VendorParamUpdate_AllSubscribed)348 TEST_F(CCodecConfigTest, VendorParamUpdate_AllSubscribed) {
349     // Test at audio domain, as video domain has a few local parameters that
350     // interfere with the testing.
351     init(C2Component::DOMAIN_AUDIO, C2Component::KIND_DECODER, MIMETYPE_AUDIO_AAC);
352 
353     ASSERT_EQ(OK, mConfig.initialize(mReflector, mConfigurable));
354 
355     // Force subscribe to all vendor params
356     ASSERT_EQ(OK, mConfig.subscribeToAllVendorParams(mConfigurable, C2_MAY_BLOCK));
357 
358     std::vector<std::unique_ptr<C2Param>> configUpdate;
359     C2PortVendorInt32Info::input i32(kCodec2Int32);
360     C2StreamVendorInt64Info::output i64(0u, kCodec2Int64);
361     std::unique_ptr<C2PortVendorStringInfo::input> str =
362         C2PortVendorStringInfo::input::AllocUnique(strlen(kCodec2Str) + 1, kCodec2Str);
363     configUpdate.push_back(C2Param::Copy(i32));
364     configUpdate.push_back(C2Param::Copy(i64));
365     configUpdate.push_back(std::move(str));
366 
367     ASSERT_TRUE(mConfig.updateConfiguration(configUpdate, D::ALL));
368 
369     int32_t vendorInt32{0};
370     ASSERT_TRUE(mConfig.mInputFormat->findInt32(KEY_VENDOR_INT32, &vendorInt32))
371             << "mInputFormat = " << mConfig.mInputFormat->debugString().c_str();
372     ASSERT_EQ(kCodec2Int32, vendorInt32);
373     ASSERT_FALSE(mConfig.mOutputFormat->findInt32(KEY_VENDOR_INT32, &vendorInt32))
374             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
375 
376     int64_t vendorInt64{0};
377     ASSERT_FALSE(mConfig.mInputFormat->findInt64(KEY_VENDOR_INT64, &vendorInt64))
378             << "mInputFormat = " << mConfig.mInputFormat->debugString().c_str();
379     ASSERT_TRUE(mConfig.mOutputFormat->findInt64(KEY_VENDOR_INT64, &vendorInt64))
380             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
381     ASSERT_EQ(kCodec2Int64, vendorInt64);
382 
383     AString vendorString;
384     ASSERT_TRUE(mConfig.mInputFormat->findString(KEY_VENDOR_STRING, &vendorString))
385             << "mInputFormat = " << mConfig.mInputFormat->debugString().c_str();
386     ASSERT_STREQ(kCodec2Str, vendorString.c_str());
387     ASSERT_FALSE(mConfig.mOutputFormat->findString(KEY_VENDOR_STRING, &vendorString))
388             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
389 }
390 
TEST_F(CCodecConfigTest,VendorParamUpdate_PartiallySubscribed)391 TEST_F(CCodecConfigTest, VendorParamUpdate_PartiallySubscribed) {
392     // Test at audio domain, as video domain has a few local parameters that
393     // interfere with the testing.
394     init(C2Component::DOMAIN_AUDIO, C2Component::KIND_DECODER, MIMETYPE_AUDIO_AAC);
395 
396     ASSERT_EQ(OK, mConfig.initialize(mReflector, mConfigurable));
397 
398     // Subscribe to example.int32 only
399     std::vector<std::unique_ptr<C2Param>> configUpdate;
400     sp<AMessage> format{new AMessage};
401     format->setInt32(KEY_VENDOR_INT32, 0);
402     configUpdate.clear();
403     ASSERT_EQ(OK, mConfig.getConfigUpdateFromSdkParams(
404             mConfigurable, format, D::ALL, C2_MAY_BLOCK, &configUpdate));
405     ASSERT_EQ(OK, mConfig.setParameters(mConfigurable, configUpdate, C2_MAY_BLOCK));
406 
407     C2PortVendorInt32Info::input i32(kCodec2Int32);
408     C2StreamVendorInt64Info::output i64(0u, kCodec2Int64);
409     std::unique_ptr<C2PortVendorStringInfo::input> str =
410         C2PortVendorStringInfo::input::AllocUnique(strlen(kCodec2Str) + 1, kCodec2Str);
411     configUpdate.clear();
412     configUpdate.push_back(C2Param::Copy(i32));
413     configUpdate.push_back(C2Param::Copy(i64));
414     configUpdate.push_back(std::move(str));
415 
416     // Only example.i32 should be updated
417     ASSERT_TRUE(mConfig.updateConfiguration(configUpdate, D::ALL));
418 
419     int32_t vendorInt32{0};
420     ASSERT_TRUE(mConfig.mInputFormat->findInt32(KEY_VENDOR_INT32, &vendorInt32))
421             << "mInputFormat = " << mConfig.mInputFormat->debugString().c_str();
422     ASSERT_EQ(kCodec2Int32, vendorInt32);
423     ASSERT_FALSE(mConfig.mOutputFormat->findInt32(KEY_VENDOR_INT32, &vendorInt32))
424             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
425 
426     int64_t vendorInt64{0};
427     ASSERT_FALSE(mConfig.mInputFormat->findInt64(KEY_VENDOR_INT64, &vendorInt64))
428             << "mInputFormat = " << mConfig.mInputFormat->debugString().c_str();
429     ASSERT_FALSE(mConfig.mOutputFormat->findInt64(KEY_VENDOR_INT64, &vendorInt64))
430             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
431 
432     AString vendorString;
433     ASSERT_FALSE(mConfig.mInputFormat->findString(KEY_VENDOR_STRING, &vendorString))
434             << "mInputFormat = " << mConfig.mInputFormat->debugString().c_str();
435     ASSERT_FALSE(mConfig.mOutputFormat->findString(KEY_VENDOR_STRING, &vendorString))
436             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
437 }
438 
TEST_F(CCodecConfigTest,SetPixelAspectRatio)439 TEST_F(CCodecConfigTest, SetPixelAspectRatio) {
440     init(C2Component::DOMAIN_VIDEO, C2Component::KIND_DECODER, MIMETYPE_VIDEO_AVC);
441 
442     ASSERT_EQ(OK, mConfig.initialize(mReflector, mConfigurable));
443 
444     sp<AMessage> format{new AMessage};
445     format->setInt32(KEY_PIXEL_ASPECT_RATIO_WIDTH, 12);
446     format->setInt32(KEY_PIXEL_ASPECT_RATIO_HEIGHT, 11);
447 
448     std::vector<std::unique_ptr<C2Param>> configUpdate;
449     ASSERT_EQ(OK, mConfig.getConfigUpdateFromSdkParams(
450             mConfigurable, format, D::ALL, C2_MAY_BLOCK, &configUpdate));
451 
452     ASSERT_EQ(1u, configUpdate.size());
453     C2StreamPixelAspectRatioInfo::output *par =
454         FindParam<std::remove_pointer<decltype(par)>::type>(configUpdate);
455     ASSERT_NE(nullptr, par);
456     ASSERT_EQ(12, par->width);
457     ASSERT_EQ(11, par->height);
458 }
459 
TEST_F(CCodecConfigTest,PixelAspectRatioUpdate)460 TEST_F(CCodecConfigTest, PixelAspectRatioUpdate) {
461     init(C2Component::DOMAIN_VIDEO, C2Component::KIND_DECODER, MIMETYPE_VIDEO_AVC);
462 
463     ASSERT_EQ(OK, mConfig.initialize(mReflector, mConfigurable));
464 
465     std::vector<std::unique_ptr<C2Param>> configUpdate;
466     C2StreamPixelAspectRatioInfo::output par(0u, 12, 11);
467     configUpdate.push_back(C2Param::Copy(par));
468 
469     ASSERT_TRUE(mConfig.updateConfiguration(configUpdate, D::ALL));
470 
471     int32_t parWidth{0};
472     ASSERT_TRUE(mConfig.mOutputFormat->findInt32(KEY_PIXEL_ASPECT_RATIO_WIDTH, &parWidth))
473             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
474     ASSERT_EQ(12, parWidth);
475     ASSERT_FALSE(mConfig.mInputFormat->findInt32(KEY_PIXEL_ASPECT_RATIO_WIDTH, &parWidth))
476             << "mInputFormat = " << mConfig.mInputFormat->debugString().c_str();
477 
478     int32_t parHeight{0};
479     ASSERT_TRUE(mConfig.mOutputFormat->findInt32(KEY_PIXEL_ASPECT_RATIO_HEIGHT, &parHeight))
480             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
481     ASSERT_EQ(11, parHeight);
482     ASSERT_FALSE(mConfig.mInputFormat->findInt32(KEY_PIXEL_ASPECT_RATIO_HEIGHT, &parHeight))
483             << "mInputFormat = " << mConfig.mInputFormat->debugString().c_str();
484 }
485 
TEST_F(CCodecConfigTest,DataspaceUpdate)486 TEST_F(CCodecConfigTest, DataspaceUpdate) {
487     init(C2Component::DOMAIN_VIDEO, C2Component::KIND_ENCODER, MIMETYPE_VIDEO_AVC);
488 
489     ASSERT_EQ(OK, mConfig.initialize(mReflector, mConfigurable));
490     class InputSurfaceStub : public InputSurfaceWrapper {
491     public:
492         ~InputSurfaceStub() override = default;
493         status_t connect(const std::shared_ptr<Codec2Client::Component> &) override {
494             return OK;
495         }
496         void disconnect() override {}
497         status_t start() override { return OK; }
498         status_t signalEndOfInputStream() override { return OK; }
499         status_t configure(Config &) override { return OK; }
500     };
501     mConfig.mInputSurface = std::make_shared<InputSurfaceStub>();
502 
503     sp<AMessage> format{new AMessage};
504     format->setInt32(KEY_COLOR_RANGE, COLOR_RANGE_LIMITED);
505     format->setInt32(KEY_COLOR_STANDARD, COLOR_STANDARD_BT709);
506     format->setInt32(KEY_COLOR_TRANSFER, COLOR_TRANSFER_SDR_VIDEO);
507     format->setInt32(KEY_BIT_RATE, 100);
508 
509     std::vector<std::unique_ptr<C2Param>> configUpdate;
510     ASSERT_EQ(OK, mConfig.getConfigUpdateFromSdkParams(
511             mConfigurable, format, D::ALL, C2_MAY_BLOCK, &configUpdate));
512     ASSERT_TRUE(mConfig.updateConfiguration(configUpdate, D::ALL));
513 
514     int32_t range{0};
515     ASSERT_TRUE(mConfig.mOutputFormat->findInt32(KEY_COLOR_RANGE, &range))
516             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
517     EXPECT_EQ(COLOR_RANGE_LIMITED, range)
518             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
519 
520     int32_t standard{0};
521     ASSERT_TRUE(mConfig.mOutputFormat->findInt32(KEY_COLOR_STANDARD, &standard))
522             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
523     EXPECT_EQ(COLOR_STANDARD_BT709, standard)
524             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
525 
526     int32_t transfer{0};
527     ASSERT_TRUE(mConfig.mOutputFormat->findInt32(KEY_COLOR_TRANSFER, &transfer))
528             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
529     EXPECT_EQ(COLOR_TRANSFER_SDR_VIDEO, transfer)
530             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
531 
532     mConfig.mInputSurface->setDataSpace(HAL_DATASPACE_BT2020_PQ);
533 
534     // Dataspace from input surface should override the configured setting
535     mConfig.updateFormats(D::ALL);
536 
537     ASSERT_TRUE(mConfig.mOutputFormat->findInt32(KEY_COLOR_RANGE, &range))
538             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
539     EXPECT_EQ(COLOR_RANGE_FULL, range)
540             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
541 
542     ASSERT_TRUE(mConfig.mOutputFormat->findInt32(KEY_COLOR_STANDARD, &standard))
543             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
544     EXPECT_EQ(COLOR_STANDARD_BT2020, standard)
545             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
546 
547     ASSERT_TRUE(mConfig.mOutputFormat->findInt32(KEY_COLOR_TRANSFER, &transfer))
548             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
549     EXPECT_EQ(COLOR_TRANSFER_ST2084, transfer)
550             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
551 
552     // Simulate bitrate update
553     format = new AMessage;
554     format->setInt32(KEY_BIT_RATE, 200);
555     configUpdate.clear();
556     ASSERT_EQ(OK, mConfig.getConfigUpdateFromSdkParams(
557             mConfigurable, format, D::ALL, C2_MAY_BLOCK, &configUpdate));
558     ASSERT_EQ(OK, mConfig.setParameters(mConfigurable, configUpdate, C2_MAY_BLOCK));
559 
560     // Color information should remain the same
561     mConfig.updateFormats(D::ALL);
562 
563     ASSERT_TRUE(mConfig.mOutputFormat->findInt32(KEY_COLOR_RANGE, &range))
564             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
565     EXPECT_EQ(COLOR_RANGE_FULL, range)
566             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
567 
568     ASSERT_TRUE(mConfig.mOutputFormat->findInt32(KEY_COLOR_STANDARD, &standard))
569             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
570     EXPECT_EQ(COLOR_STANDARD_BT2020, standard)
571             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
572 
573     ASSERT_TRUE(mConfig.mOutputFormat->findInt32(KEY_COLOR_TRANSFER, &transfer))
574             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
575     EXPECT_EQ(COLOR_TRANSFER_ST2084, transfer)
576             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
577 }
578 
579 } // namespace android
580