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