Уявіть: користувач запускає стрім, але за хвилину глядачі скаржаться на затримки та артефакти. Типова ситуація: мобільний застосунок використовує програмне кодування, а мережа не справляється з піковим бітрейтом. У результаті — втрата аудиторії та негативні відгуки. Перегрів пристрою та швидкий розряд батареї — ще одна проблема програмного кодування. Ми знаємо, як цього уникнути. Наша команда реалізувала понад 20 проєктів live streaming для iOS та Android, гарантуючи стабільність навіть при нестабільному з'єднанні. Економія ресурсів: апаратне кодування знижує енергоспоживання на 90% порівняно з програмним. За кожним стрімом стоїть складний конвеєр: захоплення з камери, апаратне кодування H.264/H.265, упаковка в контейнер, відправка на медіасервер та доставка до CDN. Кожен етап має своє API та свої підводні камені. Розберемо їх детально.
Захоплення відео та аудіо
AVCaptureSession — точка входу на iOS. Налаштовуємо пресет якості (sessionPreset = .hd1280x720), додаємо AVCaptureDeviceInput для камери та мікрофона, додаємо AVCaptureVideoDataOutput і AVCaptureAudioDataOutput з делегатами. captureOutput(_:didOutput:from:) віддає CMSampleBuffer — сирі кадри з камери в реальному часі.
Орієнтація: AVCaptureConnection.videoOrientation потрібно оновлювати при повороті пристрою. Якщо цього не робити, глядачі бачать відео боком при початку трансляції в портреті.
На Android використовуємо Camera2 API або CameraX (рекомендується). CameraX.bindToLifecycle() з Preview + VideoCapture use case. VideoCapture.output.prepareRecording() — нативний запис. Для стрімінгу потрібен сирий потік: ImageAnalysis use case з setOutputImageFormat(OUTPUT_IMAGE_FORMAT_YUV_420_888), кадри обробляємо вручну через MediaCodec.
| Платформа | API захоплення | Потік кадрів |
|---|---|---|
| iOS | AVCaptureSession | CMSampleBuffer |
| Android | CameraX/Camera2 | YUV_420_888 (Image) |
Чому апаратне кодування?
Програмний FFmpeg на телефоні — це перегрів та розряджена батарея за 20 хвилин. Ми використовуємо тільки апаратні кодувальники: VideoToolbox на iOS та MediaCodec на Android. Це в 10 разів енергоефективніше та дає стабільні 30 fps при 720p.
На iOS: VideoToolbox — VTCompressionSession. Створюємо сесію з kVTVideoEncoderSpecification_RequireHardwareAcceleratedVideoEncoder: kCFBooleanTrue. Callback outputCallback отримує CMSampleBuffer із закодованим H.264/H.265.
Важливі параметри:
-
kVTCompressionPropertyKey_RealTime: kCFBooleanTrue— режим реального часу -
kVTCompressionPropertyKey_ProfileLevel: kVTProfileLevel_H264_High_AutoLevel -
kVTCompressionPropertyKey_AverageBitRate: 2_000_000(2 Mbps для 720p) -
kVTCompressionPropertyKey_MaxKeyFrameInterval: 60(keyframe кожні 2 сек при 30 fps)
На Android: MediaCodec. MediaFormat.createVideoFormat("video/avc", width, height). configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE). В dequeueOutputBuffer отримуємо закодовані NAL units.
Для аудіо: AudioRecord → MediaCodec з audio/mp4a-latm (AAC-LC). Sample rate 44100 Гц, бітрейт 128 kbps.
Як забезпечити стабільність трансляції?
Адаптивний бітрейт — ключовий механізм. Моніторимо швидкість відправлення: RTMPStream.info.byteCount в HaishinKit, NetworkInfo callback в rtmp-rtsp-stream-client-java. Якщо пропускна здатність падає, послідовно знижуємо бітрейт, framerate та роздільну здатність. Оптимальний інтервал перевірки — 5-10 секунд, щоб уникнути різких стрибків якості. Такий підхід знижує кількість розривів на 70%.
HaishinKit — популярна бібліотека для iOS, що забезпечує RTMP та SRT трансляції. Для Android аналогічно застосовується rtmp-rtsp-stream-client-java.
Упаковка в RTMP або SRT
З CMSampleBuffer/MediaCodec output отримуємо NAL units H.264 та AAC frames. Їх потрібно упакувати в транспортний протокол. Ми використовуємо SRT через його стійкість до мережевих проблем, або RTMP для широкої сумісності з CDN.
Готові бібліотеки:
- iOS: HaishinKit (Swift) — RTMP, SRT, HLS. Нативний Swift без залежності FFmpeg.
RTMPStream,SRTStream. - Android:
rtmp-rtsp-stream-client-java(Pedro Vicente) — RTMP та RTSP push.RtmpCamera2з CameraX.SRTStreamдля SRT. - Flutter:
rtmp_streaming(обгортка над нативними бібліотеками) або нативний platform channel. - Кросплатформа з FFmpeg:
ffmpeg-kit-ios/ffmpeg-kit-android—FFmpegKit.executeAsync("-f avfoundation -i 0:0 -c:v libx264 -preset ultrafast -f flv rtmp://..."). Працює, але навантажує CPU більше апаратного кодувальника.
Порівняння RTMP і SRT
SRT кращий за RTMP в 2-3 рази за затримкою та стійкістю до втрат.
| Характеристика | RTMP | SRT |
|---|---|---|
| Затримка | 2-5 сек | 0.5-2 сек |
| Стійкість до втрат | Низька | Висока (FEC/ARQ) |
| Підтримка CDN | Широка | Зростає |
| Застосування | Традиційні стріми | Слабкі мережі, вебінари |
Для мобільного стрімінгу рекомендуємо SRT через його стійкість до мережевих проблем.
Попередній перегляд та UI
Прев'ю з камери — AVCaptureVideoPreviewLayer (iOS) / PreviewView CameraX (Android). Поверх накладаємо оверлей: індикатор «В ефірі», лічильник глядачів, бітрейт та рівень сигналу.
Перемикання фронтальна/тильна камера без переривання стріму: iOS — AVCaptureSession.beginConfiguration() → видаляємо старий input → додаємо новий → commitConfiguration(). HaishinKit підтримує це в один рядок: stream.captureSettings.isVideoMirrored.
Що входить в роботу над live streaming
- Розробка захоплення відео/аудіо з камери
- Апаратне кодування з налаштуванням параметрів
- Інтеграція обраного протоколу (RTMP/SRT/HLS)
- Адаптивний бітрейт та моніторинг мережі
- UI прев'ю та оверлей з індикаторами
- Тестування на реальних пристроях в різних мережах
- Документація з інтеграції та підтримка після запуску
Зв'яжіться з нами для обговорення вашого проєкту. Замовте розробку live streaming — отримайте консультацію інженера з досвідом. Також ви можете запросити приклади наших проєктів.
Терміни
Реалізація стрімінгу з камери (RTMP або SRT) на одну платформу з прев'ю та базовим UI — 3-5 днів. Кросплатформа з адаптивним бітрейтом, перемиканням камер та інтеграцією конкретного медіасервера — 1-2 тижні. Вартість розраховується індивідуально залежно від складності, а такий підхід окупається за рахунок стабільності та енергоефективності.







