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 <android_media_codec.h>
24 
25 #include <codec2/hidl/1.0/Configurable.h>
26 #include <codec2/hidl/client.h>
27 #include <util/C2InterfaceHelper.h>
28 
29 #include <media/stagefright/MediaCodecConstants.h>
30 
31 namespace {
32 
33 enum ExtendedC2ParamIndexKind : C2Param::type_index_t {
34     kParamIndexVendorInt32 = C2Param::TYPE_INDEX_VENDOR_START,
35     kParamIndexVendorInt64,
36     kParamIndexVendorString,
37 };
38 
39 typedef C2PortParam<C2Info, C2Int32Value, kParamIndexVendorInt32> C2PortVendorInt32Info;
40 constexpr char C2_PARAMKEY_VENDOR_INT32[] = "example.int32";
41 constexpr char KEY_VENDOR_INT32[] = "vendor.example.int32.value";
42 
43 typedef C2StreamParam<C2Info, C2Int64Value, kParamIndexVendorInt64> C2StreamVendorInt64Info;
44 constexpr char C2_PARAMKEY_VENDOR_INT64[] = "example.int64";
45 constexpr char KEY_VENDOR_INT64[] = "vendor.example.int64.value";
46 
47 typedef C2PortParam<C2Info, C2StringValue, kParamIndexVendorString> C2PortVendorStringInfo;
48 constexpr char C2_PARAMKEY_VENDOR_STRING[] = "example.string";
49 constexpr char KEY_VENDOR_STRING[] = "vendor.example.string.value";
50 
51 }  // namespace
52 
53 namespace android {
54 
55 class CCodecConfigTest : public ::testing::Test {
56 public:
57     constexpr static int32_t kCodec2Int32 = 0xC0DEC2;
58     constexpr static int64_t kCodec2Int64 = 0xC0DEC2C0DEC2ll;
59     constexpr static char kCodec2Str[] = "codec2";
60 
CCodecConfigTest()61     CCodecConfigTest()
62         : mReflector{std::make_shared<C2ReflectorHelper>()} {
63     }
64 
init(C2Component::domain_t domain,C2Component::kind_t kind,const char * mediaType)65     void init(
66             C2Component::domain_t domain,
67             C2Component::kind_t kind,
68             const char *mediaType) {
69         sp<hardware::media::c2::V1_0::utils::CachedConfigurable> cachedConfigurable =
70             new hardware::media::c2::V1_0::utils::CachedConfigurable(
71                     std::make_unique<Configurable>(mReflector, domain, kind, mediaType));
72         cachedConfigurable->init(std::make_shared<Cache>());
73         mConfigurable = std::make_shared<Codec2Client::Configurable>(cachedConfigurable);
74     }
75 
76     struct Cache : public hardware::media::c2::V1_0::utils::ParameterCache {
validateandroid::CCodecConfigTest::Cache77         c2_status_t validate(const std::vector<std::shared_ptr<C2ParamDescriptor>>&) override {
78             return C2_OK;
79         }
80     };
81 
82     class Configurable : public hardware::media::c2::V1_0::utils::ConfigurableC2Intf {
83     public:
Configurable(const std::shared_ptr<C2ReflectorHelper> & reflector,C2Component::domain_t domain,C2Component::kind_t kind,const char * mediaType)84         Configurable(
85                 const std::shared_ptr<C2ReflectorHelper> &reflector,
86                 C2Component::domain_t domain,
87                 C2Component::kind_t kind,
88                 const char *mediaType)
89             : ConfigurableC2Intf("name", 0u),
90               mImpl(reflector, domain, kind, mediaType) {
91         }
92 
query(const std::vector<C2Param::Index> & indices,c2_blocking_t mayBlock,std::vector<std::unique_ptr<C2Param>> * const params) const93         c2_status_t query(
94                 const std::vector<C2Param::Index> &indices,
95                 c2_blocking_t mayBlock,
96                 std::vector<std::unique_ptr<C2Param>>* const params) const override {
97             return mImpl.query({}, indices, mayBlock, params);
98         }
99 
config(const std::vector<C2Param * > & params,c2_blocking_t mayBlock,std::vector<std::unique_ptr<C2SettingResult>> * const failures)100         c2_status_t config(
101                 const std::vector<C2Param*> &params,
102                 c2_blocking_t mayBlock,
103                 std::vector<std::unique_ptr<C2SettingResult>>* const failures) override {
104             return mImpl.config(params, mayBlock, failures);
105         }
106 
querySupportedParams(std::vector<std::shared_ptr<C2ParamDescriptor>> * const params) const107         c2_status_t querySupportedParams(
108                 std::vector<std::shared_ptr<C2ParamDescriptor>>* const params) const override {
109             return mImpl.querySupportedParams(params);
110         }
111 
querySupportedValues(std::vector<C2FieldSupportedValuesQuery> & fields,c2_blocking_t mayBlock) const112         c2_status_t querySupportedValues(
113                 std::vector<C2FieldSupportedValuesQuery>& fields,
114                 c2_blocking_t mayBlock) const override {
115             return mImpl.querySupportedValues(fields, mayBlock);
116         }
117 
118     private:
119         class Impl : public C2InterfaceHelper {
120         public:
Impl(const std::shared_ptr<C2ReflectorHelper> & reflector,C2Component::domain_t domain,C2Component::kind_t kind,const char * mediaType)121             Impl(const std::shared_ptr<C2ReflectorHelper> &reflector,
122                     C2Component::domain_t domain,
123                     C2Component::kind_t kind,
124                     const char *mediaType)
125                 : C2InterfaceHelper{reflector} {
126 
127                 setDerivedInstance(this);
128 
129                 addParameter(
130                         DefineParam(mDomain, C2_PARAMKEY_COMPONENT_DOMAIN)
131                         .withConstValue(new C2ComponentDomainSetting(domain))
132                         .build());
133 
134                 addParameter(
135                         DefineParam(mKind, C2_PARAMKEY_COMPONENT_KIND)
136                         .withConstValue(new C2ComponentKindSetting(kind))
137                         .build());
138 
139                 addParameter(
140                         DefineParam(mInputStreamCount, C2_PARAMKEY_INPUT_STREAM_COUNT)
141                         .withConstValue(new C2PortStreamCountTuning::input(1))
142                         .build());
143 
144                 addParameter(
145                         DefineParam(mOutputStreamCount, C2_PARAMKEY_OUTPUT_STREAM_COUNT)
146                         .withConstValue(new C2PortStreamCountTuning::output(1))
147                         .build());
148 
149                 const char *rawMediaType = "";
150                 switch (domain) {
151                     case C2Component::DOMAIN_IMAGE: [[fallthrough]];
152                     case C2Component::DOMAIN_VIDEO:
153                         rawMediaType = MIMETYPE_VIDEO_RAW;
154                         break;
155                     case C2Component::DOMAIN_AUDIO:
156                         rawMediaType = MIMETYPE_AUDIO_RAW;
157                         break;
158                     default:
159                         break;
160                 }
161                 bool isEncoder = kind == C2Component::KIND_ENCODER;
162                 std::string inputMediaType{isEncoder ? rawMediaType : mediaType};
163                 std::string outputMediaType{isEncoder ? mediaType : rawMediaType};
164 
__anon38026ec30202(const auto &param, const std::string &str) 165                 auto allocSharedString = [](const auto &param, const std::string &str) {
166                     typedef typename std::remove_reference<decltype(param)>::type::element_type T;
167                     std::shared_ptr<T> ret = T::AllocShared(str.length() + 1);
168                     strcpy(ret->m.value, str.c_str());
169                     return ret;
170                 };
171 
172                 addParameter(
173                         DefineParam(mInputMediaType, C2_PARAMKEY_INPUT_MEDIA_TYPE)
174                         .withConstValue(allocSharedString(mInputMediaType, inputMediaType))
175                         .build());
176 
177                 addParameter(
178                         DefineParam(mOutputMediaType, C2_PARAMKEY_OUTPUT_MEDIA_TYPE)
179                         .withConstValue(allocSharedString(mOutputMediaType, outputMediaType))
180                         .build());
181 
182                 addParameter(
183                         DefineParam(mInt32Input, C2_PARAMKEY_VENDOR_INT32)
184                         .withDefault(new C2PortVendorInt32Info::input(0))
185                         .withFields({C2F(mInt32Input, value).any()})
186                         .withSetter(Setter<decltype(mInt32Input)::element_type>)
187                         .build());
188 
189                 addParameter(
190                         DefineParam(mInt64Output, C2_PARAMKEY_VENDOR_INT64)
191                         .withDefault(new C2StreamVendorInt64Info::output(0u, 0))
192                         .withFields({C2F(mInt64Output, value).any()})
193                         .withSetter(Setter<decltype(mInt64Output)::element_type>)
194                         .build());
195 
196                 addParameter(
197                         DefineParam(mStringInput, C2_PARAMKEY_VENDOR_STRING)
198                         .withDefault(decltype(mStringInput)::element_type::AllocShared(1, ""))
199                         .withFields({C2F(mStringInput, m.value).any()})
200                         .withSetter(Setter<decltype(mStringInput)::element_type>)
201                         .build());
202 
203                 addParameter(
204                         DefineParam(mPixelAspectRatio, C2_PARAMKEY_PIXEL_ASPECT_RATIO)
205                         .withDefault(new C2StreamPixelAspectRatioInfo::output(0u, 1, 1))
206                         .withFields({
207                             C2F(mPixelAspectRatio, width).any(),
208                             C2F(mPixelAspectRatio, height).any(),
209                         })
210                         .withSetter(Setter<C2StreamPixelAspectRatioInfo::output>)
211                         .build());
212 
213                 if (isEncoder) {
214                     addParameter(
215                             DefineParam(mInputBitrate, C2_PARAMKEY_BITRATE)
216                             .withDefault(new C2StreamBitrateInfo::input(0u))
217                             .withFields({C2F(mInputBitrate, value).any()})
218                             .withSetter(Setter<C2StreamBitrateInfo::input>)
219                             .build());
220 
221                     addParameter(
222                             DefineParam(mOutputBitrate, C2_PARAMKEY_BITRATE)
223                             .withDefault(new C2StreamBitrateInfo::output(0u))
224                             .withFields({C2F(mOutputBitrate, value).any()})
225                             .calculatedAs(
226                                 Copy<C2StreamBitrateInfo::output, C2StreamBitrateInfo::input>,
227                                 mInputBitrate)
228                             .build());
229 
230                     addParameter(
231                             DefineParam(mOutputProfileLevel, C2_PARAMKEY_PROFILE_LEVEL)
232                             .withDefault(new C2StreamProfileLevelInfo::output(
233                                     0u, PROFILE_UNUSED, LEVEL_UNUSED))
234                             .withFields({
235                                 C2F(mOutputProfileLevel, profile).any(),
236                                 C2F(mOutputProfileLevel, level).any(),
237                             })
238                             .withSetter(Setter<C2StreamProfileLevelInfo::output>)
239                             .build());
240 
241                     std::vector<C2QpOffsetRectStruct> c2QpOffsetRectsInfo;
242                     addParameter(
243                             DefineParam(mInputQpOffsetRects, C2_PARAMKEY_QP_OFFSET_RECTS)
244                                     .withDefault(C2StreamQpOffsetRects::output::AllocShared(
245                                             c2QpOffsetRectsInfo.size(), 0, c2QpOffsetRectsInfo))
246                                     .withFields({
247                                             C2F(mInputQpOffsetRects, m.values[0].qpOffset)
248                                                     .inRange(-128, 127),
249                                             C2F(mInputQpOffsetRects, m.values[0].left).any(),
250                                             C2F(mInputQpOffsetRects, m.values[0].top).any(),
251                                             C2F(mInputQpOffsetRects, m.values[0].width).any(),
252                                             C2F(mInputQpOffsetRects, m.values[0].height).any(),
253                                     })
254                                     .withSetter(Setter<C2StreamQpOffsetRects::output>)
255                                     .build());
256                 }
257 
258                 // TODO: more SDK params
259             }
260         private:
261             std::shared_ptr<C2ComponentDomainSetting> mDomain;
262             std::shared_ptr<C2ComponentKindSetting> mKind;
263             std::shared_ptr<C2PortStreamCountTuning::input> mInputStreamCount;
264             std::shared_ptr<C2PortStreamCountTuning::output> mOutputStreamCount;
265             std::shared_ptr<C2PortMediaTypeSetting::input> mInputMediaType;
266             std::shared_ptr<C2PortMediaTypeSetting::output> mOutputMediaType;
267             std::shared_ptr<C2PortVendorInt32Info::input> mInt32Input;
268             std::shared_ptr<C2StreamVendorInt64Info::output> mInt64Output;
269             std::shared_ptr<C2PortVendorStringInfo::input> mStringInput;
270             std::shared_ptr<C2StreamPixelAspectRatioInfo::output> mPixelAspectRatio;
271             std::shared_ptr<C2StreamBitrateInfo::input> mInputBitrate;
272             std::shared_ptr<C2StreamBitrateInfo::output> mOutputBitrate;
273             std::shared_ptr<C2StreamProfileLevelInfo::input> mInputProfileLevel;
274             std::shared_ptr<C2StreamProfileLevelInfo::output> mOutputProfileLevel;
275             std::shared_ptr<C2StreamQpOffsetRects::output> mInputQpOffsetRects;
276 
277             template<typename T>
Setter(bool,C2P<T> &)278             static C2R Setter(bool, C2P<T> &) {
279                 return C2R::Ok();
280             }
281 
282             template<typename ME, typename DEP>
Copy(bool,C2P<ME> & me,const C2P<DEP> & dep)283             static C2R Copy(bool, C2P<ME> &me, const C2P<DEP> &dep) {
284                 me.set().value = dep.v.value;
285                 return C2R::Ok();
286             }
287         };
288 
289         Impl mImpl;
290     };
291 
292     std::shared_ptr<C2ReflectorHelper> mReflector;
293     std::shared_ptr<Codec2Client::Configurable> mConfigurable;
294     CCodecConfig mConfig;
295 };
296 
297 using D = CCodecConfig::Domain;
298 
299 template<typename T>
FindParam(const std::vector<std::unique_ptr<C2Param>> & vec)300 T *FindParam(const std::vector<std::unique_ptr<C2Param>> &vec) {
301     for (const std::unique_ptr<C2Param> &param : vec) {
302         if (param->coreIndex() == T::CORE_INDEX) {
303             return static_cast<T *>(param.get());
304         }
305     }
306     return nullptr;
307 }
308 
TEST_F(CCodecConfigTest,SetVendorParam)309 TEST_F(CCodecConfigTest, SetVendorParam) {
310     // Test at audio domain, as video domain has a few local parameters that
311     // interfere with the testing.
312     init(C2Component::DOMAIN_AUDIO, C2Component::KIND_DECODER, MIMETYPE_AUDIO_AAC);
313 
314     ASSERT_EQ(OK, mConfig.initialize(mReflector, mConfigurable));
315 
316     sp<AMessage> format{new AMessage};
317     format->setInt32(KEY_VENDOR_INT32, kCodec2Int32);
318     format->setInt64(KEY_VENDOR_INT64, kCodec2Int64);
319     format->setString(KEY_VENDOR_STRING, kCodec2Str);
320 
321     std::vector<std::unique_ptr<C2Param>> configUpdate;
322     ASSERT_EQ(OK, mConfig.getConfigUpdateFromSdkParams(
323             mConfigurable, format, D::ALL, C2_MAY_BLOCK, &configUpdate));
324 
325     ASSERT_EQ(3u, configUpdate.size());
326     C2PortVendorInt32Info::input *i32 =
327         FindParam<std::remove_pointer<decltype(i32)>::type>(configUpdate);
328     ASSERT_NE(nullptr, i32);
329     ASSERT_EQ(kCodec2Int32, i32->value);
330 
331     C2StreamVendorInt64Info::output *i64 =
332         FindParam<std::remove_pointer<decltype(i64)>::type>(configUpdate);
333     ASSERT_NE(nullptr, i64);
334     ASSERT_EQ(kCodec2Int64, i64->value);
335 
336     C2PortVendorStringInfo::input *str =
337         FindParam<std::remove_pointer<decltype(str)>::type>(configUpdate);
338     ASSERT_NE(nullptr, str);
339     ASSERT_STREQ(kCodec2Str, str->m.value);
340 }
341 
TEST_F(CCodecConfigTest,VendorParamUpdate_Unsubscribed)342 TEST_F(CCodecConfigTest, VendorParamUpdate_Unsubscribed) {
343     // Test at audio domain, as video domain has a few local parameters that
344     // interfere with the testing.
345     init(C2Component::DOMAIN_AUDIO, C2Component::KIND_DECODER, MIMETYPE_AUDIO_AAC);
346 
347     ASSERT_EQ(OK, mConfig.initialize(mReflector, mConfigurable));
348 
349     std::vector<std::unique_ptr<C2Param>> configUpdate;
350     C2PortVendorInt32Info::input i32(kCodec2Int32);
351     C2StreamVendorInt64Info::output i64(0u, kCodec2Int64);
352     std::unique_ptr<C2PortVendorStringInfo::input> str =
353         C2PortVendorStringInfo::input::AllocUnique(strlen(kCodec2Str) + 1, kCodec2Str);
354     configUpdate.push_back(C2Param::Copy(i32));
355     configUpdate.push_back(C2Param::Copy(i64));
356     configUpdate.push_back(std::move(str));
357 
358     // The vendor parameters are not yet subscribed
359     ASSERT_FALSE(mConfig.updateConfiguration(configUpdate, D::ALL));
360 
361     int32_t vendorInt32{0};
362     ASSERT_FALSE(mConfig.mInputFormat->findInt32(KEY_VENDOR_INT32, &vendorInt32))
363             << "mInputFormat = " << mConfig.mInputFormat->debugString().c_str();
364     ASSERT_FALSE(mConfig.mOutputFormat->findInt32(KEY_VENDOR_INT32, &vendorInt32))
365             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
366 
367     int64_t vendorInt64{0};
368     ASSERT_FALSE(mConfig.mInputFormat->findInt64(KEY_VENDOR_INT64, &vendorInt64))
369             << "mInputFormat = " << mConfig.mInputFormat->debugString().c_str();
370     ASSERT_FALSE(mConfig.mOutputFormat->findInt64(KEY_VENDOR_INT64, &vendorInt64))
371             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
372 
373     AString vendorString;
374     ASSERT_FALSE(mConfig.mInputFormat->findString(KEY_VENDOR_STRING, &vendorString))
375             << "mInputFormat = " << mConfig.mInputFormat->debugString().c_str();
376     ASSERT_FALSE(mConfig.mOutputFormat->findString(KEY_VENDOR_STRING, &vendorString))
377             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
378 }
379 
TEST_F(CCodecConfigTest,VendorParamUpdate_AllSubscribed)380 TEST_F(CCodecConfigTest, VendorParamUpdate_AllSubscribed) {
381     // Test at audio domain, as video domain has a few local parameters that
382     // interfere with the testing.
383     init(C2Component::DOMAIN_AUDIO, C2Component::KIND_DECODER, MIMETYPE_AUDIO_AAC);
384 
385     ASSERT_EQ(OK, mConfig.initialize(mReflector, mConfigurable));
386 
387     // Force subscribe to all vendor params
388     ASSERT_EQ(OK, mConfig.subscribeToAllVendorParams(mConfigurable, C2_MAY_BLOCK));
389 
390     std::vector<std::unique_ptr<C2Param>> configUpdate;
391     C2PortVendorInt32Info::input i32(kCodec2Int32);
392     C2StreamVendorInt64Info::output i64(0u, kCodec2Int64);
393     std::unique_ptr<C2PortVendorStringInfo::input> str =
394         C2PortVendorStringInfo::input::AllocUnique(strlen(kCodec2Str) + 1, kCodec2Str);
395     configUpdate.push_back(C2Param::Copy(i32));
396     configUpdate.push_back(C2Param::Copy(i64));
397     configUpdate.push_back(std::move(str));
398 
399     ASSERT_TRUE(mConfig.updateConfiguration(configUpdate, D::ALL));
400 
401     int32_t vendorInt32{0};
402     ASSERT_TRUE(mConfig.mInputFormat->findInt32(KEY_VENDOR_INT32, &vendorInt32))
403             << "mInputFormat = " << mConfig.mInputFormat->debugString().c_str();
404     ASSERT_EQ(kCodec2Int32, vendorInt32);
405     ASSERT_FALSE(mConfig.mOutputFormat->findInt32(KEY_VENDOR_INT32, &vendorInt32))
406             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
407 
408     int64_t vendorInt64{0};
409     ASSERT_FALSE(mConfig.mInputFormat->findInt64(KEY_VENDOR_INT64, &vendorInt64))
410             << "mInputFormat = " << mConfig.mInputFormat->debugString().c_str();
411     ASSERT_TRUE(mConfig.mOutputFormat->findInt64(KEY_VENDOR_INT64, &vendorInt64))
412             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
413     ASSERT_EQ(kCodec2Int64, vendorInt64);
414 
415     AString vendorString;
416     ASSERT_TRUE(mConfig.mInputFormat->findString(KEY_VENDOR_STRING, &vendorString))
417             << "mInputFormat = " << mConfig.mInputFormat->debugString().c_str();
418     ASSERT_STREQ(kCodec2Str, vendorString.c_str());
419     ASSERT_FALSE(mConfig.mOutputFormat->findString(KEY_VENDOR_STRING, &vendorString))
420             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
421 }
422 
TEST_F(CCodecConfigTest,VendorParamUpdate_PartiallySubscribed)423 TEST_F(CCodecConfigTest, VendorParamUpdate_PartiallySubscribed) {
424     // Test at audio domain, as video domain has a few local parameters that
425     // interfere with the testing.
426     init(C2Component::DOMAIN_AUDIO, C2Component::KIND_DECODER, MIMETYPE_AUDIO_AAC);
427 
428     ASSERT_EQ(OK, mConfig.initialize(mReflector, mConfigurable));
429 
430     // Subscribe to example.int32 only
431     std::vector<std::unique_ptr<C2Param>> configUpdate;
432     sp<AMessage> format{new AMessage};
433     format->setInt32(KEY_VENDOR_INT32, 0);
434     configUpdate.clear();
435     ASSERT_EQ(OK, mConfig.getConfigUpdateFromSdkParams(
436             mConfigurable, format, D::ALL, C2_MAY_BLOCK, &configUpdate));
437     ASSERT_EQ(OK, mConfig.setParameters(mConfigurable, configUpdate, C2_MAY_BLOCK));
438 
439     C2PortVendorInt32Info::input i32(kCodec2Int32);
440     C2StreamVendorInt64Info::output i64(0u, kCodec2Int64);
441     std::unique_ptr<C2PortVendorStringInfo::input> str =
442         C2PortVendorStringInfo::input::AllocUnique(strlen(kCodec2Str) + 1, kCodec2Str);
443     configUpdate.clear();
444     configUpdate.push_back(C2Param::Copy(i32));
445     configUpdate.push_back(C2Param::Copy(i64));
446     configUpdate.push_back(std::move(str));
447 
448     // Only example.i32 should be updated
449     ASSERT_TRUE(mConfig.updateConfiguration(configUpdate, D::ALL));
450 
451     int32_t vendorInt32{0};
452     ASSERT_TRUE(mConfig.mInputFormat->findInt32(KEY_VENDOR_INT32, &vendorInt32))
453             << "mInputFormat = " << mConfig.mInputFormat->debugString().c_str();
454     ASSERT_EQ(kCodec2Int32, vendorInt32);
455     ASSERT_FALSE(mConfig.mOutputFormat->findInt32(KEY_VENDOR_INT32, &vendorInt32))
456             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
457 
458     int64_t vendorInt64{0};
459     ASSERT_FALSE(mConfig.mInputFormat->findInt64(KEY_VENDOR_INT64, &vendorInt64))
460             << "mInputFormat = " << mConfig.mInputFormat->debugString().c_str();
461     ASSERT_FALSE(mConfig.mOutputFormat->findInt64(KEY_VENDOR_INT64, &vendorInt64))
462             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
463 
464     AString vendorString;
465     ASSERT_FALSE(mConfig.mInputFormat->findString(KEY_VENDOR_STRING, &vendorString))
466             << "mInputFormat = " << mConfig.mInputFormat->debugString().c_str();
467     ASSERT_FALSE(mConfig.mOutputFormat->findString(KEY_VENDOR_STRING, &vendorString))
468             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
469 }
470 
TEST_F(CCodecConfigTest,SetPixelAspectRatio)471 TEST_F(CCodecConfigTest, SetPixelAspectRatio) {
472     init(C2Component::DOMAIN_VIDEO, C2Component::KIND_DECODER, MIMETYPE_VIDEO_AVC);
473 
474     ASSERT_EQ(OK, mConfig.initialize(mReflector, mConfigurable));
475 
476     sp<AMessage> format{new AMessage};
477     format->setInt32(KEY_PIXEL_ASPECT_RATIO_WIDTH, 12);
478     format->setInt32(KEY_PIXEL_ASPECT_RATIO_HEIGHT, 11);
479 
480     std::vector<std::unique_ptr<C2Param>> configUpdate;
481     ASSERT_EQ(OK, mConfig.getConfigUpdateFromSdkParams(
482             mConfigurable, format, D::ALL, C2_MAY_BLOCK, &configUpdate));
483 
484     ASSERT_EQ(1u, configUpdate.size());
485     C2StreamPixelAspectRatioInfo::output *par =
486         FindParam<std::remove_pointer<decltype(par)>::type>(configUpdate);
487     ASSERT_NE(nullptr, par);
488     ASSERT_EQ(12, par->width);
489     ASSERT_EQ(11, par->height);
490 }
491 
TEST_F(CCodecConfigTest,PixelAspectRatioUpdate)492 TEST_F(CCodecConfigTest, PixelAspectRatioUpdate) {
493     init(C2Component::DOMAIN_VIDEO, C2Component::KIND_DECODER, MIMETYPE_VIDEO_AVC);
494 
495     ASSERT_EQ(OK, mConfig.initialize(mReflector, mConfigurable));
496 
497     std::vector<std::unique_ptr<C2Param>> configUpdate;
498     C2StreamPixelAspectRatioInfo::output par(0u, 12, 11);
499     configUpdate.push_back(C2Param::Copy(par));
500 
501     ASSERT_TRUE(mConfig.updateConfiguration(configUpdate, D::ALL));
502 
503     int32_t parWidth{0};
504     ASSERT_TRUE(mConfig.mOutputFormat->findInt32(KEY_PIXEL_ASPECT_RATIO_WIDTH, &parWidth))
505             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
506     ASSERT_EQ(12, parWidth);
507     ASSERT_FALSE(mConfig.mInputFormat->findInt32(KEY_PIXEL_ASPECT_RATIO_WIDTH, &parWidth))
508             << "mInputFormat = " << mConfig.mInputFormat->debugString().c_str();
509 
510     int32_t parHeight{0};
511     ASSERT_TRUE(mConfig.mOutputFormat->findInt32(KEY_PIXEL_ASPECT_RATIO_HEIGHT, &parHeight))
512             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
513     ASSERT_EQ(11, parHeight);
514     ASSERT_FALSE(mConfig.mInputFormat->findInt32(KEY_PIXEL_ASPECT_RATIO_HEIGHT, &parHeight))
515             << "mInputFormat = " << mConfig.mInputFormat->debugString().c_str();
516 }
517 
TEST_F(CCodecConfigTest,DataspaceUpdate)518 TEST_F(CCodecConfigTest, DataspaceUpdate) {
519     init(C2Component::DOMAIN_VIDEO, C2Component::KIND_ENCODER, MIMETYPE_VIDEO_AVC);
520 
521     ASSERT_EQ(OK, mConfig.initialize(mReflector, mConfigurable));
522     class InputSurfaceStub : public InputSurfaceWrapper {
523     public:
524         ~InputSurfaceStub() override = default;
525         status_t connect(const std::shared_ptr<Codec2Client::Component> &) override {
526             return OK;
527         }
528         void disconnect() override {}
529         status_t start() override { return OK; }
530         status_t signalEndOfInputStream() override { return OK; }
531         status_t configure(Config &) override { return OK; }
532     };
533     mConfig.mInputSurface = std::make_shared<InputSurfaceStub>();
534 
535     sp<AMessage> format{new AMessage};
536     format->setInt32(KEY_COLOR_RANGE, COLOR_RANGE_LIMITED);
537     format->setInt32(KEY_COLOR_STANDARD, COLOR_STANDARD_BT709);
538     format->setInt32(KEY_COLOR_TRANSFER, COLOR_TRANSFER_SDR_VIDEO);
539     format->setInt32(KEY_BIT_RATE, 100);
540 
541     std::vector<std::unique_ptr<C2Param>> configUpdate;
542     ASSERT_EQ(OK, mConfig.getConfigUpdateFromSdkParams(
543             mConfigurable, format, D::ALL, C2_MAY_BLOCK, &configUpdate));
544     ASSERT_TRUE(mConfig.updateConfiguration(configUpdate, D::ALL));
545 
546     int32_t range{0};
547     ASSERT_TRUE(mConfig.mOutputFormat->findInt32(KEY_COLOR_RANGE, &range))
548             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
549     EXPECT_EQ(COLOR_RANGE_LIMITED, range)
550             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
551 
552     int32_t standard{0};
553     ASSERT_TRUE(mConfig.mOutputFormat->findInt32(KEY_COLOR_STANDARD, &standard))
554             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
555     EXPECT_EQ(COLOR_STANDARD_BT709, standard)
556             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
557 
558     int32_t transfer{0};
559     ASSERT_TRUE(mConfig.mOutputFormat->findInt32(KEY_COLOR_TRANSFER, &transfer))
560             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
561     EXPECT_EQ(COLOR_TRANSFER_SDR_VIDEO, transfer)
562             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
563 
564     mConfig.mInputSurface->setDataSpace(HAL_DATASPACE_BT2020_PQ);
565 
566     // Dataspace from input surface should override the configured setting
567     mConfig.updateFormats(D::ALL);
568 
569     ASSERT_TRUE(mConfig.mOutputFormat->findInt32(KEY_COLOR_RANGE, &range))
570             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
571     EXPECT_EQ(COLOR_RANGE_FULL, range)
572             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
573 
574     ASSERT_TRUE(mConfig.mOutputFormat->findInt32(KEY_COLOR_STANDARD, &standard))
575             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
576     EXPECT_EQ(COLOR_STANDARD_BT2020, standard)
577             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
578 
579     ASSERT_TRUE(mConfig.mOutputFormat->findInt32(KEY_COLOR_TRANSFER, &transfer))
580             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
581     EXPECT_EQ(COLOR_TRANSFER_ST2084, transfer)
582             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
583 
584     // Simulate bitrate update
585     format = new AMessage;
586     format->setInt32(KEY_BIT_RATE, 200);
587     configUpdate.clear();
588     ASSERT_EQ(OK, mConfig.getConfigUpdateFromSdkParams(
589             mConfigurable, format, D::ALL, C2_MAY_BLOCK, &configUpdate));
590     ASSERT_EQ(OK, mConfig.setParameters(mConfigurable, configUpdate, C2_MAY_BLOCK));
591 
592     // Color information should remain the same
593     mConfig.updateFormats(D::ALL);
594 
595     ASSERT_TRUE(mConfig.mOutputFormat->findInt32(KEY_COLOR_RANGE, &range))
596             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
597     EXPECT_EQ(COLOR_RANGE_FULL, range)
598             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
599 
600     ASSERT_TRUE(mConfig.mOutputFormat->findInt32(KEY_COLOR_STANDARD, &standard))
601             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
602     EXPECT_EQ(COLOR_STANDARD_BT2020, standard)
603             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
604 
605     ASSERT_TRUE(mConfig.mOutputFormat->findInt32(KEY_COLOR_TRANSFER, &transfer))
606             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
607     EXPECT_EQ(COLOR_TRANSFER_ST2084, transfer)
608             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
609 }
610 
611 typedef std::tuple<std::string, C2Config::profile_t, int32_t> HdrProfilesParams;
612 
613 class HdrProfilesTest
614     : public CCodecConfigTest,
615       public ::testing::WithParamInterface<HdrProfilesParams> {
616 };
617 
TEST_P(HdrProfilesTest,SetFromSdk)618 TEST_P(HdrProfilesTest, SetFromSdk) {
619     HdrProfilesParams params = GetParam();
620     std::string mediaType = std::get<0>(params);
621     C2Config::profile_t c2Profile = std::get<1>(params);
622     int32_t sdkProfile = std::get<2>(params);
623 
624     init(C2Component::DOMAIN_VIDEO, C2Component::KIND_ENCODER, mediaType.c_str());
625 
626     ASSERT_EQ(OK, mConfig.initialize(mReflector, mConfigurable));
627 
628     sp<AMessage> format{new AMessage};
629     format->setInt32(KEY_PROFILE, sdkProfile);
630 
631     std::vector<std::unique_ptr<C2Param>> configUpdate;
632     ASSERT_EQ(OK, mConfig.getConfigUpdateFromSdkParams(
633             mConfigurable, format, D::ALL, C2_MAY_BLOCK, &configUpdate));
634 
635     ASSERT_EQ(1u, configUpdate.size());
636     C2StreamProfileLevelInfo::input *pl =
637         FindParam<std::remove_pointer<decltype(pl)>::type>(configUpdate);
638     ASSERT_NE(nullptr, pl);
639     ASSERT_EQ(c2Profile, pl->profile);
640 }
641 
642 HdrProfilesParams kHdrProfilesParams[] = {
643     std::make_tuple(MIMETYPE_VIDEO_HEVC, PROFILE_HEVC_MAIN_10, HEVCProfileMain10HDR10),
644     std::make_tuple(MIMETYPE_VIDEO_HEVC, PROFILE_HEVC_MAIN_10, HEVCProfileMain10HDR10Plus),
645     std::make_tuple(MIMETYPE_VIDEO_VP9,  PROFILE_VP9_2,        VP9Profile2HDR),
646     std::make_tuple(MIMETYPE_VIDEO_VP9,  PROFILE_VP9_2,        VP9Profile2HDR10Plus),
647     std::make_tuple(MIMETYPE_VIDEO_VP9,  PROFILE_VP9_3,        VP9Profile3HDR),
648     std::make_tuple(MIMETYPE_VIDEO_VP9,  PROFILE_VP9_3,        VP9Profile3HDR10Plus),
649     std::make_tuple(MIMETYPE_VIDEO_AV1,  PROFILE_AV1_0,        AV1ProfileMain10HDR10),
650     std::make_tuple(MIMETYPE_VIDEO_AV1,  PROFILE_AV1_0,        AV1ProfileMain10HDR10Plus),
651 };
652 
653 INSTANTIATE_TEST_SUITE_P(
654         CCodecConfig,
655         HdrProfilesTest,
656         ::testing::ValuesIn(kHdrProfilesParams));
657 
TEST_F(CCodecConfigTest,SetRegionOfInterestParams)658 TEST_F(CCodecConfigTest, SetRegionOfInterestParams) {
659     if (!android::media::codec::provider_->region_of_interest()
660         || !android::media::codec::provider_->region_of_interest_support()) {
661         GTEST_SKIP() << "Skipping the test as region_of_interest flags are not enabled.\n";
662     }
663 
664     init(C2Component::DOMAIN_VIDEO, C2Component::KIND_ENCODER, MIMETYPE_VIDEO_VP9);
665 
666     ASSERT_EQ(OK, mConfig.initialize(mReflector, mConfigurable));
667 
668     const int kWidth = 32;
669     const int kHeight = 32;
670     const int kNumBlocks = ((kWidth + 15) / 16) * ((kHeight + 15) / 16);
671     int8_t mapInfo[kNumBlocks] = {-1, 0, 1, 1};
672     int top[kNumBlocks] = {0, 0, 16, 16};
673     int left[kNumBlocks] = {0, 16, 0, 16};
674     int bottom[kNumBlocks] = {16, 16, 32, 32};
675     int right[kNumBlocks] = {16, 32, 16, 32};
676     sp<AMessage> format{new AMessage};
677     format->setInt32(KEY_WIDTH, kWidth);
678     format->setInt32(KEY_HEIGHT, kHeight);
679     AString val;
680     for (int i = 0; i < kNumBlocks; i++) {
681         val.append(AStringPrintf("%d,%d-%d,%d=%d;", top[i], left[i], bottom[i],
682                                  right[i], mapInfo[i]));
683     }
684     format->setString(PARAMETER_KEY_QP_OFFSET_RECTS, val);
685 
686     std::vector<std::unique_ptr<C2Param>> configUpdate;
687     ASSERT_EQ(OK, mConfig.getConfigUpdateFromSdkParams(mConfigurable, format, D::CONFIG,
688                                                        C2_MAY_BLOCK, &configUpdate));
689 
690     EXPECT_EQ(1u, configUpdate.size());
691 
692     C2StreamQpOffsetRects::output* qpRectParam =
693             FindParam<std::remove_pointer<decltype(qpRectParam)>::type>(configUpdate);
694     ASSERT_NE(nullptr, qpRectParam);
695     ASSERT_EQ(kNumBlocks, qpRectParam->flexCount());
696     for (auto i = 0; i < kNumBlocks; i++) {
697         EXPECT_EQ(mapInfo[i], (int8_t)qpRectParam->m.values[i].qpOffset)
698                 << "qp offset for index " << i << " is not as expected ";
699         EXPECT_EQ(left[i], qpRectParam->m.values[i].left)
700                 << "left for index " << i << " is not as expected ";
701         EXPECT_EQ(top[i], qpRectParam->m.values[i].top)
702                 << "top for index " << i << " is not as expected ";
703         EXPECT_EQ(right[i] - left[i], qpRectParam->m.values[i].width)
704                 << "width for index " << i << " is not as expected ";
705         EXPECT_EQ(bottom[i] - top[i], qpRectParam->m.values[i].height)
706                 << "height for index " << i << " is not as expected ";
707     }
708 }
709 
710 } // namespace android
711