Home | History | Annotate | Download | only in v4l2_codec2
      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