Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / content / browser / renderer_host / media / video_capture_gpu_jpeg_decoder.cc
blob12ead3c6a7136dcd3e13c3a97bbd28111bebcb70
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/metrics/histogram.h"
11 #include "base/single_thread_task_runner.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/thread_task_runner_handle.h"
14 #include "base/trace_event/trace_event.h"
15 #include "content/browser/gpu/browser_gpu_channel_host_factory.h"
16 #include "content/common/gpu/client/gpu_jpeg_decode_accelerator_host.h"
17 #include "content/public/browser/browser_thread.h"
18 #include "content/public/common/content_switches.h"
19 #include "media/base/video_frame.h"
21 namespace content {
23 VideoCaptureGpuJpegDecoder::VideoCaptureGpuJpegDecoder(
24 const DecodeDoneCB& decode_done_cb)
25 : decode_done_cb_(decode_done_cb),
26 next_bitstream_buffer_id_(0),
27 in_buffer_id_(media::JpegDecodeAccelerator::kInvalidBitstreamBufferId),
28 decoder_status_(INIT_PENDING) {}
30 VideoCaptureGpuJpegDecoder::~VideoCaptureGpuJpegDecoder() {
31 DCHECK(CalledOnValidThread());
33 // |decoder_| guarantees no more JpegDecodeAccelerator::Client callbacks
34 // on IO thread after deletion.
35 decoder_.reset();
37 // |gpu_channel_host_| should outlive |decoder_|, so |gpu_channel_host_|
38 // must be released after |decoder_| has been destroyed.
39 gpu_channel_host_ = nullptr;
42 void VideoCaptureGpuJpegDecoder::Initialize() {
43 DCHECK(CalledOnValidThread());
45 base::AutoLock lock(lock_);
46 // TODO(henryhsu): enable on ARM platform after V4L2 JpegDecodeAccelerator is
47 // ready.
48 bool is_platform_supported = false;
49 #if defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY)
50 // Non-ChromeOS platforms do not support HW JPEG decode now. Do not establish
51 // gpu channel to avoid introducing overhead.
52 is_platform_supported = true;
53 #endif
55 if (!is_platform_supported ||
56 base::CommandLine::ForCurrentProcess()->HasSwitch(
57 switches::kDisableAcceleratedMjpegDecode)) {
58 decoder_status_ = FAILED;
59 RecordInitDecodeUMA_Locked();
60 return;
63 const scoped_refptr<base::SingleThreadTaskRunner> current_task_runner(
64 base::ThreadTaskRunnerHandle::Get());
65 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
66 base::Bind(&EstablishGpuChannelOnUIThread,
67 current_task_runner, AsWeakPtr()));
70 VideoCaptureGpuJpegDecoder::STATUS VideoCaptureGpuJpegDecoder::GetStatus()
71 const {
72 DCHECK(CalledOnValidThread());
73 base::AutoLock lock(lock_);
74 return decoder_status_;
77 void VideoCaptureGpuJpegDecoder::DecodeCapturedData(
78 const uint8_t* data,
79 size_t in_buffer_size,
80 const media::VideoCaptureFormat& frame_format,
81 const base::TimeTicks& timestamp,
82 scoped_ptr<media::VideoCaptureDevice::Client::Buffer> out_buffer) {
83 DCHECK(CalledOnValidThread());
84 DCHECK(decoder_);
86 TRACE_EVENT_ASYNC_BEGIN0("jpeg", "VideoCaptureGpuJpegDecoder decoding",
87 next_bitstream_buffer_id_);
88 TRACE_EVENT0("jpeg", "VideoCaptureGpuJpegDecoder::DecodeCapturedData");
90 // TODO(kcwu): enqueue decode requests in case decoding is not fast enough
91 // (say, if decoding time is longer than 16ms for 60fps 4k image)
93 base::AutoLock lock(lock_);
94 if (IsDecoding_Locked()) {
95 DVLOG(1) << "Drop captured frame. Previous jpeg frame is still decoding";
96 return;
100 // Enlarge input buffer if necessary.
101 if (!in_shared_memory_.get() ||
102 in_buffer_size > in_shared_memory_->mapped_size()) {
103 // Reserve 2x space to avoid frequent reallocations for initial frames.
104 const size_t reserved_size = 2 * in_buffer_size;
105 in_shared_memory_.reset(new base::SharedMemory);
106 if (!in_shared_memory_->CreateAndMapAnonymous(reserved_size)) {
107 base::AutoLock lock(lock_);
108 decoder_status_ = FAILED;
109 LOG(WARNING) << "CreateAndMapAnonymous failed, size=" << reserved_size;
110 return;
113 memcpy(in_shared_memory_->memory(), data, in_buffer_size);
115 // No need to lock for |in_buffer_id_| since IsDecoding_Locked() is false.
116 in_buffer_id_ = next_bitstream_buffer_id_;
117 media::BitstreamBuffer in_buffer(in_buffer_id_, in_shared_memory_->handle(),
118 in_buffer_size);
119 // Mask against 30 bits, to avoid (undefined) wraparound on signed integer.
120 next_bitstream_buffer_id_ = (next_bitstream_buffer_id_ + 1) & 0x3FFFFFFF;
122 #if defined(OS_POSIX) && !(defined(OS_MACOSX) && !defined(OS_IOS))
123 const gfx::Size dimensions = frame_format.frame_size;
124 base::SharedMemoryHandle out_handle = out_buffer->AsPlatformFile();
125 scoped_refptr<media::VideoFrame> out_frame =
126 media::VideoFrame::WrapExternalSharedMemory(
127 media::PIXEL_FORMAT_I420, // format
128 dimensions, // coded_size
129 gfx::Rect(dimensions), // visible_rect
130 dimensions, // natural_size
131 static_cast<uint8_t*>(out_buffer->data()), // data
132 out_buffer->mapped_size(), // data_size
133 out_handle, // handle
134 0, // shared_memory_offset
135 base::TimeDelta()); // timestamp
136 if (!out_frame) {
137 base::AutoLock lock(lock_);
138 decoder_status_ = FAILED;
139 LOG(ERROR) << "DecodeCapturedData: WrapExternalSharedMemory failed";
140 return;
142 out_frame->metadata()->SetDouble(media::VideoFrameMetadata::FRAME_RATE,
143 frame_format.frame_rate);
146 base::AutoLock lock(lock_);
147 decode_done_closure_ = base::Bind(
148 decode_done_cb_, base::Passed(&out_buffer), out_frame, timestamp);
150 decoder_->Decode(in_buffer, out_frame);
151 #else
152 NOTREACHED();
153 #endif
156 void VideoCaptureGpuJpegDecoder::VideoFrameReady(int32_t bitstream_buffer_id) {
157 DCHECK_CURRENTLY_ON(BrowserThread::IO);
158 TRACE_EVENT0("jpeg", "VideoCaptureGpuJpegDecoder::VideoFrameReady");
159 base::AutoLock lock(lock_);
161 if (!IsDecoding_Locked()) {
162 LOG(ERROR) << "Got decode response while not decoding";
163 return;
166 if (bitstream_buffer_id != in_buffer_id_) {
167 LOG(ERROR) << "Unexpected bitstream_buffer_id " << bitstream_buffer_id
168 << ", expected " << in_buffer_id_;
169 return;
171 in_buffer_id_ = media::JpegDecodeAccelerator::kInvalidBitstreamBufferId;
173 decode_done_closure_.Run();
174 decode_done_closure_.Reset();
176 TRACE_EVENT_ASYNC_END0("jpeg", "VideoCaptureGpuJpegDecoder decoding",
177 bitstream_buffer_id);
180 void VideoCaptureGpuJpegDecoder::NotifyError(
181 int32_t bitstream_buffer_id,
182 media::JpegDecodeAccelerator::Error error) {
183 DCHECK_CURRENTLY_ON(BrowserThread::IO);
184 LOG(ERROR) << "Decode error, bitstream_buffer_id=" << bitstream_buffer_id
185 << ", error=" << error;
187 base::AutoLock lock(lock_);
188 decode_done_closure_.Reset();
189 decoder_status_ = FAILED;
192 // static
193 void VideoCaptureGpuJpegDecoder::EstablishGpuChannelOnUIThread(
194 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
195 base::WeakPtr<VideoCaptureGpuJpegDecoder> weak_this) {
196 DCHECK_CURRENTLY_ON(BrowserThread::UI);
197 DCHECK(BrowserGpuChannelHostFactory::instance());
199 BrowserGpuChannelHostFactory::instance()->EstablishGpuChannel(
200 CAUSE_FOR_GPU_LAUNCH_JPEGDECODEACCELERATOR_INITIALIZE,
201 base::Bind(&VideoCaptureGpuJpegDecoder::GpuChannelEstablishedOnUIThread,
202 task_runner, weak_this));
205 // static
206 void VideoCaptureGpuJpegDecoder::GpuChannelEstablishedOnUIThread(
207 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
208 base::WeakPtr<VideoCaptureGpuJpegDecoder> weak_this) {
209 DCHECK_CURRENTLY_ON(BrowserThread::UI);
211 scoped_refptr<GpuChannelHost> gpu_channel_host(
212 BrowserGpuChannelHostFactory::instance()->GetGpuChannel());
213 task_runner->PostTask(
214 FROM_HERE, base::Bind(&VideoCaptureGpuJpegDecoder::FinishInitialization,
215 weak_this, base::Passed(&gpu_channel_host)));
218 void VideoCaptureGpuJpegDecoder::FinishInitialization(
219 scoped_refptr<GpuChannelHost> gpu_channel_host) {
220 DCHECK(CalledOnValidThread());
221 base::AutoLock lock(lock_);
222 if (!gpu_channel_host) {
223 LOG(ERROR) << "Failed to establish GPU channel for JPEG decoder";
224 } else if (gpu_channel_host->gpu_info().jpeg_decode_accelerator_supported) {
225 gpu_channel_host_ = gpu_channel_host.Pass();
226 decoder_ = gpu_channel_host_->CreateJpegDecoder(this);
228 decoder_status_ = decoder_ ? INIT_PASSED : FAILED;
229 RecordInitDecodeUMA_Locked();
232 bool VideoCaptureGpuJpegDecoder::IsDecoding_Locked() const {
233 lock_.AssertAcquired();
234 return !decode_done_closure_.is_null();
237 void VideoCaptureGpuJpegDecoder::RecordInitDecodeUMA_Locked() {
238 UMA_HISTOGRAM_BOOLEAN("Media.VideoCaptureGpuJpegDecoder.InitDecodeSuccess",
239 decoder_status_ == INIT_PASSED);
242 } // namespace content