1 /*
2 * Copyright 2020 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_TAG "SampleFilterPlugin"
18 #include <android-base/logging.h>
19
20 #include <chrono>
21 #include <thread>
22
23 #include <codec2/hidl/plugin/FilterPlugin.h>
24
25 #include <C2AllocatorGralloc.h>
26 #include <C2Config.h>
27 #include <C2PlatformSupport.h>
28 #include <Codec2Mapper.h>
29 #include <util/C2InterfaceHelper.h>
30
31 #include <renderengine/RenderEngine.h>
32 #include <system/window.h>
33 #include <ui/GraphicBuffer.h>
34 #include <utils/RefBase.h>
35
36 typedef C2StreamParam<C2Info, C2ColorAspectsStruct,
37 kParamIndexColorAspects | C2Param::CoreIndex::IS_REQUEST_FLAG>
38 C2StreamColorAspectsRequestInfo;
39
40 namespace android {
41
42 using namespace std::literals::chrono_literals;
43
44 class SampleToneMappingFilter
45 : public C2Component, public std::enable_shared_from_this<SampleToneMappingFilter> {
46 public:
47 class Interface : public C2ComponentInterface {
48 public:
49 static const std::string NAME;
50 static const FilterPlugin_V1::Descriptor DESCRIPTOR;
51
Interface(c2_node_id_t id)52 explicit Interface(c2_node_id_t id)
53 : mId(id),
54 mReflector(std::make_shared<C2ReflectorHelper>()),
55 mHelper(mReflector) {
56 }
57 ~Interface() override = default;
getName() const58 C2String getName() const override { return NAME; }
getId() const59 c2_node_id_t getId() const override { return mId; }
60
query_vb(const std::vector<C2Param * > & stackParams,const std::vector<C2Param::Index> & heapParamIndices,c2_blocking_t mayBlock,std::vector<std::unique_ptr<C2Param>> * const heapParams) const61 c2_status_t query_vb(
62 const std::vector<C2Param*> &stackParams,
63 const std::vector<C2Param::Index> &heapParamIndices,
64 c2_blocking_t mayBlock,
65 std::vector<std::unique_ptr<C2Param>>* const heapParams) const override {
66 return mHelper.query(stackParams, heapParamIndices, mayBlock, heapParams);
67 }
config_vb(const std::vector<C2Param * > & params,c2_blocking_t mayBlock,std::vector<std::unique_ptr<C2SettingResult>> * const failures)68 c2_status_t config_vb(
69 const std::vector<C2Param*> ¶ms,
70 c2_blocking_t mayBlock,
71 std::vector<std::unique_ptr<C2SettingResult>>* const failures) override {
72 return mHelper.config(params, mayBlock, failures);
73 }
querySupportedParams_nb(std::vector<std::shared_ptr<C2ParamDescriptor>> * const params) const74 c2_status_t querySupportedParams_nb(
75 std::vector<std::shared_ptr<C2ParamDescriptor>> * const params) const override {
76 return mHelper.querySupportedParams(params);
77 }
querySupportedValues_vb(std::vector<C2FieldSupportedValuesQuery> & fields,c2_blocking_t mayBlock) const78 c2_status_t querySupportedValues_vb(
79 std::vector<C2FieldSupportedValuesQuery> &fields,
80 c2_blocking_t mayBlock) const override {
81 return mHelper.querySupportedValues(fields, mayBlock);
82 }
createTunnel_sm(c2_node_id_t)83 c2_status_t createTunnel_sm(c2_node_id_t) override { return C2_OMITTED; }
releaseTunnel_sm(c2_node_id_t)84 c2_status_t releaseTunnel_sm(c2_node_id_t) override { return C2_OMITTED; }
85
getDataSpace()86 uint32_t getDataSpace() {
87 Helper::Lock lock = mHelper.lock();
88 uint32_t dataspace = HAL_DATASPACE_UNKNOWN;
89 C2Mapper::map(
90 mHelper.mInputColorAspectInfo->range,
91 mHelper.mInputColorAspectInfo->primaries,
92 mHelper.mInputColorAspectInfo->matrix,
93 mHelper.mInputColorAspectInfo->transfer,
94 &dataspace);
95 return dataspace;
96 }
getHdrStaticMetadata()97 std::shared_ptr<C2StreamHdrStaticInfo::input> getHdrStaticMetadata() {
98 Helper::Lock lock = mHelper.lock();
99 return mHelper.mInputHdrStaticInfo;
100 }
getPoolId()101 C2BlockPool::local_id_t getPoolId() {
102 Helper::Lock lock = mHelper.lock();
103 return mHelper.mOutputPoolIds->m.values[0];
104 }
105
IsFilteringEnabled(const std::shared_ptr<C2ComponentInterface> & intf)106 static bool IsFilteringEnabled(const std::shared_ptr<C2ComponentInterface> &intf) {
107 C2StreamColorAspectsRequestInfo::output info(0u);
108 std::vector<std::unique_ptr<C2Param>> heapParams;
109 c2_status_t err = intf->query_vb({&info}, {}, C2_MAY_BLOCK, &heapParams);
110 if (err != C2_OK && err != C2_BAD_INDEX) {
111 LOG(WARNING) << "SampleToneMappingFilter::Interface::IsFilteringEnabled: "
112 << "query failed for " << intf->getName();
113 return false;
114 }
115 return info && info.transfer == C2Color::TRANSFER_170M;
116 }
117
QueryParamsForPreviousComponent(const std::shared_ptr<C2ComponentInterface> & intf,std::vector<std::unique_ptr<C2Param>> * params)118 static c2_status_t QueryParamsForPreviousComponent(
119 [[maybe_unused]] const std::shared_ptr<C2ComponentInterface> &intf,
120 std::vector<std::unique_ptr<C2Param>> *params) {
121 params->emplace_back(new C2StreamUsageTuning::output(
122 0u, C2AndroidMemoryUsage::HW_TEXTURE_READ));
123 params->emplace_back(new C2StreamPixelFormatInfo::output(
124 0u, HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED));
125 return C2_OK;
126 }
127 private:
128 const c2_node_id_t mId;
129 std::shared_ptr<C2ReflectorHelper> mReflector;
130 struct Helper : public C2InterfaceHelper {
Helperandroid::SampleToneMappingFilter::Interface::Helper131 explicit Helper(std::shared_ptr<C2ReflectorHelper> reflector)
132 : C2InterfaceHelper(reflector) {
133 setDerivedInstance(this);
134
135 addParameter(
136 DefineParam(mApiFeatures, C2_PARAMKEY_API_FEATURES)
137 .withConstValue(new C2ApiFeaturesSetting(C2Config::api_feature_t(
138 API_REFLECTION |
139 API_VALUES |
140 API_CURRENT_VALUES |
141 API_DEPENDENCY |
142 API_SAME_INPUT_BUFFER)))
143 .build());
144
145 mName = C2ComponentNameSetting::AllocShared(NAME.size() + 1);
146 strncpy(mName->m.value, NAME.c_str(), NAME.size() + 1);
147 addParameter(
148 DefineParam(mName, C2_PARAMKEY_COMPONENT_NAME)
149 .withConstValue(mName)
150 .build());
151
152 addParameter(
153 DefineParam(mKind, C2_PARAMKEY_COMPONENT_KIND)
154 .withConstValue(new C2ComponentKindSetting(C2Component::KIND_OTHER))
155 .build());
156
157 addParameter(
158 DefineParam(mDomain, C2_PARAMKEY_COMPONENT_DOMAIN)
159 .withConstValue(new C2ComponentDomainSetting(C2Component::DOMAIN_VIDEO))
160 .build());
161
162 addParameter(
163 DefineParam(mInputStreamCount, C2_PARAMKEY_INPUT_STREAM_COUNT)
164 .withConstValue(new C2PortStreamCountTuning::input(1))
165 .build());
166
167 addParameter(
168 DefineParam(mOutputStreamCount, C2_PARAMKEY_OUTPUT_STREAM_COUNT)
169 .withConstValue(new C2PortStreamCountTuning::output(1))
170 .build());
171
172 addParameter(
173 DefineParam(mInputFormat, C2_PARAMKEY_INPUT_STREAM_BUFFER_TYPE)
174 .withConstValue(new C2StreamBufferTypeSetting::input(
175 0u, C2BufferData::GRAPHIC))
176 .build());
177
178 static const std::string kRawMediaType = "video/raw";
179 mInputMediaType = C2PortMediaTypeSetting::input::AllocShared(
180 kRawMediaType.size() + 1);
181 strncpy(mInputMediaType->m.value, kRawMediaType.c_str(), kRawMediaType.size() + 1);
182 addParameter(
183 DefineParam(mInputMediaType, C2_PARAMKEY_INPUT_MEDIA_TYPE)
184 .withConstValue(mInputMediaType)
185 .build());
186
187 addParameter(
188 DefineParam(mOutputFormat, C2_PARAMKEY_OUTPUT_STREAM_BUFFER_TYPE)
189 .withConstValue(new C2StreamBufferTypeSetting::output(
190 0u, C2BufferData::GRAPHIC))
191 .build());
192
193 mOutputMediaType = C2PortMediaTypeSetting::output::AllocShared(
194 kRawMediaType.size() + 1);
195 strncpy(mOutputMediaType->m.value, kRawMediaType.c_str(), kRawMediaType.size() + 1);
196 addParameter(
197 DefineParam(mOutputMediaType, C2_PARAMKEY_OUTPUT_MEDIA_TYPE)
198 .withConstValue(mOutputMediaType)
199 .build());
200
201 addParameter(
202 DefineParam(mActualInputDelay, C2_PARAMKEY_INPUT_DELAY)
203 .withConstValue(new C2PortActualDelayTuning::input(0u))
204 .build());
205
206 addParameter(
207 DefineParam(mActualOutputDelay, C2_PARAMKEY_OUTPUT_DELAY)
208 .withConstValue(new C2PortActualDelayTuning::output(0u))
209 .build());
210
211 addParameter(
212 DefineParam(mActualPipelineDelay, C2_PARAMKEY_PIPELINE_DELAY)
213 .withConstValue(new C2ActualPipelineDelayTuning(0u))
214 .build());
215
216 C2BlockPool::local_id_t outputPoolIds[1] = { C2BlockPool::BASIC_GRAPHIC };
217 addParameter(
218 DefineParam(mOutputPoolIds, C2_PARAMKEY_OUTPUT_BLOCK_POOLS)
219 .withDefault(C2PortBlockPoolsTuning::output::AllocShared(outputPoolIds))
220 .withFields({ C2F(mOutputPoolIds, m.values[0]).any(),
221 C2F(mOutputPoolIds, m.values).inRange(0, 1) })
222 .withSetter(OutputBlockPoolSetter)
223 .build());
224
225 addParameter(
226 DefineParam(mInputHdrStaticInfo, C2_PARAMKEY_HDR_STATIC_INFO)
227 .withDefault(new C2StreamHdrStaticInfo::input(0u))
228 .withFields({
229 C2F(mInputHdrStaticInfo, mastering.red.x).any(),
230 })
231 .withSetter(HdrStaticInfoSetter)
232 .build());
233
234 addParameter(
235 DefineParam(mOutputHdrStaticInfo, C2_PARAMKEY_HDR_STATIC_INFO)
236 .withConstValue(new C2StreamHdrStaticInfo::output(0u))
237 .build());
238
239 addParameter(
240 DefineParam(mInputColorAspectInfo, C2_PARAMKEY_COLOR_ASPECTS)
241 .withDefault(new C2StreamColorAspectsInfo::input(0u))
242 .withFields({
243 C2F(mInputColorAspectInfo, range).any(),
244 C2F(mInputColorAspectInfo, primaries).any(),
245 C2F(mInputColorAspectInfo, transfer).any(),
246 C2F(mInputColorAspectInfo, matrix).any(),
247 })
248 .withSetter(InputColorAspectsSetter)
249 .build());
250
251 addParameter(
252 DefineParam(
253 mColorAspectRequestInfo,
254 (std::string(C2_PARAMKEY_COLOR_ASPECTS) + ".request").c_str())
255 .withDefault(new C2StreamColorAspectsRequestInfo::output(0u))
256 .withFields({
257 C2F(mColorAspectRequestInfo, range).any(),
258 C2F(mColorAspectRequestInfo, primaries).any(),
259 C2F(mColorAspectRequestInfo, transfer).oneOf({
260 C2Color::TRANSFER_UNSPECIFIED,
261 C2Color::TRANSFER_170M,
262 }),
263 C2F(mColorAspectRequestInfo, matrix).any(),
264 })
265 .withSetter(ColorAspectsRequestSetter)
266 .build());
267
268 addParameter(
269 DefineParam(mOutputColorAspectInfo, C2_PARAMKEY_COLOR_ASPECTS)
270 .withDefault(new C2StreamColorAspectsInfo::output(0u))
271 .withFields({
272 C2F(mOutputColorAspectInfo, range).any(),
273 C2F(mOutputColorAspectInfo, primaries).any(),
274 C2F(mOutputColorAspectInfo, transfer).any(),
275 C2F(mOutputColorAspectInfo, matrix).any(),
276 })
277 .withSetter(OutputColorAspectsSetter,
278 mInputColorAspectInfo,
279 mColorAspectRequestInfo)
280 .build());
281 }
282
OutputBlockPoolSetterandroid::SampleToneMappingFilter::Interface::Helper283 static C2R OutputBlockPoolSetter(
284 bool mayBlock,
285 C2P<C2PortBlockPoolsTuning::output> &me) {
286 (void)mayBlock, (void)me;
287 return C2R::Ok();
288 }
289
HdrStaticInfoSetterandroid::SampleToneMappingFilter::Interface::Helper290 static C2R HdrStaticInfoSetter(
291 bool mayBlock,
292 C2P<C2StreamHdrStaticInfo::input> &me) {
293 (void)mayBlock, (void)me;
294 return C2R::Ok();
295 }
296
InputColorAspectsSetterandroid::SampleToneMappingFilter::Interface::Helper297 static C2R InputColorAspectsSetter(
298 bool mayBlock,
299 C2P<C2StreamColorAspectsInfo::input> &me) {
300 (void)mayBlock, (void)me;
301 return C2R::Ok();
302 }
303
OutputColorAspectsSetterandroid::SampleToneMappingFilter::Interface::Helper304 static C2R OutputColorAspectsSetter(
305 bool mayBlock,
306 C2P<C2StreamColorAspectsInfo::output> &me,
307 const C2P<C2StreamColorAspectsInfo::input> &inputColor,
308 const C2P<C2StreamColorAspectsRequestInfo::output> &request) {
309 (void)mayBlock;
310 me.set().range = inputColor.v.range;
311 me.set().primaries = inputColor.v.primaries;
312 me.set().transfer = inputColor.v.transfer;
313 if (request.v.transfer == C2Color::TRANSFER_170M) {
314 me.set().transfer = C2Color::TRANSFER_170M;
315 }
316 me.set().matrix = inputColor.v.matrix;
317 return C2R::Ok();
318 }
319
ColorAspectsRequestSetterandroid::SampleToneMappingFilter::Interface::Helper320 static C2R ColorAspectsRequestSetter(
321 bool mayBlock,
322 C2P<C2StreamColorAspectsRequestInfo::output> &me) {
323 (void)mayBlock;
324 if (me.v.range != C2Color::RANGE_UNSPECIFIED) {
325 me.set().range = C2Color::RANGE_UNSPECIFIED;
326 }
327 if (me.v.primaries != C2Color::PRIMARIES_UNSPECIFIED) {
328 me.set().primaries = C2Color::PRIMARIES_UNSPECIFIED;
329 }
330 if (me.v.transfer != C2Color::TRANSFER_170M) {
331 me.set().transfer = C2Color::TRANSFER_UNSPECIFIED;
332 }
333 if (me.v.matrix != C2Color::MATRIX_UNSPECIFIED) {
334 me.set().matrix = C2Color::MATRIX_UNSPECIFIED;
335 }
336 return C2R::Ok();
337 }
338
339 std::shared_ptr<C2ApiFeaturesSetting> mApiFeatures;
340
341 std::shared_ptr<C2ComponentNameSetting> mName;
342 std::shared_ptr<C2ComponentAliasesSetting> mAliases;
343 std::shared_ptr<C2ComponentKindSetting> mKind;
344 std::shared_ptr<C2ComponentDomainSetting> mDomain;
345
346 std::shared_ptr<C2PortMediaTypeSetting::input> mInputMediaType;
347 std::shared_ptr<C2PortMediaTypeSetting::output> mOutputMediaType;
348 std::shared_ptr<C2StreamBufferTypeSetting::input> mInputFormat;
349 std::shared_ptr<C2StreamBufferTypeSetting::output> mOutputFormat;
350
351 std::shared_ptr<C2PortActualDelayTuning::input> mActualInputDelay;
352 std::shared_ptr<C2PortActualDelayTuning::output> mActualOutputDelay;
353 std::shared_ptr<C2ActualPipelineDelayTuning> mActualPipelineDelay;
354
355 std::shared_ptr<C2PortStreamCountTuning::input> mInputStreamCount;
356 std::shared_ptr<C2PortStreamCountTuning::output> mOutputStreamCount;
357
358 std::shared_ptr<C2PortBlockPoolsTuning::output> mOutputPoolIds;
359
360 std::shared_ptr<C2StreamHdrStaticInfo::input> mInputHdrStaticInfo;
361 std::shared_ptr<C2StreamHdrStaticInfo::output> mOutputHdrStaticInfo;
362 std::shared_ptr<C2StreamColorAspectsInfo::input> mInputColorAspectInfo;
363 std::shared_ptr<C2StreamColorAspectsInfo::output> mOutputColorAspectInfo;
364 std::shared_ptr<C2StreamColorAspectsRequestInfo::output> mColorAspectRequestInfo;
365 } mHelper;
366 };
367
SampleToneMappingFilter(c2_node_id_t id)368 explicit SampleToneMappingFilter(c2_node_id_t id)
369 : mIntf(std::make_shared<Interface>(id)) {
370 }
~SampleToneMappingFilter()371 ~SampleToneMappingFilter() override {
372 if (mProcessingThread.joinable()) {
373 mProcessingThread.join();
374 }
375 }
376
setListener_vb(const std::shared_ptr<Listener> & listener,c2_blocking_t mayBlock)377 c2_status_t setListener_vb(
378 const std::shared_ptr<Listener> &listener, c2_blocking_t mayBlock) override {
379 std::chrono::steady_clock::time_point deadline = std::chrono::steady_clock::now() + 5ms;
380 {
381 std::unique_lock lock(mStateMutex);
382 if (mState == RELEASED) {
383 return C2_BAD_STATE;
384 }
385 if (mState == RUNNING && listener) {
386 return C2_BAD_STATE;
387 }
388 if (mState != STOPPED) {
389 return C2_BAD_STATE;
390 }
391 }
392 std::unique_lock lock(mListenerMutex, std::try_to_lock);
393 if (lock) {
394 mListener = listener;
395 return C2_OK;
396 }
397 if (mayBlock == C2_DONT_BLOCK) {
398 return C2_BLOCKING;
399 }
400 lock.try_lock_until(deadline);
401 if (!lock) {
402 return C2_TIMED_OUT;
403 }
404 mListener = listener;
405 return C2_OK;
406 }
407
queue_nb(std::list<std::unique_ptr<C2Work>> * const items)408 c2_status_t queue_nb(std::list<std::unique_ptr<C2Work>>* const items) override {
409 if (!items) {
410 return C2_BAD_VALUE;
411 }
412 {
413 std::unique_lock lock(mStateMutex);
414 if (mState != RUNNING) {
415 return C2_BAD_STATE;
416 }
417 }
418 std::unique_lock lock(mQueueMutex);
419 mQueue.splice(mQueue.end(), *items);
420 mQueueCondition.notify_all();
421 return C2_OK;
422 }
423
announce_nb(const std::vector<C2WorkOutline> &)424 c2_status_t announce_nb(const std::vector<C2WorkOutline> &) override { return C2_OMITTED; }
425
flush_sm(flush_mode_t mode,std::list<std::unique_ptr<C2Work>> * const flushedWork)426 c2_status_t flush_sm(
427 flush_mode_t mode,
428 std::list<std::unique_ptr<C2Work>>* const flushedWork) override {
429 if (!flushedWork) {
430 return C2_BAD_VALUE;
431 }
432 if (mode == FLUSH_CHAIN) {
433 return C2_BAD_VALUE;
434 }
435 {
436 std::unique_lock lock(mStateMutex);
437 if (mState != RUNNING) {
438 return C2_BAD_STATE;
439 }
440 }
441 {
442 std::unique_lock lock(mQueueMutex);
443 mQueue.swap(*flushedWork);
444 }
445 // NOTE: this component does not have internal state to flush.
446 return C2_OK;
447 }
448
drain_nb(drain_mode_t mode)449 c2_status_t drain_nb(drain_mode_t mode) override {
450 if (mode == DRAIN_CHAIN) {
451 return C2_BAD_VALUE;
452 }
453 {
454 std::unique_lock lock(mStateMutex);
455 if (mState != RUNNING) {
456 return C2_BAD_STATE;
457 }
458 }
459 // NOTE: this component does not wait for work items before processing.
460 return C2_OK;
461 }
462
start()463 c2_status_t start() override {
464 //std::chrono::steady_clock::time_point deadline = std::chrono::steady_clock::now() + 500ms;
465 {
466 std::unique_lock lock(mStateMutex);
467 if (mState == STARTING) {
468 return C2_DUPLICATE;
469 }
470 if (mState != STOPPED) {
471 return C2_BAD_STATE;
472 }
473 mState = STARTING;
474 }
475 {
476 std::unique_lock lock(mProcessingMutex);
477 if (!mProcessingThread.joinable()) {
478 mProcessingThread = std::thread([this]() {
479 processLoop(shared_from_this());
480 });
481 }
482 }
483 {
484 std::unique_lock lock(mStateMutex);
485 mState = RUNNING;
486 }
487 return C2_OK;
488 }
489
stop()490 c2_status_t stop() override {
491 //std::chrono::steady_clock::time_point deadline = std::chrono::steady_clock::now() + 500ms;
492 {
493 std::unique_lock lock(mStateMutex);
494 if (mState == STOPPING) {
495 return C2_DUPLICATE;
496 }
497 if (mState != RUNNING) {
498 return C2_BAD_STATE;
499 }
500 mState = STOPPING;
501 }
502 {
503 std::unique_lock lock(mQueueMutex);
504 mQueueCondition.notify_all();
505 }
506 {
507 std::unique_lock lock(mProcessingMutex);
508 if (mProcessingThread.joinable()) {
509 mProcessingThread.join();
510 }
511 }
512 {
513 std::unique_lock lock(mStateMutex);
514 mState = STOPPED;
515 }
516 return C2_OK;
517 }
518
reset()519 c2_status_t reset() override {
520 //std::chrono::steady_clock::time_point deadline = std::chrono::steady_clock::now() + 500ms;
521 {
522 std::unique_lock lock(mStateMutex);
523 if (mState == RESETTING) {
524 return C2_DUPLICATE;
525 }
526 if (mState == RELEASED) {
527 return C2_BAD_STATE;
528 }
529 mState = RESETTING;
530 }
531 {
532 std::unique_lock lock(mQueueMutex);
533 mQueueCondition.notify_all();
534 }
535 {
536 std::unique_lock lock(mProcessingMutex);
537 if (mProcessingThread.joinable()) {
538 mProcessingThread.join();
539 }
540 }
541 {
542 std::unique_lock lock(mStateMutex);
543 mState = STOPPED;
544 }
545 return C2_OK;
546 }
547
release()548 c2_status_t release() override {
549 //std::chrono::steady_clock::time_point deadline = std::chrono::steady_clock::now() + 500ms;
550 {
551 std::unique_lock lock(mStateMutex);
552 if (mState == RELEASED || mState == RELEASING) {
553 return C2_DUPLICATE;
554 }
555 // TODO: return C2_BAD_STATE if not stopped
556 mState = RELEASING;
557 }
558 {
559 std::unique_lock lock(mQueueMutex);
560 mQueueCondition.notify_all();
561 }
562 {
563 std::unique_lock lock(mProcessingMutex);
564 if (mProcessingThread.joinable()) {
565 mProcessingThread.join();
566 }
567 }
568 {
569 std::unique_lock lock(mStateMutex);
570 mState = RELEASED;
571 }
572 return C2_OK;
573 }
574
intf()575 std::shared_ptr<C2ComponentInterface> intf() override {
576 return mIntf;
577 }
578
579 private:
processLoop(std::shared_ptr<SampleToneMappingFilter> thiz)580 void processLoop(std::shared_ptr<SampleToneMappingFilter> thiz) {
581 constexpr float kDefaultMaxLumiance = 500.0;
582 constexpr float kDefaultMaxMasteringLuminance = 1000.0;
583 constexpr float kDefaultMaxContentLuminance = 1000.0;
584 constexpr uint32_t kDstUsage =
585 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
586 GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
587
588 int32_t workCount = 0;
589 std::unique_ptr<renderengine::RenderEngine> renderEngine = renderengine::RenderEngine::create(
590 renderengine::RenderEngineCreationArgs::Builder()
591 .setPixelFormat(static_cast<int>(ui::PixelFormat::RGBA_8888))
592 .setImageCacheSize(2 /*maxFrameBufferAcquiredBuffers*/)
593 .setUseColorManagerment(true)
594 .setEnableProtectedContext(false)
595 .setPrecacheToneMapperShaderOnly(true)
596 .setContextPriority(renderengine::RenderEngine::ContextPriority::LOW)
597 .build());
598 if (!renderEngine) {
599 std::unique_lock lock(mListenerMutex);
600 mListener->onError_nb(thiz, C2_CORRUPTED);
601 return;
602 }
603 uint32_t textureName = 0;
604 renderEngine->genTextures(1, &textureName);
605
606 while (true) {
607 // Before doing anything, verify the state
608 {
609 std::unique_lock lock(mStateMutex);
610 if (mState != RUNNING) {
611 break;
612 }
613 }
614 // Extract one work item
615 std::unique_ptr<C2Work> work;
616 {
617 std::unique_lock lock(mQueueMutex);
618 if (mQueue.empty()) {
619 mQueueCondition.wait_for(lock, 1s);
620 }
621 if (mQueue.empty()) {
622 continue;
623 }
624 mQueue.front().swap(work);
625 mQueue.pop_front();
626 ++workCount;
627 }
628 LOG(VERBOSE) << "work #" << workCount << ": flags=" << work->input.flags
629 << " timestamp=" << work->input.ordinal.timestamp.peek();;
630
631 std::vector<C2Param *> configUpdate;
632 for (const std::unique_ptr<C2Param> ¶m : work->input.configUpdate) {
633 configUpdate.push_back(param.get());
634 }
635 std::vector<std::unique_ptr<C2SettingResult>> failures;
636 mIntf->config_vb(configUpdate, C2_MAY_BLOCK, &failures);
637
638 std::shared_ptr<C2StreamHdrStaticInfo::input> hdrStaticInfo =
639 mIntf->getHdrStaticMetadata();
640 uint32_t dataspace = mIntf->getDataSpace();
641
642 std::shared_ptr<C2Buffer> buffer;
643 if (!work->input.buffers.empty()) {
644 buffer = work->input.buffers.front();
645 }
646 std::shared_ptr<C2Buffer> outC2Buffer;
647 status_t err = OK;
648 if (buffer) {
649 if (buffer->hasInfo(C2StreamHdrStaticInfo::output::PARAM_TYPE)) {
650 std::shared_ptr<const C2Info> info =
651 buffer->getInfo(C2StreamHdrStaticInfo::output::PARAM_TYPE);
652 std::unique_ptr<C2Param> flipped = C2Param::CopyAsStream(
653 *info, false /* output */, info->stream());
654 hdrStaticInfo.reset(static_cast<C2StreamHdrStaticInfo::input *>(
655 flipped.release()));
656 }
657 const C2Handle *c2Handle =
658 buffer->data().graphicBlocks().front().handle();
659 uint32_t width, height, format, stride, igbp_slot, generation;
660 uint64_t usage, igbp_id;
661 _UnwrapNativeCodec2GrallocMetadata(
662 c2Handle, &width, &height, &format, &usage, &stride, &generation,
663 &igbp_id, &igbp_slot);
664 native_handle_t *grallocHandle = UnwrapNativeCodec2GrallocHandle(c2Handle);
665 sp<GraphicBuffer> srcBuffer = new GraphicBuffer(
666 grallocHandle, GraphicBuffer::CLONE_HANDLE,
667 width, height, format, 1, usage, stride);
668
669 native_handle_delete(grallocHandle);
670 std::shared_ptr<C2GraphicBlock> dstBlock;
671 C2BlockPool::local_id_t poolId = mIntf->getPoolId();
672 std::shared_ptr<C2BlockPool> pool;
673 GetCodec2BlockPool(poolId, thiz, &pool);
674 pool->fetchGraphicBlock(
675 width, height, HAL_PIXEL_FORMAT_RGBA_8888, C2AndroidMemoryUsage::FromGrallocUsage(kDstUsage),
676 &dstBlock);
677 outC2Buffer = C2Buffer::CreateGraphicBuffer(
678 dstBlock->share(C2Rect(width, height), C2Fence()));
679 c2Handle = dstBlock->handle();
680 _UnwrapNativeCodec2GrallocMetadata(
681 c2Handle, &width, &height, &format, &usage, &stride, &generation,
682 &igbp_id, &igbp_slot);
683 grallocHandle = UnwrapNativeCodec2GrallocHandle(c2Handle);
684 sp<GraphicBuffer> dstBuffer = new GraphicBuffer(
685 grallocHandle, GraphicBuffer::CLONE_HANDLE,
686 width, height, format, 1, usage, stride);
687
688 native_handle_delete(grallocHandle);
689 Rect sourceCrop(0, 0, width, height);
690
691 renderengine::DisplaySettings clientCompositionDisplay;
692 std::vector<const renderengine::LayerSettings*> clientCompositionLayers;
693
694 clientCompositionDisplay.physicalDisplay = sourceCrop;
695 clientCompositionDisplay.clip = sourceCrop;
696
697 clientCompositionDisplay.outputDataspace = ui::Dataspace::V0_SRGB;
698 clientCompositionDisplay.maxLuminance = kDefaultMaxLumiance;
699 clientCompositionDisplay.clearRegion = Region::INVALID_REGION;
700 renderengine::LayerSettings layerSettings;
701 layerSettings.geometry.boundaries = sourceCrop.toFloatRect();
702 layerSettings.alpha = 1.0f;
703
704 layerSettings.sourceDataspace = static_cast<ui::Dataspace>(dataspace);
705
706 // from BufferLayer
707 layerSettings.source.buffer.buffer = srcBuffer;
708 layerSettings.source.buffer.isOpaque = true;
709 // TODO: fence
710 layerSettings.source.buffer.fence = Fence::NO_FENCE;
711 layerSettings.source.buffer.textureName = textureName;
712 layerSettings.source.buffer.usePremultipliedAlpha = false;
713 layerSettings.source.buffer.maxMasteringLuminance =
714 (hdrStaticInfo && *hdrStaticInfo &&
715 hdrStaticInfo->mastering.maxLuminance > 0 &&
716 hdrStaticInfo->mastering.minLuminance > 0)
717 ? hdrStaticInfo->mastering.maxLuminance : kDefaultMaxMasteringLuminance;
718 layerSettings.source.buffer.maxContentLuminance =
719 (hdrStaticInfo && *hdrStaticInfo && hdrStaticInfo->maxCll > 0)
720 ? hdrStaticInfo->maxCll : kDefaultMaxContentLuminance;
721
722 // Set filtering to false since the capture itself doesn't involve
723 // any scaling, metadata retriever JNI is scaling the bitmap if
724 // display size is different from decoded size. If that scaling
725 // needs to be handled by server side, consider enable this based
726 // display size vs decoded size.
727 layerSettings.source.buffer.useTextureFiltering = false;
728 layerSettings.source.buffer.textureTransform = mat4();
729 clientCompositionLayers.push_back(&layerSettings);
730
731 // Use an empty fence for the buffer fence, since we just created the buffer so
732 // there is no need for synchronization with the GPU.
733 base::unique_fd bufferFence;
734 base::unique_fd drawFence;
735 renderEngine->useProtectedContext(false);
736 err = renderEngine->drawLayers(
737 clientCompositionDisplay, clientCompositionLayers, dstBuffer.get(),
738 /*useFramebufferCache=*/false, std::move(bufferFence), &drawFence);
739
740 sp<Fence> fence = new Fence(std::move(drawFence));
741
742 // We can move waiting for fence & sending it back on a separate thread to improve
743 // efficiency, but leaving it here for simplicity.
744 if (err != OK) {
745 LOG(ERROR) << "drawLayers returned err " << err;
746 } else {
747 err = fence->wait(500);
748 if (err != OK) {
749 LOG(WARNING) << "wait for fence returned err " << err;
750 }
751 }
752 renderEngine->cleanupPostRender(renderengine::RenderEngine::CleanupMode::CLEAN_ALL);
753 }
754
755 work->worklets.front()->output.ordinal = work->input.ordinal;
756 work->worklets.front()->output.flags = work->input.flags;
757 if (err == OK) {
758 work->workletsProcessed = 1;
759 if (outC2Buffer) {
760 work->worklets.front()->output.buffers.push_back(outC2Buffer);
761 }
762 work->result = C2_OK;
763 } else {
764 work->result = C2_CORRUPTED;
765 }
766 std::list<std::unique_ptr<C2Work>> items;
767 items.push_back(std::move(work));
768
769 std::unique_lock lock(mListenerMutex);
770 mListener->onWorkDone_nb(thiz, std::move(items));
771 LOG(VERBOSE) << "sent work #" << workCount;
772 }
773 }
774
775 mutable std::timed_mutex mListenerMutex;
776 std::shared_ptr<Listener> mListener;
777
778 mutable std::mutex mQueueMutex;
779 mutable std::condition_variable mQueueCondition;
780 std::list<std::unique_ptr<C2Work>> mQueue;
781
782 const std::shared_ptr<Interface> mIntf;
783
784 mutable std::mutex mStateMutex;
785 enum State {
786 STOPPED,
787 RUNNING,
788 RELEASED,
789 STARTING, // STOPPED -> RUNNING
790 STOPPING, // RUNNING -> STOPPED
791 RESETTING, // <<ANY>> -> STOPPED
792 RELEASING, // STOPPED -> RELEASED
793 } mState;
794
795 mutable std::mutex mProcessingMutex;
796 std::thread mProcessingThread;
797
798 };
799
800 // static
801 const std::string SampleToneMappingFilter::Interface::NAME = "c2.sample.tone-mapper";
802 // static
803 const FilterPlugin_V1::Descriptor SampleToneMappingFilter::Interface::DESCRIPTOR = {
804 // controlParams
805 { C2StreamColorAspectsRequestInfo::output::PARAM_TYPE },
806 // affectedParams
807 {
808 C2StreamHdrStaticInfo::output::PARAM_TYPE,
809 C2StreamColorAspectsInfo::output::PARAM_TYPE,
810 },
811 };
812
813 class SampleC2ComponentStore : public C2ComponentStore {
814 public:
SampleC2ComponentStore()815 SampleC2ComponentStore()
816 : mReflector(std::make_shared<C2ReflectorHelper>()),
817 mIntf(mReflector),
818 mFactories(CreateFactories()) {
819 }
820 ~SampleC2ComponentStore() = default;
821
getName() const822 C2String getName() const override { return "android.sample.filter-plugin-store"; }
createComponent(C2String name,std::shared_ptr<C2Component> * const component)823 c2_status_t createComponent(
824 C2String name, std::shared_ptr<C2Component>* const component) override {
825 if (mFactories.count(name) == 0) {
826 return C2_BAD_VALUE;
827 }
828 return mFactories.at(name)->createComponent(++mNodeId, component);
829 }
createInterface(C2String name,std::shared_ptr<C2ComponentInterface> * const interface)830 c2_status_t createInterface(
831 C2String name, std::shared_ptr<C2ComponentInterface>* const interface) override {
832 if (mFactories.count(name) == 0) {
833 return C2_BAD_VALUE;
834 }
835 return mFactories.at(name)->createInterface(++mNodeId, interface);
836 }
listComponents()837 std::vector<std::shared_ptr<const C2Component::Traits>> listComponents() override {
838 std::vector<std::shared_ptr<const C2Component::Traits>> ret;
839 for (const auto &[name, factory] : mFactories) {
840 ret.push_back(factory->getTraits());
841 }
842 return ret;
843 }
copyBuffer(std::shared_ptr<C2GraphicBuffer>,std::shared_ptr<C2GraphicBuffer>)844 c2_status_t copyBuffer(
845 std::shared_ptr<C2GraphicBuffer>, std::shared_ptr<C2GraphicBuffer>) override {
846 return C2_OMITTED;
847 }
query_sm(const std::vector<C2Param * > & stackParams,const std::vector<C2Param::Index> & heapParamIndices,std::vector<std::unique_ptr<C2Param>> * const heapParams) const848 c2_status_t query_sm(
849 const std::vector<C2Param*> &stackParams,
850 const std::vector<C2Param::Index> &heapParamIndices,
851 std::vector<std::unique_ptr<C2Param>>* const heapParams) const override {
852 return mIntf.query(stackParams, heapParamIndices, C2_MAY_BLOCK, heapParams);
853 }
config_sm(const std::vector<C2Param * > & params,std::vector<std::unique_ptr<C2SettingResult>> * const failures)854 c2_status_t config_sm(
855 const std::vector<C2Param*> ¶ms,
856 std::vector<std::unique_ptr<C2SettingResult>>* const failures) override {
857 return mIntf.config(params, C2_MAY_BLOCK, failures);
858 }
getParamReflector() const859 std::shared_ptr<C2ParamReflector> getParamReflector() const override {
860 return mReflector;
861 }
querySupportedParams_nb(std::vector<std::shared_ptr<C2ParamDescriptor>> * const params) const862 c2_status_t querySupportedParams_nb(
863 std::vector<std::shared_ptr<C2ParamDescriptor>> * const params) const override {
864 return mIntf.querySupportedParams(params);
865 }
querySupportedValues_sm(std::vector<C2FieldSupportedValuesQuery> & fields) const866 c2_status_t querySupportedValues_sm(
867 std::vector<C2FieldSupportedValuesQuery> &fields) const override {
868 return mIntf.querySupportedValues(fields, C2_MAY_BLOCK);
869 }
870
871 private:
872 class ComponentFactory {
873 public:
874 virtual ~ComponentFactory() = default;
875
getTraits()876 const std::shared_ptr<const C2Component::Traits> &getTraits() { return mTraits; }
877
878 virtual c2_status_t createComponent(
879 c2_node_id_t id,
880 std::shared_ptr<C2Component>* const component) const = 0;
881 virtual c2_status_t createInterface(
882 c2_node_id_t id,
883 std::shared_ptr<C2ComponentInterface>* const interface) const = 0;
884 protected:
ComponentFactory(const std::shared_ptr<const C2Component::Traits> & traits)885 ComponentFactory(const std::shared_ptr<const C2Component::Traits> &traits)
886 : mTraits(traits) {
887 }
888 private:
889 const std::shared_ptr<const C2Component::Traits> mTraits;
890 };
891
892 template <class T>
893 struct ComponentFactoryImpl : public ComponentFactory {
894 public:
ComponentFactoryImplandroid::SampleC2ComponentStore::ComponentFactoryImpl895 ComponentFactoryImpl(const std::shared_ptr<const C2Component::Traits> &traits)
896 : ComponentFactory(traits) {
897 }
898 ~ComponentFactoryImpl() override = default;
createComponentandroid::SampleC2ComponentStore::ComponentFactoryImpl899 c2_status_t createComponent(
900 c2_node_id_t id,
901 std::shared_ptr<C2Component>* const component) const override {
902 *component = std::make_shared<T>(id);
903 return C2_OK;
904 }
createInterfaceandroid::SampleC2ComponentStore::ComponentFactoryImpl905 c2_status_t createInterface(
906 c2_node_id_t id,
907 std::shared_ptr<C2ComponentInterface>* const interface) const override {
908 *interface = std::make_shared<typename T::Interface>(id);
909 return C2_OK;
910 }
911 };
912
913 template <class T>
AddFactory(std::map<C2String,std::unique_ptr<ComponentFactory>> * factories)914 static void AddFactory(std::map<C2String, std::unique_ptr<ComponentFactory>> *factories) {
915 std::shared_ptr<C2ComponentInterface> intf{new typename T::Interface(0)};
916 std::shared_ptr<C2Component::Traits> traits(new (std::nothrow) C2Component::Traits);
917 CHECK(C2InterfaceUtils::FillTraitsFromInterface(traits.get(), intf))
918 << "Failed to fill traits from interface";
919 factories->emplace(traits->name, new ComponentFactoryImpl<T>(traits));
920 }
921
CreateFactories()922 static std::map<C2String, std::unique_ptr<ComponentFactory>> CreateFactories() {
923 std::map<C2String, std::unique_ptr<ComponentFactory>> factories;
924 AddFactory<SampleToneMappingFilter>(&factories);
925 return factories;
926 }
927
928
929 std::shared_ptr<C2ReflectorHelper> mReflector;
930 struct Interface : public C2InterfaceHelper {
Interfaceandroid::SampleC2ComponentStore::Interface931 explicit Interface(std::shared_ptr<C2ReflectorHelper> reflector)
932 : C2InterfaceHelper(reflector) {
933 }
934 } mIntf;
935
936 const std::map<C2String, std::unique_ptr<ComponentFactory>> mFactories;
937
938 std::atomic_int32_t mNodeId{0};
939 };
940
941 class SampleFilterPlugin : public FilterPlugin_V1 {
942 public:
SampleFilterPlugin()943 SampleFilterPlugin() : mStore(new SampleC2ComponentStore) {}
944 ~SampleFilterPlugin() override = default;
945
getComponentStore()946 std::shared_ptr<C2ComponentStore> getComponentStore() override {
947 return mStore;
948 }
949
describe(C2String name,Descriptor * desc)950 bool describe(C2String name, Descriptor *desc) override {
951 if (name == SampleToneMappingFilter::Interface::NAME) {
952 *desc = SampleToneMappingFilter::Interface::DESCRIPTOR;
953 return true;
954 }
955 return false;
956 }
957
isFilteringEnabled(const std::shared_ptr<C2ComponentInterface> & intf)958 bool isFilteringEnabled(const std::shared_ptr<C2ComponentInterface> &intf) override {
959 if (intf->getName() == SampleToneMappingFilter::Interface::NAME) {
960 return SampleToneMappingFilter::Interface::IsFilteringEnabled(intf);
961 }
962 return false;
963 }
964
queryParamsForPreviousComponent(const std::shared_ptr<C2ComponentInterface> & intf,std::vector<std::unique_ptr<C2Param>> * params)965 c2_status_t queryParamsForPreviousComponent(
966 const std::shared_ptr<C2ComponentInterface> &intf,
967 std::vector<std::unique_ptr<C2Param>> *params) override {
968 if (intf->getName() == SampleToneMappingFilter::Interface::NAME) {
969 return SampleToneMappingFilter::Interface::QueryParamsForPreviousComponent(
970 intf, params);
971 }
972 return C2_BAD_VALUE;
973 }
974
975 private:
976 std::shared_ptr<C2ComponentStore> mStore;
977 };
978
979 } // namespace android
980
981 extern "C" {
982
GetFilterPluginVersion()983 int32_t GetFilterPluginVersion() {
984 return ::android::SampleFilterPlugin::VERSION;
985 }
986
CreateFilterPlugin()987 void *CreateFilterPlugin() {
988 return new ::android::SampleFilterPlugin;
989 }
990
DestroyFilterPlugin(void * plugin)991 void DestroyFilterPlugin(void *plugin) {
992 delete (::android::SampleFilterPlugin *)plugin;
993 }
994
995 } // extern "C"
996