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

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: Created 5 years, 7 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 <map>
10
11 #include "base/bind.h"
12 #include "base/logging.h"
13 #include "base/memory/shared_memory.h"
14 #include "base/single_thread_task_runner.h"
15 #include "base/stl_util.h"
16 #include "base/trace_event/trace_event.h"
17 #include "content/common/gpu/gpu_channel.h"
18 #include "content/common/gpu/gpu_messages.h"
19 #include "ipc/ipc_message_macros.h"
20 #include "ipc/message_filter.h"
21 #include "media/filters/jpeg_parser.h"
22 #include "ui/gfx/geometry/size.h"
23
24 #if defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY)
25 #include "content/common/gpu/media/vaapi_jpeg_decode_accelerator.h"
26 #endif
27
28 namespace {
29
30 void DecodeFinished(scoped_ptr<base::SharedMemory> shm) {
31 // Do nothing. Because VideoFrame is backed by |shm|, the purpose of this
32 // function is to just keep reference of |shm| to make sure it lives util
33 // decode finishes.
34 }
35
36 } // namespace
37
38 namespace content {
39
40 class GpuJpegDecodeAccelerator::Client
41 : public media::JpegDecodeAccelerator::Client {
42 public:
43 Client(content::GpuJpegDecodeAccelerator* owner, int32 route_id)
44 : owner_(owner->AsWeakPtr()), route_id_(route_id) {}
45
46 // media::JpegDecodeAccelerator::Client implementation.
47 void VideoFrameReady(int32_t bitstream_buffer_id) override {
48 if (owner_)
49 owner_->NotifyDecodeStatus(route_id_, bitstream_buffer_id,
50 media::JpegDecodeAccelerator::NO_ERROR);
51 }
52
53 void NotifyError(int32_t bitstream_buffer_id,
54 media::JpegDecodeAccelerator::Error error) override {
55 if (owner_)
56 owner_->NotifyDecodeStatus(route_id_, bitstream_buffer_id, error);
57 }
58
59 void Decode(const media::BitstreamBuffer& bitstream_buffer,
60 const scoped_refptr<media::VideoFrame>& video_frame) {
61 DCHECK(accelerator_);
62 accelerator_->Decode(bitstream_buffer, video_frame);
63 }
64
65 void set_accelerator(scoped_ptr<media::JpegDecodeAccelerator> accelerator) {
66 accelerator_ = accelerator.Pass();
67 }
68
69 private:
70 base::WeakPtr<content::GpuJpegDecodeAccelerator> owner_;
71 int32 route_id_;
72 scoped_ptr<media::JpegDecodeAccelerator> accelerator_;
73 };
74
75 // Create, destroy, and RemoveClient run on child thread. All other methods run
76 // on IO thread.
77 class GpuJpegDecodeAccelerator::MessageFilter : public IPC::MessageFilter {
78 public:
79 explicit MessageFilter(GpuJpegDecodeAccelerator* owner)
80 : owner_(owner->AsWeakPtr()),
81 child_task_runner_(owner_->child_task_runner_),
82 io_task_runner_(owner_->io_task_runner_) {}
83
84 void OnChannelError() override { sender_ = NULL; }
Pawel Osciak 2015/05/28 09:13:17 s/NULL/nullptr/ here and in other places.
kcwu 2015/05/28 12:10:27 Done.
85
86 void OnChannelClosing() override { sender_ = NULL; }
87
88 void OnFilterAdded(IPC::Sender* sender) override { sender_ = sender; }
89
90 bool OnMessageReceived(const IPC::Message& msg) override {
91 const int32 route_id = msg.routing_id();
92 if (client_map_.count(route_id) == 0)
93 return false;
94
95 bool handled = true;
96 IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(MessageFilter, msg, &route_id)
97 IPC_MESSAGE_HANDLER(AcceleratedJpegDecoderMsg_Decode, OnDecodeOnIOThread)
98 IPC_MESSAGE_HANDLER(AcceleratedJpegDecoderMsg_Destroy,
99 OnDestroyOnIOThread)
100 IPC_MESSAGE_UNHANDLED(handled = false)
101 IPC_END_MESSAGE_MAP()
102 return handled;
103 }
104
105 bool SendOnIOThread(IPC::Message* message) {
106 DCHECK(!message->is_sync());
107 if (!sender_) {
108 delete message;
109 return false;
110 }
111 return sender_->Send(message);
112 }
113
114 void AddClientOnIOThread(int32 route_id,
115 Client* client,
116 IPC::Message* reply_msg) {
117 DCHECK(io_task_runner_->BelongsToCurrentThread());
118 DCHECK(client_map_.count(route_id) == 0);
119
120 client_map_[route_id] = client;
121 GpuMsg_CreateJpegDecoder::WriteReplyParams(reply_msg, true);
122 SendOnIOThread(reply_msg);
123 }
124
125 void OnDestroyOnIOThread(const int32* route_id) {
126 DCHECK(io_task_runner_->BelongsToCurrentThread());
127 const auto& it = client_map_.find(*route_id);
128 DCHECK(it != client_map_.end());
Pawel Osciak 2015/05/28 09:13:17 DCHECK_NE
kcwu 2015/05/28 12:10:27 DCHECK_NE is not for iterator. The arguments need
129 Client* client = it->second;
130 DCHECK(client);
131 client_map_.erase(it);
132
133 child_task_runner_->PostTask(
134 FROM_HERE, base::Bind(&MessageFilter::DestroyClient, this, client));
135 }
136
137 void DestroyClient(Client* client) {
138 DCHECK(child_task_runner_->BelongsToCurrentThread());
139 delete client;
140 if (owner_)
141 owner_->ClientRemoved();
142 }
143
144 void NotifyDecodeStatusOnIOThread(int32 route_id,
145 int32_t buffer_id,
146 media::JpegDecodeAccelerator::Error error) {
147 DCHECK(io_task_runner_->BelongsToCurrentThread());
148 SendOnIOThread(new AcceleratedJpegDecoderHostMsg_DecodeAck(
149 route_id, buffer_id, error));
150 }
151
152 void OnDecodeOnIOThread(
153 const int32* route_id,
154 const AcceleratedJpegDecoderMsg_Decode_Params& params) {
155 DCHECK(io_task_runner_->BelongsToCurrentThread());
156 DCHECK(route_id);
157 TRACE_EVENT0("jpeg", "GpuJpegDecodeAccelerator::MessageFilter::OnDecode");
158
159 if (params.input_buffer_id < 0) {
160 LOG(ERROR) << "BitstreamBuffer id " << params.input_buffer_id
161 << " out of range";
162 NotifyDecodeStatusOnIOThread(
163 *route_id, params.input_buffer_id,
164 media::JpegDecodeAccelerator::INVALID_ARGUMENT);
165 return;
166 }
167
168 media::BitstreamBuffer input_buffer(params.input_buffer_id,
169 params.input_buffer_handle,
170 params.input_buffer_size);
171
172 scoped_ptr<base::SharedMemory> output_shm(
173 new base::SharedMemory(params.output_video_frame_handle, false));
174 if (!output_shm->Map(params.output_buffer_size)) {
175 LOG(ERROR) << "Could not map output shared memory for input buffer id "
176 << params.input_buffer_id;
177 NotifyDecodeStatusOnIOThread(
178 *route_id, params.input_buffer_id,
179 media::JpegDecodeAccelerator::PLATFORM_FAILURE);
180 return;
181 }
182
183 uint8* shm_memory = reinterpret_cast<uint8*>(output_shm->memory());
184 scoped_refptr<media::VideoFrame> frame =
185 media::VideoFrame::WrapExternalPackedMemory(
186 media::VideoFrame::I420,
187 params.coded_size,
188 gfx::Rect(params.coded_size),
189 params.coded_size,
190 shm_memory,
191 params.output_buffer_size,
192 params.output_video_frame_handle,
193 0,
194 base::TimeDelta(),
195 base::Bind(DecodeFinished, base::Passed(&output_shm)));
196
197 if (!frame.get()) {
198 LOG(ERROR) << "Could not create VideoFrame for input buffer id "
199 << params.input_buffer_id;
200 NotifyDecodeStatusOnIOThread(
201 *route_id, params.input_buffer_id,
202 media::JpegDecodeAccelerator::PLATFORM_FAILURE);
203 return;
204 }
205
206 DCHECK(client_map_.count(*route_id) > 0);
Pawel Osciak 2015/05/28 09:13:17 DCHECK_GT
kcwu 2015/05/28 12:10:27 Done.
207 Client* client = client_map_[*route_id];
208 client->Decode(input_buffer, frame);
209 }
210
211 protected:
212 ~MessageFilter() override {
213 // Make sure |client_map_| is deleted on child thread.
214 DCHECK(child_task_runner_->BelongsToCurrentThread());
kcwu 2015/05/27 14:13:23 The ownership of |Client| is maintained by the fil
piman 2015/05/27 21:08:40 Correct, it could be deleted on either the child t
215 STLDeleteValues(&client_map_);
216 }
217
218 private:
219 base::WeakPtr<GpuJpegDecodeAccelerator> owner_;
220
221 // GPU child task runner.
222 scoped_refptr<base::SingleThreadTaskRunner> child_task_runner_;
223
224 // GPU IO task runner.
225 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
226
227 // The sender to which this filter was added.
228 IPC::Sender* sender_;
229
230 // A map from route id to JpegDecodeAccelerator.
231 // Unless in destructor (on child thread), |client_map_| should only be
232 // accessed on IO thread.
233 std::map<int32, Client*> client_map_;
Pawel Osciak 2015/05/28 09:13:17 Could we use a scoper?
kcwu 2015/05/28 12:10:27 Scoper implys it will automatically delete Client
234 };
235
236 GpuJpegDecodeAccelerator::GpuJpegDecodeAccelerator(
237 GpuChannel* channel,
238 const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner)
239 : channel_(channel),
240 child_task_runner_(base::ThreadTaskRunnerHandle::Get()),
241 io_task_runner_(io_task_runner),
242 client_number_(0) {
243 }
244
245 GpuJpegDecodeAccelerator::~GpuJpegDecodeAccelerator() {
246 DCHECK(CalledOnValidThread());
247 if (client_number_ > 0)
248 channel_->RemoveFilter(filter_.get());
249 }
250
251 bool GpuJpegDecodeAccelerator::OnMessageReceived(const IPC::Message& msg) {
252 // Messages are actually handled in filter on IO thread.
253 return false;
254 }
255
256 void GpuJpegDecodeAccelerator::AddClient(int32 route_id,
257 IPC::Message* reply_msg) {
258 DCHECK(CalledOnValidThread());
259 scoped_ptr<media::JpegDecodeAccelerator> accelerator;
260
261 // When adding more platforms, GpuJpegDecoder::Supported need
262 // update as well.
263 #if defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY)
264 accelerator.reset(new VaapiJpegDecodeAccelerator(io_task_runner_));
265 #else
266 DVLOG(1) << "HW JPEG decode acceleration not available.";
267 #endif
268
269 scoped_ptr<Client> client(new Client(this, route_id));
270 if (!accelerator.get() || !accelerator->Initialize(client.get())) {
271 DLOG(ERROR) << "JPEG accelerator Initialize failed";
272 GpuMsg_CreateJpegDecoder::WriteReplyParams(reply_msg, false);
273 Send(reply_msg);
274 return;
275 }
276 client->set_accelerator(accelerator.Pass());
277
278 if (client_number_ == 0) {
279 filter_ = new MessageFilter(this);
280 // This should be before AddClientOnIOThread.
281 channel_->AddFilter(filter_.get());
282 }
283 client_number_++;
284
285 io_task_runner_->PostTask(
286 FROM_HERE, base::Bind(&MessageFilter::AddClientOnIOThread, filter_,
287 route_id, client.release(), reply_msg));
288 }
289
290 void GpuJpegDecodeAccelerator::NotifyDecodeStatus(
291 int32 route_id,
292 int32_t buffer_id,
293 media::JpegDecodeAccelerator::Error error) {
294 DCHECK(CalledOnValidThread());
295 Send(new AcceleratedJpegDecoderHostMsg_DecodeAck(route_id, buffer_id, error));
296 }
297
298 void GpuJpegDecodeAccelerator::ClientRemoved() {
299 DCHECK(CalledOnValidThread());
300 DCHECK_GT(client_number_, 0);
301 client_number_--;
302 if (client_number_ == 0) {
303 channel_->RemoveFilter(filter_.get());
304 filter_ = nullptr;
305 }
306 }
307
308 bool GpuJpegDecodeAccelerator::Send(IPC::Message* message) {
309 DCHECK(CalledOnValidThread());
310 return channel_->Send(message);
311 }
312
313 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698