OLD | NEW |
---|---|
(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. | |
21 // TODO(kcwu): move this logic to GpuInfo. | |
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_)); | |
mcasas
2015/04/28 00:04:49
Is this needed or is |captured_data_| set before u
kcwu
2015/04/30 19:25:43
Done.
Not needed. Removed.
| |
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( | |
mcasas
2015/04/28 00:04:49
VideoFrameReadyOnIOThread()?
kcwu
2015/04/30 19:25:42
This name is inheritance from media::JpegDecodeAcc
| |
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_, | |
mcasas
2015/04/28 00:04:49
DecodeDone() in l.106 is executed in mutual exclus
kcwu
2015/04/30 19:25:42
Done.
| |
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()); | |
mcasas
2015/04/28 00:04:49
These chained DCHECKs are a symptom of excessive c
kcwu
2015/04/30 19:25:42
Done.
| |
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 | |
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 { | |
mcasas
2015/04/28 00:04:50
l.181-185:
if (!IsFailed())
return;
kcwu
2015/04/30 19:25:43
Done.
| |
182 base::AutoLock lock(lock_); | |
183 if (fail_state_ != NOT_FAIL) | |
184 return; | |
185 } | |
mcasas
2015/04/28 00:04:49
There is quite a lot of sequential locking-unlocki
kcwu
2015/04/30 19:25:43
Locking is refactored now.
| |
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_); | |
mcasas
2015/04/28 00:04:50
l.253-255:
if(!IsFailed())
return;
kcwu
2015/04/30 19:25:43
Not sure what do you mean.
Please take a look anyw
| |
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 | |
OLD | NEW |