6967e794abfc31948e726ceccbb2da07d7b97796
[WebKit-https.git] / Source / WebCore / platform / mediastream / mac / RealtimeOutgoingVideoSource.cpp
1 /*
2  * Copyright (C) 2017 Apple Inc.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted, provided that the following conditions
6  * are required to be met:
7  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution.
13  * 3.  Neither the name of Apple Inc. nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE INC. AND ITS CONTRIBUTORS BE LIABLE FOR
21  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include "config.h"
30 #include "RealtimeOutgoingVideoSource.h"
31
32 #if USE(LIBWEBRTC)
33
34 #include <webrtc/common_video/include/corevideo_frame_buffer.h>
35 #include <webrtc/common_video/libyuv/include/webrtc_libyuv.h>
36 #include <webrtc/media/base/videoframe.h>
37 #include <wtf/MainThread.h>
38
39 #include "CoreMediaSoftLink.h"
40 #include "CoreVideoSoftLink.h"
41
42 namespace WebCore {
43
44 RealtimeOutgoingVideoSource::RealtimeOutgoingVideoSource(Ref<RealtimeMediaSource>&& videoSource)
45     : m_videoSource(WTFMove(videoSource))
46     , m_blackFrameTimer(*this, &RealtimeOutgoingVideoSource::sendOneBlackFrame)
47 {
48     m_videoSource->addObserver(*this);
49     setSizeFromSource();
50 }
51
52 bool RealtimeOutgoingVideoSource::setSource(Ref<RealtimeMediaSource>&& newSource)
53 {
54     if (!m_initialSettings)
55         m_initialSettings = m_videoSource->settings();
56
57     auto newSettings = newSource->settings();
58
59     if (m_initialSettings->width() < newSettings.width() || m_initialSettings->height() < newSettings.height())
60         return false;
61
62     m_videoSource->removeObserver(*this);
63     m_videoSource = WTFMove(newSource);
64     m_videoSource->addObserver(*this);
65     setSizeFromSource();
66     return true;
67 }
68
69 void RealtimeOutgoingVideoSource::stop()
70 {
71     m_videoSource->removeObserver(*this);
72     m_blackFrameTimer.stop();
73     m_isStopped = true;
74 }
75
76 void RealtimeOutgoingVideoSource::sourceMutedChanged()
77 {
78     ASSERT(m_muted != m_videoSource->muted());
79     m_muted = m_videoSource->muted();
80
81     if (m_muted && m_sinks.size() && m_enabled)
82         sendBlackFrame();
83 }
84
85 void RealtimeOutgoingVideoSource::sourceEnabledChanged()
86 {
87     ASSERT(m_enabled != m_videoSource->enabled());
88     m_enabled = m_videoSource->enabled();
89
90     if (!m_enabled && m_sinks.size() && !m_muted)
91         sendBlackFrame();
92 }
93
94 void RealtimeOutgoingVideoSource::setSizeFromSource()
95 {
96     const auto& settings = m_videoSource->settings();
97     m_width = settings.width();
98     m_height = settings.height();
99 }
100
101 bool RealtimeOutgoingVideoSource::GetStats(Stats*)
102 {
103     return false;
104 }
105
106 void RealtimeOutgoingVideoSource::AddOrUpdateSink(rtc::VideoSinkInterface<webrtc::VideoFrame>* sink, const rtc::VideoSinkWants&)
107 {
108     // FIXME: support sinkWants
109     if (!m_sinks.contains(sink))
110         m_sinks.append(sink);
111 }
112
113 void RealtimeOutgoingVideoSource::RemoveSink(rtc::VideoSinkInterface<webrtc::VideoFrame>* sink)
114 {
115     m_sinks.removeFirst(sink);
116 }
117
118 void RealtimeOutgoingVideoSource::sendBlackFrame()
119 {
120     if (!m_blackFrame) {
121         auto frame = m_bufferPool.CreateBuffer(m_width, m_height);
122         frame->SetToBlack();
123         m_blackFrame = WTFMove(frame);
124     }
125     sendOneBlackFrame();
126     // FIXME: We should not need to send two black frames but VTB requires that so we are sure a black frame is sent over the wire.
127     m_blackFrameTimer.startOneShot(0_s);
128 }
129
130 void RealtimeOutgoingVideoSource::sendOneBlackFrame()
131 {
132     sendFrame(rtc::scoped_refptr<webrtc::VideoFrameBuffer>(m_blackFrame));
133 }
134
135 void RealtimeOutgoingVideoSource::sendFrame(rtc::scoped_refptr<webrtc::VideoFrameBuffer>&& buffer)
136 {
137     webrtc::VideoFrame frame(buffer, 0, 0, m_currentRotation);
138     for (auto* sink : m_sinks)
139         sink->OnFrame(frame);
140 }
141
142 void RealtimeOutgoingVideoSource::videoSampleAvailable(MediaSample& sample)
143 {
144     if (!m_sinks.size())
145         return;
146
147     if (m_muted || !m_enabled)
148         return;
149
150     switch (sample.videoRotation()) {
151     case MediaSample::VideoRotation::None:
152         m_currentRotation = webrtc::kVideoRotation_0;
153         break;
154     case MediaSample::VideoRotation::UpsideDown:
155         m_currentRotation = webrtc::kVideoRotation_180;
156         break;
157     case MediaSample::VideoRotation::Right:
158         m_currentRotation = webrtc::kVideoRotation_90;
159         break;
160     case MediaSample::VideoRotation::Left:
161         m_currentRotation = webrtc::kVideoRotation_270;
162         break;
163     }
164
165     ASSERT(sample.platformSample().type == PlatformSample::CMSampleBufferType);
166     auto pixelBuffer = static_cast<CVPixelBufferRef>(CMSampleBufferGetImageBuffer(sample.platformSample().sample.cmSampleBuffer));
167     auto pixelFormatType = CVPixelBufferGetPixelFormatType(pixelBuffer);
168
169     if (pixelFormatType == kCVPixelFormatType_420YpCbCr8Planar || pixelFormatType == kCVPixelFormatType_420YpCbCr8BiPlanarFullRange) {
170         sendFrame(new rtc::RefCountedObject<webrtc::CoreVideoFrameBuffer>(pixelBuffer));
171         return;
172     }
173
174     CVPixelBufferLockBaseAddress(pixelBuffer, 0);
175     auto* source = reinterpret_cast<uint8_t*>(CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 0));
176
177     auto newBuffer = m_bufferPool.CreateBuffer(m_width, m_height);
178     if (pixelFormatType == kCVPixelFormatType_32BGRA)
179         webrtc::ConvertToI420(webrtc::kARGB, source, 0, 0, m_width, m_height, 0, webrtc::kVideoRotation_0, newBuffer);
180     else {
181         ASSERT(pixelFormatType == kCVPixelFormatType_32ARGB);
182         webrtc::ConvertToI420(webrtc::kBGRA, source, 0, 0, m_width, m_height, 0, webrtc::kVideoRotation_0, newBuffer);
183     }
184     CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);
185     sendFrame(WTFMove(newBuffer));
186 }
187
188 } // namespace WebCore
189
190 #endif // USE(LIBWEBRTC)