1 /*
2  * Copyright 2017 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 "C2GoldfishAvcDec"
19 #include <inttypes.h>
20 #include <log/log.h>
21 #include <media/stagefright/foundation/AUtils.h>
22 #include <media/stagefright/foundation/MediaDefs.h>
23 
24 #include <C2AllocatorGralloc.h>
25 #include <C2PlatformSupport.h>
26 //#include <android/hardware/graphics/common/1.0/types.h>
27 
28 #include <android/hardware/graphics/allocator/3.0/IAllocator.h>
29 #include <android/hardware/graphics/mapper/3.0/IMapper.h>
30 #include <hidl/LegacySupport.h>
31 
32 #include <media/stagefright/foundation/MediaDefs.h>
33 
34 #include <C2Debug.h>
35 #include <C2PlatformSupport.h>
36 #include <Codec2Mapper.h>
37 #include <SimpleC2Interface.h>
38 #include <goldfish_codec2/store/GoldfishComponentStore.h>
39 #include <gralloc_cb_bp.h>
40 
41 #include <color_buffer_utils.h>
42 
43 #include "C2GoldfishAvcDec.h"
44 
45 #include <mutex>
46 
47 #define DEBUG 0
48 #if DEBUG
49 #define DDD(...) ALOGD(__VA_ARGS__)
50 #else
51 #define DDD(...) ((void)0)
52 #endif
53 
54 using ::android::hardware::graphics::common::V1_0::BufferUsage;
55 using ::android::hardware::graphics::common::V1_2::PixelFormat;
56 
57 namespace android {
58 
59 namespace {
60 constexpr size_t kMinInputBufferSize = 6 * 1024 * 1024;
61 constexpr char COMPONENT_NAME[] = "c2.goldfish.h264.decoder";
62 constexpr uint32_t kDefaultOutputDelay = 8;
63 /* avc specification allows for a maximum delay of 16 frames.
64    As soft avc decoder supports interlaced, this delay would be 32 fields.
65    And avc decoder implementation has an additional delay of 2 decode calls.
66    So total maximum output delay is 34 */
67 constexpr uint32_t kMaxOutputDelay = 34;
68 constexpr uint32_t kMinInputBytes = 4;
69 
70 static std::mutex s_decoder_count_mutex;
71 static int s_decoder_count = 0;
72 
allocateDecoderId()73 int allocateDecoderId() {
74   DDD("calling %s", __func__);
75   std::lock_guard<std::mutex> lock(s_decoder_count_mutex);
76   if (s_decoder_count >= 32 || s_decoder_count < 0) {
77     ALOGE("calling %s failed", __func__);
78     return -1;
79   }
80   ++ s_decoder_count;
81   DDD("calling %s success total decoder %d", __func__, s_decoder_count);
82   return s_decoder_count;;
83 }
84 
deAllocateDecoderId()85 bool deAllocateDecoderId() {
86   DDD("calling %s", __func__);
87   std::lock_guard<std::mutex> lock(s_decoder_count_mutex);
88   if (s_decoder_count < 1) {
89     ALOGE("calling %s failed ", __func__);
90     return false;
91   }
92   -- s_decoder_count;
93   DDD("calling %s success total decoder %d", __func__, s_decoder_count);
94   return true;
95 }
96 
97 
98 } // namespace
99 
100 class C2GoldfishAvcDec::IntfImpl : public SimpleInterface<void>::BaseParams {
101   public:
IntfImpl(const std::shared_ptr<C2ReflectorHelper> & helper)102     explicit IntfImpl(const std::shared_ptr<C2ReflectorHelper> &helper)
103         : SimpleInterface<void>::BaseParams(
104               helper, COMPONENT_NAME, C2Component::KIND_DECODER,
105               C2Component::DOMAIN_VIDEO, MEDIA_MIMETYPE_VIDEO_AVC) {
106         noPrivateBuffers(); // TODO: account for our buffers here
107         noInputReferences();
108         noOutputReferences();
109         noInputLatency();
110         noTimeStretch();
111 
112         // TODO: Proper support for reorder depth.
113         addParameter(
114             DefineParam(mActualOutputDelay, C2_PARAMKEY_OUTPUT_DELAY)
115                 .withDefault(
116                     new C2PortActualDelayTuning::output(kDefaultOutputDelay))
117                 .withFields({C2F(mActualOutputDelay, value)
118                                  .inRange(0, kMaxOutputDelay)})
119                 .withSetter(
120                     Setter<
121                         decltype(*mActualOutputDelay)>::StrictValueWithNoDeps)
122                 .build());
123 
124         // TODO: output latency and reordering
125 
126         addParameter(DefineParam(mAttrib, C2_PARAMKEY_COMPONENT_ATTRIBUTES)
127                          .withConstValue(new C2ComponentAttributesSetting(
128                              C2Component::ATTRIB_IS_TEMPORAL))
129                          .build());
130 
131         // coded and output picture size is the same for this codec
132         addParameter(
133             DefineParam(mSize, C2_PARAMKEY_PICTURE_SIZE)
134                 .withDefault(new C2StreamPictureSizeInfo::output(0u, 320, 240))
135                 .withFields({
136                     C2F(mSize, width).inRange(2, 4096, 2),
137                     C2F(mSize, height).inRange(2, 4096, 2),
138                 })
139                 .withSetter(SizeSetter)
140                 .build());
141 
142         addParameter(DefineParam(mMaxSize, C2_PARAMKEY_MAX_PICTURE_SIZE)
143                          .withDefault(new C2StreamMaxPictureSizeTuning::output(
144                              0u, 320, 240))
145                          .withFields({
146                              C2F(mSize, width).inRange(2, 4096, 2),
147                              C2F(mSize, height).inRange(2, 4096, 2),
148                          })
149                          .withSetter(MaxPictureSizeSetter, mSize)
150                          .build());
151 
152         addParameter(
153             DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL)
154                 .withDefault(new C2StreamProfileLevelInfo::input(
155                     0u, C2Config::PROFILE_AVC_CONSTRAINED_BASELINE,
156                     C2Config::LEVEL_AVC_5_2))
157                 .withFields(
158                     {C2F(mProfileLevel, profile)
159                          .oneOf({C2Config::PROFILE_AVC_CONSTRAINED_BASELINE,
160                                  C2Config::PROFILE_AVC_BASELINE,
161                                  C2Config::PROFILE_AVC_MAIN,
162                                  C2Config::PROFILE_AVC_CONSTRAINED_HIGH,
163                                  C2Config::PROFILE_AVC_PROGRESSIVE_HIGH,
164                                  C2Config::PROFILE_AVC_HIGH}),
165                      C2F(mProfileLevel, level)
166                          .oneOf(
167                              {C2Config::LEVEL_AVC_1, C2Config::LEVEL_AVC_1B,
168                               C2Config::LEVEL_AVC_1_1, C2Config::LEVEL_AVC_1_2,
169                               C2Config::LEVEL_AVC_1_3, C2Config::LEVEL_AVC_2,
170                               C2Config::LEVEL_AVC_2_1, C2Config::LEVEL_AVC_2_2,
171                               C2Config::LEVEL_AVC_3, C2Config::LEVEL_AVC_3_1,
172                               C2Config::LEVEL_AVC_3_2, C2Config::LEVEL_AVC_4,
173                               C2Config::LEVEL_AVC_4_1, C2Config::LEVEL_AVC_4_2,
174                               C2Config::LEVEL_AVC_5, C2Config::LEVEL_AVC_5_1,
175                               C2Config::LEVEL_AVC_5_2})})
176                 .withSetter(ProfileLevelSetter, mSize)
177                 .build());
178 
179         addParameter(
180             DefineParam(mMaxInputSize, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE)
181                 .withDefault(new C2StreamMaxBufferSizeInfo::input(
182                     0u, kMinInputBufferSize))
183                 .withFields({
184                     C2F(mMaxInputSize, value).any(),
185                 })
186                 .calculatedAs(MaxInputSizeSetter, mMaxSize)
187                 .build());
188 
189         C2ChromaOffsetStruct locations[1] = {
190             C2ChromaOffsetStruct::ITU_YUV_420_0()};
191         std::shared_ptr<C2StreamColorInfo::output> defaultColorInfo =
192             C2StreamColorInfo::output::AllocShared(1u, 0u, 8u /* bitDepth */,
193                                                    C2Color::YUV_420);
194         memcpy(defaultColorInfo->m.locations, locations, sizeof(locations));
195 
196         defaultColorInfo = C2StreamColorInfo::output::AllocShared(
197             {C2ChromaOffsetStruct::ITU_YUV_420_0()}, 0u, 8u /* bitDepth */,
198             C2Color::YUV_420);
199         helper->addStructDescriptors<C2ChromaOffsetStruct>();
200 
201         addParameter(DefineParam(mColorInfo, C2_PARAMKEY_CODED_COLOR_INFO)
202                          .withConstValue(defaultColorInfo)
203                          .build());
204 
205         addParameter(
206             DefineParam(mDefaultColorAspects, C2_PARAMKEY_DEFAULT_COLOR_ASPECTS)
207                 .withDefault(new C2StreamColorAspectsTuning::output(
208                     0u, C2Color::RANGE_UNSPECIFIED,
209                     C2Color::PRIMARIES_UNSPECIFIED,
210                     C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED))
211                 .withFields({C2F(mDefaultColorAspects, range)
212                                  .inRange(C2Color::RANGE_UNSPECIFIED,
213                                           C2Color::RANGE_OTHER),
214                              C2F(mDefaultColorAspects, primaries)
215                                  .inRange(C2Color::PRIMARIES_UNSPECIFIED,
216                                           C2Color::PRIMARIES_OTHER),
217                              C2F(mDefaultColorAspects, transfer)
218                                  .inRange(C2Color::TRANSFER_UNSPECIFIED,
219                                           C2Color::TRANSFER_OTHER),
220                              C2F(mDefaultColorAspects, matrix)
221                                  .inRange(C2Color::MATRIX_UNSPECIFIED,
222                                           C2Color::MATRIX_OTHER)})
223                 .withSetter(DefaultColorAspectsSetter)
224                 .build());
225 
226         addParameter(
227             DefineParam(mCodedColorAspects, C2_PARAMKEY_VUI_COLOR_ASPECTS)
228                 .withDefault(new C2StreamColorAspectsInfo::input(
229                     0u, C2Color::RANGE_LIMITED, C2Color::PRIMARIES_UNSPECIFIED,
230                     C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED))
231                 .withFields({C2F(mCodedColorAspects, range)
232                                  .inRange(C2Color::RANGE_UNSPECIFIED,
233                                           C2Color::RANGE_OTHER),
234                              C2F(mCodedColorAspects, primaries)
235                                  .inRange(C2Color::PRIMARIES_UNSPECIFIED,
236                                           C2Color::PRIMARIES_OTHER),
237                              C2F(mCodedColorAspects, transfer)
238                                  .inRange(C2Color::TRANSFER_UNSPECIFIED,
239                                           C2Color::TRANSFER_OTHER),
240                              C2F(mCodedColorAspects, matrix)
241                                  .inRange(C2Color::MATRIX_UNSPECIFIED,
242                                           C2Color::MATRIX_OTHER)})
243                 .withSetter(CodedColorAspectsSetter)
244                 .build());
245 
246         addParameter(
247             DefineParam(mColorAspects, C2_PARAMKEY_COLOR_ASPECTS)
248                 .withDefault(new C2StreamColorAspectsInfo::output(
249                     0u, C2Color::RANGE_UNSPECIFIED,
250                     C2Color::PRIMARIES_UNSPECIFIED,
251                     C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED))
252                 .withFields({C2F(mColorAspects, range)
253                                  .inRange(C2Color::RANGE_UNSPECIFIED,
254                                           C2Color::RANGE_OTHER),
255                              C2F(mColorAspects, primaries)
256                                  .inRange(C2Color::PRIMARIES_UNSPECIFIED,
257                                           C2Color::PRIMARIES_OTHER),
258                              C2F(mColorAspects, transfer)
259                                  .inRange(C2Color::TRANSFER_UNSPECIFIED,
260                                           C2Color::TRANSFER_OTHER),
261                              C2F(mColorAspects, matrix)
262                                  .inRange(C2Color::MATRIX_UNSPECIFIED,
263                                           C2Color::MATRIX_OTHER)})
264                 .withSetter(ColorAspectsSetter, mDefaultColorAspects,
265                             mCodedColorAspects)
266                 .build());
267 
268         // TODO: support more formats?
269         addParameter(DefineParam(mPixelFormat, C2_PARAMKEY_PIXEL_FORMAT)
270                          .withConstValue(new C2StreamPixelFormatInfo::output(
271                              0u, HAL_PIXEL_FORMAT_YCBCR_420_888))
272                          .build());
273     }
SizeSetter(bool mayBlock,const C2P<C2StreamPictureSizeInfo::output> & oldMe,C2P<C2StreamPictureSizeInfo::output> & me)274     static C2R SizeSetter(bool mayBlock,
275                           const C2P<C2StreamPictureSizeInfo::output> &oldMe,
276                           C2P<C2StreamPictureSizeInfo::output> &me) {
277         (void)mayBlock;
278         DDD("calling sizesetter now %d", oldMe.v.height);
279         DDD("new calling sizesetter now %d", me.v.height);
280 
281         C2R res = C2R::Ok();
282         if (!me.F(me.v.width).supportsAtAll(me.v.width)) {
283             ALOGW("w %d is not supported, using old one %d", me.v.width, oldMe.v.width);
284             res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.width)));
285             me.set().width = oldMe.v.width;
286         }
287         if (!me.F(me.v.height).supportsAtAll(me.v.height)) {
288             ALOGW("h %d is not supported, using old one %d", me.v.height, oldMe.v.height);
289             res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.height)));
290             me.set().height = oldMe.v.height;
291         }
292         return res;
293     }
294 
295     static C2R
MaxPictureSizeSetter(bool mayBlock,C2P<C2StreamMaxPictureSizeTuning::output> & me,const C2P<C2StreamPictureSizeInfo::output> & size)296     MaxPictureSizeSetter(bool mayBlock,
297                          C2P<C2StreamMaxPictureSizeTuning::output> &me,
298                          const C2P<C2StreamPictureSizeInfo::output> &size) {
299         (void)mayBlock;
300         // TODO: get max width/height from the size's field helpers vs.
301         // hardcoding
302         me.set().width = c2_min(c2_max(me.v.width, size.v.width), 4096u);
303         me.set().height = c2_min(c2_max(me.v.height, size.v.height), 4096u);
304         return C2R::Ok();
305     }
306 
MaxInputSizeSetter(bool mayBlock,C2P<C2StreamMaxBufferSizeInfo::input> & me,const C2P<C2StreamMaxPictureSizeTuning::output> & maxSize)307     static C2R MaxInputSizeSetter(
308         bool mayBlock, C2P<C2StreamMaxBufferSizeInfo::input> &me,
309         const C2P<C2StreamMaxPictureSizeTuning::output> &maxSize) {
310         (void)mayBlock;
311         // assume compression ratio of 2
312         me.set().value = c2_max((((maxSize.v.width + 15) / 16) *
313                                  ((maxSize.v.height + 15) / 16) * 192),
314                                 kMinInputBufferSize);
315         return C2R::Ok();
316     }
317 
318     static C2R
ProfileLevelSetter(bool mayBlock,C2P<C2StreamProfileLevelInfo::input> & me,const C2P<C2StreamPictureSizeInfo::output> & size)319     ProfileLevelSetter(bool mayBlock, C2P<C2StreamProfileLevelInfo::input> &me,
320                        const C2P<C2StreamPictureSizeInfo::output> &size) {
321         (void)mayBlock;
322         (void)size;
323         (void)me; // TODO: validate
324         return C2R::Ok();
325     }
326 
327     static C2R
DefaultColorAspectsSetter(bool mayBlock,C2P<C2StreamColorAspectsTuning::output> & me)328     DefaultColorAspectsSetter(bool mayBlock,
329                               C2P<C2StreamColorAspectsTuning::output> &me) {
330         (void)mayBlock;
331         if (me.v.range > C2Color::RANGE_OTHER) {
332             me.set().range = C2Color::RANGE_OTHER;
333         }
334         if (me.v.primaries > C2Color::PRIMARIES_OTHER) {
335             me.set().primaries = C2Color::PRIMARIES_OTHER;
336         }
337         if (me.v.transfer > C2Color::TRANSFER_OTHER) {
338             me.set().transfer = C2Color::TRANSFER_OTHER;
339         }
340         if (me.v.matrix > C2Color::MATRIX_OTHER) {
341             me.set().matrix = C2Color::MATRIX_OTHER;
342         }
343         DDD("default primaries %d default range %d", me.set().primaries,
344             me.set().range);
345         return C2R::Ok();
346     }
347 
348     static C2R
CodedColorAspectsSetter(bool mayBlock,C2P<C2StreamColorAspectsInfo::input> & me)349     CodedColorAspectsSetter(bool mayBlock,
350                             C2P<C2StreamColorAspectsInfo::input> &me) {
351         (void)mayBlock;
352         if (me.v.range > C2Color::RANGE_OTHER) {
353             me.set().range = C2Color::RANGE_OTHER;
354         }
355         if (me.v.primaries > C2Color::PRIMARIES_OTHER) {
356             me.set().primaries = C2Color::PRIMARIES_OTHER;
357         }
358         if (me.v.transfer > C2Color::TRANSFER_OTHER) {
359             me.set().transfer = C2Color::TRANSFER_OTHER;
360         }
361         if (me.v.matrix > C2Color::MATRIX_OTHER) {
362             me.set().matrix = C2Color::MATRIX_OTHER;
363         }
364         DDD("coded primaries %d coded range %d", me.set().primaries,
365             me.set().range);
366         return C2R::Ok();
367     }
368 
369     static C2R
ColorAspectsSetter(bool mayBlock,C2P<C2StreamColorAspectsInfo::output> & me,const C2P<C2StreamColorAspectsTuning::output> & def,const C2P<C2StreamColorAspectsInfo::input> & coded)370     ColorAspectsSetter(bool mayBlock, C2P<C2StreamColorAspectsInfo::output> &me,
371                        const C2P<C2StreamColorAspectsTuning::output> &def,
372                        const C2P<C2StreamColorAspectsInfo::input> &coded) {
373         (void)mayBlock;
374         // take default values for all unspecified fields, and coded values for
375         // specified ones
376         DDD("before change primaries %d range %d", me.v.primaries, me.v.range);
377         me.set().range =
378             coded.v.range == RANGE_UNSPECIFIED ? def.v.range : coded.v.range;
379         me.set().primaries = coded.v.primaries == PRIMARIES_UNSPECIFIED
380                                  ? def.v.primaries
381                                  : coded.v.primaries;
382         me.set().transfer = coded.v.transfer == TRANSFER_UNSPECIFIED
383                                 ? def.v.transfer
384                                 : coded.v.transfer;
385         me.set().matrix = coded.v.matrix == MATRIX_UNSPECIFIED ? def.v.matrix
386                                                                : coded.v.matrix;
387 
388         DDD("after change primaries %d range %d", me.v.primaries, me.v.range);
389         return C2R::Ok();
390     }
391 
getColorAspects_l()392     std::shared_ptr<C2StreamColorAspectsInfo::output> getColorAspects_l() {
393         return mColorAspects;
394     }
395 
width() const396     int width() const { return mSize->width; }
397 
height() const398     int height() const { return mSize->height; }
399 
primaries() const400     int primaries() const { return mColorAspects->primaries; }
401 
range() const402     int range() const { return mColorAspects->range; }
403 
transfer() const404     int transfer() const { return mColorAspects->transfer; }
405 
406    private:
407     std::shared_ptr<C2StreamProfileLevelInfo::input> mProfileLevel;
408     std::shared_ptr<C2StreamPictureSizeInfo::output> mSize;
409     std::shared_ptr<C2StreamMaxPictureSizeTuning::output> mMaxSize;
410     std::shared_ptr<C2StreamMaxBufferSizeInfo::input> mMaxInputSize;
411     std::shared_ptr<C2StreamColorInfo::output> mColorInfo;
412     std::shared_ptr<C2StreamColorAspectsInfo::input> mCodedColorAspects;
413     std::shared_ptr<C2StreamColorAspectsTuning::output> mDefaultColorAspects;
414     std::shared_ptr<C2StreamColorAspectsInfo::output> mColorAspects;
415     std::shared_ptr<C2StreamPixelFormatInfo::output> mPixelFormat;
416 };
417 
ivd_aligned_malloc(void * ctxt,uint32_t alignment,uint32_t size)418 static void *ivd_aligned_malloc(void *ctxt, uint32_t alignment, uint32_t size) {
419     (void)ctxt;
420     return memalign(alignment, size);
421 }
422 
ivd_aligned_free(void * ctxt,void * mem)423 static void ivd_aligned_free(void *ctxt, void *mem) {
424     (void)ctxt;
425     free(mem);
426 }
427 
C2GoldfishAvcDec(const char * name,c2_node_id_t id,const std::shared_ptr<IntfImpl> & intfImpl)428 C2GoldfishAvcDec::C2GoldfishAvcDec(const char *name, c2_node_id_t id,
429                                    const std::shared_ptr<IntfImpl> &intfImpl)
430     : SimpleC2Component(
431           std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)),
432       mIntf(intfImpl), mOutBufferFlush(nullptr), mWidth(1920), mHeight(1080),
433       mHeaderDecoded(false), mOutIndex(0u) {
434     mWidth = mIntf->width();
435     mHeight = mIntf->height();
436     DDD("creating avc decoder now w %d h %d", mWidth, mHeight);
437 }
438 
~C2GoldfishAvcDec()439 C2GoldfishAvcDec::~C2GoldfishAvcDec() { onRelease(); }
440 
onInit()441 c2_status_t C2GoldfishAvcDec::onInit() {
442     ALOGD("calling onInit");
443     mId = allocateDecoderId();
444     if (mId <= 0) return C2_NO_MEMORY;
445     status_t err = initDecoder();
446     return err == OK ? C2_OK : C2_CORRUPTED;
447 }
448 
onStop()449 c2_status_t C2GoldfishAvcDec::onStop() {
450     if (OK != resetDecoder())
451         return C2_CORRUPTED;
452     resetPlugin();
453     return C2_OK;
454 }
455 
onReset()456 void C2GoldfishAvcDec::onReset() { (void)onStop(); }
457 
onRelease()458 void C2GoldfishAvcDec::onRelease() {
459     DDD("calling onRelease");
460     if (mId > 0) {
461       deAllocateDecoderId();
462       mId = -1;
463     }
464     deleteContext();
465     if (mOutBlock) {
466         mOutBlock.reset();
467     }
468 }
469 
decodeHeaderAfterFlush()470 void C2GoldfishAvcDec::decodeHeaderAfterFlush() {
471     if (mContext && !mCsd0.empty() && !mCsd1.empty()) {
472         mContext->decodeFrame(&(mCsd0[0]), mCsd0.size(), 0);
473         mContext->decodeFrame(&(mCsd1[0]), mCsd1.size(), 0);
474         DDD("resending csd0 and csd1");
475     }
476 }
477 
onFlush_sm()478 c2_status_t C2GoldfishAvcDec::onFlush_sm() {
479     if (OK != setFlushMode())
480         return C2_CORRUPTED;
481 
482     if (!mContext) {
483         // just ignore if context is not even created
484         return C2_OK;
485     }
486 
487     uint32_t bufferSize = mStride * mHeight * 3 / 2;
488     mOutBufferFlush = (uint8_t *)ivd_aligned_malloc(nullptr, 128, bufferSize);
489     if (!mOutBufferFlush) {
490         ALOGE("could not allocate tmp output buffer (for flush) of size %u ",
491               bufferSize);
492         return C2_NO_MEMORY;
493     }
494 
495     while (true) {
496         mPts = 0;
497         constexpr bool hasPicture = false;
498         setDecodeArgs(nullptr, nullptr, 0, 0, 0, hasPicture);
499         mImg = mContext->getImage();
500         if (mImg.data == nullptr) {
501             resetPlugin();
502             break;
503         }
504     }
505 
506     if (mOutBufferFlush) {
507         ivd_aligned_free(nullptr, mOutBufferFlush);
508         mOutBufferFlush = nullptr;
509     }
510 
511     deleteContext();
512     return C2_OK;
513 }
514 
sendMetadata()515 void C2GoldfishAvcDec::sendMetadata() {
516     // compare and send if changed
517     MetaDataColorAspects currentMetaData = {1, 0, 0, 0};
518     currentMetaData.primaries = mIntf->primaries();
519     currentMetaData.range = mIntf->range();
520     currentMetaData.transfer = mIntf->transfer();
521 
522     DDD("metadata primaries %d range %d transfer %d",
523             (int)(currentMetaData.primaries),
524             (int)(currentMetaData.range),
525             (int)(currentMetaData.transfer)
526        );
527 
528     if (mSentMetadata.primaries == currentMetaData.primaries &&
529         mSentMetadata.range == currentMetaData.range &&
530         mSentMetadata.transfer == currentMetaData.transfer) {
531         DDD("metadata is the same, no need to update");
532         return;
533     }
534     std::swap(mSentMetadata, currentMetaData);
535 
536     mContext->sendMetadata(&(mSentMetadata));
537 }
538 
createDecoder()539 status_t C2GoldfishAvcDec::createDecoder() {
540 
541     DDD("creating avc context now w %d h %d", mWidth, mHeight);
542     if (mEnableAndroidNativeBuffers) {
543         mContext.reset(new MediaH264Decoder(RenderMode::RENDER_BY_HOST_GPU));
544     } else {
545         mContext.reset(new MediaH264Decoder(RenderMode::RENDER_BY_GUEST_CPU));
546     }
547     mContext->initH264Context(mWidth, mHeight, mWidth, mHeight,
548                               MediaH264Decoder::PixelFormat::YUV420P);
549     return OK;
550 }
551 
setParams(size_t stride)552 status_t C2GoldfishAvcDec::setParams(size_t stride) {
553     (void)stride;
554     return OK;
555 }
556 
initDecoder()557 status_t C2GoldfishAvcDec::initDecoder() {
558     mStride = ALIGN2(mWidth);
559     mSignalledError = false;
560     resetPlugin();
561 
562     return OK;
563 }
564 
setDecodeArgs(C2ReadView * inBuffer,C2GraphicView * outBuffer,size_t inOffset,size_t inSize,uint32_t tsMarker,bool hasPicture)565 bool C2GoldfishAvcDec::setDecodeArgs(C2ReadView *inBuffer,
566                                      C2GraphicView *outBuffer, size_t inOffset,
567                                      size_t inSize, uint32_t tsMarker, bool hasPicture) {
568     uint32_t displayStride = mStride;
569     (void)inBuffer;
570     (void)inOffset;
571     (void)inSize;
572     (void)tsMarker;
573     if (outBuffer) {
574         C2PlanarLayout layout;
575         layout = outBuffer->layout();
576         displayStride = layout.planes[C2PlanarLayout::PLANE_Y].rowInc;
577     }
578 
579     if (inBuffer) {
580         //= tsMarker;
581         mInPBuffer = const_cast<uint8_t *>(inBuffer->data() + inOffset);
582         mInPBufferSize = inSize;
583         mInTsMarker = tsMarker;
584         if (hasPicture) {
585             insertPts(tsMarker, mPts);
586         }
587     }
588 
589     // uint32_t displayHeight = mHeight;
590     // size_t lumaSize = displayStride * displayHeight;
591     // size_t chromaSize = lumaSize >> 2;
592 
593     if (mStride != displayStride) {
594         mStride = displayStride;
595         if (OK != setParams(mStride))
596             return false;
597     }
598 
599     return true;
600 }
601 
setFlushMode()602 status_t C2GoldfishAvcDec::setFlushMode() {
603     if (mContext) {
604         mContext->flush();
605     }
606     mHeaderDecoded = false;
607     return OK;
608 }
609 
resetDecoder()610 status_t C2GoldfishAvcDec::resetDecoder() {
611     mStride = 0;
612     mSignalledError = false;
613     mHeaderDecoded = false;
614     deleteContext();
615 
616     return OK;
617 }
618 
resetPlugin()619 void C2GoldfishAvcDec::resetPlugin() {
620     mSignalledOutputEos = false;
621     gettimeofday(&mTimeStart, nullptr);
622     gettimeofday(&mTimeEnd, nullptr);
623     if (mOutBlock) {
624         mOutBlock.reset();
625     }
626 }
627 
deleteContext()628 void C2GoldfishAvcDec::deleteContext() {
629     if (mContext) {
630         mContext->destroyH264Context();
631         mContext.reset(nullptr);
632         mPts2Index.clear();
633         mOldPts2Index.clear();
634         mIndex2Pts.clear();
635     }
636 }
637 
fillEmptyWork(const std::unique_ptr<C2Work> & work)638 static void fillEmptyWork(const std::unique_ptr<C2Work> &work) {
639     uint32_t flags = 0;
640     if (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) {
641         flags |= C2FrameData::FLAG_END_OF_STREAM;
642         DDD("signalling eos");
643     }
644     DDD("fill empty work");
645     work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
646     work->worklets.front()->output.buffers.clear();
647     work->worklets.front()->output.ordinal = work->input.ordinal;
648     work->workletsProcessed = 1u;
649 }
650 
finishWork(uint64_t index,const std::unique_ptr<C2Work> & work)651 void C2GoldfishAvcDec::finishWork(uint64_t index,
652                                   const std::unique_ptr<C2Work> &work) {
653     std::shared_ptr<C2Buffer> buffer =
654         createGraphicBuffer(std::move(mOutBlock), C2Rect(mWidth, mHeight));
655     mOutBlock = nullptr;
656     {
657         IntfImpl::Lock lock = mIntf->lock();
658         buffer->setInfo(mIntf->getColorAspects_l());
659     }
660 
661     class FillWork {
662       public:
663         FillWork(uint32_t flags, C2WorkOrdinalStruct ordinal,
664                  const std::shared_ptr<C2Buffer> &buffer)
665             : mFlags(flags), mOrdinal(ordinal), mBuffer(buffer) {}
666         ~FillWork() = default;
667 
668         void operator()(const std::unique_ptr<C2Work> &work) {
669             work->worklets.front()->output.flags = (C2FrameData::flags_t)mFlags;
670             work->worklets.front()->output.buffers.clear();
671             work->worklets.front()->output.ordinal = mOrdinal;
672             work->workletsProcessed = 1u;
673             work->result = C2_OK;
674             if (mBuffer) {
675                 work->worklets.front()->output.buffers.push_back(mBuffer);
676             }
677             DDD("timestamp = %lld, index = %lld, w/%s buffer",
678                 mOrdinal.timestamp.peekll(), mOrdinal.frameIndex.peekll(),
679                 mBuffer ? "" : "o");
680         }
681 
682       private:
683         const uint32_t mFlags;
684         const C2WorkOrdinalStruct mOrdinal;
685         const std::shared_ptr<C2Buffer> mBuffer;
686     };
687 
688     auto fillWork = [buffer](const std::unique_ptr<C2Work> &work) {
689         work->worklets.front()->output.flags = (C2FrameData::flags_t)0;
690         work->worklets.front()->output.buffers.clear();
691         work->worklets.front()->output.buffers.push_back(buffer);
692         work->worklets.front()->output.ordinal = work->input.ordinal;
693         work->workletsProcessed = 1u;
694     };
695     if (work && c2_cntr64_t(index) == work->input.ordinal.frameIndex) {
696         bool eos = ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0);
697         // TODO: Check if cloneAndSend can be avoided by tracking number of
698         // frames remaining
699         if (eos) {
700             if (buffer) {
701                 mOutIndex = index;
702                 C2WorkOrdinalStruct outOrdinal = work->input.ordinal;
703                 DDD("%s %d: cloneAndSend ", __func__, __LINE__);
704                 cloneAndSend(
705                     mOutIndex, work,
706                     FillWork(C2FrameData::FLAG_INCOMPLETE, outOrdinal, buffer));
707                 buffer.reset();
708             }
709         } else {
710             DDD("%s %d: fill", __func__, __LINE__);
711             fillWork(work);
712         }
713     } else {
714         DDD("%s %d: finish", __func__, __LINE__);
715         finish(index, fillWork);
716     }
717 }
718 
719 c2_status_t
ensureDecoderState(const std::shared_ptr<C2BlockPool> & pool)720 C2GoldfishAvcDec::ensureDecoderState(const std::shared_ptr<C2BlockPool> &pool) {
721     if (mOutBlock && (mOutBlock->width() != ALIGN2(mWidth) ||
722                       mOutBlock->height() != mHeight)) {
723         mOutBlock.reset();
724     }
725     if (!mOutBlock) {
726         const uint32_t format = HAL_PIXEL_FORMAT_YV12;
727         const C2MemoryUsage usage = {(uint64_t)(BufferUsage::VIDEO_DECODER),
728                                      C2MemoryUsage::CPU_WRITE | C2MemoryUsage::CPU_READ};
729         c2_status_t err = pool->fetchGraphicBlock(ALIGN2(mWidth), mHeight,
730                                                   format, usage, &mOutBlock);
731         if (err != C2_OK) {
732             ALOGE("fetchGraphicBlock for Output failed with status %d", err);
733             return err;
734         }
735         if (mEnableAndroidNativeBuffers) {
736             auto c2Handle = mOutBlock->handle();
737             native_handle_t *grallocHandle =
738                 UnwrapNativeCodec2GrallocHandle(c2Handle);
739             mHostColorBufferId = getColorBufferHandle(grallocHandle);
740             DDD("found handle %d", mHostColorBufferId);
741         }
742         DDD("provided (%dx%d) required (%dx%d)", mOutBlock->width(),
743             mOutBlock->height(), ALIGN2(mWidth), mHeight);
744     }
745 
746     return C2_OK;
747 }
748 
checkMode(const std::shared_ptr<C2BlockPool> & pool)749 void C2GoldfishAvcDec::checkMode(const std::shared_ptr<C2BlockPool> &pool) {
750     mWidth = mIntf->width();
751     mHeight = mIntf->height();
752     //const bool isGraphic = (pool->getLocalId() == C2PlatformAllocatorStore::GRALLOC);
753     const bool isGraphic = (pool->getAllocatorId() & C2Allocator::GRAPHIC);
754     DDD("buffer pool allocator id %x",  (int)(pool->getAllocatorId()));
755     if (isGraphic) {
756         uint64_t client_usage = getClientUsage(pool);
757         DDD("client has usage as 0x%llx", client_usage);
758         if (client_usage & BufferUsage::CPU_READ_MASK) {
759             DDD("decoding to guest byte buffer as client has read usage");
760             mEnableAndroidNativeBuffers = false;
761         } else {
762             DDD("decoding to host color buffer");
763             mEnableAndroidNativeBuffers = true;
764         }
765     } else {
766         DDD("decoding to guest byte buffer");
767         mEnableAndroidNativeBuffers = false;
768     }
769 }
770 
getVuiParams(h264_image_t & img)771 void C2GoldfishAvcDec::getVuiParams(h264_image_t &img) {
772     VuiColorAspects vuiColorAspects;
773     vuiColorAspects.primaries = img.color_primaries;
774     vuiColorAspects.transfer = img.color_trc;
775     vuiColorAspects.coeffs = img.colorspace;
776     vuiColorAspects.fullRange = img.color_range == 2 ? true : false;
777 
778     // convert vui aspects to C2 values if changed
779     if (!(vuiColorAspects == mBitstreamColorAspects)) {
780         mBitstreamColorAspects = vuiColorAspects;
781         ColorAspects sfAspects;
782         C2StreamColorAspectsInfo::input codedAspects = {0u};
783         ColorUtils::convertIsoColorAspectsToCodecAspects(
784             vuiColorAspects.primaries, vuiColorAspects.transfer,
785             vuiColorAspects.coeffs, vuiColorAspects.fullRange, sfAspects);
786         if (!C2Mapper::map(sfAspects.mPrimaries, &codedAspects.primaries)) {
787             codedAspects.primaries = C2Color::PRIMARIES_UNSPECIFIED;
788         }
789         if (!C2Mapper::map(sfAspects.mRange, &codedAspects.range)) {
790             codedAspects.range = C2Color::RANGE_UNSPECIFIED;
791         }
792         if (!C2Mapper::map(sfAspects.mMatrixCoeffs, &codedAspects.matrix)) {
793             codedAspects.matrix = C2Color::MATRIX_UNSPECIFIED;
794         }
795         if (!C2Mapper::map(sfAspects.mTransfer, &codedAspects.transfer)) {
796             codedAspects.transfer = C2Color::TRANSFER_UNSPECIFIED;
797         }
798         std::vector<std::unique_ptr<C2SettingResult>> failures;
799         (void)mIntf->config({&codedAspects}, C2_MAY_BLOCK, &failures);
800     }
801 }
802 
copyImageData(h264_image_t & img)803 void C2GoldfishAvcDec::copyImageData(h264_image_t &img) {
804     getVuiParams(img);
805     if (mEnableAndroidNativeBuffers)
806         return;
807 
808     auto writeView = mOutBlock->map().get();
809     if (writeView.error()) {
810         ALOGE("graphic view map failed %d", writeView.error());
811         return;
812     }
813     size_t dstYStride = writeView.layout().planes[C2PlanarLayout::PLANE_Y].rowInc;
814     size_t dstUVStride = writeView.layout().planes[C2PlanarLayout::PLANE_U].rowInc;
815 
816     uint8_t *pYBuffer = const_cast<uint8_t *>(writeView.data()[C2PlanarLayout::PLANE_Y]);
817     uint8_t *pUBuffer = const_cast<uint8_t *>(writeView.data()[C2PlanarLayout::PLANE_U]);
818     uint8_t *pVBuffer = const_cast<uint8_t *>(writeView.data()[C2PlanarLayout::PLANE_V]);
819 
820     for (int i = 0; i < mHeight; ++i) {
821         memcpy(pYBuffer + i * dstYStride, img.data + i * mWidth, mWidth);
822     }
823     for (int i = 0; i < mHeight / 2; ++i) {
824         memcpy(pUBuffer + i * dstUVStride,
825                img.data + mWidth * mHeight + i * mWidth / 2, mWidth / 2);
826     }
827     for (int i = 0; i < mHeight / 2; ++i) {
828         memcpy(pVBuffer + i * dstUVStride,
829                img.data + mWidth * mHeight * 5 / 4 + i * mWidth / 2,
830                mWidth / 2);
831     }
832 }
833 
getWorkIndex(uint64_t pts)834 uint64_t C2GoldfishAvcDec::getWorkIndex(uint64_t pts) {
835     if (!mOldPts2Index.empty()) {
836         auto iter = mOldPts2Index.find(pts);
837         if (iter != mOldPts2Index.end()) {
838             auto index = iter->second;
839             DDD("found index %d for pts %" PRIu64, (int)index, pts);
840             return index;
841         }
842     }
843     auto iter = mPts2Index.find(pts);
844     if (iter != mPts2Index.end()) {
845         auto index = iter->second;
846         DDD("found index %d for pts %" PRIu64, (int)index, pts);
847         return index;
848     }
849     DDD("not found index for pts %" PRIu64, pts);
850     return 0;
851 }
852 
insertPts(uint32_t work_index,uint64_t pts)853 void C2GoldfishAvcDec::insertPts(uint32_t work_index, uint64_t pts) {
854     auto iter = mPts2Index.find(pts);
855     if (iter != mPts2Index.end()) {
856         // we have a collision here:
857         // apparently, older session is not done yet,
858         // lets save them
859         DDD("inserted to old pts %" PRIu64 " with index %d", pts, (int)iter->second);
860         mOldPts2Index[iter->first] = iter->second;
861     }
862     DDD("inserted pts %" PRIu64 " with index %d", pts, (int)work_index);
863     mIndex2Pts[work_index] = pts;
864     mPts2Index[pts] = work_index;
865 }
866 
removePts(uint64_t pts)867 void C2GoldfishAvcDec::removePts(uint64_t pts) {
868     bool found = false;
869     uint64_t index = 0;
870     // note: check old pts first to see
871     // if we have some left over, check them
872     if (!mOldPts2Index.empty()) {
873         auto iter = mOldPts2Index.find(pts);
874         if (iter != mOldPts2Index.end()) {
875             index = iter->second;
876             mOldPts2Index.erase(iter);
877             found = true;
878         }
879     } else {
880         auto iter = mPts2Index.find(pts);
881         if (iter != mPts2Index.end()) {
882             index = iter->second;
883             mPts2Index.erase(iter);
884             found = true;
885         }
886     }
887 
888     if (!found) return;
889 
890     auto iter2 = mIndex2Pts.find(index);
891     if (iter2 == mIndex2Pts.end()) return;
892     mIndex2Pts.erase(iter2);
893 }
894 
895 // TODO: can overall error checking be improved?
896 // TODO: allow configuration of color format and usage for graphic buffers
897 // instead
898 //       of hard coding them to HAL_PIXEL_FORMAT_YV12
899 // TODO: pass coloraspects information to surface
900 // TODO: test support for dynamic change in resolution
901 // TODO: verify if the decoder sent back all frames
process(const std::unique_ptr<C2Work> & work,const std::shared_ptr<C2BlockPool> & pool)902 void C2GoldfishAvcDec::process(const std::unique_ptr<C2Work> &work,
903                                const std::shared_ptr<C2BlockPool> &pool) {
904     // Initialize output work
905     work->result = C2_OK;
906     work->workletsProcessed = 0u;
907     work->worklets.front()->output.flags = work->input.flags;
908     if (mSignalledError || mSignalledOutputEos) {
909         work->result = C2_BAD_VALUE;
910         return;
911     }
912 
913     DDD("process work");
914     if (!mContext) {
915         DDD("creating decoder context to host in process work");
916         checkMode(pool);
917         createDecoder();
918         decodeHeaderAfterFlush();
919     }
920 
921     size_t inOffset = 0u;
922     size_t inSize = 0u;
923     uint32_t workIndex = work->input.ordinal.frameIndex.peeku() & 0xFFFFFFFF;
924     mPts = work->input.ordinal.timestamp.peeku();
925     C2ReadView rView = mDummyReadView;
926     if (!work->input.buffers.empty()) {
927         rView =
928             work->input.buffers[0]->data().linearBlocks().front().map().get();
929         inSize = rView.capacity();
930         if (inSize && rView.error()) {
931             ALOGE("read view map failed %d", rView.error());
932             work->result = rView.error();
933             return;
934         }
935     }
936     bool eos = ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0);
937     bool hasPicture = (inSize > 0);
938 
939     DDD("in buffer attr. size %zu timestamp %d frameindex %d, flags %x", inSize,
940         (int)work->input.ordinal.timestamp.peeku(),
941         (int)work->input.ordinal.frameIndex.peeku(), work->input.flags);
942     size_t inPos = 0;
943     while (inPos < inSize && inSize - inPos >= kMinInputBytes) {
944         if (C2_OK != ensureDecoderState(pool)) {
945             mSignalledError = true;
946             work->workletsProcessed = 1u;
947             work->result = C2_CORRUPTED;
948             return;
949         }
950 
951         {
952             // C2GraphicView wView;// = mOutBlock->map().get();
953             // if (wView.error()) {
954             //    ALOGE("graphic view map failed %d", wView.error());
955             //    work->result = wView.error();
956             //    return;
957             //}
958             if (work->input.flags & C2FrameData::FLAG_CODEC_CONFIG) {
959                 hasPicture = false;
960             }
961             if (!setDecodeArgs(&rView, nullptr, inOffset + inPos,
962                                inSize - inPos, workIndex, hasPicture)) {
963                 mSignalledError = true;
964                 work->workletsProcessed = 1u;
965                 work->result = C2_CORRUPTED;
966                 return;
967             }
968 
969             DDD("flag is %x", work->input.flags);
970             if (work->input.flags & C2FrameData::FLAG_CODEC_CONFIG) {
971                 if (mCsd0.empty()) {
972                     mCsd0.assign(mInPBuffer, mInPBuffer + mInPBufferSize);
973                     DDD("assign to csd0 with %d bytpes", mInPBufferSize);
974                 } else if (mCsd1.empty()) {
975                     mCsd1.assign(mInPBuffer, mInPBuffer + mInPBufferSize);
976                     DDD("assign to csd1 with %d bytpes", mInPBufferSize);
977                 }
978             }
979 
980             bool whChanged = false;
981             if (GoldfishH264Helper::isSpsFrame(mInPBuffer, mInPBufferSize)) {
982                 mH264Helper.reset(new GoldfishH264Helper(mWidth, mHeight));
983                 whChanged = mH264Helper->decodeHeader(mInPBuffer, mInPBufferSize);
984                 if (whChanged) {
985                         DDD("w changed from old %d to new %d\n", mWidth, mH264Helper->getWidth());
986                         DDD("h changed from old %d to new %d\n", mHeight, mH264Helper->getHeight());
987                         if (1) {
988                             drainInternal(DRAIN_COMPONENT_NO_EOS, pool, work);
989                             resetDecoder();
990                             resetPlugin();
991                             work->workletsProcessed = 0u;
992                         }
993                         {
994                             mWidth = mH264Helper->getWidth();
995                             mHeight = mH264Helper->getHeight();
996                             C2StreamPictureSizeInfo::output size(0u, mWidth, mHeight);
997                             std::vector<std::unique_ptr<C2SettingResult>> failures;
998                             c2_status_t err = mIntf->config({&size}, C2_MAY_BLOCK, &failures);
999                             if (err == OK) {
1000                                 work->worklets.front()->output.configUpdate.push_back(
1001                                         C2Param::Copy(size));
1002                                 ensureDecoderState(pool);
1003                             } else {
1004                                 ALOGE("Cannot set width and height");
1005                                 mSignalledError = true;
1006                                 work->workletsProcessed = 1u;
1007                                 work->result = C2_CORRUPTED;
1008                                 return;
1009                             }
1010                         }
1011                         if (!mContext) {
1012                             DDD("creating decoder context to host in process work");
1013                             checkMode(pool);
1014                             createDecoder();
1015                         }
1016                         continue;
1017                 } // end of whChanged
1018             } // end of isSpsFrame
1019 
1020             sendMetadata();
1021 
1022             uint32_t delay;
1023             GETTIME(&mTimeStart, nullptr);
1024             TIME_DIFF(mTimeEnd, mTimeStart, delay);
1025             (void)delay;
1026             //(void) ivdec_api_function(mDecHandle, &s_decode_ip, &s_decode_op);
1027             DDD("decoding");
1028             h264_result_t h264Res =
1029                 mContext->decodeFrame(mInPBuffer, mInPBufferSize, mPts);
1030             mConsumedBytes = h264Res.bytesProcessed;
1031             DDD("decoding consumed %d", (int)mConsumedBytes);
1032 
1033             if (mHostColorBufferId > 0) {
1034                 mImg = mContext->renderOnHostAndReturnImageMetadata(
1035                     mHostColorBufferId);
1036             } else {
1037                 mImg = mContext->getImage();
1038             }
1039             uint32_t decodeTime;
1040             GETTIME(&mTimeEnd, nullptr);
1041             TIME_DIFF(mTimeStart, mTimeEnd, decodeTime);
1042             (void)decodeTime;
1043         }
1044 
1045         if (mImg.data != nullptr) {
1046             DDD("got data %" PRIu64 " with pts %" PRIu64,  getWorkIndex(mImg.pts), mImg.pts);
1047             mHeaderDecoded = true;
1048             copyImageData(mImg);
1049             finishWork(getWorkIndex(mImg.pts), work);
1050             removePts(mImg.pts);
1051         } else {
1052             work->workletsProcessed = 0u;
1053         }
1054 
1055         inPos += mConsumedBytes;
1056     }
1057     if (eos) {
1058         DDD("drain because of eos");
1059         drainInternal(DRAIN_COMPONENT_WITH_EOS, pool, work);
1060         mSignalledOutputEos = true;
1061     } else if (!hasPicture) {
1062         DDD("no picture, fill empty work");
1063         fillEmptyWork(work);
1064     }
1065 
1066     work->input.buffers.clear();
1067 }
1068 
1069 c2_status_t
drainInternal(uint32_t drainMode,const std::shared_ptr<C2BlockPool> & pool,const std::unique_ptr<C2Work> & work)1070 C2GoldfishAvcDec::drainInternal(uint32_t drainMode,
1071                                 const std::shared_ptr<C2BlockPool> &pool,
1072                                 const std::unique_ptr<C2Work> &work) {
1073     if (drainMode == NO_DRAIN) {
1074         ALOGW("drain with NO_DRAIN: no-op");
1075         return C2_OK;
1076     }
1077     if (drainMode == DRAIN_CHAIN) {
1078         ALOGW("DRAIN_CHAIN not supported");
1079         return C2_OMITTED;
1080     }
1081 
1082     if (OK != setFlushMode())
1083         return C2_CORRUPTED;
1084     while (true) {
1085         if (C2_OK != ensureDecoderState(pool)) {
1086             mSignalledError = true;
1087             work->workletsProcessed = 1u;
1088             work->result = C2_CORRUPTED;
1089             return C2_CORRUPTED;
1090         }
1091         /*
1092         C2GraphicView wView = mOutBlock->map().get();
1093         if (wView.error()) {
1094             ALOGE("graphic view map failed %d", wView.error());
1095             return C2_CORRUPTED;
1096         }
1097         if (!setDecodeArgs(nullptr, &wView, 0, 0, 0)) {
1098             mSignalledError = true;
1099             work->workletsProcessed = 1u;
1100             return C2_CORRUPTED;
1101         }
1102         */
1103 
1104         if (mHostColorBufferId > 0) {
1105             mImg = mContext->renderOnHostAndReturnImageMetadata(
1106                 mHostColorBufferId);
1107         } else {
1108             mImg = mContext->getImage();
1109         }
1110 
1111         // TODO: maybe keep rendering to screen
1112         //        mImg = mContext->getImage();
1113         if (mImg.data != nullptr) {
1114             DDD("got data in drain mode %" PRIu64 " with pts %" PRIu64,  getWorkIndex(mImg.pts), mImg.pts);
1115             copyImageData(mImg);
1116             finishWork(getWorkIndex(mImg.pts), work);
1117             removePts(mImg.pts);
1118         } else {
1119             fillEmptyWork(work);
1120             break;
1121         }
1122     }
1123 
1124     return C2_OK;
1125 }
1126 
drain(uint32_t drainMode,const std::shared_ptr<C2BlockPool> & pool)1127 c2_status_t C2GoldfishAvcDec::drain(uint32_t drainMode,
1128                                     const std::shared_ptr<C2BlockPool> &pool) {
1129     DDD("drainInternal because of drain");
1130     return drainInternal(drainMode, pool, nullptr);
1131 }
1132 
1133 class C2GoldfishAvcDecFactory : public C2ComponentFactory {
1134   public:
C2GoldfishAvcDecFactory()1135     C2GoldfishAvcDecFactory()
1136         : mHelper(std::static_pointer_cast<C2ReflectorHelper>(
1137               GoldfishComponentStore::Create()->getParamReflector())) {}
1138 
1139     virtual c2_status_t
createComponent(c2_node_id_t id,std::shared_ptr<C2Component> * const component,std::function<void (C2Component *)> deleter)1140     createComponent(c2_node_id_t id,
1141                     std::shared_ptr<C2Component> *const component,
1142                     std::function<void(C2Component *)> deleter) override {
1143         *component = std::shared_ptr<C2Component>(
1144             new C2GoldfishAvcDec(
1145                 COMPONENT_NAME, id,
1146                 std::make_shared<C2GoldfishAvcDec::IntfImpl>(mHelper)),
1147             deleter);
1148         return C2_OK;
1149     }
1150 
createInterface(c2_node_id_t id,std::shared_ptr<C2ComponentInterface> * const interface,std::function<void (C2ComponentInterface *)> deleter)1151     virtual c2_status_t createInterface(
1152         c2_node_id_t id, std::shared_ptr<C2ComponentInterface> *const interface,
1153         std::function<void(C2ComponentInterface *)> deleter) override {
1154         *interface = std::shared_ptr<C2ComponentInterface>(
1155             new SimpleInterface<C2GoldfishAvcDec::IntfImpl>(
1156                 COMPONENT_NAME, id,
1157                 std::make_shared<C2GoldfishAvcDec::IntfImpl>(mHelper)),
1158             deleter);
1159         return C2_OK;
1160     }
1161 
1162     virtual ~C2GoldfishAvcDecFactory() override = default;
1163 
1164   private:
1165     std::shared_ptr<C2ReflectorHelper> mHelper;
1166 };
1167 
1168 } // namespace android
1169 
CreateCodec2Factory()1170 extern "C" ::C2ComponentFactory *CreateCodec2Factory() {
1171     DDD("in %s", __func__);
1172     return new ::android::C2GoldfishAvcDecFactory();
1173 }
1174 
DestroyCodec2Factory(::C2ComponentFactory * factory)1175 extern "C" void DestroyCodec2Factory(::C2ComponentFactory *factory) {
1176     DDD("in %s", __func__);
1177     delete factory;
1178 }
1179