~mmach/netext73/webkit2gtk

« back to all changes in this revision

Viewing changes to Source/WebKit/WebProcess/GPU/webrtc/LibWebRTCCodecs.cpp

  • Committer: mmach
  • Date: 2023-06-16 17:21:37 UTC
  • Revision ID: netbit73@gmail.com-20230616172137-2rqx6yr96ga9g3kp
1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2020 Apple Inc. All rights reserved.
 
3
 *
 
4
 * Redistribution and use in source and binary forms, with or without
 
5
 * modification, are permitted provided that the following conditions
 
6
 * are met:
 
7
 * 1. Redistributions of source code must retain the above copyright
 
8
 *    notice, this list of conditions and the following disclaimer.
 
9
 * 2. Redistributions in binary form must reproduce the above copyright
 
10
 *    notice, this list of conditions and the following disclaimer in the
 
11
 *    documentation and/or other materials provided with the distribution.
 
12
 *
 
13
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
 
14
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 
15
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 
16
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
 
17
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 
18
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 
19
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 
20
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 
21
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 
22
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 
23
 * THE POSSIBILITY OF SUCH DAMAGE.
 
24
 */
 
25
 
 
26
#include "config.h"
 
27
#include "LibWebRTCCodecs.h"
 
28
 
 
29
#if USE(LIBWEBRTC) && PLATFORM(COCOA) && ENABLE(GPU_PROCESS)
 
30
 
 
31
#include "DataReference.h"
 
32
#include "GPUProcessConnection.h"
 
33
#include "LibWebRTCCodecsProxyMessages.h"
 
34
#include "WebProcess.h"
 
35
#include <WebCore/LibWebRTCMacros.h>
 
36
#include <WebCore/RealtimeVideoUtilities.h>
 
37
#include <WebCore/RemoteVideoSample.h>
 
38
#include <pal/cf/CoreMediaSoftLink.h>
 
39
#include <webrtc/sdk/WebKit/WebKitEncoder.h>
 
40
#include <webrtc/sdk/WebKit/WebKitUtilities.h>
 
41
#include <wtf/MainThread.h>
 
