Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(457)

Side by Side Diff: content/common/gpu/media/gpu_jpeg_decode_accelerator.cc

Issue 1124423008: MJPEG acceleration for video capture using VAAPI, the GPU and IPC part (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@mjpeg-1-media
Patch Set: split out host part Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 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 "content/common/gpu/media/gpu_jpeg_decode_accelerator.h"
6
7 #include <stdint.h>
8
9 #include "base/bind.h"
10 #include "base/containers/hash_tables.h"
11 #include "base/logging.h"
12 #include "base/memory/shared_memory.h"
13 #include "base/single_thread_task_runner.h"
14 #include "base/stl_util.h"
15 #include "base/trace_event/trace_event.h"
16 #include "content/common/gpu/gpu_channel.h"
17 #include "content/common/gpu/gpu_messages.h"
18 #include "ipc/ipc_message_macros.h"
19 #include "ipc/message_filter.h"
20 #include "media/filters/jpeg_parser.h"
21 #include "ui/gfx/geometry/size.h"
22
23 #if defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY)
24 #include "content/common/gpu/media/vaapi_jpeg_decode_accelerator.h"
25 #endif
26
27 namespace {
28
29 void DecodeFinished(scoped_ptr<base::SharedMemory> shm) {
30 // Do nothing. Because VideoFrame is backed by |shm|, the purpose of this
31 // function is to just keep reference of |shm| to make sure it lives util
32 // decode finishes.
33 }
34
35 } // namespace
36
37 namespace content {
38
39 class GpuJpegDecodeAccelerator::Client
40 : public media::JpegDecodeAccelerator::Client,
41 public base::NonThreadSafe {
42 public:
43 Client(content::GpuJpegDecodeAccelerator* owner, int32 route_id)
44 : owner_(owner->AsWeakPtr()), route_id_(route_id) {}
45
46 ~Client() { DCHECK(CalledOnValidThread()); }
47
48 // media::JpegDecodeAccelerator::Client implementation.
49 void VideoFrameReady(int32_t bitstream_buffer_id) override {
50 DCHECK(CalledOnValidThread());
51 if (owner_)
52 owner_->NotifyDecodeStatus(route_id_, bitstream_buffer_id,
53 media::JpegDecodeAccelerator::NO_ERROR);
54 }
55
56 void NotifyError(int32_t bitstream_buffer_id,
57 media::JpegDecodeAccelerator::Error error) override {
58 DCHECK(CalledOnValidThread());
59 if (owner_)
60 owner_->NotifyDecodeStatus(route_id_, bitstream_buffer_id, error);
61 }
62
63 void Decode(const media::BitstreamBuffer& bitstream_buffer,
64 const scoped_refptr<media::VideoFrame>& video_frame) {
65 DCHECK(CalledOnValidThread());
66 DCHECK(accelerator_);
67 accelerator_->Decode(bitstream_buffer, video_frame);
68 }
69
70 void set_accelerator(scoped_ptr<media::JpegDecodeAccelerator> accelerator) {
71 DCHECK(CalledOnValidThread());
72 accelerator_ = accelerator.Pass();
73 }
74
75 private:
76 base::WeakPtr<content::GpuJpegDecodeAccelerator> owner_;
77 int32 route_id_;
78 scoped_ptr<media::JpegDecodeAccelerator> accelerator_;
79 };
80
81 // Create, destroy, and RemoveClient run on child thread. All other methods run
82 // on IO thread.
83 class GpuJpegDecodeAccelerator::MessageFilter : public IPC::MessageFilter {
84 public:
85 explicit MessageFilter(GpuJpegDecodeAccelerator* owner)
86 : owner_(owner->AsWeakPtr()),
87 child_task_runner_(owner_->child_task_runner_),
88 io_task_runner_(owner_->io_task_runner_) {}
89
90 void OnChannelError() override { sender_ = nullptr; }
91
92 void OnChannelClosing() override { sender_ = nullptr; }
93
94 void OnFilterAdded(IPC::Sender* sender) override { sender_ = sender; }
95
96 bool OnMessageReceived(const IPC::Message& msg) override {
97 const int32 route_id = msg.routing_id();
98 if (client_map_.find(route_id) == client_map_.end())
99 return false;
100
101 bool handled = true;
102 IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(MessageFilter, msg, &route_id)
103 IPC_MESSAGE_HANDLER(AcceleratedJpegDecoderMsg_Decode, OnDecodeOnIOThread)
104 IPC_MESSAGE_HANDLER(AcceleratedJpegDecoderMsg_Destroy,
105 OnDestroyOnIOThread)
106 IPC_MESSAGE_UNHANDLED(handled = false)
107 IPC_END_MESSAGE_MAP()
108 return handled;
109 }
110
111 bool SendOnIOThread(IPC::Message* message) {
112 DCHECK(!message->is_sync());
113 if (!sender_) {
114 delete message;
115 return false;
116 }
117 return sender_->Send(message);
118 }
119
120 void AddClientOnIOThread(int32 route_id,
121 Client* client,
122 IPC::Message* reply_msg) {
123 DCHECK(io_task_runner_->BelongsToCurrentThread());
124 DCHECK(client_map_.count(route_id) == 0);
125
126 client_map_[route_id] = client;
127 GpuMsg_CreateJpegDecoder::WriteReplyParams(reply_msg, true);
128 SendOnIOThread(reply_msg);
129 }
130
131 void OnDestroyOnIOThread(const int32* route_id) {
132 DCHECK(io_task_runner_->BelongsToCurrentThread());
133 const auto& it = client_map_.find(*route_id);
134 DCHECK(it != client_map_.end());
135 Client* client = it->second;
136 DCHECK(client);
137 client_map_.erase(it);
138
139 child_task_runner_->PostTask(
140 FROM_HERE, base::Bind(&MessageFilter::DestroyClient, this, client));
141 }
142
143 void DestroyClient(Client* client) {
144 DCHECK(child_task_runner_->BelongsToCurrentThread());
145 delete client;
146 if (owner_)
147 owner_->ClientRemoved();
148 }
149
150 void NotifyDecodeStatusOnIOThread(int32 route_id,
151 int32_t buffer_id,
152 media::JpegDecodeAccelerator::Error error) {
153 DCHECK(io_task_runner_->BelongsToCurrentThread());
154 SendOnIOThread(new AcceleratedJpegDecoderHostMsg_DecodeAck(
155 route_id, buffer_id, error));
156 }
157
158 void OnDecodeOnIOThread(
159 const int32* route_id,
160 const AcceleratedJpegDecoderMsg_Decode_Params& params) {
161 DCHECK(io_task_runner_->BelongsToCurrentThread());
162 DCHECK(route_id);
163 TRACE_EVENT0("jpeg", "GpuJpegDecodeAccelerator::MessageFilter::OnDecode");
164
165 // For handles in |params|, |params.output_video_frame_handle| is wrapped
166 // into scoper first. |params.input_buffer_handle| is closed manually for
167 // early exits.
168 scoped_ptr<base::SharedMemory> output_shm(
169 new base::SharedMemory(params.output_video_frame_handle, false));
170 if (!output_shm->Map(params.output_buffer_size)) {
171 LOG(ERROR) << "Could not map output shared memory for input buffer id "
172 << params.input_buffer_id;
173 NotifyDecodeStatusOnIOThread(
174 *route_id, params.input_buffer_id,
175 media::JpegDecodeAccelerator::PLATFORM_FAILURE);
176 base::SharedMemory::CloseHandle(params.input_buffer_handle);
177 return;
178 }
179
180 if (params.input_buffer_id < 0) {
181 LOG(ERROR) << "BitstreamBuffer id " << params.input_buffer_id
182 << " out of range";
183 NotifyDecodeStatusOnIOThread(
184 *route_id, params.input_buffer_id,
185 media::JpegDecodeAccelerator::INVALID_ARGUMENT);
186 base::SharedMemory::CloseHandle(params.input_buffer_handle);
187 return;
188 }
189
190 media::BitstreamBuffer input_buffer(params.input_buffer_id,
191 params.input_buffer_handle,
192 params.input_buffer_size);
193
194 uint8_t* shm_memory = static_cast<uint8_t*>(output_shm->memory());
195 scoped_refptr<media::VideoFrame> frame =
196 media::VideoFrame::WrapExternalSharedMemory(
197 media::VideoFrame::I420, // format
198 params.coded_size, // coded_size
199 gfx::Rect(params.coded_size), // visible_rect
200 params.coded_size, // natural_size
201 shm_memory, // data
202 params.output_buffer_size, // data_size
203 params.output_video_frame_handle, // handle
204 0, // data_offset
205 base::TimeDelta()); // timestamp
206 frame->AddDestructionObserver(
207 base::Bind(DecodeFinished, base::Passed(&output_shm)));
208
209 if (!frame.get()) {
210 LOG(ERROR) << "Could not create VideoFrame for input buffer id "
211 << params.input_buffer_id;
212 NotifyDecodeStatusOnIOThread(
213 *route_id, params.input_buffer_id,
214 media::JpegDecodeAccelerator::PLATFORM_FAILURE);
215 base::SharedMemory::CloseHandle(params.input_buffer_handle);
216 return;
217 }
218
219 DCHECK_GT(client_map_.count(*route_id), 0u);
220 Client* client = client_map_[*route_id];
221 client->Decode(input_buffer, frame);
222 }
223
224 protected:
225 ~MessageFilter() override {
226 if (client_map_.empty())
227 return;
228
229 if (child_task_runner_->BelongsToCurrentThread()) {
230 STLDeleteValues(&client_map_);
231 } else {
232 // Make sure |Client| are deleted on child thread.
233 scoped_ptr<ClientMap> client_map(new ClientMap);
234 client_map->swap(client_map_);
235
236 child_task_runner_->PostTask(
237 FROM_HERE,
238 base::Bind(&DeleteClientMapOnChildThread, base::Passed(&client_map)));
239 }
240 }
241
242 private:
243 using ClientMap = base::hash_map<int32, Client*>;
244
245 // Must be static because this method runs after destructor.
246 static void DeleteClientMapOnChildThread(scoped_ptr<ClientMap> client_map) {
247 STLDeleteValues(client_map.get());
248 }
249
250 base::WeakPtr<GpuJpegDecodeAccelerator> owner_;
251
252 // GPU child task runner.
253 scoped_refptr<base::SingleThreadTaskRunner> child_task_runner_;
254
255 // GPU IO task runner.
256 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
257
258 // The sender to which this filter was added.
259 IPC::Sender* sender_;
260
261 // A map from route id to JpegDecodeAccelerator.
262 // Unless in destructor (maybe on child thread), |client_map_| should
263 // only be accessed on IO thread.
264 ClientMap client_map_;
265 };
266
267 GpuJpegDecodeAccelerator::GpuJpegDecodeAccelerator(
268 GpuChannel* channel,
269 const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner)
270 : channel_(channel),
271 child_task_runner_(base::ThreadTaskRunnerHandle::Get()),
272 io_task_runner_(io_task_runner),
273 client_number_(0) {
274 }
275
276 GpuJpegDecodeAccelerator::~GpuJpegDecodeAccelerator() {
277 DCHECK(CalledOnValidThread());
278 if (filter_) {
279 channel_->RemoveFilter(filter_.get());
280 }
281 }
282
283 void GpuJpegDecodeAccelerator::AddClient(int32 route_id,
284 IPC::Message* reply_msg) {
285 DCHECK(CalledOnValidThread());
286 scoped_ptr<media::JpegDecodeAccelerator> accelerator;
287
288 // When adding more platforms, GpuJpegDecoder::Supported need
289 // update as well.
290 #if defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY)
291 accelerator.reset(new VaapiJpegDecodeAccelerator(io_task_runner_));
292 #else
293 DVLOG(1) << "HW JPEG decode acceleration not available.";
294 #endif
295
296 scoped_ptr<Client> client(new Client(this, route_id));
297 if (!accelerator.get() || !accelerator->Initialize(client.get())) {
298 DLOG(ERROR) << "JPEG accelerator Initialize failed";
299 GpuMsg_CreateJpegDecoder::WriteReplyParams(reply_msg, false);
300 Send(reply_msg);
301 return;
302 }
303 client->set_accelerator(accelerator.Pass());
304
305 if (!filter_) {
306 DCHECK_EQ(client_number_, 0);
307 filter_ = new MessageFilter(this);
308 // This should be before AddClientOnIOThread.
309 channel_->AddFilter(filter_.get());
310 }
311 client_number_++;
312
313 // In this PostTask, |client| may leak if |io_task_runner_| is destroyed
314 // before |client| reached AddClientOnIOThread. However we cannot use scoper
315 // to protect it because |client| can only be deleted on child thread. The IO
316 // thread is destroyed at termination, at which point it's ok to leak since
317 // we're going to tear down the process anyway. So we just crossed fingers
318 // here instead of making the code unnecessary complicated.
319 io_task_runner_->PostTask(
320 FROM_HERE, base::Bind(&MessageFilter::AddClientOnIOThread, filter_,
321 route_id, client.release(), reply_msg));
322 }
323
324 void GpuJpegDecodeAccelerator::NotifyDecodeStatus(
325 int32 route_id,
326 int32_t buffer_id,
327 media::JpegDecodeAccelerator::Error error) {
328 DCHECK(CalledOnValidThread());
329 Send(new AcceleratedJpegDecoderHostMsg_DecodeAck(route_id, buffer_id, error));
330 }
331
332 void GpuJpegDecodeAccelerator::ClientRemoved() {
333 DCHECK(CalledOnValidThread());
334 DCHECK_GT(client_number_, 0);
335 client_number_--;
336 if (client_number_ == 0) {
337 channel_->RemoveFilter(filter_.get());
338 filter_ = nullptr;
339 }
340 }
341
342 bool GpuJpegDecodeAccelerator::Send(IPC::Message* message) {
343 DCHECK(CalledOnValidThread());
344 return channel_->Send(message);
345 }
346
347 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698