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 <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