42
 
 
43
namespace WebKit {
 
44
using namespace WebCore;
 
45
 
 
46
static webrtc::WebKitVideoDecoder createVideoDecoder(const webrtc::SdpVideoFormat& format)
 
47
{
 
48
    if (format.name != "H264")
 
49
        return nullptr;
 
50
 
 
51
    return WebProcess::singleton().libWebRTCCodecs().createDecoder();
 
52
}
 
53
 
 
54
static int32_t releaseVideoDecoder(webrtc::WebKitVideoDecoder decoder)
 
55
{
 
56
    return WebProcess::singleton().libWebRTCCodecs().releaseDecoder(*static_cast<LibWebRTCCodecs::Decoder*>(decoder));
 
57
}
 
58
 
 
59
static int32_t decodeVideoFrame(webrtc::WebKitVideoDecoder decoder, uint32_t timeStamp, const uint8_t* data, size_t size)
 
60
{
 
61
    return WebProcess::singleton().libWebRTCCodecs().decodeFrame(*static_cast<LibWebRTCCodecs::Decoder*>(decoder), timeStamp, data, size);
 
62
}
 
63
 
 
64
static int32_t registerDecodeCompleteCallback(webrtc::WebKitVideoDecoder decoder, void* decodedImageCallback)
 
65
{
 
66
    WebProcess::singleton().libWebRTCCodecs().registerDecodeFrameCallback(*static_cast<LibWebRTCCodecs::Decoder*>(decoder), decodedImageCallback);
 
67
    return 0;
 
68
}
 
69
 
 
70
static webrtc::WebKitVideoEncoder createVideoEncoder(const webrtc::SdpVideoFormat& format)
 
71
{
 
72
    if (format.name != "H264")
 
73
        return nullptr;
 
74
 
 
75
    return WebProcess::singleton().libWebRTCCodecs().createEncoder(format.parameters);
 
76
}
 
77
 
 
78
static int32_t releaseVideoEncoder(webrtc::WebKitVideoEncoder encoder)
 
79
{
 
80
    return WebProcess::singleton().libWebRTCCodecs().releaseEncoder(*static_cast<LibWebRTCCodecs::Encoder*>(encoder));
 
81
}
 
82
 
 
83
static int32_t initializeVideoEncoder(webrtc::WebKitVideoEncoder encoder, const webrtc::VideoCodec& codec)
 
84
{
 
85
    return WebProcess::singleton().libWebRTCCodecs().initializeEncoder(*static_cast<LibWebRTCCodecs::Encoder*>(encoder), codec.width, codec.height, codec.startBitrate, codec.maxBitrate, codec.minBitrate, codec.maxFramerate);
 
86
}
 
87
 
 
88
static inline MediaSample::VideoRotation toMediaSampleVideoRotation(webrtc::VideoRotation rotation)
 
89
{
 
90
    switch (rotation) {
 
91
    case webrtc::kVideoRotation_0:
 
92
        return MediaSample::VideoRotation::None;
 
93
    case webrtc::kVideoRotation_180:
 
94
        return MediaSample::VideoRotation::UpsideDown;
 
95
    case webrtc::kVideoRotation_90:
 
96
        return MediaSample::VideoRotation::Right;
 
97
    case webrtc::kVideoRotation_270:
 
98
        return MediaSample::VideoRotation::Left;
 
99
    }
 
100
    ASSERT_NOT_REACHED();
 
101
    return MediaSample::VideoRotation::None;
 
102
}
 
103
 
 
104
static int32_t encodeVideoFrame(webrtc::WebKitVideoEncoder encoder, const webrtc::VideoFrame& frame, bool shouldEncodeAsKeyFrame)
 
105
{
 
106
    RetainPtr<CVPixelBufferRef> newPixelBuffer;
 
107
    auto pixelBuffer = webrtc::pixelBufferFromFrame(frame, [&newPixelBuffer](size_t width, size_t height) -> CVPixelBufferRef {
 
108
        auto pixelBufferPool = WebProcess::singleton().libWebRTCCodecs().pixelBufferPool(width, height);
 
109
        if (!pixelBufferPool)
 
110
            return nullptr;
 
111
 
 
112
        newPixelBuffer = WebCore::createPixelBufferFromPool(pixelBufferPool);
 
113
        return newPixelBuffer.get();
 
114
    });
 
115
 
 
116
    if (!pixelBuffer)
 
117
        return WEBRTC_VIDEO_CODEC_ERROR;
 
118
 
 
119
    auto sample = RemoteVideoSample::create(pixelBuffer, MediaTime(frame.timestamp_us(), 1000000), toMediaSampleVideoRotation(frame.rotation()));
 
120
    return WebProcess::singleton().libWebRTCCodecs().encodeFrame(*static_cast<LibWebRTCCodecs::Encoder*>(encoder), *sample, shouldEncodeAsKeyFrame);
 
121
}
 
122
 
 
123
static int32_t registerEncodeCompleteCallback(webrtc::WebKitVideoEncoder encoder, void* encodedImageCallback)
 
124
{
 
125
    WebProcess::singleton().libWebRTCCodecs().registerEncodeFrameCallback(*static_cast<LibWebRTCCodecs::Encoder*>(encoder), encodedImageCallback);
 
126
    return 0;
 
127
}
 
128
 
 
129
static void setEncodeRatesCallback(webrtc::WebKitVideoEncoder encoder, const webrtc::VideoEncoder::RateControlParameters& parameters)
 
130
{
 
131
    uint32_t bitRate = parameters.bitrate.get_sum_kbps();
 
132
    uint32_t frameRate = static_cast<uint32_t>(parameters.framerate_fps + 0.5);
 
133
    WebProcess::singleton().libWebRTCCodecs().setEncodeRates(*static_cast<LibWebRTCCodecs::Encoder*>(encoder), bitRate, frameRate);
 
134
}
 
135
 
 
136
void LibWebRTCCodecs::setCallbacks(bool useGPUProcess)
 
137
{
 
138
    ASSERT(isMainThread());
 
139
 
 
140
    if (!useGPUProcess) {
 
141
        webrtc::setVideoDecoderCallbacks(nullptr, nullptr, nullptr, nullptr);
 
142
        webrtc::setVideoEncoderCallbacks(nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
 
143
        return;
 
144
    }
 
145
    // Let's create WebProcess libWebRTCCodecs since it may be called from various threads.
 
146
    WebProcess::singleton().libWebRTCCodecs();
 
147
    webrtc::setVideoDecoderCallbacks(createVideoDecoder, releaseVideoDecoder, decodeVideoFrame, registerDecodeCompleteCallback);
 
148
    webrtc::setVideoEncoderCallbacks(createVideoEncoder, releaseVideoEncoder, initializeVideoEncoder, encodeVideoFrame, registerEncodeCompleteCallback, setEncodeRatesCallback);
 
149
}
 
150
 
 
151
LibWebRTCCodecs::Decoder* LibWebRTCCodecs::createDecoder()
 
152
{
 
153
    auto decoder = makeUnique<Decoder>();
 
154
    auto* result = decoder.get();
 
155
    decoder->identifier = RTCDecoderIdentifier::generateThreadSafe();
 
156
 
 
157
    callOnMainRunLoop([this, decoder = WTFMove(decoder)]() mutable {
 
158
        decoder->connection = &WebProcess::singleton().ensureGPUProcessConnection().connection();
 
159
 
 
160
        auto decoderIdentifier = decoder->identifier;
 
161
        decoder->connection->send(Messages::LibWebRTCCodecsProxy::CreateDecoder { decoderIdentifier }, 0);
 
162
 
 
163
        ASSERT(!m_decoders.contains(decoderIdentifier));
 
164
        m_decoders.add(decoderIdentifier, WTFMove(decoder));
 
165
    });
 
166
    return result;
 
167
}
 
168
 
 
169
int32_t LibWebRTCCodecs::releaseDecoder(Decoder& decoder)
 
170
{
 
171
    LockHolder holder(decoder.decodedImageCallbackLock);
 
172
    decoder.decodedImageCallback = nullptr;
 
173
 
 
174
    callOnMainRunLoop([this, decoderIdentifier = decoder.identifier] {
 
175
        ASSERT(m_decoders.contains(decoderIdentifier));
 
176
 
 
177
        m_decoders.remove(decoderIdentifier);
 
178
        WebProcess::singleton().ensureGPUProcessConnection().connection().send(Messages::LibWebRTCCodecsProxy::ReleaseDecoder { decoderIdentifier }, 0);
 
179
    });
 
180
    return 0;
 
181
}
 
182
 
 
183
int32_t LibWebRTCCodecs::decodeFrame(Decoder& decoder, uint32_t timeStamp, const uint8_t* data, size_t size)
 
184
{
 
185
    if (!decoder.connection || decoder.hasError) {
 
186
        decoder.hasError = false;
 
187
        return WEBRTC_VIDEO_CODEC_ERROR;
 
188
    }
 
189
 
 
190
    decoder.connection->send(Messages::LibWebRTCCodecsProxy::DecodeFrame { decoder.identifier, timeStamp, IPC::DataReference { data, size } }, 0);
 
191
    return WEBRTC_VIDEO_CODEC_OK;
 
192
}
 
193
 
 
194
void LibWebRTCCodecs::registerDecodeFrameCallback(Decoder& decoder, void* decodedImageCallback)
 
195
{
 
196
    LockHolder holder(decoder.decodedImageCallbackLock);
 
197
    decoder.decodedImageCallback = decodedImageCallback;
 
198
}
 
199
 
 
200
void LibWebRTCCodecs::failedDecoding(RTCDecoderIdentifier decoderIdentifier)
 
201
{
 
202
    ASSERT(isMainThread());
 
203
 
 
204
    if (auto* decoder = m_decoders.get(decoderIdentifier))
 
205
        decoder->hasError = true;
 
206
}
 
207
 
 
208
void LibWebRTCCodecs::completedDecoding(RTCDecoderIdentifier decoderIdentifier, uint32_t timeStamp, WebCore::RemoteVideoSample&& remoteSample)
 
209
{
 
210
    ASSERT(isMainThread());
 
211
 
 
212
    // FIXME: Do error logging.
 
213
    auto* decoder = m_decoders.get(decoderIdentifier);
 
214
    if (!decoder)
 
215
        return;
 
216
 
 
217
    auto locker = tryHoldLock(decoder->decodedImageCallbackLock);
 
218
    if (!locker)
 
219
        return;
 
220
 
 
221
    if (!decoder->decodedImageCallback)
 
222
        return;
 
223
 
 
224
    if (!m_imageTransferSession || m_imageTransferSession->pixelFormat() != remoteSample.videoFormat())
 
225
        m_imageTransferSession = WebCore::ImageTransferSessionVT::create(remoteSample.videoFormat());
 
226
 
 
227
    if (!m_imageTransferSession) {
 
228
        ASSERT_NOT_REACHED();
 
229
        return;
 
230
    }
 
231
 
 
232
    auto pixelBuffer = m_imageTransferSession->createPixelBuffer(remoteSample.surface(), remoteSample.size());
 
233
    if (!pixelBuffer) {
 
234
        ASSERT_NOT_REACHED();
 
235
        return;
 
236
    }
 
237
 
 
238
    webrtc::RemoteVideoDecoder::decodeComplete(decoder->decodedImageCallback, timeStamp, pixelBuffer.get(), remoteSample.time().toDouble());
 
239
}
 
240
 
 
241
LibWebRTCCodecs::Encoder* LibWebRTCCodecs::createEncoder(const std::map<std::string, std::string>& formatParameters)
 
242
{
 
243
    auto encoder = makeUnique<Encoder>();
 
244
    auto* result = encoder.get();
 
245
    encoder->identifier = RTCEncoderIdentifier::generateThreadSafe();
 
246
 
 
247
    Vector<std::pair<String, String>> parameters;
 
248
    for (auto& keyValue : formatParameters)
 
249
        parameters.append(std::make_pair(String::fromUTF8(keyValue.first.data(), keyValue.first.length()), String::fromUTF8(keyValue.second.data(), keyValue.second.length())));
 
250
 
 
251
    callOnMainRunLoop([this, encoder = WTFMove(encoder), parameters = WTFMove(parameters)]() mutable {
 
252
        auto encoderIdentifier = encoder->identifier;
 
253
        ASSERT(!m_encoders.contains(encoderIdentifier));
 
254
 
 
255
        WebProcess::singleton().ensureGPUProcessConnection().connection().send(Messages::LibWebRTCCodecsProxy::CreateEncoder { encoderIdentifier, parameters }, 0);
 
256
        m_encoders.add(encoderIdentifier, WTFMove(encoder));
 
257
    });
 
258
    return result;
 
259
}
 
260
 
 
261
int32_t LibWebRTCCodecs::releaseEncoder(Encoder& encoder)
 
262
{
 
263
    LockHolder holder(encoder.encodedImageCallbackLock);
 
264
    encoder.encodedImageCallback = nullptr;
 
265
 
 
266
    callOnMainRunLoop([this, encoderIdentifier = encoder.identifier] {
 
267
        ASSERT(m_encoders.contains(encoderIdentifier));
 
268
 
 
269
        m_encoders.remove(encoderIdentifier);
 
270
        WebProcess::singleton().ensureGPUProcessConnection().connection().send(Messages::LibWebRTCCodecsProxy::ReleaseEncoder { encoderIdentifier }, 0);
 
271
    });
 
272
    return 0;
 
273
}
 
274
 
 
275
int32_t LibWebRTCCodecs::initializeEncoder(Encoder& encoder, uint16_t width, uint16_t height, unsigned startBitRate, unsigned maxBitRate, unsigned minBitRate, uint32_t maxFrameRate)
 
276
{
 
277
    callOnMainRunLoop([this, encoderIdentifier = encoder.identifier, width, height, startBitRate, maxBitRate, minBitRate, maxFrameRate] {
 
278
        if (auto* encoder = m_encoders.get(encoderIdentifier)) {
 
279
            auto& connection = WebProcess::singleton().ensureGPUProcessConnection().connection();
 
280
            connection.send(Messages::LibWebRTCCodecsProxy::InitializeEncoder { encoderIdentifier, width, height, startBitRate, maxBitRate, minBitRate, maxFrameRate }, 0);
 
281
            // We set encoder->connection here so that InitializeEncoder is sent before any EncodeFrame message.
 
282
            encoder->connection = &connection;
 
283
        }
 
284
    });
 
285
    return 0;
 
286
}
 
287
 
 
288
int32_t LibWebRTCCodecs::encodeFrame(Encoder& encoder, const WebCore::RemoteVideoSample& frame, bool shouldEncodeAsKeyFrame)
 
289
{
 
290
    if (!encoder.connection)
 
291
        return WEBRTC_VIDEO_CODEC_ERROR;
 
292
 
 
293
    encoder.connection->send(Messages::LibWebRTCCodecsProxy::EncodeFrame { encoder.identifier, frame, shouldEncodeAsKeyFrame }, 0);
 
294
    return WEBRTC_VIDEO_CODEC_OK;
 
295
}
 
296
 
 
297
void LibWebRTCCodecs::registerEncodeFrameCallback(Encoder& encoder, void* encodedImageCallback)
 
298
{
 
299
    LockHolder holder(encoder.encodedImageCallbackLock);
 
300
    encoder.encodedImageCallback = encodedImageCallback;
 
301
}
 
302
 
 
303
void LibWebRTCCodecs::setEncodeRates(Encoder& encoder, uint32_t bitRate, uint32_t frameRate)
 
304
{
 
305
    if (!encoder.connection) {
 
306
        callOnMainRunLoop([this, encoderIdentifier = encoder.identifier, bitRate, frameRate] {
 
307
            UNUSED_PARAM(this);
 
308
            ASSERT(m_encoders.contains(encoderIdentifier));
 
309
            ASSERT(m_encoders.get(encoderIdentifier)->connection);
 
310
            WebProcess::singleton().ensureGPUProcessConnection().connection().send(Messages::LibWebRTCCodecsProxy::SetEncodeRates { encoderIdentifier, bitRate, frameRate }, 0);
 
311
        });
 
312
        return;
 
313
    }
 
314
    encoder.connection->send(Messages::LibWebRTCCodecsProxy::SetEncodeRates { encoder.identifier, bitRate, frameRate }, 0);
 
315
}
 
316
 
 
317
void LibWebRTCCodecs::completedEncoding(RTCEncoderIdentifier identifier, IPC::DataReference&& data, const webrtc::WebKitEncodedFrameInfo& info, webrtc::WebKitRTPFragmentationHeader&& fragmentationHeader)
 
318
{
 
319
    ASSERT(isMainThread());
 
320
 
 
321
    // FIXME: Do error logging.
 
322
    auto* encoder = m_encoders.get(identifier);
 
323
    if (!encoder)
 
324
        return;
 
325
 
 
326
    auto locker = tryHoldLock(encoder->encodedImageCallbackLock);
 
327
    if (!locker)
 
328
        return;
 
329
 
 
330
    if (!encoder->encodedImageCallback)
 
331
        return;
 
332
 
 
333
    webrtc::RemoteVideoEncoder::encodeComplete(encoder->encodedImageCallback, const_cast<uint8_t*>(data.data()), data.size(), info, fragmentationHeader.value());
 
334
}
 
335
 
 
336
CVPixelBufferPoolRef LibWebRTCCodecs::pixelBufferPool(size_t width, size_t height)
 
337
{
 
338
    if (!m_pixelBufferPool || m_pixelBufferPoolWidth != width || m_pixelBufferPoolHeight != height) {
 
339
        m_pixelBufferPool = createPixelBufferPool(width, height);
 
340
        m_pixelBufferPoolWidth = width;
 
341
        m_pixelBufferPoolHeight = height;
 
342
    }
 
343
    return m_pixelBufferPool.get();
 
344
}
 
345
 
 
346
}
 
347
 
 
348
#endif