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

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

Issue 1016773002: MJPEG acceleration for video capture using VAAPI (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fix coded size, shm handle Created 5 years, 9 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/vaapi_jpeg_decode_accelerator.h"
6
7 #include "base/bind.h"
8 #include "base/logging.h"
9 #include "base/metrics/histogram.h"
10 #include "base/stl_util.h"
11 #include "base/strings/string_util.h"
12 #include "base/synchronization/waitable_event.h"
13 #include "content/common/gpu/gpu_channel.h"
14 #include "content/common/gpu/media/vaapi_picture.h"
15 #include "media/base/bind_to_current_loop.h"
16 #include "media/base/video_frame.h"
17 #include "media/filters/jpeg_parser.h"
18 #include "media/video/picture.h"
19 #include "ui/gl/gl_bindings.h"
20
21 static void ReportVaapiError() {
22 }
23
24 namespace content {
25
26 #define RETURN_AND_NOTIFY_ON_FAILURE(result, log, buffer_id, error_code, ret) \
27 do { \
28 if (!(result)) { \
29 LOG(ERROR) << log; \
30 NotifyError(buffer_id, error_code); \
31 return ret; \
32 } \
33 } while (0)
34
35 // XXX
36 #undef DLOG
37 #define DLOG LOG
38
39 VaapiJpegDecodeAccelerator::InputBuffer::InputBuffer() : id(0), size(0) {
40 }
41
42 VaapiJpegDecodeAccelerator::InputBuffer::~InputBuffer() {
43 }
44
45 void VaapiJpegDecodeAccelerator::NotifyError(int32_t bitstream_buffer_id,
46 Error error) {
47 if (message_loop_ != base::MessageLoop::current()) {
48 DCHECK(decoder_thread_proxy_->BelongsToCurrentThread());
49 message_loop_->PostTask(FROM_HERE,
50 base::Bind(&VaapiJpegDecodeAccelerator::NotifyError,
51 weak_this_,
52 bitstream_buffer_id,
53 error));
54 return;
55 }
56
57 // Post Cleanup() as a task so we don't recursively acquire lock_.
58 message_loop_->PostTask(FROM_HERE, base::Bind(
59 &VaapiJpegDecodeAccelerator::Cleanup, weak_this_));
60
61 LOG(ERROR) << "Notifying of error " << error;
62 if (client_) {
63 client_->NotifyError(bitstream_buffer_id, error);
64 client_ptr_factory_.reset();
65 }
66 }
67
68 VaapiJpegDecodeAccelerator::VaapiJpegDecodeAccelerator()
69 : state_(kUninitialized),
70 input_ready_(&lock_),
71 message_loop_(base::MessageLoop::current()),
72 decoder_thread_("VaapiDecoderThread"),
73 weak_this_factory_(this) {
74 weak_this_ = weak_this_factory_.GetWeakPtr();
75 }
76
77 VaapiJpegDecodeAccelerator::~VaapiJpegDecodeAccelerator() {
78 DCHECK_EQ(message_loop_, base::MessageLoop::current());
79 }
80
81 bool VaapiJpegDecodeAccelerator::Initialize(Client* client) {
82 DCHECK_EQ(message_loop_, base::MessageLoop::current());
83
84 client_ptr_factory_.reset(new base::WeakPtrFactory<Client>(client));
85 client_ = client_ptr_factory_->GetWeakPtr();
86
87 base::AutoLock auto_lock(lock_);
88 DCHECK_EQ(state_, kUninitialized);
89
90 vaapi_wrapper_ = VaapiWrapper::Create(
91 VaapiWrapper::kDecode, VAProfileJPEGBaseline,
92 base::Bind(&ReportVaapiError));
93
94 if (!vaapi_wrapper_.get()) {
95 LOG(ERROR) << "Failed initializing VAAPI";
wuchengli 2015/03/23 06:30:15 DLOG
kcwu 2015/04/14 20:02:34 Done.
96 return false;
97 }
98
99 CHECK(decoder_thread_.Start());
100 decoder_thread_proxy_ = decoder_thread_.message_loop_proxy();
101
102 return true;
103 }
104
105 bool VaapiJpegDecodeAccelerator::OutputPicture(
106 VASurfaceID va_surface_id,
107 int32_t input_id,
108 const scoped_refptr<media::VideoFrame>& video_frame) {
109 DCHECK_EQ(message_loop_, base::MessageLoop::current());
110
111 DVLOG(3) << "Outputting VASurface " << va_surface_id
112 << " into video_frame associate to input buffer id " << input_id;
113
114 #if 0
115 RETURN_AND_NOTIFY_ON_FAILURE(picture->DownloadFromSurface(va_surface),
116 "Failed putting surface into pixmap",
117 input_id,
118 PLATFORM_FAILURE, );
119 #endif
120 VAImage image;
121 VAImageFormat format;
122 const uint32_t kI420Fourcc = VA_FOURCC('I', '4', '2', '0');
123 memset(&image, 0, sizeof(image));
124 memset(&format, 0, sizeof(format));
125 format.fourcc = kI420Fourcc;
126 format.byte_order = VA_LSB_FIRST;
127 format.bits_per_pixel = 12; // 12 for I420
128
129 void* mem;
130 gfx::Size coded_size = video_frame->coded_size();
131 if (!vaapi_wrapper_->GetVaImage(
132 va_surface_id, &format, coded_size, &image, &mem)) {
133 LOG(ERROR) << "Cannot get VAImage";
134 return false;
135 }
136
137 uint8* frame_mem = video_frame->data(media::VideoFrame::kYPlane);
138 size_t frame_buffer_size =
139 media::VideoFrame::AllocationSize(media::VideoFrame::I420, coded_size);
140 memcpy(frame_mem, mem, frame_buffer_size);
141
142 vaapi_wrapper_->ReturnVaImage(&image);
143
144 if (client_)
145 client_->VideoFrameReady(input_id);
146
147 return true;
148 }
149
150 void VaapiJpegDecodeAccelerator::MapAndQueueNewInputBuffer(
151 const media::BitstreamBuffer& bitstream_buffer,
152 const scoped_refptr<media::VideoFrame>& video_frame) {
153 DCHECK_EQ(message_loop_, base::MessageLoop::current());
154
155 DVLOG(4) << "Mapping new input buffer id: " << bitstream_buffer.id()
156 << " size: " << (int)bitstream_buffer.size();
157
158 scoped_ptr<base::SharedMemory> shm(
159 new base::SharedMemory(bitstream_buffer.handle(), true));
160 RETURN_AND_NOTIFY_ON_FAILURE(shm->Map(bitstream_buffer.size()),
161 "Failed to map input buffer",
162 bitstream_buffer.id(),
163 UNREADABLE_INPUT,);
164
165 base::AutoLock auto_lock(lock_);
166
167 // Set up a new input buffer and queue it for later.
168 linked_ptr<InputBuffer> input_buffer(new InputBuffer());
169 input_buffer->shm.reset(shm.release());
170 input_buffer->id = bitstream_buffer.id();
171 input_buffer->size = bitstream_buffer.size();
172 input_buffer->video_frame = video_frame;
173
174 input_buffers_.push(input_buffer);
175 input_ready_.Signal();
176 }
177
178 bool VaapiJpegDecodeAccelerator::GetInputBuffer_Locked() {
179 DCHECK(decoder_thread_proxy_->BelongsToCurrentThread());
180 lock_.AssertAcquired();
181
182 if (curr_input_buffer_.get())
183 return true;
184
185 // Will only wait if it is expected that in current state new buffers will
186 // be queued from the client via Decode(). The state can change during wait.
187 while (input_buffers_.empty() && (state_ == kDecoding || state_ == kIdle)) {
188 input_ready_.Wait();
189 }
190
191 // We could have got woken up in a different state or never got to sleep
192 // due to current state; check for that.
193 switch (state_) {
194 case kDecoding:
195 case kIdle:
196 DCHECK(!input_buffers_.empty());
197
198 curr_input_buffer_ = input_buffers_.front();
199 input_buffers_.pop();
200
201 DVLOG(4) << "New current bitstream buffer, id: "
202 << curr_input_buffer_->id
203 << " size: " << curr_input_buffer_->size;
204
205 return true;
206
207 default:
208 // We got woken up due to being destroyed/reset, ignore any already
209 // queued inputs.
210 return false;
211 }
212 }
213
214 void VaapiJpegDecodeAccelerator::DecodeTask() {
215 DCHECK(decoder_thread_proxy_->BelongsToCurrentThread());
216 base::AutoLock auto_lock(lock_);
217
218 if (state_ != kDecoding)
219 return;
220
221 if (GetInputBuffer_Locked()) {
222 DCHECK(curr_input_buffer_.get());
223
224 do {
225 base::AutoUnlock auto_unlock(lock_);
226
227 media::JpegParseResult parse_result;
228
229 if (!media::ParseJpegPicture(
230 reinterpret_cast<const uint8_t*>(curr_input_buffer_->shm->memory()),
231 curr_input_buffer_->size,
232 &parse_result)) {
233 NotifyError(curr_input_buffer_->id,
234 media::JpegDecodeAccelerator::PARSE_JPEG_FAILED);
235 break;
236 }
237
238 gfx::Size coded_size(parse_result.frame_header.coded_width,
239 parse_result.frame_header.coded_height);
240
241 vaapi_wrapper_->DestroySurfaces(); // XXX assume one frame at a time
242 std::vector<VASurfaceID> va_surfaces;
243 if (!vaapi_wrapper_->CreateSurfaces(coded_size, 1, &va_surfaces))
244 break;
245
246 if (!VaapiJpegDecoder::Decode(vaapi_wrapper_.get(), parse_result,
247 va_surfaces[0])) {
248 // TODO UNSUPPORTED_JPEG ?
249 DLOG(ERROR) << "Decode failed";
250 NotifyError(curr_input_buffer_->id,
251 media::JpegDecodeAccelerator::PLATFORM_FAILURE);
252 break;
253 }
254
255 if (!OutputPicture(va_surfaces[0], curr_input_buffer_->id,
256 curr_input_buffer_->video_frame)) {
257 DLOG(ERROR) << "Output failed";
258 NotifyError(curr_input_buffer_->id,
259 media::JpegDecodeAccelerator::PLATFORM_FAILURE);
260 break;
261 }
262 vaapi_wrapper_->DestroySurfaces();
263 } while (0);
264 curr_input_buffer_.reset();
265
266 }
267 state_ = kIdle;
268 }
269
270 void VaapiJpegDecodeAccelerator::Decode(
271 const media::BitstreamBuffer& bitstream_buffer,
272 const scoped_refptr<media::VideoFrame>& video_frame) {
273 DCHECK_EQ(message_loop_, base::MessageLoop::current());
wuchengli 2015/03/23 06:30:15 Decode runs on IO thread. Right? DCHECK(io_message
kcwu 2015/04/16 14:38:26 Done.
274
275
276 // We got a new input buffer from the client, map it and queue for later use.
277 MapAndQueueNewInputBuffer(bitstream_buffer, video_frame);
278
279 base::AutoLock auto_lock(lock_);
280 state_ = kDecoding;
281 decoder_thread_proxy_->PostTask(FROM_HERE, base::Bind(
282 &VaapiJpegDecodeAccelerator::DecodeTask,
283 base::Unretained(this)));
284 }
285
286 void VaapiJpegDecodeAccelerator::Cleanup() {
287 DCHECK_EQ(message_loop_, base::MessageLoop::current());
288
289 if (state_ == kUninitialized || state_ == kDestroying)
290 return;
291
292 DVLOG(1) << "Destroying VAVDA";
293 base::AutoLock auto_lock(lock_);
294 state_ = kDestroying;
295
296 client_ptr_factory_.reset();
297 weak_this_factory_.InvalidateWeakPtrs();
298
299 // Signal all potential waiters on the decoder_thread_, let them early-exit,
300 // as we've just moved to the kDestroying state, and wait for all tasks
301 // to finish.
302 input_ready_.Signal();
303 {
304 base::AutoUnlock auto_unlock(lock_);
305 decoder_thread_.Stop();
306 }
307
308 state_ = kUninitialized;
309 }
310
311 void VaapiJpegDecodeAccelerator::Destroy() {
312 DCHECK_EQ(message_loop_, base::MessageLoop::current());
313 Cleanup();
314 delete this;
315 }
316
317 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698