1 // Copyright 2020 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "third_party/blink/renderer/modules/mediastream/pushable_media_stream_video_source.h"
6
7 #include "base/run_loop.h"
8 #include "media/base/bind_to_current_loop.h"
9 #include "testing/gtest/include/gtest/gtest.h"
10 #include "third_party/blink/public/mojom/mediastream/media_stream.mojom-blink.h"
11 #include "third_party/blink/public/web/modules/mediastream/media_stream_video_sink.h"
12 #include "third_party/blink/public/web/web_heap.h"
13 #include "third_party/blink/renderer/modules/mediastream/media_stream_video_track.h"
14 #include "third_party/blink/renderer/modules/mediastream/video_track_adapter_settings.h"
15 #include "third_party/blink/renderer/platform/mediastream/media_stream_source.h"
16 #include "third_party/blink/renderer/platform/testing/io_task_runner_testing_platform_support.h"
17 #include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
18
19 namespace blink {
20
21 namespace {
22
23 class FakeMediaStreamVideoSink : public MediaStreamVideoSink {
24 public:
FakeMediaStreamVideoSink(base::TimeTicks * capture_time,media::VideoFrameMetadata * metadata,gfx::Size * natural_size,base::OnceClosure got_frame_cb)25 FakeMediaStreamVideoSink(base::TimeTicks* capture_time,
26 media::VideoFrameMetadata* metadata,
27 gfx::Size* natural_size,
28 base::OnceClosure got_frame_cb)
29 : capture_time_(capture_time),
30 metadata_(metadata),
31 natural_size_(natural_size),
32 got_frame_cb_(std::move(got_frame_cb)) {}
33
ConnectToTrack(const WebMediaStreamTrack & track)34 void ConnectToTrack(const WebMediaStreamTrack& track) {
35 MediaStreamVideoSink::ConnectToTrack(
36 track,
37 ConvertToBaseRepeatingCallback(
38 CrossThreadBindRepeating(&FakeMediaStreamVideoSink::OnVideoFrame,
39 WTF::CrossThreadUnretained(this))),
40 true);
41 }
42
DisconnectFromTrack()43 void DisconnectFromTrack() { MediaStreamVideoSink::DisconnectFromTrack(); }
44
OnVideoFrame(scoped_refptr<media::VideoFrame> frame,base::TimeTicks capture_time)45 void OnVideoFrame(scoped_refptr<media::VideoFrame> frame,
46 base::TimeTicks capture_time) {
47 *capture_time_ = capture_time;
48 *metadata_ = *frame->metadata();
49 *natural_size_ = frame->natural_size();
50 std::move(got_frame_cb_).Run();
51 }
52
53 private:
54 base::TimeTicks* const capture_time_;
55 media::VideoFrameMetadata* const metadata_;
56 gfx::Size* const natural_size_;
57 base::OnceClosure got_frame_cb_;
58 };
59
60 } // namespace
61
62 class PushableMediaStreamVideoSourceTest : public testing::Test {
63 public:
PushableMediaStreamVideoSourceTest()64 PushableMediaStreamVideoSourceTest() {
65 pushable_video_source_ = new PushableMediaStreamVideoSource();
66 stream_source_ = MakeGarbageCollected<MediaStreamSource>(
67 "dummy_source_id", MediaStreamSource::kTypeVideo, "dummy_source_name",
68 false /* remote */);
69 stream_source_->SetPlatformSource(base::WrapUnique(pushable_video_source_));
70 }
71
TearDown()72 void TearDown() override {
73 stream_source_ = nullptr;
74 WebHeap::CollectAllGarbageForTesting();
75 }
76
StartSource()77 WebMediaStreamTrack StartSource() {
78 return MediaStreamVideoTrack::CreateVideoTrack(
79 pushable_video_source_,
80 MediaStreamVideoSource::ConstraintsOnceCallback(),
81 /*enabled=*/true);
82 }
83
84 protected:
85 ScopedTestingPlatformSupport<IOTaskRunnerTestingPlatformSupport> platform_;
86
87 Persistent<MediaStreamSource> stream_source_;
88 PushableMediaStreamVideoSource* pushable_video_source_;
89 };
90
TEST_F(PushableMediaStreamVideoSourceTest,StartAndStop)91 TEST_F(PushableMediaStreamVideoSourceTest, StartAndStop) {
92 EXPECT_EQ(MediaStreamSource::kReadyStateLive,
93 stream_source_->GetReadyState());
94 EXPECT_FALSE(pushable_video_source_->running());
95
96 WebMediaStreamTrack track = StartSource();
97 EXPECT_EQ(MediaStreamSource::kReadyStateLive,
98 stream_source_->GetReadyState());
99 EXPECT_TRUE(pushable_video_source_->running());
100
101 // If the pushable source stops, the MediaStreamSource should stop.
102 pushable_video_source_->StopSource();
103 EXPECT_EQ(MediaStreamSource::kReadyStateEnded,
104 stream_source_->GetReadyState());
105 EXPECT_FALSE(pushable_video_source_->running());
106 }
107
TEST_F(PushableMediaStreamVideoSourceTest,FramesPropagateToSink)108 TEST_F(PushableMediaStreamVideoSourceTest, FramesPropagateToSink) {
109 WebMediaStreamTrack track = StartSource();
110 base::RunLoop run_loop;
111 base::TimeTicks reference_capture_time = base::TimeTicks::Now();
112 base::TimeTicks capture_time;
113 media::VideoFrameMetadata metadata;
114 gfx::Size natural_size;
115 FakeMediaStreamVideoSink fake_sink(
116 &capture_time, &metadata, &natural_size,
117 media::BindToCurrentLoop(run_loop.QuitClosure()));
118 fake_sink.ConnectToTrack(track);
119 const scoped_refptr<media::VideoFrame> frame =
120 media::VideoFrame::CreateBlackFrame(gfx::Size(100, 50));
121 frame->metadata()->frame_rate = 30.0;
122
123 pushable_video_source_->PushFrame(frame, reference_capture_time);
124 run_loop.Run();
125
126 fake_sink.DisconnectFromTrack();
127 EXPECT_EQ(reference_capture_time, capture_time);
128 EXPECT_EQ(30.0, *metadata.frame_rate);
129 EXPECT_EQ(natural_size.width(), 100);
130 EXPECT_EQ(natural_size.height(), 50);
131 }
132
133 } // namespace blink
134