• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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> {
Convertmojo::TypeConverter24     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 
C2VDAAdaptorProxy()40 C2VDAAdaptorProxy::C2VDAAdaptorProxy()
41       : C2VDAAdaptorProxy(::arc::MojoProcessSupport::getLeakyInstance()) {}
42 
C2VDAAdaptorProxy(::arc::MojoProcessSupport * mojoProcessSupport)43 C2VDAAdaptorProxy::C2VDAAdaptorProxy(::arc::MojoProcessSupport* mojoProcessSupport)
44       : mClient(nullptr),
45         mMojoTaskRunner(mojoProcessSupport->mojo_thread().getTaskRunner()),
46         mBinding(this),
47         mRelay(new ::arc::CancellationRelay()) {}
48 
~C2VDAAdaptorProxy()49 C2VDAAdaptorProxy::~C2VDAAdaptorProxy() {}
50 
onConnectionError(const std::string & pipeName)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 
establishChannel()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 
establishChannelOnMojoThread(std::shared_ptr<::arc::Future<bool>> future)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 
onVersionReady(std::shared_ptr<::arc::Future<bool>> future,uint32_t version)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 
ProvidePictureBuffers(::arc::mojom::PictureBufferFormatPtr format)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 }
PictureReady(::arc::mojom::PicturePtr picture)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 
convertErrorCode(::arc::mojom::VideoDecodeAccelerator::Result error)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 
NotifyError(::arc::mojom::VideoDecodeAccelerator::Result error)119 void C2VDAAdaptorProxy::NotifyError(::arc::mojom::VideoDecodeAccelerator::Result error) {
120     ALOGE("NotifyError %d", static_cast<int>(error));
121     mClient->notifyError(convertErrorCode(error));
122 }
123 
NotifyEndOfBitstreamBuffer(int32_t bitstream_id)124 void C2VDAAdaptorProxy::NotifyEndOfBitstreamBuffer(int32_t bitstream_id) {
125     ALOGV("NotifyEndOfBitstreamBuffer");
126     mClient->notifyEndOfBitstreamBuffer(bitstream_id);
127 }
128 
NotifyResetDone(::arc::mojom::VideoDecodeAccelerator::Result result)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 
NotifyFlushDone(::arc::mojom::VideoDecodeAccelerator::Result result)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
GetSupportedProfiles(uint32_t inputFormatFourcc)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
ResolveBufferFormat(bool crcb,bool semiplanar)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 
initialize(media::VideoCodecProfile profile,bool secureMode,VideoDecodeAcceleratorAdaptor::Client * client)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 
initializeOnMojoThread(const media::VideoCodecProfile profile,const bool secureMode,const::arc::mojom::VideoDecodeAccelerator::InitializeCallback & cb)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 
decode(int32_t bitstreamId,int handleFd,off_t offset,uint32_t size)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 
decodeOnMojoThread(int32_t bitstreamId,int handleFd,off_t offset,uint32_t size)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 
assignPictureBuffers(uint32_t numOutputBuffers)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 
assignPictureBuffersOnMojoThread(uint32_t numOutputBuffers)265 void C2VDAAdaptorProxy::assignPictureBuffersOnMojoThread(uint32_t numOutputBuffers) {
266     mVDAPtr->AssignPictureBuffers(numOutputBuffers);
267 }
268 
importBufferForPicture(int32_t pictureBufferId,HalPixelFormat format,int handleFd,const std::vector<VideoFramePlane> & planes)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 
importBufferForPictureOnMojoThread(int32_t pictureBufferId,HalPixelFormat format,int handleFd,const std::vector<VideoFramePlane> & planes)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 
reusePictureBuffer(int32_t pictureBufferId)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 
reusePictureBufferOnMojoThread(int32_t pictureBufferId)304 void C2VDAAdaptorProxy::reusePictureBufferOnMojoThread(int32_t pictureBufferId) {
305     mVDAPtr->ReusePictureBuffer(pictureBufferId);
306 }
307 
flush()308 void C2VDAAdaptorProxy::flush() {
309     ALOGV("flush");
310     mMojoTaskRunner->PostTask(
311             FROM_HERE, base::Bind(&C2VDAAdaptorProxy::flushOnMojoThread, base::Unretained(this)));
312 }
313 
flushOnMojoThread()314 void C2VDAAdaptorProxy::flushOnMojoThread() {
315     mVDAPtr->Flush(base::Bind(&C2VDAAdaptorProxy::NotifyFlushDone, base::Unretained(this)));
316 }
317 
reset()318 void C2VDAAdaptorProxy::reset() {
319     ALOGV("reset");
320     mMojoTaskRunner->PostTask(
321             FROM_HERE, base::Bind(&C2VDAAdaptorProxy::resetOnMojoThread, base::Unretained(this)));
322 }
323 
resetOnMojoThread()324 void C2VDAAdaptorProxy::resetOnMojoThread() {
325     mVDAPtr->Reset(base::Bind(&C2VDAAdaptorProxy::NotifyResetDone, base::Unretained(this)));
326 }
327 
destroy()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 
closeChannelOnMojoThread()338 void C2VDAAdaptorProxy::closeChannelOnMojoThread() {
339     if (mBinding.is_bound()) mBinding.Close();
340     mVDAPtr.reset();
341 }
342 
343 }  // namespace arc
344 }  // namespace android
345