| 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/capture/video/fake_video_capture_device.h" | 5 #include "device/capture/video/fake_video_capture_device.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 #include <algorithm> | 8 #include <algorithm> |
| 9 #include <utility> | 9 #include <utility> |
| 10 | 10 |
| 11 #include "base/bind.h" | 11 #include "base/bind.h" |
| 12 #include "base/location.h" | 12 #include "base/location.h" |
| 13 #include "base/single_thread_task_runner.h" | 13 #include "base/single_thread_task_runner.h" |
| 14 #include "base/strings/stringprintf.h" | 14 #include "base/strings/stringprintf.h" |
| 15 #include "base/threading/thread_task_runner_handle.h" | 15 #include "base/threading/thread_task_runner_handle.h" |
| 16 #include "media/audio/fake_audio_input_stream.h" | 16 #include "media/audio/fake_audio_input_stream.h" |
| 17 #include "media/base/video_frame.h" | 17 #include "media/base/video_frame.h" |
| 18 #include "mojo/public/cpp/bindings/string.h" | 18 #include "mojo/public/cpp/bindings/string.h" |
| 19 #include "third_party/skia/include/core/SkBitmap.h" | 19 #include "third_party/skia/include/core/SkBitmap.h" |
| 20 #include "third_party/skia/include/core/SkCanvas.h" | 20 #include "third_party/skia/include/core/SkCanvas.h" |
| 21 #include "third_party/skia/include/core/SkMatrix.h" | 21 #include "third_party/skia/include/core/SkMatrix.h" |
| 22 #include "third_party/skia/include/core/SkPaint.h" | 22 #include "third_party/skia/include/core/SkPaint.h" |
| 23 #include "ui/gfx/codec/png_codec.h" | 23 #include "ui/gfx/codec/png_codec.h" |
| 24 | 24 |
| 25 namespace media { | 25 namespace device { |
| 26 | 26 |
| 27 // Sweep at 600 deg/sec. | 27 // Sweep at 600 deg/sec. |
| 28 static const float kPacmanAngularVelocity = 600; | 28 static const float kPacmanAngularVelocity = 600; |
| 29 // Beep every 500 ms. | 29 // Beep every 500 ms. |
| 30 static const int kBeepInterval = 500; | 30 static const int kBeepInterval = 500; |
| 31 | 31 |
| 32 static const uint32_t kMinZoom = 100; | 32 static const uint32_t kMinZoom = 100; |
| 33 static const uint32_t kMaxZoom = 400; | 33 static const uint32_t kMaxZoom = 400; |
| 34 | 34 |
| 35 void DrawPacman(bool use_argb, | 35 void DrawPacman(bool use_argb, |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 89 } | 89 } |
| 90 | 90 |
| 91 // Creates a PNG-encoded frame and sends it back to |callback|. The other | 91 // Creates a PNG-encoded frame and sends it back to |callback|. The other |
| 92 // parameters are used to replicate the PacMan rendering. | 92 // parameters are used to replicate the PacMan rendering. |
| 93 void DoTakeFakePhoto(VideoCaptureDevice::TakePhotoCallback callback, | 93 void DoTakeFakePhoto(VideoCaptureDevice::TakePhotoCallback callback, |
| 94 const VideoCaptureFormat& capture_format, | 94 const VideoCaptureFormat& capture_format, |
| 95 base::TimeDelta elapsed_time, | 95 base::TimeDelta elapsed_time, |
| 96 float fake_capture_rate, | 96 float fake_capture_rate, |
| 97 uint32_t zoom) { | 97 uint32_t zoom) { |
| 98 std::unique_ptr<uint8_t[]> buffer(new uint8_t[VideoFrame::AllocationSize( | 98 std::unique_ptr<uint8_t[]> buffer(new uint8_t[VideoFrame::AllocationSize( |
| 99 PIXEL_FORMAT_ARGB, capture_format.frame_size)]); | 99 media::PIXEL_FORMAT_ARGB, capture_format.frame_size)]); |
| 100 | 100 |
| 101 DrawPacman(true /* use_argb */, buffer.get(), elapsed_time, fake_capture_rate, | 101 DrawPacman(true /* use_argb */, buffer.get(), elapsed_time, fake_capture_rate, |
| 102 capture_format.frame_size, zoom); | 102 capture_format.frame_size, zoom); |
| 103 | 103 |
| 104 mojom::BlobPtr blob = mojom::Blob::New(); | 104 media::mojom::BlobPtr blob = media::mojom::Blob::New(); |
| 105 const bool result = gfx::PNGCodec::Encode( | 105 const bool result = gfx::PNGCodec::Encode( |
| 106 buffer.get(), gfx::PNGCodec::FORMAT_RGBA, capture_format.frame_size, | 106 buffer.get(), gfx::PNGCodec::FORMAT_RGBA, capture_format.frame_size, |
| 107 capture_format.frame_size.width() * 4, true /* discard_transparency */, | 107 capture_format.frame_size.width() * 4, true /* discard_transparency */, |
| 108 std::vector<gfx::PNGCodec::Comment>(), &blob->data); | 108 std::vector<gfx::PNGCodec::Comment>(), &blob->data); |
| 109 DCHECK(result); | 109 DCHECK(result); |
| 110 | 110 |
| 111 blob->mime_type = "image/png"; | 111 blob->mime_type = "image/png"; |
| 112 callback.Run(std::move(blob)); | 112 callback.Run(std::move(blob)); |
| 113 } | 113 } |
| 114 | 114 |
| (...skipping 22 matching lines...) Expand all Loading... |
| 137 if (params.requested_format.frame_size.width() > 1280) | 137 if (params.requested_format.frame_size.width() > 1280) |
| 138 capture_format_.frame_size.SetSize(1920, 1080); | 138 capture_format_.frame_size.SetSize(1920, 1080); |
| 139 else if (params.requested_format.frame_size.width() > 640) | 139 else if (params.requested_format.frame_size.width() > 640) |
| 140 capture_format_.frame_size.SetSize(1280, 720); | 140 capture_format_.frame_size.SetSize(1280, 720); |
| 141 else if (params.requested_format.frame_size.width() > 320) | 141 else if (params.requested_format.frame_size.width() > 320) |
| 142 capture_format_.frame_size.SetSize(640, 480); | 142 capture_format_.frame_size.SetSize(640, 480); |
| 143 else | 143 else |
| 144 capture_format_.frame_size.SetSize(320, 240); | 144 capture_format_.frame_size.SetSize(320, 240); |
| 145 | 145 |
| 146 if (buffer_ownership_ == BufferOwnership::CLIENT_BUFFERS) { | 146 if (buffer_ownership_ == BufferOwnership::CLIENT_BUFFERS) { |
| 147 capture_format_.pixel_storage = PIXEL_STORAGE_CPU; | 147 capture_format_.pixel_storage = media::PIXEL_STORAGE_CPU; |
| 148 capture_format_.pixel_format = PIXEL_FORMAT_ARGB; | 148 capture_format_.pixel_format = media::PIXEL_FORMAT_ARGB; |
| 149 DVLOG(1) << "starting with client argb buffers"; | 149 DVLOG(1) << "starting with client argb buffers"; |
| 150 } else if (buffer_ownership_ == BufferOwnership::OWN_BUFFERS) { | 150 } else if (buffer_ownership_ == BufferOwnership::OWN_BUFFERS) { |
| 151 capture_format_.pixel_storage = PIXEL_STORAGE_CPU; | 151 capture_format_.pixel_storage = media::PIXEL_STORAGE_CPU; |
| 152 capture_format_.pixel_format = PIXEL_FORMAT_I420; | 152 capture_format_.pixel_format = media::PIXEL_FORMAT_I420; |
| 153 DVLOG(1) << "starting with own I420 buffers"; | 153 DVLOG(1) << "starting with own I420 buffers"; |
| 154 } | 154 } |
| 155 | 155 |
| 156 if (capture_format_.pixel_format == PIXEL_FORMAT_I420) { | 156 if (capture_format_.pixel_format == media::PIXEL_FORMAT_I420) { |
| 157 fake_frame_.reset(new uint8_t[VideoFrame::AllocationSize( | 157 fake_frame_.reset(new uint8_t[VideoFrame::AllocationSize( |
| 158 PIXEL_FORMAT_I420, capture_format_.frame_size)]); | 158 media::PIXEL_FORMAT_I420, capture_format_.frame_size)]); |
| 159 } | 159 } |
| 160 | 160 |
| 161 beep_time_ = base::TimeDelta(); | 161 beep_time_ = base::TimeDelta(); |
| 162 elapsed_time_ = base::TimeDelta(); | 162 elapsed_time_ = base::TimeDelta(); |
| 163 | 163 |
| 164 if (buffer_ownership_ == BufferOwnership::CLIENT_BUFFERS) | 164 if (buffer_ownership_ == BufferOwnership::CLIENT_BUFFERS) |
| 165 BeepAndScheduleNextCapture( | 165 BeepAndScheduleNextCapture( |
| 166 base::TimeTicks::Now(), | 166 base::TimeTicks::Now(), |
| 167 base::Bind(&FakeVideoCaptureDevice::CaptureUsingClientBuffers, | 167 base::Bind(&FakeVideoCaptureDevice::CaptureUsingClientBuffers, |
| 168 weak_factory_.GetWeakPtr())); | 168 weak_factory_.GetWeakPtr())); |
| 169 else if (buffer_ownership_ == BufferOwnership::OWN_BUFFERS) | 169 else if (buffer_ownership_ == BufferOwnership::OWN_BUFFERS) |
| 170 BeepAndScheduleNextCapture( | 170 BeepAndScheduleNextCapture( |
| 171 base::TimeTicks::Now(), | 171 base::TimeTicks::Now(), |
| 172 base::Bind(&FakeVideoCaptureDevice::CaptureUsingOwnBuffers, | 172 base::Bind(&FakeVideoCaptureDevice::CaptureUsingOwnBuffers, |
| 173 weak_factory_.GetWeakPtr())); | 173 weak_factory_.GetWeakPtr())); |
| 174 } | 174 } |
| 175 | 175 |
| 176 void FakeVideoCaptureDevice::StopAndDeAllocate() { | 176 void FakeVideoCaptureDevice::StopAndDeAllocate() { |
| 177 DCHECK(thread_checker_.CalledOnValidThread()); | 177 DCHECK(thread_checker_.CalledOnValidThread()); |
| 178 client_.reset(); | 178 client_.reset(); |
| 179 } | 179 } |
| 180 | 180 |
| 181 void FakeVideoCaptureDevice::GetPhotoCapabilities( | 181 void FakeVideoCaptureDevice::GetPhotoCapabilities( |
| 182 GetPhotoCapabilitiesCallback callback) { | 182 GetPhotoCapabilitiesCallback callback) { |
| 183 mojom::PhotoCapabilitiesPtr photo_capabilities = | 183 media::mojom::PhotoCapabilitiesPtr photo_capabilities = |
| 184 mojom::PhotoCapabilities::New(); | 184 media::mojom::PhotoCapabilities::New(); |
| 185 photo_capabilities->iso = mojom::Range::New(); | 185 photo_capabilities->iso = media::mojom::Range::New(); |
| 186 photo_capabilities->iso->current = 100; | 186 photo_capabilities->iso->current = 100; |
| 187 photo_capabilities->iso->max = 100; | 187 photo_capabilities->iso->max = 100; |
| 188 photo_capabilities->iso->min = 100; | 188 photo_capabilities->iso->min = 100; |
| 189 photo_capabilities->height = mojom::Range::New(); | 189 photo_capabilities->height = media::mojom::Range::New(); |
| 190 photo_capabilities->height->current = capture_format_.frame_size.height(); | 190 photo_capabilities->height->current = capture_format_.frame_size.height(); |
| 191 photo_capabilities->height->max = 1080; | 191 photo_capabilities->height->max = 1080; |
| 192 photo_capabilities->height->min = 240; | 192 photo_capabilities->height->min = 240; |
| 193 photo_capabilities->width = mojom::Range::New(); | 193 photo_capabilities->width = media::mojom::Range::New(); |
| 194 photo_capabilities->width->current = capture_format_.frame_size.width(); | 194 photo_capabilities->width->current = capture_format_.frame_size.width(); |
| 195 photo_capabilities->width->max = 1920; | 195 photo_capabilities->width->max = 1920; |
| 196 photo_capabilities->width->min = 320; | 196 photo_capabilities->width->min = 320; |
| 197 photo_capabilities->focus_mode = mojom::FocusMode::UNAVAILABLE; | 197 photo_capabilities->focus_mode = media::mojom::FocusMode::UNAVAILABLE; |
| 198 photo_capabilities->zoom = mojom::Range::New(); | 198 photo_capabilities->zoom = media::mojom::Range::New(); |
| 199 photo_capabilities->zoom->current = current_zoom_; | 199 photo_capabilities->zoom->current = current_zoom_; |
| 200 photo_capabilities->zoom->max = kMaxZoom; | 200 photo_capabilities->zoom->max = kMaxZoom; |
| 201 photo_capabilities->zoom->min = kMinZoom; | 201 photo_capabilities->zoom->min = kMinZoom; |
| 202 photo_capabilities->focus_mode = mojom::FocusMode::UNAVAILABLE; | 202 photo_capabilities->focus_mode = media::mojom::FocusMode::UNAVAILABLE; |
| 203 callback.Run(std::move(photo_capabilities)); | 203 callback.Run(std::move(photo_capabilities)); |
| 204 } | 204 } |
| 205 | 205 |
| 206 void FakeVideoCaptureDevice::SetPhotoOptions(mojom::PhotoSettingsPtr settings, | 206 void FakeVideoCaptureDevice::SetPhotoOptions( |
| 207 SetPhotoOptionsCallback callback) { | 207 media::mojom::PhotoSettingsPtr settings, |
| 208 SetPhotoOptionsCallback callback) { |
| 208 if (settings->has_zoom) | 209 if (settings->has_zoom) |
| 209 current_zoom_ = std::max(kMinZoom, std::min(settings->zoom, kMaxZoom)); | 210 current_zoom_ = std::max(kMinZoom, std::min(settings->zoom, kMaxZoom)); |
| 210 callback.Run(true); | 211 callback.Run(true); |
| 211 } | 212 } |
| 212 | 213 |
| 213 void FakeVideoCaptureDevice::TakePhoto(TakePhotoCallback callback) { | 214 void FakeVideoCaptureDevice::TakePhoto(TakePhotoCallback callback) { |
| 214 base::ThreadTaskRunnerHandle::Get()->PostTask( | 215 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 215 FROM_HERE, | 216 FROM_HERE, |
| 216 base::Bind(&DoTakeFakePhoto, base::Passed(&callback), capture_format_, | 217 base::Bind(&DoTakeFakePhoto, base::Passed(&callback), capture_format_, |
| 217 elapsed_time_, fake_capture_rate_, current_zoom_)); | 218 elapsed_time_, fake_capture_rate_, current_zoom_)); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 243 base::TimeTicks expected_execution_time) { | 244 base::TimeTicks expected_execution_time) { |
| 244 DCHECK(thread_checker_.CalledOnValidThread()); | 245 DCHECK(thread_checker_.CalledOnValidThread()); |
| 245 | 246 |
| 246 std::unique_ptr<VideoCaptureDevice::Client::Buffer> capture_buffer( | 247 std::unique_ptr<VideoCaptureDevice::Client::Buffer> capture_buffer( |
| 247 client_->ReserveOutputBuffer(capture_format_.frame_size, | 248 client_->ReserveOutputBuffer(capture_format_.frame_size, |
| 248 capture_format_.pixel_format, | 249 capture_format_.pixel_format, |
| 249 capture_format_.pixel_storage)); | 250 capture_format_.pixel_storage)); |
| 250 DLOG_IF(ERROR, !capture_buffer) << "Couldn't allocate Capture Buffer"; | 251 DLOG_IF(ERROR, !capture_buffer) << "Couldn't allocate Capture Buffer"; |
| 251 DCHECK(capture_buffer->data()) << "Buffer has NO backing memory"; | 252 DCHECK(capture_buffer->data()) << "Buffer has NO backing memory"; |
| 252 | 253 |
| 253 if (capture_format_.pixel_storage == PIXEL_STORAGE_GPUMEMORYBUFFER && | 254 if (capture_format_.pixel_storage == media::PIXEL_STORAGE_GPUMEMORYBUFFER && |
| 254 capture_format_.pixel_format == media::PIXEL_FORMAT_I420) { | 255 capture_format_.pixel_format == media::PIXEL_FORMAT_I420) { |
| 255 // Since SkBitmap expects a packed&continuous memory region for I420, we | 256 // Since SkBitmap expects a packed&continuous memory region for I420, we |
| 256 // need to use |fake_frame_| to draw onto. | 257 // need to use |fake_frame_| to draw onto. |
| 257 memset(fake_frame_.get(), 0, capture_format_.ImageAllocationSize()); | 258 memset(fake_frame_.get(), 0, capture_format_.ImageAllocationSize()); |
| 258 DrawPacman(false /* use_argb */, fake_frame_.get(), elapsed_time_, | 259 DrawPacman(false /* use_argb */, fake_frame_.get(), elapsed_time_, |
| 259 fake_capture_rate_, capture_format_.frame_size, current_zoom_); | 260 fake_capture_rate_, capture_format_.frame_size, current_zoom_); |
| 260 | 261 |
| 261 // Copy data from |fake_frame_| into the reserved planes of GpuMemoryBuffer. | 262 // Copy data from |fake_frame_| into the reserved planes of GpuMemoryBuffer. |
| 262 size_t offset = 0; | 263 size_t offset = 0; |
| 263 for (size_t i = 0; i < VideoFrame::NumPlanes(PIXEL_FORMAT_I420); ++i) { | 264 for (size_t i = 0; i < VideoFrame::NumPlanes(media::PIXEL_FORMAT_I420); |
| 265 ++i) { |
| 264 const size_t plane_size = | 266 const size_t plane_size = |
| 265 VideoFrame::PlaneSize(PIXEL_FORMAT_I420, i, | 267 VideoFrame::PlaneSize(media::PIXEL_FORMAT_I420, i, |
| 266 capture_format_.frame_size) | 268 capture_format_.frame_size) |
| 267 .GetArea(); | 269 .GetArea(); |
| 268 memcpy(capture_buffer->data(i), fake_frame_.get() + offset, plane_size); | 270 memcpy(capture_buffer->data(i), fake_frame_.get() + offset, plane_size); |
| 269 offset += plane_size; | 271 offset += plane_size; |
| 270 } | 272 } |
| 271 } else { | 273 } else { |
| 272 DCHECK_EQ(capture_format_.pixel_storage, PIXEL_STORAGE_CPU); | 274 DCHECK_EQ(capture_format_.pixel_storage, media::PIXEL_STORAGE_CPU); |
| 273 DCHECK_EQ(capture_format_.pixel_format, PIXEL_FORMAT_ARGB); | 275 DCHECK_EQ(capture_format_.pixel_format, media::PIXEL_FORMAT_ARGB); |
| 274 uint8_t* data_ptr = static_cast<uint8_t*>(capture_buffer->data()); | 276 uint8_t* data_ptr = static_cast<uint8_t*>(capture_buffer->data()); |
| 275 memset(data_ptr, 0, capture_buffer->mapped_size()); | 277 memset(data_ptr, 0, capture_buffer->mapped_size()); |
| 276 DrawPacman(true /* use_argb */, data_ptr, elapsed_time_, fake_capture_rate_, | 278 DrawPacman(true /* use_argb */, data_ptr, elapsed_time_, fake_capture_rate_, |
| 277 capture_format_.frame_size, current_zoom_); | 279 capture_format_.frame_size, current_zoom_); |
| 278 } | 280 } |
| 279 | 281 |
| 280 // Give the captured frame to the client. | 282 // Give the captured frame to the client. |
| 281 base::TimeTicks now = base::TimeTicks::Now(); | 283 base::TimeTicks now = base::TimeTicks::Now(); |
| 282 if (first_ref_time_.is_null()) | 284 if (first_ref_time_.is_null()) |
| 283 first_ref_time_ = now; | 285 first_ref_time_ = now; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 295 const base::Callback<void(base::TimeTicks)>& next_capture) { | 297 const base::Callback<void(base::TimeTicks)>& next_capture) { |
| 296 const base::TimeDelta beep_interval = | 298 const base::TimeDelta beep_interval = |
| 297 base::TimeDelta::FromMilliseconds(kBeepInterval); | 299 base::TimeDelta::FromMilliseconds(kBeepInterval); |
| 298 const base::TimeDelta frame_interval = | 300 const base::TimeDelta frame_interval = |
| 299 base::TimeDelta::FromMicroseconds(1e6 / fake_capture_rate_); | 301 base::TimeDelta::FromMicroseconds(1e6 / fake_capture_rate_); |
| 300 beep_time_ += frame_interval; | 302 beep_time_ += frame_interval; |
| 301 elapsed_time_ += frame_interval; | 303 elapsed_time_ += frame_interval; |
| 302 | 304 |
| 303 // Generate a synchronized beep twice per second. | 305 // Generate a synchronized beep twice per second. |
| 304 if (beep_time_ >= beep_interval) { | 306 if (beep_time_ >= beep_interval) { |
| 305 FakeAudioInputStream::BeepOnce(); | 307 media::FakeAudioInputStream::BeepOnce(); |
| 306 beep_time_ -= beep_interval; | 308 beep_time_ -= beep_interval; |
| 307 } | 309 } |
| 308 | 310 |
| 309 // Reschedule next CaptureTask. | 311 // Reschedule next CaptureTask. |
| 310 const base::TimeTicks current_time = base::TimeTicks::Now(); | 312 const base::TimeTicks current_time = base::TimeTicks::Now(); |
| 311 // Don't accumulate any debt if we are lagging behind - just post the next | 313 // Don't accumulate any debt if we are lagging behind - just post the next |
| 312 // frame immediately and continue as normal. | 314 // frame immediately and continue as normal. |
| 313 const base::TimeTicks next_execution_time = | 315 const base::TimeTicks next_execution_time = |
| 314 std::max(current_time, expected_execution_time + frame_interval); | 316 std::max(current_time, expected_execution_time + frame_interval); |
| 315 const base::TimeDelta delay = next_execution_time - current_time; | 317 const base::TimeDelta delay = next_execution_time - current_time; |
| 316 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( | 318 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( |
| 317 FROM_HERE, base::Bind(next_capture, next_execution_time), delay); | 319 FROM_HERE, base::Bind(next_capture, next_execution_time), delay); |
| 318 } | 320 } |
| 319 | 321 |
| 320 } // namespace media | 322 } // namespace device |
| OLD | NEW |