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*> ¶ms,
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 ¶m, const std::string &str) 165 auto allocSharedString = [](const auto ¶m, 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> ¶m : 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