#ios #opentok #screensharing
#iOS #opentok #скриншот
Вопрос:
Мы используем ReplayKit для получения CMSSampleBuffers и пересылки их в OTVideoCaptureConsumer, и после изменения размера буферов ReplayKit в буфер размером 1280х720 или 1024х768 мы получаем ленту общего доступа к экрану, но она всегда становится размытой.
Убедившись, что мы контролируем частоту кадров в секунду, отправляемую на videoCaptureConsumer, чтобы ограничить пропускную способность, мы по-прежнему не можем получить изображение хорошего качества, полученное с медиа-маршрутизатора на подписанных устройствах.
Мы проверили, что изображение, отправленное OpenTok OTVideoCaptureConsumer, является четким изображением, но результирующий поток всегда очень быстро становится размытым на стороне подписчика
Вопрос: Кто-нибудь нашел способ получить чистый канал общего доступа к экрану с помощью OpenTok iOS SDK, независимо от размера экрана устройства?
Попытки:
- Другой способ отправки кадров:
Я пытался отправлять изображения с помощью CVPixelBuffer и OTVideoFrame. В примере, предложенном службой поддержки OpenTok, используются оба метода CVPixelBuffer для изображений с камеры и OTVideoFrame для черных изображений, когда с камеры не получено ни одного кадра. Но результирующий поток становится размытым в любом случае
- Разные форматы и размеры:
Я не нашел никакой документации, в которой упоминались бы спецификации изображения, ожидаемого iOS SDK. Есть ли что-нибудь доступное где-нибудь, чтобы помочь нам понять, каковы поддерживаемые форматы изображений, ограничения на размер данных и поддерживаемые разрешения?
Я попытался отправить буфер ReplayKit как есть пользователю videoCaptureConsumer из нашего приложения и, например, на iPad 9.7 Pro. собственное разрешение экрана составляет 1920×1440, что, похоже, принимается iOS SDK (возвращает успех), но отображает только черный экран на стороне подписчика.
У меня просто нет другой идеи
- Повторная передача последнего кадра, когда ReplayKit прекращает отправку кадров:
Я видел это поведение в примере Twilio ReplayKit, но должны ли мы повторно отправлять последний кадр, когда ReplayKit не отправляет ни одного кадра? Я не видел ни одного документа, если все в порядке или если медиа-маршрутизатор будет вести себя правильно, если мы это сделаем
PS: некоторые ссылки, которые я нашел на случай, если это может помочь кому-то другому
Все, что я видел в предлагаемом примере поддержки OpenTok, это:
- поддерживаемые пресеты для iOS AVCaptureSession, которые затем пересылаются в OTVideoCapturer (Custom-Video-Driver / Lets-Build-OTPublisher / Single-Cam-Capturer/TBExampleVideoCapture.m # L255)
- жестко заданный размер черных рамок (Custom-Video-Driver / Lets-Build-OTPublisher / Single-Cam-Capturer /TBExampleVideoCapture.m # L552)
- необработанный CMSampleBuffer пересылается непосредственно пользователю videoCaptureConsumer (Custom-Video-Driver / Lets-Build-OTPublisher/ Single-Cam-Capturer/TBExampleVideoCapture.m # L711)
Из документа OpenTok и сообщений на форуме:
- OTVideoCaptureConsumer doc
- В документе OTPublisherKit упоминается, что частота кадров должна составлять 5 кадров в секунду или ниже, а сам код
- связанный вопрос
- и документ JS, касающийся максимальных разрешений, которые, по-видимому, установлены для издателя для общего доступа к экрану
Я также нашел несколько других сообщений, которые помогли понять, в чем может быть проблема:
- к сожалению, не очень приятный… кто упомянул, что изображения должны быть «кратными 16»
- еще один пример, который, похоже, тоже рассматривал этот случай и ограничивает вывод до 1280
Комментарии:
1. Есть ли у вас какие-либо обновления по этому поводу? У меня такая же проблема с последним обновлением, и расширение широковещательной передачи постоянно превышает лимит памяти.
Ответ №1:
В итоге я использовал OTVideoFrame для отправки изображения и реализации логики повторной отправки последнего кадра с использованием DispatchWorkItem
// We just received a frame, cancel any retransmit
self.resetRetransmitTimer()
let resized = cgImage
self.checkPixelBufferSize(forImage: resized)
let ref = self.fillPixelBuffer(withCGImage: resized)
CVPixelBufferLockBaseAddress(ref, CVPixelBufferLockFlags.readOnly)
self.videoFrame?.format?.pixelFormat = .ARGB
self.videoFrame?.timestamp = timestamp
self.videoFrame?.format?.estimatedCaptureDelay = 10
self.videoFrame?.format?.estimatedFramesPerSecond = self.config.desiredFrameRate
self.videoFrame?.orientation = .up
self.videoFrame?.clearPlanes()
self.videoFrame?.planes?.addPointer(CVPixelBufferGetBaseAddress(ref))
self.videoCaptureConsumer?.consumeFrame(self.videoFrame!)
self.lastReplayKitImage = cgImage
self.lastReplayKitImageTimeStamp = timestamp
CVPixelBufferUnlockBaseAddress(ref, CVPixelBufferLockFlags.readOnly)
self.scheduleRetransmitTimer()
Комментарии:
1. Можете ли вы поделиться подробным кодом? Как работают таймеры передачи?