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

Side by Side Diff: content/common/gpu/media/vaapi_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/vaapi_jpeg_decode_accelerator.h"
6
7 #include "base/bind.h"
8 #include "base/logging.h"
9 #include "base/thread_task_runner_handle.h"
10 #include "base/trace_event/trace_event.h"
11 #include "content/common/gpu/gpu_channel.h"
12 #include "content/common/gpu/media/vaapi_picture.h"
13 #include "media/base/video_frame.h"
14 #include "media/filters/jpeg_parser.h"
15
16 static void ReportVaapiError() {
17 }
18
19 namespace content {
20
21 VaapiJpegDecodeAccelerator::DecodeRequest::DecodeRequest(
22 const media::BitstreamBuffer& bitstream_buffer,
23 scoped_refptr<media::VideoFrame> video_frame)
24 : bitstream_buffer(bitstream_buffer), video_frame(video_frame) {
25 }
26
27 VaapiJpegDecodeAccelerator::DecodeRequest::~DecodeRequest() {
28 }
29
30 void VaapiJpegDecodeAccelerator::NotifyError(int32_t bitstream_buffer_id,
31 Error error) {
32 if (task_runner_ != base::ThreadTaskRunnerHandle::Get()) {
piman 2015/05/18 22:46:19 I don't like this pattern very much. The caller kn
kcwu 2015/05/25 18:57:17 Done.
33 DCHECK(decoder_task_runner_->BelongsToCurrentThread());
34 task_runner_->PostTask(FROM_HERE,
35 base::Bind(&VaapiJpegDecodeAccelerator::NotifyError,
36 weak_this_, bitstream_buffer_id, error));
37 return;
38 }
39
40 Cleanup();
piman 2015/05/18 22:46:19 Is it needed to do this here? It'll be done at Des
kcwu 2015/05/25 18:57:17 Done.
41
42 LOG(ERROR) << "Notifying of error " << error;
piman 2015/05/18 22:46:20 Is this needed in release builds? It seems like ev
kcwu 2015/05/25 18:57:17 Done.
43 if (client_) {
44 client_->NotifyError(bitstream_buffer_id, error);
45 client_ptr_factory_.reset();
46 }
47 }
48
49 VaapiJpegDecodeAccelerator::VaapiJpegDecodeAccelerator(
50 const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner)
51 : initialized_(false),
52 task_runner_(base::ThreadTaskRunnerHandle::Get()),
53 io_task_runner_(io_task_runner),
54 decoder_thread_("VaapiJpegDecoderThread"),
piman 2015/05/18 22:46:19 Can we share a single thread among all decoders? B
kcwu 2015/05/26 14:51:30 This only happens if both external and internal ca
55 va_surface_(VA_INVALID_SURFACE),
56 weak_this_factory_(this) {
57 weak_this_ = weak_this_factory_.GetWeakPtr();
58 }
59
60 VaapiJpegDecodeAccelerator::~VaapiJpegDecodeAccelerator() {
61 DCHECK_EQ(task_runner_, base::ThreadTaskRunnerHandle::Get());
62 }
63
64 bool VaapiJpegDecodeAccelerator::Initialize(Client* client) {
65 DCHECK_EQ(task_runner_, base::ThreadTaskRunnerHandle::Get());
66
67 client_ptr_factory_.reset(new base::WeakPtrFactory<Client>(client));
68 client_ = client_ptr_factory_->GetWeakPtr();
piman 2015/05/18 22:46:19 Why is a WeakPtr needed here? It seems like the cl
kcwu 2015/05/25 18:57:17 Done.
69
70 base::AutoLock auto_lock(lock_);
71 DCHECK(!initialized_);
72
73 vaapi_wrapper_ =
74 VaapiWrapper::Create(VaapiWrapper::kDecode, VAProfileJPEGBaseline,
75 base::Bind(&ReportVaapiError));
76
77 if (!vaapi_wrapper_.get()) {
78 DLOG(ERROR) << "Failed initializing VAAPI";
79 return false;
80 }
81
82 if (!decoder_thread_.Start()) {
83 LOG(ERROR) << "Failed to start decoding thread.";
piman 2015/05/18 22:46:20 DLOG
kcwu 2015/05/25 18:57:17 Done.
84 return false;
85 }
86 decoder_task_runner_ = decoder_thread_.task_runner();
87
88 initialized_ = true;
89 return true;
90 }
91
92 bool VaapiJpegDecodeAccelerator::OutputPicture(
93 VASurfaceID va_surface_id,
94 int32_t input_buffer_id,
95 const scoped_refptr<media::VideoFrame>& video_frame) {
96 DCHECK(decoder_task_runner_->BelongsToCurrentThread());
97
98 TRACE_EVENT1("jpeg", "VaapiJpegDecodeAccelerator::OutputPicture",
99 "input_buffer_id", input_buffer_id);
100
101 DVLOG(3) << "Outputting VASurface " << va_surface_id
102 << " into video_frame associate to input buffer id "
103 << input_buffer_id;
104
105 VAImage image;
106 VAImageFormat format;
107 const uint32_t kI420Fourcc = VA_FOURCC('I', '4', '2', '0');
108 memset(&image, 0, sizeof(image));
109 memset(&format, 0, sizeof(format));
110 format.fourcc = kI420Fourcc;
111 format.byte_order = VA_LSB_FIRST;
112 format.bits_per_pixel = 12; // 12 for I420
113
114 void* mem;
piman 2015/05/18 22:46:19 nit: = nullptr;
kcwu 2015/05/25 18:57:17 Done.
115 gfx::Size coded_size = video_frame->coded_size();
116 if (!vaapi_wrapper_->GetVaImage(va_surface_id, &format, coded_size, &image,
117 &mem)) {
118 DLOG(ERROR) << "Cannot get VAImage";
119 return false;
120 }
121
122 uint8* frame_mem = video_frame->data(media::VideoFrame::kYPlane);
123 size_t frame_buffer_size =
124 media::VideoFrame::AllocationSize(media::VideoFrame::I420, coded_size);
125 memcpy(frame_mem, mem, frame_buffer_size);
126
127 vaapi_wrapper_->ReturnVaImage(&image);
128
129 if (client_)
130 client_->VideoFrameReady(input_buffer_id);
131
132 return true;
133 }
134
135 void VaapiJpegDecodeAccelerator::DecodeTask() {
136 DVLOG(3) << __func__;
137 DCHECK(decoder_task_runner_->BelongsToCurrentThread());
138 TRACE_EVENT0("jpeg", "DecodeTask");
139 linked_ptr<DecodeRequest> request;
140 {
141 base::AutoLock auto_lock(lock_);
142
143 DCHECK(!decode_requests_.empty());
144 request = decode_requests_.front();
145 decode_requests_.pop();
146 }
147
148 do {
149 DVLOG(4) << "Mapping new input buffer id: "
150 << request->bitstream_buffer.id()
151 << " size: " << (int)request->bitstream_buffer.size();
152
153 scoped_ptr<base::SharedMemory> shm(
154 new base::SharedMemory(request->bitstream_buffer.handle(), true));
155 if (!shm->Map(request->bitstream_buffer.size())) {
156 LOG(ERROR) << "Failed to map input buffer";
157 NotifyError(request->bitstream_buffer.id(), UNREADABLE_INPUT);
158 break;
159 }
160
161 media::JpegParseResult parse_result;
162
163 if (!media::ParseJpegPicture(
164 reinterpret_cast<const uint8_t*>(shm->memory()),
165 request->bitstream_buffer.size(), &parse_result)) {
166 DLOG(ERROR) << "ParseJpegPicture failed";
167 NotifyError(request->bitstream_buffer.id(),
168 media::JpegDecodeAccelerator::PARSE_JPEG_FAILED);
169 break;
170 }
171
172 // Reuse VASurface if size doesn't change.
173 // This is not only optimization, but also to avoid libva resoruce leak.
piman 2015/05/18 22:46:20 typo: s/resoruce/resource/
kcwu 2015/05/25 18:57:16 Done.
174 // crosbug.com/p/39584
175 gfx::Size coded_size(parse_result.frame_header.coded_width,
176 parse_result.frame_header.coded_height);
177 if (coded_size != last_coded_size_ || va_surface_ == VA_INVALID_SURFACE) {
178 vaapi_wrapper_->DestroySurfaces();
179 std::vector<VASurfaceID> va_surfaces;
180 if (!vaapi_wrapper_->CreateSurfaces(coded_size, 1, &va_surfaces))
181 break;
182 va_surface_ = va_surfaces[0];
183 last_coded_size_ = coded_size;
184 }
185
186 if (!VaapiJpegDecoder::Decode(vaapi_wrapper_.get(), parse_result,
187 va_surface_)) {
188 LOG(ERROR) << "Decode failed";
189 NotifyError(request->bitstream_buffer.id(),
190 media::JpegDecodeAccelerator::PLATFORM_FAILURE);
191 break;
192 }
193
194 if (!OutputPicture(va_surface_, request->bitstream_buffer.id(),
195 request->video_frame)) {
196 LOG(ERROR) << "Output failed";
197 NotifyError(request->bitstream_buffer.id(),
198 media::JpegDecodeAccelerator::PLATFORM_FAILURE);
199 break;
200 }
201 } while (0);
202 }
203
204 void VaapiJpegDecodeAccelerator::Decode(
205 const media::BitstreamBuffer& bitstream_buffer,
206 const scoped_refptr<media::VideoFrame>& video_frame) {
207 DVLOG(3) << __func__;
208 DCHECK(io_task_runner_->BelongsToCurrentThread());
209 TRACE_EVENT1("jpeg", "Decode", "input_id", bitstream_buffer.id());
210
211 if (!initialized_)
piman 2015/05/18 22:46:19 This is used outside the lock. Even with a lock,
kcwu 2015/05/25 18:57:17 I will add a checking in DecodeTask. The check her
212 return;
213
214 // Set up a new decode request and queue it for later.
215 linked_ptr<DecodeRequest> input_buffer(
216 new DecodeRequest(bitstream_buffer, video_frame));
217 base::AutoLock auto_lock(lock_);
218 decode_requests_.push(input_buffer);
219
220 decoder_task_runner_->PostTask(
221 FROM_HERE, base::Bind(&VaapiJpegDecodeAccelerator::DecodeTask,
222 base::Unretained(this)));
223 }
224
225 void VaapiJpegDecodeAccelerator::Cleanup() {
226 DCHECK_EQ(task_runner_, base::ThreadTaskRunnerHandle::Get());
227
228 base::AutoLock auto_lock(lock_);
229 if (!initialized_)
230 return;
231
232 DVLOG(1) << "Destroying VaapiJpegDecodeAccelerator";
233
234 client_ptr_factory_.reset();
235 weak_this_factory_.InvalidateWeakPtrs();
236
237 {
238 base::AutoUnlock auto_unlock(lock_);
239 decoder_thread_.Stop();
240 }
241
242 initialized_ = false;
243 }
244
245 void VaapiJpegDecodeAccelerator::Destroy() {
246 DCHECK_EQ(task_runner_, base::ThreadTaskRunnerHandle::Get());
247 Cleanup();
248 delete this;
249 }
250
251 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698