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

Side by Side Diff: content/browser/renderer_host/gpu_jpeg_decoder.cc

Issue 1016773002: MJPEG acceleration for video capture using VAAPI (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: support multiple jpeg decoder 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/browser/renderer_host/gpu_jpeg_decoder.h"
6
7 #include "base/bind.h"
8 #include "base/logging.h"
9 #include "content/browser/gpu/browser_gpu_channel_host_factory.h"
10 #include "content/common/gpu/client/gpu_jpeg_decode_accelerator_host.h"
11 #include "content/public/browser/browser_thread.h"
12 #include "media/base/video_frame.h"
13
14 namespace content {
15
16 // static
17 bool GpuJpegDecoder::Supported() {
18 // A lightweight check for caller to avoid IPC latency for known unsupported
19 // platform. Initialize() can do the real platform supporting check but it
20 // requires an IPC.
wuchengli 2015/04/24 05:54:23 s/IPC/IPC even for platforms that do not support H
kcwu 2015/04/30 19:25:39 Done.
21 // TODO(kcwu): move this logic to GpuInfo.
wuchengli 2015/04/24 05:54:23 s/logic/information/
kcwu 2015/04/30 19:25:39 Done.
22 #if defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY)
23 return true;
24 #endif
25 return false;
26 }
27
28 GpuJpegDecoder::GpuJpegDecoder(
29 media::VideoCaptureDevice::Client* device_client)
30 : device_client_(device_client),
31 main_task_runner_(base::MessageLoopProxy::current()),
32 fail_state_(NOT_FAIL),
33 next_bitstream_buffer_id_(0),
34 in_buffer_(media::JpegDecodeAccelerator::kInvalidBitstreamBufferId,
35 base::SharedMemory::NULLHandle(),
36 0) {
37 }
38
39 GpuJpegDecoder::~GpuJpegDecoder() {
40 DCHECK(main_task_runner_->BelongsToCurrentThread());
41 }
42
43 bool GpuJpegDecoder::IsDecoding() {
44 base::AutoLock lock(lock_);
45 return out_frame_ != nullptr;
46 }
47
48 bool GpuJpegDecoder::IsExpectedDecodeResponse(
49 int32 bitstream_buffer_id) {
50 if (bitstream_buffer_id ==
51 media::JpegDecodeAccelerator::kInvalidBitstreamBufferId)
52 return false;
53
54 if (!IsDecoding()) {
55 LOG(ERROR) << "Got decode response while not decoding";
56 return false;
57 }
58
59 if (bitstream_buffer_id != in_buffer_.id()) {
60 LOG(ERROR) << "Unexpected bitstream_buffer_id " << bitstream_buffer_id
61 << ", expected " << in_buffer_.id();
62 return false;
63 }
64
65 return true;
66 }
67
68 void GpuJpegDecoder::DecodeDone() {
69 base::AutoLock lock(lock_);
70 memset(&captured_data_, 0, sizeof(captured_data_));
71 out_buffer_ = nullptr;
72 out_frame_ = nullptr;
73 }
74
75 bool GpuJpegDecoder::Initialize() {
76 DVLOG(3) << __func__;
77 DCHECK(main_task_runner_->BelongsToCurrentThread());
78 GpuChannelHost* const host =
79 BrowserGpuChannelHostFactory::instance()->GetGpuChannel();
80 decoder_ = host->CreateJpegDecoder(
81 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO));
82 if (!decoder_->Initialize(this)) {
83 decoder_.reset();
84 fail_state_ = FAILED;
85 return false;
86 }
87 return true;
88 }
89
90 bool GpuJpegDecoder::IsFailed() {
91 base::AutoLock lock(lock_);
92 return fail_state_ == FAILED;
93 }
94
95 void GpuJpegDecoder::VideoFrameReady(
96 int32_t bitstream_buffer_id) {
97 DVLOG(3) << __func__;
98 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
99
100 if (!IsExpectedDecodeResponse(bitstream_buffer_id))
101 return;
102
103 device_client_->OnIncomingCapturedVideoFrame(out_buffer_, out_frame_,
104 captured_data_.timestamp);
105
106 DecodeDone();
107 }
108
109 void GpuJpegDecoder::FallbackToSoftwareDecode() {
110 DVLOG(1) << "Fallback to software decode";
111 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO) ||
112 main_task_runner_->BelongsToCurrentThread());
113 DCHECK_EQ(BrowserThread::CurrentlyOn(BrowserThread::IO), IsDecoding());
114
115 CapturedData captured_data;
116 {
117 base::AutoLock lock(lock_);
118 // See comment below.
119 if (BrowserThread::CurrentlyOn(BrowserThread::IO))
120 fail_state_ = FAILING;
121 else
122 fail_state_ = FAILED;
123 captured_data = captured_data_;
124 }
125
126 // If we are on |main_task_runner_| thread, OnIncomingCapturedData is
127 // reentrant. But it's okay since |fail_state_| is FAILED and it won't go
128 // hardware decoding route this time.
129 // If we are on IO thread and next frame is coming on |main_task_runner_|
130 // thread, the next frame will call DecodeCapturedData() and drop immediately
wuchengli 2015/04/24 05:54:23 Hmm. If we may still drop a frame, I prefer droppi
kcwu 2015/04/30 19:25:39 the behavior changed to always drop current frame
131 // due to |fail_state_| is FAILING. This is to avoid next frame decoded
132 // before this frame.
133 device_client_->OnIncomingCapturedData(captured_data.data,
134 captured_data.length,
135 captured_data.frame_format,
136 captured_data.rotation,
137 captured_data.timestamp);
138 {
139 base::AutoLock lock(lock_);
140 fail_state_ = FAILED;
141 }
142 }
143
144 void GpuJpegDecoder::NotifyError(
145 int32_t bitstream_buffer_id,
146 media::JpegDecodeAccelerator::Error error) {
147 DVLOG(3) << __func__;
148 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
149
150 // Error not associated to any bitstream buffer. For example, GPU channel
151 // is broken.
152 if (bitstream_buffer_id ==
153 media::JpegDecodeAccelerator::kInvalidBitstreamBufferId) {
154 {
155 base::AutoLock lock(lock_);
156 fail_state_ = FAILED;
157 }
158 DecodeDone();
159 return;
160 }
161
162 if (!IsExpectedDecodeResponse(bitstream_buffer_id))
163 return;
164
165 FallbackToSoftwareDecode();
166 DecodeDone();
167 }
168
169 void GpuJpegDecoder::DecodeCapturedData(
170 const uint8* data,
171 int length,
172 const media::VideoCaptureFormat& frame_format,
173 int rotation,
174 const base::TimeTicks& timestamp) {
175 DCHECK(main_task_runner_->BelongsToCurrentThread());
176 DCHECK(decoder_);
177 if (IsDecoding()) {
178 DVLOG(1) << "Drop captured frame. Previous jpeg frame is still decoding";
179 return;
180 }
181 {
182 base::AutoLock lock(lock_);
183 if (fail_state_ != NOT_FAIL)
184 return;
185 }
186
187 // Since IsDecoding() is false here and we only decode a frame at a time,
188 // after this point, the only possible multithread access to this class is
189 // NotifyError. This means |fail_state_| may be set to FAILED when running
190 // following code.
191
192 const gfx::Size dimensions = frame_format.frame_size;
193 scoped_refptr<media::VideoCaptureDevice::Client::Buffer> out_buffer =
194 device_client_->ReserveOutputBuffer(media::PIXEL_FORMAT_I420, dimensions);
195 if (!out_buffer.get()) {
196 DVLOG(1) << "Drop captured frame. No available buffers"
197 << " (all buffers are still queued to display)";
198 return;
199 }
200
201 CapturedData captured_data;
202 captured_data.data = const_cast<uint8*>(data);
203 captured_data.length = length;
204 captured_data.frame_format = frame_format;
205 captured_data.rotation = rotation;
206 captured_data.timestamp = timestamp;
207
208 size_t in_buffer_size = captured_data.length;
209
210 scoped_ptr<base::SharedMemory> in_shared_memory;
211 {
212 // Swap out to local variable in order to reduce lock time on IO thread.
213 base::AutoLock lock(lock_);
214 std::swap(in_shared_memory, in_shared_memory_);
215 }
216 // Enlarge input buffer if necessary.
217 if (!in_shared_memory.get() ||
218 in_buffer_size > in_shared_memory->mapped_size()) {
219 in_shared_memory.reset(new base::SharedMemory);
220 if (!in_shared_memory->CreateAndMapAnonymous(in_buffer_size)) {
221 DLOG(ERROR) << "CreateAndMapAnonymous failed, size=" << in_buffer_size;
222 captured_data_ = captured_data;
223 FallbackToSoftwareDecode();
224 return;
225 }
226 }
227
228 media::BitstreamBuffer in_buffer(next_bitstream_buffer_id_,
229 in_shared_memory->handle(), in_buffer_size);
230 // Mask against 30 bits, to avoid (undefined) wraparound on signed integer.
231 next_bitstream_buffer_id_ = (next_bitstream_buffer_id_ + 1) & 0x3FFFFFFF;
232
233 scoped_refptr<media::VideoFrame> out_frame =
234 media::VideoFrame::WrapExternalPackedMemory(
235 media::VideoFrame::I420,
236 dimensions,
237 gfx::Rect(dimensions),
238 dimensions,
239 reinterpret_cast<uint8*>(out_buffer->data()),
240 out_buffer->size(),
241 out_buffer->handle(),
242 0,
243 base::TimeDelta(),
244 base::Closure());
245 DCHECK(out_frame.get());
246
247 out_frame->metadata()->SetDouble(media::VideoFrameMetadata::FRAME_RATE,
248 captured_data.frame_format.frame_rate);
249
250 memcpy(in_shared_memory->memory(), captured_data.data, in_buffer_size);
251 captured_data.data = reinterpret_cast<uint8*>(in_shared_memory->memory());
252
253 base::AutoLock lock(lock_);
254 if (fail_state_ != NOT_FAIL)
255 return;
256 captured_data_ = captured_data;
257 in_buffer_ = in_buffer;
258 std::swap(in_shared_memory_, in_shared_memory);
259 out_buffer_ = out_buffer;
260 out_frame_ = out_frame;
261
262 decoder_->Decode(in_buffer_, out_frame_);
263 }
264
265 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698