• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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           initializeSystemResources();
64     }
65 
init(C2Component::domain_t domain,C2Component::kind_t kind,const char * mediaType)66     void init(
67             C2Component::domain_t domain,
68             C2Component::kind_t kind,
69             const char *mediaType) {
70         sp<hardware::media::c2::V1_0::utils::CachedConfigurable> cachedConfigurable =
71             new hardware::media::c2::V1_0::utils::CachedConfigurable(
72                     std::make_unique<Configurable>(mReflector, domain, kind, mediaType,
73                                                    mSystemResources, mExcludedResources));
74         cachedConfigurable->init(std::make_shared<Cache>());
75         mConfigurable = std::make_shared<Codec2Client::Configurable>(cachedConfigurable);
76     }
77 
78     struct Cache : public hardware::media::c2::V1_0::utils::ParameterCache {
validateandroid::CCodecConfigTest::Cache79         c2_status_t validate(const std::vector<std::shared_ptr<C2ParamDescriptor>>&) override {
80             return C2_OK;
81         }
82     };
83 
84     class Configurable : public hardware::media::c2::V1_0::utils::ConfigurableC2Intf {
85     public:
Configurable(const std::shared_ptr<C2ReflectorHelper> & reflector,C2Component::domain_t domain,C2Component::kind_t kind,const char * mediaType,const std::vector<C2SystemResourceStruct> & systemResources,const std::vector<C2SystemResourceStruct> & excludedResources)86         Configurable(
87                 const std::shared_ptr<C2ReflectorHelper> &reflector,
88                 C2Component::domain_t domain,
89                 C2Component::kind_t kind,
90                 const char *mediaType,
91                 const std::vector<C2SystemResourceStruct>& systemResources,
92                 const std::vector<C2SystemResourceStruct>& excludedResources)
93             : ConfigurableC2Intf("name", 0u),
94               mImpl(reflector, domain, kind, mediaType, systemResources, excludedResources) {
95         }
96 
query(const std::vector<C2Param::Index> & indices,c2_blocking_t mayBlock,std::vector<std::unique_ptr<C2Param>> * const params) const97         c2_status_t query(
98                 const std::vector<C2Param::Index> &indices,
99                 c2_blocking_t mayBlock,
100                 std::vector<std::unique_ptr<C2Param>>* const params) const override {
101             return mImpl.query({}, indices, mayBlock, params);
102         }
103 
config(const std::vector<C2Param * > & params,c2_blocking_t mayBlock,std::vector<std::unique_ptr<C2SettingResult>> * const failures)104         c2_status_t config(
105                 const std::vector<C2Param*> &params,
106                 c2_blocking_t mayBlock,
107                 std::vector<std::unique_ptr<C2SettingResult>>* const failures) override {
108             return mImpl.config(params, mayBlock, failures);
109         }
110 
querySupportedParams(std::vector<std::shared_ptr<C2ParamDescriptor>> * const params) const111         c2_status_t querySupportedParams(
112                 std::vector<std::shared_ptr<C2ParamDescriptor>>* const params) const override {
113             return mImpl.querySupportedParams(params);
114         }
115 
querySupportedValues(std::vector<C2FieldSupportedValuesQuery> & fields,c2_blocking_t mayBlock) const116         c2_status_t querySupportedValues(
117                 std::vector<C2FieldSupportedValuesQuery>& fields,
118                 c2_blocking_t mayBlock) const override {
119             return mImpl.querySupportedValues(fields, mayBlock);
120         }
121 
122     private:
123         class Impl : public C2InterfaceHelper {
124         public:
Impl(const std::shared_ptr<C2ReflectorHelper> & reflector,C2Component::domain_t domain,C2Component::kind_t kind,const char * mediaType,const std::vector<C2SystemResourceStruct> & systemResources,const std::vector<C2SystemResourceStruct> & excludedResources)125             Impl(const std::shared_ptr<C2ReflectorHelper> &reflector,
126                     C2Component::domain_t domain,
127                     C2Component::kind_t kind,
128                     const char *mediaType,
129                     const std::vector<C2SystemResourceStruct>& systemResources,
130                     const std::vector<C2SystemResourceStruct>& excludedResources)
131                 : C2InterfaceHelper{reflector} {
132 
133                 setDerivedInstance(this);
134 
135                 addParameter(
136                         DefineParam(mDomain, C2_PARAMKEY_COMPONENT_DOMAIN)
137                         .withConstValue(new C2ComponentDomainSetting(domain))
138                         .build());
139 
140                 addParameter(
141                         DefineParam(mKind, C2_PARAMKEY_COMPONENT_KIND)
142                         .withConstValue(new C2ComponentKindSetting(kind))
143                         .build());
144 
145                 addParameter(
146                         DefineParam(mInputStreamCount, C2_PARAMKEY_INPUT_STREAM_COUNT)
147                         .withConstValue(new C2PortStreamCountTuning::input(1))
148                         .build());
149 
150                 addParameter(
151                         DefineParam(mOutputStreamCount, C2_PARAMKEY_OUTPUT_STREAM_COUNT)
152                         .withConstValue(new C2PortStreamCountTuning::output(1))
153                         .build());
154 
155                 const char *rawMediaType = "";
156                 switch (domain) {
157                     case C2Component::DOMAIN_IMAGE: [[fallthrough]];
158                     case C2Component::DOMAIN_VIDEO:
159                         rawMediaType = MIMETYPE_VIDEO_RAW;
160                         break;
161                     case C2Component::DOMAIN_AUDIO:
162                         rawMediaType = MIMETYPE_AUDIO_RAW;
163                         break;
164                     default:
165                         break;
166                 }
167                 bool isEncoder = kind == C2Component::KIND_ENCODER;
168                 std::string inputMediaType{isEncoder ? rawMediaType : mediaType};
169                 std::string outputMediaType{isEncoder ? mediaType : rawMediaType};
170 
__anon243c35b90202(const auto &param, const std::string &str) 171                 auto allocSharedString = [](const auto &param, const std::string &str) {
172                     typedef typename std::remove_reference<decltype(param)>::type::element_type T;
173                     std::shared_ptr<T> ret = T::AllocShared(str.length() + 1);
174                     strcpy(ret->m.value, str.c_str());
175                     return ret;
176                 };
177 
178                 addParameter(
179                         DefineParam(mInputMediaType, C2_PARAMKEY_INPUT_MEDIA_TYPE)
180                         .withConstValue(allocSharedString(mInputMediaType, inputMediaType))
181                         .build());
182 
183                 addParameter(
184                         DefineParam(mOutputMediaType, C2_PARAMKEY_OUTPUT_MEDIA_TYPE)
185                         .withConstValue(allocSharedString(mOutputMediaType, outputMediaType))
186                         .build());
187 
188                 addParameter(
189                         DefineParam(mInt32Input, C2_PARAMKEY_VENDOR_INT32)
190                         .withDefault(new C2PortVendorInt32Info::input(0))
191                         .withFields({C2F(mInt32Input, value).any()})
192                         .withSetter(Setter<decltype(mInt32Input)::element_type>)
193                         .build());
194 
195                 addParameter(
196                         DefineParam(mInt64Output, C2_PARAMKEY_VENDOR_INT64)
197                         .withDefault(new C2StreamVendorInt64Info::output(0u, 0))
198                         .withFields({C2F(mInt64Output, value).any()})
199                         .withSetter(Setter<decltype(mInt64Output)::element_type>)
200                         .build());
201 
202                 addParameter(
203                         DefineParam(mStringInput, C2_PARAMKEY_VENDOR_STRING)
204                         .withDefault(decltype(mStringInput)::element_type::AllocShared(1, ""))
205                         .withFields({C2F(mStringInput, m.value).any()})
206                         .withSetter(Setter<decltype(mStringInput)::element_type>)
207                         .build());
208 
209                 addParameter(
210                         DefineParam(mPixelAspectRatio, C2_PARAMKEY_PIXEL_ASPECT_RATIO)
211                         .withDefault(new C2StreamPixelAspectRatioInfo::output(0u, 1, 1))
212                         .withFields({
213                             C2F(mPixelAspectRatio, width).any(),
214                             C2F(mPixelAspectRatio, height).any(),
215                         })
216                         .withSetter(Setter<C2StreamPixelAspectRatioInfo::output>)
217                         .build());
218 
219                 // Add System Resource Capacity
220                 addParameter(
221                     DefineParam(mResourcesCapacity, C2_PARAMKEY_RESOURCES_CAPACITY)
222                     .withDefault(C2ResourcesCapacityTuning::AllocShared(
223                             systemResources.size(), systemResources))
224                     .withFields({
225                             C2F(mResourcesCapacity, m.values[0].id).any(),
226                             C2F(mResourcesCapacity, m.values[0].kind).any(),
227                             C2F(mResourcesCapacity, m.values[0].amount).any(),
228                     })
229                     .withSetter(Setter<C2ResourcesCapacityTuning>)
230                     .build());
231 
232                 // Add Excluded System Resources
233                 addParameter(
234                     DefineParam(mResourcesExcluded, C2_PARAMKEY_RESOURCES_EXCLUDED)
235                     .withDefault(C2ResourcesExcludedTuning::AllocShared(
236                             excludedResources.size(), excludedResources))
237                     .withFields({
238                             C2F(mResourcesExcluded, m.values[0].id).any(),
239                             C2F(mResourcesExcluded, m.values[0].kind).any(),
240                             C2F(mResourcesExcluded, m.values[0].amount).any(),
241                     })
242                     .withSetter(Setter<C2ResourcesExcludedTuning>)
243                     .build());
244 
245                 if (isEncoder) {
246                     addParameter(
247                             DefineParam(mInputBitrate, C2_PARAMKEY_BITRATE)
248                             .withDefault(new C2StreamBitrateInfo::input(0u))
249                             .withFields({C2F(mInputBitrate, value).any()})
250                             .withSetter(Setter<C2StreamBitrateInfo::input>)
251                             .build());
252 
253                     addParameter(
254                             DefineParam(mOutputBitrate, C2_PARAMKEY_BITRATE)
255                             .withDefault(new C2StreamBitrateInfo::output(0u))
256                             .withFields({C2F(mOutputBitrate, value).any()})
257                             .calculatedAs(
258                                 Copy<C2StreamBitrateInfo::output, C2StreamBitrateInfo::input>,
259                                 mInputBitrate)
260                             .build());
261 
262                     addParameter(
263                             DefineParam(mOutputProfileLevel, C2_PARAMKEY_PROFILE_LEVEL)
264                             .withDefault(new C2StreamProfileLevelInfo::output(
265                                     0u, PROFILE_UNUSED, LEVEL_UNUSED))
266                             .withFields({
267                                 C2F(mOutputProfileLevel, profile).any(),
268                                 C2F(mOutputProfileLevel, level).any(),
269                             })
270                             .withSetter(Setter<C2StreamProfileLevelInfo::output>)
271                             .build());
272 
273                     std::vector<C2QpOffsetRectStruct> c2QpOffsetRectsInfo;
274                     addParameter(
275                             DefineParam(mInputQpOffsetRects, C2_PARAMKEY_QP_OFFSET_RECTS)
276                                     .withDefault(C2StreamQpOffsetRects::output::AllocShared(
277                                             c2QpOffsetRectsInfo.size(), 0, c2QpOffsetRectsInfo))
278                                     .withFields({
279                                             C2F(mInputQpOffsetRects, m.values[0].qpOffset)
280                                                     .inRange(-128, 127),
281                                             C2F(mInputQpOffsetRects, m.values[0].left).any(),
282                                             C2F(mInputQpOffsetRects, m.values[0].top).any(),
283                                             C2F(mInputQpOffsetRects, m.values[0].width).any(),
284                                             C2F(mInputQpOffsetRects, m.values[0].height).any(),
285                                     })
286                                     .withSetter(Setter<C2StreamQpOffsetRects::output>)
287                                     .build());
288                 }
289 
290                 // TODO: more SDK params
291             }
292         private:
293             std::shared_ptr<C2ComponentDomainSetting> mDomain;
294             std::shared_ptr<C2ComponentKindSetting> mKind;
295             std::shared_ptr<C2PortStreamCountTuning::input> mInputStreamCount;
296             std::shared_ptr<C2PortStreamCountTuning::output> mOutputStreamCount;
297             std::shared_ptr<C2PortMediaTypeSetting::input> mInputMediaType;
298             std::shared_ptr<C2PortMediaTypeSetting::output> mOutputMediaType;
299             std::shared_ptr<C2PortVendorInt32Info::input> mInt32Input;
300             std::shared_ptr<C2StreamVendorInt64Info::output> mInt64Output;
301             std::shared_ptr<C2PortVendorStringInfo::input> mStringInput;
302             std::shared_ptr<C2StreamPixelAspectRatioInfo::output> mPixelAspectRatio;
303             std::shared_ptr<C2StreamBitrateInfo::input> mInputBitrate;
304             std::shared_ptr<C2StreamBitrateInfo::output> mOutputBitrate;
305             std::shared_ptr<C2StreamProfileLevelInfo::input> mInputProfileLevel;
306             std::shared_ptr<C2StreamProfileLevelInfo::output> mOutputProfileLevel;
307             std::shared_ptr<C2StreamQpOffsetRects::output> mInputQpOffsetRects;
308             std::shared_ptr<C2ResourcesCapacityTuning> mResourcesCapacity;
309             std::shared_ptr<C2ResourcesExcludedTuning> mResourcesExcluded;
310 
311             template<typename T>
Setter(bool,C2P<T> &)312             static C2R Setter(bool, C2P<T> &) {
313                 return C2R::Ok();
314             }
315 
316             template<typename ME, typename DEP>
Copy(bool,C2P<ME> & me,const C2P<DEP> & dep)317             static C2R Copy(bool, C2P<ME> &me, const C2P<DEP> &dep) {
318                 me.set().value = dep.v.value;
319                 return C2R::Ok();
320             }
321         };
322 
323         Impl mImpl;
324     };
325 
326     std::shared_ptr<C2ReflectorHelper> mReflector;
327     std::shared_ptr<Codec2Client::Configurable> mConfigurable;
328     CCodecConfig mConfig;
329 
330     /*
331      * This test tracks two system resources:
332      *  - max instance limit, which is capped at 64
333      *  - max pixel count: up to 4 instances of 4K ==> 4 * 3840 * 2400
334      *
335      *  These 2 resource types are given 2 different ids as below.
336      */
initializeSystemResources()337     void initializeSystemResources() {
338         // max instance limit 64
339         const uint32_t kMaxInstanceCount = 0x1000;
340         // max pixel count: up to 4 instances of 4K
341         const uint32_t kMaxPixelCount = 0x1001;
342         mSystemResources.push_back(C2SystemResourceStruct(kMaxInstanceCount, CONST, 64));
343         mSystemResources.push_back(C2SystemResourceStruct(kMaxPixelCount, CONST, 4 * 3840 * 2400));
344 
345         // Nothing is excluded, but lets just add them with amount as 0.
346         mExcludedResources.push_back(C2SystemResourceStruct(kMaxInstanceCount, CONST, 0));
347         mExcludedResources.push_back(C2SystemResourceStruct(kMaxPixelCount, CONST, 0));
348     }
349 
validateSystemResources(const std::vector<C2SystemResourceStruct> & resources) const350     bool validateSystemResources(const std::vector<C2SystemResourceStruct>& resources) const {
351         if (resources.size() != mSystemResources.size()) {
352             return false;
353         }
354 
355         for (const auto& resource : mSystemResources) {
356             auto found = std::find_if(resources.begin(),
357                                       resources.end(),
358                                       [resource](const C2SystemResourceStruct& item) {
359                                           return (item.id == resource.id &&
360                                                   item.kind == resource.kind &&
361                                                   item.amount == resource.amount); });
362 
363             if (found == resources.end()) {
364                 return false;
365             }
366         }
367 
368         return true;
369     }
370 
371 private:
372     std::vector<C2SystemResourceStruct> mSystemResources;
373     std::vector<C2SystemResourceStruct> mExcludedResources;
374 };
375 
376 using D = CCodecConfig::Domain;
377 
378 template<typename T>
FindParam(const std::vector<std::unique_ptr<C2Param>> & vec)379 T *FindParam(const std::vector<std::unique_ptr<C2Param>> &vec) {
380     for (const std::unique_ptr<C2Param> &param : vec) {
381         if (param->coreIndex() == T::CORE_INDEX) {
382             return static_cast<T *>(param.get());
383         }
384     }
385     return nullptr;
386 }
387 
TEST_F(CCodecConfigTest,SetVendorParam)388 TEST_F(CCodecConfigTest, SetVendorParam) {
389     // Test at audio domain, as video domain has a few local parameters that
390     // interfere with the testing.
391     init(C2Component::DOMAIN_AUDIO, C2Component::KIND_DECODER, MIMETYPE_AUDIO_AAC);
392 
393     ASSERT_EQ(OK, mConfig.initialize(mReflector, mConfigurable));
394 
395     sp<AMessage> format{new AMessage};
396     format->setInt32(KEY_VENDOR_INT32, kCodec2Int32);
397     format->setInt64(KEY_VENDOR_INT64, kCodec2Int64);
398     format->setString(KEY_VENDOR_STRING, kCodec2Str);
399 
400     std::vector<std::unique_ptr<C2Param>> configUpdate;
401     ASSERT_EQ(OK, mConfig.getConfigUpdateFromSdkParams(
402             mConfigurable, format, D::ALL, C2_MAY_BLOCK, &configUpdate));
403 
404     ASSERT_EQ(3u, configUpdate.size());
405     C2PortVendorInt32Info::input *i32 =
406         FindParam<std::remove_pointer<decltype(i32)>::type>(configUpdate);
407     ASSERT_NE(nullptr, i32);
408     ASSERT_EQ(kCodec2Int32, i32->value);
409 
410     C2StreamVendorInt64Info::output *i64 =
411         FindParam<std::remove_pointer<decltype(i64)>::type>(configUpdate);
412     ASSERT_NE(nullptr, i64);
413     ASSERT_EQ(kCodec2Int64, i64->value);
414 
415     C2PortVendorStringInfo::input *str =
416         FindParam<std::remove_pointer<decltype(str)>::type>(configUpdate);
417     ASSERT_NE(nullptr, str);
418     ASSERT_STREQ(kCodec2Str, str->m.value);
419 }
420 
TEST_F(CCodecConfigTest,VendorParamUpdate_Unsubscribed)421 TEST_F(CCodecConfigTest, VendorParamUpdate_Unsubscribed) {
422     // Test at audio domain, as video domain has a few local parameters that
423     // interfere with the testing.
424     init(C2Component::DOMAIN_AUDIO, C2Component::KIND_DECODER, MIMETYPE_AUDIO_AAC);
425 
426     ASSERT_EQ(OK, mConfig.initialize(mReflector, mConfigurable));
427 
428     std::vector<std::unique_ptr<C2Param>> configUpdate;
429     C2PortVendorInt32Info::input i32(kCodec2Int32);
430     C2StreamVendorInt64Info::output i64(0u, kCodec2Int64);
431     std::unique_ptr<C2PortVendorStringInfo::input> str =
432         C2PortVendorStringInfo::input::AllocUnique(strlen(kCodec2Str) + 1, kCodec2Str);
433     configUpdate.push_back(C2Param::Copy(i32));
434     configUpdate.push_back(C2Param::Copy(i64));
435     configUpdate.push_back(std::move(str));
436 
437     // The vendor parameters are not yet subscribed
438     ASSERT_FALSE(mConfig.updateConfiguration(configUpdate, D::ALL));
439 
440     int32_t vendorInt32{0};
441     ASSERT_FALSE(mConfig.mInputFormat->findInt32(KEY_VENDOR_INT32, &vendorInt32))
442             << "mInputFormat = " << mConfig.mInputFormat->debugString().c_str();
443     ASSERT_FALSE(mConfig.mOutputFormat->findInt32(KEY_VENDOR_INT32, &vendorInt32))
444             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
445 
446     int64_t vendorInt64{0};
447     ASSERT_FALSE(mConfig.mInputFormat->findInt64(KEY_VENDOR_INT64, &vendorInt64))
448             << "mInputFormat = " << mConfig.mInputFormat->debugString().c_str();
449     ASSERT_FALSE(mConfig.mOutputFormat->findInt64(KEY_VENDOR_INT64, &vendorInt64))
450             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
451 
452     AString vendorString;
453     ASSERT_FALSE(mConfig.mInputFormat->findString(KEY_VENDOR_STRING, &vendorString))
454             << "mInputFormat = " << mConfig.mInputFormat->debugString().c_str();
455     ASSERT_FALSE(mConfig.mOutputFormat->findString(KEY_VENDOR_STRING, &vendorString))
456             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
457 }
458 
TEST_F(CCodecConfigTest,VendorParamUpdate_AllSubscribed)459 TEST_F(CCodecConfigTest, VendorParamUpdate_AllSubscribed) {
460     // Test at audio domain, as video domain has a few local parameters that
461     // interfere with the testing.
462     init(C2Component::DOMAIN_AUDIO, C2Component::KIND_DECODER, MIMETYPE_AUDIO_AAC);
463 
464     ASSERT_EQ(OK, mConfig.initialize(mReflector, mConfigurable));
465 
466     // Force subscribe to all vendor params
467     ASSERT_EQ(OK, mConfig.subscribeToAllVendorParams(mConfigurable, C2_MAY_BLOCK));
468 
469     std::vector<std::unique_ptr<C2Param>> configUpdate;
470     C2PortVendorInt32Info::input i32(kCodec2Int32);
471     C2StreamVendorInt64Info::output i64(0u, kCodec2Int64);
472     std::unique_ptr<C2PortVendorStringInfo::input> str =
473         C2PortVendorStringInfo::input::AllocUnique(strlen(kCodec2Str) + 1, kCodec2Str);
474     configUpdate.push_back(C2Param::Copy(i32));
475     configUpdate.push_back(C2Param::Copy(i64));
476     configUpdate.push_back(std::move(str));
477 
478     ASSERT_TRUE(mConfig.updateConfiguration(configUpdate, D::ALL));
479 
480     int32_t vendorInt32{0};
481     ASSERT_TRUE(mConfig.mInputFormat->findInt32(KEY_VENDOR_INT32, &vendorInt32))
482             << "mInputFormat = " << mConfig.mInputFormat->debugString().c_str();
483     ASSERT_EQ(kCodec2Int32, vendorInt32);
484     ASSERT_FALSE(mConfig.mOutputFormat->findInt32(KEY_VENDOR_INT32, &vendorInt32))
485             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
486 
487     int64_t vendorInt64{0};
488     ASSERT_FALSE(mConfig.mInputFormat->findInt64(KEY_VENDOR_INT64, &vendorInt64))
489             << "mInputFormat = " << mConfig.mInputFormat->debugString().c_str();
490     ASSERT_TRUE(mConfig.mOutputFormat->findInt64(KEY_VENDOR_INT64, &vendorInt64))
491             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
492     ASSERT_EQ(kCodec2Int64, vendorInt64);
493 
494     AString vendorString;
495     ASSERT_TRUE(mConfig.mInputFormat->findString(KEY_VENDOR_STRING, &vendorString))
496             << "mInputFormat = " << mConfig.mInputFormat->debugString().c_str();
497     ASSERT_STREQ(kCodec2Str, vendorString.c_str());
498     ASSERT_FALSE(mConfig.mOutputFormat->findString(KEY_VENDOR_STRING, &vendorString))
499             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
500 }
501 
TEST_F(CCodecConfigTest,VendorParamUpdate_PartiallySubscribed)502 TEST_F(CCodecConfigTest, VendorParamUpdate_PartiallySubscribed) {
503     // Test at audio domain, as video domain has a few local parameters that
504     // interfere with the testing.
505     init(C2Component::DOMAIN_AUDIO, C2Component::KIND_DECODER, MIMETYPE_AUDIO_AAC);
506 
507     ASSERT_EQ(OK, mConfig.initialize(mReflector, mConfigurable));
508 
509     // Subscribe to example.int32 only
510     std::vector<std::unique_ptr<C2Param>> configUpdate;
511     sp<AMessage> format{new AMessage};
512     format->setInt32(KEY_VENDOR_INT32, 0);
513     configUpdate.clear();
514     ASSERT_EQ(OK, mConfig.getConfigUpdateFromSdkParams(
515             mConfigurable, format, D::ALL, C2_MAY_BLOCK, &configUpdate));
516     ASSERT_EQ(OK, mConfig.setParameters(mConfigurable, configUpdate, C2_MAY_BLOCK));
517 
518     C2PortVendorInt32Info::input i32(kCodec2Int32);
519     C2StreamVendorInt64Info::output i64(0u, kCodec2Int64);
520     std::unique_ptr<C2PortVendorStringInfo::input> str =
521         C2PortVendorStringInfo::input::AllocUnique(strlen(kCodec2Str) + 1, kCodec2Str);
522     configUpdate.clear();
523     configUpdate.push_back(C2Param::Copy(i32));
524     configUpdate.push_back(C2Param::Copy(i64));
525     configUpdate.push_back(std::move(str));
526 
527     // Only example.i32 should be updated
528     ASSERT_TRUE(mConfig.updateConfiguration(configUpdate, D::ALL));
529 
530     int32_t vendorInt32{0};
531     ASSERT_TRUE(mConfig.mInputFormat->findInt32(KEY_VENDOR_INT32, &vendorInt32))
532             << "mInputFormat = " << mConfig.mInputFormat->debugString().c_str();
533     ASSERT_EQ(kCodec2Int32, vendorInt32);
534     ASSERT_FALSE(mConfig.mOutputFormat->findInt32(KEY_VENDOR_INT32, &vendorInt32))
535             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
536 
537     int64_t vendorInt64{0};
538     ASSERT_FALSE(mConfig.mInputFormat->findInt64(KEY_VENDOR_INT64, &vendorInt64))
539             << "mInputFormat = " << mConfig.mInputFormat->debugString().c_str();
540     ASSERT_FALSE(mConfig.mOutputFormat->findInt64(KEY_VENDOR_INT64, &vendorInt64))
541             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
542 
543     AString vendorString;
544     ASSERT_FALSE(mConfig.mInputFormat->findString(KEY_VENDOR_STRING, &vendorString))
545             << "mInputFormat = " << mConfig.mInputFormat->debugString().c_str();
546     ASSERT_FALSE(mConfig.mOutputFormat->findString(KEY_VENDOR_STRING, &vendorString))
547             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
548 }
549 
TEST_F(CCodecConfigTest,SetPixelAspectRatio)550 TEST_F(CCodecConfigTest, SetPixelAspectRatio) {
551     init(C2Component::DOMAIN_VIDEO, C2Component::KIND_DECODER, MIMETYPE_VIDEO_AVC);
552 
553     ASSERT_EQ(OK, mConfig.initialize(mReflector, mConfigurable));
554 
555     sp<AMessage> format{new AMessage};
556     format->setInt32(KEY_PIXEL_ASPECT_RATIO_WIDTH, 12);
557     format->setInt32(KEY_PIXEL_ASPECT_RATIO_HEIGHT, 11);
558 
559     std::vector<std::unique_ptr<C2Param>> configUpdate;
560     ASSERT_EQ(OK, mConfig.getConfigUpdateFromSdkParams(
561             mConfigurable, format, D::ALL, C2_MAY_BLOCK, &configUpdate));
562 
563     ASSERT_EQ(1u, configUpdate.size());
564     C2StreamPixelAspectRatioInfo::output *par =
565         FindParam<std::remove_pointer<decltype(par)>::type>(configUpdate);
566     ASSERT_NE(nullptr, par);
567     ASSERT_EQ(12, par->width);
568     ASSERT_EQ(11, par->height);
569 }
570 
TEST_F(CCodecConfigTest,PixelAspectRatioUpdate)571 TEST_F(CCodecConfigTest, PixelAspectRatioUpdate) {
572     init(C2Component::DOMAIN_VIDEO, C2Component::KIND_DECODER, MIMETYPE_VIDEO_AVC);
573 
574     ASSERT_EQ(OK, mConfig.initialize(mReflector, mConfigurable));
575 
576     std::vector<std::unique_ptr<C2Param>> configUpdate;
577     C2StreamPixelAspectRatioInfo::output par(0u, 12, 11);
578     configUpdate.push_back(C2Param::Copy(par));
579 
580     ASSERT_TRUE(mConfig.updateConfiguration(configUpdate, D::ALL));
581 
582     int32_t parWidth{0};
583     ASSERT_TRUE(mConfig.mOutputFormat->findInt32(KEY_PIXEL_ASPECT_RATIO_WIDTH, &parWidth))
584             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
585     ASSERT_EQ(12, parWidth);
586     ASSERT_FALSE(mConfig.mInputFormat->findInt32(KEY_PIXEL_ASPECT_RATIO_WIDTH, &parWidth))
587             << "mInputFormat = " << mConfig.mInputFormat->debugString().c_str();
588 
589     int32_t parHeight{0};
590     ASSERT_TRUE(mConfig.mOutputFormat->findInt32(KEY_PIXEL_ASPECT_RATIO_HEIGHT, &parHeight))
591             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
592     ASSERT_EQ(11, parHeight);
593     ASSERT_FALSE(mConfig.mInputFormat->findInt32(KEY_PIXEL_ASPECT_RATIO_HEIGHT, &parHeight))
594             << "mInputFormat = " << mConfig.mInputFormat->debugString().c_str();
595 }
596 
TEST_F(CCodecConfigTest,DataspaceUpdate)597 TEST_F(CCodecConfigTest, DataspaceUpdate) {
598     init(C2Component::DOMAIN_VIDEO, C2Component::KIND_ENCODER, MIMETYPE_VIDEO_AVC);
599 
600     ASSERT_EQ(OK, mConfig.initialize(mReflector, mConfigurable));
601     class InputSurfaceStub : public InputSurfaceWrapper {
602     public:
603         ~InputSurfaceStub() override = default;
604         status_t connect(const std::shared_ptr<Codec2Client::Component> &) override {
605             return OK;
606         }
607         void disconnect() override {}
608         status_t start() override { return OK; }
609         status_t signalEndOfInputStream() override { return OK; }
610         status_t configure(Config &) override { return OK; }
611     };
612     mConfig.mInputSurface = std::make_shared<InputSurfaceStub>();
613 
614     sp<AMessage> format{new AMessage};
615     format->setInt32(KEY_COLOR_RANGE, COLOR_RANGE_LIMITED);
616     format->setInt32(KEY_COLOR_STANDARD, COLOR_STANDARD_BT709);
617     format->setInt32(KEY_COLOR_TRANSFER, COLOR_TRANSFER_SDR_VIDEO);
618     format->setInt32(KEY_BIT_RATE, 100);
619 
620     std::vector<std::unique_ptr<C2Param>> configUpdate;
621     ASSERT_EQ(OK, mConfig.getConfigUpdateFromSdkParams(
622             mConfigurable, format, D::ALL, C2_MAY_BLOCK, &configUpdate));
623     ASSERT_TRUE(mConfig.updateConfiguration(configUpdate, D::ALL));
624 
625     int32_t range{0};
626     ASSERT_TRUE(mConfig.mOutputFormat->findInt32(KEY_COLOR_RANGE, &range))
627             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
628     EXPECT_EQ(COLOR_RANGE_LIMITED, range)
629             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
630 
631     int32_t standard{0};
632     ASSERT_TRUE(mConfig.mOutputFormat->findInt32(KEY_COLOR_STANDARD, &standard))
633             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
634     EXPECT_EQ(COLOR_STANDARD_BT709, standard)
635             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
636 
637     int32_t transfer{0};
638     ASSERT_TRUE(mConfig.mOutputFormat->findInt32(KEY_COLOR_TRANSFER, &transfer))
639             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
640     EXPECT_EQ(COLOR_TRANSFER_SDR_VIDEO, transfer)
641             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
642 
643     mConfig.mInputSurface->setDataSpace(HAL_DATASPACE_BT2020_PQ);
644 
645     // Dataspace from input surface should override the configured setting
646     mConfig.updateFormats(D::ALL);
647 
648     ASSERT_TRUE(mConfig.mOutputFormat->findInt32(KEY_COLOR_RANGE, &range))
649             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
650     EXPECT_EQ(COLOR_RANGE_FULL, range)
651             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
652 
653     ASSERT_TRUE(mConfig.mOutputFormat->findInt32(KEY_COLOR_STANDARD, &standard))
654             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
655     EXPECT_EQ(COLOR_STANDARD_BT2020, standard)
656             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
657 
658     ASSERT_TRUE(mConfig.mOutputFormat->findInt32(KEY_COLOR_TRANSFER, &transfer))
659             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
660     EXPECT_EQ(COLOR_TRANSFER_ST2084, transfer)
661             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
662 
663     // Simulate bitrate update
664     format = new AMessage;
665     format->setInt32(KEY_BIT_RATE, 200);
666     configUpdate.clear();
667     ASSERT_EQ(OK, mConfig.getConfigUpdateFromSdkParams(
668             mConfigurable, format, D::ALL, C2_MAY_BLOCK, &configUpdate));
669     ASSERT_EQ(OK, mConfig.setParameters(mConfigurable, configUpdate, C2_MAY_BLOCK));
670 
671     // Color information should remain the same
672     mConfig.updateFormats(D::ALL);
673 
674     ASSERT_TRUE(mConfig.mOutputFormat->findInt32(KEY_COLOR_RANGE, &range))
675             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
676     EXPECT_EQ(COLOR_RANGE_FULL, range)
677             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
678 
679     ASSERT_TRUE(mConfig.mOutputFormat->findInt32(KEY_COLOR_STANDARD, &standard))
680             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
681     EXPECT_EQ(COLOR_STANDARD_BT2020, standard)
682             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
683 
684     ASSERT_TRUE(mConfig.mOutputFormat->findInt32(KEY_COLOR_TRANSFER, &transfer))
685             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
686     EXPECT_EQ(COLOR_TRANSFER_ST2084, transfer)
687             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
688 }
689 
690 typedef std::tuple<std::string, C2Config::profile_t, int32_t> HdrProfilesParams;
691 
692 class HdrProfilesTest
693     : public CCodecConfigTest,
694       public ::testing::WithParamInterface<HdrProfilesParams> {
695 };
696 
TEST_P(HdrProfilesTest,SetFromSdk)697 TEST_P(HdrProfilesTest, SetFromSdk) {
698     HdrProfilesParams params = GetParam();
699     std::string mediaType = std::get<0>(params);
700     C2Config::profile_t c2Profile = std::get<1>(params);
701     int32_t sdkProfile = std::get<2>(params);
702 
703     init(C2Component::DOMAIN_VIDEO, C2Component::KIND_ENCODER, mediaType.c_str());
704 
705     ASSERT_EQ(OK, mConfig.initialize(mReflector, mConfigurable));
706 
707     sp<AMessage> format{new AMessage};
708     format->setInt32(KEY_PROFILE, sdkProfile);
709 
710     std::vector<std::unique_ptr<C2Param>> configUpdate;
711     ASSERT_EQ(OK, mConfig.getConfigUpdateFromSdkParams(
712             mConfigurable, format, D::ALL, C2_MAY_BLOCK, &configUpdate));
713 
714     ASSERT_EQ(1u, configUpdate.size());
715     C2StreamProfileLevelInfo::input *pl =
716         FindParam<std::remove_pointer<decltype(pl)>::type>(configUpdate);
717     ASSERT_NE(nullptr, pl);
718     ASSERT_EQ(c2Profile, pl->profile);
719 }
720 
721 HdrProfilesParams kHdrProfilesParams[] = {
722     std::make_tuple(MIMETYPE_VIDEO_HEVC, PROFILE_HEVC_MAIN_10, HEVCProfileMain10HDR10),
723     std::make_tuple(MIMETYPE_VIDEO_HEVC, PROFILE_HEVC_MAIN_10, HEVCProfileMain10HDR10Plus),
724     std::make_tuple(MIMETYPE_VIDEO_VP9,  PROFILE_VP9_2,        VP9Profile2HDR),
725     std::make_tuple(MIMETYPE_VIDEO_VP9,  PROFILE_VP9_2,        VP9Profile2HDR10Plus),
726     std::make_tuple(MIMETYPE_VIDEO_VP9,  PROFILE_VP9_3,        VP9Profile3HDR),
727     std::make_tuple(MIMETYPE_VIDEO_VP9,  PROFILE_VP9_3,        VP9Profile3HDR10Plus),
728     std::make_tuple(MIMETYPE_VIDEO_AV1,  PROFILE_AV1_0,        AV1ProfileMain10HDR10),
729     std::make_tuple(MIMETYPE_VIDEO_AV1,  PROFILE_AV1_0,        AV1ProfileMain10HDR10Plus),
730 };
731 
732 INSTANTIATE_TEST_SUITE_P(
733         CCodecConfig,
734         HdrProfilesTest,
735         ::testing::ValuesIn(kHdrProfilesParams));
736 
TEST_F(CCodecConfigTest,SetRegionOfInterestParams)737 TEST_F(CCodecConfigTest, SetRegionOfInterestParams) {
738     if (!android::media::codec::provider_->region_of_interest()
739         || !android::media::codec::provider_->region_of_interest_support()) {
740         GTEST_SKIP() << "Skipping the test as region_of_interest flags are not enabled.\n";
741     }
742 
743     init(C2Component::DOMAIN_VIDEO, C2Component::KIND_ENCODER, MIMETYPE_VIDEO_VP9);
744 
745     ASSERT_EQ(OK, mConfig.initialize(mReflector, mConfigurable));
746 
747     const int kWidth = 32;
748     const int kHeight = 32;
749     const int kNumBlocks = ((kWidth + 15) / 16) * ((kHeight + 15) / 16);
750     int8_t mapInfo[kNumBlocks] = {-1, 0, 1, 1};
751     int top[kNumBlocks] = {0, 0, 16, 16};
752     int left[kNumBlocks] = {0, 16, 0, 16};
753     int bottom[kNumBlocks] = {16, 16, 32, 32};
754     int right[kNumBlocks] = {16, 32, 16, 32};
755     sp<AMessage> format{new AMessage};
756     format->setInt32(KEY_WIDTH, kWidth);
757     format->setInt32(KEY_HEIGHT, kHeight);
758     AString val;
759     for (int i = 0; i < kNumBlocks; i++) {
760         val.append(AStringPrintf("%d,%d-%d,%d=%d;", top[i], left[i], bottom[i],
761                                  right[i], mapInfo[i]));
762     }
763     format->setString(PARAMETER_KEY_QP_OFFSET_RECTS, val);
764 
765     std::vector<std::unique_ptr<C2Param>> configUpdate;
766     ASSERT_EQ(OK, mConfig.getConfigUpdateFromSdkParams(mConfigurable, format, D::CONFIG,
767                                                        C2_MAY_BLOCK, &configUpdate));
768 
769     EXPECT_EQ(1u, configUpdate.size());
770 
771     C2StreamQpOffsetRects::output* qpRectParam =
772             FindParam<std::remove_pointer<decltype(qpRectParam)>::type>(configUpdate);
773     ASSERT_NE(nullptr, qpRectParam);
774     ASSERT_EQ(kNumBlocks, qpRectParam->flexCount());
775     for (auto i = 0; i < kNumBlocks; i++) {
776         EXPECT_EQ(mapInfo[i], (int8_t)qpRectParam->m.values[i].qpOffset)
777                 << "qp offset for index " << i << " is not as expected ";
778         EXPECT_EQ(left[i], qpRectParam->m.values[i].left)
779                 << "left for index " << i << " is not as expected ";
780         EXPECT_EQ(top[i], qpRectParam->m.values[i].top)
781                 << "top for index " << i << " is not as expected ";
782         EXPECT_EQ(right[i] - left[i], qpRectParam->m.values[i].width)
783                 << "width for index " << i << " is not as expected ";
784         EXPECT_EQ(bottom[i] - top[i], qpRectParam->m.values[i].height)
785                 << "height for index " << i << " is not as expected ";
786     }
787 }
788 
789 static
queryGlobalResources(std::shared_ptr<Codec2Client::Configurable> & configurable,std::vector<C2SystemResourceStruct> & resources)790 c2_status_t queryGlobalResources(std::shared_ptr<Codec2Client::Configurable>& configurable,
791                                  std::vector<C2SystemResourceStruct>& resources) {
792     std::vector<std::unique_ptr<C2Param>> heapParams;
793     c2_status_t c2err = configurable->query(
794             {},
795             {C2ResourcesCapacityTuning::PARAM_TYPE, C2ResourcesExcludedTuning::PARAM_TYPE},
796             C2_MAY_BLOCK, &heapParams);
797 
798     if (c2err == C2_OK && heapParams.size() == 2u) {
799         // Construct Globally available resources now.
800         // Get the total capacity first.
801         const C2ResourcesCapacityTuning* systemCapacity =
802                 C2ResourcesCapacityTuning::From(heapParams[0].get());
803         if (systemCapacity && *systemCapacity) {
804             for (size_t i = 0; i < systemCapacity->flexCount(); ++i) {
805                 resources.push_back(systemCapacity->m.values[i]);
806                 ALOGI("System Resource[%zu]{%u %d %jd}", i,
807                       systemCapacity->m.values[i].id,
808                       systemCapacity->m.values[i].kind,
809                       systemCapacity->m.values[i].amount);
810             }
811         } else {
812             ALOGE("Failed to get C2ResourcesCapacityTuning");
813             return C2_BAD_VALUE;
814         }
815 
816         // Get the excluded resource info.
817         // The available resource should exclude this, if there are any.
818         const C2ResourcesExcludedTuning* systemExcluded =
819                 C2ResourcesExcludedTuning::From(heapParams[1].get());
820         if (systemExcluded && *systemExcluded) {
821             for (size_t i = 0; i < systemExcluded->flexCount(); ++i) {
822                 const C2SystemResourceStruct& resource =
823                     systemExcluded->m.values[i];
824                 ALOGI("Excluded Resource[%zu]{%u %d %jd}", i,
825                       resource.id, resource.kind, resource.amount);
826                 uint64_t excluded = (resource.kind == CONST) ? resource.amount : 0;
827                 auto found = std::find_if(resources.begin(),
828                                           resources.end(),
829                                           [resource](const C2SystemResourceStruct& item) {
830                                               return item.id == resource.id; });
831 
832                 if (found != resources.end()) {
833                     // Take off excluded resources from available resources.
834                     if (found->amount >= excluded) {
835                         found->amount -= excluded;
836                     } else {
837                        ALOGE("Excluded resources(%jd) can't be more than Available resources(%jd)",
838                              excluded, found->amount);
839                        return C2_BAD_VALUE;
840                     }
841                 } else {
842                     ALOGE("Failed to find the resource [%u]", resource.id);
843                     return C2_BAD_VALUE;
844                 }
845             }
846         } else {
847             ALOGE("Failed to get C2ResourcesExcludedTuning");
848             return C2_BAD_VALUE;
849         }
850 
851     } else if (c2err == C2_OK) {
852         ALOGE("Expected query results for 2 params, but got %zu", heapParams.size());
853         return C2_BAD_VALUE;
854     } else {
855         ALOGE("Failed to query component store for system resources: %d", c2err);
856         return c2err;
857     }
858 
859     size_t index = 0;
860     for (const auto& resource : resources) {
861         ALOGI("Globally Available System Resource[%zu]{%u %d %jd}", index++,
862               resource.id, resource.kind, resource.amount);
863     }
864     return c2err;
865 }
866 
TEST_F(CCodecConfigTest,QuerySystemResources)867 TEST_F(CCodecConfigTest, QuerySystemResources) {
868     init(C2Component::DOMAIN_VIDEO, C2Component::KIND_DECODER, MIMETYPE_VIDEO_AVC);
869 
870     ASSERT_EQ(OK, mConfig.initialize(mReflector, mConfigurable));
871 
872     std::vector<C2SystemResourceStruct> resources;
873     ASSERT_EQ(C2_OK, queryGlobalResources(mConfigurable, resources));
874 
875     // Make sure that what we got from the query is the same as what was added.
876     ASSERT_TRUE(validateSystemResources(resources));
877 }
878 
879 } // namespace android
880