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

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: gpu_jpeg_decode_accelerator.cc filter to dispatch decode task 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/logging.h"
11 #include "base/memory/shared_memory.h"
12 #include "base/single_thread_task_runner.h"
13 #include "base/trace_event/trace_event.h"
14 #include "content/common/gpu/gpu_channel.h"
15 #include "content/common/gpu/gpu_messages.h"
16 #include "ipc/ipc_message_macros.h"
17 #include "ipc/message_filter.h"
18 #include "media/filters/jpeg_parser.h"
19 #include "ui/gfx/geometry/size.h"
20
21 #if defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY)
22 #include "content/common/gpu/media/vaapi_jpeg_decode_accelerator.h"
23 #endif
24
25 namespace {
26
27 void DecodeFinished(scoped_ptr<base::SharedMemory> shm) {
28 // Do nothing. Because VideoFrame is backed by |shm|, the purpose of this
29 // function is to just keep reference of |shm| to make sure it lives util
30 // decode finishes.
31 }
32
33 } // namespace
34
35 namespace content {
36
37 class GpuJpegDecodeAccelerator::Client
38 : public media::JpegDecodeAccelerator::Client {
39 public:
40 Client(content::GpuJpegDecodeAccelerator* owner, int32 route_id)
41 : owner_(owner), route_id_(route_id) {}
42
43 // media::JpegDecodeAccelerator::Client implementation.
44 void VideoFrameReady(int32_t bitstream_buffer_id) override {
45 owner_->NotifyDecodeStatus(route_id_, bitstream_buffer_id,
46 media::JpegDecodeAccelerator::NO_ERROR);
47 }
48
49 void NotifyError(int32_t bitstream_buffer_id,
50 media::JpegDecodeAccelerator::Error error) override {
51 owner_->NotifyDecodeStatus(route_id_, bitstream_buffer_id, error);
52 }
53
54 void set_accelerator(scoped_ptr<media::JpegDecodeAccelerator> accelerator) {
55 accelerator_ = accelerator.Pass();
56 }
57
58 private:
59 content::GpuJpegDecodeAccelerator* owner_;
60 int32 route_id_;
61 scoped_ptr<media::JpegDecodeAccelerator> accelerator_;
62 };
63
64 class GpuJpegDecodeAccelerator::MessageFilter : public IPC::MessageFilter {
65 public:
66 MessageFilter(GpuJpegDecodeAccelerator* owner) : owner_(owner) {}
piman 2015/05/26 23:31:53 nit: explicit.
kcwu 2015/05/27 14:13:23 Done.
67
68 void OnChannelError() override { sender_ = NULL; }
69
70 void OnChannelClosing() override { sender_ = NULL; }
71
72 void OnFilterAdded(IPC::Sender* sender) override { sender_ = sender; }
73
74 bool OnMessageReceived(const IPC::Message& msg) override {
75 const int32 route_id = msg.routing_id();
76 if (!accelerator_map_.Lookup(route_id))
77 return false;
78
79 bool handled = true;
80 IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(MessageFilter, msg, &route_id)
81 IPC_MESSAGE_HANDLER(AcceleratedJpegDecoderMsg_Decode, OnDecodeOnIOThread)
82 IPC_MESSAGE_HANDLER(AcceleratedJpegDecoderMsg_Destroy,
83 OnDestroyOnIOThread)
84 IPC_MESSAGE_UNHANDLED(handled = false)
85 IPC_END_MESSAGE_MAP()
86 return handled;
87 }
88
89 bool SendOnIOThread(IPC::Message* message) {
90 DCHECK(!message->is_sync());
91 if (!sender_) {
92 delete message;
93 return false;
94 }
95 return sender_->Send(message);
96 }
97
98 void AddClientOnIOThread(int32 route_id,
99 media::JpegDecodeAccelerator* accelerator,
100 IPC::Message* reply_msg) {
101 DCHECK(owner_->io_task_runner_->BelongsToCurrentThread());
102 DCHECK(!accelerator_map_.Lookup(route_id));
103
104 accelerator_map_.AddWithID(accelerator, route_id);
105 GpuMsg_CreateJpegDecoder::WriteReplyParams(reply_msg, true);
106 SendOnIOThread(reply_msg);
107 }
108
109 void OnDestroyOnIOThread(const int32* route_id) {
110 DCHECK(owner_->io_task_runner_->BelongsToCurrentThread());
111 accelerator_map_.Remove(*route_id);
112
113 owner_->child_task_runner_->PostTask(
114 FROM_HERE, base::Bind(&GpuJpegDecodeAccelerator::RemoveClient,
115 base::Unretained(owner_), *route_id));
piman 2015/05/26 23:31:53 The GpuJpegDecodeAccelerator could be destroyed be
kcwu 2015/05/27 14:13:23 Done.Thanks for your detail suggestion. However a
piman 2015/05/27 21:08:40 I would prefer if you didn't wait there. I don't t
wuchengli 2015/05/28 03:41:39 GpuJpegDecodeAccelerator owns the filter. When GJD
kcwu 2015/05/28 12:10:26 Done. I made ~GpuJpegDecodeAccelerator waiting for
116 }
117
118 void NotifyDecodeStatusOnIOThread(int32 route_id,
119 int32_t buffer_id,
120 media::JpegDecodeAccelerator::Error error) {
121 DCHECK(owner_->io_task_runner_->BelongsToCurrentThread());
122 SendOnIOThread(new AcceleratedJpegDecoderHostMsg_DecodeAck(
123 route_id, buffer_id, error));
124 }
125
126 void OnDecodeOnIOThread(
127 const int32* route_id,
128 const AcceleratedJpegDecoderMsg_Decode_Params& params) {
129 DCHECK(owner_->io_task_runner_->BelongsToCurrentThread());
130 DCHECK(route_id);
131 TRACE_EVENT0("jpeg", "GpuJpegDecodeAccelerator::MessageFilter::OnDecode");
132
133 if (params.input_buffer_id < 0) {
134 LOG(ERROR) << "BitstreamBuffer id " << params.input_buffer_id
135 << " out of range";
136 NotifyDecodeStatusOnIOThread(
137 *route_id, params.input_buffer_id,
138 media::JpegDecodeAccelerator::INVALID_ARGUMENT);
139 return;
140 }
141
142 media::BitstreamBuffer input_buffer(params.input_buffer_id,
143 params.input_buffer_handle,
144 params.input_buffer_size);
145
146 scoped_ptr<base::SharedMemory> output_shm(
147 new base::SharedMemory(params.output_video_frame_handle, false));
148 if (!output_shm->Map(params.output_buffer_size)) {
149 LOG(ERROR) << "Could not map output shared memory for input buffer id "
150 << params.input_buffer_id;
151 NotifyDecodeStatusOnIOThread(
152 *route_id, params.input_buffer_id,
153 media::JpegDecodeAccelerator::PLATFORM_FAILURE);
154 return;
155 }
156
157 uint8* shm_memory = reinterpret_cast<uint8*>(output_shm->memory());
158 scoped_refptr<media::VideoFrame> frame =
159 media::VideoFrame::WrapExternalPackedMemory(
160 media::VideoFrame::I420,
161 params.coded_size,
162 gfx::Rect(params.coded_size),
163 params.coded_size,
164 shm_memory,
165 params.output_buffer_size,
166 params.output_video_frame_handle,
167 0,
168 base::TimeDelta(),
169 base::Bind(DecodeFinished, base::Passed(&output_shm)));
170
171 if (!frame.get()) {
172 LOG(ERROR) << "Could not create VideoFrame for input buffer id "
173 << params.input_buffer_id;
174 NotifyDecodeStatusOnIOThread(
175 *route_id, params.input_buffer_id,
176 media::JpegDecodeAccelerator::PLATFORM_FAILURE);
177 return;
178 }
179
180 media::JpegDecodeAccelerator* accelerator =
181 accelerator_map_.Lookup(*route_id);
182 DCHECK(accelerator);
183 accelerator->Decode(input_buffer, frame);
184 }
185
186 protected:
187 virtual ~MessageFilter() {}
188
189 private:
190 GpuJpegDecodeAccelerator* owner_;
191
192 // The sender to which this filter was added.
193 IPC::Sender* sender_;
194
195 // A map from route id to JpegDecodeAccelerator.
196 // This doesn't take ownership. The ownership is still maintained by
197 // GpuJpegDecodeAccelerator on child thread.
198 IDMap<media::JpegDecodeAccelerator, IDMapExternalPointer> accelerator_map_;
199 };
200
201 GpuJpegDecodeAccelerator::GpuJpegDecodeAccelerator(
202 GpuChannel* channel,
203 const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner)
204 : channel_(channel),
205 filter_(new MessageFilter(this)),
206 child_task_runner_(base::ThreadTaskRunnerHandle::Get()),
207 io_task_runner_(io_task_runner) {
208 }
209
210 GpuJpegDecodeAccelerator::~GpuJpegDecodeAccelerator() {
211 DCHECK(CalledOnValidThread());
212 DCHECK(client_map_.IsEmpty());
213 }
214
215 bool GpuJpegDecodeAccelerator::OnMessageReceived(const IPC::Message& msg) {
216 // Messages are actually handled in filter on IO thread.
217 return false;
218 }
219
220 void GpuJpegDecodeAccelerator::AddClient(int32 route_id,
221 IPC::Message* reply_msg) {
222 DCHECK(CalledOnValidThread());
223 scoped_ptr<media::JpegDecodeAccelerator> accelerator;
224
225 // When adding more platforms, GpuJpegDecoder::Supported need
226 // update as well.
227 #if defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY)
228 accelerator.reset(new VaapiJpegDecodeAccelerator(io_task_runner_));
229 #else
230 DVLOG(1) << "HW JPEG decode acceleration not available.";
231 #endif
232
233 scoped_ptr<Client> client(new Client(this, route_id));
234 if (!accelerator.get() || !accelerator->Initialize(client.get())) {
235 DLOG(ERROR) << "JPEG accelerator Initialize failed";
236 GpuMsg_CreateJpegDecoder::WriteReplyParams(reply_msg, false);
237 Send(reply_msg);
238 return;
239 }
240
241 if (client_map_.IsEmpty())
242 channel_->AddFilter(filter_.get());
243
244 io_task_runner_->PostTask(
245 FROM_HERE, base::Bind(&MessageFilter::AddClientOnIOThread, filter_,
246 route_id, accelerator.get(), reply_msg));
247
248 client->set_accelerator(accelerator.Pass());
249 client_map_.AddWithID(client.release(), route_id);
250 }
251
252 void GpuJpegDecodeAccelerator::NotifyDecodeStatus(
253 int32 route_id,
254 int32_t buffer_id,
255 media::JpegDecodeAccelerator::Error error) {
256 DCHECK(CalledOnValidThread());
257 Send(new AcceleratedJpegDecoderHostMsg_DecodeAck(route_id, buffer_id, error));
258 }
259
260 void GpuJpegDecodeAccelerator::RemoveClient(int32 route_id) {
261 DCHECK(CalledOnValidThread());
262
263 client_map_.Remove(route_id);
264 if (client_map_.IsEmpty())
265 channel_->RemoveFilter(filter_.get());
266 }
267
268 bool GpuJpegDecodeAccelerator::Send(IPC::Message* message) {
269 DCHECK(CalledOnValidThread());
270 return channel_->Send(message);
271 }
272
273 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698