OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2016 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 #include "chrome/gpu/gpu_arc_video_service.h" | |
6 | |
7 #include <fcntl.h> | |
8 | |
9 #include <utility> | |
10 | |
11 #include "base/bind.h" | |
12 #include "base/logging.h" | |
13 #include "base/thread_task_runner_handle.h" | |
14 #include "chrome/gpu/arc_gpu_video_decode_accelerator.h" | |
15 #include "chrome/gpu/arc_video_accelerator.h" | |
16 #include "components/arc/common/video_accelerator.mojom.h" | |
17 #include "mojo/edk/embedder/embedder.h" | |
18 #include "mojo/public/cpp/bindings/binding.h" | |
19 #include "mojo/public/cpp/bindings/type_converter.h" | |
20 | |
21 namespace { | |
22 | |
23 // Child process may be created in the different namespace, thus we don't have | |
24 // its real PID. Since Mojo in POSIX only uses the value as identifier for the | |
25 // routing table, we can give it fake value as long as it is unique. | |
26 // Chrome OS uses default pid_max of 32k, so we can safely shift the pid range | |
27 // by kPidBase and don't conflict with legitimate process. | |
28 // | |
29 // This assumes all video accelerator clients are from the same namespace and | |
30 // the max pid of the said namespace is kPidMask. | |
31 base::ProcessHandle RemapChildPid(uint32_t pid) { | |
32 uint32_t kPidBase = 0x3F000000; // arbitrary chosen. | |
33 uint32_t kPidMask = 0x7fff; // the default, 32k. | |
34 return kPidBase + (pid & kPidMask); | |
35 } | |
36 | |
37 } // namespace | |
38 | |
39 namespace mojo { | |
40 | |
41 template <> | |
42 struct TypeConverter<arc::BufferMetadataPtr, chromeos::arc::BufferMetadata> { | |
43 static arc::BufferMetadataPtr Convert( | |
44 const chromeos::arc::BufferMetadata& input) { | |
45 arc::BufferMetadataPtr result = arc::BufferMetadata::New(); | |
46 result->timestamp = input.timestamp; | |
47 result->flags = input.flags; | |
48 result->bytes_used = input.bytes_used; | |
49 return result; | |
50 } | |
51 }; | |
52 | |
53 template <> | |
54 struct TypeConverter<chromeos::arc::BufferMetadata, arc::BufferMetadataPtr> { | |
55 static chromeos::arc::BufferMetadata Convert( | |
56 const arc::BufferMetadataPtr& input) { | |
57 chromeos::arc::BufferMetadata result; | |
58 result.timestamp = input->timestamp; | |
59 result.flags = input->flags; | |
60 result.bytes_used = input->bytes_used; | |
61 return result; | |
62 } | |
63 }; | |
64 | |
65 template <> | |
66 struct TypeConverter<arc::VideoFormatPtr, chromeos::arc::VideoFormat> { | |
67 static arc::VideoFormatPtr Convert(const chromeos::arc::VideoFormat& input) { | |
68 arc::VideoFormatPtr result = arc::VideoFormat::New(); | |
69 result->pixel_format = input.pixel_format; | |
70 result->buffer_size = input.image_size; | |
71 result->min_num_buffers = input.min_num_buffers; | |
72 result->coded_width = input.coded_width; | |
73 result->coded_height = input.coded_height; | |
74 result->crop_left = input.crop_left; | |
75 result->crop_width = input.crop_width; | |
76 result->crop_top = input.crop_top; | |
77 result->crop_height = input.crop_height; | |
78 return result; | |
79 } | |
80 }; | |
81 | |
82 template <> | |
83 struct TypeConverter<chromeos::arc::ArcVideoAccelerator::Config, | |
84 arc::ArcVideoAcceleratorConfigPtr> { | |
85 static chromeos::arc::ArcVideoAccelerator::Config Convert( | |
86 const arc::ArcVideoAcceleratorConfigPtr& input) { | |
87 chromeos::arc::ArcVideoAccelerator::Config result; | |
88 result.device_type = | |
89 static_cast<chromeos::arc::DeviceType>(input->device_type); | |
90 result.num_input_buffers = input->num_input_buffers; | |
91 result.input_pixel_format = input->input_pixel_format; | |
92 return result; | |
93 } | |
94 }; | |
95 | |
96 } // namespace mojo | |
97 | |
98 namespace chromeos { | |
99 namespace arc { | |
100 | |
101 class GpuArcVideoService::AcceleratorStub | |
102 : public ::arc::VideoAcceleratorService, | |
103 public ArcVideoAccelerator::Client { | |
104 public: | |
105 // |owner| outlives AcceleratorStub. | |
106 explicit AcceleratorStub(GpuArcVideoService* owner) | |
107 : owner_(owner), binding_(this) {} | |
108 | |
109 ~AcceleratorStub() override { DCHECK(thread_checker_.CalledOnValidThread()); } | |
110 | |
111 bool Connect(std::string token) { | |
112 DVLOG(2) << "Connect"; | |
113 | |
114 mojo::ScopedMessagePipeHandle server_pipe = | |
115 mojo::edk::CreateParentMessagePipe(token); | |
116 if (!server_pipe.is_valid()) { | |
117 LOG(ERROR) << "Invalid pipe"; | |
118 return false; | |
119 } | |
120 | |
121 client_.Bind(mojo::InterfacePtrInfo<::arc::VideoAcceleratorServiceClient>( | |
122 std::move(server_pipe), 0u)); | |
123 | |
124 // base::Unretained is safe because we owned |client_| | |
125 client_.set_connection_error_handler( | |
126 base::Bind(&GpuArcVideoService::AcceleratorStub::OnConnectionError, | |
127 base::Unretained(this))); | |
128 | |
129 accelerator_.reset( | |
130 new ArcGpuVideoDecodeAccelerator(base::ThreadTaskRunnerHandle::Get())); | |
131 | |
132 ::arc::VideoAcceleratorServicePtr service; | |
133 binding_.Bind(GetProxy(&service)); | |
134 // base::Unretained is safe because we owned |binding_| | |
135 binding_.set_connection_error_handler( | |
136 base::Bind(&GpuArcVideoService::AcceleratorStub::OnConnectionError, | |
137 base::Unretained(this))); | |
138 | |
139 client_->SetService(std::move(service)); | |
140 return true; | |
141 } | |
142 | |
143 void OnConnectionError() { | |
144 DVLOG(2) << "OnConnectionError"; | |
145 owner_->RemoveClient(this); | |
146 // |this| is deleted. | |
147 } | |
148 | |
149 // ArcVideoAccelerator::Client implementation: | |
150 void OnError(ArcVideoAccelerator::Error error) override { | |
151 DVLOG(2) << "OnError " << error; | |
152 client_->OnError( | |
153 static_cast<::arc::VideoAcceleratorServiceClient::Error>(error)); | |
154 } | |
155 | |
156 void OnBufferDone(PortType port, | |
157 uint32_t index, | |
158 const BufferMetadata& metadata) override { | |
159 DVLOG(2) << "OnBufferDone " << port << "," << index; | |
160 client_->OnBufferDone(static_cast<::arc::PortType>(port), index, | |
161 ::arc::BufferMetadata::From(metadata)); | |
162 } | |
163 | |
164 void OnOutputFormatChanged(const VideoFormat& format) override { | |
165 DVLOG(2) << "OnOutputFormatChanged"; | |
166 client_->OnOutputFormatChanged(::arc::VideoFormat::From(format)); | |
167 } | |
168 | |
169 // ::arc::VideoAcceleratorService impementation: | |
170 void Initialize(::arc::ArcVideoAcceleratorConfigPtr config, | |
171 const InitializeCallback& callback) override { | |
172 DVLOG(2) << "Initialize"; | |
173 bool result = accelerator_->Initialize( | |
174 config.To<ArcVideoAccelerator::Config>(), this); | |
175 callback.Run(result); | |
176 } | |
177 | |
178 void BindSharedMemory(::arc::PortType port, | |
179 uint32_t index, | |
180 mojo::ScopedHandle ashmem_handle, | |
181 uint64_t offset, | |
182 uint64_t length) override { | |
183 DVLOG(2) << "BindSharedMemoryCallback port=" << port << ", index=" << index | |
184 << ", offset=" << offset << ", length=" << length; | |
185 // TODO(kcwu) make sure do we need special care for invalid handle? | |
186 mojo::edk::ScopedPlatformHandle scoped_platform_handle; | |
187 MojoResult mojo_result = mojo::edk::PassWrappedPlatformHandle( | |
188 ashmem_handle.release().value(), &scoped_platform_handle); | |
189 DCHECK_EQ(mojo_result, MOJO_RESULT_OK); | |
190 | |
191 int fd = scoped_platform_handle.release().handle; | |
192 accelerator_->BindSharedMemory(static_cast<PortType>(port), index, fd, | |
193 static_cast<size_t>(offset), | |
194 static_cast<size_t>(length)); | |
195 } | |
196 | |
197 void BindDmabuf(::arc::PortType port, | |
198 uint32_t index, | |
199 mojo::ScopedHandle dmabuf_handle) override { | |
200 DVLOG(2) << "BindDmabuf port=" << port << ", index=" << index; | |
201 mojo::edk::ScopedPlatformHandle scoped_platform_handle; | |
202 MojoResult mojo_result = mojo::edk::PassWrappedPlatformHandle( | |
203 dmabuf_handle.release().value(), &scoped_platform_handle); | |
204 DCHECK_EQ(mojo_result, MOJO_RESULT_OK); | |
205 | |
206 int fd = scoped_platform_handle.release().handle; | |
207 accelerator_->BindDmabuf(static_cast<PortType>(port), index, fd); | |
208 } | |
209 | |
210 void UseBuffer(::arc::PortType port, | |
211 uint32_t index, | |
212 ::arc::BufferMetadataPtr metadata) override { | |
213 DVLOG(2) << "UseBuffer port=" << port << ", index=" << index; | |
214 accelerator_->UseBuffer(static_cast<PortType>(port), index, | |
215 metadata.To<BufferMetadata>()); | |
216 } | |
217 | |
218 void SetNumberOfOutputBuffers(uint64_t number) override { | |
219 DVLOG(2) << "SetNumberOfOutputBuffers number=" << number; | |
220 accelerator_->SetNumberOfOutputBuffers(static_cast<size_t>(number)); | |
221 } | |
222 | |
223 void Reset(const ResetCallback& callback) override { | |
224 DVLOG(2) << "Reset"; | |
225 accelerator_->Reset(); | |
226 callback.Run(); | |
227 } | |
228 | |
229 private: | |
230 base::ThreadChecker thread_checker_; | |
231 GpuArcVideoService* const owner_; | |
232 scoped_ptr<ArcVideoAccelerator> accelerator_; | |
233 ::arc::VideoAcceleratorServiceClientPtr client_; | |
234 mojo::Binding<::arc::VideoAcceleratorService> binding_; | |
235 }; | |
236 | |
237 GpuArcVideoService::GpuArcVideoService( | |
238 mojo::InterfaceRequest<::arc::VideoHost> req) | |
Owen Lin
2016/03/14 08:45:52
s/req/request/ ?
kcwu
2016/03/14 12:55:49
Done.
| |
239 : binding_(this, std::move(req)) {} | |
240 | |
241 GpuArcVideoService::~GpuArcVideoService() {} | |
242 | |
243 void GpuArcVideoService::OnRequestArcVideoAcceleratorChannel( | |
244 uint32_t pid, | |
245 const OnRequestArcVideoAcceleratorChannelCallback& callback) { | |
246 DVLOG(1) << "OnRequestArcVideoAcceleratorChannelCallback"; | |
247 | |
248 mojo::edk::ScopedPlatformHandle child_handle = | |
249 mojo::edk::ChildProcessLaunched(RemapChildPid(pid)); | |
250 | |
251 MojoHandle wrapped_handle; | |
252 MojoResult wrap_result = mojo::edk::CreatePlatformHandleWrapper( | |
253 std::move(child_handle), &wrapped_handle); | |
254 if (wrap_result != MOJO_RESULT_OK) { | |
255 LOG(WARNING) << "Pipe failed to wrap handles. Closing: " << wrap_result; | |
256 callback.Run(mojo::ScopedHandle(), std::string()); | |
257 return; | |
258 } | |
259 | |
260 scoped_ptr<AcceleratorStub> stub(new AcceleratorStub(this)); | |
261 | |
262 std::string token = mojo::edk::GenerateRandomToken(); | |
263 if (!stub->Connect(token)) { | |
264 callback.Run(mojo::ScopedHandle(), std::string()); | |
265 return; | |
266 } | |
267 accelerator_stubs_[stub.get()] = std::move(stub); | |
268 | |
269 callback.Run(mojo::ScopedHandle(mojo::Handle(wrapped_handle)), token); | |
270 } | |
271 | |
272 void GpuArcVideoService::RemoveClient(AcceleratorStub* stub) { | |
273 accelerator_stubs_.erase(stub); | |
274 } | |
275 | |
276 } // namespace arc | |
277 } // namespace chromeos | |
OLD | NEW |