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

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: address most comments Created 5 years, 8 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) \
wuchengli 2015/04/15 07:11:59 This is only used once. Just use the following cod
kcwu 2015/04/16 14:38:28 Done.
27 do { \
28 if (!(result)) { \
29 LOG(ERROR) << log; \
30 NotifyError(buffer_id, error_code); \
31 return ret; \
32 } \
33 } while (0)
34
35 VaapiJpegDecodeAccelerator::InputBuffer::InputBuffer() : id(0), size(0) {
36 }
37
38 VaapiJpegDecodeAccelerator::InputBuffer::~InputBuffer() {
39 }
40
41 void VaapiJpegDecodeAccelerator::NotifyError(int32_t bitstream_buffer_id,
42 Error error) {
43 if (message_loop_ != base::MessageLoop::current()) {
44 DCHECK(decoder_thread_proxy_->BelongsToCurrentThread());
45 message_loop_->PostTask(FROM_HERE,
46 base::Bind(&VaapiJpegDecodeAccelerator::NotifyError,
47 weak_this_, bitstream_buffer_id, error));
48 return;
49 }
50
51 // Post Cleanup() as a task so we don't recursively acquire lock_.
wuchengli 2015/04/15 07:11:58 I don't understand why recursively acquire lock_ i
kcwu 2015/04/20 17:47:59 I don't, neither. I guess VAVDA's original Cleanup
52 message_loop_->PostTask(
53 FROM_HERE, base::Bind(&VaapiJpegDecodeAccelerator::Cleanup, weak_this_));
54
55 LOG(ERROR) << "Notifying of error " << error;
56 if (client_) {
57 client_->NotifyError(bitstream_buffer_id, error);
58 client_ptr_factory_.reset();
59 }
60 }
61
62 VaapiJpegDecodeAccelerator::VaapiJpegDecodeAccelerator()
63 : state_(kUninitialized),
64 input_ready_(&lock_),
65 message_loop_(base::MessageLoop::current()),
66 decoder_thread_("VaapiDecoderThread"),
wuchengli 2015/04/15 07:11:58 s/VaapiDecoderThread/VaapiJpegDecoderThread/ to di
kcwu 2015/04/20 17:47:59 Done.
67 weak_this_factory_(this) {
68 weak_this_ = weak_this_factory_.GetWeakPtr();
69 }
70
71 VaapiJpegDecodeAccelerator::~VaapiJpegDecodeAccelerator() {
72 DCHECK_EQ(message_loop_, base::MessageLoop::current());
73 }
74
75 bool VaapiJpegDecodeAccelerator::Initialize(Client* client) {
76 DCHECK_EQ(message_loop_, base::MessageLoop::current());
77
78 client_ptr_factory_.reset(new base::WeakPtrFactory<Client>(client));
79 client_ = client_ptr_factory_->GetWeakPtr();
80
81 base::AutoLock auto_lock(lock_);
82 DCHECK_EQ(state_, kUninitialized);
83
84 vaapi_wrapper_ =
85 VaapiWrapper::Create(VaapiWrapper::kDecode, VAProfileJPEGBaseline,
86 base::Bind(&ReportVaapiError));
87
88 if (!vaapi_wrapper_.get()) {
89 DLOG(ERROR) << "Failed initializing VAAPI";
90 return false;
91 }
92
93 CHECK(decoder_thread_.Start());
94 decoder_thread_proxy_ = decoder_thread_.message_loop_proxy();
95
96 state_ = kIdle;
97 return true;
98 }
99
100 bool VaapiJpegDecodeAccelerator::OutputPicture(
101 VASurfaceID va_surface_id,
102 int32_t input_id,
103 const scoped_refptr<media::VideoFrame>& video_frame) {
104 DCHECK(decoder_thread_proxy_->BelongsToCurrentThread());
105
106 DVLOG(3) << "Outputting VASurface " << va_surface_id
107 << " into video_frame associate to input buffer id " << input_id;
108
109 VAImage image;
110 VAImageFormat format;
111 const uint32_t kI420Fourcc = VA_FOURCC('I', '4', '2', '0');
112 memset(&image, 0, sizeof(image));
113 memset(&format, 0, sizeof(format));
114 format.fourcc = kI420Fourcc;
115 format.byte_order = VA_LSB_FIRST;
116 format.bits_per_pixel = 12; // 12 for I420
117
118 void* mem;
119 gfx::Size coded_size = video_frame->coded_size();
120 if (!vaapi_wrapper_->GetVaImage(va_surface_id, &format, coded_size, &image,
121 &mem)) {
122 DLOG(ERROR) << "Cannot get VAImage";
123 return false;
124 }
125
126 uint8* frame_mem = video_frame->data(media::VideoFrame::kYPlane);
127 size_t frame_buffer_size =
128 media::VideoFrame::AllocationSize(media::VideoFrame::I420, coded_size);
129 memcpy(frame_mem, mem, frame_buffer_size);
wuchengli 2015/04/15 07:11:59 Can we import frame_mem to vaapi so we can get rid
kcwu 2015/04/20 17:47:59 I don't know how. I will ask.
130
131 vaapi_wrapper_->ReturnVaImage(&image);
132
133 if (client_)
134 client_->VideoFrameReady(input_id);
wuchengli 2015/04/15 07:11:59 This should be posted to io thread to reduce laten
kcwu 2015/04/20 17:47:59 I don't think this will reduce latency to post thi
135
136 return true;
137 }
138
139 void VaapiJpegDecodeAccelerator::MapAndQueueNewInputBuffer(
140 const media::BitstreamBuffer& bitstream_buffer,
141 const scoped_refptr<media::VideoFrame>& video_frame) {
142 DVLOG(4) << "Mapping new input buffer id: " << bitstream_buffer.id()
143 << " size: " << (int)bitstream_buffer.size();
144
145 scoped_ptr<base::SharedMemory> shm(
146 new base::SharedMemory(bitstream_buffer.handle(), true));
147 RETURN_AND_NOTIFY_ON_FAILURE(shm->Map(bitstream_buffer.size()),
148 "Failed to map input buffer",
149 bitstream_buffer.id(), UNREADABLE_INPUT, );
150
151 base::AutoLock auto_lock(lock_);
wuchengli 2015/04/15 07:11:59 This can be moved to line 159.
kcwu 2015/04/16 14:38:28 Done.
152
153 // Set up a new input buffer and queue it for later.
154 linked_ptr<InputBuffer> input_buffer(new InputBuffer());
155 input_buffer->shm.reset(shm.release());
156 input_buffer->id = bitstream_buffer.id();
157 input_buffer->size = bitstream_buffer.size();
158 input_buffer->video_frame = video_frame;
159
160 input_buffers_.push(input_buffer);
161 input_ready_.Signal();
162 }
163
164 void VaapiJpegDecodeAccelerator::DecodeTask() {
165 DVLOG(3) << __func__;
166 DCHECK(decoder_thread_proxy_->BelongsToCurrentThread());
167 base::AutoLock auto_lock(lock_);
168
169 if (state_ != kIdle) {
170 DLOG(ERROR) << "not idle state";
171 return;
172 }
173
174 state_ = kDecoding;
wuchengli 2015/04/15 07:11:59 Why do we need kDecoding state?
kcwu 2015/04/20 17:47:59 Done.
175
176 DCHECK(!input_buffers_.empty());
177 curr_input_buffer_ = input_buffers_.front();
wuchengli 2015/04/15 07:11:59 curr_input_buffer_ doesn't have to be a class vari
kcwu 2015/04/16 14:38:28 Done.
178 input_buffers_.pop();
179 DVLOG(4) << "New current bitstream buffer, id: " << curr_input_buffer_->id
180 << " size: " << curr_input_buffer_->size;
181
182 do {
183 base::AutoUnlock auto_unlock(lock_);
wuchengli 2015/04/15 07:11:58 I think adding a code block for line 167-178 and l
kcwu 2015/04/20 17:47:59 Done.
184
185 media::JpegParseResult parse_result;
186
187 if (!media::ParseJpegPicture(
188 reinterpret_cast<const uint8_t*>(curr_input_buffer_->shm->memory()),
189 curr_input_buffer_->size, &parse_result)) {
wuchengli 2015/04/15 07:11:59 add a DLOG(ERROR)
kcwu 2015/04/20 17:47:59 Done.
190 NotifyError(curr_input_buffer_->id,
191 media::JpegDecodeAccelerator::PARSE_JPEG_FAILED);
192 break;
193 }
194
195 gfx::Size coded_size(parse_result.frame_header.coded_width,
196 parse_result.frame_header.coded_height);
197
198 vaapi_wrapper_->DestroySurfaces();
wuchengli 2015/04/15 07:11:59 Do we need this?
kcwu 2015/04/16 14:38:28 Done.
199 std::vector<VASurfaceID> va_surfaces;
200 if (!vaapi_wrapper_->CreateSurfaces(coded_size, 1, &va_surfaces))
201 break;
202
203 if (!VaapiJpegDecoder::Decode(vaapi_wrapper_.get(), parse_result,
204 va_surfaces[0])) {
205 DLOG(ERROR) << "Decode failed";
wuchengli 2015/04/15 07:11:59 Can this happen? s/DLOG/LOG/
kcwu 2015/04/16 14:38:28 Done.
206 NotifyError(curr_input_buffer_->id,
207 media::JpegDecodeAccelerator::PLATFORM_FAILURE);
208 break;
209 }
210
211 if (!OutputPicture(va_surfaces[0], curr_input_buffer_->id,
212 curr_input_buffer_->video_frame)) {
213 DLOG(ERROR) << "Output failed";
wuchengli 2015/04/15 07:11:59 Can this happen? s/DLOG/LOG/
kcwu 2015/04/16 14:38:28 Done.
214 NotifyError(curr_input_buffer_->id,
215 media::JpegDecodeAccelerator::PLATFORM_FAILURE);
216 break;
217 }
218 vaapi_wrapper_->DestroySurfaces();
219 } while (0);
220 curr_input_buffer_.reset();
221
222 state_ = kIdle;
223 }
224
225 void VaapiJpegDecodeAccelerator::Decode(
226 const media::BitstreamBuffer& bitstream_buffer,
227 const scoped_refptr<media::VideoFrame>& video_frame) {
228 DVLOG(3) << __func__;
229 // We got a new input buffer from the client, map it and queue for later use.
wuchengli 2015/04/15 07:11:59 s/client, map/client. Map/
kcwu 2015/04/16 14:38:28 Done.
230 MapAndQueueNewInputBuffer(bitstream_buffer, video_frame);
231
232 base::AutoLock auto_lock(lock_);
wuchengli 2015/04/15 07:11:59 The lock is not required here?
kcwu 2015/04/16 14:38:28 Done.
233 decoder_thread_proxy_->PostTask(
234 FROM_HERE, base::Bind(&VaapiJpegDecodeAccelerator::DecodeTask,
235 base::Unretained(this)));
236 }
237
238 void VaapiJpegDecodeAccelerator::Cleanup() {
239 DCHECK_EQ(message_loop_, base::MessageLoop::current());
240
241 base::AutoLock auto_lock(lock_);
242 if (state_ == kUninitialized || state_ == kDestroying)
wuchengli 2015/04/15 07:11:59 Why do we need kDestroying?
kcwu 2015/04/20 17:47:59 Done.
243 return;
244
245 DVLOG(1) << "Destroying VAJDA";
wuchengli 2015/04/15 07:11:58 VAJDA is a uncommon abbreviation. s/VAJDA/VaapiJpe
kcwu 2015/04/16 14:38:28 Done.
246 state_ = kDestroying;
247
248 client_ptr_factory_.reset();
249 weak_this_factory_.InvalidateWeakPtrs();
250
251 // Signal all potential waiters on the decoder_thread_, let them early-exit,
252 // as we've just moved to the kDestroying state, and wait for all tasks
253 // to finish.
254 input_ready_.Signal();
wuchengli 2015/04/15 07:11:58 Not used. Also remove the comments.
kcwu 2015/04/16 14:38:28 Done.
255 {
256 base::AutoUnlock auto_unlock(lock_);
257 decoder_thread_.Stop();
258 }
259
260 state_ = kUninitialized;
261 }
262
263 void VaapiJpegDecodeAccelerator::Destroy() {
264 DCHECK_EQ(message_loop_, base::MessageLoop::current());
265 Cleanup();
266 delete this;
267 }
268
269 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698