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 |