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

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: reuse VASurface 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/browser/renderer_host/gpu_jpeg_decoder.h"
6
7 #include "base/bind.h"
8 #include "base/logging.h"
9 #include "base/trace_event/trace_event.h"
10 #include "content/browser/gpu/browser_gpu_channel_host_factory.h"
11 #include "content/common/gpu/client/gpu_jpeg_decode_accelerator_host.h"
12 #include "content/public/browser/browser_thread.h"
13 #include "media/base/video_frame.h"
14
15 namespace content {
16
17 // static
18 bool GpuJpegDecoder::Supported() {
19 // A lightweight check for caller to avoid IPC latency for known unsupported
20 // platform. Initialize() can do the real platform supporting check but it
21 // requires an IPC even for platforms that do not support HW decoder.
22 // TODO(kcwu): move this information to GpuInfo.
23 #if defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY)
24 return true;
25 #endif
26 return false;
27 }
28
29 GpuJpegDecoder::GpuJpegDecoder(media::VideoCaptureDevice::Client* device_client,
30 const DecodeDoneCB& decode_done_cb)
31 : device_client_(device_client),
32 decode_done_cb_(decode_done_cb),
33 capture_task_runner_(base::MessageLoopProxy::current()),
34 initialized_(false),
35 failed_(false),
36 next_bitstream_buffer_id_(0),
37 in_buffer_(media::JpegDecodeAccelerator::kInvalidBitstreamBufferId,
38 base::SharedMemory::NULLHandle(),
39 0) {
40 }
41
42 GpuJpegDecoder::~GpuJpegDecoder() {
43 DCHECK(capture_task_runner_->BelongsToCurrentThread());
44 }
45
46 bool GpuJpegDecoder::IsDecoding_Locked() {
47 lock_.AssertAcquired();
48 return !decode_done_closure_.is_null();
49 }
50
51 bool GpuJpegDecoder::Initialize() {
52 DVLOG(3) << __func__;
53 DCHECK(capture_task_runner_->BelongsToCurrentThread());
54 base::AutoLock lock(lock_);
55 if (!initialized_) {
56 GpuChannelHost* const host =
57 BrowserGpuChannelHostFactory::instance()->GetGpuChannel();
58 decoder_ = host->CreateJpegDecoder(
59 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO));
60 if (!decoder_->Initialize(this)) {
61 decoder_.reset();
62 failed_ = true;
63 }
64 initialized_ = true;
65 }
66 return !failed_;
67 }
68
69 void GpuJpegDecoder::VideoFrameReady(int32_t bitstream_buffer_id) {
70 DVLOG(3) << __func__;
71 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
72 TRACE_EVENT0("jpeg", "GpuJpegDecoder::VideoFrameReady");
73 base::AutoLock lock(lock_);
74
75 if (bitstream_buffer_id ==
76 media::JpegDecodeAccelerator::kInvalidBitstreamBufferId)
77 return;
78
79 if (!IsDecoding_Locked()) {
80 LOG(ERROR) << "Got decode response while not decoding";
81 return;
82 }
83
84 if (bitstream_buffer_id != in_buffer_.id()) {
85 LOG(ERROR) << "Unexpected bitstream_buffer_id " << bitstream_buffer_id
86 << ", expected " << in_buffer_.id();
87 return;
88 }
89
90 decode_done_closure_.Run();
91 decode_done_closure_.Reset();
92
93 TRACE_EVENT_ASYNC_END0("jpeg", "GpuJpegDecoder decoding",
94 bitstream_buffer_id);
95 }
96
97 void GpuJpegDecoder::NotifyError(int32_t bitstream_buffer_id,
98 media::JpegDecodeAccelerator::Error error) {
99 DVLOG(3) << __func__;
100 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
101 LOG(ERROR) << "Decode error, bitstream_buffer_id=" << bitstream_buffer_id;
102
103 base::AutoLock lock(lock_);
104 failed_ = true;
105 decode_done_closure_.Reset();
106 }
107
108 bool GpuJpegDecoder::DecodeCapturedData(
109 const uint8* data,
110 size_t in_buffer_size,
111 const media::VideoCaptureFormat& frame_format,
112 int rotation,
113 const base::TimeTicks& timestamp) {
114 DCHECK(capture_task_runner_->BelongsToCurrentThread());
115 DCHECK(initialized_);
116 TRACE_EVENT_ASYNC_BEGIN0("jpeg", "GpuJpegDecoder decoding",
117 next_bitstream_buffer_id_);
118 TRACE_EVENT0("jpeg", "GpuJpegDecoder::DecodeCapturedData");
119
120 {
121 base::AutoLock lock(lock_);
122 // Conditions that lead to return true, which means dropping frame, should
123 // be checked first. Otherwise the latter frames may be decoded (via caller
124 // fallback to software decoding) before the former frame.
mcasas 2015/05/07 00:59:03 Wait, is there still fallback to software decoding
wuchengli 2015/05/07 06:23:14 I discussed with Kuang-che. He'll remove the fallb
kcwu 2015/05/08 14:42:42 Done.
125 if (IsDecoding_Locked()) {
126 DVLOG(1) << "Drop captured frame. Previous jpeg frame is still decoding";
127 return true;
128 }
129 if (failed_)
130 return false;
wuchengli 2015/05/06 07:59:18 Can we return a enum from this function? SUCCESS (
kcwu 2015/05/08 14:42:42 Acknowledged. Revised to use jpeg thread.
131 if (rotation != 0) // unsupported
132 return false;
133 }
134
135 // Since IsDecoding_Locked() is false here and we only decode a frame at a
wuchengli 2015/05/04 14:14:41 This is not right. Suppose DecodeCapturedData is c
kcwu 2015/05/08 14:42:42 Acknowledged. Revised to use jpeg thread.
136 // time, after this point, the only possible multithread access to this class
137 // is NotifyError. This means |failed_| may be set to true when running
138 // following code.
139
140 const gfx::Size dimensions = frame_format.frame_size;
141 scoped_ptr<media::VideoCaptureDevice::Client::Buffer> out_buffer(
142 device_client_->ReserveOutputBuffer(media::PIXEL_FORMAT_I420,
143 dimensions));
144 if (!out_buffer.get()) {
145 DVLOG(1) << "Drop captured frame. No available buffers"
146 << " (all buffers are still queued to display)";
147 return false;
148 }
149
150 // Enlarge input buffer if necessary.
151 // Since IsDecoding_Locked() is false, |in_shared_memory_| will not be
152 // accessed concurrently on another thread or even GPU process. It's safe to
153 // change |in_shared_memory_| without lock.
154 if (!in_shared_memory_.get() ||
155 in_buffer_size > in_shared_memory_->mapped_size()) {
156 in_shared_memory_.reset(new base::SharedMemory);
157 if (!in_shared_memory_->CreateAndMapAnonymous(in_buffer_size)) {
158 DLOG(ERROR) << "CreateAndMapAnonymous failed, size=" << in_buffer_size;
159 base::AutoLock lock(lock_);
160 failed_ = true;
161 return false;
162 }
163 }
164
165 media::BitstreamBuffer in_buffer(next_bitstream_buffer_id_,
166 in_shared_memory_->handle(), in_buffer_size);
167 // Mask against 30 bits, to avoid (undefined) wraparound on signed integer.
168 next_bitstream_buffer_id_ = (next_bitstream_buffer_id_ + 1) & 0x3FFFFFFF;
169
170 scoped_refptr<media::VideoFrame> out_frame =
171 media::VideoFrame::WrapExternalPackedMemory(
172 media::VideoFrame::I420,
173 dimensions,
174 gfx::Rect(dimensions),
175 dimensions,
176 reinterpret_cast<uint8*>(out_buffer->data()),
177 out_buffer->size(),
178 out_buffer->AsPlatformHandle(),
179 0,
180 base::TimeDelta(),
181 base::Closure());
182 DCHECK(out_frame.get());
183
184 out_frame->metadata()->SetDouble(media::VideoFrameMetadata::FRAME_RATE,
185 frame_format.frame_rate);
186
187 memcpy(in_shared_memory_->memory(), data, in_buffer_size);
188
189 base::AutoLock lock(lock_);
190 if (failed_)
191 return false;
192 in_buffer_ = in_buffer;
193 decode_done_closure_ = base::Bind(decode_done_cb_, base::Passed(&out_buffer),
194 out_frame, timestamp);
195
196 decoder_->Decode(in_buffer_, out_frame);
197 return true;
198 }
199
200 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698