Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / content / browser / renderer_host / media / video_capture_gpu_jpeg_decoder.cc
blob011d8e8e1b7a93676443208d71ad35a3ff72f552
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.
5 #include "content/browser/renderer_host/media/video_capture_gpu_jpeg_decoder.h"
7 #include "base/bind.h"
8 #include "base/command_line.h"
9 #include "base/logging.h"
10 #include "base/single_thread_task_runner.h"
11 #include "base/strings/stringprintf.h"
12 #include "base/thread_task_runner_handle.h"
13 #include "base/trace_event/trace_event.h"
14 #include "content/browser/gpu/browser_gpu_channel_host_factory.h"
15 #include "content/common/gpu/client/gpu_jpeg_decode_accelerator_host.h"
16 #include "content/public/browser/browser_thread.h"
17 #include "content/public/common/content_switches.h"
18 #include "media/base/video_frame.h"
20 namespace content {
22 VideoCaptureGpuJpegDecoder::VideoCaptureGpuJpegDecoder(
23 const DecodeDoneCB& decode_done_cb,
24 const ErrorCB& error_cb)
25 : decode_done_cb_(decode_done_cb),
26 error_cb_(error_cb),
27 next_bitstream_buffer_id_(0),
28 in_buffer_id_(media::JpegDecodeAccelerator::kInvalidBitstreamBufferId),
29 init_status_(INIT_PENDING) {
32 VideoCaptureGpuJpegDecoder::~VideoCaptureGpuJpegDecoder() {
33 DCHECK(CalledOnValidThread());
35 // |decoder_| guarantees no more JpegDecodeAccelerator::Client callbacks
36 // on IO thread after deletion.
37 decoder_.reset();
39 // |gpu_channel_host_| should outlive |decoder_|, so |gpu_channel_host_|
40 // must be released after |decoder_| has been destroyed.
41 gpu_channel_host_ = nullptr;
44 bool VideoCaptureGpuJpegDecoder::IsDecoding_Locked() {
45 lock_.AssertAcquired();
46 return !decode_done_closure_.is_null();
49 void VideoCaptureGpuJpegDecoder::Initialize() {
50 DCHECK(CalledOnValidThread());
52 // Non-ChromeOS platforms do not support HW JPEG decode now. Do not establish
53 // gpu channel to introduce overhead.
54 #if !defined(OS_CHROMEOS)
55 init_status_ = INIT_FAILED;
56 return;
57 #else
58 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
59 switches::kEnableAcceleratedMjpegDecode)) {
60 init_status_ = INIT_FAILED;
61 return;
64 const scoped_refptr<base::SingleThreadTaskRunner> current_task_runner(
65 base::ThreadTaskRunnerHandle::Get());
66 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
67 base::Bind(&EstablishGpuChannelOnUIThread,
68 current_task_runner, AsWeakPtr()));
69 #endif
72 VideoCaptureGpuJpegDecoder::Status VideoCaptureGpuJpegDecoder::GetStatus() {
73 DCHECK(CalledOnValidThread());
74 return init_status_;
77 // static
78 void VideoCaptureGpuJpegDecoder::EstablishGpuChannelOnUIThread(
79 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
80 base::WeakPtr<VideoCaptureGpuJpegDecoder> weak_this) {
81 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
82 DCHECK(BrowserGpuChannelHostFactory::instance());
84 BrowserGpuChannelHostFactory::instance()->EstablishGpuChannel(
85 CAUSE_FOR_GPU_LAUNCH_JPEGDECODEACCELERATOR_INITIALIZE,
86 base::Bind(&VideoCaptureGpuJpegDecoder::GpuChannelEstablishedOnUIThread,
87 task_runner, weak_this));
90 // static
91 void VideoCaptureGpuJpegDecoder::GpuChannelEstablishedOnUIThread(
92 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
93 base::WeakPtr<VideoCaptureGpuJpegDecoder> weak_this) {
94 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
96 scoped_refptr<GpuChannelHost> gpu_channel_host(
97 BrowserGpuChannelHostFactory::instance()->GetGpuChannel());
98 task_runner->PostTask(FROM_HERE,
99 base::Bind(&VideoCaptureGpuJpegDecoder::InitializeDone,
100 weak_this, base::Passed(&gpu_channel_host)));
103 void VideoCaptureGpuJpegDecoder::InitializeDone(
104 scoped_refptr<GpuChannelHost> gpu_channel_host) {
105 DCHECK(CalledOnValidThread());
106 if (!gpu_channel_host) {
107 LOG(ERROR) << "Failed to establish GPU channel for JPEG decoder";
108 init_status_ = INIT_FAILED;
109 return;
112 if (gpu_channel_host->gpu_info().jpeg_decode_accelerator_supported) {
113 gpu_channel_host_ = gpu_channel_host.Pass();
114 decoder_ = gpu_channel_host_->CreateJpegDecoder(this);
116 init_status_ = decoder_ ? INIT_PASSED : INIT_FAILED;
119 void VideoCaptureGpuJpegDecoder::VideoFrameReady(int32_t bitstream_buffer_id) {
120 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
121 TRACE_EVENT0("jpeg", "VideoCaptureGpuJpegDecoder::VideoFrameReady");
122 base::AutoLock lock(lock_);
124 if (!IsDecoding_Locked()) {
125 LOG(ERROR) << "Got decode response while not decoding";
126 return;
129 if (bitstream_buffer_id != in_buffer_id_) {
130 LOG(ERROR) << "Unexpected bitstream_buffer_id " << bitstream_buffer_id
131 << ", expected " << in_buffer_id_;
132 return;
134 in_buffer_id_ = media::JpegDecodeAccelerator::kInvalidBitstreamBufferId;
136 decode_done_closure_.Run();
137 decode_done_closure_.Reset();
139 TRACE_EVENT_ASYNC_END0("jpeg", "VideoCaptureGpuJpegDecoder decoding",
140 bitstream_buffer_id);
143 void VideoCaptureGpuJpegDecoder::NotifyError(
144 int32_t bitstream_buffer_id,
145 media::JpegDecodeAccelerator::Error error) {
146 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
147 LOG(ERROR) << "Decode error, bitstream_buffer_id=" << bitstream_buffer_id
148 << ", error=" << error;
150 base::AutoLock lock(lock_);
151 decode_done_closure_.Reset();
153 error_cb_.Run(
154 base::StringPrintf("JPEG Decode error, bitstream_buffer_id=%d, error=%d",
155 bitstream_buffer_id, error));
158 void VideoCaptureGpuJpegDecoder::DecodeCapturedData(
159 const uint8_t* data,
160 size_t in_buffer_size,
161 const media::VideoCaptureFormat& frame_format,
162 const base::TimeTicks& timestamp,
163 scoped_ptr<media::VideoCaptureDevice::Client::Buffer> out_buffer) {
164 DCHECK(CalledOnValidThread());
165 DCHECK(decoder_);
167 TRACE_EVENT_ASYNC_BEGIN0("jpeg", "VideoCaptureGpuJpegDecoder decoding",
168 next_bitstream_buffer_id_);
169 TRACE_EVENT0("jpeg", "VideoCaptureGpuJpegDecoder::DecodeCapturedData");
171 // TODO(kcwu): enqueue decode requests in case decoding is not fast enough
172 // (say, if decoding time is longer than 16ms for 60fps 4k image)
174 base::AutoLock lock(lock_);
175 if (IsDecoding_Locked()) {
176 DVLOG(1) << "Drop captured frame. Previous jpeg frame is still decoding";
177 return;
181 // Enlarge input buffer if necessary.
182 if (!in_shared_memory_.get() ||
183 in_buffer_size > in_shared_memory_->mapped_size()) {
184 // Reserve 2x space to avoid frequent reallocations for initial frames.
185 const size_t reserved_size = 2 * in_buffer_size;
186 in_shared_memory_.reset(new base::SharedMemory);
187 if (!in_shared_memory_->CreateAndMapAnonymous(reserved_size)) {
188 base::AutoLock lock(lock_);
189 error_cb_.Run(base::StringPrintf("CreateAndMapAnonymous failed, size=%zd",
190 reserved_size));
191 return;
194 memcpy(in_shared_memory_->memory(), data, in_buffer_size);
196 // No need to lock for |in_buffer_id_| since IsDecoding_Locked() is false.
197 in_buffer_id_ = next_bitstream_buffer_id_;
198 media::BitstreamBuffer in_buffer(in_buffer_id_, in_shared_memory_->handle(),
199 in_buffer_size);
200 // Mask against 30 bits, to avoid (undefined) wraparound on signed integer.
201 next_bitstream_buffer_id_ = (next_bitstream_buffer_id_ + 1) & 0x3FFFFFFF;
203 #if defined(OS_POSIX) && !(defined(OS_MACOSX) && !defined(OS_IOS))
204 const gfx::Size dimensions = frame_format.frame_size;
205 base::SharedMemoryHandle out_handle = out_buffer->AsPlatformFile();
206 scoped_refptr<media::VideoFrame> out_frame =
207 media::VideoFrame::WrapExternalSharedMemory(
208 media::PIXEL_FORMAT_I420, // format
209 dimensions, // coded_size
210 gfx::Rect(dimensions), // visible_rect
211 dimensions, // natural_size
212 static_cast<uint8_t*>(out_buffer->data()), // data
213 out_buffer->size(), // data_size
214 out_handle, // handle
215 0, // shared_memory_offset
216 base::TimeDelta()); // timestamp
217 if (!out_frame) {
218 base::AutoLock lock(lock_);
219 error_cb_.Run("DecodeCapturedData: WrapExternalSharedMemory");
220 return;
222 out_frame->metadata()->SetDouble(media::VideoFrameMetadata::FRAME_RATE,
223 frame_format.frame_rate);
226 base::AutoLock lock(lock_);
227 decode_done_closure_ = base::Bind(
228 decode_done_cb_, base::Passed(&out_buffer), out_frame, timestamp);
230 decoder_->Decode(in_buffer, out_frame);
231 #else
232 NOTREACHED();
233 #endif
236 } // namespace content