Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(47)

Side by Side Diff: media/capture/video/fake_video_capture_device.cc

Issue 2700173002: Add MJPEG support to FakeVideoCaptureDevice (Closed)
Patch Set: Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 "media/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/macros.h" 13 #include "base/macros.h"
14 #include "base/memory/weak_ptr.h" 14 #include "base/memory/weak_ptr.h"
15 #include "base/single_thread_task_runner.h" 15 #include "base/single_thread_task_runner.h"
16 #include "base/strings/stringprintf.h" 16 #include "base/strings/stringprintf.h"
17 #include "base/threading/thread_checker.h" 17 #include "base/threading/thread_checker.h"
18 #include "base/threading/thread_task_runner_handle.h" 18 #include "base/threading/thread_task_runner_handle.h"
19 #include "base/time/time.h" 19 #include "base/time/time.h"
20 #include "media/audio/fake_audio_input_stream.h" 20 #include "media/audio/fake_audio_input_stream.h"
21 #include "media/base/video_frame.h" 21 #include "media/base/video_frame.h"
22 #include "third_party/skia/include/core/SkBitmap.h" 22 #include "third_party/skia/include/core/SkBitmap.h"
23 #include "third_party/skia/include/core/SkCanvas.h" 23 #include "third_party/skia/include/core/SkCanvas.h"
24 #include "third_party/skia/include/core/SkMatrix.h" 24 #include "third_party/skia/include/core/SkMatrix.h"
25 #include "third_party/skia/include/core/SkPaint.h" 25 #include "third_party/skia/include/core/SkPaint.h"
26 #include "ui/gfx/codec/jpeg_codec.h"
26 #include "ui/gfx/codec/png_codec.h" 27 #include "ui/gfx/codec/png_codec.h"
27 28
28 namespace media { 29 namespace media {
29 30
30 namespace { 31 namespace {
31 // Sweep at 600 deg/sec. 32 // Sweep at 600 deg/sec.
32 static const float kPacmanAngularVelocity = 600; 33 static const float kPacmanAngularVelocity = 600;
33 // Beep every 500 ms. 34 // Beep every 500 ms.
34 static const int kBeepInterval = 500; 35 static const int kBeepInterval = 500;
35 // Gradient travels from bottom to top in 5 seconds. 36 // Gradient travels from bottom to top in 5 seconds.
36 static const float kGradientFrequency = 1.f / 5; 37 static const float kGradientFrequency = 1.f / 5;
37 38
38 static const double kMinZoom = 100.0; 39 static const double kMinZoom = 100.0;
39 static const double kMaxZoom = 400.0; 40 static const double kMaxZoom = 400.0;
40 static const double kZoomStep = 1.0; 41 static const double kZoomStep = 1.0;
41 static const double kInitialZoom = 100.0; 42 static const double kInitialZoom = 100.0;
42 43
43 static const gfx::Size kSupportedSizesOrderedByIncreasingWidth[] = { 44 static const gfx::Size kSupportedSizesOrderedByIncreasingWidth[] = {
44 gfx::Size(96, 96), gfx::Size(320, 240), gfx::Size(640, 480), 45 gfx::Size(96, 96), gfx::Size(320, 240), gfx::Size(640, 480),
45 gfx::Size(1280, 720), gfx::Size(1920, 1080)}; 46 gfx::Size(1280, 720), gfx::Size(1920, 1080)};
46 static const int kSupportedSizesCount = 47 static const int kSupportedSizesCount =
47 arraysize(kSupportedSizesOrderedByIncreasingWidth); 48 arraysize(kSupportedSizesOrderedByIncreasingWidth);
48 49
49 static const VideoPixelFormat kSupportedPixelFormats[] = { 50 static const VideoPixelFormat kSupportedPixelFormats[] = {
50 PIXEL_FORMAT_I420, PIXEL_FORMAT_Y16, PIXEL_FORMAT_ARGB}; 51 PIXEL_FORMAT_I420, PIXEL_FORMAT_Y16, PIXEL_FORMAT_ARGB, PIXEL_FORMAT_MJPEG};
51 52
52 static gfx::Size SnapToSupportedSize(const gfx::Size& requested_size) { 53 static gfx::Size SnapToSupportedSize(const gfx::Size& requested_size) {
53 for (const gfx::Size& supported_size : 54 for (const gfx::Size& supported_size :
54 kSupportedSizesOrderedByIncreasingWidth) { 55 kSupportedSizesOrderedByIncreasingWidth) {
55 if (requested_size.width() <= supported_size.width()) 56 if (requested_size.width() <= supported_size.width())
56 return supported_size; 57 return supported_size;
57 } 58 }
58 return kSupportedSizesOrderedByIncreasingWidth[kSupportedSizesCount - 1]; 59 return kSupportedSizesOrderedByIncreasingWidth[kSupportedSizesCount - 1];
59 } 60 }
60 61
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
145 ~ClientBufferFrameDeliverer() override; 146 ~ClientBufferFrameDeliverer() override;
146 147
147 // Implementation of FrameDeliverer 148 // Implementation of FrameDeliverer
148 void Initialize(VideoPixelFormat pixel_format, 149 void Initialize(VideoPixelFormat pixel_format,
149 std::unique_ptr<VideoCaptureDevice::Client> client, 150 std::unique_ptr<VideoCaptureDevice::Client> client,
150 const FakeDeviceState* device_state) override; 151 const FakeDeviceState* device_state) override;
151 void Uninitialize() override; 152 void Uninitialize() override;
152 void PaintAndDeliverNextFrame(base::TimeDelta timestamp_to_paint) override; 153 void PaintAndDeliverNextFrame(base::TimeDelta timestamp_to_paint) override;
153 }; 154 };
154 155
156 class CAPTURE_EXPORT JpegEncodingFrameDeliverer : public FrameDeliverer {
157 public:
158 JpegEncodingFrameDeliverer(std::unique_ptr<PacmanFramePainter> frame_painter);
159 ~JpegEncodingFrameDeliverer() override;
160
161 // Implementation of FrameDeliveryStrategy
162 void Initialize(VideoPixelFormat pixel_format,
163 std::unique_ptr<VideoCaptureDevice::Client> client,
164 const FakeDeviceState* device_state) override;
165 void Uninitialize() override;
166 void PaintAndDeliverNextFrame(base::TimeDelta timestamp_to_paint) override;
167
168 private:
169 const FakeDeviceState* device_state_ = nullptr;
170 std::unique_ptr<uint8_t[]> argb_buffer_;
171 int argb_buffer_size_in_bytes_ = -1;
172 std::vector<unsigned char> jpeg_buffer_;
173 std::unique_ptr<VideoCaptureDevice::Client> client_;
174 // The system time when we receive the first frame.
175 base::TimeTicks first_ref_time_;
chfremer 2017/02/17 18:07:38 I forgot to remove members |device_state|, |client
chfremer 2017/02/22 17:28:41 Done.
176 };
177
155 // Implements the photo functionality of a VideoCaptureDevice 178 // Implements the photo functionality of a VideoCaptureDevice
156 class FakePhotoDevice { 179 class FakePhotoDevice {
157 public: 180 public:
158 FakePhotoDevice(std::unique_ptr<PacmanFramePainter> argb_painter, 181 FakePhotoDevice(std::unique_ptr<PacmanFramePainter> argb_painter,
159 const FakeDeviceState* fake_device_state); 182 const FakeDeviceState* fake_device_state);
160 ~FakePhotoDevice(); 183 ~FakePhotoDevice();
161 184
162 void GetPhotoCapabilities( 185 void GetPhotoCapabilities(
163 VideoCaptureDevice::GetPhotoCapabilitiesCallback callback); 186 VideoCaptureDevice::GetPhotoCapabilitiesCallback callback);
164 void TakePhoto(VideoCaptureDevice::TakePhotoCallback callback, 187 void TakePhoto(VideoCaptureDevice::TakePhotoCallback callback,
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
235 } 258 }
236 } 259 }
237 if (!pixel_format_supported) { 260 if (!pixel_format_supported) {
238 DLOG(ERROR) << "Requested an unsupported pixel format " 261 DLOG(ERROR) << "Requested an unsupported pixel format "
239 << VideoPixelFormatToString(pixel_format); 262 << VideoPixelFormatToString(pixel_format);
240 return nullptr; 263 return nullptr;
241 } 264 }
242 265
243 auto device_state = 266 auto device_state =
244 base::MakeUnique<FakeDeviceState>(kInitialZoom, frame_rate, pixel_format); 267 base::MakeUnique<FakeDeviceState>(kInitialZoom, frame_rate, pixel_format);
245 auto video_frame_painter = 268 std::unique_ptr<PacmanFramePainter> video_frame_painter;
246 base::MakeUnique<PacmanFramePainter>(pixel_format, device_state.get()); 269 if (pixel_format == PIXEL_FORMAT_MJPEG) {
270 video_frame_painter = base::MakeUnique<PacmanFramePainter>(
271 PIXEL_FORMAT_ARGB, device_state.get());
272 } else {
273 video_frame_painter =
274 base::MakeUnique<PacmanFramePainter>(pixel_format, device_state.get());
275 }
mcasas 2017/02/17 18:35:47 I find this part hard to read, mostly because of t
chfremer 2017/02/22 17:28:42 Done.
276
247 std::unique_ptr<FrameDeliverer> frame_delivery_strategy; 277 std::unique_ptr<FrameDeliverer> frame_delivery_strategy;
248 switch (delivery_mode) { 278 switch (delivery_mode) {
249 case DeliveryMode::USE_DEVICE_INTERNAL_BUFFERS: 279 case DeliveryMode::USE_DEVICE_INTERNAL_BUFFERS:
250 frame_delivery_strategy = base::MakeUnique<OwnBufferFrameDeliverer>( 280 if (pixel_format == PIXEL_FORMAT_MJPEG) {
251 std::move(video_frame_painter)); 281 frame_delivery_strategy = base::MakeUnique<JpegEncodingFrameDeliverer>(
282 std::move(video_frame_painter));
283 } else {
284 frame_delivery_strategy = base::MakeUnique<OwnBufferFrameDeliverer>(
285 std::move(video_frame_painter));
286 }
252 break; 287 break;
253 case DeliveryMode::USE_CLIENT_PROVIDED_BUFFERS: 288 case DeliveryMode::USE_CLIENT_PROVIDED_BUFFERS:
289 if (pixel_format == PIXEL_FORMAT_MJPEG) {
290 DLOG(ERROR) << "PIXEL_FORMAT_MJPEG cannot be used in combination with "
291 << "USE_CLIENT_BUFFERS.";
292 return nullptr;
293 }
mcasas 2017/02/17 18:35:47 Maybe not in this CL, but I don't see any fundamen
chfremer 2017/02/22 17:28:41 I thought so, too, until I tried and ran into some
254 frame_delivery_strategy = base::MakeUnique<ClientBufferFrameDeliverer>( 294 frame_delivery_strategy = base::MakeUnique<ClientBufferFrameDeliverer>(
255 std::move(video_frame_painter)); 295 std::move(video_frame_painter));
256 break; 296 break;
257 } 297 }
258 298
259 auto photo_frame_painter = base::MakeUnique<PacmanFramePainter>( 299 auto photo_frame_painter = base::MakeUnique<PacmanFramePainter>(
260 PIXEL_FORMAT_ARGB, device_state.get()); 300 PIXEL_FORMAT_ARGB, device_state.get());
261 auto photo_device = base::MakeUnique<FakePhotoDevice>( 301 auto photo_device = base::MakeUnique<FakePhotoDevice>(
262 std::move(photo_frame_painter), device_state.get()); 302 std::move(photo_frame_painter), device_state.get());
263 303
(...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after
507 } 547 }
508 548
509 void FakeVideoCaptureDevice::TakePhoto(TakePhotoCallback callback) { 549 void FakeVideoCaptureDevice::TakePhoto(TakePhotoCallback callback) {
510 DCHECK(thread_checker_.CalledOnValidThread()); 550 DCHECK(thread_checker_.CalledOnValidThread());
511 base::ThreadTaskRunnerHandle::Get()->PostTask( 551 base::ThreadTaskRunnerHandle::Get()->PostTask(
512 FROM_HERE, base::Bind(&FakePhotoDevice::TakePhoto, 552 FROM_HERE, base::Bind(&FakePhotoDevice::TakePhoto,
513 base::Unretained(photo_device_.get()), 553 base::Unretained(photo_device_.get()),
514 base::Passed(&callback), elapsed_time_)); 554 base::Passed(&callback), elapsed_time_));
515 } 555 }
516 556
557 JpegEncodingFrameDeliverer::JpegEncodingFrameDeliverer(
558 std::unique_ptr<PacmanFramePainter> frame_painter)
559 : FrameDeliverer(std::move(frame_painter)) {}
560
561 JpegEncodingFrameDeliverer::~JpegEncodingFrameDeliverer() = default;
562
563 void JpegEncodingFrameDeliverer::Initialize(
564 VideoPixelFormat pixel_format,
565 std::unique_ptr<VideoCaptureDevice::Client> client,
566 const FakeDeviceState* device_state) {
567 client_ = std::move(client);
568 device_state_ = device_state;
569 }
570
571 void JpegEncodingFrameDeliverer::Uninitialize() {
572 client_.reset();
573 device_state_ = nullptr;
mcasas 2017/02/17 18:35:47 l.567-568 and l.572-573 are common among all Frame
chfremer 2017/02/22 17:28:41 Agreed. Thanks. I moved the common initialize and
574 argb_buffer_.reset();
575 argb_buffer_size_in_bytes_ = -1;
576 jpeg_buffer_.clear();
577 }
578
579 void JpegEncodingFrameDeliverer::PaintAndDeliverNextFrame(
580 base::TimeDelta timestamp_to_paint) {
581 if (client_ == nullptr)
582 return;
583
584 int required_argb_buffer_size_in_bytes = VideoFrame::AllocationSize(
585 PIXEL_FORMAT_ARGB, device_state_->format.frame_size);
586 if (argb_buffer_size_in_bytes_ < required_argb_buffer_size_in_bytes) {
587 argb_buffer_ =
588 base::MakeUnique<uint8_t[]>(required_argb_buffer_size_in_bytes);
589 argb_buffer_size_in_bytes_ = required_argb_buffer_size_in_bytes;
590 }
mcasas 2017/02/17 18:35:47 Instead of having a |argb_buffer_| and |argb_buff
chfremer 2017/02/22 17:28:41 Nice. Thanks. Done.
591
592 frame_painter_->PaintFrame(timestamp_to_paint, argb_buffer_.get());
593
594 static const int kBytePerPixel = 4;
mcasas 2017/02/17 18:35:47 s/kBytePer/BytesPer/ But you can skip it altogethe
chfremer 2017/02/22 17:28:41 Done.
595 static const int kQuality = 75;
596 bool success = gfx::JPEGCodec::Encode(
597 argb_buffer_.get(), gfx::JPEGCodec::FORMAT_RGBA,
mcasas 2017/02/17 18:35:47 We seem to be using ARGB format internally whereas
chfremer 2017/02/22 17:28:41 Thanks for raising this. Yes, this probably leads
598 device_state_->format.frame_size.width(),
599 device_state_->format.frame_size.height(),
600 device_state_->format.frame_size.width() * kBytePerPixel, kQuality,
mcasas 2017/02/17 18:35:47 Use here VideoFrame::RowBytes(1 /* plane */, PIXE
chfremer 2017/02/22 17:28:42 Did you mean 0 instead of 1 for the plane index? D
601 &jpeg_buffer_);
602 if (!success) {
603 DLOG(ERROR) << "Jpeg encoding failed";
604 return;
605 }
606
607 const size_t frame_size = jpeg_buffer_.size();
608 base::TimeTicks now = base::TimeTicks::Now();
609 client_->OnIncomingCapturedData(&jpeg_buffer_[0], frame_size,
610 device_state_->format, 0 /* rotation */, now,
611 CalculateTimeSinceFirstInvocation(now));
612 }
613
517 OwnBufferFrameDeliverer::OwnBufferFrameDeliverer( 614 OwnBufferFrameDeliverer::OwnBufferFrameDeliverer(
518 std::unique_ptr<PacmanFramePainter> frame_painter) 615 std::unique_ptr<PacmanFramePainter> frame_painter)
519 : FrameDeliverer(std::move(frame_painter)) {} 616 : FrameDeliverer(std::move(frame_painter)) {}
520 617
521 OwnBufferFrameDeliverer::~OwnBufferFrameDeliverer() = default; 618 OwnBufferFrameDeliverer::~OwnBufferFrameDeliverer() = default;
522 619
523 void OwnBufferFrameDeliverer::Initialize( 620 void OwnBufferFrameDeliverer::Initialize(
524 VideoPixelFormat pixel_format, 621 VideoPixelFormat pixel_format,
525 std::unique_ptr<VideoCaptureDevice::Client> client, 622 std::unique_ptr<VideoCaptureDevice::Client> client,
526 const FakeDeviceState* device_state) { 623 const FakeDeviceState* device_state) {
527 client_ = std::move(client); 624 client_ = std::move(client);
528 device_state_ = device_state; 625 device_state_ = device_state;
529 buffer_.reset(new uint8_t[VideoFrame::AllocationSize( 626 buffer_.reset(new uint8_t[VideoFrame::AllocationSize(
530 pixel_format, device_state_->format.frame_size)]); 627 pixel_format, device_state_->format.frame_size)]);
531 } 628 }
532 629
533 void OwnBufferFrameDeliverer::Uninitialize() { 630 void OwnBufferFrameDeliverer::Uninitialize() {
534 client_.reset(); 631 client_.reset();
535 device_state_ = nullptr; 632 device_state_ = nullptr;
536 buffer_.reset(); 633 buffer_.reset();
537 } 634 }
538 635
539 void OwnBufferFrameDeliverer::PaintAndDeliverNextFrame( 636 void OwnBufferFrameDeliverer::PaintAndDeliverNextFrame(
540 base::TimeDelta timestamp_to_paint) { 637 base::TimeDelta timestamp_to_paint) {
541 if (!client_) 638 if (!client_)
542 return; 639 return;
543 const size_t frame_size = device_state_->format.ImageAllocationSize(); 640 const size_t frame_size = device_state_->format.ImageAllocationSize();
544 memset(buffer_.get(), 0, frame_size);
545 frame_painter_->PaintFrame(timestamp_to_paint, buffer_.get());
546 base::TimeTicks now = base::TimeTicks::Now(); 641 base::TimeTicks now = base::TimeTicks::Now();
547 client_->OnIncomingCapturedData(buffer_.get(), frame_size, 642 client_->OnIncomingCapturedData(buffer_.get(), frame_size,
548 device_state_->format, 0 /* rotation */, now, 643 device_state_->format, 0 /* rotation */, now,
549 CalculateTimeSinceFirstInvocation(now)); 644 CalculateTimeSinceFirstInvocation(now));
550 } 645 }
551 646
552 ClientBufferFrameDeliverer::ClientBufferFrameDeliverer( 647 ClientBufferFrameDeliverer::ClientBufferFrameDeliverer(
553 std::unique_ptr<PacmanFramePainter> frame_painter) 648 std::unique_ptr<PacmanFramePainter> frame_painter)
554 : FrameDeliverer(std::move(frame_painter)) {} 649 : FrameDeliverer(std::move(frame_painter)) {}
555 650
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
630 int session_id) { 725 int session_id) {
631 DCHECK(thread_checker_.CalledOnValidThread()); 726 DCHECK(thread_checker_.CalledOnValidThread());
632 if (session_id != current_session_id_) 727 if (session_id != current_session_id_)
633 return; 728 return;
634 729
635 frame_deliverer_->PaintAndDeliverNextFrame(elapsed_time_); 730 frame_deliverer_->PaintAndDeliverNextFrame(elapsed_time_);
636 BeepAndScheduleNextCapture(expected_execution_time); 731 BeepAndScheduleNextCapture(expected_execution_time);
637 } 732 }
638 733
639 } // namespace media 734 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698