Johny Lin | 7c4cb52 | 2017-06-26 16:10:24 +0800 | [diff] [blame] | 1 | // Copyright 2017 The Chromium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | //#define LOG_NDEBUG 0 |
| 6 | #define LOG_TAG "C2VDAComponent" |
| 7 | |
Hirokazu Honda | 4b97b37 | 2018-01-21 23:20:59 +0000 | [diff] [blame] | 8 | #ifdef V4L2_CODEC2_ARC |
| 9 | #include <C2VDAAdaptorProxy.h> |
| 10 | #else |
Johny Lin | c6d0b6f | 2017-12-19 15:47:06 +0800 | [diff] [blame] | 11 | #include <C2VDAAdaptor.h> |
Hirokazu Honda | 4b97b37 | 2018-01-21 23:20:59 +0000 | [diff] [blame] | 12 | #endif |
| 13 | |
Lajos Molnar | d18cc34 | 2017-10-17 07:58:02 -0700 | [diff] [blame] | 14 | #define __C2_GENERATE_GLOBAL_VARS__ |
Pin-chih Lin | 906956a | 2018-05-22 14:12:59 +0800 | [diff] [blame] | 15 | #include <C2VDAAllocatorStore.h> |
Hirokazu Honda | ca17a06 | 2018-07-31 10:48:56 +0900 | [diff] [blame] | 16 | #include <C2VDAComponent.h> |
| 17 | #include <C2VDAPixelFormat.h> |
| 18 | #include <C2VDASupport.h> // to getParamReflector from vda store |
Pin-chih Lin | 906956a | 2018-05-22 14:12:59 +0800 | [diff] [blame] | 19 | #include <C2VdaBqBlockPool.h> |
Pin-chih Lin | 585324e | 2018-07-25 16:24:54 +0800 | [diff] [blame] | 20 | #include <C2VdaPooledBlockPool.h> |
Johny Lin | 8a2118e | 2018-02-08 16:29:25 +0800 | [diff] [blame] | 21 | |
Pin-chih Lin | 3aff30b | 2018-10-02 21:11:01 +0800 | [diff] [blame] | 22 | #include <h264_parser.h> |
| 23 | |
Pin-chih Lin | 906956a | 2018-05-22 14:12:59 +0800 | [diff] [blame] | 24 | #include <C2AllocatorGralloc.h> |
Johny Lin | 8a2118e | 2018-02-08 16:29:25 +0800 | [diff] [blame] | 25 | #include <C2ComponentFactory.h> |
Pin-chih Lin | 85e1ec6 | 2018-05-16 16:17:16 +0800 | [diff] [blame] | 26 | #include <C2PlatformSupport.h> |
Pin-chih Lin | 3aff30b | 2018-10-02 21:11:01 +0800 | [diff] [blame] | 27 | #include <Codec2Mapper.h> |
Hirokazu Honda | decfca1 | 2018-01-23 01:59:09 +0900 | [diff] [blame] | 28 | |
Johny Lin | c6d0b6f | 2017-12-19 15:47:06 +0800 | [diff] [blame] | 29 | #include <base/bind.h> |
| 30 | #include <base/bind_helpers.h> |
Johny Lin | 7c4cb52 | 2017-06-26 16:10:24 +0800 | [diff] [blame] | 31 | |
| 32 | #include <media/stagefright/MediaDefs.h> |
Pin-chih Lin | 3aff30b | 2018-10-02 21:11:01 +0800 | [diff] [blame] | 33 | #include <media/stagefright/foundation/ColorUtils.h> |
Johny Lin | 7c4cb52 | 2017-06-26 16:10:24 +0800 | [diff] [blame] | 34 | #include <utils/Log.h> |
| 35 | #include <utils/misc.h> |
| 36 | |
Johny Lin | c6d0b6f | 2017-12-19 15:47:06 +0800 | [diff] [blame] | 37 | #include <inttypes.h> |
Pin-chih Lin | 1ca0d0b | 2018-05-04 13:58:06 +0800 | [diff] [blame] | 38 | #include <string.h> |
Johny Lin | c6d0b6f | 2017-12-19 15:47:06 +0800 | [diff] [blame] | 39 | #include <algorithm> |
Hirokazu Honda | 3f3c8a4 | 2018-05-09 22:25:19 +0800 | [diff] [blame] | 40 | #include <string> |
Johny Lin | c6d0b6f | 2017-12-19 15:47:06 +0800 | [diff] [blame] | 41 | |
Johny Lin | a891f0e | 2017-12-19 10:25:27 +0800 | [diff] [blame] | 42 | #define UNUSED(expr) \ |
| 43 | do { \ |
| 44 | (void)(expr); \ |
| 45 | } while (0) |
Johny Lin | 7c4cb52 | 2017-06-26 16:10:24 +0800 | [diff] [blame] | 46 | |
| 47 | namespace android { |
| 48 | |
| 49 | namespace { |
| 50 | |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 51 | // Mask against 30 bits to avoid (undefined) wraparound on signed integer. |
Lajos Molnar | 2a2b901 | 2018-01-23 17:24:57 -0800 | [diff] [blame] | 52 | int32_t frameIndexToBitstreamId(c2_cntr64_t frameIndex) { |
| 53 | return static_cast<int32_t>(frameIndex.peeku() & 0x3FFFFFFF); |
Johny Lin | 7c4cb52 | 2017-06-26 16:10:24 +0800 | [diff] [blame] | 54 | } |
| 55 | |
Pin-chih Lin | 2fea071 | 2018-05-14 19:57:14 +0800 | [diff] [blame] | 56 | // Use basic graphic block pool/allocator as default. |
| 57 | const C2BlockPool::local_id_t kDefaultOutputBlockPool = C2BlockPool::BASIC_GRAPHIC; |
| 58 | |
Pin-chih Lin | 226ec46 | 2018-03-28 20:15:26 +0800 | [diff] [blame] | 59 | const C2String kH264DecoderName = "c2.vda.avc.decoder"; |
| 60 | const C2String kVP8DecoderName = "c2.vda.vp8.decoder"; |
| 61 | const C2String kVP9DecoderName = "c2.vda.vp9.decoder"; |
Hirokazu Honda | 3f3c8a4 | 2018-05-09 22:25:19 +0800 | [diff] [blame] | 62 | const C2String kH264SecureDecoderName = "c2.vda.avc.decoder.secure"; |
| 63 | const C2String kVP8SecureDecoderName = "c2.vda.vp8.decoder.secure"; |
| 64 | const C2String kVP9SecureDecoderName = "c2.vda.vp9.decoder.secure"; |
Johny Lin | 7c4cb52 | 2017-06-26 16:10:24 +0800 | [diff] [blame] | 65 | |
Pin-chih Lin | 906956a | 2018-05-22 14:12:59 +0800 | [diff] [blame] | 66 | const uint32_t kDpbOutputBufferExtraCount = 3; // Use the same number as ACodec. |
| 67 | const int kDequeueRetryDelayUs = 10000; // Wait time of dequeue buffer retry in microseconds. |
Pin-chih Lin | 81a44bb | 2018-08-17 17:54:00 +0800 | [diff] [blame] | 68 | const int32_t kAllocateBufferMaxRetries = 10; // Max retry time for fetchGraphicBlock timeout. |
Johny Lin | 9be5270 | 2017-11-15 20:52:31 +0800 | [diff] [blame] | 69 | } // namespace |
Johny Lin | 7c4cb52 | 2017-06-26 16:10:24 +0800 | [diff] [blame] | 70 | |
Pin-chih Lin | db84a6c | 2018-09-13 21:38:50 +0800 | [diff] [blame] | 71 | static c2_status_t adaptorResultToC2Status(VideoDecodeAcceleratorAdaptor::Result result) { |
| 72 | switch (result) { |
| 73 | case VideoDecodeAcceleratorAdaptor::Result::SUCCESS: |
| 74 | return C2_OK; |
| 75 | case VideoDecodeAcceleratorAdaptor::Result::ILLEGAL_STATE: |
| 76 | ALOGE("Got error: ILLEGAL_STATE"); |
| 77 | return C2_BAD_STATE; |
| 78 | case VideoDecodeAcceleratorAdaptor::Result::INVALID_ARGUMENT: |
| 79 | ALOGE("Got error: INVALID_ARGUMENT"); |
| 80 | return C2_BAD_VALUE; |
| 81 | case VideoDecodeAcceleratorAdaptor::Result::UNREADABLE_INPUT: |
| 82 | ALOGE("Got error: UNREADABLE_INPUT"); |
| 83 | return C2_BAD_VALUE; |
| 84 | case VideoDecodeAcceleratorAdaptor::Result::PLATFORM_FAILURE: |
| 85 | ALOGE("Got error: PLATFORM_FAILURE"); |
| 86 | return C2_CORRUPTED; |
| 87 | case VideoDecodeAcceleratorAdaptor::Result::INSUFFICIENT_RESOURCES: |
| 88 | ALOGE("Got error: INSUFFICIENT_RESOURCES"); |
| 89 | return C2_NO_MEMORY; |
| 90 | default: |
| 91 | ALOGE("Unrecognizable adaptor result (value = %d)...", result); |
| 92 | return C2_CORRUPTED; |
| 93 | } |
| 94 | } |
| 95 | |
Pin-chih Lin | 3aff30b | 2018-10-02 21:11:01 +0800 | [diff] [blame] | 96 | // static |
| 97 | C2R C2VDAComponent::IntfImpl::ProfileLevelSetter(bool mayBlock, |
| 98 | C2P<C2StreamProfileLevelInfo::input>& info) { |
| 99 | (void)mayBlock; |
| 100 | return info.F(info.v.profile) |
| 101 | .validatePossible(info.v.profile) |
| 102 | .plus(info.F(info.v.level).validatePossible(info.v.level)); |
| 103 | } |
| 104 | |
| 105 | // static |
| 106 | C2R C2VDAComponent::IntfImpl::SizeSetter(bool mayBlock, |
| 107 | C2P<C2StreamPictureSizeInfo::output>& videoSize) { |
| 108 | (void)mayBlock; |
| 109 | // TODO: maybe apply block limit? |
| 110 | return videoSize.F(videoSize.v.width) |
| 111 | .validatePossible(videoSize.v.width) |
| 112 | .plus(videoSize.F(videoSize.v.height).validatePossible(videoSize.v.height)); |
| 113 | } |
| 114 | |
| 115 | // static |
| 116 | template <typename T> |
| 117 | C2R C2VDAComponent::IntfImpl::DefaultColorAspectsSetter(bool mayBlock, C2P<T>& def) { |
| 118 | (void)mayBlock; |
| 119 | if (def.v.range > C2Color::RANGE_OTHER) { |
| 120 | def.set().range = C2Color::RANGE_OTHER; |
| 121 | } |
| 122 | if (def.v.primaries > C2Color::PRIMARIES_OTHER) { |
| 123 | def.set().primaries = C2Color::PRIMARIES_OTHER; |
| 124 | } |
| 125 | if (def.v.transfer > C2Color::TRANSFER_OTHER) { |
| 126 | def.set().transfer = C2Color::TRANSFER_OTHER; |
| 127 | } |
| 128 | if (def.v.matrix > C2Color::MATRIX_OTHER) { |
| 129 | def.set().matrix = C2Color::MATRIX_OTHER; |
| 130 | } |
| 131 | return C2R::Ok(); |
| 132 | } |
| 133 | |
| 134 | // static |
| 135 | C2R C2VDAComponent::IntfImpl::MergedColorAspectsSetter( |
| 136 | bool mayBlock, C2P<C2StreamColorAspectsInfo::output>& merged, |
| 137 | const C2P<C2StreamColorAspectsTuning::output>& def, |
| 138 | const C2P<C2StreamColorAspectsInfo::input>& coded) { |
| 139 | (void)mayBlock; |
| 140 | // Take coded values for all specified fields, and default values for unspecified ones. |
| 141 | merged.set().range = coded.v.range == RANGE_UNSPECIFIED ? def.v.range : coded.v.range; |
| 142 | merged.set().primaries = |
| 143 | coded.v.primaries == PRIMARIES_UNSPECIFIED ? def.v.primaries : coded.v.primaries; |
| 144 | merged.set().transfer = |
| 145 | coded.v.transfer == TRANSFER_UNSPECIFIED ? def.v.transfer : coded.v.transfer; |
| 146 | merged.set().matrix = coded.v.matrix == MATRIX_UNSPECIFIED ? def.v.matrix : coded.v.matrix; |
| 147 | return C2R::Ok(); |
| 148 | } |
| 149 | |
Pin-chih Lin | 1ca0d0b | 2018-05-04 13:58:06 +0800 | [diff] [blame] | 150 | C2VDAComponent::IntfImpl::IntfImpl(C2String name, const std::shared_ptr<C2ReflectorHelper>& helper) |
| 151 | : C2InterfaceHelper(helper), mInitStatus(C2_OK) { |
| 152 | setDerivedInstance(this); |
| 153 | |
Johny Lin | 9be5270 | 2017-11-15 20:52:31 +0800 | [diff] [blame] | 154 | // TODO(johnylin): use factory function to determine whether V4L2 stream or slice API is. |
Pin-chih Lin | 1ca0d0b | 2018-05-04 13:58:06 +0800 | [diff] [blame] | 155 | char inputMime[128]; |
Hirokazu Honda | 3f3c8a4 | 2018-05-09 22:25:19 +0800 | [diff] [blame] | 156 | if (name == kH264DecoderName || name == kH264SecureDecoderName) { |
Pin-chih Lin | 1ca0d0b | 2018-05-04 13:58:06 +0800 | [diff] [blame] | 157 | strcpy(inputMime, MEDIA_MIMETYPE_VIDEO_AVC); |
Pin-chih Lin | 3aff30b | 2018-10-02 21:11:01 +0800 | [diff] [blame] | 158 | mInputCodec = InputCodec::H264; |
Pin-chih Lin | e50c6ef | 2018-10-02 09:35:15 +0800 | [diff] [blame] | 159 | addParameter( |
| 160 | DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL) |
| 161 | .withDefault(new C2StreamProfileLevelInfo::input( |
| 162 | 0u, C2Config::PROFILE_AVC_MAIN, C2Config::LEVEL_AVC_4)) |
| 163 | .withFields( |
| 164 | {C2F(mProfileLevel, profile) |
| 165 | .oneOf({C2Config::PROFILE_AVC_BASELINE, |
| 166 | C2Config::PROFILE_AVC_CONSTRAINED_BASELINE, |
| 167 | C2Config::PROFILE_AVC_MAIN, |
| 168 | C2Config::PROFILE_AVC_HIGH, |
| 169 | C2Config::PROFILE_AVC_CONSTRAINED_HIGH}), |
| 170 | C2F(mProfileLevel, level) |
| 171 | .oneOf({C2Config::LEVEL_AVC_1, C2Config::LEVEL_AVC_1B, |
| 172 | C2Config::LEVEL_AVC_1_1, C2Config::LEVEL_AVC_1_2, |
| 173 | C2Config::LEVEL_AVC_1_3, C2Config::LEVEL_AVC_2, |
| 174 | C2Config::LEVEL_AVC_2_1, C2Config::LEVEL_AVC_2_2, |
| 175 | C2Config::LEVEL_AVC_3, C2Config::LEVEL_AVC_3_1, |
| 176 | C2Config::LEVEL_AVC_3_2, C2Config::LEVEL_AVC_4, |
| 177 | C2Config::LEVEL_AVC_4_1, C2Config::LEVEL_AVC_4_2, |
| 178 | C2Config::LEVEL_AVC_5, C2Config::LEVEL_AVC_5_1, |
| 179 | C2Config::LEVEL_AVC_5_2})}) |
Pin-chih Lin | 3aff30b | 2018-10-02 21:11:01 +0800 | [diff] [blame] | 180 | .withSetter(ProfileLevelSetter) |
Pin-chih Lin | e50c6ef | 2018-10-02 09:35:15 +0800 | [diff] [blame] | 181 | .build()); |
Hirokazu Honda | 3f3c8a4 | 2018-05-09 22:25:19 +0800 | [diff] [blame] | 182 | } else if (name == kVP8DecoderName || name == kVP8SecureDecoderName) { |
Pin-chih Lin | 1ca0d0b | 2018-05-04 13:58:06 +0800 | [diff] [blame] | 183 | strcpy(inputMime, MEDIA_MIMETYPE_VIDEO_VP8); |
Pin-chih Lin | 3aff30b | 2018-10-02 21:11:01 +0800 | [diff] [blame] | 184 | mInputCodec = InputCodec::VP8; |
Pin-chih Lin | e50c6ef | 2018-10-02 09:35:15 +0800 | [diff] [blame] | 185 | addParameter(DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL) |
| 186 | .withConstValue(new C2StreamProfileLevelInfo::input( |
| 187 | 0u, C2Config::PROFILE_UNUSED, C2Config::LEVEL_UNUSED)) |
| 188 | .build()); |
Hirokazu Honda | 3f3c8a4 | 2018-05-09 22:25:19 +0800 | [diff] [blame] | 189 | } else if (name == kVP9DecoderName || name == kVP9SecureDecoderName) { |
Pin-chih Lin | 1ca0d0b | 2018-05-04 13:58:06 +0800 | [diff] [blame] | 190 | strcpy(inputMime, MEDIA_MIMETYPE_VIDEO_VP9); |
Pin-chih Lin | 3aff30b | 2018-10-02 21:11:01 +0800 | [diff] [blame] | 191 | mInputCodec = InputCodec::VP9; |
Pin-chih Lin | e50c6ef | 2018-10-02 09:35:15 +0800 | [diff] [blame] | 192 | addParameter( |
| 193 | DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL) |
| 194 | .withDefault(new C2StreamProfileLevelInfo::input( |
| 195 | 0u, C2Config::PROFILE_VP9_0, C2Config::LEVEL_VP9_5)) |
| 196 | .withFields({C2F(mProfileLevel, profile).oneOf({C2Config::PROFILE_VP9_0}), |
| 197 | C2F(mProfileLevel, level) |
| 198 | .oneOf({C2Config::LEVEL_VP9_1, C2Config::LEVEL_VP9_1_1, |
| 199 | C2Config::LEVEL_VP9_2, C2Config::LEVEL_VP9_2_1, |
| 200 | C2Config::LEVEL_VP9_3, C2Config::LEVEL_VP9_3_1, |
| 201 | C2Config::LEVEL_VP9_4, C2Config::LEVEL_VP9_4_1, |
| 202 | C2Config::LEVEL_VP9_5})}) |
Pin-chih Lin | 3aff30b | 2018-10-02 21:11:01 +0800 | [diff] [blame] | 203 | .withSetter(ProfileLevelSetter) |
Pin-chih Lin | e50c6ef | 2018-10-02 09:35:15 +0800 | [diff] [blame] | 204 | .build()); |
Johny Lin | 9be5270 | 2017-11-15 20:52:31 +0800 | [diff] [blame] | 205 | } else { |
| 206 | ALOGE("Invalid component name: %s", name.c_str()); |
| 207 | mInitStatus = C2_BAD_VALUE; |
| 208 | return; |
| 209 | } |
Johny Lin | 7c4cb52 | 2017-06-26 16:10:24 +0800 | [diff] [blame] | 210 | // Get supported profiles from VDA. |
Johny Lin | 9be5270 | 2017-11-15 20:52:31 +0800 | [diff] [blame] | 211 | // TODO: re-think the suitable method of getting supported profiles for both pure Android and |
| 212 | // ARC++. |
Pin-chih Lin | 1ca0d0b | 2018-05-04 13:58:06 +0800 | [diff] [blame] | 213 | media::VideoDecodeAccelerator::SupportedProfiles supportedProfiles; |
Hirokazu Honda | 4b97b37 | 2018-01-21 23:20:59 +0000 | [diff] [blame] | 214 | #ifdef V4L2_CODEC2_ARC |
Pin-chih Lin | 3aff30b | 2018-10-02 21:11:01 +0800 | [diff] [blame] | 215 | supportedProfiles = arc::C2VDAAdaptorProxy::GetSupportedProfiles(mInputCodec); |
Hirokazu Honda | 4b97b37 | 2018-01-21 23:20:59 +0000 | [diff] [blame] | 216 | #else |
Pin-chih Lin | 3aff30b | 2018-10-02 21:11:01 +0800 | [diff] [blame] | 217 | supportedProfiles = C2VDAAdaptor::GetSupportedProfiles(mInputCodec); |
Hirokazu Honda | 4b97b37 | 2018-01-21 23:20:59 +0000 | [diff] [blame] | 218 | #endif |
Pin-chih Lin | 1ca0d0b | 2018-05-04 13:58:06 +0800 | [diff] [blame] | 219 | if (supportedProfiles.empty()) { |
Pin-chih Lin | 3aff30b | 2018-10-02 21:11:01 +0800 | [diff] [blame] | 220 | ALOGE("No supported profile from input codec: %d", mInputCodec); |
Johny Lin | 9be5270 | 2017-11-15 20:52:31 +0800 | [diff] [blame] | 221 | mInitStatus = C2_BAD_VALUE; |
| 222 | return; |
| 223 | } |
Johny Lin | 7c4cb52 | 2017-06-26 16:10:24 +0800 | [diff] [blame] | 224 | |
Pin-chih Lin | 1ca0d0b | 2018-05-04 13:58:06 +0800 | [diff] [blame] | 225 | mCodecProfile = supportedProfiles[0].profile; |
Johny Lin | 7c4cb52 | 2017-06-26 16:10:24 +0800 | [diff] [blame] | 226 | |
Pin-chih Lin | 1ca0d0b | 2018-05-04 13:58:06 +0800 | [diff] [blame] | 227 | auto minSize = supportedProfiles[0].min_resolution; |
| 228 | auto maxSize = supportedProfiles[0].max_resolution; |
Johny Lin | 7c4cb52 | 2017-06-26 16:10:24 +0800 | [diff] [blame] | 229 | |
Pin-chih Lin | 1ca0d0b | 2018-05-04 13:58:06 +0800 | [diff] [blame] | 230 | addParameter( |
| 231 | DefineParam(mInputFormat, C2_PARAMKEY_INPUT_STREAM_BUFFER_TYPE) |
| 232 | .withConstValue(new C2StreamBufferTypeSetting::input(0u, C2FormatCompressed)) |
| 233 | .build()); |
Johny Lin | 7c4cb52 | 2017-06-26 16:10:24 +0800 | [diff] [blame] | 234 | |
Pin-chih Lin | 1ca0d0b | 2018-05-04 13:58:06 +0800 | [diff] [blame] | 235 | addParameter(DefineParam(mOutputFormat, C2_PARAMKEY_OUTPUT_STREAM_BUFFER_TYPE) |
| 236 | .withConstValue(new C2StreamBufferTypeSetting::output(0u, C2FormatVideo)) |
| 237 | .build()); |
Johny Lin | 7c4cb52 | 2017-06-26 16:10:24 +0800 | [diff] [blame] | 238 | |
Pin-chih Lin | 1ca0d0b | 2018-05-04 13:58:06 +0800 | [diff] [blame] | 239 | addParameter( |
| 240 | DefineParam(mInputMediaType, C2_PARAMKEY_INPUT_MEDIA_TYPE) |
| 241 | .withConstValue(AllocSharedString<C2PortMediaTypeSetting::input>(inputMime)) |
| 242 | .build()); |
Johny Lin | 7c4cb52 | 2017-06-26 16:10:24 +0800 | [diff] [blame] | 243 | |
Pin-chih Lin | 1ca0d0b | 2018-05-04 13:58:06 +0800 | [diff] [blame] | 244 | addParameter(DefineParam(mOutputMediaType, C2_PARAMKEY_OUTPUT_MEDIA_TYPE) |
| 245 | .withConstValue(AllocSharedString<C2PortMediaTypeSetting::output>( |
| 246 | MEDIA_MIMETYPE_VIDEO_RAW)) |
| 247 | .build()); |
Johny Lin | 7c4cb52 | 2017-06-26 16:10:24 +0800 | [diff] [blame] | 248 | |
Pin-chih Lin | 1ca0d0b | 2018-05-04 13:58:06 +0800 | [diff] [blame] | 249 | addParameter(DefineParam(mSize, C2_PARAMKEY_STREAM_PICTURE_SIZE) |
| 250 | .withDefault(new C2StreamPictureSizeInfo::output(0u, 176, 144)) |
| 251 | .withFields({ |
| 252 | C2F(mSize, width).inRange(minSize.width(), maxSize.width(), 16), |
| 253 | C2F(mSize, height).inRange(minSize.height(), maxSize.height(), 16), |
| 254 | }) |
Pin-chih Lin | 3aff30b | 2018-10-02 21:11:01 +0800 | [diff] [blame] | 255 | .withSetter(SizeSetter) |
Pin-chih Lin | 1ca0d0b | 2018-05-04 13:58:06 +0800 | [diff] [blame] | 256 | .build()); |
Pin-chih Lin | 2fea071 | 2018-05-14 19:57:14 +0800 | [diff] [blame] | 257 | |
Hirokazu Honda | d41df2d | 2018-09-26 12:39:21 +0900 | [diff] [blame] | 258 | // App may set a smaller value for maximum of input buffer size than actually required |
| 259 | // by mistake. C2VDAComponent overrides it if the value specified by app is smaller than |
| 260 | // the calculated value in MaxSizeCalculator(). |
| 261 | // This value is the default maximum of linear buffer size (kLinearBufferSize) in |
| 262 | // CCodecBufferChannel.cpp. |
| 263 | constexpr static size_t kLinearBufferSize = 1048576; |
| 264 | struct LocalCalculator { |
| 265 | static C2R MaxSizeCalculator(bool mayBlock, C2P<C2StreamMaxBufferSizeInfo::input>& me, |
| 266 | const C2P<C2StreamPictureSizeInfo::output>& size) { |
| 267 | (void)mayBlock; |
| 268 | // TODO: Need larger size? |
| 269 | me.set().value = kLinearBufferSize; |
| 270 | const uint32_t width = size.v.width; |
| 271 | const uint32_t height = size.v.height; |
| 272 | // Enlarge the input buffer for 4k video |
| 273 | if ((width > 1920 && height > 1080)) { |
| 274 | me.set().value = 4 * kLinearBufferSize; |
| 275 | } |
| 276 | return C2R::Ok(); |
| 277 | } |
| 278 | }; |
| 279 | addParameter(DefineParam(mMaxInputSize, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE) |
| 280 | .withDefault(new C2StreamMaxBufferSizeInfo::input(0u, kLinearBufferSize)) |
| 281 | .withFields({ |
| 282 | C2F(mMaxInputSize, value).any(), |
| 283 | }) |
| 284 | .calculatedAs(LocalCalculator::MaxSizeCalculator, mSize) |
| 285 | .build()); |
| 286 | |
Hirokazu Honda | 3f3c8a4 | 2018-05-09 22:25:19 +0800 | [diff] [blame] | 287 | bool secureMode = name.find(".secure") != std::string::npos; |
| 288 | C2Allocator::id_t inputAllocators[] = {secureMode ? C2VDAAllocatorStore::SECURE_LINEAR |
| 289 | : C2PlatformAllocatorStore::ION}; |
Pin-chih Lin | b4ef939 | 2018-07-31 16:41:15 +0800 | [diff] [blame] | 290 | |
| 291 | C2Allocator::id_t outputAllocators[] = {C2VDAAllocatorStore::V4L2_BUFFERPOOL}; |
| 292 | |
| 293 | C2Allocator::id_t surfaceAllocator = secureMode ? C2VDAAllocatorStore::SECURE_GRAPHIC |
| 294 | : C2VDAAllocatorStore::V4L2_BUFFERQUEUE; |
Pin-chih Lin | 2fea071 | 2018-05-14 19:57:14 +0800 | [diff] [blame] | 295 | |
| 296 | addParameter( |
| 297 | DefineParam(mInputAllocatorIds, C2_PARAMKEY_INPUT_ALLOCATORS) |
| 298 | .withConstValue(C2PortAllocatorsTuning::input::AllocShared(inputAllocators)) |
| 299 | .build()); |
| 300 | |
| 301 | addParameter( |
| 302 | DefineParam(mOutputAllocatorIds, C2_PARAMKEY_OUTPUT_ALLOCATORS) |
| 303 | .withConstValue(C2PortAllocatorsTuning::output::AllocShared(outputAllocators)) |
| 304 | .build()); |
| 305 | |
Pin-chih Lin | b4ef939 | 2018-07-31 16:41:15 +0800 | [diff] [blame] | 306 | addParameter(DefineParam(mOutputSurfaceAllocatorId, C2_PARAMKEY_OUTPUT_SURFACE_ALLOCATOR) |
| 307 | .withConstValue(new C2PortSurfaceAllocatorTuning::output(surfaceAllocator)) |
| 308 | .build()); |
| 309 | |
Pin-chih Lin | 2fea071 | 2018-05-14 19:57:14 +0800 | [diff] [blame] | 310 | C2BlockPool::local_id_t outputBlockPools[] = {kDefaultOutputBlockPool}; |
| 311 | |
| 312 | addParameter( |
| 313 | DefineParam(mOutputBlockPoolIds, C2_PARAMKEY_OUTPUT_BLOCK_POOLS) |
| 314 | .withDefault(C2PortBlockPoolsTuning::output::AllocShared(outputBlockPools)) |
| 315 | .withFields({C2F(mOutputBlockPoolIds, m.values[0]).any(), |
| 316 | C2F(mOutputBlockPoolIds, m.values).inRange(0, 1)}) |
| 317 | .withSetter(Setter<C2PortBlockPoolsTuning::output>::NonStrictValuesWithNoDeps) |
| 318 | .build()); |
Pin-chih Lin | 3aff30b | 2018-10-02 21:11:01 +0800 | [diff] [blame] | 319 | |
| 320 | addParameter( |
| 321 | DefineParam(mDefaultColorAspects, C2_PARAMKEY_DEFAULT_COLOR_ASPECTS) |
| 322 | .withDefault(new C2StreamColorAspectsTuning::output( |
| 323 | 0u, C2Color::RANGE_UNSPECIFIED, C2Color::PRIMARIES_UNSPECIFIED, |
| 324 | C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED)) |
| 325 | .withFields( |
| 326 | {C2F(mDefaultColorAspects, range) |
| 327 | .inRange(C2Color::RANGE_UNSPECIFIED, C2Color::RANGE_OTHER), |
| 328 | C2F(mDefaultColorAspects, primaries) |
| 329 | .inRange(C2Color::PRIMARIES_UNSPECIFIED, |
| 330 | C2Color::PRIMARIES_OTHER), |
| 331 | C2F(mDefaultColorAspects, transfer) |
| 332 | .inRange(C2Color::TRANSFER_UNSPECIFIED, |
| 333 | C2Color::TRANSFER_OTHER), |
| 334 | C2F(mDefaultColorAspects, matrix) |
| 335 | .inRange(C2Color::MATRIX_UNSPECIFIED, C2Color::MATRIX_OTHER)}) |
| 336 | .withSetter(DefaultColorAspectsSetter) |
| 337 | .build()); |
| 338 | |
| 339 | addParameter( |
| 340 | DefineParam(mCodedColorAspects, C2_PARAMKEY_VUI_COLOR_ASPECTS) |
| 341 | .withDefault(new C2StreamColorAspectsInfo::input( |
| 342 | 0u, C2Color::RANGE_LIMITED, C2Color::PRIMARIES_UNSPECIFIED, |
| 343 | C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED)) |
| 344 | .withFields( |
| 345 | {C2F(mCodedColorAspects, range) |
| 346 | .inRange(C2Color::RANGE_UNSPECIFIED, C2Color::RANGE_OTHER), |
| 347 | C2F(mCodedColorAspects, primaries) |
| 348 | .inRange(C2Color::PRIMARIES_UNSPECIFIED, |
| 349 | C2Color::PRIMARIES_OTHER), |
| 350 | C2F(mCodedColorAspects, transfer) |
| 351 | .inRange(C2Color::TRANSFER_UNSPECIFIED, |
| 352 | C2Color::TRANSFER_OTHER), |
| 353 | C2F(mCodedColorAspects, matrix) |
| 354 | .inRange(C2Color::MATRIX_UNSPECIFIED, C2Color::MATRIX_OTHER)}) |
| 355 | .withSetter(DefaultColorAspectsSetter) |
| 356 | .build()); |
| 357 | |
| 358 | addParameter( |
| 359 | DefineParam(mColorAspects, C2_PARAMKEY_COLOR_ASPECTS) |
| 360 | .withDefault(new C2StreamColorAspectsInfo::output( |
| 361 | 0u, C2Color::RANGE_UNSPECIFIED, C2Color::PRIMARIES_UNSPECIFIED, |
| 362 | C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED)) |
| 363 | .withFields( |
| 364 | {C2F(mColorAspects, range) |
| 365 | .inRange(C2Color::RANGE_UNSPECIFIED, C2Color::RANGE_OTHER), |
| 366 | C2F(mColorAspects, primaries) |
| 367 | .inRange(C2Color::PRIMARIES_UNSPECIFIED, |
| 368 | C2Color::PRIMARIES_OTHER), |
| 369 | C2F(mColorAspects, transfer) |
| 370 | .inRange(C2Color::TRANSFER_UNSPECIFIED, |
| 371 | C2Color::TRANSFER_OTHER), |
| 372 | C2F(mColorAspects, matrix) |
| 373 | .inRange(C2Color::MATRIX_UNSPECIFIED, C2Color::MATRIX_OTHER)}) |
| 374 | .withSetter(MergedColorAspectsSetter, mDefaultColorAspects, mCodedColorAspects) |
| 375 | .build()); |
Johny Lin | 7c4cb52 | 2017-06-26 16:10:24 +0800 | [diff] [blame] | 376 | } |
| 377 | |
| 378 | //////////////////////////////////////////////////////////////////////////////// |
Johny Lin | a891f0e | 2017-12-19 10:25:27 +0800 | [diff] [blame] | 379 | #define EXPECT_STATE_OR_RETURN_ON_ERROR(x) \ |
| 380 | do { \ |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 381 | if (mComponentState == ComponentState::ERROR) return; \ |
Johny Lin | a891f0e | 2017-12-19 10:25:27 +0800 | [diff] [blame] | 382 | CHECK_EQ(mComponentState, ComponentState::x); \ |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 383 | } while (0) |
| 384 | |
Johny Lin | a891f0e | 2017-12-19 10:25:27 +0800 | [diff] [blame] | 385 | #define EXPECT_RUNNING_OR_RETURN_ON_ERROR() \ |
| 386 | do { \ |
| 387 | if (mComponentState == ComponentState::ERROR) return; \ |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 388 | CHECK_NE(mComponentState, ComponentState::UNINITIALIZED); \ |
| 389 | } while (0) |
| 390 | |
Johny Lin | ac6e270 | 2018-01-17 12:11:52 +0800 | [diff] [blame] | 391 | C2VDAComponent::VideoFormat::VideoFormat(HalPixelFormat pixelFormat, uint32_t minNumBuffers, |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 392 | media::Size codedSize, media::Rect visibleRect) |
Johny Lin | a891f0e | 2017-12-19 10:25:27 +0800 | [diff] [blame] | 393 | : mPixelFormat(pixelFormat), |
| 394 | mMinNumBuffers(minNumBuffers), |
| 395 | mCodedSize(codedSize), |
| 396 | mVisibleRect(visibleRect) {} |
Johny Lin | 7c4cb52 | 2017-06-26 16:10:24 +0800 | [diff] [blame] | 397 | |
Pin-chih Lin | 1ca0d0b | 2018-05-04 13:58:06 +0800 | [diff] [blame] | 398 | C2VDAComponent::C2VDAComponent(C2String name, c2_node_id_t id, |
| 399 | const std::shared_ptr<C2ReflectorHelper>& helper) |
| 400 | : mIntfImpl(std::make_shared<IntfImpl>(name, helper)), |
| 401 | mIntf(std::make_shared<SimpleInterface<IntfImpl>>(name.c_str(), id, mIntfImpl)), |
Johny Lin | a891f0e | 2017-12-19 10:25:27 +0800 | [diff] [blame] | 402 | mThread("C2VDAComponentThread"), |
Pin-chih Lin | 906956a | 2018-05-22 14:12:59 +0800 | [diff] [blame] | 403 | mDequeueThread("C2VDAComponentDequeueThread"), |
Johny Lin | a891f0e | 2017-12-19 10:25:27 +0800 | [diff] [blame] | 404 | mVDAInitResult(VideoDecodeAcceleratorAdaptor::Result::ILLEGAL_STATE), |
| 405 | mComponentState(ComponentState::UNINITIALIZED), |
Pin-chih Lin | 617d763 | 2018-05-30 16:48:07 +0800 | [diff] [blame] | 406 | mPendingOutputEOS(false), |
Pin-chih Lin | 3aff30b | 2018-10-02 21:11:01 +0800 | [diff] [blame] | 407 | mPendingColorAspectsChange(false), |
| 408 | mPendingColorAspectsChangeFrameIndex(0), |
Johny Lin | a891f0e | 2017-12-19 10:25:27 +0800 | [diff] [blame] | 409 | mCodecProfile(media::VIDEO_CODEC_PROFILE_UNKNOWN), |
| 410 | mState(State::UNLOADED), |
| 411 | mWeakThisFactory(this) { |
Johny Lin | 9be5270 | 2017-11-15 20:52:31 +0800 | [diff] [blame] | 412 | // TODO(johnylin): the client may need to know if init is failed. |
Pin-chih Lin | 1ca0d0b | 2018-05-04 13:58:06 +0800 | [diff] [blame] | 413 | if (mIntfImpl->status() != C2_OK) { |
| 414 | ALOGE("Component interface init failed (err code = %d)", mIntfImpl->status()); |
Johny Lin | 9be5270 | 2017-11-15 20:52:31 +0800 | [diff] [blame] | 415 | return; |
| 416 | } |
Hirokazu Honda | 3f3c8a4 | 2018-05-09 22:25:19 +0800 | [diff] [blame] | 417 | |
| 418 | mSecureMode = name.find(".secure") != std::string::npos; |
Johny Lin | 744cff1 | 2017-08-16 16:56:25 +0800 | [diff] [blame] | 419 | if (!mThread.Start()) { |
Johny Lin | 9be5270 | 2017-11-15 20:52:31 +0800 | [diff] [blame] | 420 | ALOGE("Component thread failed to start."); |
Johny Lin | 744cff1 | 2017-08-16 16:56:25 +0800 | [diff] [blame] | 421 | return; |
| 422 | } |
| 423 | mTaskRunner = mThread.task_runner(); |
Pin-chih Lin | 2a00c24 | 2018-03-28 20:41:50 +0800 | [diff] [blame] | 424 | mState.store(State::LOADED); |
Johny Lin | 7c4cb52 | 2017-06-26 16:10:24 +0800 | [diff] [blame] | 425 | } |
| 426 | |
| 427 | C2VDAComponent::~C2VDAComponent() { |
Johny Lin | 744cff1 | 2017-08-16 16:56:25 +0800 | [diff] [blame] | 428 | if (mThread.IsRunning()) { |
Johny Lin | a891f0e | 2017-12-19 10:25:27 +0800 | [diff] [blame] | 429 | mTaskRunner->PostTask(FROM_HERE, |
Pin-chih Lin | 448c0c7 | 2018-05-22 14:17:53 +0800 | [diff] [blame] | 430 | ::base::Bind(&C2VDAComponent::onDestroy, ::base::Unretained(this))); |
Johny Lin | 744cff1 | 2017-08-16 16:56:25 +0800 | [diff] [blame] | 431 | mThread.Stop(); |
| 432 | } |
Johny Lin | 744cff1 | 2017-08-16 16:56:25 +0800 | [diff] [blame] | 433 | } |
| 434 | |
Johny Lin | 744cff1 | 2017-08-16 16:56:25 +0800 | [diff] [blame] | 435 | void C2VDAComponent::onDestroy() { |
| 436 | DCHECK(mTaskRunner->BelongsToCurrentThread()); |
| 437 | ALOGV("onDestroy"); |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 438 | if (mVDAAdaptor.get()) { |
| 439 | mVDAAdaptor->destroy(); |
| 440 | mVDAAdaptor.reset(nullptr); |
| 441 | } |
Pin-chih Lin | 906956a | 2018-05-22 14:12:59 +0800 | [diff] [blame] | 442 | stopDequeueThread(); |
Johny Lin | 744cff1 | 2017-08-16 16:56:25 +0800 | [diff] [blame] | 443 | } |
| 444 | |
Pin-chih Lin | 448c0c7 | 2018-05-22 14:17:53 +0800 | [diff] [blame] | 445 | void C2VDAComponent::onStart(media::VideoCodecProfile profile, ::base::WaitableEvent* done) { |
Johny Lin | 744cff1 | 2017-08-16 16:56:25 +0800 | [diff] [blame] | 446 | DCHECK(mTaskRunner->BelongsToCurrentThread()); |
| 447 | ALOGV("onStart"); |
Hirokazu Honda | ce27506 | 2017-10-30 11:34:57 +0900 | [diff] [blame] | 448 | CHECK_EQ(mComponentState, ComponentState::UNINITIALIZED); |
Pin-chih Lin | 878832b | 2018-04-18 20:33:13 +0800 | [diff] [blame] | 449 | |
| 450 | #ifdef V4L2_CODEC2_ARC |
| 451 | mVDAAdaptor.reset(new arc::C2VDAAdaptorProxy()); |
| 452 | #else |
| 453 | mVDAAdaptor.reset(new C2VDAAdaptor()); |
| 454 | #endif |
| 455 | |
Hirokazu Honda | 3f3c8a4 | 2018-05-09 22:25:19 +0800 | [diff] [blame] | 456 | mVDAInitResult = mVDAAdaptor->initialize(profile, mSecureMode, this); |
Johny Lin | 744cff1 | 2017-08-16 16:56:25 +0800 | [diff] [blame] | 457 | if (mVDAInitResult == VideoDecodeAcceleratorAdaptor::Result::SUCCESS) { |
| 458 | mComponentState = ComponentState::STARTED; |
| 459 | } |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 460 | |
Pin-chih Lin | 3aff30b | 2018-10-02 21:11:01 +0800 | [diff] [blame] | 461 | if (!mSecureMode && mIntfImpl->getInputCodec() == InputCodec::H264) { |
| 462 | // Get default color aspects on start. |
| 463 | updateColorAspects(); |
| 464 | mPendingColorAspectsChange = false; |
| 465 | } |
| 466 | |
Johny Lin | 744cff1 | 2017-08-16 16:56:25 +0800 | [diff] [blame] | 467 | done->Signal(); |
| 468 | } |
| 469 | |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 470 | void C2VDAComponent::onQueueWork(std::unique_ptr<C2Work> work) { |
| 471 | DCHECK(mTaskRunner->BelongsToCurrentThread()); |
Johny Lin | 3760d5f | 2018-01-31 14:40:13 +0800 | [diff] [blame] | 472 | ALOGV("onQueueWork: flags=0x%x, index=%llu, timestamp=%llu", work->input.flags, |
| 473 | work->input.ordinal.frameIndex.peekull(), work->input.ordinal.timestamp.peekull()); |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 474 | EXPECT_RUNNING_OR_RETURN_ON_ERROR(); |
Johny Lin | 3760d5f | 2018-01-31 14:40:13 +0800 | [diff] [blame] | 475 | |
| 476 | uint32_t drainMode = NO_DRAIN; |
| 477 | if (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) { |
| 478 | drainMode = DRAIN_COMPONENT_WITH_EOS; |
| 479 | } |
| 480 | mQueue.push({std::move(work), drainMode}); |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 481 | // TODO(johnylin): set a maximum size of mQueue and check if mQueue is already full. |
| 482 | |
| 483 | mTaskRunner->PostTask(FROM_HERE, |
Pin-chih Lin | 448c0c7 | 2018-05-22 14:17:53 +0800 | [diff] [blame] | 484 | ::base::Bind(&C2VDAComponent::onDequeueWork, ::base::Unretained(this))); |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 485 | } |
| 486 | |
| 487 | void C2VDAComponent::onDequeueWork() { |
| 488 | DCHECK(mTaskRunner->BelongsToCurrentThread()); |
| 489 | ALOGV("onDequeueWork"); |
| 490 | EXPECT_RUNNING_OR_RETURN_ON_ERROR(); |
| 491 | if (mQueue.empty()) { |
| 492 | return; |
| 493 | } |
Pin-chih Lin | 29d50d9 | 2018-05-30 14:03:52 +0800 | [diff] [blame] | 494 | if (mComponentState == ComponentState::DRAINING || |
| 495 | mComponentState == ComponentState::FLUSHING) { |
| 496 | ALOGV("Temporarily stop dequeueing works since component is draining/flushing."); |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 497 | return; |
| 498 | } |
| 499 | if (mComponentState != ComponentState::STARTED) { |
| 500 | ALOGE("Work queue should be empty if the component is not in STARTED state."); |
| 501 | return; |
| 502 | } |
| 503 | |
| 504 | // Dequeue a work from mQueue. |
Johny Lin | 3760d5f | 2018-01-31 14:40:13 +0800 | [diff] [blame] | 505 | std::unique_ptr<C2Work> work(std::move(mQueue.front().mWork)); |
| 506 | auto drainMode = mQueue.front().mDrainMode; |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 507 | mQueue.pop(); |
| 508 | |
Pin-chih Lin | ca72eff | 2018-06-12 11:22:04 +0800 | [diff] [blame] | 509 | CHECK_LE(work->input.buffers.size(), 1u); |
Pin-chih Lin | 2dcfa1a | 2018-11-28 14:25:09 +0800 | [diff] [blame] | 510 | bool isEmptyCSDWork = false; |
| 511 | // Use frameIndex as bitstreamId. |
| 512 | int32_t bitstreamId = frameIndexToBitstreamId(work->input.ordinal.frameIndex); |
Pin-chih Lin | ca72eff | 2018-06-12 11:22:04 +0800 | [diff] [blame] | 513 | if (work->input.buffers.empty()) { |
Pin-chih Lin | 3fe0c8d | 2018-09-11 12:17:53 +0800 | [diff] [blame] | 514 | // Client may queue a work with no input buffer for either it's EOS or empty CSD, otherwise |
| 515 | // every work must have one input buffer. |
Pin-chih Lin | 2dcfa1a | 2018-11-28 14:25:09 +0800 | [diff] [blame] | 516 | isEmptyCSDWork = work->input.flags & C2FrameData::FLAG_CODEC_CONFIG; |
| 517 | CHECK(drainMode != NO_DRAIN || isEmptyCSDWork); |
Pin-chih Lin | 3fe0c8d | 2018-09-11 12:17:53 +0800 | [diff] [blame] | 518 | // Emplace a nullptr to unify the check for work done. |
| 519 | ALOGV("Got a work with no input buffer! Emplace a nullptr inside."); |
| 520 | work->input.buffers.emplace_back(nullptr); |
Pin-chih Lin | ca72eff | 2018-06-12 11:22:04 +0800 | [diff] [blame] | 521 | } else { |
| 522 | // If input.buffers is not empty, the buffer should have meaningful content inside. |
| 523 | C2ConstLinearBlock linearBlock = work->input.buffers.front()->data().linearBlocks().front(); |
| 524 | CHECK_GT(linearBlock.size(), 0u); |
Pin-chih Lin | 3aff30b | 2018-10-02 21:11:01 +0800 | [diff] [blame] | 525 | |
| 526 | // Call parseCodedColorAspects() to try to parse color aspects from bitstream only if: |
| 527 | // 1) This is non-secure decoding. |
| 528 | // 2) This is H264 codec. |
| 529 | // 3) This input is CSD buffer (with flags FLAG_CODEC_CONFIG). |
| 530 | if (!mSecureMode && (mIntfImpl->getInputCodec() == InputCodec::H264) && |
| 531 | (work->input.flags & C2FrameData::FLAG_CODEC_CONFIG)) { |
| 532 | if (parseCodedColorAspects(linearBlock)) { |
| 533 | // Record current frame index, color aspects should be updated only for output |
| 534 | // buffers whose frame indices are not less than this one. |
| 535 | mPendingColorAspectsChange = true; |
| 536 | mPendingColorAspectsChangeFrameIndex = work->input.ordinal.frameIndex.peeku(); |
| 537 | } |
| 538 | } |
Johny Lin | 3760d5f | 2018-01-31 14:40:13 +0800 | [diff] [blame] | 539 | // Send input buffer to VDA for decode. |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 540 | sendInputBufferToAccelerator(linearBlock, bitstreamId); |
| 541 | } |
| 542 | |
Johny Lin | 3760d5f | 2018-01-31 14:40:13 +0800 | [diff] [blame] | 543 | CHECK_EQ(work->worklets.size(), 1u); |
| 544 | work->worklets.front()->output.flags = static_cast<C2FrameData::flags_t>(0); |
| 545 | work->worklets.front()->output.buffers.clear(); |
| 546 | work->worklets.front()->output.ordinal = work->input.ordinal; |
| 547 | |
| 548 | if (drainMode != NO_DRAIN) { |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 549 | mVDAAdaptor->flush(); |
| 550 | mComponentState = ComponentState::DRAINING; |
Pin-chih Lin | 617d763 | 2018-05-30 16:48:07 +0800 | [diff] [blame] | 551 | mPendingOutputEOS = drainMode == DRAIN_COMPONENT_WITH_EOS; |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 552 | } |
| 553 | |
Johny Lin | 3760d5f | 2018-01-31 14:40:13 +0800 | [diff] [blame] | 554 | // Put work to mPendingWorks. |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 555 | mPendingWorks.emplace_back(std::move(work)); |
Pin-chih Lin | 2dcfa1a | 2018-11-28 14:25:09 +0800 | [diff] [blame] | 556 | if (isEmptyCSDWork) { |
| 557 | // Directly report the empty CSD work as finished. |
| 558 | reportWorkIfFinished(bitstreamId); |
| 559 | } |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 560 | |
| 561 | if (!mQueue.empty()) { |
Pin-chih Lin | 448c0c7 | 2018-05-22 14:17:53 +0800 | [diff] [blame] | 562 | mTaskRunner->PostTask(FROM_HERE, ::base::Bind(&C2VDAComponent::onDequeueWork, |
| 563 | ::base::Unretained(this))); |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 564 | } |
| 565 | } |
| 566 | |
| 567 | void C2VDAComponent::onInputBufferDone(int32_t bitstreamId) { |
| 568 | DCHECK(mTaskRunner->BelongsToCurrentThread()); |
| 569 | ALOGV("onInputBufferDone: bitstream id=%d", bitstreamId); |
| 570 | EXPECT_RUNNING_OR_RETURN_ON_ERROR(); |
| 571 | |
| 572 | C2Work* work = getPendingWorkByBitstreamId(bitstreamId); |
| 573 | if (!work) { |
| 574 | reportError(C2_CORRUPTED); |
| 575 | return; |
| 576 | } |
| 577 | |
Pin-chih Lin | cd56fe7 | 2018-05-04 10:29:23 +0800 | [diff] [blame] | 578 | // When the work is done, the input buffer shall be reset by component. |
| 579 | work->input.buffers.front().reset(); |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 580 | |
Pin-chih Lin | 2dcfa1a | 2018-11-28 14:25:09 +0800 | [diff] [blame] | 581 | reportWorkIfFinished(bitstreamId); |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 582 | } |
| 583 | |
Pin-chih Lin | 585324e | 2018-07-25 16:24:54 +0800 | [diff] [blame] | 584 | void C2VDAComponent::onOutputBufferReturned(std::shared_ptr<C2GraphicBlock> block, |
| 585 | uint32_t poolId) { |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 586 | DCHECK(mTaskRunner->BelongsToCurrentThread()); |
Pin-chih Lin | 585324e | 2018-07-25 16:24:54 +0800 | [diff] [blame] | 587 | ALOGV("onOutputBufferReturned: pool id=%u", poolId); |
Pin-chih Lin | 9bf0e96 | 2018-03-08 23:36:17 +0800 | [diff] [blame] | 588 | if (mComponentState == ComponentState::UNINITIALIZED) { |
| 589 | // Output buffer is returned from client after component is stopped. Just let the buffer be |
| 590 | // released. |
| 591 | return; |
| 592 | } |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 593 | |
Pin-chih Lin | 81a44bb | 2018-08-17 17:54:00 +0800 | [diff] [blame] | 594 | if (block->width() != static_cast<uint32_t>(mOutputFormat.mCodedSize.width()) || |
| 595 | block->height() != static_cast<uint32_t>(mOutputFormat.mCodedSize.height())) { |
| 596 | // Output buffer is returned after we changed output resolution. Just let the buffer be |
| 597 | // released. |
| 598 | ALOGV("Discard obsolete graphic block: pool id=%u", poolId); |
| 599 | return; |
| 600 | } |
| 601 | |
Pin-chih Lin | 585324e | 2018-07-25 16:24:54 +0800 | [diff] [blame] | 602 | GraphicBlockInfo* info = getGraphicBlockByPoolId(poolId); |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 603 | if (!info) { |
| 604 | reportError(C2_CORRUPTED); |
| 605 | return; |
| 606 | } |
| 607 | CHECK_EQ(info->mState, GraphicBlockInfo::State::OWNED_BY_CLIENT); |
Pin-chih Lin | 585324e | 2018-07-25 16:24:54 +0800 | [diff] [blame] | 608 | info->mGraphicBlock = std::move(block); |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 609 | info->mState = GraphicBlockInfo::State::OWNED_BY_COMPONENT; |
| 610 | |
| 611 | if (mPendingOutputFormat) { |
| 612 | tryChangeOutputFormat(); |
| 613 | } else { |
Pin-chih Lin | 2dcfa1a | 2018-11-28 14:25:09 +0800 | [diff] [blame] | 614 | // Do not pass the ownership to accelerator if this buffer will still be reused under |
| 615 | // |mPendingBuffersToWork|. |
| 616 | auto existingFrame = std::find_if( |
| 617 | mPendingBuffersToWork.begin(), mPendingBuffersToWork.end(), |
| 618 | [id = info->mBlockId](const OutputBufferInfo& o) { return o.mBlockId == id; }); |
| 619 | bool ownByAccelerator = existingFrame == mPendingBuffersToWork.end(); |
| 620 | sendOutputBufferToAccelerator(info, ownByAccelerator); |
| 621 | sendOutputBufferToWorkIfAny(false /* dropIfUnavailable */); |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 622 | } |
| 623 | } |
| 624 | |
| 625 | void C2VDAComponent::onOutputBufferDone(int32_t pictureBufferId, int32_t bitstreamId) { |
| 626 | DCHECK(mTaskRunner->BelongsToCurrentThread()); |
| 627 | ALOGV("onOutputBufferDone: picture id=%d, bitstream id=%d", pictureBufferId, bitstreamId); |
| 628 | EXPECT_RUNNING_OR_RETURN_ON_ERROR(); |
| 629 | |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 630 | GraphicBlockInfo* info = getGraphicBlockById(pictureBufferId); |
| 631 | if (!info) { |
| 632 | reportError(C2_CORRUPTED); |
| 633 | return; |
| 634 | } |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 635 | |
Pin-chih Lin | 2dcfa1a | 2018-11-28 14:25:09 +0800 | [diff] [blame] | 636 | if (info->mState == GraphicBlockInfo::State::OWNED_BY_ACCELERATOR) { |
| 637 | info->mState = GraphicBlockInfo::State::OWNED_BY_COMPONENT; |
Pin-chih Lin | 3aff30b | 2018-10-02 21:11:01 +0800 | [diff] [blame] | 638 | } |
Pin-chih Lin | 2dcfa1a | 2018-11-28 14:25:09 +0800 | [diff] [blame] | 639 | mPendingBuffersToWork.push_back({bitstreamId, pictureBufferId}); |
| 640 | sendOutputBufferToWorkIfAny(false /* dropIfUnavailable */); |
| 641 | } |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 642 | |
Pin-chih Lin | 2dcfa1a | 2018-11-28 14:25:09 +0800 | [diff] [blame] | 643 | void C2VDAComponent::sendOutputBufferToWorkIfAny(bool dropIfUnavailable) { |
| 644 | DCHECK(mTaskRunner->BelongsToCurrentThread()); |
| 645 | |
| 646 | while (!mPendingBuffersToWork.empty()) { |
| 647 | auto nextBuffer = mPendingBuffersToWork.front(); |
| 648 | GraphicBlockInfo* info = getGraphicBlockById(nextBuffer.mBlockId); |
| 649 | CHECK_NE(info->mState, GraphicBlockInfo::State::OWNED_BY_ACCELERATOR); |
| 650 | |
| 651 | C2Work* work = getPendingWorkByBitstreamId(nextBuffer.mBitstreamId); |
| 652 | if (!work) { |
| 653 | reportError(C2_CORRUPTED); |
| 654 | return; |
| 655 | } |
| 656 | |
| 657 | if (info->mState == GraphicBlockInfo::State::OWNED_BY_CLIENT) { |
| 658 | // This buffer is the existing frame and still owned by client. |
| 659 | if (!dropIfUnavailable && |
| 660 | std::find(mUndequeuedBlockIds.begin(), mUndequeuedBlockIds.end(), |
| 661 | nextBuffer.mBlockId) == mUndequeuedBlockIds.end()) { |
| 662 | ALOGV("Still waiting for existing frame returned from client..."); |
| 663 | return; |
| 664 | } |
| 665 | ALOGV("Drop this frame..."); |
| 666 | sendOutputBufferToAccelerator(info, false /* ownByAccelerator */); |
| 667 | work->worklets.front()->output.flags = C2FrameData::FLAG_DROP_FRAME; |
| 668 | } else { |
| 669 | // This buffer is ready to push into the corresponding work. |
| 670 | // Output buffer will be passed to client soon along with mListener->onWorkDone_nb(). |
| 671 | info->mState = GraphicBlockInfo::State::OWNED_BY_CLIENT; |
| 672 | mBuffersInClient++; |
| 673 | updateUndequeuedBlockIds(info->mBlockId); |
| 674 | |
| 675 | // Attach output buffer to the work corresponded to bitstreamId. |
| 676 | C2ConstGraphicBlock constBlock = info->mGraphicBlock->share( |
| 677 | C2Rect(mOutputFormat.mVisibleRect.width(), |
| 678 | mOutputFormat.mVisibleRect.height()), |
| 679 | C2Fence()); |
| 680 | MarkBlockPoolDataAsShared(constBlock); |
| 681 | |
| 682 | std::shared_ptr<C2Buffer> buffer = C2Buffer::CreateGraphicBuffer(std::move(constBlock)); |
| 683 | if (mPendingColorAspectsChange && |
| 684 | work->input.ordinal.frameIndex.peeku() >= mPendingColorAspectsChangeFrameIndex) { |
| 685 | updateColorAspects(); |
| 686 | mPendingColorAspectsChange = false; |
| 687 | } |
| 688 | if (mCurrentColorAspects) { |
| 689 | buffer->setInfo(mCurrentColorAspects); |
| 690 | } |
| 691 | work->worklets.front()->output.buffers.emplace_back(std::move(buffer)); |
| 692 | info->mGraphicBlock.reset(); |
| 693 | } |
| 694 | reportWorkIfFinished(nextBuffer.mBitstreamId); |
| 695 | mPendingBuffersToWork.pop_front(); |
| 696 | } |
| 697 | } |
| 698 | |
| 699 | void C2VDAComponent::updateUndequeuedBlockIds(int32_t blockId) { |
| 700 | // The size of |mUndequedBlockIds| will always be the minimum buffer count for display. |
| 701 | mUndequeuedBlockIds.push_back(blockId); |
| 702 | mUndequeuedBlockIds.pop_front(); |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 703 | } |
| 704 | |
Johny Lin | 3760d5f | 2018-01-31 14:40:13 +0800 | [diff] [blame] | 705 | void C2VDAComponent::onDrain(uint32_t drainMode) { |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 706 | DCHECK(mTaskRunner->BelongsToCurrentThread()); |
Johny Lin | 3760d5f | 2018-01-31 14:40:13 +0800 | [diff] [blame] | 707 | ALOGV("onDrain: mode = %u", drainMode); |
| 708 | EXPECT_RUNNING_OR_RETURN_ON_ERROR(); |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 709 | |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 710 | if (!mQueue.empty()) { |
Johny Lin | 3760d5f | 2018-01-31 14:40:13 +0800 | [diff] [blame] | 711 | // Mark last queued work as "drain-till-here" by setting drainMode. Do not change drainMode |
| 712 | // if last work already has one. |
| 713 | if (mQueue.back().mDrainMode == NO_DRAIN) { |
| 714 | mQueue.back().mDrainMode = drainMode; |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 715 | } |
Johny Lin | 3760d5f | 2018-01-31 14:40:13 +0800 | [diff] [blame] | 716 | } else if (!mPendingWorks.empty()) { |
| 717 | // Neglect drain request if component is not in STARTED mode. Otherwise, enters DRAINING |
| 718 | // mode and signal VDA flush immediately. |
| 719 | if (mComponentState == ComponentState::STARTED) { |
| 720 | mVDAAdaptor->flush(); |
| 721 | mComponentState = ComponentState::DRAINING; |
Pin-chih Lin | 617d763 | 2018-05-30 16:48:07 +0800 | [diff] [blame] | 722 | mPendingOutputEOS = drainMode == DRAIN_COMPONENT_WITH_EOS; |
Johny Lin | 3760d5f | 2018-01-31 14:40:13 +0800 | [diff] [blame] | 723 | } else { |
| 724 | ALOGV("Neglect drain. Component in state: %d", mComponentState); |
| 725 | } |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 726 | } else { |
| 727 | // Do nothing. |
| 728 | ALOGV("No buffers in VDA, drain takes no effect."); |
| 729 | } |
| 730 | } |
| 731 | |
| 732 | void C2VDAComponent::onDrainDone() { |
| 733 | DCHECK(mTaskRunner->BelongsToCurrentThread()); |
| 734 | ALOGV("onDrainDone"); |
| 735 | if (mComponentState == ComponentState::DRAINING) { |
| 736 | mComponentState = ComponentState::STARTED; |
| 737 | } else if (mComponentState == ComponentState::STOPPING) { |
| 738 | // The client signals stop right before VDA notifies drain done. Let stop process goes. |
| 739 | return; |
Pin-chih Lin | 617d763 | 2018-05-30 16:48:07 +0800 | [diff] [blame] | 740 | } else if (mComponentState != ComponentState::FLUSHING) { |
| 741 | // It is reasonable to get onDrainDone in FLUSHING, which means flush is already signaled |
| 742 | // and component should still expect onFlushDone callback from VDA. |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 743 | ALOGE("Unexpected state while onDrainDone(). State=%d", mComponentState); |
| 744 | reportError(C2_BAD_STATE); |
| 745 | return; |
| 746 | } |
| 747 | |
Pin-chih Lin | 2dcfa1a | 2018-11-28 14:25:09 +0800 | [diff] [blame] | 748 | // Drop all pending existing frames and return all finished works before drain done. |
| 749 | sendOutputBufferToWorkIfAny(true /* dropIfUnavailable */); |
| 750 | CHECK(mPendingBuffersToWork.empty()); |
| 751 | |
Pin-chih Lin | 617d763 | 2018-05-30 16:48:07 +0800 | [diff] [blame] | 752 | if (mPendingOutputEOS) { |
Johny Lin | 3760d5f | 2018-01-31 14:40:13 +0800 | [diff] [blame] | 753 | // Return EOS work. |
| 754 | reportEOSWork(); |
| 755 | } |
| 756 | // mPendingWorks must be empty after draining is finished. |
| 757 | CHECK(mPendingWorks.empty()); |
| 758 | |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 759 | // Work dequeueing was stopped while component draining. Restart it. |
| 760 | mTaskRunner->PostTask(FROM_HERE, |
Pin-chih Lin | 448c0c7 | 2018-05-22 14:17:53 +0800 | [diff] [blame] | 761 | ::base::Bind(&C2VDAComponent::onDequeueWork, ::base::Unretained(this))); |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 762 | } |
| 763 | |
| 764 | void C2VDAComponent::onFlush() { |
| 765 | DCHECK(mTaskRunner->BelongsToCurrentThread()); |
| 766 | ALOGV("onFlush"); |
Pin-chih Lin | 617d763 | 2018-05-30 16:48:07 +0800 | [diff] [blame] | 767 | if (mComponentState == ComponentState::FLUSHING || |
| 768 | mComponentState == ComponentState::STOPPING) { |
| 769 | return; // Ignore other flush request when component is flushing or stopping. |
Pin-chih Lin | 2a00c24 | 2018-03-28 20:41:50 +0800 | [diff] [blame] | 770 | } |
Pin-chih Lin | 617d763 | 2018-05-30 16:48:07 +0800 | [diff] [blame] | 771 | EXPECT_RUNNING_OR_RETURN_ON_ERROR(); |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 772 | |
| 773 | mVDAAdaptor->reset(); |
Pin-chih Lin | 617d763 | 2018-05-30 16:48:07 +0800 | [diff] [blame] | 774 | // Pop all works in mQueue and put into mAbandonedWorks. |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 775 | while (!mQueue.empty()) { |
Pin-chih Lin | 617d763 | 2018-05-30 16:48:07 +0800 | [diff] [blame] | 776 | mAbandonedWorks.emplace_back(std::move(mQueue.front().mWork)); |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 777 | mQueue.pop(); |
| 778 | } |
| 779 | mComponentState = ComponentState::FLUSHING; |
| 780 | } |
| 781 | |
Pin-chih Lin | 448c0c7 | 2018-05-22 14:17:53 +0800 | [diff] [blame] | 782 | void C2VDAComponent::onStop(::base::WaitableEvent* done) { |
Johny Lin | 744cff1 | 2017-08-16 16:56:25 +0800 | [diff] [blame] | 783 | DCHECK(mTaskRunner->BelongsToCurrentThread()); |
| 784 | ALOGV("onStop"); |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 785 | EXPECT_RUNNING_OR_RETURN_ON_ERROR(); |
| 786 | |
Pin-chih Lin | a95fb65 | 2018-05-03 21:08:14 +0800 | [diff] [blame] | 787 | // Do not request VDA reset again before the previous one is done. If reset is already sent by |
| 788 | // onFlush(), just regard the following NotifyResetDone callback as for stopping. |
| 789 | if (mComponentState != ComponentState::FLUSHING) { |
| 790 | mVDAAdaptor->reset(); |
| 791 | } |
| 792 | |
Pin-chih Lin | 617d763 | 2018-05-30 16:48:07 +0800 | [diff] [blame] | 793 | // Pop all works in mQueue and put into mAbandonedWorks. |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 794 | while (!mQueue.empty()) { |
Pin-chih Lin | 617d763 | 2018-05-30 16:48:07 +0800 | [diff] [blame] | 795 | mAbandonedWorks.emplace_back(std::move(mQueue.front().mWork)); |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 796 | mQueue.pop(); |
| 797 | } |
| 798 | |
Johny Lin | 744cff1 | 2017-08-16 16:56:25 +0800 | [diff] [blame] | 799 | mStopDoneEvent = done; // restore done event which shoud be signaled in onStopDone(). |
| 800 | mComponentState = ComponentState::STOPPING; |
| 801 | } |
| 802 | |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 803 | void C2VDAComponent::onResetDone() { |
Johny Lin | 744cff1 | 2017-08-16 16:56:25 +0800 | [diff] [blame] | 804 | DCHECK(mTaskRunner->BelongsToCurrentThread()); |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 805 | if (mComponentState == ComponentState::ERROR) { |
| 806 | return; |
| 807 | } |
| 808 | if (mComponentState == ComponentState::FLUSHING) { |
| 809 | onFlushDone(); |
| 810 | } else if (mComponentState == ComponentState::STOPPING) { |
| 811 | onStopDone(); |
| 812 | } else { |
| 813 | reportError(C2_CORRUPTED); |
| 814 | } |
| 815 | } |
| 816 | |
| 817 | void C2VDAComponent::onFlushDone() { |
| 818 | ALOGV("onFlushDone"); |
| 819 | reportAbandonedWorks(); |
Pin-chih Lin | 2dcfa1a | 2018-11-28 14:25:09 +0800 | [diff] [blame] | 820 | mPendingBuffersToWork.clear(); |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 821 | mComponentState = ComponentState::STARTED; |
Pin-chih Lin | 29d50d9 | 2018-05-30 14:03:52 +0800 | [diff] [blame] | 822 | |
| 823 | // Work dequeueing was stopped while component flushing. Restart it. |
| 824 | mTaskRunner->PostTask(FROM_HERE, |
| 825 | ::base::Bind(&C2VDAComponent::onDequeueWork, ::base::Unretained(this))); |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 826 | } |
| 827 | |
| 828 | void C2VDAComponent::onStopDone() { |
Johny Lin | 744cff1 | 2017-08-16 16:56:25 +0800 | [diff] [blame] | 829 | ALOGV("onStopDone"); |
Johny Lin | 744cff1 | 2017-08-16 16:56:25 +0800 | [diff] [blame] | 830 | CHECK(mStopDoneEvent); |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 831 | |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 832 | // TODO(johnylin): At this moment, there may be C2Buffer still owned by client, do we need to |
| 833 | // do something for them? |
| 834 | reportAbandonedWorks(); |
| 835 | mPendingOutputFormat.reset(); |
Pin-chih Lin | 2dcfa1a | 2018-11-28 14:25:09 +0800 | [diff] [blame] | 836 | mPendingBuffersToWork.clear(); |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 837 | if (mVDAAdaptor.get()) { |
| 838 | mVDAAdaptor->destroy(); |
| 839 | mVDAAdaptor.reset(nullptr); |
| 840 | } |
| 841 | |
Pin-chih Lin | 906956a | 2018-05-22 14:12:59 +0800 | [diff] [blame] | 842 | stopDequeueThread(); |
Pin-chih Lin | 1a350e8 | 2018-09-21 14:17:40 +0800 | [diff] [blame] | 843 | mGraphicBlocks.clear(); |
Pin-chih Lin | 906956a | 2018-05-22 14:12:59 +0800 | [diff] [blame] | 844 | |
Johny Lin | 744cff1 | 2017-08-16 16:56:25 +0800 | [diff] [blame] | 845 | mStopDoneEvent->Signal(); |
| 846 | mStopDoneEvent = nullptr; |
| 847 | mComponentState = ComponentState::UNINITIALIZED; |
Johny Lin | 7c4cb52 | 2017-06-26 16:10:24 +0800 | [diff] [blame] | 848 | } |
| 849 | |
Johny Lin | a891f0e | 2017-12-19 10:25:27 +0800 | [diff] [blame] | 850 | c2_status_t C2VDAComponent::setListener_vb(const std::shared_ptr<C2Component::Listener>& listener, |
| 851 | c2_blocking_t mayBlock) { |
Lajos Molnar | 2737fb6 | 2017-12-19 09:46:42 -0800 | [diff] [blame] | 852 | UNUSED(mayBlock); |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 853 | // TODO(johnylin): API says this method must be supported in all states, however I'm quite not |
| 854 | // sure what is the use case. |
Pin-chih Lin | 2a00c24 | 2018-03-28 20:41:50 +0800 | [diff] [blame] | 855 | if (mState.load() != State::LOADED) { |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 856 | return C2_BAD_STATE; |
| 857 | } |
Lajos Molnar | b78444e | 2017-11-27 16:08:31 -0800 | [diff] [blame] | 858 | mListener = listener; |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 859 | return C2_OK; |
| 860 | } |
| 861 | |
| 862 | void C2VDAComponent::sendInputBufferToAccelerator(const C2ConstLinearBlock& input, |
| 863 | int32_t bitstreamId) { |
| 864 | ALOGV("sendInputBufferToAccelerator"); |
| 865 | int dupFd = dup(input.handle()->data[0]); |
| 866 | if (dupFd < 0) { |
Johny Lin | a891f0e | 2017-12-19 10:25:27 +0800 | [diff] [blame] | 867 | ALOGE("Failed to dup(%d) input buffer (bitstreamId=%d), errno=%d", input.handle()->data[0], |
| 868 | bitstreamId, errno); |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 869 | reportError(C2_CORRUPTED); |
| 870 | return; |
| 871 | } |
Johny Lin | a891f0e | 2017-12-19 10:25:27 +0800 | [diff] [blame] | 872 | ALOGV("Decode bitstream ID: %d, offset: %u size: %u", bitstreamId, input.offset(), |
| 873 | input.size()); |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 874 | mVDAAdaptor->decode(bitstreamId, dupFd, input.offset(), input.size()); |
| 875 | } |
| 876 | |
Pin-chih Lin | 2dcfa1a | 2018-11-28 14:25:09 +0800 | [diff] [blame] | 877 | std::deque<std::unique_ptr<C2Work>>::iterator C2VDAComponent::findPendingWorkByBitstreamId( |
| 878 | int32_t bitstreamId) { |
| 879 | return std::find_if(mPendingWorks.begin(), mPendingWorks.end(), |
| 880 | [bitstreamId](const std::unique_ptr<C2Work>& w) { |
| 881 | return frameIndexToBitstreamId(w->input.ordinal.frameIndex) == |
| 882 | bitstreamId; |
| 883 | }); |
| 884 | } |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 885 | |
Pin-chih Lin | 2dcfa1a | 2018-11-28 14:25:09 +0800 | [diff] [blame] | 886 | C2Work* C2VDAComponent::getPendingWorkByBitstreamId(int32_t bitstreamId) { |
| 887 | auto workIter = findPendingWorkByBitstreamId(bitstreamId); |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 888 | if (workIter == mPendingWorks.end()) { |
| 889 | ALOGE("Can't find pending work by bitstream ID: %d", bitstreamId); |
| 890 | return nullptr; |
| 891 | } |
| 892 | return workIter->get(); |
| 893 | } |
| 894 | |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 895 | C2VDAComponent::GraphicBlockInfo* C2VDAComponent::getGraphicBlockById(int32_t blockId) { |
Johny Lin | a891f0e | 2017-12-19 10:25:27 +0800 | [diff] [blame] | 896 | if (blockId < 0 || blockId >= static_cast<int32_t>(mGraphicBlocks.size())) { |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 897 | ALOGE("getGraphicBlockById failed: id=%d", blockId); |
| 898 | return nullptr; |
| 899 | } |
| 900 | return &mGraphicBlocks[blockId]; |
| 901 | } |
| 902 | |
Pin-chih Lin | 585324e | 2018-07-25 16:24:54 +0800 | [diff] [blame] | 903 | C2VDAComponent::GraphicBlockInfo* C2VDAComponent::getGraphicBlockByPoolId(uint32_t poolId) { |
Pin-chih Lin | 906956a | 2018-05-22 14:12:59 +0800 | [diff] [blame] | 904 | auto blockIter = std::find_if(mGraphicBlocks.begin(), mGraphicBlocks.end(), |
Pin-chih Lin | 585324e | 2018-07-25 16:24:54 +0800 | [diff] [blame] | 905 | [poolId](const GraphicBlockInfo& gb) { |
| 906 | return gb.mPoolId == poolId; |
Pin-chih Lin | 906956a | 2018-05-22 14:12:59 +0800 | [diff] [blame] | 907 | }); |
| 908 | |
| 909 | if (blockIter == mGraphicBlocks.end()) { |
Pin-chih Lin | 585324e | 2018-07-25 16:24:54 +0800 | [diff] [blame] | 910 | ALOGE("getGraphicBlockByPoolId failed: poolId=%u", poolId); |
Pin-chih Lin | 906956a | 2018-05-22 14:12:59 +0800 | [diff] [blame] | 911 | return nullptr; |
| 912 | } |
| 913 | return &(*blockIter); |
| 914 | } |
| 915 | |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 916 | void C2VDAComponent::onOutputFormatChanged(std::unique_ptr<VideoFormat> format) { |
| 917 | DCHECK(mTaskRunner->BelongsToCurrentThread()); |
| 918 | ALOGV("onOutputFormatChanged"); |
| 919 | EXPECT_RUNNING_OR_RETURN_ON_ERROR(); |
| 920 | |
| 921 | ALOGV("New output format(pixel_format=0x%x, min_num_buffers=%u, coded_size=%s, crop_rect=%s)", |
Johny Lin | ac6e270 | 2018-01-17 12:11:52 +0800 | [diff] [blame] | 922 | static_cast<uint32_t>(format->mPixelFormat), format->mMinNumBuffers, |
| 923 | format->mCodedSize.ToString().c_str(), format->mVisibleRect.ToString().c_str()); |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 924 | |
| 925 | for (auto& info : mGraphicBlocks) { |
| 926 | if (info.mState == GraphicBlockInfo::State::OWNED_BY_ACCELERATOR) |
| 927 | info.mState = GraphicBlockInfo::State::OWNED_BY_COMPONENT; |
| 928 | } |
| 929 | |
| 930 | CHECK(!mPendingOutputFormat); |
| 931 | mPendingOutputFormat = std::move(format); |
| 932 | tryChangeOutputFormat(); |
| 933 | } |
| 934 | |
| 935 | void C2VDAComponent::tryChangeOutputFormat() { |
| 936 | DCHECK(mTaskRunner->BelongsToCurrentThread()); |
| 937 | ALOGV("tryChangeOutputFormat"); |
| 938 | CHECK(mPendingOutputFormat); |
| 939 | |
Pin-chih Lin | 81a44bb | 2018-08-17 17:54:00 +0800 | [diff] [blame] | 940 | // At this point, all output buffers should not be owned by accelerator. The component is not |
| 941 | // able to know when a client will release all owned output buffers by now. But it is ok to |
| 942 | // leave them to client since componenet won't own those buffers anymore. |
| 943 | // TODO(johnylin): we may also set a parameter for component to keep dequeueing buffers and |
| 944 | // change format only after the component owns most buffers. This may prevent |
| 945 | // too many buffers are still on client's hand while component starts to |
| 946 | // allocate more buffers. However, it leads latency on output format change. |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 947 | for (const auto& info : mGraphicBlocks) { |
Pin-chih Lin | 81a44bb | 2018-08-17 17:54:00 +0800 | [diff] [blame] | 948 | CHECK(info.mState != GraphicBlockInfo::State::OWNED_BY_ACCELERATOR); |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 949 | } |
| 950 | |
Pin-chih Lin | 2dcfa1a | 2018-11-28 14:25:09 +0800 | [diff] [blame] | 951 | // Drop all pending existing frames and return all finished works before changing output format. |
| 952 | sendOutputBufferToWorkIfAny(true /* dropIfUnavailable */); |
| 953 | CHECK(mPendingBuffersToWork.empty()); |
| 954 | |
Johny Lin | ac6e270 | 2018-01-17 12:11:52 +0800 | [diff] [blame] | 955 | CHECK_EQ(mPendingOutputFormat->mPixelFormat, HalPixelFormat::YCbCr_420_888); |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 956 | |
| 957 | mOutputFormat.mPixelFormat = mPendingOutputFormat->mPixelFormat; |
| 958 | mOutputFormat.mMinNumBuffers = mPendingOutputFormat->mMinNumBuffers; |
| 959 | mOutputFormat.mCodedSize = mPendingOutputFormat->mCodedSize; |
| 960 | |
| 961 | setOutputFormatCrop(mPendingOutputFormat->mVisibleRect); |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 962 | |
Johny Lin | ac6e270 | 2018-01-17 12:11:52 +0800 | [diff] [blame] | 963 | c2_status_t err = allocateBuffersFromBlockAllocator( |
| 964 | mPendingOutputFormat->mCodedSize, |
| 965 | static_cast<uint32_t>(mPendingOutputFormat->mPixelFormat)); |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 966 | if (err != C2_OK) { |
| 967 | reportError(err); |
| 968 | return; |
| 969 | } |
| 970 | |
| 971 | for (auto& info : mGraphicBlocks) { |
Pin-chih Lin | 2dcfa1a | 2018-11-28 14:25:09 +0800 | [diff] [blame] | 972 | sendOutputBufferToAccelerator(&info, true /* ownByAccelerator */); |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 973 | } |
| 974 | mPendingOutputFormat.reset(); |
| 975 | } |
| 976 | |
| 977 | c2_status_t C2VDAComponent::allocateBuffersFromBlockAllocator(const media::Size& size, |
Johny Lin | ac6e270 | 2018-01-17 12:11:52 +0800 | [diff] [blame] | 978 | uint32_t pixelFormat) { |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 979 | ALOGV("allocateBuffersFromBlockAllocator(%s, 0x%x)", size.ToString().c_str(), pixelFormat); |
| 980 | |
Pin-chih Lin | 62585f0 | 2018-05-29 21:00:03 +0800 | [diff] [blame] | 981 | stopDequeueThread(); |
| 982 | |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 983 | size_t bufferCount = mOutputFormat.mMinNumBuffers + kDpbOutputBufferExtraCount; |
| 984 | |
| 985 | // Allocate the output buffers. |
| 986 | mVDAAdaptor->assignPictureBuffers(bufferCount); |
| 987 | |
Pin-chih Lin | 2fea071 | 2018-05-14 19:57:14 +0800 | [diff] [blame] | 988 | // Get block pool ID configured from the client. |
Pin-chih Lin | 62585f0 | 2018-05-29 21:00:03 +0800 | [diff] [blame] | 989 | std::shared_ptr<C2BlockPool> blockPool; |
Pin-chih Lin | 2fea071 | 2018-05-14 19:57:14 +0800 | [diff] [blame] | 990 | auto poolId = mIntfImpl->getBlockPoolId(); |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 991 | ALOGI("Using C2BlockPool ID = %" PRIu64 " for allocating output buffers", poolId); |
Pin-chih Lin | 62585f0 | 2018-05-29 21:00:03 +0800 | [diff] [blame] | 992 | auto err = GetCodec2BlockPool(poolId, shared_from_this(), &blockPool); |
| 993 | if (err != C2_OK) { |
| 994 | ALOGE("Graphic block allocator is invalid"); |
| 995 | reportError(err); |
| 996 | return err; |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 997 | } |
| 998 | |
| 999 | mGraphicBlocks.clear(); |
Pin-chih Lin | 906956a | 2018-05-22 14:12:59 +0800 | [diff] [blame] | 1000 | |
Pin-chih Lin | 585324e | 2018-07-25 16:24:54 +0800 | [diff] [blame] | 1001 | bool useBufferQueue = blockPool->getAllocatorId() == C2PlatformAllocatorStore::BUFFERQUEUE; |
Pin-chih Lin | 2dcfa1a | 2018-11-28 14:25:09 +0800 | [diff] [blame] | 1002 | size_t minBuffersForDisplay = 0; |
Pin-chih Lin | 585324e | 2018-07-25 16:24:54 +0800 | [diff] [blame] | 1003 | if (useBufferQueue) { |
| 1004 | ALOGV("Bufferqueue-backed block pool is used."); |
Pin-chih Lin | 5ab2613 | 2018-05-09 22:25:19 +0800 | [diff] [blame] | 1005 | // Set requested buffer count to C2VdaBqBlockPool. |
| 1006 | std::shared_ptr<C2VdaBqBlockPool> bqPool = |
Pin-chih Lin | 62585f0 | 2018-05-29 21:00:03 +0800 | [diff] [blame] | 1007 | std::static_pointer_cast<C2VdaBqBlockPool>(blockPool); |
Pin-chih Lin | 5ab2613 | 2018-05-09 22:25:19 +0800 | [diff] [blame] | 1008 | if (bqPool) { |
| 1009 | err = bqPool->requestNewBufferSet(static_cast<int32_t>(bufferCount)); |
Pin-chih Lin | 585324e | 2018-07-25 16:24:54 +0800 | [diff] [blame] | 1010 | if (err != C2_OK) { |
| 1011 | ALOGE("failed to request new buffer set to block pool: %d", err); |
Pin-chih Lin | 5ab2613 | 2018-05-09 22:25:19 +0800 | [diff] [blame] | 1012 | reportError(err); |
| 1013 | return err; |
| 1014 | } |
Pin-chih Lin | 2dcfa1a | 2018-11-28 14:25:09 +0800 | [diff] [blame] | 1015 | err = bqPool->getMinBuffersForDisplay(&minBuffersForDisplay); |
| 1016 | if (err != C2_OK) { |
| 1017 | ALOGE("failed to query minimum undequeued buffer count from block pool: %d", err); |
| 1018 | reportError(err); |
| 1019 | return err; |
| 1020 | } |
Pin-chih Lin | 5ab2613 | 2018-05-09 22:25:19 +0800 | [diff] [blame] | 1021 | } else { |
| 1022 | ALOGE("static_pointer_cast C2VdaBqBlockPool failed..."); |
| 1023 | reportError(C2_CORRUPTED); |
| 1024 | return C2_CORRUPTED; |
Pin-chih Lin | 906956a | 2018-05-22 14:12:59 +0800 | [diff] [blame] | 1025 | } |
Pin-chih Lin | 585324e | 2018-07-25 16:24:54 +0800 | [diff] [blame] | 1026 | } else { |
| 1027 | ALOGV("Bufferpool-backed block pool is used."); |
| 1028 | // Set requested buffer count to C2VdaPooledBlockPool. |
| 1029 | std::shared_ptr<C2VdaPooledBlockPool> bpPool = |
| 1030 | std::static_pointer_cast<C2VdaPooledBlockPool>(blockPool); |
| 1031 | if (bpPool) { |
| 1032 | err = bpPool->requestNewBufferSet(static_cast<int32_t>(bufferCount)); |
| 1033 | if (err != C2_OK) { |
| 1034 | ALOGE("failed to request new buffer set to block pool: %d", err); |
| 1035 | reportError(err); |
| 1036 | return err; |
| 1037 | } |
Pin-chih Lin | 2dcfa1a | 2018-11-28 14:25:09 +0800 | [diff] [blame] | 1038 | minBuffersForDisplay = 0; // no undequeued buffer restriction for bufferpool. |
Pin-chih Lin | 585324e | 2018-07-25 16:24:54 +0800 | [diff] [blame] | 1039 | } else { |
| 1040 | ALOGE("static_pointer_cast C2VdaPooledBlockPool failed..."); |
| 1041 | reportError(C2_CORRUPTED); |
| 1042 | return C2_CORRUPTED; |
| 1043 | } |
Pin-chih Lin | 906956a | 2018-05-22 14:12:59 +0800 | [diff] [blame] | 1044 | } |
| 1045 | |
Pin-chih Lin | 2dcfa1a | 2018-11-28 14:25:09 +0800 | [diff] [blame] | 1046 | ALOGV("Minimum undequeued buffer count = %zu", minBuffersForDisplay); |
| 1047 | mUndequeuedBlockIds.resize(minBuffersForDisplay, -1); |
| 1048 | |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 1049 | for (size_t i = 0; i < bufferCount; ++i) { |
| 1050 | std::shared_ptr<C2GraphicBlock> block; |
Hirokazu Honda | 3f3c8a4 | 2018-05-09 22:25:19 +0800 | [diff] [blame] | 1051 | C2MemoryUsage usage = { |
| 1052 | mSecureMode ? C2MemoryUsage::READ_PROTECTED : C2MemoryUsage::CPU_READ, 0}; |
Pin-chih Lin | 81a44bb | 2018-08-17 17:54:00 +0800 | [diff] [blame] | 1053 | |
| 1054 | int32_t retries_left = kAllocateBufferMaxRetries; |
| 1055 | err = C2_NO_INIT; |
| 1056 | while (err != C2_OK) { |
| 1057 | err = blockPool->fetchGraphicBlock(size.width(), size.height(), pixelFormat, usage, |
| 1058 | &block); |
| 1059 | if (err == C2_TIMED_OUT && retries_left > 0) { |
| 1060 | ALOGD("allocate buffer timeout, %d retry time(s) left...", retries_left); |
| 1061 | retries_left--; |
| 1062 | } else if (err != C2_OK) { |
| 1063 | mGraphicBlocks.clear(); |
| 1064 | ALOGE("failed to allocate buffer: %d", err); |
| 1065 | reportError(err); |
| 1066 | return err; |
| 1067 | } |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 1068 | } |
Pin-chih Lin | 81a44bb | 2018-08-17 17:54:00 +0800 | [diff] [blame] | 1069 | |
Pin-chih Lin | 585324e | 2018-07-25 16:24:54 +0800 | [diff] [blame] | 1070 | uint32_t poolId; |
| 1071 | if (useBufferQueue) { |
| 1072 | err = C2VdaBqBlockPool::getPoolIdFromGraphicBlock(block, &poolId); |
| 1073 | } else { // use bufferpool |
| 1074 | err = C2VdaPooledBlockPool::getPoolIdFromGraphicBlock(block, &poolId); |
| 1075 | } |
| 1076 | if (err != C2_OK) { |
| 1077 | mGraphicBlocks.clear(); |
| 1078 | ALOGE("failed to getPoolIdFromGraphicBlock: %d", err); |
| 1079 | reportError(err); |
| 1080 | return err; |
| 1081 | } |
Hirokazu Honda | 3f3c8a4 | 2018-05-09 22:25:19 +0800 | [diff] [blame] | 1082 | if (mSecureMode) { |
| 1083 | appendSecureOutputBuffer(std::move(block), poolId); |
| 1084 | } else { |
| 1085 | appendOutputBuffer(std::move(block), poolId); |
| 1086 | } |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 1087 | } |
| 1088 | mOutputFormat.mMinNumBuffers = bufferCount; |
Pin-chih Lin | 906956a | 2018-05-22 14:12:59 +0800 | [diff] [blame] | 1089 | |
Pin-chih Lin | 02faf85 | 2018-10-24 14:20:53 +0800 | [diff] [blame] | 1090 | if (!startDequeueThread(size, pixelFormat, std::move(blockPool), |
| 1091 | true /* resetBuffersInClient */)) { |
Pin-chih Lin | 906956a | 2018-05-22 14:12:59 +0800 | [diff] [blame] | 1092 | reportError(C2_CORRUPTED); |
| 1093 | return C2_CORRUPTED; |
| 1094 | } |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 1095 | return C2_OK; |
| 1096 | } |
| 1097 | |
Pin-chih Lin | 585324e | 2018-07-25 16:24:54 +0800 | [diff] [blame] | 1098 | void C2VDAComponent::appendOutputBuffer(std::shared_ptr<C2GraphicBlock> block, uint32_t poolId) { |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 1099 | GraphicBlockInfo info; |
Johny Lin | 8a2118e | 2018-02-08 16:29:25 +0800 | [diff] [blame] | 1100 | info.mBlockId = static_cast<int32_t>(mGraphicBlocks.size()); |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 1101 | info.mGraphicBlock = std::move(block); |
Pin-chih Lin | 585324e | 2018-07-25 16:24:54 +0800 | [diff] [blame] | 1102 | info.mPoolId = poolId; |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 1103 | |
Johny Lin | 727e957 | 2018-01-24 21:04:06 +0800 | [diff] [blame] | 1104 | C2ConstGraphicBlock constBlock = info.mGraphicBlock->share( |
| 1105 | C2Rect(info.mGraphicBlock->width(), info.mGraphicBlock->height()), C2Fence()); |
| 1106 | |
| 1107 | const C2GraphicView& view = constBlock.map().get(); |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 1108 | const uint8_t* const* data = view.data(); |
| 1109 | CHECK_NE(data, nullptr); |
Lajos Molnar | a0c6bbd | 2018-01-03 12:53:15 -0800 | [diff] [blame] | 1110 | const C2PlanarLayout& layout = view.layout(); |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 1111 | |
Johny Lin | 8a2118e | 2018-02-08 16:29:25 +0800 | [diff] [blame] | 1112 | ALOGV("allocate graphic buffer: %p, id: %d, size: %dx%d", info.mGraphicBlock->handle(), |
Johny Lin | a891f0e | 2017-12-19 10:25:27 +0800 | [diff] [blame] | 1113 | info.mBlockId, info.mGraphicBlock->width(), info.mGraphicBlock->height()); |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 1114 | |
| 1115 | // get offset from data pointers |
Lajos Molnar | a0c6bbd | 2018-01-03 12:53:15 -0800 | [diff] [blame] | 1116 | uint32_t offsets[C2PlanarLayout::MAX_NUM_PLANES]; |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 1117 | auto baseAddress = reinterpret_cast<intptr_t>(data[0]); |
Lajos Molnar | a0c6bbd | 2018-01-03 12:53:15 -0800 | [diff] [blame] | 1118 | for (uint32_t i = 0; i < layout.numPlanes; ++i) { |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 1119 | auto planeAddress = reinterpret_cast<intptr_t>(data[i]); |
| 1120 | offsets[i] = static_cast<uint32_t>(planeAddress - baseAddress); |
| 1121 | } |
| 1122 | |
Johny Lin | ac6e270 | 2018-01-17 12:11:52 +0800 | [diff] [blame] | 1123 | bool crcb = false; |
Johny Lin | 3a3eb60 | 2018-01-03 16:46:13 +0800 | [diff] [blame] | 1124 | if (layout.numPlanes == 3 && |
| 1125 | offsets[C2PlanarLayout::PLANE_U] > offsets[C2PlanarLayout::PLANE_V]) { |
| 1126 | // YCrCb format |
| 1127 | std::swap(offsets[C2PlanarLayout::PLANE_U], offsets[C2PlanarLayout::PLANE_V]); |
Johny Lin | ac6e270 | 2018-01-17 12:11:52 +0800 | [diff] [blame] | 1128 | crcb = true; |
Johny Lin | 3a3eb60 | 2018-01-03 16:46:13 +0800 | [diff] [blame] | 1129 | } |
| 1130 | |
Johny Lin | ac6e270 | 2018-01-17 12:11:52 +0800 | [diff] [blame] | 1131 | bool semiplanar = false; |
Johny Lin | 3a3eb60 | 2018-01-03 16:46:13 +0800 | [diff] [blame] | 1132 | uint32_t passedNumPlanes = layout.numPlanes; |
| 1133 | if (layout.planes[C2PlanarLayout::PLANE_U].colInc == 2) { // chroma_step |
| 1134 | // Semi-planar format |
| 1135 | passedNumPlanes--; |
Johny Lin | ac6e270 | 2018-01-17 12:11:52 +0800 | [diff] [blame] | 1136 | semiplanar = true; |
Johny Lin | 3a3eb60 | 2018-01-03 16:46:13 +0800 | [diff] [blame] | 1137 | } |
| 1138 | |
| 1139 | for (uint32_t i = 0; i < passedNumPlanes; ++i) { |
Lajos Molnar | a0c6bbd | 2018-01-03 12:53:15 -0800 | [diff] [blame] | 1140 | ALOGV("plane %u: stride: %d, offset: %u", i, layout.planes[i].rowInc, offsets[i]); |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 1141 | } |
Hirokazu Honda | ca17a06 | 2018-07-31 10:48:56 +0900 | [diff] [blame] | 1142 | info.mPixelFormat = resolveBufferFormat(crcb, semiplanar); |
Johny Lin | ac6e270 | 2018-01-17 12:11:52 +0800 | [diff] [blame] | 1143 | ALOGV("HAL pixel format: 0x%x", static_cast<uint32_t>(info.mPixelFormat)); |
| 1144 | |
Pin-chih Lin | 448c0c7 | 2018-05-22 14:17:53 +0800 | [diff] [blame] | 1145 | ::base::ScopedFD passedHandle(dup(info.mGraphicBlock->handle()->data[0])); |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 1146 | if (!passedHandle.is_valid()) { |
| 1147 | ALOGE("Failed to dup(%d), errno=%d", info.mGraphicBlock->handle()->data[0], errno); |
| 1148 | reportError(C2_CORRUPTED); |
| 1149 | return; |
| 1150 | } |
| 1151 | std::vector<VideoFramePlane> passedPlanes; |
Johny Lin | 3a3eb60 | 2018-01-03 16:46:13 +0800 | [diff] [blame] | 1152 | for (uint32_t i = 0; i < passedNumPlanes; ++i) { |
Lajos Molnar | a0c6bbd | 2018-01-03 12:53:15 -0800 | [diff] [blame] | 1153 | CHECK_GT(layout.planes[i].rowInc, 0); |
| 1154 | passedPlanes.push_back({offsets[i], static_cast<uint32_t>(layout.planes[i].rowInc)}); |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 1155 | } |
| 1156 | info.mHandle = std::move(passedHandle); |
| 1157 | info.mPlanes = std::move(passedPlanes); |
| 1158 | |
| 1159 | mGraphicBlocks.push_back(std::move(info)); |
| 1160 | } |
| 1161 | |
Hirokazu Honda | 3f3c8a4 | 2018-05-09 22:25:19 +0800 | [diff] [blame] | 1162 | void C2VDAComponent::appendSecureOutputBuffer(std::shared_ptr<C2GraphicBlock> block, |
| 1163 | uint32_t poolId) { |
| 1164 | #ifdef V4L2_CODEC2_ARC |
| 1165 | const C2Handle* const handle = block->handle(); |
| 1166 | const int handleFd = handle->data[0]; |
| 1167 | ::base::ScopedFD passedHandle(dup(handleFd)); |
| 1168 | if (!passedHandle.is_valid()) { |
| 1169 | ALOGE("Failed to dup(%d), errno=%d", handleFd, errno); |
| 1170 | reportError(C2_CORRUPTED); |
| 1171 | return; |
| 1172 | } |
| 1173 | |
Hirokazu Honda | ca17a06 | 2018-07-31 10:48:56 +0900 | [diff] [blame] | 1174 | android::HalPixelFormat pixelFormat = getPlatformPixelFormat(); |
| 1175 | if (pixelFormat == android::HalPixelFormat::UNKNOWN) { |
| 1176 | ALOGE("Failed to get pixel format on platform."); |
| 1177 | reportError(C2_CORRUPTED); |
| 1178 | return; |
| 1179 | } |
| 1180 | CHECK(pixelFormat == android::HalPixelFormat::YV12 || |
| 1181 | pixelFormat == android::HalPixelFormat::NV12); |
Hirokazu Honda | 3f3c8a4 | 2018-05-09 22:25:19 +0800 | [diff] [blame] | 1182 | ALOGV("HAL pixel format: 0x%x", static_cast<uint32_t>(pixelFormat)); |
| 1183 | |
| 1184 | GraphicBlockInfo info; |
| 1185 | info.mBlockId = static_cast<int32_t>(mGraphicBlocks.size()); |
| 1186 | info.mGraphicBlock = std::move(block); |
| 1187 | info.mPoolId = poolId; |
| 1188 | info.mHandle = std::move(passedHandle); |
| 1189 | info.mPixelFormat = pixelFormat; |
| 1190 | // In secure mode, since planes are not referred in Chrome side, empty plane is valid. |
| 1191 | info.mPlanes.clear(); |
| 1192 | mGraphicBlocks.push_back(std::move(info)); |
| 1193 | #else |
| 1194 | ALOGE("appendSecureOutputBuffer() is not supported..."); |
| 1195 | reportError(C2_OMITTED); |
| 1196 | #endif // V4L2_CODEC2_ARC |
| 1197 | } |
| 1198 | |
Pin-chih Lin | 2dcfa1a | 2018-11-28 14:25:09 +0800 | [diff] [blame] | 1199 | void C2VDAComponent::sendOutputBufferToAccelerator(GraphicBlockInfo* info, bool ownByAccelerator) { |
| 1200 | DCHECK(mTaskRunner->BelongsToCurrentThread()); |
| 1201 | ALOGV("sendOutputBufferToAccelerator index=%d ownByAccelerator=%d", info->mBlockId, |
| 1202 | ownByAccelerator); |
| 1203 | |
| 1204 | if (ownByAccelerator) { |
| 1205 | CHECK_EQ(info->mState, GraphicBlockInfo::State::OWNED_BY_COMPONENT); |
| 1206 | info->mState = GraphicBlockInfo::State::OWNED_BY_ACCELERATOR; |
| 1207 | } |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 1208 | |
| 1209 | // is_valid() is true for the first time the buffer is passed to VDA. In that case, VDA needs to |
| 1210 | // import the buffer first. |
| 1211 | if (info->mHandle.is_valid()) { |
Johny Lin | ac6e270 | 2018-01-17 12:11:52 +0800 | [diff] [blame] | 1212 | mVDAAdaptor->importBufferForPicture(info->mBlockId, info->mPixelFormat, |
| 1213 | info->mHandle.release(), info->mPlanes); |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 1214 | } else { |
| 1215 | mVDAAdaptor->reusePictureBuffer(info->mBlockId); |
| 1216 | } |
| 1217 | } |
| 1218 | |
Pin-chih Lin | 3aff30b | 2018-10-02 21:11:01 +0800 | [diff] [blame] | 1219 | bool C2VDAComponent::parseCodedColorAspects(const C2ConstLinearBlock& input) { |
| 1220 | C2ReadView view = input.map().get(); |
| 1221 | const uint8_t* data = view.data(); |
| 1222 | const uint32_t size = view.capacity(); |
| 1223 | |
| 1224 | std::unique_ptr<media::H264Parser> h264Parser = std::make_unique<media::H264Parser>(); |
| 1225 | h264Parser->SetStream(data, static_cast<off_t>(size)); |
| 1226 | media::H264NALU nalu; |
| 1227 | media::H264Parser::Result parRes = h264Parser->AdvanceToNextNALU(&nalu); |
| 1228 | if (parRes != media::H264Parser::kEOStream && parRes != media::H264Parser::kOk) { |
| 1229 | ALOGE("H264 AdvanceToNextNALU error: %d", static_cast<int>(parRes)); |
| 1230 | return false; |
| 1231 | } |
| 1232 | if (nalu.nal_unit_type != media::H264NALU::kSPS) { |
| 1233 | ALOGV("NALU is not SPS"); |
| 1234 | return false; |
| 1235 | } |
| 1236 | |
| 1237 | int spsId; |
| 1238 | parRes = h264Parser->ParseSPS(&spsId); |
| 1239 | if (parRes != media::H264Parser::kEOStream && parRes != media::H264Parser::kOk) { |
| 1240 | ALOGE("H264 ParseSPS error: %d", static_cast<int>(parRes)); |
| 1241 | return false; |
| 1242 | } |
| 1243 | |
| 1244 | // Parse ISO color aspects from H264 SPS bitstream. |
| 1245 | const media::H264SPS* sps = h264Parser->GetSPS(spsId); |
| 1246 | if (!sps->colour_description_present_flag) { |
| 1247 | ALOGV("No Color Description in SPS"); |
| 1248 | return false; |
| 1249 | } |
| 1250 | int32_t primaries = sps->colour_primaries; |
| 1251 | int32_t transfer = sps->transfer_characteristics; |
| 1252 | int32_t coeffs = sps->matrix_coefficients; |
| 1253 | bool fullRange = sps->video_full_range_flag; |
| 1254 | |
| 1255 | // Convert ISO color aspects to ColorUtils::ColorAspects. |
| 1256 | ColorAspects colorAspects; |
| 1257 | ColorUtils::convertIsoColorAspectsToCodecAspects(primaries, transfer, coeffs, fullRange, |
| 1258 | colorAspects); |
| 1259 | ALOGV("Parsed ColorAspects from bitstream: (R:%d, P:%d, M:%d, T:%d)", colorAspects.mRange, |
| 1260 | colorAspects.mPrimaries, colorAspects.mMatrixCoeffs, colorAspects.mTransfer); |
| 1261 | |
| 1262 | // Map ColorUtils::ColorAspects to C2StreamColorAspectsInfo::input parameter. |
| 1263 | C2StreamColorAspectsInfo::input codedAspects = {0u}; |
| 1264 | if (!C2Mapper::map(colorAspects.mPrimaries, &codedAspects.primaries)) { |
| 1265 | codedAspects.primaries = C2Color::PRIMARIES_UNSPECIFIED; |
| 1266 | } |
| 1267 | if (!C2Mapper::map(colorAspects.mRange, &codedAspects.range)) { |
| 1268 | codedAspects.range = C2Color::RANGE_UNSPECIFIED; |
| 1269 | } |
| 1270 | if (!C2Mapper::map(colorAspects.mMatrixCoeffs, &codedAspects.matrix)) { |
| 1271 | codedAspects.matrix = C2Color::MATRIX_UNSPECIFIED; |
| 1272 | } |
| 1273 | if (!C2Mapper::map(colorAspects.mTransfer, &codedAspects.transfer)) { |
| 1274 | codedAspects.transfer = C2Color::TRANSFER_UNSPECIFIED; |
| 1275 | } |
| 1276 | // Configure to interface. |
| 1277 | std::vector<std::unique_ptr<C2SettingResult>> failures; |
| 1278 | c2_status_t status = mIntfImpl->config({&codedAspects}, C2_MAY_BLOCK, &failures); |
| 1279 | if (status != C2_OK) { |
| 1280 | ALOGE("Failed to config color aspects to interface, error: %d", status); |
| 1281 | return false; |
| 1282 | } |
| 1283 | return true; |
| 1284 | } |
| 1285 | |
| 1286 | c2_status_t C2VDAComponent::updateColorAspects() { |
| 1287 | ALOGV("updateColorAspects"); |
| 1288 | std::unique_ptr<C2StreamColorAspectsInfo::output> colorAspects = |
| 1289 | std::make_unique<C2StreamColorAspectsInfo::output>( |
| 1290 | 0u, C2Color::RANGE_UNSPECIFIED, C2Color::PRIMARIES_UNSPECIFIED, |
| 1291 | C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED); |
| 1292 | c2_status_t status = mIntfImpl->query({colorAspects.get()}, {}, C2_DONT_BLOCK, nullptr); |
| 1293 | if (status != C2_OK) { |
| 1294 | ALOGE("Failed to query color aspects, error: %d", status); |
| 1295 | return status; |
| 1296 | } |
| 1297 | mCurrentColorAspects = std::move(colorAspects); |
| 1298 | return C2_OK; |
| 1299 | } |
| 1300 | |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 1301 | void C2VDAComponent::onVisibleRectChanged(const media::Rect& cropRect) { |
| 1302 | DCHECK(mTaskRunner->BelongsToCurrentThread()); |
| 1303 | ALOGV("onVisibleRectChanged"); |
| 1304 | EXPECT_RUNNING_OR_RETURN_ON_ERROR(); |
| 1305 | |
| 1306 | // We should make sure there is no pending output format change. That is, the input cropRect is |
| 1307 | // corresponding to current output format. |
| 1308 | CHECK(mPendingOutputFormat == nullptr); |
| 1309 | setOutputFormatCrop(cropRect); |
| 1310 | } |
| 1311 | |
| 1312 | void C2VDAComponent::setOutputFormatCrop(const media::Rect& cropRect) { |
| 1313 | ALOGV("setOutputFormatCrop(%dx%d)", cropRect.width(), cropRect.height()); |
Pin-chih Lin | 8c97420 | 2018-04-12 16:47:41 +0800 | [diff] [blame] | 1314 | // This visible rect should be set as crop window for each C2ConstGraphicBlock passed to |
| 1315 | // framework. |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 1316 | mOutputFormat.mVisibleRect = cropRect; |
Lajos Molnar | b78444e | 2017-11-27 16:08:31 -0800 | [diff] [blame] | 1317 | } |
| 1318 | |
Pin-chih Lin | 02faf85 | 2018-10-24 14:20:53 +0800 | [diff] [blame] | 1319 | void C2VDAComponent::onSurfaceChanged() { |
| 1320 | DCHECK(mTaskRunner->BelongsToCurrentThread()); |
| 1321 | ALOGV("onSurfaceChanged"); |
| 1322 | |
| 1323 | if (mComponentState == ComponentState::UNINITIALIZED) { |
| 1324 | return; // Component is already stopped, no need to update graphic blocks. |
| 1325 | } |
| 1326 | |
| 1327 | stopDequeueThread(); |
| 1328 | |
| 1329 | // Get block pool ID configured from the client. |
| 1330 | std::shared_ptr<C2BlockPool> blockPool; |
| 1331 | auto blockPoolId = mIntfImpl->getBlockPoolId(); |
| 1332 | ALOGI("Retrieving C2BlockPool ID = %" PRIu64 " for updating output buffers", blockPoolId); |
| 1333 | auto err = GetCodec2BlockPool(blockPoolId, shared_from_this(), &blockPool); |
| 1334 | if (err != C2_OK) { |
| 1335 | ALOGE("Graphic block allocator is invalid"); |
| 1336 | reportError(err); |
| 1337 | return; |
| 1338 | } |
| 1339 | if (blockPool->getAllocatorId() != C2PlatformAllocatorStore::BUFFERQUEUE) { |
| 1340 | ALOGE("Only Bufferqueue-backed block pool would need to change surface."); |
| 1341 | reportError(C2_CORRUPTED); |
| 1342 | return; |
| 1343 | } |
| 1344 | |
| 1345 | std::shared_ptr<C2VdaBqBlockPool> bqPool = |
| 1346 | std::static_pointer_cast<C2VdaBqBlockPool>(blockPool); |
| 1347 | if (!bqPool) { |
| 1348 | ALOGE("static_pointer_cast C2VdaBqBlockPool failed..."); |
| 1349 | reportError(C2_CORRUPTED); |
| 1350 | return; |
| 1351 | } |
| 1352 | |
Pin-chih Lin | 2dcfa1a | 2018-11-28 14:25:09 +0800 | [diff] [blame] | 1353 | size_t minBuffersForDisplay = 0; |
| 1354 | err = bqPool->getMinBuffersForDisplay(&minBuffersForDisplay); |
| 1355 | if (err != C2_OK) { |
| 1356 | ALOGE("failed to query minimum undequeued buffer count from block pool: %d", err); |
| 1357 | reportError(err); |
| 1358 | return; |
| 1359 | } |
| 1360 | ALOGV("Minimum undequeued buffer count = %zu", minBuffersForDisplay); |
| 1361 | mUndequeuedBlockIds.resize(minBuffersForDisplay, -1); |
| 1362 | |
Pin-chih Lin | 02faf85 | 2018-10-24 14:20:53 +0800 | [diff] [blame] | 1363 | for (auto& info : mGraphicBlocks) { |
| 1364 | bool willCancel = (info.mGraphicBlock == nullptr); |
| 1365 | uint32_t oldSlot = info.mPoolId; |
| 1366 | ALOGV("Updating graphic block #%d: slot = %u, willCancel = %d", info.mBlockId, oldSlot, |
| 1367 | willCancel); |
| 1368 | uint32_t newSlot; |
| 1369 | std::shared_ptr<C2GraphicBlock> block; |
| 1370 | err = bqPool->updateGraphicBlock(willCancel, oldSlot, &newSlot, &block); |
| 1371 | if (err == C2_CANCELED) { |
| 1372 | // There may be a chance that a task in task runner before onSurfaceChange triggers |
| 1373 | // output format change. If so, block pool will return C2_CANCELED and no need to |
| 1374 | // updateGraphicBlock anymore. |
| 1375 | return; |
| 1376 | } |
| 1377 | if (err != C2_OK) { |
| 1378 | ALOGE("failed to update graphic block from block pool: %d", err); |
| 1379 | reportError(err); |
| 1380 | return; |
| 1381 | } |
| 1382 | |
| 1383 | // Update slot index. |
| 1384 | info.mPoolId = newSlot; |
| 1385 | // Update C2GraphicBlock if |willCancel| is false. Note that although the old C2GraphicBlock |
| 1386 | // will be released, the block pool data destructor won't do detachBuffer to new surface |
| 1387 | // because the producer ID is not matched. |
| 1388 | if (!willCancel) { |
| 1389 | info.mGraphicBlock = std::move(block); |
| 1390 | } |
| 1391 | } |
| 1392 | |
| 1393 | if (!startDequeueThread(mOutputFormat.mCodedSize, |
| 1394 | static_cast<uint32_t>(mOutputFormat.mPixelFormat), std::move(blockPool), |
| 1395 | false /* resetBuffersInClient */)) { |
| 1396 | reportError(C2_CORRUPTED); |
| 1397 | } |
| 1398 | } |
| 1399 | |
Lajos Molnar | b78444e | 2017-11-27 16:08:31 -0800 | [diff] [blame] | 1400 | c2_status_t C2VDAComponent::queue_nb(std::list<std::unique_ptr<C2Work>>* const items) { |
Pin-chih Lin | 2a00c24 | 2018-03-28 20:41:50 +0800 | [diff] [blame] | 1401 | if (mState.load() != State::RUNNING) { |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 1402 | return C2_BAD_STATE; |
| 1403 | } |
| 1404 | while (!items->empty()) { |
Johny Lin | a891f0e | 2017-12-19 10:25:27 +0800 | [diff] [blame] | 1405 | mTaskRunner->PostTask(FROM_HERE, |
Pin-chih Lin | 448c0c7 | 2018-05-22 14:17:53 +0800 | [diff] [blame] | 1406 | ::base::Bind(&C2VDAComponent::onQueueWork, ::base::Unretained(this), |
| 1407 | ::base::Passed(&items->front()))); |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 1408 | items->pop_front(); |
| 1409 | } |
| 1410 | return C2_OK; |
Johny Lin | 7c4cb52 | 2017-06-26 16:10:24 +0800 | [diff] [blame] | 1411 | } |
| 1412 | |
Lajos Molnar | b78444e | 2017-11-27 16:08:31 -0800 | [diff] [blame] | 1413 | c2_status_t C2VDAComponent::announce_nb(const std::vector<C2WorkOutline>& items) { |
Johny Lin | 7c4cb52 | 2017-06-26 16:10:24 +0800 | [diff] [blame] | 1414 | UNUSED(items); |
Lajos Molnar | c81d232 | 2017-11-15 16:23:43 -0800 | [diff] [blame] | 1415 | return C2_OMITTED; // Tunneling is not supported by now |
Johny Lin | 7c4cb52 | 2017-06-26 16:10:24 +0800 | [diff] [blame] | 1416 | } |
| 1417 | |
Johny Lin | a891f0e | 2017-12-19 10:25:27 +0800 | [diff] [blame] | 1418 | c2_status_t C2VDAComponent::flush_sm(flush_mode_t mode, |
| 1419 | std::list<std::unique_ptr<C2Work>>* const flushedWork) { |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 1420 | if (mode != FLUSH_COMPONENT) { |
Lajos Molnar | c81d232 | 2017-11-15 16:23:43 -0800 | [diff] [blame] | 1421 | return C2_OMITTED; // Tunneling is not supported by now |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 1422 | } |
Pin-chih Lin | 2a00c24 | 2018-03-28 20:41:50 +0800 | [diff] [blame] | 1423 | if (mState.load() != State::RUNNING) { |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 1424 | return C2_BAD_STATE; |
| 1425 | } |
Pin-chih Lin | 448c0c7 | 2018-05-22 14:17:53 +0800 | [diff] [blame] | 1426 | mTaskRunner->PostTask(FROM_HERE, ::base::Bind(&C2VDAComponent::onFlush, |
| 1427 | ::base::Unretained(this))); |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 1428 | // Instead of |flushedWork|, abandoned works will be returned via onWorkDone_nb() callback. |
| 1429 | return C2_OK; |
Johny Lin | 7c4cb52 | 2017-06-26 16:10:24 +0800 | [diff] [blame] | 1430 | } |
| 1431 | |
Lajos Molnar | b78444e | 2017-11-27 16:08:31 -0800 | [diff] [blame] | 1432 | c2_status_t C2VDAComponent::drain_nb(drain_mode_t mode) { |
Johny Lin | 3760d5f | 2018-01-31 14:40:13 +0800 | [diff] [blame] | 1433 | if (mode != DRAIN_COMPONENT_WITH_EOS && mode != DRAIN_COMPONENT_NO_EOS) { |
Lajos Molnar | c81d232 | 2017-11-15 16:23:43 -0800 | [diff] [blame] | 1434 | return C2_OMITTED; // Tunneling is not supported by now |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 1435 | } |
Pin-chih Lin | 2a00c24 | 2018-03-28 20:41:50 +0800 | [diff] [blame] | 1436 | if (mState.load() != State::RUNNING) { |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 1437 | return C2_BAD_STATE; |
| 1438 | } |
Pin-chih Lin | 448c0c7 | 2018-05-22 14:17:53 +0800 | [diff] [blame] | 1439 | mTaskRunner->PostTask(FROM_HERE, |
| 1440 | ::base::Bind(&C2VDAComponent::onDrain, ::base::Unretained(this), |
| 1441 | static_cast<uint32_t>(mode))); |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 1442 | return C2_OK; |
Johny Lin | 7c4cb52 | 2017-06-26 16:10:24 +0800 | [diff] [blame] | 1443 | } |
| 1444 | |
Lajos Molnar | b78444e | 2017-11-27 16:08:31 -0800 | [diff] [blame] | 1445 | c2_status_t C2VDAComponent::start() { |
Pin-chih Lin | 2a00c24 | 2018-03-28 20:41:50 +0800 | [diff] [blame] | 1446 | // Use mStartStopLock to block other asynchronously start/stop calls. |
| 1447 | std::lock_guard<std::mutex> lock(mStartStopLock); |
| 1448 | |
| 1449 | if (mState.load() != State::LOADED) { |
Johny Lin | 744cff1 | 2017-08-16 16:56:25 +0800 | [diff] [blame] | 1450 | return C2_BAD_STATE; // start() is only supported when component is in LOADED state. |
| 1451 | } |
| 1452 | |
Pin-chih Lin | 1ca0d0b | 2018-05-04 13:58:06 +0800 | [diff] [blame] | 1453 | mCodecProfile = mIntfImpl->getCodecProfile(); |
| 1454 | ALOGI("get parameter: mCodecProfile = %d", static_cast<int>(mCodecProfile)); |
| 1455 | |
Pin-chih Lin | 448c0c7 | 2018-05-22 14:17:53 +0800 | [diff] [blame] | 1456 | ::base::WaitableEvent done(::base::WaitableEvent::ResetPolicy::AUTOMATIC, |
| 1457 | ::base::WaitableEvent::InitialState::NOT_SIGNALED); |
| 1458 | mTaskRunner->PostTask(FROM_HERE, |
| 1459 | ::base::Bind(&C2VDAComponent::onStart, ::base::Unretained(this), |
| 1460 | mCodecProfile, &done)); |
Johny Lin | 744cff1 | 2017-08-16 16:56:25 +0800 | [diff] [blame] | 1461 | done.Wait(); |
Pin-chih Lin | db84a6c | 2018-09-13 21:38:50 +0800 | [diff] [blame] | 1462 | c2_status_t c2Status = adaptorResultToC2Status(mVDAInitResult); |
| 1463 | if (c2Status != C2_OK) { |
| 1464 | ALOGE("Failed to start component due to VDA error..."); |
| 1465 | return c2Status; |
Johny Lin | 744cff1 | 2017-08-16 16:56:25 +0800 | [diff] [blame] | 1466 | } |
Pin-chih Lin | 2a00c24 | 2018-03-28 20:41:50 +0800 | [diff] [blame] | 1467 | mState.store(State::RUNNING); |
Johny Lin | 744cff1 | 2017-08-16 16:56:25 +0800 | [diff] [blame] | 1468 | return C2_OK; |
Johny Lin | 7c4cb52 | 2017-06-26 16:10:24 +0800 | [diff] [blame] | 1469 | } |
| 1470 | |
Lajos Molnar | b78444e | 2017-11-27 16:08:31 -0800 | [diff] [blame] | 1471 | c2_status_t C2VDAComponent::stop() { |
Pin-chih Lin | 2a00c24 | 2018-03-28 20:41:50 +0800 | [diff] [blame] | 1472 | // Use mStartStopLock to block other asynchronously start/stop calls. |
| 1473 | std::lock_guard<std::mutex> lock(mStartStopLock); |
| 1474 | |
| 1475 | auto state = mState.load(); |
| 1476 | if (!(state == State::RUNNING || state == State::ERROR)) { |
| 1477 | return C2_OK; // Component is already in stopped state. |
Johny Lin | 744cff1 | 2017-08-16 16:56:25 +0800 | [diff] [blame] | 1478 | } |
| 1479 | |
Pin-chih Lin | 448c0c7 | 2018-05-22 14:17:53 +0800 | [diff] [blame] | 1480 | ::base::WaitableEvent done(::base::WaitableEvent::ResetPolicy::AUTOMATIC, |
| 1481 | ::base::WaitableEvent::InitialState::NOT_SIGNALED); |
Johny Lin | 744cff1 | 2017-08-16 16:56:25 +0800 | [diff] [blame] | 1482 | mTaskRunner->PostTask(FROM_HERE, |
Pin-chih Lin | 448c0c7 | 2018-05-22 14:17:53 +0800 | [diff] [blame] | 1483 | ::base::Bind(&C2VDAComponent::onStop, ::base::Unretained(this), &done)); |
Johny Lin | 744cff1 | 2017-08-16 16:56:25 +0800 | [diff] [blame] | 1484 | done.Wait(); |
Pin-chih Lin | 2a00c24 | 2018-03-28 20:41:50 +0800 | [diff] [blame] | 1485 | mState.store(State::LOADED); |
Johny Lin | 744cff1 | 2017-08-16 16:56:25 +0800 | [diff] [blame] | 1486 | return C2_OK; |
Johny Lin | 7c4cb52 | 2017-06-26 16:10:24 +0800 | [diff] [blame] | 1487 | } |
| 1488 | |
Lajos Molnar | 2737fb6 | 2017-12-19 09:46:42 -0800 | [diff] [blame] | 1489 | c2_status_t C2VDAComponent::reset() { |
Johny Lin | a891f0e | 2017-12-19 10:25:27 +0800 | [diff] [blame] | 1490 | return stop(); |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 1491 | // TODO(johnylin): reset is different than stop that it could be called in any state. |
| 1492 | // TODO(johnylin): when reset is called, set ComponentInterface to default values. |
Johny Lin | 7c4cb52 | 2017-06-26 16:10:24 +0800 | [diff] [blame] | 1493 | } |
| 1494 | |
Lajos Molnar | 2737fb6 | 2017-12-19 09:46:42 -0800 | [diff] [blame] | 1495 | c2_status_t C2VDAComponent::release() { |
Pin-chih Lin | 2a00c24 | 2018-03-28 20:41:50 +0800 | [diff] [blame] | 1496 | return reset(); |
Johny Lin | 7c4cb52 | 2017-06-26 16:10:24 +0800 | [diff] [blame] | 1497 | } |
| 1498 | |
| 1499 | std::shared_ptr<C2ComponentInterface> C2VDAComponent::intf() { |
| 1500 | return mIntf; |
| 1501 | } |
| 1502 | |
Johny Lin | ac6e270 | 2018-01-17 12:11:52 +0800 | [diff] [blame] | 1503 | void C2VDAComponent::providePictureBuffers(uint32_t minNumBuffers, const media::Size& codedSize) { |
| 1504 | // Always use fexible pixel 420 format YCbCr_420_888 in Android. |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 1505 | // Uses coded size for crop rect while it is not available. |
Johny Lin | ac6e270 | 2018-01-17 12:11:52 +0800 | [diff] [blame] | 1506 | auto format = std::make_unique<VideoFormat>(HalPixelFormat::YCbCr_420_888, minNumBuffers, |
| 1507 | codedSize, media::Rect(codedSize)); |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 1508 | |
| 1509 | // Set mRequestedVisibleRect to default. |
| 1510 | mRequestedVisibleRect = media::Rect(); |
| 1511 | |
Pin-chih Lin | 448c0c7 | 2018-05-22 14:17:53 +0800 | [diff] [blame] | 1512 | mTaskRunner->PostTask(FROM_HERE, ::base::Bind(&C2VDAComponent::onOutputFormatChanged, |
| 1513 | ::base::Unretained(this), |
| 1514 | ::base::Passed(&format))); |
Johny Lin | 7c4cb52 | 2017-06-26 16:10:24 +0800 | [diff] [blame] | 1515 | } |
| 1516 | |
Johny Lin | 744cff1 | 2017-08-16 16:56:25 +0800 | [diff] [blame] | 1517 | void C2VDAComponent::dismissPictureBuffer(int32_t pictureBufferId) { |
| 1518 | UNUSED(pictureBufferId); |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 1519 | // no ops |
Johny Lin | 7c4cb52 | 2017-06-26 16:10:24 +0800 | [diff] [blame] | 1520 | } |
| 1521 | |
Johny Lin | a891f0e | 2017-12-19 10:25:27 +0800 | [diff] [blame] | 1522 | void C2VDAComponent::pictureReady(int32_t pictureBufferId, int32_t bitstreamId, |
| 1523 | const media::Rect& cropRect) { |
Johny Lin | 744cff1 | 2017-08-16 16:56:25 +0800 | [diff] [blame] | 1524 | UNUSED(pictureBufferId); |
| 1525 | UNUSED(bitstreamId); |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 1526 | |
| 1527 | if (mRequestedVisibleRect != cropRect) { |
| 1528 | mRequestedVisibleRect = cropRect; |
Pin-chih Lin | 448c0c7 | 2018-05-22 14:17:53 +0800 | [diff] [blame] | 1529 | mTaskRunner->PostTask(FROM_HERE, ::base::Bind(&C2VDAComponent::onVisibleRectChanged, |
| 1530 | ::base::Unretained(this), cropRect)); |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 1531 | } |
| 1532 | |
Pin-chih Lin | 448c0c7 | 2018-05-22 14:17:53 +0800 | [diff] [blame] | 1533 | mTaskRunner->PostTask(FROM_HERE, ::base::Bind(&C2VDAComponent::onOutputBufferDone, |
| 1534 | ::base::Unretained(this), |
| 1535 | pictureBufferId, bitstreamId)); |
Johny Lin | 7c4cb52 | 2017-06-26 16:10:24 +0800 | [diff] [blame] | 1536 | } |
| 1537 | |
Johny Lin | 744cff1 | 2017-08-16 16:56:25 +0800 | [diff] [blame] | 1538 | void C2VDAComponent::notifyEndOfBitstreamBuffer(int32_t bitstreamId) { |
Pin-chih Lin | 448c0c7 | 2018-05-22 14:17:53 +0800 | [diff] [blame] | 1539 | mTaskRunner->PostTask(FROM_HERE, ::base::Bind(&C2VDAComponent::onInputBufferDone, |
| 1540 | ::base::Unretained(this), bitstreamId)); |
Johny Lin | 7c4cb52 | 2017-06-26 16:10:24 +0800 | [diff] [blame] | 1541 | } |
| 1542 | |
| 1543 | void C2VDAComponent::notifyFlushDone() { |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 1544 | mTaskRunner->PostTask(FROM_HERE, |
Pin-chih Lin | 448c0c7 | 2018-05-22 14:17:53 +0800 | [diff] [blame] | 1545 | ::base::Bind(&C2VDAComponent::onDrainDone, ::base::Unretained(this))); |
Johny Lin | 7c4cb52 | 2017-06-26 16:10:24 +0800 | [diff] [blame] | 1546 | } |
| 1547 | |
| 1548 | void C2VDAComponent::notifyResetDone() { |
Johny Lin | 744cff1 | 2017-08-16 16:56:25 +0800 | [diff] [blame] | 1549 | mTaskRunner->PostTask(FROM_HERE, |
Pin-chih Lin | 448c0c7 | 2018-05-22 14:17:53 +0800 | [diff] [blame] | 1550 | ::base::Bind(&C2VDAComponent::onResetDone, ::base::Unretained(this))); |
Johny Lin | 7c4cb52 | 2017-06-26 16:10:24 +0800 | [diff] [blame] | 1551 | } |
| 1552 | |
| 1553 | void C2VDAComponent::notifyError(VideoDecodeAcceleratorAdaptor::Result error) { |
Pin-chih Lin | db84a6c | 2018-09-13 21:38:50 +0800 | [diff] [blame] | 1554 | ALOGE("Got notifyError from VDA..."); |
| 1555 | c2_status_t err = adaptorResultToC2Status(error); |
| 1556 | if (err == C2_OK) { |
| 1557 | ALOGW("Shouldn't get SUCCESS err code in NotifyError(). Skip it..."); |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 1558 | return; |
| 1559 | } |
| 1560 | reportError(err); |
| 1561 | } |
| 1562 | |
Pin-chih Lin | 2dcfa1a | 2018-11-28 14:25:09 +0800 | [diff] [blame] | 1563 | void C2VDAComponent::reportWorkIfFinished(int32_t bitstreamId) { |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 1564 | DCHECK(mTaskRunner->BelongsToCurrentThread()); |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 1565 | |
Pin-chih Lin | 2dcfa1a | 2018-11-28 14:25:09 +0800 | [diff] [blame] | 1566 | auto workIter = findPendingWorkByBitstreamId(bitstreamId); |
| 1567 | if (workIter == mPendingWorks.end()) { |
| 1568 | reportError(C2_CORRUPTED); |
| 1569 | return; |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 1570 | } |
| 1571 | |
Pin-chih Lin | 2dcfa1a | 2018-11-28 14:25:09 +0800 | [diff] [blame] | 1572 | // EOS work will not be reported here. reportEOSWork() does it. |
| 1573 | auto work = workIter->get(); |
| 1574 | if (isWorkDone(work)) { |
| 1575 | if (work->worklets.front()->output.flags & C2FrameData::FLAG_DROP_FRAME) { |
| 1576 | // TODO: actually framework does not handle FLAG_DROP_FRAME, use C2_NOT_FOUND result to |
| 1577 | // let framework treat this as flushed work. |
| 1578 | work->result = C2_NOT_FOUND; |
| 1579 | } else { |
| 1580 | work->result = C2_OK; |
| 1581 | } |
| 1582 | work->workletsProcessed = static_cast<uint32_t>(work->worklets.size()); |
| 1583 | |
| 1584 | ALOGV("Reported finished work index=%llu", work->input.ordinal.frameIndex.peekull()); |
| 1585 | std::list<std::unique_ptr<C2Work>> finishedWorks; |
| 1586 | finishedWorks.emplace_back(std::move(*workIter)); |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 1587 | mListener->onWorkDone_nb(shared_from_this(), std::move(finishedWorks)); |
Pin-chih Lin | 2dcfa1a | 2018-11-28 14:25:09 +0800 | [diff] [blame] | 1588 | mPendingWorks.erase(workIter); |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 1589 | } |
| 1590 | } |
| 1591 | |
| 1592 | bool C2VDAComponent::isWorkDone(const C2Work* work) const { |
Pin-chih Lin | 3fe0c8d | 2018-09-11 12:17:53 +0800 | [diff] [blame] | 1593 | if (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) { |
| 1594 | // This is EOS work and should be processed by reportEOSWork(). |
Pin-chih Lin | ca72eff | 2018-06-12 11:22:04 +0800 | [diff] [blame] | 1595 | return false; |
| 1596 | } |
Pin-chih Lin | cd56fe7 | 2018-05-04 10:29:23 +0800 | [diff] [blame] | 1597 | if (work->input.buffers.front()) { |
Johny Lin | 3760d5f | 2018-01-31 14:40:13 +0800 | [diff] [blame] | 1598 | // Input buffer is still owned by VDA. |
Johny Lin | 3760d5f | 2018-01-31 14:40:13 +0800 | [diff] [blame] | 1599 | return false; |
| 1600 | } |
Pin-chih Lin | 617d763 | 2018-05-30 16:48:07 +0800 | [diff] [blame] | 1601 | if (mPendingOutputEOS && mPendingWorks.size() == 1u) { |
| 1602 | // If mPendingOutputEOS is true, the last returned work should be marked EOS flag and |
| 1603 | // returned by reportEOSWork() instead. |
Johny Lin | 3760d5f | 2018-01-31 14:40:13 +0800 | [diff] [blame] | 1604 | return false; |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 1605 | } |
Pin-chih Lin | 41db963 | 2018-09-11 15:41:39 +0800 | [diff] [blame] | 1606 | if (!(work->input.flags & C2FrameData::FLAG_CODEC_CONFIG) && |
Pin-chih Lin | 2dcfa1a | 2018-11-28 14:25:09 +0800 | [diff] [blame] | 1607 | !(work->worklets.front()->output.flags & C2FrameData::FLAG_DROP_FRAME) && |
Pin-chih Lin | 41db963 | 2018-09-11 15:41:39 +0800 | [diff] [blame] | 1608 | work->worklets.front()->output.buffers.empty()) { |
Pin-chih Lin | 2dcfa1a | 2018-11-28 14:25:09 +0800 | [diff] [blame] | 1609 | // Unless the input is CSD or the output is dropped, this work is not done because the |
| 1610 | // output buffer is not returned from VDA yet. |
Pin-chih Lin | 41db963 | 2018-09-11 15:41:39 +0800 | [diff] [blame] | 1611 | return false; |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 1612 | } |
Pin-chih Lin | 2dcfa1a | 2018-11-28 14:25:09 +0800 | [diff] [blame] | 1613 | return true; // This work is done. |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 1614 | } |
| 1615 | |
Johny Lin | 3760d5f | 2018-01-31 14:40:13 +0800 | [diff] [blame] | 1616 | void C2VDAComponent::reportEOSWork() { |
| 1617 | ALOGV("reportEOSWork"); |
| 1618 | DCHECK(mTaskRunner->BelongsToCurrentThread()); |
| 1619 | // In this moment all works prior to EOS work should be done and returned to listener. |
| 1620 | if (mPendingWorks.size() != 1u) { // only EOS work left |
| 1621 | ALOGE("It shouldn't have remaining works in mPendingWorks except EOS work."); |
| 1622 | reportError(C2_CORRUPTED); |
| 1623 | return; |
| 1624 | } |
| 1625 | |
Pin-chih Lin | 617d763 | 2018-05-30 16:48:07 +0800 | [diff] [blame] | 1626 | mPendingOutputEOS = false; |
| 1627 | |
Johny Lin | 3760d5f | 2018-01-31 14:40:13 +0800 | [diff] [blame] | 1628 | std::unique_ptr<C2Work> eosWork(std::move(mPendingWorks.front())); |
| 1629 | mPendingWorks.pop_front(); |
Pin-chih Lin | ca72eff | 2018-06-12 11:22:04 +0800 | [diff] [blame] | 1630 | if (!eosWork->input.buffers.empty()) { |
| 1631 | eosWork->input.buffers.front().reset(); |
| 1632 | } |
Johny Lin | 3760d5f | 2018-01-31 14:40:13 +0800 | [diff] [blame] | 1633 | eosWork->result = C2_OK; |
| 1634 | eosWork->workletsProcessed = static_cast<uint32_t>(eosWork->worklets.size()); |
| 1635 | eosWork->worklets.front()->output.flags = C2FrameData::FLAG_END_OF_STREAM; |
| 1636 | |
| 1637 | std::list<std::unique_ptr<C2Work>> finishedWorks; |
| 1638 | finishedWorks.emplace_back(std::move(eosWork)); |
| 1639 | mListener->onWorkDone_nb(shared_from_this(), std::move(finishedWorks)); |
| 1640 | } |
| 1641 | |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 1642 | void C2VDAComponent::reportAbandonedWorks() { |
| 1643 | DCHECK(mTaskRunner->BelongsToCurrentThread()); |
Lajos Molnar | fa7abe5 | 2018-01-25 21:48:00 -0800 | [diff] [blame] | 1644 | std::list<std::unique_ptr<C2Work>> abandonedWorks; |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 1645 | |
| 1646 | while (!mPendingWorks.empty()) { |
| 1647 | std::unique_ptr<C2Work> work(std::move(mPendingWorks.front())); |
| 1648 | mPendingWorks.pop_front(); |
| 1649 | |
Pin-chih Lin | 388dba4 | 2018-03-20 21:06:39 +0800 | [diff] [blame] | 1650 | // TODO: correlate the definition of flushed work result to framework. |
| 1651 | work->result = C2_NOT_FOUND; |
Pin-chih Lin | ca72eff | 2018-06-12 11:22:04 +0800 | [diff] [blame] | 1652 | // When the work is abandoned, buffer in input.buffers shall reset by component. |
| 1653 | if (!work->input.buffers.empty()) { |
| 1654 | work->input.buffers.front().reset(); |
| 1655 | } |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 1656 | abandonedWorks.emplace_back(std::move(work)); |
| 1657 | } |
| 1658 | |
Pin-chih Lin | 617d763 | 2018-05-30 16:48:07 +0800 | [diff] [blame] | 1659 | for (auto& work : mAbandonedWorks) { |
| 1660 | // TODO: correlate the definition of flushed work result to framework. |
| 1661 | work->result = C2_NOT_FOUND; |
Pin-chih Lin | ca72eff | 2018-06-12 11:22:04 +0800 | [diff] [blame] | 1662 | // When the work is abandoned, buffer in input.buffers shall reset by component. |
| 1663 | if (!work->input.buffers.empty()) { |
| 1664 | work->input.buffers.front().reset(); |
| 1665 | } |
Pin-chih Lin | 617d763 | 2018-05-30 16:48:07 +0800 | [diff] [blame] | 1666 | abandonedWorks.emplace_back(std::move(work)); |
| 1667 | } |
| 1668 | mAbandonedWorks.clear(); |
| 1669 | |
| 1670 | // Pending EOS work will be abandoned here due to component flush if any. |
| 1671 | mPendingOutputEOS = false; |
| 1672 | |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 1673 | if (!abandonedWorks.empty()) { |
| 1674 | mListener->onWorkDone_nb(shared_from_this(), std::move(abandonedWorks)); |
| 1675 | } |
| 1676 | } |
| 1677 | |
| 1678 | void C2VDAComponent::reportError(c2_status_t error) { |
Pin-chih Lin | 1ca0d0b | 2018-05-04 13:58:06 +0800 | [diff] [blame] | 1679 | mListener->onError_nb(shared_from_this(), static_cast<uint32_t>(error)); |
Johny Lin | 7c4cb52 | 2017-06-26 16:10:24 +0800 | [diff] [blame] | 1680 | } |
| 1681 | |
Pin-chih Lin | 62585f0 | 2018-05-29 21:00:03 +0800 | [diff] [blame] | 1682 | bool C2VDAComponent::startDequeueThread(const media::Size& size, uint32_t pixelFormat, |
Pin-chih Lin | 02faf85 | 2018-10-24 14:20:53 +0800 | [diff] [blame] | 1683 | std::shared_ptr<C2BlockPool> blockPool, |
| 1684 | bool resetBuffersInClient) { |
Pin-chih Lin | 906956a | 2018-05-22 14:12:59 +0800 | [diff] [blame] | 1685 | CHECK(!mDequeueThread.IsRunning()); |
| 1686 | if (!mDequeueThread.Start()) { |
| 1687 | ALOGE("failed to start dequeue thread!!"); |
| 1688 | return false; |
| 1689 | } |
| 1690 | mDequeueLoopStop.store(false); |
Pin-chih Lin | 02faf85 | 2018-10-24 14:20:53 +0800 | [diff] [blame] | 1691 | if (resetBuffersInClient) { |
| 1692 | mBuffersInClient.store(0u); |
| 1693 | } |
Pin-chih Lin | 906956a | 2018-05-22 14:12:59 +0800 | [diff] [blame] | 1694 | mDequeueThread.task_runner()->PostTask( |
Pin-chih Lin | 448c0c7 | 2018-05-22 14:17:53 +0800 | [diff] [blame] | 1695 | FROM_HERE, ::base::Bind(&C2VDAComponent::dequeueThreadLoop, ::base::Unretained(this), |
Pin-chih Lin | 62585f0 | 2018-05-29 21:00:03 +0800 | [diff] [blame] | 1696 | size, pixelFormat, std::move(blockPool))); |
Pin-chih Lin | 906956a | 2018-05-22 14:12:59 +0800 | [diff] [blame] | 1697 | return true; |
| 1698 | } |
| 1699 | |
| 1700 | void C2VDAComponent::stopDequeueThread() { |
| 1701 | if (mDequeueThread.IsRunning()) { |
| 1702 | mDequeueLoopStop.store(true); |
| 1703 | mDequeueThread.Stop(); |
| 1704 | } |
| 1705 | } |
| 1706 | |
Pin-chih Lin | 62585f0 | 2018-05-29 21:00:03 +0800 | [diff] [blame] | 1707 | void C2VDAComponent::dequeueThreadLoop(const media::Size& size, uint32_t pixelFormat, |
| 1708 | std::shared_ptr<C2BlockPool> blockPool) { |
Pin-chih Lin | 906956a | 2018-05-22 14:12:59 +0800 | [diff] [blame] | 1709 | ALOGV("dequeueThreadLoop starts"); |
| 1710 | DCHECK(mDequeueThread.task_runner()->BelongsToCurrentThread()); |
| 1711 | |
| 1712 | while (!mDequeueLoopStop.load()) { |
| 1713 | if (mBuffersInClient.load() == 0) { |
| 1714 | ::usleep(kDequeueRetryDelayUs); // wait for retry |
| 1715 | continue; |
| 1716 | } |
| 1717 | std::shared_ptr<C2GraphicBlock> block; |
Hirokazu Honda | 3f3c8a4 | 2018-05-09 22:25:19 +0800 | [diff] [blame] | 1718 | C2MemoryUsage usage = { |
| 1719 | mSecureMode ? C2MemoryUsage::READ_PROTECTED : C2MemoryUsage::CPU_READ, 0}; |
Pin-chih Lin | 62585f0 | 2018-05-29 21:00:03 +0800 | [diff] [blame] | 1720 | auto err = blockPool->fetchGraphicBlock(size.width(), size.height(), pixelFormat, usage, |
| 1721 | &block); |
Pin-chih Lin | 906956a | 2018-05-22 14:12:59 +0800 | [diff] [blame] | 1722 | if (err == C2_TIMED_OUT) { |
Pin-chih Lin | 02faf85 | 2018-10-24 14:20:53 +0800 | [diff] [blame] | 1723 | // Mutexes often do not care for FIFO. Practically the thread who is locking the mutex |
| 1724 | // usually will be granted to lock again right thereafter. To make this loop not too |
| 1725 | // bossy, the simpliest way is to add a short delay to the next time acquiring the |
| 1726 | // lock. TODO (b/118354314): replace this if there is better solution. |
| 1727 | ::usleep(1); |
Pin-chih Lin | 906956a | 2018-05-22 14:12:59 +0800 | [diff] [blame] | 1728 | continue; // wait for retry |
| 1729 | } |
Pin-chih Lin | 02faf85 | 2018-10-24 14:20:53 +0800 | [diff] [blame] | 1730 | if (err == C2_BAD_STATE) { |
| 1731 | ALOGV("Got informed from block pool surface is changed."); |
| 1732 | mTaskRunner->PostTask(FROM_HERE, ::base::Bind(&C2VDAComponent::onSurfaceChanged, |
| 1733 | ::base::Unretained(this))); |
| 1734 | break; // terminate the loop, will be resumed after onSurfaceChanged(). |
| 1735 | } |
Pin-chih Lin | 906956a | 2018-05-22 14:12:59 +0800 | [diff] [blame] | 1736 | if (err == C2_OK) { |
Pin-chih Lin | 585324e | 2018-07-25 16:24:54 +0800 | [diff] [blame] | 1737 | uint32_t poolId; |
| 1738 | if (blockPool->getAllocatorId() == C2PlatformAllocatorStore::BUFFERQUEUE) { |
| 1739 | err = C2VdaBqBlockPool::getPoolIdFromGraphicBlock(block, &poolId); |
| 1740 | } else { // bufferpool |
| 1741 | err = C2VdaPooledBlockPool::getPoolIdFromGraphicBlock(block, &poolId); |
| 1742 | } |
| 1743 | |
| 1744 | if (err != C2_OK) { |
| 1745 | ALOGE("dequeueThreadLoop got error on getPoolIdFromGraphicBlock: %d", err); |
| 1746 | break; |
| 1747 | } |
| 1748 | mTaskRunner->PostTask(FROM_HERE, |
| 1749 | ::base::Bind(&C2VDAComponent::onOutputBufferReturned, |
| 1750 | ::base::Unretained(this), std::move(block), poolId)); |
Pin-chih Lin | 906956a | 2018-05-22 14:12:59 +0800 | [diff] [blame] | 1751 | mBuffersInClient--; |
| 1752 | } else { |
| 1753 | ALOGE("dequeueThreadLoop got error: %d", err); |
| 1754 | break; |
| 1755 | } |
| 1756 | } |
| 1757 | ALOGV("dequeueThreadLoop terminates"); |
| 1758 | } |
| 1759 | |
Hirokazu Honda | decfca1 | 2018-01-23 01:59:09 +0900 | [diff] [blame] | 1760 | class C2VDAComponentFactory : public C2ComponentFactory { |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 1761 | public: |
Pin-chih Lin | 1ca0d0b | 2018-05-04 13:58:06 +0800 | [diff] [blame] | 1762 | C2VDAComponentFactory(C2String decoderName) |
| 1763 | : mDecoderName(decoderName), |
| 1764 | mReflector(std::static_pointer_cast<C2ReflectorHelper>( |
| 1765 | GetCodec2VDAComponentStore()->getParamReflector())){}; |
Hirokazu Honda | decfca1 | 2018-01-23 01:59:09 +0900 | [diff] [blame] | 1766 | |
| 1767 | c2_status_t createComponent(c2_node_id_t id, std::shared_ptr<C2Component>* const component, |
| 1768 | ComponentDeleter deleter) override { |
| 1769 | UNUSED(deleter); |
Pin-chih Lin | 1ca0d0b | 2018-05-04 13:58:06 +0800 | [diff] [blame] | 1770 | *component = std::shared_ptr<C2Component>(new C2VDAComponent(mDecoderName, id, mReflector)); |
Hirokazu Honda | decfca1 | 2018-01-23 01:59:09 +0900 | [diff] [blame] | 1771 | return C2_OK; |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 1772 | } |
Hirokazu Honda | decfca1 | 2018-01-23 01:59:09 +0900 | [diff] [blame] | 1773 | c2_status_t createInterface(c2_node_id_t id, |
| 1774 | std::shared_ptr<C2ComponentInterface>* const interface, |
| 1775 | InterfaceDeleter deleter) override { |
| 1776 | UNUSED(deleter); |
| 1777 | *interface = |
Pin-chih Lin | 1ca0d0b | 2018-05-04 13:58:06 +0800 | [diff] [blame] | 1778 | std::shared_ptr<C2ComponentInterface>(new SimpleInterface<C2VDAComponent::IntfImpl>( |
| 1779 | mDecoderName.c_str(), id, |
| 1780 | std::make_shared<C2VDAComponent::IntfImpl>(mDecoderName, mReflector))); |
Hirokazu Honda | decfca1 | 2018-01-23 01:59:09 +0900 | [diff] [blame] | 1781 | return C2_OK; |
| 1782 | } |
| 1783 | ~C2VDAComponentFactory() override = default; |
| 1784 | |
| 1785 | private: |
| 1786 | const C2String mDecoderName; |
Pin-chih Lin | 1ca0d0b | 2018-05-04 13:58:06 +0800 | [diff] [blame] | 1787 | std::shared_ptr<C2ReflectorHelper> mReflector; |
Johny Lin | 52bffe1 | 2017-09-19 14:26:06 +0800 | [diff] [blame] | 1788 | }; |
Johny Lin | 7c4cb52 | 2017-06-26 16:10:24 +0800 | [diff] [blame] | 1789 | } // namespace android |
| 1790 | |
Hirokazu Honda | 3f3c8a4 | 2018-05-09 22:25:19 +0800 | [diff] [blame] | 1791 | extern "C" ::C2ComponentFactory* CreateC2VDAH264Factory(bool secureMode) { |
| 1792 | ALOGV("in %s (secureMode=%d)", __func__, secureMode); |
| 1793 | return secureMode ? new ::android::C2VDAComponentFactory(android::kH264SecureDecoderName) |
| 1794 | : new ::android::C2VDAComponentFactory(android::kH264DecoderName); |
Johny Lin | 7c4cb52 | 2017-06-26 16:10:24 +0800 | [diff] [blame] | 1795 | } |
| 1796 | |
Lajos Molnar | 93e4f22 | 2018-02-22 17:05:17 -0800 | [diff] [blame] | 1797 | extern "C" void DestroyC2VDAH264Factory(::C2ComponentFactory* factory) { |
Hirokazu Honda | decfca1 | 2018-01-23 01:59:09 +0900 | [diff] [blame] | 1798 | ALOGV("in %s", __func__); |
| 1799 | delete factory; |
| 1800 | } |
| 1801 | |
Hirokazu Honda | 3f3c8a4 | 2018-05-09 22:25:19 +0800 | [diff] [blame] | 1802 | extern "C" ::C2ComponentFactory* CreateC2VDAVP8Factory(bool secureMode) { |
| 1803 | ALOGV("in %s (secureMode=%d)", __func__, secureMode); |
| 1804 | return secureMode ? new ::android::C2VDAComponentFactory(android::kVP8SecureDecoderName) |
| 1805 | : new ::android::C2VDAComponentFactory(android::kVP8DecoderName); |
Hirokazu Honda | decfca1 | 2018-01-23 01:59:09 +0900 | [diff] [blame] | 1806 | } |
| 1807 | |
Lajos Molnar | 93e4f22 | 2018-02-22 17:05:17 -0800 | [diff] [blame] | 1808 | extern "C" void DestroyC2VDAVP8Factory(::C2ComponentFactory* factory) { |
Hirokazu Honda | decfca1 | 2018-01-23 01:59:09 +0900 | [diff] [blame] | 1809 | ALOGV("in %s", __func__); |
| 1810 | delete factory; |
| 1811 | } |
| 1812 | |
Hirokazu Honda | 3f3c8a4 | 2018-05-09 22:25:19 +0800 | [diff] [blame] | 1813 | extern "C" ::C2ComponentFactory* CreateC2VDAVP9Factory(bool secureMode) { |
| 1814 | ALOGV("in %s (secureMode=%d)", __func__, secureMode); |
| 1815 | return secureMode ? new ::android::C2VDAComponentFactory(android::kVP9SecureDecoderName) |
| 1816 | : new ::android::C2VDAComponentFactory(android::kVP9DecoderName); |
Hirokazu Honda | decfca1 | 2018-01-23 01:59:09 +0900 | [diff] [blame] | 1817 | } |
| 1818 | |
Lajos Molnar | 93e4f22 | 2018-02-22 17:05:17 -0800 | [diff] [blame] | 1819 | extern "C" void DestroyC2VDAVP9Factory(::C2ComponentFactory* factory) { |
Hirokazu Honda | decfca1 | 2018-01-23 01:59:09 +0900 | [diff] [blame] | 1820 | ALOGV("in %s", __func__); |
| 1821 | delete factory; |
Johny Lin | 7c4cb52 | 2017-06-26 16:10:24 +0800 | [diff] [blame] | 1822 | } |