Chromium Code Reviews| Index: content/browser/renderer_host/media/video_capture_device_client.cc |
| diff --git a/content/browser/renderer_host/media/video_capture_device_client.cc b/content/browser/renderer_host/media/video_capture_device_client.cc |
| index e9900a5810f57cd2567a369ea3e00bf547e0f5ac..5cb91f6b476762420c675cd1e3dfbb9c2261abc3 100644 |
| --- a/content/browser/renderer_host/media/video_capture_device_client.cc |
| +++ b/content/browser/renderer_host/media/video_capture_device_client.cc |
| @@ -6,13 +6,18 @@ |
| #include "base/bind.h" |
| #include "base/strings/stringprintf.h" |
| +#include "base/synchronization/waitable_event.h" |
| #include "base/trace_event/trace_event.h" |
| +#include "content/browser/gpu/browser_gpu_channel_host_factory.h" |
| #include "content/browser/renderer_host/media/video_capture_buffer_pool.h" |
| #include "content/browser/renderer_host/media/video_capture_controller.h" |
| +#include "content/common/gpu/client/gpu_jpeg_decode_accelerator_host.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "media/base/bind_to_current_loop.h" |
| #include "media/base/video_capture_types.h" |
| #include "media/base/video_frame.h" |
| +#include "media/base/video_util.h" |
| +#include "media/base/yuv_convert.h" |
| #include "third_party/libyuv/include/libyuv.h" |
| using media::VideoCaptureFormat; |
| @@ -51,10 +56,79 @@ VideoCaptureDeviceClient::VideoCaptureDeviceClient( |
| const base::WeakPtr<VideoCaptureController>& controller, |
| const scoped_refptr<VideoCaptureBufferPool>& buffer_pool) |
| : controller_(controller), |
| + jpeg_decode_event_(nullptr), |
| buffer_pool_(buffer_pool), |
| - last_captured_pixel_format_(media::PIXEL_FORMAT_UNKNOWN) {} |
| + last_captured_pixel_format_(media::PIXEL_FORMAT_UNKNOWN), |
| + next_bitstream_buffer_id_(0) {} |
| -VideoCaptureDeviceClient::~VideoCaptureDeviceClient() {} |
| +VideoCaptureDeviceClient::~VideoCaptureDeviceClient() { |
| + if (jpeg_decoder_.get()) |
|
mcasas
2015/03/23 19:29:51
If |jpeg_decoder_| is created from the VCD, then i
kcwu
2015/03/30 18:12:14
jpeg_decoder_ is scoped_ptr(with DefaultDeleter),
|
| + jpeg_decoder_->Destroy(); |
| +} |
| + |
| +bool VideoCaptureDeviceClient::InitializeJpegDecoder() { |
|
mcasas
2015/03/23 19:29:51
This method looks convoluted and exposes too much
kcwu
2015/03/30 18:12:14
Using MJPEG or YUV formats is determined in VideoC
|
| + LOG(ERROR) << __func__; |
|
mcasas
2015/03/23 19:29:51
Suggest s/LOG(ERROR)/DVLOG(1)/
kcwu
2015/04/16 14:38:26
Done.
|
| + GpuChannelHost* host = |
|
mcasas
2015/03/23 19:29:51
GpuChannelHost* const
kcwu
2015/04/14 20:02:34
Done.
|
| + BrowserGpuChannelHostFactory::instance()->GetGpuChannel(); |
| + LOG(ERROR) << "host =" << host; |
| + GpuJpegDecodeAcceleratorHost* decoder = host->CreateJpegDecoder(); |
|
mcasas
2015/03/23 19:29:50
* const
kcwu
2015/04/14 20:02:33
Done.
|
| + if (!decoder->Initialize(this)) { |
| + decoder->Destroy(); |
| + return false; |
| + } |
| + jpeg_decoder_.reset(decoder); |
| + |
| + return true; |
| +} |
| + |
| +void VideoCaptureDeviceClient::VideoFrameReady( |
| + int32_t bitstream_buffer_id) { |
|
wuchengli
2015/03/23 06:30:14
Add DCHECK to make sure this runs on IO thread. Th
kcwu
2015/03/30 18:12:14
DCHECK added. But still PostTask because I want to
|
| + auto map_it = jpeg_decode_task_map_.find(bitstream_buffer_id); |
|
wuchengli
2015/03/23 06:30:14
Like you said, since you are blocking the v4l2 thr
kcwu
2015/03/30 18:12:14
This is refactored to async code.
|
| + if (map_it == jpeg_decode_task_map_.end()) { |
| + LOG(ERROR) << "VideoFrameReady unknown bitstream_buffer_id " |
| + << bitstream_buffer_id; |
| + return; |
| + } |
| + auto captured_data = map_it->second; |
| + auto frame_format = captured_data.frame_format; |
| + |
| + BrowserThread::PostTask( |
| + BrowserThread::IO, |
| + FROM_HERE, |
| + base::Bind( |
| + &VideoCaptureController::DoIncomingCapturedVideoFrameOnIOThread, |
| + controller_, |
| + captured_data.buffer, |
| + captured_data.frame, |
| + captured_data.timestamp)); |
| + |
| + jpeg_decode_task_map_.erase(map_it); |
| + |
| + CHECK(jpeg_decode_event_); |
| + jpeg_decode_event_->Signal(); |
| +} |
| + |
| +void VideoCaptureDeviceClient::NotifyError( |
| + int32_t bitstream_buffer_id, |
| + media::JpegDecodeAccelerator::Error error) { |
| + LOG(ERROR) << "NotifyError"; |
| + |
| + auto map_it = jpeg_decode_task_map_.find(bitstream_buffer_id); |
| + if (map_it != jpeg_decode_task_map_.end()) { |
| + auto captured_data = map_it->second; |
| + LOG(ERROR) << "fallback to software decode *******************************"; |
| + OnIncomingCapturedData2(captured_data); |
| + jpeg_decode_task_map_.erase(map_it); |
| + CHECK(jpeg_decode_event_); |
| + jpeg_decode_event_->Signal(); |
| + return; |
| + } |
| + |
| + // TODO(kcwu) |
| + LOG(ERROR) << "give up???"; |
| + CHECK(jpeg_decode_event_); |
| + jpeg_decode_event_->Signal(); |
| +} |
| void VideoCaptureDeviceClient::OnIncomingCapturedData( |
| const uint8* data, |
| @@ -64,6 +138,13 @@ void VideoCaptureDeviceClient::OnIncomingCapturedData( |
| const base::TimeTicks& timestamp) { |
| TRACE_EVENT0("video", "VideoCaptureController::OnIncomingCapturedData"); |
| + CapturedData captured_data; |
| + captured_data.data = data; |
| + captured_data.length = length; |
| + captured_data.frame_format = frame_format; |
| + captured_data.rotation = rotation; |
| + captured_data.timestamp = timestamp; |
| + |
| if (last_captured_pixel_format_ != frame_format.pixel_format) { |
| OnLog("Pixel format: " + media::VideoCaptureFormat::PixelFormatToString( |
| frame_format.pixel_format)); |
| @@ -73,8 +154,96 @@ void VideoCaptureDeviceClient::OnIncomingCapturedData( |
| if (!frame_format.IsValid()) |
| return; |
| + const gfx::Size size = frame_format.frame_size; |
| + if (rotation != 0 || frame_format.pixel_format != media::PIXEL_FORMAT_MJPEG || |
| + size.width() % 2 != 0 || size.height() % 2 != 0) { |
| + OnIncomingCapturedData2(captured_data); |
|
wuchengli
2015/03/23 06:30:14
Please measure the decode time of both cases and p
kcwu
2015/04/14 20:02:34
Acknowledged.
|
| + return; |
| + } |
| + |
| + base::SharedMemory in_memory; |
| + gfx::Size dimensions = frame_format.frame_size; |
| + size_t in_buffer_size = length; |
| + scoped_refptr<Buffer> out_buffer = |
| + ReserveOutputBuffer(media::VideoFrame::I420, dimensions); |
| + captured_data.buffer = out_buffer; |
| + |
| + if (in_memory.CreateAnonymous(in_buffer_size) && |
| + in_memory.Map(in_buffer_size)) { |
| + media::BitstreamBuffer in_buffer(next_bitstream_buffer_id_, |
| + in_memory.handle(), |
| + in_buffer_size); |
| + // Mask against 30 bits, to avoid (undefined) wraparound on signed integer. |
| + next_bitstream_buffer_id_ = (next_bitstream_buffer_id_ + 1) & 0x3FFFFFFF; |
| + |
| + base::SharedMemoryHandle buffer_handle = |
| + buffer_pool_->GetBufferSharedMemory(out_buffer->id()); |
| + |
| + uint8* shm_memory = reinterpret_cast<uint8*>(in_memory.memory()); |
| + memcpy(shm_memory, data, length); |
| + |
|
mcasas
2015/03/23 19:29:50
There's a lot of extra code to just maintain the i
kcwu
2015/03/30 18:12:14
Done.
|
| + scoped_refptr<media::VideoFrame> out_frame = |
| + media::VideoFrame::WrapExternalPackedMemory( |
| + media::VideoFrame::I420, |
| + dimensions, |
| + gfx::Rect(dimensions), |
| + dimensions, |
| + reinterpret_cast<uint8*>(out_buffer->data()), |
| + out_buffer->size(), |
| + buffer_handle, |
| + 0, |
| + base::TimeDelta(), |
| + base::Closure()); |
|
wuchengli
2015/03/23 06:30:14
Set framerate like line 387.
frame->metadata()->Se
kcwu
2015/03/30 18:12:14
Done.
|
| + DCHECK(out_frame.get()); |
| + |
| + captured_data.frame = out_frame; |
| + jpeg_decode_task_map_[in_buffer.id()] = captured_data; |
| + |
| + CHECK(!jpeg_decode_event_); |
| + jpeg_decode_event_ = new base::WaitableEvent(false, false); |
|
wuchengli
2015/03/23 06:30:14
Use scoped_ptr
kcwu
2015/03/30 18:12:14
Code removed.
|
| + |
| + BrowserThread::PostTask( |
| + BrowserThread::IO, |
| + FROM_HERE, |
| + base::Bind( |
| + &VideoCaptureDeviceClient::DecodeJpegOnIOThread, |
|
wuchengli
2015/03/23 06:30:14
Post to JpegDecodeAccelerator::Decode directly.
kcwu
2015/03/30 18:12:14
Modified to call Decode() directly.
|
| + base::Unretained(this), |
| + in_buffer, |
| + out_frame)); |
| + |
| + jpeg_decode_event_->Wait(); |
| + delete jpeg_decode_event_; |
| + jpeg_decode_event_ = nullptr; |
| + } |
| +} |
| + |
| +void VideoCaptureDeviceClient::DecodeJpegOnIOThread( |
| + media::BitstreamBuffer in_buffer, |
| + scoped_refptr<media::VideoFrame> out_frame) { |
| + DCHECK(jpeg_decoder_); |
| + |
| + jpeg_decoder_->Decode(in_buffer, out_frame); |
| +} |
| + |
| +// TODO(kcwu): need better name |
| +void VideoCaptureDeviceClient::OnIncomingCapturedData2( |
| + const CapturedData& captured_data) { |
| + |
| + const uint8* data = captured_data.data; |
| + int length = captured_data.length; |
| + const VideoCaptureFormat& frame_format = captured_data.frame_format; |
| + int rotation = captured_data.rotation; |
| + base::TimeTicks timestamp = captured_data.timestamp; |
| + |
| + if (last_captured_pixel_format_ != frame_format.pixel_format) { |
| + OnLog("Pixel format: " + media::VideoCaptureFormat::PixelFormatToString( |
| + frame_format.pixel_format)); |
| + last_captured_pixel_format_ = frame_format.pixel_format; |
| + } |
| + |
| // Chopped pixels in width/height in case video capture device has odd |
| // numbers for width/height. |
| + // XXX kcwu: why crop?? |
| int chopped_width = 0; |
| int chopped_height = 0; |
| int new_unrotated_width = frame_format.frame_size.width(); |