1 /*
2 * Copyright (C) 2024 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 //#define LOG_NDEBUG 0
18 #define LOG_TAG "C2SoftApvEnc"
19 #include <log/log.h>
20
21 #include <android_media_swcodec_flags.h>
22
23 #include <media/hardware/VideoAPI.h>
24 #include <media/stagefright/MediaDefs.h>
25 #include <media/stagefright/MediaErrors.h>
26 #include <media/stagefright/MetaData.h>
27 #include <media/stagefright/foundation/AUtils.h>
28
29 #include <C2Debug.h>
30 #include <C2PlatformSupport.h>
31 #include <Codec2BufferUtils.h>
32 #include <Codec2CommonUtils.h>
33 #include <Codec2Mapper.h>
34 #include <SimpleC2Interface.h>
35 #include <media/stagefright/foundation/ABitReader.h>
36 #include <util/C2InterfaceHelper.h>
37 #include <cmath>
38 #include "C2SoftApvEnc.h"
39 #include "isAtLeastRelease.h"
40
41 namespace android {
42
43 namespace {
44
45 constexpr char COMPONENT_NAME[] = "c2.android.apv.encoder";
46 constexpr uint32_t kMinOutBufferSize = 524288;
47 constexpr uint32_t kMaxBitstreamBufSize = 16 * 1024 * 1024;
48 constexpr int32_t kApvQpMin = 0;
49 constexpr int32_t kApvQpMax = 51;
50 constexpr int32_t kApvDefaultQP = 32;
51
52 #define PROFILE_APV_DEFAULT 0
53 #define LEVEL_APV_DEFAULT 0
54 #define MAX_NUM_FRMS (1) // supports only 1-frame input
55
56 } // namespace
57
58 class C2SoftApvEnc::IntfImpl : public SimpleInterface<void>::BaseParams {
59 public:
IntfImpl(const std::shared_ptr<C2ReflectorHelper> & helper)60 explicit IntfImpl(const std::shared_ptr<C2ReflectorHelper>& helper)
61 : SimpleInterface<void>::BaseParams(helper, COMPONENT_NAME, C2Component::KIND_ENCODER,
62 C2Component::DOMAIN_VIDEO, MEDIA_MIMETYPE_VIDEO_APV) {
63 noPrivateBuffers();
64 noInputReferences();
65 noOutputReferences();
66 noTimeStretch();
67 setDerivedInstance(this);
68
69 addParameter(DefineParam(mAttrib, C2_PARAMKEY_COMPONENT_ATTRIBUTES)
70 .withConstValue(new C2ComponentAttributesSetting(
71 C2Component::ATTRIB_IS_TEMPORAL))
72 .build());
73
74 addParameter(DefineParam(mUsage, C2_PARAMKEY_INPUT_STREAM_USAGE)
75 .withConstValue(new C2StreamUsageTuning::input(
76 0u, (uint64_t)C2MemoryUsage::CPU_READ))
77 .build());
78
79 // matches size limits in codec library
80 addParameter(DefineParam(mSize, C2_PARAMKEY_PICTURE_SIZE)
81 .withDefault(new C2StreamPictureSizeInfo::input(0u, 320, 240))
82 .withFields({
83 C2F(mSize, width).inRange(2, 4096, 2),
84 C2F(mSize, height).inRange(2, 4096, 2),
85 })
86 .withSetter(SizeSetter)
87 .build());
88
89 addParameter(DefineParam(mBitrate, C2_PARAMKEY_BITRATE)
90 .withDefault(new C2StreamBitrateInfo::output(0u, 512000))
91 .withFields({C2F(mBitrate, value).inRange(512000, 240000000)})
92 .withSetter(BitrateSetter)
93 .build());
94
95 addParameter(DefineParam(mFrameRate, C2_PARAMKEY_FRAME_RATE)
96 .withDefault(new C2StreamFrameRateInfo::output(0u, 15.))
97 .withFields({C2F(mFrameRate, value).greaterThan(0.)})
98 .withSetter(Setter<decltype(*mFrameRate)>::StrictValueWithNoDeps)
99 .build());
100
101 addParameter(DefineParam(mQuality, C2_PARAMKEY_QUALITY)
102 .withDefault(new C2StreamQualityTuning::output(0u, 40))
103 .withFields({C2F(mQuality, value).inRange(0, 100)})
104 .withSetter(Setter<decltype(*mQuality)>::NonStrictValueWithNoDeps)
105 .build());
106
107 addParameter(
108 DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL)
109 .withDefault(new C2StreamProfileLevelInfo::output(
110 0u, C2Config::PROFILE_APV_422_10, LEVEL_APV_1_BAND_0))
111 .withFields({
112 C2F(mProfileLevel, profile).oneOf({C2Config::PROFILE_APV_422_10}),
113 C2F(mProfileLevel, level)
114 .oneOf({
115 C2Config::LEVEL_APV_1_BAND_0,
116 C2Config::LEVEL_APV_1_1_BAND_0,
117 C2Config::LEVEL_APV_2_BAND_0,
118 C2Config::LEVEL_APV_2_1_BAND_0,
119 C2Config::LEVEL_APV_3_BAND_0,
120 C2Config::LEVEL_APV_3_1_BAND_0,
121 C2Config::LEVEL_APV_4_BAND_0,
122 C2Config::LEVEL_APV_4_1_BAND_0,
123 C2Config::LEVEL_APV_5_BAND_0,
124 C2Config::LEVEL_APV_5_1_BAND_0,
125 C2Config::LEVEL_APV_6_BAND_0,
126 C2Config::LEVEL_APV_6_1_BAND_0,
127 C2Config::LEVEL_APV_7_BAND_0,
128 C2Config::LEVEL_APV_7_1_BAND_0,
129 C2Config::LEVEL_APV_1_BAND_1,
130 C2Config::LEVEL_APV_1_1_BAND_1,
131 C2Config::LEVEL_APV_2_BAND_1,
132 C2Config::LEVEL_APV_2_1_BAND_1,
133 C2Config::LEVEL_APV_3_BAND_1,
134 C2Config::LEVEL_APV_3_1_BAND_1,
135 C2Config::LEVEL_APV_4_BAND_1,
136 C2Config::LEVEL_APV_4_1_BAND_1,
137 C2Config::LEVEL_APV_5_BAND_1,
138 C2Config::LEVEL_APV_5_1_BAND_1,
139 C2Config::LEVEL_APV_6_BAND_1,
140 C2Config::LEVEL_APV_6_1_BAND_1,
141 C2Config::LEVEL_APV_7_BAND_1,
142 C2Config::LEVEL_APV_7_1_BAND_1,
143 C2Config::LEVEL_APV_1_BAND_2,
144 C2Config::LEVEL_APV_1_1_BAND_2,
145 C2Config::LEVEL_APV_2_BAND_2,
146 C2Config::LEVEL_APV_2_1_BAND_2,
147 C2Config::LEVEL_APV_3_BAND_2,
148 C2Config::LEVEL_APV_3_1_BAND_2,
149 C2Config::LEVEL_APV_4_BAND_2,
150 C2Config::LEVEL_APV_4_1_BAND_2,
151 C2Config::LEVEL_APV_5_BAND_2,
152 C2Config::LEVEL_APV_5_1_BAND_2,
153 C2Config::LEVEL_APV_6_BAND_2,
154 C2Config::LEVEL_APV_6_1_BAND_2,
155 C2Config::LEVEL_APV_7_BAND_2,
156 C2Config::LEVEL_APV_7_1_BAND_2,
157 C2Config::LEVEL_APV_1_BAND_3,
158 C2Config::LEVEL_APV_1_1_BAND_3,
159 C2Config::LEVEL_APV_2_BAND_3,
160 C2Config::LEVEL_APV_2_1_BAND_3,
161 C2Config::LEVEL_APV_3_BAND_3,
162 C2Config::LEVEL_APV_3_1_BAND_3,
163 C2Config::LEVEL_APV_4_BAND_3,
164 C2Config::LEVEL_APV_4_1_BAND_3,
165 C2Config::LEVEL_APV_5_BAND_3,
166 C2Config::LEVEL_APV_5_1_BAND_3,
167 C2Config::LEVEL_APV_6_BAND_3,
168 C2Config::LEVEL_APV_6_1_BAND_3,
169 C2Config::LEVEL_APV_7_BAND_3,
170 C2Config::LEVEL_APV_7_1_BAND_3,
171 }),
172 })
173 .withSetter(ProfileLevelSetter, mSize, mFrameRate, mBitrate)
174 .build());
175
176 addParameter(DefineParam(mColorAspects, C2_PARAMKEY_COLOR_ASPECTS)
177 .withDefault(new C2StreamColorAspectsInfo::input(
178 0u, C2Color::RANGE_UNSPECIFIED, C2Color::PRIMARIES_UNSPECIFIED,
179 C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED))
180 .withFields({C2F(mColorAspects, range)
181 .inRange(C2Color::RANGE_UNSPECIFIED,
182 C2Color::RANGE_OTHER),
183 C2F(mColorAspects, primaries)
184 .inRange(C2Color::PRIMARIES_UNSPECIFIED,
185 C2Color::PRIMARIES_OTHER),
186 C2F(mColorAspects, transfer)
187 .inRange(C2Color::TRANSFER_UNSPECIFIED,
188 C2Color::TRANSFER_OTHER),
189 C2F(mColorAspects, matrix)
190 .inRange(C2Color::MATRIX_UNSPECIFIED,
191 C2Color::MATRIX_OTHER)})
192 .withSetter(ColorAspectsSetter)
193 .build());
194
195 addParameter(DefineParam(mCodedColorAspects, C2_PARAMKEY_VUI_COLOR_ASPECTS)
196 .withDefault(new C2StreamColorAspectsInfo::output(
197 0u, C2Color::RANGE_LIMITED, C2Color::PRIMARIES_UNSPECIFIED,
198 C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED))
199 .withFields({C2F(mCodedColorAspects, range)
200 .inRange(C2Color::RANGE_UNSPECIFIED,
201 C2Color::RANGE_OTHER),
202 C2F(mCodedColorAspects, primaries)
203 .inRange(C2Color::PRIMARIES_UNSPECIFIED,
204 C2Color::PRIMARIES_OTHER),
205 C2F(mCodedColorAspects, transfer)
206 .inRange(C2Color::TRANSFER_UNSPECIFIED,
207 C2Color::TRANSFER_OTHER),
208 C2F(mCodedColorAspects, matrix)
209 .inRange(C2Color::MATRIX_UNSPECIFIED,
210 C2Color::MATRIX_OTHER)})
211 .withSetter(CodedColorAspectsSetter, mColorAspects)
212 .build());
213 std::vector<uint32_t> pixelFormats = {
214 HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED,
215 HAL_PIXEL_FORMAT_YCBCR_420_888,
216 };
217 if (isHalPixelFormatSupported((AHardwareBuffer_Format)HAL_PIXEL_FORMAT_YCBCR_P010)) {
218 pixelFormats.push_back(HAL_PIXEL_FORMAT_YCBCR_P010);
219 }
220 if (isHalPixelFormatSupported((AHardwareBuffer_Format)AHARDWAREBUFFER_FORMAT_YCbCr_P210)) {
221 pixelFormats.push_back(AHARDWAREBUFFER_FORMAT_YCbCr_P210);
222 }
223 addParameter(DefineParam(mPixelFormat, C2_PARAMKEY_PIXEL_FORMAT)
224 .withDefault(new C2StreamPixelFormatInfo::input(
225 0u, HAL_PIXEL_FORMAT_YCBCR_420_888))
226 .withFields({C2F(mPixelFormat, value).oneOf({pixelFormats})})
227 .withSetter((Setter<decltype(*mPixelFormat)>::StrictValueWithNoDeps))
228 .build());
229 }
230
BitrateSetter(bool mayBlock,C2P<C2StreamBitrateInfo::output> & me)231 static C2R BitrateSetter(bool mayBlock, C2P<C2StreamBitrateInfo::output>& me) {
232 (void)mayBlock;
233 C2R res = C2R::Ok();
234 if (me.v.value < 1000000) {
235 me.set().value = 1000000;
236 }
237 return res;
238 }
239
SizeSetter(bool mayBlock,const C2P<C2StreamPictureSizeInfo::input> & oldMe,C2P<C2StreamPictureSizeInfo::input> & me)240 static C2R SizeSetter(bool mayBlock, const C2P<C2StreamPictureSizeInfo::input>& oldMe,
241 C2P<C2StreamPictureSizeInfo::input>& me) {
242 (void)mayBlock;
243 C2R res = C2R::Ok();
244 if (!me.F(me.v.width).supportsAtAll(me.v.width)) {
245 res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.width)));
246 me.set().width = oldMe.v.width;
247 }
248 if (!me.F(me.v.height).supportsAtAll(me.v.height)) {
249 res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.height)));
250 me.set().height = oldMe.v.height;
251 }
252 return res;
253 }
254
ProfileLevelSetter(bool mayBlock,C2P<C2StreamProfileLevelInfo::output> & me,const C2P<C2StreamPictureSizeInfo::input> & size,const C2P<C2StreamFrameRateInfo::output> & frameRate,const C2P<C2StreamBitrateInfo::output> & bitrate)255 static C2R ProfileLevelSetter(bool mayBlock, C2P<C2StreamProfileLevelInfo::output>& me,
256 const C2P<C2StreamPictureSizeInfo::input>& size,
257 const C2P<C2StreamFrameRateInfo::output>& frameRate,
258 const C2P<C2StreamBitrateInfo::output>& bitrate) {
259 (void)mayBlock;
260 if (!me.F(me.v.profile).supportsAtAll(me.v.profile)) {
261 me.set().profile = C2Config::PROFILE_APV_422_10;
262 }
263 if (!me.F(me.v.level).supportsAtAll(me.v.level)) {
264 me.set().level = LEVEL_APV_1_BAND_0;
265 }
266
267 int32_t bandIdc = me.v.level <= LEVEL_APV_7_1_BAND_0 ? 0 :
268 me.v.level <= LEVEL_APV_7_1_BAND_1 ? 1 :
269 me.v.level <= LEVEL_APV_7_1_BAND_2 ? 2 : 3;
270
271 me.set().level = decisionApvLevel(size.v.width, size.v.height, frameRate.v.value,
272 (uint64_t)bitrate.v.value, bandIdc);
273 return C2R::Ok();
274 }
275
ColorAspectsSetter(bool mayBlock,C2P<C2StreamColorAspectsInfo::input> & me)276 static C2R ColorAspectsSetter(bool mayBlock, C2P<C2StreamColorAspectsInfo::input>& me) {
277 (void)mayBlock;
278 if (me.v.range > C2Color::RANGE_OTHER) {
279 me.set().range = C2Color::RANGE_OTHER;
280 }
281 if (me.v.primaries > C2Color::PRIMARIES_OTHER) {
282 me.set().primaries = C2Color::PRIMARIES_OTHER;
283 }
284 if (me.v.transfer > C2Color::TRANSFER_OTHER) {
285 me.set().transfer = C2Color::TRANSFER_OTHER;
286 }
287 if (me.v.matrix > C2Color::MATRIX_OTHER) {
288 me.set().matrix = C2Color::MATRIX_OTHER;
289 }
290 return C2R::Ok();
291 }
292
CodedColorAspectsSetter(bool mayBlock,C2P<C2StreamColorAspectsInfo::output> & me,const C2P<C2StreamColorAspectsInfo::input> & coded)293 static C2R CodedColorAspectsSetter(bool mayBlock, C2P<C2StreamColorAspectsInfo::output>& me,
294 const C2P<C2StreamColorAspectsInfo::input>& coded) {
295 (void)mayBlock;
296 me.set().range = coded.v.range;
297 me.set().primaries = coded.v.primaries;
298 me.set().transfer = coded.v.transfer;
299 me.set().matrix = coded.v.matrix;
300 return C2R::Ok();
301 }
302
decisionApvLevel(int32_t width,int32_t height,int32_t fps,uint64_t bitrate,int32_t band)303 static C2Config::level_t decisionApvLevel(int32_t width, int32_t height, int32_t fps,
304 uint64_t bitrate, int32_t band) {
305 C2Config::level_t level = C2Config::LEVEL_APV_1_BAND_0;
306 struct LevelLimits {
307 C2Config::level_t level;
308 uint64_t samplesPerSec;
309 uint64_t kbpsOfBand;
310 };
311
312 constexpr LevelLimits kLimitsBand0[] = {
313 {LEVEL_APV_1_BAND_0, 3'041'280, 7'000},
314 {LEVEL_APV_1_1_BAND_0, 6'082'560, 14'000},
315 {LEVEL_APV_2_BAND_0, 15'667'200, 36'000},
316 {LEVEL_APV_2_1_BAND_0, 31'334'400, 71'000},
317 {LEVEL_APV_3_BAND_0, 66'846'720, 101'000},
318 {LEVEL_APV_3_1_BAND_0, 133'693'440, 201'000},
319 {LEVEL_APV_4_BAND_0, 265'420'800, 401'000},
320 {LEVEL_APV_4_1_BAND_0, 530'841'600, 780'000},
321 {LEVEL_APV_5_BAND_0, 1'061'683'200, 1'560'000},
322 {LEVEL_APV_5_1_BAND_0, 2'123'366'400, 3'324'000},
323 {LEVEL_APV_6_BAND_0, 4'777'574'400, 6'648'000},
324 {LEVEL_APV_6_1_BAND_0, 8'493'465'600, 13'296'000},
325 {LEVEL_APV_7_BAND_0, 16'986'931'200, 26'592'000},
326 {LEVEL_APV_7_1_BAND_0, 33'973'862'400, 53'184'000},
327 };
328
329 constexpr LevelLimits kLimitsBand1[] = {
330 {LEVEL_APV_1_BAND_1, 3'041'280, 11'000},
331 {LEVEL_APV_1_1_BAND_1, 6'082'560, 21'000},
332 {LEVEL_APV_2_BAND_1, 15'667'200, 53'000},
333 {LEVEL_APV_2_1_BAND_1, 31'334'400, 106'00},
334 {LEVEL_APV_3_BAND_1, 66'846'720, 151'000},
335 {LEVEL_APV_3_1_BAND_1, 133'693'440, 301'000},
336 {LEVEL_APV_4_BAND_1, 265'420'800, 602'000},
337 {LEVEL_APV_4_1_BAND_1, 530'841'600, 1'170'000},
338 {LEVEL_APV_5_BAND_1, 1'061'683'200, 2'340'000},
339 {LEVEL_APV_5_1_BAND_1, 2'123'366'400, 4'986'000},
340 {LEVEL_APV_6_BAND_1, 4'777'574'400, 9'972'000},
341 {LEVEL_APV_6_1_BAND_1, 8'493'465'600, 19'944'000},
342 {LEVEL_APV_7_BAND_1, 16'986'931'200, 39'888'000},
343 {LEVEL_APV_7_1_BAND_1, 33'973'862'400, 79'776'000},
344 };
345
346 constexpr LevelLimits kLimitsBand2[] = {
347 {LEVEL_APV_1_BAND_2, 3'041'280, 14'000},
348 {LEVEL_APV_1_1_BAND_2, 6'082'560, 28'000},
349 {LEVEL_APV_2_BAND_2, 15'667'200, 71'000},
350 {LEVEL_APV_2_1_BAND_2, 31'334'400, 141'000},
351 {LEVEL_APV_3_BAND_2, 66'846'720, 201'000},
352 {LEVEL_APV_3_1_BAND_2, 133'693'440, 401'000},
353 {LEVEL_APV_4_BAND_2, 265'420'800, 780'000},
354 {LEVEL_APV_4_1_BAND_2, 530'841'600, 1'560'000},
355 {LEVEL_APV_5_BAND_2, 1'061'683'200, 3'324'000},
356 {LEVEL_APV_5_1_BAND_2, 2'123'366'400, 6'648'000},
357 {LEVEL_APV_6_BAND_2, 4'777'574'400, 13'296'000},
358 {LEVEL_APV_6_1_BAND_2, 8'493'465'600, 26'592'000},
359 {LEVEL_APV_7_BAND_2, 16'986'931'200, 53'184'000},
360 {LEVEL_APV_7_1_BAND_2, 33'973'862'400, 106'368'000},
361 };
362
363 constexpr LevelLimits kLimitsBand3[] = {
364 {LEVEL_APV_1_BAND_3, 3'041'280, 21'000},
365 {LEVEL_APV_1_1_BAND_3, 6'082'560, 42'000},
366 {LEVEL_APV_2_BAND_3, 15'667'200, 106'000},
367 {LEVEL_APV_2_1_BAND_3, 31'334'400, 212'000},
368 {LEVEL_APV_3_BAND_3, 66'846'720, 301'000},
369 {LEVEL_APV_3_1_BAND_3, 133'693'440, 602'000},
370 {LEVEL_APV_4_BAND_3, 265'420'800, 1'170'000},
371 {LEVEL_APV_4_1_BAND_3, 530'841'600, 2'340'000},
372 {LEVEL_APV_5_BAND_3, 1'061'683'200, 4'986'000},
373 {LEVEL_APV_5_1_BAND_3, 2'123'366'400, 9'972'000},
374 {LEVEL_APV_6_BAND_3, 4'777'574'400, 19'944'000},
375 {LEVEL_APV_6_1_BAND_3, 8'493'465'600, 39'888'000},
376 {LEVEL_APV_7_BAND_3, 16'986'931'200, 79'776'000},
377 {LEVEL_APV_7_1_BAND_3, 33'973'862'400, 159'552'000},
378 };
379
380 uint64_t samplesPerSec = width * height * fps;
381 if (band == 0) {
382 for (const LevelLimits& limit : kLimitsBand0) {
383 if (samplesPerSec <= limit.samplesPerSec && bitrate <= limit.kbpsOfBand * 1000) {
384 level = limit.level;
385 break;
386 }
387 }
388 } else if (band == 1) {
389 for (const LevelLimits& limit : kLimitsBand1) {
390 if (samplesPerSec <= limit.samplesPerSec && bitrate <= limit.kbpsOfBand * 1000) {
391 level = limit.level;
392 break;
393 }
394 }
395 } else if (band == 2) {
396 for (const LevelLimits& limit : kLimitsBand2) {
397 if (samplesPerSec <= limit.samplesPerSec && bitrate <= limit.kbpsOfBand * 1000) {
398 level = limit.level;
399 break;
400 }
401 }
402 } else if (band == 3) {
403 for (const LevelLimits& limit : kLimitsBand3) {
404 if (samplesPerSec <= limit.samplesPerSec && bitrate <= limit.kbpsOfBand * 1000) {
405 level = limit.level;
406 break;
407 }
408 }
409 } else {
410 ALOGE("Invalid band_idc on calculte level");
411 }
412
413 return level;
414 }
415
getProfile_l() const416 uint32_t getProfile_l() const {
417 int32_t profile = PROFILE_UNUSED;
418
419 switch (mProfileLevel->profile) {
420 case C2Config::PROFILE_APV_422_10:
421 profile = 33;
422 break;
423 case C2Config::PROFILE_APV_422_12:
424 profile = 44;
425 break;
426 case C2Config::PROFILE_APV_444_10:
427 profile = 55;
428 break;
429 case C2Config::PROFILE_APV_444_12:
430 profile = 66;
431 break;
432 case C2Config::PROFILE_APV_4444_10:
433 profile = 77;
434 break;
435 case C2Config::PROFILE_APV_4444_12:
436 profile = 88;
437 break;
438 case C2Config::PROFILE_APV_400_10:
439 profile = 99;
440 break;
441 default:
442 ALOGW("Unrecognized profile: %x", mProfileLevel->profile);
443 }
444 return profile;
445 }
446
getLevel_l() const447 uint32_t getLevel_l() const {
448 int32_t level = LEVEL_UNUSED;
449
450 // TODO: Add Band settings
451 switch (mProfileLevel->level) {
452 case C2Config::LEVEL_APV_1_BAND_0:
453 [[fallthrough]];
454 case C2Config::LEVEL_APV_1_BAND_1:
455 [[fallthrough]];
456 case C2Config::LEVEL_APV_1_BAND_2:
457 [[fallthrough]];
458 case C2Config::LEVEL_APV_1_BAND_3:
459 level = 10;
460 break;
461 case C2Config::LEVEL_APV_1_1_BAND_0:
462 [[fallthrough]];
463 case C2Config::LEVEL_APV_1_1_BAND_1:
464 [[fallthrough]];
465 case C2Config::LEVEL_APV_1_1_BAND_2:
466 [[fallthrough]];
467 case C2Config::LEVEL_APV_1_1_BAND_3:
468 level = 11;
469 break;
470 case C2Config::LEVEL_APV_2_BAND_0:
471 [[fallthrough]];
472 case C2Config::LEVEL_APV_2_BAND_1:
473 [[fallthrough]];
474 case C2Config::LEVEL_APV_2_BAND_2:
475 [[fallthrough]];
476 case C2Config::LEVEL_APV_2_BAND_3:
477 level = 20;
478 break;
479 case C2Config::LEVEL_APV_2_1_BAND_0:
480 [[fallthrough]];
481 case C2Config::LEVEL_APV_2_1_BAND_1:
482 [[fallthrough]];
483 case C2Config::LEVEL_APV_2_1_BAND_2:
484 [[fallthrough]];
485 case C2Config::LEVEL_APV_2_1_BAND_3:
486 level = 21;
487 break;
488 case C2Config::LEVEL_APV_3_BAND_0:
489 [[fallthrough]];
490 case C2Config::LEVEL_APV_3_BAND_1:
491 [[fallthrough]];
492 case C2Config::LEVEL_APV_3_BAND_2:
493 [[fallthrough]];
494 case C2Config::LEVEL_APV_3_BAND_3:
495 level = 30;
496 break;
497 case C2Config::LEVEL_APV_3_1_BAND_0:
498 [[fallthrough]];
499 case C2Config::LEVEL_APV_3_1_BAND_1:
500 [[fallthrough]];
501 case C2Config::LEVEL_APV_3_1_BAND_2:
502 [[fallthrough]];
503 case C2Config::LEVEL_APV_3_1_BAND_3:
504 level = 31;
505 break;
506 case C2Config::LEVEL_APV_4_BAND_0:
507 [[fallthrough]];
508 case C2Config::LEVEL_APV_4_BAND_1:
509 [[fallthrough]];
510 case C2Config::LEVEL_APV_4_BAND_2:
511 [[fallthrough]];
512 case C2Config::LEVEL_APV_4_BAND_3:
513 level = 40;
514 break;
515 case C2Config::LEVEL_APV_4_1_BAND_0:
516 [[fallthrough]];
517 case C2Config::LEVEL_APV_4_1_BAND_1:
518 [[fallthrough]];
519 case C2Config::LEVEL_APV_4_1_BAND_2:
520 [[fallthrough]];
521 case C2Config::LEVEL_APV_4_1_BAND_3:
522 level = 41;
523 break;
524 case C2Config::LEVEL_APV_5_BAND_0:
525 [[fallthrough]];
526 case C2Config::LEVEL_APV_5_BAND_1:
527 [[fallthrough]];
528 case C2Config::LEVEL_APV_5_BAND_2:
529 [[fallthrough]];
530 case C2Config::LEVEL_APV_5_BAND_3:
531 level = 50;
532 break;
533 case C2Config::LEVEL_APV_5_1_BAND_0:
534 [[fallthrough]];
535 case C2Config::LEVEL_APV_5_1_BAND_1:
536 [[fallthrough]];
537 case C2Config::LEVEL_APV_5_1_BAND_2:
538 [[fallthrough]];
539 case C2Config::LEVEL_APV_5_1_BAND_3:
540 level = 51;
541 break;
542 case C2Config::LEVEL_APV_6_BAND_0:
543 [[fallthrough]];
544 case C2Config::LEVEL_APV_6_BAND_1:
545 [[fallthrough]];
546 case C2Config::LEVEL_APV_6_BAND_2:
547 [[fallthrough]];
548 case C2Config::LEVEL_APV_6_BAND_3:
549 level = 60;
550 break;
551 case C2Config::LEVEL_APV_6_1_BAND_0:
552 [[fallthrough]];
553 case C2Config::LEVEL_APV_6_1_BAND_1:
554 [[fallthrough]];
555 case C2Config::LEVEL_APV_6_1_BAND_2:
556 [[fallthrough]];
557 case C2Config::LEVEL_APV_6_1_BAND_3:
558 level = 61;
559 break;
560 case C2Config::LEVEL_APV_7_BAND_0:
561 [[fallthrough]];
562 case C2Config::LEVEL_APV_7_BAND_1:
563 [[fallthrough]];
564 case C2Config::LEVEL_APV_7_BAND_2:
565 [[fallthrough]];
566 case C2Config::LEVEL_APV_7_BAND_3:
567 level = 70;
568 break;
569 case C2Config::LEVEL_APV_7_1_BAND_0:
570 [[fallthrough]];
571 case C2Config::LEVEL_APV_7_1_BAND_1:
572 [[fallthrough]];
573 case C2Config::LEVEL_APV_7_1_BAND_2:
574 [[fallthrough]];
575 case C2Config::LEVEL_APV_7_1_BAND_3:
576 level = 71;
577 break;
578 default:
579 ALOGW("Unrecognized level: %x", mProfileLevel->level);
580 }
581 // Convert to APV level_idc according to APV spec
582 return level * 3;
583 }
584
getBandIdc_l() const585 uint32_t getBandIdc_l() const {
586 uint32_t bandIdc = 0;
587
588 switch (mProfileLevel->level) {
589 case C2Config::LEVEL_APV_1_BAND_0:
590 [[fallthrough]];
591 case C2Config::LEVEL_APV_1_1_BAND_0:
592 [[fallthrough]];
593 case C2Config::LEVEL_APV_2_BAND_0:
594 [[fallthrough]];
595 case C2Config::LEVEL_APV_2_1_BAND_0:
596 [[fallthrough]];
597 case C2Config::LEVEL_APV_3_BAND_0:
598 [[fallthrough]];
599 case C2Config::LEVEL_APV_3_1_BAND_0:
600 [[fallthrough]];
601 case C2Config::LEVEL_APV_4_BAND_0:
602 [[fallthrough]];
603 case C2Config::LEVEL_APV_4_1_BAND_0:
604 [[fallthrough]];
605 case C2Config::LEVEL_APV_5_BAND_0:
606 [[fallthrough]];
607 case C2Config::LEVEL_APV_5_1_BAND_0:
608 [[fallthrough]];
609 case C2Config::LEVEL_APV_6_BAND_0:
610 [[fallthrough]];
611 case C2Config::LEVEL_APV_6_1_BAND_0:
612 [[fallthrough]];
613 case C2Config::LEVEL_APV_7_BAND_0:
614 [[fallthrough]];
615 case C2Config::LEVEL_APV_7_1_BAND_0:
616 bandIdc = 0;
617 break;
618 case C2Config::LEVEL_APV_1_BAND_1:
619 [[fallthrough]];
620 case C2Config::LEVEL_APV_1_1_BAND_1:
621 [[fallthrough]];
622 case C2Config::LEVEL_APV_2_BAND_1:
623 [[fallthrough]];
624 case C2Config::LEVEL_APV_2_1_BAND_1:
625 [[fallthrough]];
626 case C2Config::LEVEL_APV_3_BAND_1:
627 [[fallthrough]];
628 case C2Config::LEVEL_APV_3_1_BAND_1:
629 [[fallthrough]];
630 case C2Config::LEVEL_APV_4_BAND_1:
631 [[fallthrough]];
632 case C2Config::LEVEL_APV_4_1_BAND_1:
633 [[fallthrough]];
634 case C2Config::LEVEL_APV_5_BAND_1:
635 [[fallthrough]];
636 case C2Config::LEVEL_APV_5_1_BAND_1:
637 [[fallthrough]];
638 case C2Config::LEVEL_APV_6_BAND_1:
639 [[fallthrough]];
640 case C2Config::LEVEL_APV_6_1_BAND_1:
641 [[fallthrough]];
642 case C2Config::LEVEL_APV_7_BAND_1:
643 [[fallthrough]];
644 case C2Config::LEVEL_APV_7_1_BAND_1:
645 bandIdc = 1;
646 break;
647 case C2Config::LEVEL_APV_1_BAND_2:
648 [[fallthrough]];
649 case C2Config::LEVEL_APV_1_1_BAND_2:
650 [[fallthrough]];
651 case C2Config::LEVEL_APV_2_BAND_2:
652 [[fallthrough]];
653 case C2Config::LEVEL_APV_2_1_BAND_2:
654 [[fallthrough]];
655 case C2Config::LEVEL_APV_3_BAND_2:
656 [[fallthrough]];
657 case C2Config::LEVEL_APV_3_1_BAND_2:
658 [[fallthrough]];
659 case C2Config::LEVEL_APV_4_BAND_2:
660 [[fallthrough]];
661 case C2Config::LEVEL_APV_4_1_BAND_2:
662 [[fallthrough]];
663 case C2Config::LEVEL_APV_5_BAND_2:
664 [[fallthrough]];
665 case C2Config::LEVEL_APV_5_1_BAND_2:
666 [[fallthrough]];
667 case C2Config::LEVEL_APV_6_BAND_2:
668 [[fallthrough]];
669 case C2Config::LEVEL_APV_6_1_BAND_2:
670 [[fallthrough]];
671 case C2Config::LEVEL_APV_7_BAND_2:
672 [[fallthrough]];
673 case C2Config::LEVEL_APV_7_1_BAND_2:
674 bandIdc = 2;
675 break;
676 case C2Config::LEVEL_APV_1_BAND_3:
677 [[fallthrough]];
678 case C2Config::LEVEL_APV_1_1_BAND_3:
679 [[fallthrough]];
680 case C2Config::LEVEL_APV_2_BAND_3:
681 [[fallthrough]];
682 case C2Config::LEVEL_APV_2_1_BAND_3:
683 [[fallthrough]];
684 case C2Config::LEVEL_APV_3_BAND_3:
685 [[fallthrough]];
686 case C2Config::LEVEL_APV_3_1_BAND_3:
687 [[fallthrough]];
688 case C2Config::LEVEL_APV_4_BAND_3:
689 [[fallthrough]];
690 case C2Config::LEVEL_APV_4_1_BAND_3:
691 [[fallthrough]];
692 case C2Config::LEVEL_APV_5_BAND_3:
693 [[fallthrough]];
694 case C2Config::LEVEL_APV_5_1_BAND_3:
695 [[fallthrough]];
696 case C2Config::LEVEL_APV_6_BAND_3:
697 [[fallthrough]];
698 case C2Config::LEVEL_APV_6_1_BAND_3:
699 [[fallthrough]];
700 case C2Config::LEVEL_APV_7_BAND_3:
701 [[fallthrough]];
702 case C2Config::LEVEL_APV_7_1_BAND_3:
703 bandIdc = 3;
704 break;
705 default:
706 ALOGW("Unrecognized bandIdc through level: %x", mProfileLevel->level);
707 }
708 return bandIdc;
709 }
710
getSize_l() const711 std::shared_ptr<C2StreamPictureSizeInfo::input> getSize_l() const { return mSize; }
getFrameRate_l() const712 std::shared_ptr<C2StreamFrameRateInfo::output> getFrameRate_l() const { return mFrameRate; }
getBitrate_l() const713 std::shared_ptr<C2StreamBitrateInfo::output> getBitrate_l() const { return mBitrate; }
getQuality_l() const714 std::shared_ptr<C2StreamQualityTuning::output> getQuality_l() const { return mQuality; }
getColorAspects_l() const715 std::shared_ptr<C2StreamColorAspectsInfo::input> getColorAspects_l() const {
716 return mColorAspects;
717 }
getCodedColorAspects_l() const718 std::shared_ptr<C2StreamColorAspectsInfo::output> getCodedColorAspects_l() const {
719 return mCodedColorAspects;
720 }
getPictureQuantization_l() const721 std::shared_ptr<C2StreamPictureQuantizationTuning::output> getPictureQuantization_l() const {
722 return mPictureQuantization;
723 }
getProfileLevel_l() const724 std::shared_ptr<C2StreamProfileLevelInfo::output> getProfileLevel_l() const {
725 return mProfileLevel;
726 }
getPixelFormat_l() const727 std::shared_ptr<C2StreamPixelFormatInfo::input> getPixelFormat_l() const {
728 return mPixelFormat;
729 }
730
731 private:
732 std::shared_ptr<C2StreamProfileLevelInfo::output> mProfileLevel;
733 std::shared_ptr<C2StreamUsageTuning::input> mUsage;
734 std::shared_ptr<C2StreamPictureSizeInfo::input> mSize;
735 std::shared_ptr<C2StreamFrameRateInfo::output> mFrameRate;
736 std::shared_ptr<C2StreamBitrateInfo::output> mBitrate;
737 std::shared_ptr<C2StreamQualityTuning::output> mQuality;
738 std::shared_ptr<C2StreamColorAspectsInfo::input> mColorAspects;
739 std::shared_ptr<C2StreamColorAspectsInfo::output> mCodedColorAspects;
740 std::shared_ptr<C2StreamPictureQuantizationTuning::output> mPictureQuantization;
741 std::shared_ptr<C2StreamColorInfo::input> mColorFormat;
742 std::shared_ptr<C2StreamPixelFormatInfo::input> mPixelFormat;
743 };
744
C2SoftApvEnc(const char * name,c2_node_id_t id,const std::shared_ptr<IntfImpl> & intfImpl)745 C2SoftApvEnc::C2SoftApvEnc(const char* name, c2_node_id_t id,
746 const std::shared_ptr<IntfImpl>& intfImpl)
747 : SimpleC2Component(std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)),
748 mIntf(intfImpl),
749 mColorFormat(OAPV_CF_PLANAR2),
750 mStarted(false),
751 mSignalledEos(false),
752 mSignalledError(false),
753 mOutBlock(nullptr) {
754 resetEncoder();
755 }
756
C2SoftApvEnc(const char * name,c2_node_id_t id,const std::shared_ptr<C2ReflectorHelper> & helper)757 C2SoftApvEnc::C2SoftApvEnc(const char* name, c2_node_id_t id,
758 const std::shared_ptr<C2ReflectorHelper>& helper)
759 : C2SoftApvEnc(name, id, std::make_shared<IntfImpl>(helper)) {
760 }
761
~C2SoftApvEnc()762 C2SoftApvEnc::~C2SoftApvEnc() {
763 onRelease();
764 }
765
onInit()766 c2_status_t C2SoftApvEnc::onInit() {
767 return C2_OK;
768 }
769
onStop()770 c2_status_t C2SoftApvEnc::onStop() {
771 return C2_OK;
772 }
773
onReset()774 void C2SoftApvEnc::onReset() {
775 releaseEncoder();
776 resetEncoder();
777 }
778
onRelease()779 void C2SoftApvEnc::onRelease() {
780 releaseEncoder();
781 }
782
onFlush_sm()783 c2_status_t C2SoftApvEnc::onFlush_sm() {
784 return C2_OK;
785 }
786
fillEmptyWork(const std::unique_ptr<C2Work> & work)787 static void fillEmptyWork(const std::unique_ptr<C2Work>& work) {
788 uint32_t flags = 0;
789 if (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) {
790 flags |= C2FrameData::FLAG_END_OF_STREAM;
791 ALOGV("Signalling EOS");
792 }
793 work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
794 work->worklets.front()->output.buffers.clear();
795 work->worklets.front()->output.ordinal = work->input.ordinal;
796 work->workletsProcessed = 1u;
797 }
798
getQpFromQuality(int32_t quality)799 int32_t C2SoftApvEnc::getQpFromQuality(int32_t quality) {
800 int32_t qp = ((kApvQpMin - kApvQpMax) * quality / 100) + kApvQpMax;
801 qp = std::min(qp, (int)kApvQpMax);
802 qp = std::max(qp, (int)kApvQpMin);
803 return qp;
804 }
805
resetEncoder()806 c2_status_t C2SoftApvEnc::resetEncoder() {
807 ALOGV("reset");
808 mInitEncoder = false;
809 mStarted = false;
810 mSignalledEos = false;
811 mSignalledError = false;
812 mBitDepth = 10;
813 mMaxFrames = MAX_NUM_FRMS;
814 mReceivedFrames = 0;
815 mReceivedFirstFrame = false;
816 mColorFormat = OAPV_CF_PLANAR2;
817 memset(&mInputFrames, 0, sizeof(mInputFrames));
818 memset(&mReconFrames, 0, sizeof(mReconFrames));
819 return C2_OK;
820 }
821
releaseEncoder()822 c2_status_t C2SoftApvEnc::releaseEncoder() {
823 for (int32_t i = 0; i < MAX_NUM_FRMS; i++) {
824 if (mInputFrames.frm[i].imgb != nullptr) {
825 imgb_release(mInputFrames.frm[i].imgb);
826 mInputFrames.frm[i].imgb = nullptr;
827 }
828 }
829
830 if (mBitstreamBuf) {
831 std::free(mBitstreamBuf);
832 mBitstreamBuf = nullptr;
833 }
834 return C2_OK;
835 }
836
drain(uint32_t drainMode,const std::shared_ptr<C2BlockPool> & pool)837 c2_status_t C2SoftApvEnc::drain(uint32_t drainMode, const std::shared_ptr<C2BlockPool>& pool) {
838 return drainInternal(drainMode, pool, nullptr);
839 }
840
showEncoderParams(oapve_cdesc_t * cdsc)841 void C2SoftApvEnc::showEncoderParams(oapve_cdesc_t* cdsc) {
842 std::string title = "APV encoder params:";
843 ALOGD("%s width = %d, height = %d", title.c_str(), cdsc->param[0].w, cdsc->param[0].h);
844 ALOGD("%s FrameRate = %f", title.c_str(),
845 (double)cdsc->param[0].fps_num / cdsc->param[0].fps_den);
846 ALOGD("%s BitRate = %d Kbps", title.c_str(), cdsc->param[0].bitrate);
847 ALOGD("%s QP = %d", title.c_str(), cdsc->param[0].qp);
848 ALOGD("%s profile_idc = %d, level_idc = %d, band_idc = %d", title.c_str(),
849 cdsc->param[0].profile_idc, cdsc->param[0].level_idc / 3, cdsc->param[0].band_idc);
850 ALOGD("%s Bitrate Mode: %d", title.c_str(), cdsc->param[0].rc_type);
851 ALOGD("%s mColorAspects primaries: %d, transfer: %d, matrix: %d, range: %d", title.c_str(),
852 mColorAspects->primaries, mColorAspects->transfer, mColorAspects->matrix,
853 mColorAspects->range);
854 ALOGD("%s mCodedColorAspects primaries: %d, transfer: %d, matrix: %d, range: %d", title.c_str(),
855 mCodedColorAspects->primaries, mCodedColorAspects->transfer, mCodedColorAspects->matrix,
856 mCodedColorAspects->range);
857 ALOGD("%s Input color format: %s", title.c_str(),
858 mColorFormat == OAPV_CF_YCBCR422 ? "YUV422P10LE" : "P210");
859 ALOGD("%s max_num_frms: %d", title.c_str(), cdsc->max_num_frms);
860 }
861
initEncoder()862 c2_status_t C2SoftApvEnc::initEncoder() {
863 if (mInitEncoder) {
864 return C2_OK;
865 }
866 ALOGV("initEncoder");
867
868 mSize = mIntf->getSize_l();
869 mFrameRate = mIntf->getFrameRate_l();
870 mBitrate = mIntf->getBitrate_l();
871 mQuality = mIntf->getQuality_l();
872 mColorAspects = mIntf->getColorAspects_l();
873 mCodedColorAspects = mIntf->getCodedColorAspects_l();
874 mProfileLevel = mIntf->getProfileLevel_l();
875 mPixelFormat = mIntf->getPixelFormat_l();
876
877 mCodecDesc = std::make_unique<oapve_cdesc_t>();
878 if (mCodecDesc == nullptr) {
879 ALOGE("Allocate ctx failed");
880 return C2_NO_INIT;
881 }
882 mCodecDesc->max_bs_buf_size = kMaxBitstreamBufSize;
883 mCodecDesc->max_num_frms = MAX_NUM_FRMS;
884 // TODO: Bound parameters to CPU count
885 mCodecDesc->threads = 4;
886
887 int32_t ret = C2_OK;
888 /* set params */
889 for (int32_t i = 0; i < mMaxFrames; i++) {
890 oapve_param_t* param = &mCodecDesc->param[i];
891 ret = oapve_param_default(param);
892 if (OAPV_FAILED(ret)) {
893 ALOGE("cannot set default parameter");
894 return C2_NO_INIT;
895 }
896 setParams(*param);
897 }
898
899 showEncoderParams(mCodecDesc.get());
900
901 /* create encoder */
902 mEncoderId = oapve_create(mCodecDesc.get(), NULL);
903 if (mEncoderId == NULL) {
904 ALOGE("cannot create APV encoder");
905 return C2_CORRUPTED;
906 }
907
908 /* create metadata */
909 mMetaId = oapvm_create(&ret);
910 if (mMetaId == NULL) {
911 ALOGE("cannot create APV encoder");
912 return C2_NO_MEMORY;
913 }
914
915 /* create image buffers */
916 for (int32_t i = 0; i < mMaxFrames; i++) {
917 if (mBitDepth == 10) {
918 mInputFrames.frm[i].imgb = imgb_create(mCodecDesc->param[0].w, mCodecDesc->param[0].h,
919 OAPV_CS_SET(mColorFormat, mBitDepth, 0));
920 mReconFrames.frm[i].imgb = nullptr;
921 } else {
922 mInputFrames.frm[i].imgb = imgb_create(mCodecDesc->param[0].w, mCodecDesc->param[0].h,
923 OAPV_CS_SET(mColorFormat, 10, 0));
924 mReconFrames.frm[i].imgb = nullptr;
925 }
926 }
927
928 /* allocate bitstream buffer */
929 mBitstreamBuf = new unsigned char[kMaxBitstreamBufSize];
930 if (mBitstreamBuf == nullptr) {
931 ALOGE("cannot allocate bitstream buffer, size= %d", kMaxBitstreamBufSize);
932 return C2_NO_MEMORY;
933 }
934
935 mStarted = true;
936 mInitEncoder = true;
937 return C2_OK;
938 }
939
setParams(oapve_param_t & param)940 void C2SoftApvEnc::setParams(oapve_param_t& param) {
941 param.w = mSize->width;
942 param.h = mSize->height;
943 param.fps_num = (int)(mFrameRate->value * 100);
944 param.fps_den = 100;
945 param.bitrate = (int)(mBitrate->value / 1000);
946 param.rc_type = OAPV_RC_ABR;
947
948 param.qp = kApvDefaultQP;
949 param.band_idc = mIntf->getBandIdc_l();
950 param.profile_idc = mIntf->getProfile_l();
951 param.level_idc = mIntf->getLevel_l();
952 mColorAspects = mIntf->getColorAspects_l();
953 ColorAspects sfAspects;
954 if (!C2Mapper::map(mColorAspects->primaries, &sfAspects.mPrimaries)) {
955 sfAspects.mPrimaries = android::ColorAspects::PrimariesUnspecified;
956 }
957 if (!C2Mapper::map(mColorAspects->range, &sfAspects.mRange)) {
958 sfAspects.mRange = android::ColorAspects::RangeUnspecified;
959 }
960 if (!C2Mapper::map(mColorAspects->matrix, &sfAspects.mMatrixCoeffs)) {
961 sfAspects.mMatrixCoeffs = android::ColorAspects::MatrixUnspecified;
962 }
963 if (!C2Mapper::map(mColorAspects->transfer, &sfAspects.mTransfer)) {
964 sfAspects.mTransfer = android::ColorAspects::TransferUnspecified;
965 }
966
967 int32_t isoPrimaries, isoTransfer, isoMatrix;
968 bool isoFullRange;
969 ColorUtils::convertCodecColorAspectsToIsoAspects(sfAspects,
970 &isoPrimaries, &isoTransfer, &isoMatrix, &isoFullRange);
971 param.color_primaries = isoPrimaries;
972 param.transfer_characteristics = isoTransfer;
973 param.matrix_coefficients = isoMatrix;
974 param.full_range_flag = isoFullRange;
975
976 if (mColorAspects->primaries != C2Color::PRIMARIES_UNSPECIFIED ||
977 mColorAspects->transfer != C2Color::TRANSFER_UNSPECIFIED ||
978 mColorAspects->matrix != C2Color::MATRIX_UNSPECIFIED ||
979 mColorAspects->range != C2Color::RANGE_UNSPECIFIED) {
980 param.color_description_present_flag = 1;
981 }
982 }
983
setEncodeArgs(oapv_frms_t * inputFrames,const C2GraphicView * const input,uint64_t workIndex)984 c2_status_t C2SoftApvEnc::setEncodeArgs(oapv_frms_t* inputFrames, const C2GraphicView* const input,
985 uint64_t workIndex) {
986 if (input->width() < mSize->width || input->height() < mSize->height) {
987 /* Expect width height to be configured */
988 ALOGW("unexpected Capacity Aspect %d(%d) x %d(%d)", input->width(), mSize->width,
989 input->height(), mSize->height);
990 return C2_BAD_VALUE;
991 }
992 const C2PlanarLayout& layout = input->layout();
993 uint8_t* yPlane = const_cast<uint8_t*>(input->data()[C2PlanarLayout::PLANE_Y]);
994 uint8_t* uPlane = const_cast<uint8_t*>(input->data()[C2PlanarLayout::PLANE_U]);
995 uint8_t* vPlane = const_cast<uint8_t*>(input->data()[C2PlanarLayout::PLANE_V]);
996
997 uint32_t width = mSize->width;
998 uint32_t height = mSize->height;
999
1000 /* width and height must be even */
1001 if (width & 1u || height & 1u) {
1002 ALOGW("height(%u) and width(%u) must both be even", height, width);
1003 return C2_BAD_VALUE;
1004 }
1005
1006 /* Set num frames */
1007 inputFrames->num_frms = MAX_NUM_FRMS;
1008 inputFrames->frm[mReceivedFrames].group_id = 1;
1009 inputFrames->frm[mReceivedFrames].pbu_type = OAPV_PBU_TYPE_PRIMARY_FRAME;
1010
1011 switch (layout.type) {
1012 case C2PlanarLayout::TYPE_RGB: {
1013 uint16_t *dstY = (uint16_t*)inputFrames->frm[0].imgb->a[0];
1014 uint16_t *dstUV = (uint16_t*)inputFrames->frm[0].imgb->a[1];
1015 size_t dstYStride = inputFrames->frm[0].imgb->s[0] / 2;
1016 size_t dstUVStride = inputFrames->frm[0].imgb->s[1] / 2;
1017 convertRGBToP210(dstY, dstUV, (uint32_t*)(input->data()[0]),
1018 layout.planes[layout.PLANE_Y].rowInc / 4,
1019 dstYStride, dstUVStride, width, height,
1020 mColorAspects->matrix, mColorAspects->range);
1021 break;
1022 }
1023 case C2PlanarLayout::TYPE_RGBA: {
1024 [[fallthrough]];
1025 }
1026 case C2PlanarLayout::TYPE_YUVA: {
1027 ALOGV("Convert from ABGR2101010 to P210");
1028 if (mColorFormat == OAPV_CF_PLANAR2) {
1029 uint16_t *dstY, *dstUV;
1030 dstY = (uint16_t*)inputFrames->frm[0].imgb->a[0];
1031 dstUV = (uint16_t*)inputFrames->frm[0].imgb->a[1];
1032 size_t dstYStride = inputFrames->frm[0].imgb->s[0] / 2;
1033 size_t dstUVStride = inputFrames->frm[0].imgb->s[1] / 2;
1034 convertRGBA1010102ToP210(dstY, dstUV, (uint32_t*)(input->data()[0]),
1035 layout.planes[layout.PLANE_Y].rowInc / 4,
1036 dstYStride, dstUVStride, width, height,
1037 mColorAspects->matrix, mColorAspects->range);
1038 break;
1039 } else {
1040 ALOGE("Not supported color format. %d", mColorFormat);
1041 return C2_BAD_VALUE;
1042 }
1043 }
1044 case C2PlanarLayout::TYPE_YUV: {
1045 if (IsP010(*input)) {
1046 ALOGV("Convert from P010 to P210");
1047 if (mColorFormat == OAPV_CF_PLANAR2) {
1048 uint16_t *srcY = (uint16_t*)(input->data()[0]);
1049 uint16_t *srcUV = (uint16_t*)(input->data()[1]);
1050 uint16_t *dstY = (uint16_t*)inputFrames->frm[0].imgb->a[0];
1051 uint16_t *dstUV = (uint16_t*)inputFrames->frm[0].imgb->a[1];
1052 size_t dstYStride = inputFrames->frm[0].imgb->s[0] / 2;
1053 size_t dstUVStride = inputFrames->frm[0].imgb->s[1] / 2;
1054 convertP010ToP210(dstY, dstUV, srcY, srcUV,
1055 layout.planes[layout.PLANE_Y].rowInc / 2,
1056 layout.planes[layout.PLANE_U].rowInc / 2,
1057 dstYStride, dstUVStride, width, height);
1058 } else {
1059 ALOGE("Not supported color format. %d", mColorFormat);
1060 return C2_BAD_VALUE;
1061 }
1062 } else if (IsP210(*input)) {
1063 ALOGV("Convert from P210 to P210");
1064 if (mColorFormat == OAPV_CF_PLANAR2) {
1065 uint16_t *srcY = (uint16_t*)(input->data()[0]);
1066 uint16_t *srcUV = (uint16_t*)(input->data()[1]);
1067 uint16_t *dstY = (uint16_t*)inputFrames->frm[0].imgb->a[0];
1068 uint16_t *dstUV = (uint16_t*)inputFrames->frm[0].imgb->a[1];
1069 size_t srcYStride = layout.planes[layout.PLANE_Y].rowInc / 2;
1070 size_t srcUVStride = layout.planes[layout.PLANE_U].rowInc / 2;
1071 size_t dstYStride = inputFrames->frm[0].imgb->s[0] / 2;
1072 size_t dstUVStride = inputFrames->frm[0].imgb->s[1] / 2;
1073
1074 for (size_t y = 0; y < height; ++y) {
1075 std::memcpy(dstY, srcY, width * sizeof(uint16_t));
1076 dstY += dstYStride;
1077 srcY += srcYStride;
1078 }
1079
1080 for (size_t y = 0; y < height; ++y) {
1081 std::memcpy(dstUV, srcUV, width * sizeof(uint16_t));
1082 srcUV += srcUVStride;
1083 dstUV += dstUVStride;
1084 }
1085 } else {
1086 ALOGE("Not supported color format. %d", mColorFormat);
1087 return C2_BAD_VALUE;
1088 }
1089 } else if (IsNV12(*input) || IsNV21(*input)) {
1090 ALOGV("Convert from NV12 to P210");
1091 uint8_t *srcY = (uint8_t*)input->data()[0];
1092 uint8_t *srcUV = (uint8_t*)input->data()[1];
1093 uint16_t *dstY = (uint16_t*)inputFrames->frm[0].imgb->a[0];
1094 uint16_t *dstUV = (uint16_t*)inputFrames->frm[0].imgb->a[1];
1095 size_t dstYStride = inputFrames->frm[0].imgb->s[0] / 2;
1096 size_t dstUVStride = inputFrames->frm[0].imgb->s[1] / 2;
1097 convertSemiPlanar8ToP210(dstY, dstUV, srcY, srcUV,
1098 layout.planes[layout.PLANE_Y].rowInc,
1099 layout.planes[layout.PLANE_U].rowInc,
1100 dstYStride, dstUVStride,
1101 width, height, CONV_FORMAT_I420, IsNV12(*input));
1102 } else if (IsI420(*input)) {
1103 ALOGV("Convert from I420 to P210");
1104 uint8_t *srcY = (uint8_t*)input->data()[0];
1105 uint8_t *srcU = (uint8_t*)input->data()[1];
1106 uint8_t *srcV = (uint8_t*)input->data()[2];
1107 uint16_t *dstY = (uint16_t*)inputFrames->frm[0].imgb->a[0];
1108 uint16_t *dstUV = (uint16_t*)inputFrames->frm[0].imgb->a[1];
1109 size_t dstYStride = inputFrames->frm[0].imgb->s[0] / 2;
1110 size_t dstUVStride = inputFrames->frm[0].imgb->s[1] / 2;
1111 convertPlanar8ToP210(dstY, dstUV, srcY, srcU, srcV,
1112 layout.planes[C2PlanarLayout::PLANE_Y].rowInc,
1113 layout.planes[C2PlanarLayout::PLANE_U].rowInc,
1114 layout.planes[C2PlanarLayout::PLANE_V].rowInc,
1115 dstYStride, dstUVStride,
1116 width, height,
1117 CONV_FORMAT_I420);
1118
1119 } else {
1120 ALOGE("Not supported color format. %d", mColorFormat);
1121 return C2_BAD_VALUE;
1122 }
1123 break;
1124 }
1125
1126 default:
1127 ALOGE("Unrecognized plane type: %d", layout.type);
1128 return C2_BAD_VALUE;
1129 }
1130
1131 return C2_OK;
1132 }
1133
finishWork(uint64_t workIndex,const std::unique_ptr<C2Work> & work,const std::shared_ptr<C2BlockPool> & pool,oapv_bitb_t * bitb,oapve_stat_t * stat)1134 void C2SoftApvEnc::finishWork(uint64_t workIndex, const std::unique_ptr<C2Work>& work,
1135 const std::shared_ptr<C2BlockPool>& pool, oapv_bitb_t* bitb,
1136 oapve_stat_t* stat) {
1137 std::shared_ptr<C2LinearBlock> block;
1138 C2MemoryUsage usage = {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE};
1139 c2_status_t status = pool->fetchLinearBlock(stat->write, usage, &block);
1140 if (C2_OK != status) {
1141 ALOGE("fetchLinearBlock for Output failed with status 0x%x", status);
1142 mSignalledError = true;
1143 work->result = status;
1144 work->workletsProcessed = 1u;
1145 return;
1146 }
1147
1148 C2WriteView wView = block->map().get();
1149 if (C2_OK != wView.error()) {
1150 ALOGE("write view map failed with status 0x%x", wView.error());
1151 mSignalledError = true;
1152 work->result = wView.error();
1153 work->workletsProcessed = 1u;
1154 return;
1155 }
1156 if ((!mReceivedFirstFrame)) {
1157 createCsdData(work, bitb, stat->write);
1158 mReceivedFirstFrame = true;
1159 }
1160
1161 memcpy(wView.data(), bitb->addr, stat->write);
1162 std::shared_ptr<C2Buffer> buffer = createLinearBuffer(block, 0, stat->write);
1163
1164 /* All frames are SYNC FRAME */
1165 buffer->setInfo(std::make_shared<C2StreamPictureTypeMaskInfo::output>(0u /* stream id */,
1166 C2Config::SYNC_FRAME));
1167
1168 auto fillWork = [buffer](const std::unique_ptr<C2Work>& work) {
1169 work->worklets.front()->output.flags = (C2FrameData::flags_t)0;
1170 work->worklets.front()->output.buffers.clear();
1171 work->worklets.front()->output.buffers.push_back(buffer);
1172 work->worklets.front()->output.ordinal = work->input.ordinal;
1173 work->workletsProcessed = 1u;
1174 };
1175 if (work && c2_cntr64_t(workIndex) == work->input.ordinal.frameIndex) {
1176 fillWork(work);
1177 if (mSignalledEos) {
1178 work->worklets.front()->output.flags = C2FrameData::FLAG_END_OF_STREAM;
1179 }
1180 } else {
1181 finish(workIndex, fillWork);
1182 }
1183 }
1184
createCsdData(const std::unique_ptr<C2Work> & work,oapv_bitb_t * bitb,uint32_t encodedSize)1185 void C2SoftApvEnc::createCsdData(const std::unique_ptr<C2Work>& work,
1186 oapv_bitb_t* bitb,
1187 uint32_t encodedSize) {
1188 if (encodedSize < 35) {
1189 ALOGE("the first frame size is too small, so no csd data will be created.");
1190 return;
1191 }
1192 ABitReader reader((uint8_t*)bitb->addr, encodedSize);
1193
1194 uint8_t number_of_configuration_entry = 0;
1195 uint8_t pbu_type = 0;
1196 uint8_t number_of_frame_info = 0;
1197 bool color_description_present_flag = false;
1198 bool capture_time_distance_ignored = false;
1199 uint8_t profile_idc = 0;
1200 uint8_t level_idc = 0;
1201 uint8_t band_idc = 0;
1202 uint32_t frame_width = 0;
1203 uint32_t frame_height = 0;
1204 uint8_t chroma_format_idc = 0;
1205 uint8_t bit_depth_minus8 = 0;
1206 uint8_t capture_time_distance = 0;
1207 uint8_t color_primaries = 0;
1208 uint8_t transfer_characteristics = 0;
1209 uint8_t full_range_flag = 0;
1210 uint8_t matrix_coefficients = 0;
1211
1212 /* pbu_header() */
1213 reader.skipBits(32); // pbu_size
1214 reader.skipBits(32); // signature
1215 reader.skipBits(32); // currReadSize
1216 pbu_type = reader.getBits(8); // pbu_type
1217 reader.skipBits(16); // group_id
1218 reader.skipBits(8); // reserved_zero_8bits
1219
1220 /* frame info() */
1221 profile_idc = reader.getBits(8); // profile_idc
1222 level_idc = reader.getBits(8); // level_idc
1223 band_idc = reader.getBits(3); // band_idc
1224 reader.skipBits(5); // reserved_zero_5bits
1225 frame_width = reader.getBits(24); // width
1226 frame_height = reader.getBits(24); // height
1227 chroma_format_idc = reader.getBits(4); // chroma_format_idc
1228 bit_depth_minus8 = reader.getBits(4); // bit_depth
1229 capture_time_distance = reader.getBits(8); // capture_time_distance
1230 reader.skipBits(8); // reserved_zero_8bits
1231
1232 /* frame header() */
1233 reader.skipBits(8); // reserved_zero_8bit
1234 color_description_present_flag = reader.getBits(1); // color_description_present_flag
1235 if (color_description_present_flag) {
1236 color_primaries = reader.getBits(8); // color_primaries
1237 transfer_characteristics = reader.getBits(8); // transfer_characteristics
1238 matrix_coefficients = reader.getBits(8); // matrix_coefficients
1239 full_range_flag = reader.getBits(1); // full_range_flag
1240 reader.skipBits(7); // reserved_zero_7bits
1241 }
1242
1243 number_of_configuration_entry = 1; // The real-time encoding on the device is assumed to be 1.
1244 number_of_frame_info = 1; // The real-time encoding on the device is assumed to be 1.
1245
1246 std::vector<uint8_t> csdData;
1247
1248 csdData.push_back((uint8_t)0x1);
1249 csdData.push_back(number_of_configuration_entry);
1250
1251 for (uint8_t i = 0; i < number_of_configuration_entry; i++) {
1252 csdData.push_back(pbu_type);
1253 csdData.push_back(number_of_frame_info);
1254 for (uint8_t j = 0; j < number_of_frame_info; j++) {
1255 csdData.push_back((uint8_t)((color_description_present_flag << 1) |
1256 capture_time_distance_ignored));
1257 csdData.push_back(profile_idc);
1258 csdData.push_back(level_idc);
1259 csdData.push_back(band_idc);
1260 csdData.push_back((uint8_t)((frame_width >> 24) & 0xff));
1261 csdData.push_back((uint8_t)((frame_width >> 16) & 0xff));
1262 csdData.push_back((uint8_t)((frame_width >> 8) & 0xff));
1263 csdData.push_back((uint8_t)(frame_width & 0xff));
1264 csdData.push_back((uint8_t)((frame_height >> 24) & 0xff));
1265 csdData.push_back((uint8_t)((frame_height >> 16) & 0xff));
1266 csdData.push_back((uint8_t)((frame_height >> 8) & 0xff));
1267 csdData.push_back((uint8_t)(frame_height & 0xff));
1268 csdData.push_back((uint8_t)(((chroma_format_idc << 4) & 0xf0) |
1269 (bit_depth_minus8 & 0xf)));
1270 csdData.push_back((uint8_t)(capture_time_distance));
1271 if (color_description_present_flag) {
1272 csdData.push_back(color_primaries);
1273 csdData.push_back(transfer_characteristics);
1274 csdData.push_back(matrix_coefficients);
1275 csdData.push_back(full_range_flag << 7);
1276 }
1277 }
1278 }
1279
1280 std::unique_ptr<C2StreamInitDataInfo::output> csd =
1281 C2StreamInitDataInfo::output::AllocUnique(csdData.size(), 0u);
1282 if (!csd) {
1283 ALOGE("CSD allocation failed");
1284 mSignalledError = true;
1285 work->result = C2_NO_MEMORY;
1286 work->workletsProcessed = 1u;
1287 return;
1288 }
1289
1290 memcpy(csd->m.value, csdData.data(), csdData.size());
1291 work->worklets.front()->output.configUpdate.push_back(std::move(csd));
1292 }
1293
drainInternal(uint32_t drainMode,const std::shared_ptr<C2BlockPool> & pool,const std::unique_ptr<C2Work> & work)1294 c2_status_t C2SoftApvEnc::drainInternal(uint32_t drainMode,
1295 const std::shared_ptr<C2BlockPool>& pool,
1296 const std::unique_ptr<C2Work>& work) {
1297 fillEmptyWork(work);
1298 return C2_OK;
1299 }
1300
process(const std::unique_ptr<C2Work> & work,const std::shared_ptr<C2BlockPool> & pool)1301 void C2SoftApvEnc::process(const std::unique_ptr<C2Work>& work,
1302 const std::shared_ptr<C2BlockPool>& pool) {
1303 c2_status_t error;
1304 work->result = C2_OK;
1305 work->workletsProcessed = 0u;
1306 work->worklets.front()->output.flags = work->input.flags;
1307
1308 nsecs_t timeDelay = 0;
1309 uint64_t workIndex = work->input.ordinal.frameIndex.peekull();
1310
1311 mSignalledEos = false;
1312 mOutBlock = nullptr;
1313
1314 if (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) {
1315 ALOGV("Got FLAG_END_OF_STREAM");
1316 mSignalledEos = true;
1317 }
1318
1319 /* Initialize encoder if not already initialized */
1320 if (initEncoder() != C2_OK) {
1321 ALOGE("Failed to initialize encoder");
1322 mSignalledError = true;
1323 work->result = C2_CORRUPTED;
1324 work->workletsProcessed = 1u;
1325 ALOGE("[%s] Failed to make Codec context", __func__);
1326 return;
1327 }
1328 if (mSignalledError) {
1329 ALOGE("[%s] Received signalled error", __func__);
1330 return;
1331 }
1332
1333 if (mSignalledEos) {
1334 drainInternal(DRAIN_COMPONENT_WITH_EOS, pool, work);
1335 return;
1336 }
1337
1338 std::shared_ptr<C2GraphicView> view;
1339 std::shared_ptr<C2Buffer> inputBuffer = nullptr;
1340 if (!work->input.buffers.empty()) {
1341 inputBuffer = work->input.buffers[0];
1342 view = std::make_shared<C2GraphicView>(
1343 inputBuffer->data().graphicBlocks().front().map().get());
1344 if (view->error() != C2_OK) {
1345 ALOGE("graphic view map err = %d", view->error());
1346 work->workletsProcessed = 1u;
1347 return;
1348 }
1349 } else {
1350 ALOGV("Empty input Buffer");
1351 uint32_t flags = 0;
1352 if (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) {
1353 flags |= C2FrameData::FLAG_END_OF_STREAM;
1354 }
1355 work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
1356 work->worklets.front()->output.buffers.clear();
1357 work->worklets.front()->output.ordinal = work->input.ordinal;
1358 work->workletsProcessed = 1u;
1359 return;
1360 }
1361
1362 if (!inputBuffer) {
1363 fillEmptyWork(work);
1364 return;
1365 }
1366
1367 oapve_stat_t stat;
1368 auto outBufferSize =
1369 mCodecDesc->param[mReceivedFrames].w * mCodecDesc->param[mReceivedFrames].h * 4;
1370 if (!mOutBlock) {
1371 C2MemoryUsage usage = {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE};
1372 c2_status_t err = pool->fetchLinearBlock(outBufferSize, usage, &mOutBlock);
1373 if (err != C2_OK) {
1374 work->result = err;
1375 work->workletsProcessed = 1u;
1376 ALOGE("fetchLinearBlock has failed. err = %d", err);
1377 return;
1378 }
1379 }
1380
1381 C2WriteView wView = mOutBlock->map().get();
1382 if (wView.error() != C2_OK) {
1383 work->result = wView.error();
1384 work->workletsProcessed = 1u;
1385 return;
1386 }
1387
1388 view->setCrop_be(C2Rect(mSize->width, mSize->height));
1389
1390 error = setEncodeArgs(&mInputFrames, view.get(), workIndex);
1391 if (error != C2_OK) {
1392 ALOGE("setEncodeArgs has failed. err = %d", error);
1393 mSignalledError = true;
1394 work->result = error;
1395 work->workletsProcessed = 1u;
1396 return;
1397 }
1398
1399 if (++mReceivedFrames < mMaxFrames) {
1400 return;
1401 }
1402 mReceivedFrames = 0;
1403
1404 std::shared_ptr<oapv_bitb_t> bits = std::make_shared<oapv_bitb_t>();
1405 std::memset(mBitstreamBuf, 0, kMaxBitstreamBufSize);
1406 bits->addr = mBitstreamBuf;
1407 bits->bsize = kMaxBitstreamBufSize;
1408 bits->err = C2_OK;
1409
1410 if (mInputFrames.frm[0].imgb) {
1411 int32_t status =
1412 oapve_encode(mEncoderId, &mInputFrames, mMetaId, bits.get(), &stat, &mReconFrames);
1413 if (status != C2_OK) {
1414 ALOGE("oapve_encode has failed. err = %d", status);
1415 mSignalledError = true;
1416 work->result = C2_CORRUPTED;
1417 work->workletsProcessed = 1u;
1418 return;
1419 }
1420 } else if (!mSignalledEos) {
1421 fillEmptyWork(work);
1422 }
1423 finishWork(workIndex, work, pool, bits.get(), &stat);
1424 }
1425
1426 class C2SoftApvEncFactory : public C2ComponentFactory {
1427 public:
C2SoftApvEncFactory()1428 C2SoftApvEncFactory()
1429 : mHelper(std::static_pointer_cast<C2ReflectorHelper>(
1430 GetCodec2PlatformComponentStore()->getParamReflector())) {}
1431
createComponent(c2_node_id_t id,std::shared_ptr<C2Component> * const component,std::function<void (C2Component *)> deleter)1432 virtual c2_status_t createComponent(c2_node_id_t id,
1433 std::shared_ptr<C2Component>* const component,
1434 std::function<void(C2Component*)> deleter) override {
1435 *component = std::shared_ptr<C2Component>(
1436 new C2SoftApvEnc(COMPONENT_NAME, id,
1437 std::make_shared<C2SoftApvEnc::IntfImpl>(mHelper)),
1438 deleter);
1439 return C2_OK;
1440 }
1441
createInterface(c2_node_id_t id,std::shared_ptr<C2ComponentInterface> * const interface,std::function<void (C2ComponentInterface *)> deleter)1442 c2_status_t createInterface(c2_node_id_t id,
1443 std::shared_ptr<C2ComponentInterface>* const interface,
1444 std::function<void(C2ComponentInterface*)> deleter) override {
1445 *interface = std::shared_ptr<C2ComponentInterface>(
1446 new SimpleInterface<C2SoftApvEnc::IntfImpl>(
1447 COMPONENT_NAME, id, std::make_shared<C2SoftApvEnc::IntfImpl>(mHelper)),
1448 deleter);
1449 return C2_OK;
1450 }
1451
1452 ~C2SoftApvEncFactory() override = default;
1453
1454 private:
1455 std::shared_ptr<C2ReflectorHelper> mHelper;
1456 };
1457
1458 } // namespace android
1459
CreateCodec2Factory()1460 __attribute__((cfi_canonical_jump_table)) extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
1461 if (!android::media::swcodec::flags::apv_software_codec()) {
1462 ALOGV("APV SW Codec is not enabled");
1463 return nullptr;
1464 }
1465
1466 bool enabled = isAtLeastRelease(36, "Baklava");
1467 ALOGD("isAtLeastRelease(36, Baklava) says enable: %s", enabled ? "yes" : "no");
1468 if (!enabled) {
1469 return nullptr;
1470 }
1471
1472 return new ::android::C2SoftApvEncFactory();
1473 }
1474
DestroyCodec2Factory(::C2ComponentFactory * factory)1475 __attribute__((cfi_canonical_jump_table)) extern "C" void DestroyCodec2Factory(
1476 ::C2ComponentFactory* factory) {
1477 delete factory;
1478 }
1479