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"
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"
22 VideoCaptureGpuJpegDecoder::VideoCaptureGpuJpegDecoder(
23 const DecodeDoneCB
& decode_done_cb
,
24 const ErrorCB
& error_cb
)
25 : decode_done_cb_(decode_done_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.
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
;
58 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
59 switches::kEnableAcceleratedMjpegDecode
)) {
60 init_status_
= INIT_FAILED
;
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()));
72 VideoCaptureGpuJpegDecoder::Status
VideoCaptureGpuJpegDecoder::GetStatus() {
73 DCHECK(CalledOnValidThread());
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
));
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
;
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";
129 if (bitstream_buffer_id
!= in_buffer_id_
) {
130 LOG(ERROR
) << "Unexpected bitstream_buffer_id " << bitstream_buffer_id
131 << ", expected " << in_buffer_id_
;
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();
154 base::StringPrintf("JPEG Decode error, bitstream_buffer_id=%d, error=%d",
155 bitstream_buffer_id
, error
));
158 void VideoCaptureGpuJpegDecoder::DecodeCapturedData(
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());
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";
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",
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(),
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
218 base::AutoLock
lock(lock_
);
219 error_cb_
.Run("DecodeCapturedData: WrapExternalSharedMemory");
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
);
236 } // namespace content