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

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: rebase 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/strings/stringprintf.h"
10 #include "base/trace_event/trace_event.h"
11 #include "content/browser/gpu/browser_gpu_channel_host_factory.h"
12 #include "content/common/gpu/client/gpu_jpeg_decode_accelerator_host.h"
13 #include "content/public/browser/browser_thread.h"
14 #include "media/base/video_frame.h"
15
16 namespace content {
17
18 // static
19 bool GpuJpegDecoder::Supported() {
20 // A lightweight check for caller to avoid IPC latency for known unsupported
21 // platform. Initialize() can do the real platform supporting check but it
22 // requires an IPC even for platforms that do not support HW decoder.
23 // TODO(kcwu): move this information to GpuInfo.
24 #if defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY)
25 return true;
26 #endif
27 return false;
28 }
29
30 GpuJpegDecoder::GpuJpegDecoder(const DecodeDoneCB& decode_done_cb,
31 const ErrorCB& error_cb)
32 : jpeg_thread_("GpuJpegDecoderThread"),
33 create_event_(false, false),
34 decode_event_(false, false),
35 decode_done_cb_(decode_done_cb),
36 error_cb_(error_cb),
37 next_bitstream_buffer_id_(0),
38 in_buffer_(media::JpegDecodeAccelerator::kInvalidBitstreamBufferId,
39 base::SharedMemory::NULLHandle(),
40 0) {
41 }
42
43 GpuJpegDecoder::~GpuJpegDecoder() {
44 DCHECK(CalledOnValidThread());
wuchengli 2015/05/13 15:04:05 We need a GpuJpegDecoder::Destroy to stop jpeg thr
kcwu 2015/05/26 07:04:19 Acknowledged. piman raised the same issue in https
45 }
46
47 bool GpuJpegDecoder::IsDecoding() {
48 DCHECK(CalledOnValidThread());
wuchengli 2015/05/13 15:04:05 DCHECK(jpeg_thread_proxy_->BelongsToCurrentThread(
kcwu 2015/05/25 18:20:34 Done.
49 return !decode_done_closure_.is_null();
50 }
51
52 bool GpuJpegDecoder::Initialize() {
53 DVLOG(3) << __func__;
54 DCHECK(CalledOnValidThread());
55 DCHECK(!jpeg_thread_.IsRunning());
56
57 if (!jpeg_thread_.Start()) {
58 LOG(ERROR) << "Failed to start decoding thread.";
59 return false;
60 }
61 jpeg_thread_proxy_ = jpeg_thread_.message_loop_proxy();
62
63 jpeg_thread_proxy_->PostTask(
64 FROM_HERE,
65 base::Bind(&GpuJpegDecoder::CreateDecoderOnJpegThread,
66 base::Unretained(this)));
67 create_event_.Wait();
68
69 if (!decoder_) {
70 jpeg_thread_.Stop();
71 return false;
72 }
73
74 return true;
75 }
76
77 void GpuJpegDecoder::CreateDecoderOnJpegThread() {
78 DCHECK(jpeg_thread_proxy_->BelongsToCurrentThread());
79 GpuChannelHost* const host =
80 BrowserGpuChannelHostFactory::instance()->GetGpuChannel();
81 decoder_ = host->CreateJpegDecoder();
82 if (!decoder_->Initialize(this)) {
83 decoder_.reset();
84 }
85 create_event_.Signal();
86 }
87
88 void GpuJpegDecoder::VideoFrameReady(int32_t bitstream_buffer_id) {
89 DVLOG(3) << __func__;
90 DCHECK(jpeg_thread_proxy_->BelongsToCurrentThread());
91 TRACE_EVENT0("jpeg", "GpuJpegDecoder::VideoFrameReady");
92
93 if (bitstream_buffer_id ==
94 media::JpegDecodeAccelerator::kInvalidBitstreamBufferId)
wuchengli 2015/05/13 15:04:05 When will this happen? If this is an error, remove
kcwu 2015/05/25 18:20:34 Done.
95 return;
96
97 if (!IsDecoding()) {
98 LOG(ERROR) << "Got decode response while not decoding";
99 return;
100 }
101
102 if (bitstream_buffer_id != in_buffer_.id()) {
103 LOG(ERROR) << "Unexpected bitstream_buffer_id " << bitstream_buffer_id
104 << ", expected " << in_buffer_.id();
105 return;
106 }
107
108 decode_done_closure_.Run();
109 decode_done_closure_.Reset();
110
111 TRACE_EVENT_ASYNC_END0("jpeg", "GpuJpegDecoder decoding",
112 bitstream_buffer_id);
113 }
114
115 void GpuJpegDecoder::NotifyError(int32_t bitstream_buffer_id,
116 media::JpegDecodeAccelerator::Error error) {
117 DVLOG(3) << __func__;
118 DCHECK(jpeg_thread_proxy_->BelongsToCurrentThread());
119 LOG(ERROR) << "Decode error, bitstream_buffer_id=" << bitstream_buffer_id;
120
121 decode_done_closure_.Reset();
122
123 error_cb_.Run(
124 base::StringPrintf("Decode error, bitstream_buffer_id=%d, error=%d",
125 bitstream_buffer_id, error));
126 }
127
128 void GpuJpegDecoder::DecodeCapturedData(
129 const uint8* data,
130 size_t in_buffer_size,
131 const media::VideoCaptureFormat& frame_format,
132 const base::TimeTicks& timestamp,
133 scoped_ptr<media::VideoCaptureDevice::Client::Buffer> out_buffer) {
134 DCHECK(CalledOnValidThread());
135
136 jpeg_thread_proxy_->PostTask(
137 FROM_HERE,
138 base::Bind(
139 &GpuJpegDecoder::DecodeCapturedDataOnJpegThread,
140 base::Unretained(this),
141 data,
142 in_buffer_size,
143 frame_format,
144 timestamp,
145 base::Passed(&out_buffer)));
146
147 // Wait until |data| is copied out.
148 decode_event_.Wait();
149 }
150
151
152 void GpuJpegDecoder::DecodeCapturedDataOnJpegThread(
153 const uint8* data,
154 size_t in_buffer_size,
155 const media::VideoCaptureFormat& frame_format,
156 const base::TimeTicks& timestamp,
157 scoped_ptr<media::VideoCaptureDevice::Client::Buffer> out_buffer) {
158 DCHECK(jpeg_thread_proxy_->BelongsToCurrentThread());
159 TRACE_EVENT_ASYNC_BEGIN0("jpeg", "GpuJpegDecoder decoding",
160 next_bitstream_buffer_id_);
161 TRACE_EVENT0("jpeg", "GpuJpegDecoder::DecodeCapturedDataOnJpegThread");
162
163 // TODO(kcwu): enqueue decode requests in case decoding is not fast enough
164 // (say, if decoding time is longer than 16ms for 60fps 4k image)
165 if (IsDecoding()) {
166 DVLOG(1) << "Drop captured frame. Previous jpeg frame is still decoding";
167 decode_event_.Signal();
168 return;
169 }
170
171 // Enlarge input buffer if necessary.
172 if (!in_shared_memory_.get() ||
173 in_buffer_size > in_shared_memory_->mapped_size()) {
174 // Reserve 2x space to avoid frequently reallocate for initial frames.
175 size_t reserved_size = 2 * in_buffer_size;
176 in_shared_memory_.reset(new base::SharedMemory);
177 if (!in_shared_memory_->CreateAndMapAnonymous(reserved_size)) {
178 error_cb_.Run(base::StringPrintf("CreateAndMapAnonymous failed, size=%ld",
henryhsu 2015/05/12 09:42:03 There is a warning in arm platform. Please change
kcwu 2015/05/25 18:20:34 Done.
179 reserved_size));
180 decode_event_.Signal();
181 return;
182 }
183 }
184 memcpy(in_shared_memory_->memory(), data, in_buffer_size);
185 decode_event_.Signal();
186
187 in_buffer_ = media::BitstreamBuffer(
188 next_bitstream_buffer_id_, in_shared_memory_->handle(), in_buffer_size);
189 // Mask against 30 bits, to avoid (undefined) wraparound on signed integer.
190 next_bitstream_buffer_id_ = (next_bitstream_buffer_id_ + 1) & 0x3FFFFFFF;
191
192 const gfx::Size dimensions = frame_format.frame_size;
193 scoped_refptr<media::VideoFrame> out_frame =
194 media::VideoFrame::WrapExternalPackedMemory(
195 media::VideoFrame::I420,
196 dimensions,
197 gfx::Rect(dimensions),
198 dimensions,
199 reinterpret_cast<uint8*>(out_buffer->data()),
200 out_buffer->size(),
201 base::SharedMemoryHandle(out_buffer->AsPlatformHandle(), true),
202 0,
203 base::TimeDelta(),
204 base::Closure());
205 DCHECK(out_frame.get());
206 out_frame->metadata()->SetDouble(media::VideoFrameMetadata::FRAME_RATE,
207 frame_format.frame_rate);
208
209 decode_done_closure_ = base::Bind(decode_done_cb_, base::Passed(&out_buffer),
210 out_frame, timestamp);
211 decoder_->Decode(in_buffer_, out_frame);
212 }
213
214 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698