Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "media/video/capture/fake_video_capture_device.h" | 5 #include "media/video/capture/fake_video_capture_device.h" |
| 6 | 6 |
| 7 #include <string> | 7 #include <string> |
| 8 | 8 |
| 9 #if defined(OS_CHROMEOS) && defined(USE_OZONE) | |
| 10 #include <errno.h> | |
| 11 #include <sys/fcntl.h> | |
| 12 #include <sys/mman.h> | |
| 13 #include <xf86drm.h> | |
| 14 #endif | |
| 15 | |
| 9 #include "base/bind.h" | 16 #include "base/bind.h" |
| 10 #include "base/memory/scoped_ptr.h" | 17 #include "base/memory/scoped_ptr.h" |
| 11 #include "base/strings/stringprintf.h" | 18 #include "base/strings/stringprintf.h" |
| 12 #include "media/audio/fake_audio_input_stream.h" | 19 #include "media/audio/fake_audio_input_stream.h" |
| 13 #include "media/base/video_frame.h" | 20 #include "media/base/video_frame.h" |
| 14 #include "third_party/skia/include/core/SkBitmap.h" | 21 #include "third_party/skia/include/core/SkBitmap.h" |
| 15 #include "third_party/skia/include/core/SkCanvas.h" | 22 #include "third_party/skia/include/core/SkCanvas.h" |
| 16 #include "third_party/skia/include/core/SkPaint.h" | 23 #include "third_party/skia/include/core/SkPaint.h" |
| 17 | 24 |
| 25 #if defined(OS_CHROMEOS) && defined(USE_OZONE) | |
| 26 #include "base/files/file_enumerator.h" | |
| 27 #include "base/posix/eintr_wrapper.h" | |
| 28 #include "base/strings/string_util.h" | |
| 29 #endif | |
| 30 | |
| 18 namespace media { | 31 namespace media { |
| 19 | 32 |
| 20 static const int kFakeCaptureBeepCycle = 10; // Visual beep every 0.5s. | 33 static const int kFakeCaptureBeepCycle = 10; // Visual beep every 0.5s. |
| 21 | 34 |
| 35 #if defined(OS_CHROMEOS) && defined(USE_OZONE) | |
| 36 static const char kVgemSysCardPath[] = "/sys/bus/platform/devices/vgem/drm/"; | |
| 37 static const char kVgemDevDriCardPathFormat[] = "/dev/dri/card%d"; | |
| 38 | |
| 39 // Class to encapsulate opening the Vgem Fd and using it for mmap()ing and | |
| 40 // munmap()ing an incoming PrimeFd representing a Dma-Buf. | |
| 41 class FakeVideoCaptureDevice::VgemWrapper { | |
| 42 public: | |
| 43 VgemWrapper() {} | |
| 44 ~VgemWrapper() {} | |
| 45 | |
| 46 // Finds out the /dev/dri/cardX associated with the Vgem, if any, and tries to | |
| 47 // open it. IsValid() tells if it has succeeded. | |
| 48 void Initialize(); | |
| 49 bool IsValid() const { return vgem_fd_.is_valid(); } | |
| 50 | |
| 51 // Tries to mmap() and incoming Dma-Buf PrimeFd into process space. | |
| 52 uint8* MmapPrimeFd(base::PlatformFile dma_buf_fd, size_t size); | |
| 53 // munmap()s the given |data_ptr| obtained from MmapPrimeFd(). | |
| 54 void MunmapPointer(uint8* data_ptr, size_t size); | |
| 55 | |
| 56 private: | |
| 57 base::ScopedFD vgem_fd_; | |
| 58 }; | |
| 59 | |
| 60 void FakeVideoCaptureDevice::VgemWrapper::Initialize() { | |
| 61 // VGEM fd is a /dev/dri device but we cannot know in advance which one, for | |
| 62 // that we inspect the /sys/.../vgem/.../cardX, if we find one such card, then | |
| 63 // VGEM is present in the system and we can reuse the index. | |
| 64 base::FileEnumerator file_iter( | |
| 65 base::FilePath::FromUTF8Unsafe(kVgemSysCardPath), | |
| 66 true, | |
| 67 base::FileEnumerator::FILES, | |
|
dshwang
2015/05/12 12:58:44
false, base::FileEnumerator::DIRECTORIES,
I use t
| |
| 68 FILE_PATH_LITERAL("card*")); | |
| 69 | |
| 70 while (!file_iter.Next().empty()) { | |
| 71 // Inspect the card%d files in the directory, if any. Extract the index. | |
| 72 DVLOG(1) << file_iter.GetInfo().GetName().BaseName().MaybeAsASCII(); | |
| 73 std::string name(file_iter.GetInfo().GetName().BaseName().MaybeAsASCII()); | |
| 74 base::TrimString(name, "card", &name); | |
| 75 errno = 0; | |
| 76 const int device_index = strtol(name.c_str(), NULL, 10); | |
| 77 DLOG_IF(ERROR, errno != 0) << "Error extracting integer from " << name; | |
| 78 if (errno != 0) | |
| 79 return; | |
| 80 | |
| 81 const base::FilePath vgem_path = base::FilePath( | |
| 82 base::StringPrintf(kVgemDevDriCardPathFormat, device_index)); | |
| 83 DVLOG(1) << "possible Vgem fd is " << vgem_path.MaybeAsASCII(); | |
| 84 | |
| 85 vgem_fd_.reset( | |
| 86 HANDLE_EINTR(open(vgem_path.MaybeAsASCII().c_str(), O_RDWR))); | |
| 87 if (vgem_fd_.is_valid()) { | |
| 88 DVLOG(1) << "Opened Vgem file " << vgem_path.MaybeAsASCII(); | |
| 89 return; | |
| 90 } | |
| 91 DLOG(ERROR) << "Failed to open vgem device driver file " | |
| 92 << vgem_path.MaybeAsASCII(); | |
| 93 } | |
| 94 } | |
| 95 | |
| 96 uint8* FakeVideoCaptureDevice::VgemWrapper::MmapPrimeFd( | |
| 97 base::PlatformFile dma_buf_fd, | |
| 98 size_t size) { | |
| 99 uint32_t foreign_imported_handle; | |
| 100 int result = drmPrimeFDToHandle(vgem_fd_.get(), | |
| 101 dma_buf_fd, | |
| 102 &foreign_imported_handle); | |
| 103 if (result) { | |
| 104 DLOG(ERROR) << "Error mapping PrimeFd to Handle"; | |
| 105 return nullptr; | |
| 106 } | |
| 107 | |
| 108 struct drm_mode_map_dumb mmap_arg = {}; | |
| 109 mmap_arg.handle = foreign_imported_handle; | |
| 110 result = drmIoctl(vgem_fd_.get(), | |
| 111 DRM_IOCTL_MODE_MAP_DUMB, | |
| 112 &mmap_arg); | |
| 113 if (result || (mmap_arg.offset == 0u)) { | |
| 114 DLOG(ERROR) << "Error preparing Handle to be mmap()ed"; | |
| 115 return nullptr; | |
| 116 } | |
| 117 | |
| 118 void* data_ptr = mmap(NULL, size, (PROT_READ | PROT_WRITE), MAP_SHARED, | |
| 119 vgem_fd_.get(), mmap_arg.offset); | |
| 120 if (data_ptr == MAP_FAILED) { | |
| 121 DLOG(ERROR) << "Error mmap()ing the dma-buf into userspace"; | |
| 122 return nullptr; | |
| 123 } | |
| 124 return static_cast<uint8*>(data_ptr); | |
| 125 } | |
| 126 | |
| 127 void FakeVideoCaptureDevice::VgemWrapper::MunmapPointer( | |
| 128 uint8* data_ptr, size_t size) { | |
| 129 munmap(data_ptr, size); | |
| 130 } | |
| 131 #endif | |
| 132 | |
| 22 void DrawPacman(bool use_argb, | 133 void DrawPacman(bool use_argb, |
| 23 uint8_t* const data, | 134 uint8_t* const data, |
| 24 int frame_count, | 135 int frame_count, |
| 25 int frame_interval, | 136 int frame_interval, |
| 26 const gfx::Size& frame_size) { | 137 const gfx::Size& frame_size) { |
| 27 // |kN32_SkColorType| stands for the appropriiate RGBA/BGRA format. | 138 // |kN32_SkColorType| stands for the appropriiate RGBA/BGRA format. |
| 28 const SkColorType colorspace = | 139 const SkColorType colorspace = |
| 29 use_argb ? kN32_SkColorType : kAlpha_8_SkColorType; | 140 use_argb ? kN32_SkColorType : kAlpha_8_SkColorType; |
| 30 const SkImageInfo info = SkImageInfo::Make(frame_size.width(), | 141 const SkImageInfo info = SkImageInfo::Make(frame_size.width(), |
| 31 frame_size.height(), | 142 frame_size.height(), |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 94 capture_format_.frame_rate = 30.0; | 205 capture_format_.frame_rate = 30.0; |
| 95 if (params.requested_format.frame_size.width() > 1280) | 206 if (params.requested_format.frame_size.width() > 1280) |
| 96 capture_format_.frame_size.SetSize(1920, 1080); | 207 capture_format_.frame_size.SetSize(1920, 1080); |
| 97 else if (params.requested_format.frame_size.width() > 640) | 208 else if (params.requested_format.frame_size.width() > 640) |
| 98 capture_format_.frame_size.SetSize(1280, 720); | 209 capture_format_.frame_size.SetSize(1280, 720); |
| 99 else if (params.requested_format.frame_size.width() > 320) | 210 else if (params.requested_format.frame_size.width() > 320) |
| 100 capture_format_.frame_size.SetSize(640, 480); | 211 capture_format_.frame_size.SetSize(640, 480); |
| 101 else | 212 else |
| 102 capture_format_.frame_size.SetSize(320, 240); | 213 capture_format_.frame_size.SetSize(320, 240); |
| 103 | 214 |
| 215 #if defined(OS_CHROMEOS) && defined(USE_OZONE) | |
| 216 vgem_wrapper_.reset(new VgemWrapper()); | |
| 217 vgem_wrapper_->Initialize(); | |
| 218 #endif | |
| 219 | |
| 104 if (device_type_ == USING_OWN_BUFFERS || | 220 if (device_type_ == USING_OWN_BUFFERS || |
| 105 device_type_ == USING_OWN_BUFFERS_TRIPLANAR) { | 221 device_type_ == USING_OWN_BUFFERS_TRIPLANAR) { |
| 106 fake_frame_.reset(new uint8[VideoFrame::AllocationSize( | 222 fake_frame_.reset(new uint8[VideoFrame::AllocationSize( |
| 107 VideoFrame::I420, capture_format_.frame_size)]); | 223 VideoFrame::I420, capture_format_.frame_size)]); |
| 108 BeepAndScheduleNextCapture( | 224 BeepAndScheduleNextCapture( |
| 109 base::Bind(&FakeVideoCaptureDevice::CaptureUsingOwnBuffers, | 225 base::Bind(&FakeVideoCaptureDevice::CaptureUsingOwnBuffers, |
| 110 weak_factory_.GetWeakPtr())); | 226 weak_factory_.GetWeakPtr())); |
| 111 } else if (device_type_ == USING_CLIENT_BUFFERS_I420 || | 227 } else if (device_type_ == USING_CLIENT_BUFFERS_I420 || |
| 112 device_type_ == USING_CLIENT_BUFFERS_GPU) { | 228 device_type_ == USING_CLIENT_BUFFERS_GPU) { |
| 113 DVLOG(1) << "starting with " << (device_type_ == USING_CLIENT_BUFFERS_I420 | 229 DVLOG(1) << "starting with " << (device_type_ == USING_CLIENT_BUFFERS_I420 |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 165 | 281 |
| 166 void FakeVideoCaptureDevice::CaptureUsingClientBuffers( | 282 void FakeVideoCaptureDevice::CaptureUsingClientBuffers( |
| 167 VideoPixelFormat pixel_format) { | 283 VideoPixelFormat pixel_format) { |
| 168 DCHECK(thread_checker_.CalledOnValidThread()); | 284 DCHECK(thread_checker_.CalledOnValidThread()); |
| 169 | 285 |
| 170 scoped_ptr<VideoCaptureDevice::Client::Buffer> capture_buffer( | 286 scoped_ptr<VideoCaptureDevice::Client::Buffer> capture_buffer( |
| 171 client_->ReserveOutputBuffer(pixel_format, capture_format_.frame_size)); | 287 client_->ReserveOutputBuffer(pixel_format, capture_format_.frame_size)); |
| 172 DLOG_IF(ERROR, !capture_buffer) << "Couldn't allocate Capture Buffer"; | 288 DLOG_IF(ERROR, !capture_buffer) << "Couldn't allocate Capture Buffer"; |
| 173 | 289 |
| 174 if (capture_buffer.get()) { | 290 if (capture_buffer.get()) { |
| 175 uint8_t* const data_ptr = static_cast<uint8_t*>(capture_buffer->data()); | 291 uint8_t* data_ptr = static_cast<uint8_t*>(capture_buffer->data()); |
| 176 DCHECK(data_ptr) << "Buffer has NO backing memory"; | 292 |
| 177 DCHECK_EQ(capture_buffer->GetType(), gfx::SHARED_MEMORY_BUFFER); | 293 #if defined(OS_CHROMEOS) && defined(USE_OZONE) |
| 294 if (!data_ptr && vgem_wrapper_->IsValid()) { | |
| 295 data_ptr = vgem_wrapper_->MmapPrimeFd(capture_buffer->AsPlatformFile(), | |
| 296 capture_buffer->size()); | |
| 297 } | |
| 298 #endif | |
| 299 DCHECK(data_ptr); | |
| 178 memset(data_ptr, 0, capture_buffer->size()); | 300 memset(data_ptr, 0, capture_buffer->size()); |
| 179 | 301 |
| 180 DrawPacman( | 302 DrawPacman( |
| 181 (pixel_format == media::PIXEL_FORMAT_GPUMEMORYBUFFER), /* use_argb */ | 303 (pixel_format == media::PIXEL_FORMAT_GPUMEMORYBUFFER), /* use_argb */ |
| 182 data_ptr, | 304 data_ptr, |
| 183 frame_count_, | 305 frame_count_, |
| 184 kFakeCapturePeriodMs, | 306 kFakeCapturePeriodMs, |
| 185 capture_format_.frame_size); | 307 capture_format_.frame_size); |
| 186 | 308 |
| 187 // Give the captured frame to the client. | 309 // Give the captured frame to the client. |
| 188 const VideoCaptureFormat format(capture_format_.frame_size, | 310 const VideoCaptureFormat format(capture_format_.frame_size, |
| 189 capture_format_.frame_rate, | 311 capture_format_.frame_rate, |
| 190 pixel_format); | 312 pixel_format); |
| 191 client_->OnIncomingCapturedBuffer(capture_buffer.Pass(), format, | 313 client_->OnIncomingCapturedBuffer(capture_buffer.Pass(), format, |
| 192 base::TimeTicks::Now()); | 314 base::TimeTicks::Now()); |
| 315 #if defined(OS_CHROMEOS) && defined(USE_OZONE) | |
| 316 if (vgem_wrapper_->IsValid()) | |
| 317 vgem_wrapper_->MunmapPointer(data_ptr, capture_buffer->size()); | |
| 318 #endif | |
| 193 } | 319 } |
| 194 | 320 |
| 195 BeepAndScheduleNextCapture( | 321 BeepAndScheduleNextCapture( |
| 196 base::Bind(&FakeVideoCaptureDevice::CaptureUsingClientBuffers, | 322 base::Bind(&FakeVideoCaptureDevice::CaptureUsingClientBuffers, |
| 197 weak_factory_.GetWeakPtr(), pixel_format)); | 323 weak_factory_.GetWeakPtr(), pixel_format)); |
| 198 } | 324 } |
| 199 | 325 |
| 200 void FakeVideoCaptureDevice::BeepAndScheduleNextCapture( | 326 void FakeVideoCaptureDevice::BeepAndScheduleNextCapture( |
| 201 const base::Closure& next_capture) { | 327 const base::Closure& next_capture) { |
| 202 // Generate a synchronized beep sound every so many frames. | 328 // Generate a synchronized beep sound every so many frames. |
| 203 if (frame_count_++ % kFakeCaptureBeepCycle == 0) | 329 if (frame_count_++ % kFakeCaptureBeepCycle == 0) |
| 204 FakeAudioInputStream::BeepOnce(); | 330 FakeAudioInputStream::BeepOnce(); |
| 205 | 331 |
| 206 // Reschedule next CaptureTask. | 332 // Reschedule next CaptureTask. |
| 207 base::MessageLoop::current()->PostDelayedTask(FROM_HERE, next_capture, | 333 base::MessageLoop::current()->PostDelayedTask(FROM_HERE, next_capture, |
| 208 base::TimeDelta::FromMilliseconds(kFakeCapturePeriodMs)); | 334 base::TimeDelta::FromMilliseconds(kFakeCapturePeriodMs)); |
| 209 } | 335 } |
| 210 | 336 |
| 211 } // namespace media | 337 } // namespace media |
| OLD | NEW |