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 "C2VDAAdaptorProxy" 7 8 #include <C2ArcVideoAcceleratorFactory.h> 9 #include <C2VDAAdaptorProxy.h> 10 11 #include <arc/MojoProcessSupport.h> 12 #include <arc/MojoThread.h> 13 #include <base/bind.h> 14 #include <base/files/scoped_file.h> 15 #include <mojo/public/cpp/platform/platform_handle.h> 16 #include <mojo/public/cpp/system/platform_handle.h> 17 18 #include <binder/IServiceManager.h> 19 #include <utils/Log.h> 20 21 namespace mojo { 22 template <> 23 struct TypeConverter<::arc::VideoFramePlane, android::VideoFramePlane> { 24 static ::arc::VideoFramePlane Convert(const android::VideoFramePlane& plane) { 25 return ::arc::VideoFramePlane{static_cast<int32_t>(plane.mOffset), 26 static_cast<int32_t>(plane.mStride)}; 27 } 28 }; 29 } // namespace mojo 30 31 namespace android { 32 namespace arc { 33 C2VDAAdaptorProxy::C2VDAAdaptorProxy() 34 : C2VDAAdaptorProxy(::arc::MojoProcessSupport::getLeakyInstance()) {} 35 36 C2VDAAdaptorProxy::C2VDAAdaptorProxy(::arc::MojoProcessSupport* mojoProcessSupport) 37 : mClient(nullptr), 38 mMojoTaskRunner(mojoProcessSupport->mojo_thread().getTaskRunner()), 39 mBinding(this), 40 mRelay(new ::arc::CancellationRelay()) {} 41 42 C2VDAAdaptorProxy::~C2VDAAdaptorProxy() {} 43 44 void C2VDAAdaptorProxy::onConnectionError(const std::string& pipeName) { 45 ALOGE("onConnectionError (%s)", pipeName.c_str()); 46 mRelay->cancel(); 47 NotifyError(::arc::mojom::VideoDecodeAccelerator::Result::PLATFORM_FAILURE); 48 } 49 50 bool C2VDAAdaptorProxy::establishChannel() { 51 ALOGV("establishChannel"); 52 auto future = ::arc::Future<bool>::make_shared(mRelay); 53 mMojoTaskRunner->PostTask(FROM_HERE, 54 ::base::Bind(&C2VDAAdaptorProxy::establishChannelOnMojoThread, 55 ::base::Unretained(this), future)); 56 return future->wait() && future->get(); 57 } 58 59 void C2VDAAdaptorProxy::establishChannelOnMojoThread(std::shared_ptr<::arc::Future<bool>> future) { 60 auto& factory = ::android::GetC2ArcVideoAcceleratorFactory(); 61 62 if (!factory.createVideoDecodeAccelerator(mojo::MakeRequest(&mVDAPtr))) { 63 future->set(false); 64 return; 65 } 66 mVDAPtr.set_connection_error_handler(::base::Bind(&C2VDAAdaptorProxy::onConnectionError, 67 ::base::Unretained(this), 68 std::string("mVDAPtr (vda pipe)"))); 69 mVDAPtr.QueryVersion(::base::Bind(&C2VDAAdaptorProxy::onVersionReady, ::base::Unretained(this), 70 std::move(future))); 71 } 72 73 void C2VDAAdaptorProxy::onVersionReady(std::shared_ptr<::arc::Future<bool>> future, uint32_t version) { 74 ALOGI("VideoDecodeAccelerator ready (version=%d)", version); 75 76 future->set(true); 77 } 78 79 void C2VDAAdaptorProxy::ProvidePictureBuffers(::arc::mojom::PictureBufferFormatPtr format) { 80 ALOGV("ProvidePictureBuffers"); 81 mClient->providePictureBuffers( 82 format->min_num_buffers, 83 media::Size(format->coded_size.width(), format->coded_size.height())); 84 } 85 void C2VDAAdaptorProxy::PictureReady(::arc::mojom::PicturePtr picture) { 86 ALOGV("PictureReady"); 87 const auto& rect = picture->crop_rect; 88 mClient->pictureReady(picture->picture_buffer_id, picture->bitstream_id, 89 media::Rect(rect.x(), rect.y(), rect.right(), rect.bottom())); 90 } 91 92 static VideoDecodeAcceleratorAdaptor::Result convertErrorCode( 93 ::arc::mojom::VideoDecodeAccelerator::Result error) { 94 switch (error) { 95 case ::arc::mojom::VideoDecodeAccelerator::Result::ILLEGAL_STATE: 96 return VideoDecodeAcceleratorAdaptor::ILLEGAL_STATE; 97 case ::arc::mojom::VideoDecodeAccelerator::Result::INVALID_ARGUMENT: 98 return VideoDecodeAcceleratorAdaptor::INVALID_ARGUMENT; 99 case ::arc::mojom::VideoDecodeAccelerator::Result::UNREADABLE_INPUT: 100 return VideoDecodeAcceleratorAdaptor::UNREADABLE_INPUT; 101 case ::arc::mojom::VideoDecodeAccelerator::Result::PLATFORM_FAILURE: 102 return VideoDecodeAcceleratorAdaptor::PLATFORM_FAILURE; 103 case ::arc::mojom::VideoDecodeAccelerator::Result::INSUFFICIENT_RESOURCES: 104 return VideoDecodeAcceleratorAdaptor::INSUFFICIENT_RESOURCES; 105 106 default: 107 ALOGE("Unknown error code: %d", static_cast<int>(error)); 108 return VideoDecodeAcceleratorAdaptor::PLATFORM_FAILURE; 109 } 110 } 111 112 void C2VDAAdaptorProxy::NotifyError(::arc::mojom::VideoDecodeAccelerator::Result error) { 113 ALOGE("NotifyError %d", static_cast<int>(error)); 114 mClient->notifyError(convertErrorCode(error)); 115 } 116 117 void C2VDAAdaptorProxy::NotifyEndOfBitstreamBuffer(int32_t bitstream_id) { 118 ALOGV("NotifyEndOfBitstreamBuffer"); 119 mClient->notifyEndOfBitstreamBuffer(bitstream_id); 120 } 121 122 void C2VDAAdaptorProxy::NotifyResetDone(::arc::mojom::VideoDecodeAccelerator::Result result) { 123 ALOGV("NotifyResetDone"); 124 // Always notify reset done to component even if result is not success. On shutdown, MediaCodec 125 // will wait on shutdown complete notification despite any error. If no notification, it will be 126 // hanging until timeout and force release. 127 if (result != ::arc::mojom::VideoDecodeAccelerator::Result::SUCCESS) { 128 ALOGE("Reset is done incorrectly."); 129 NotifyError(result); 130 } 131 mClient->notifyResetDone(); 132 } 133 134 void C2VDAAdaptorProxy::NotifyFlushDone(::arc::mojom::VideoDecodeAccelerator::Result result) { 135 ALOGV("NotifyFlushDone"); 136 if (result == ::arc::mojom::VideoDecodeAccelerator::Result::CANCELLED) { 137 // Flush is cancelled by a succeeding Reset(). A client expects this behavior. 138 ALOGE("Flush is canceled."); 139 return; 140 } 141 if (result != ::arc::mojom::VideoDecodeAccelerator::Result::SUCCESS) { 142 ALOGE("Flush is done incorrectly."); 143 NotifyError(result); 144 return; 145 } 146 mClient->notifyFlushDone(); 147 } 148 149 //static 150 media::VideoDecodeAccelerator::SupportedProfiles C2VDAAdaptorProxy::GetSupportedProfiles( 151 InputCodec inputCodec) { 152 media::VideoDecodeAccelerator::SupportedProfiles profiles(1); 153 profiles[0].min_resolution = media::Size(16, 16); 154 profiles[0].max_resolution = media::Size(4096, 4096); 155 switch (inputCodec) { 156 case InputCodec::H264: 157 profiles[0].profile = media::H264PROFILE_MAIN; 158 break; 159 case InputCodec::VP8: 160 profiles[0].profile = media::VP8PROFILE_ANY; 161 break; 162 case InputCodec::VP9: 163 profiles[0].profile = media::VP9PROFILE_PROFILE0; 164 break; 165 default: 166 ALOGE("Unknown input codec: %d", inputCodec); 167 return {}; 168 } 169 return profiles; 170 } 171 172 VideoDecodeAcceleratorAdaptor::Result C2VDAAdaptorProxy::initialize( 173 media::VideoCodecProfile profile, bool secureMode, 174 VideoDecodeAcceleratorAdaptor::Client* client) { 175 ALOGV("initialize(profile=%d, secureMode=%d)", static_cast<int>(profile), 176 static_cast<int>(secureMode)); 177 DCHECK(client); 178 DCHECK(!mClient); 179 mClient = client; 180 181 if (!establishChannel()) { 182 ALOGE("establishChannel failed"); 183 return VideoDecodeAcceleratorAdaptor::PLATFORM_FAILURE; 184 } 185 186 auto future = ::arc::Future<::arc::mojom::VideoDecodeAccelerator::Result>::make_shared(mRelay); 187 mMojoTaskRunner->PostTask(FROM_HERE, ::base::Bind(&C2VDAAdaptorProxy::initializeOnMojoThread, 188 ::base::Unretained(this), profile, secureMode, 189 ::arc::FutureCallback(future))); 190 191 if (!future->wait()) { 192 ALOGE("Connection lost"); 193 return VideoDecodeAcceleratorAdaptor::PLATFORM_FAILURE; 194 } 195 return static_cast<VideoDecodeAcceleratorAdaptor::Result>(future->get()); 196 } 197 198 void C2VDAAdaptorProxy::initializeOnMojoThread( 199 const media::VideoCodecProfile profile, const bool secureMode, 200 const ::arc::mojom::VideoDecodeAccelerator::InitializeCallback& cb) { 201 // base::Unretained is safe because we own |mBinding|. 202 mojo::InterfacePtr<::arc::mojom::VideoDecodeClient> client; 203 mBinding.Bind(mojo::MakeRequest(&client)); 204 mBinding.set_connection_error_handler(::base::Bind(&C2VDAAdaptorProxy::onConnectionError, 205 ::base::Unretained(this), 206 std::string("mBinding (client pipe)"))); 207 208 ::arc::mojom::VideoDecodeAcceleratorConfigPtr arcConfig = 209 ::arc::mojom::VideoDecodeAcceleratorConfig::New(); 210 arcConfig->secure_mode = secureMode; 211 arcConfig->profile = static_cast<::arc::mojom::VideoCodecProfile>(profile); 212 mVDAPtr->Initialize(std::move(arcConfig), std::move(client), cb); 213 } 214 215 void C2VDAAdaptorProxy::decode(int32_t bitstreamId, int handleFd, off_t offset, uint32_t size) { 216 ALOGV("decode"); 217 mMojoTaskRunner->PostTask( 218 FROM_HERE, ::base::Bind(&C2VDAAdaptorProxy::decodeOnMojoThread, ::base::Unretained(this), 219 bitstreamId, handleFd, offset, size)); 220 } 221 222 void C2VDAAdaptorProxy::decodeOnMojoThread(int32_t bitstreamId, int handleFd, off_t offset, 223 uint32_t size) { 224 mojo::ScopedHandle wrappedHandle = 225 mojo::WrapPlatformHandle(mojo::PlatformHandle(::base::ScopedFD(handleFd))); 226 if (!wrappedHandle.is_valid()) { 227 ALOGE("failed to wrap handle"); 228 NotifyError(::arc::mojom::VideoDecodeAccelerator::Result::PLATFORM_FAILURE); 229 return; 230 } 231 auto bufferPtr = ::arc::mojom::BitstreamBuffer::New(); 232 bufferPtr->bitstream_id = bitstreamId; 233 bufferPtr->handle_fd = std::move(wrappedHandle); 234 bufferPtr->offset = offset; 235 bufferPtr->bytes_used = size; 236 mVDAPtr->Decode(std::move(bufferPtr)); 237 } 238 239 void C2VDAAdaptorProxy::assignPictureBuffers(uint32_t numOutputBuffers) { 240 ALOGV("assignPictureBuffers: %d", numOutputBuffers); 241 mMojoTaskRunner->PostTask(FROM_HERE, 242 ::base::Bind(&C2VDAAdaptorProxy::assignPictureBuffersOnMojoThread, 243 ::base::Unretained(this), numOutputBuffers)); 244 } 245 246 void C2VDAAdaptorProxy::assignPictureBuffersOnMojoThread(uint32_t numOutputBuffers) { 247 mVDAPtr->AssignPictureBuffers(numOutputBuffers); 248 } 249 250 void C2VDAAdaptorProxy::importBufferForPicture(int32_t pictureBufferId, HalPixelFormat format, 251 int handleFd, 252 const std::vector<VideoFramePlane>& planes) { 253 ALOGV("importBufferForPicture"); 254 mMojoTaskRunner->PostTask( 255 FROM_HERE, 256 ::base::Bind(&C2VDAAdaptorProxy::importBufferForPictureOnMojoThread, 257 ::base::Unretained(this), pictureBufferId, format, handleFd, planes)); 258 } 259 260 void C2VDAAdaptorProxy::importBufferForPictureOnMojoThread( 261 int32_t pictureBufferId, HalPixelFormat format, int handleFd, 262 const std::vector<VideoFramePlane>& planes) { 263 mojo::ScopedHandle wrappedHandle = 264 mojo::WrapPlatformHandle(mojo::PlatformHandle(::base::ScopedFD(handleFd))); 265 if (!wrappedHandle.is_valid()) { 266 ALOGE("failed to wrap handle"); 267 NotifyError(::arc::mojom::VideoDecodeAccelerator::Result::PLATFORM_FAILURE); 268 return; 269 } 270 271 mVDAPtr->ImportBufferForPicture(pictureBufferId, 272 static_cast<::arc::mojom::HalPixelFormat>(format), 273 std::move(wrappedHandle), 274 mojo::ConvertTo<std::vector<::arc::VideoFramePlane>>(planes)); 275 } 276 277 void C2VDAAdaptorProxy::reusePictureBuffer(int32_t pictureBufferId) { 278 ALOGV("reusePictureBuffer: %d", pictureBufferId); 279 mMojoTaskRunner->PostTask(FROM_HERE, 280 ::base::Bind(&C2VDAAdaptorProxy::reusePictureBufferOnMojoThread, 281 ::base::Unretained(this), pictureBufferId)); 282 } 283 284 void C2VDAAdaptorProxy::reusePictureBufferOnMojoThread(int32_t pictureBufferId) { 285 mVDAPtr->ReusePictureBuffer(pictureBufferId); 286 } 287 288 void C2VDAAdaptorProxy::flush() { 289 ALOGV("flush"); 290 mMojoTaskRunner->PostTask( 291 FROM_HERE, ::base::Bind(&C2VDAAdaptorProxy::flushOnMojoThread, ::base::Unretained(this))); 292 } 293 294 void C2VDAAdaptorProxy::flushOnMojoThread() { 295 mVDAPtr->Flush(::base::Bind(&C2VDAAdaptorProxy::NotifyFlushDone, ::base::Unretained(this))); 296 } 297 298 void C2VDAAdaptorProxy::reset() { 299 ALOGV("reset"); 300 mMojoTaskRunner->PostTask( 301 FROM_HERE, ::base::Bind(&C2VDAAdaptorProxy::resetOnMojoThread, ::base::Unretained(this))); 302 } 303 304 void C2VDAAdaptorProxy::resetOnMojoThread() { 305 mVDAPtr->Reset(::base::Bind(&C2VDAAdaptorProxy::NotifyResetDone, ::base::Unretained(this))); 306 } 307 308 void C2VDAAdaptorProxy::destroy() { 309 ALOGV("destroy"); 310 ::arc::Future<void> future; 311 ::arc::PostTaskAndSetFutureWithResult( 312 mMojoTaskRunner.get(), FROM_HERE, 313 ::base::Bind(&C2VDAAdaptorProxy::closeChannelOnMojoThread, ::base::Unretained(this)), 314 &future); 315 future.get(); 316 } 317 318 void C2VDAAdaptorProxy::closeChannelOnMojoThread() { 319 if (mBinding.is_bound()) mBinding.Close(); 320 mVDAPtr.reset(); 321 } 322 323 } // namespace arc 324 } // namespace android 325