Terjemahan disediakan oleh mesin penerjemah. Jika konten terjemahan yang diberikan bertentangan dengan versi bahasa Inggris aslinya, utamakan versi bahasa Inggris.
Kasus Penggunaan Lanjutan untuk IVS iOS Broadcast SDK | Streaming Low-Latency
Di sini kami menyajikan beberapa kasus penggunaan lanjutan. Mulailah dengan pengaturan dasar di atas dan lanjutkan di sini.
Membuat Konfigurasi Siaran
Di sini kita membuat konfigurasi khusus dengan dua slot mixer yang memungkinkan kita untuk mengikat dua sumber video ke mixer. Satu (custom) adalah layar penuh dan diletakkan di belakang yang lain (camera), yang lebih kecil dan di sudut kanan bawah. Perhatikan bahwa untuk custom slot kami tidak mengatur posisi, ukuran, atau mode aspek. Karena kami tidak mengatur parameter ini, slot menggunakan pengaturan video untuk ukuran dan posisi.
let config = IVSBroadcastConfiguration() try config.audio.setBitrate(128_000) try config.video.setMaxBitrate(3_500_000) try config.video.setMinBitrate(500_000) try config.video.setInitialBitrate(1_500_000) try config.video.setSize(CGSize(width: 1280, height: 720)) config.video.defaultAspectMode = .fit config.mixer.slots = [ try { let slot = IVSMixerSlotConfiguration() // Do not automatically bind to a source slot.preferredAudioInput = .unknown // Bind to user image if unbound slot.preferredVideoInput = .userImage try slot.setName("custom") return slot }(), try { let slot = IVSMixerSlotConfiguration() slot.zIndex = 1 slot.aspect = .fill slot.size = CGSize(width: 300, height: 300) slot.position = CGPoint(x: config.video.size.width - 400, y: config.video.size.height - 400) try slot.setName("camera") return slot }() ]
Buat Sesi Siaran (Versi Lanjutan)
Buat IVSBroadcastSession seperti yang Anda lakukan dalam contoh dasar, tetapi berikan konfigurasi khusus Anda di sini. Juga sediakan nil untuk array perangkat, karena kami akan menambahkannya secara manual.
let broadcastSession = try IVSBroadcastSession( configuration: config, // The configuration we created above descriptors: nil, // We’ll manually attach devices after delegate: self)
Iterasi dan Pasang Perangkat Kamera
Di sini kami mengulangi melalui perangkat input yang telah dideteksi SDK. SDK hanya akan mengembalikan perangkat bawaan di iOS. Bahkan jika perangkat audio Bluetooth terhubung, mereka akan muncul sebagai perangkat bawaan. Untuk informasi selengkapnya, lihat Solusi Masalah yang & Diketahui di IVS iOS Broadcast SDK | Streaming Low-Latency.
Setelah kami menemukan perangkat yang ingin kami gunakan, kami memanggil attachDevice untuk melampirkannya:
let frontCamera = IVSBroadcastSession.listAvailableDevices() .filter { $0.type == .camera && $0.position == .front } .first if let camera = frontCamera { broadcastSession.attach(camera, toSlotWithName: "camera") { device, error in // check error } }
Tukar Kamera
// This assumes you’ve kept a reference called `currentCamera` that points to the current camera. let wants: IVSDevicePosition = (currentCamera.descriptor().position == .front) ? .back : .front // Remove the current preview view since the device will be changing. previewView.subviews.forEach { $0.removeFromSuperview() } let foundCamera = IVSBroadcastSession .listAvailableDevices() .first { $0.type == .camera && $0.position == wants } guard let newCamera = foundCamera else { return } broadcastSession.exchangeOldDevice(currentCamera, withNewDevice: newCamera) { newDevice, _ in currentCamera = newDevice if let camera = newDevice as? IVSImageDevice { do { previewView.addSubview(try finalCamera.previewView()) } catch { print("Error creating preview view \(error)") } } }
Buat Sumber Input Kustom
Untuk memasukkan data suara atau gambar yang dihasilkan aplikasi Anda, gunakan, createImageSource ataucreateAudioSource. Kedua metode ini membuat perangkat virtual (IVSCustomImageSourcedanIVSCustomAudioSource) yang dapat diikat ke mixer seperti perangkat lainnya.
Perangkat yang dikembalikan oleh kedua metode ini menerima a CMSampleBuffer melalui fung onSampleBuffer sinya:
-
Untuk sumber video, format piksel harus
kCVPixelFormatType_32BGRA,420YpCbCr8BiPlanarFullRange, atau420YpCbCr8BiPlanarVideoRange. -
Untuk sumber audio, buffer harus berisi data PCM Linear.
Anda tidak dapat menggunakan input AVCaptureSession dengan kamera untuk memberi makan sumber gambar khusus sambil juga menggunakan perangkat kamera yang disediakan oleh SDK siaran. Jika Anda ingin menggunakan beberapa kamera secara bersamaan, gunakan AVCaptureMultiCamSession dan berikan dua sumber gambar khusus.
Sumber gambar khusus terutama harus digunakan dengan konten statis seperti gambar, atau dengan konten video:
let customImageSource = broadcastSession.createImageSource(withName: "video") try broadcastSession.attach(customImageSource, toSlotWithName: "custom")
Memantau Konektivitas Jaringan
Adalah umum bagi perangkat seluler untuk sementara kehilangan dan mendapatkan kembali konektivitas jaringan saat bepergian. Karena itu, penting untuk memantau konektivitas jaringan aplikasi Anda dan merespons dengan tepat ketika ada perubahan.
Ketika koneksi penyiar terputus, status SDK siaran akan berubah menjadi error dan kemudiandisconnected. Anda akan diberitahu tentang perubahan ini melaluiIVSBroadcastSessionDelegate. Ketika Anda menerima perubahan status ini:
-
Pantau status konektivitas aplikasi siaran Anda dan panggil
startdengan titik akhir dan kunci streaming Anda, setelah koneksi Anda dipulihkan. -
Penting: Pantau panggilan balik delegasi negara dan pastikan status berubah menjadi
connectedsetelah meneleponstartlagi.
Lepaskan Perangkat
Jika Anda ingin melepaskan dan tidak mengganti perangkat, lepaskan dengan atau: IVSDevice IVSDeviceDescriptor
broadcastSession.detachDevice(currentCamera)
ReplayKit Integrasi
Untuk melakukan streaming layar perangkat dan audio sistem di iOS, Anda harus berintegrasi dengan ReplayKitIVSReplayKitBroadcastSession. Di RPBroadcastSampleHandler subkelas Anda, buat instanceIVSReplayKitBroadcastSession, lalu:
-
Mulai sesi di
broadcastStarted -
Hentikan sesi di
broadcastFinished
Objek sesi akan memiliki tiga sumber khusus untuk gambar layar, audio aplikasi, dan audio mikrofon. Berikan yang CMSampleBuffers disediakan processSampleBuffer ke sumber khusus tersebut.
Untuk menangani orientasi perangkat, Anda perlu mengekstrak ReplayKit-specific metadata dari buffer sampel. Gunakan kode berikut:
let imageSource = session.systemImageSource; if let orientationAttachment = CMGetAttachment(sampleBuffer, key: RPVideoSampleOrientationKey as CFString, attachmentModeOut: nil) as? NSNumber, let orientation = CGImagePropertyOrientation(rawValue: orientationAttachment.uint32Value) { switch orientation { case .up, .upMirrored: imageSource.setHandsetRotation(0) case .down, .downMirrored: imageSource.setHandsetRotation(Float.pi) case .right, .rightMirrored: imageSource.setHandsetRotation(-(Float.pi / 2)) case .left, .leftMirrored: imageSource.setHandsetRotation((Float.pi / 2)) } }
Dimungkinkan untuk mengintegrasikan ReplayKit menggunakan al IVSBroadcastSession ih-alihIVSReplayKitBroadcastSession. Namun, ReplayKit-specific varian ini memiliki beberapa modifikasi untuk mengurangi jejak memori internal, agar tetap berada dalam batas memori Apple untuk ekstensi siaran.
Dapatkan Pengaturan Siaran yang Direkomendasikan
Untuk mengevaluasi koneksi pengguna Anda sebelum memulai siaran, gunakan IVSBroadcastSession.recommendedVideoSettings untuk menjalankan tes singkat. Saat pengujian berjalan, Anda akan menerima beberapa rekomendasi, dipesan dari yang paling banyak hingga yang paling tidak direkomendasikan. Dalam versi SDK ini, tidak mungkin untuk mengkonfigurasi ulang saat iniIVSBroadcastSession, jadi Anda harus mengalokasinya dan kemudian membuat yang baru dengan pengaturan yang disarankan. Anda akan terus menerima IVSBroadcastSessionTestResults sampai result.status ada Success atauError. Anda dapat memeriksa kemajuan denganresult.progress.
Amazon IVS mendukung bitrate maksimum 8,5 Mbps (untuk saluran yang type STANDARD atauADVANCED), sehingga yang maximumBitrate dikembalikan oleh metode ini tidak pernah melebihi 8,5 Mbps. Untuk memperhitungkan fluktuasi kecil dalam kinerja jaringan, yang disarankan initialBitrate dikembalikan oleh metode ini sedikit kurang dari bitrate sebenarnya yang diukur dalam pengujian. (Menggunakan 100% dari bandwidth yang tersedia biasanya tidak disarankan.)
func runBroadcastTest() { self.test = session.recommendedVideoSettings(with: IVS_RTMPS_URL, streamKey: IVS_STREAMKEY) { [weak self] result in if result.status == .success { self?.recommendation = result.recommendations[0]; } } }
Menggunakan Auto-Reconnect
IVS mendukung koneksi ulang otomatis ke siaran jika siaran berhenti secara tak terduga tanpa memanggil stop API; misalnya, kehilangan sementara dalam konektivitas jaringan. Untuk mengaktifkan koneksi ulang otomatis, setel enabled properti ke. IVSBroadcastConfiguration.autoReconnect true
Ketika sesuatu menyebabkan aliran berhenti secara tak terduga, SDK mencoba lagi hingga 5 kali, mengikuti strategi mundur linier. Ini memberi tahu aplikasi Anda tentang status coba lagi melalui fungsi. IVSBroadcastSessionDelegate.didChangeRetryState
Di balik layar, auto-reconnect menggunakan fungsionalitas pengambilalihan aliran IVS dengan menambahkan nomor prioritas, dimulai dengan 1, ke akhir kunci aliran yang disediakan. Untuk durasi IVSBroadcastSession instance, angka itu bertambah 1 setiap kali koneksi ulang dicoba. Ini berarti jika koneksi perangkat terputus 4 kali selama siaran, dan setiap kehilangan memerlukan 1-4 upaya coba lagi, prioritas streaming terakhir bisa berada di antara 5 dan 17. Karena itu, kami sarankan Anda tidak menggunakan pengambilalihan aliran IVS dari perangkat lain saat koneksi ulang otomatis diaktifkan di SDK untuk saluran yang sama. Tidak ada jaminan prioritas apa yang digunakan SDK pada saat itu, dan SDK akan mencoba menyambung kembali dengan prioritas yang lebih tinggi jika perangkat lain mengambil alih.
Gunakan Video Latar Belakang
Anda dapat melanjutkan non-si RelayKit aran, bahkan dengan aplikasi Anda di latar belakang.
Untuk menghemat daya dan menjaga aplikasi latar depan responsif, iOS hanya memberikan satu aplikasi pada satu waktu akses ke GPU. Amazon IVS Broadcast SDK menggunakan GPU pada beberapa tahap pipeline video, termasuk menyusun beberapa sumber input, menskalakan gambar, dan pengkodean gambar. Sementara aplikasi penyiaran berada di latar belakang, tidak ada jaminan bahwa SDK dapat melakukan tindakan ini.
Untuk mengatasi hal ini, gunakan createAppBackgroundImageSource metode ini. Ini memungkinkan SDK untuk terus menyiarkan video dan audio saat berada di latar belakang. Ini mengembalikan sebuahIVSBackgroundImageSource, yang merupakan normal IVSCustomImageSource dengan finish fungsi tambahan. Setiap CMSampleBuffer yang disediakan untuk sumber gambar latar belakang dikodekan pada kecepatan bingkai yang disediakan oleh aslinyaIVSVideoConfiguration. Stempel waktu pada diabaikanCMSampleBuffer.
SDK kemudian menskalakan dan mengkodekan gambar-gambar tersebut dan menyimpannya dalam cache, secara otomatis mengulang umpan itu ketika aplikasi Anda masuk ke latar belakang. Saat aplikasi Anda kembali ke latar depan, perangkat gambar terlampir menjadi aktif kembali dan aliran yang telah dikodekan berhenti melakukan perulangan.
Untuk membatalkan proses ini, gunakanremoveImageSourceOnAppBackgrounded. Anda tidak perlu memanggil ini kecuali Anda ingin secara eksplisit mengembalikan perilaku latar belakang SDK; jika tidak, itu dibersihkan secara otomatis pada deallokasi. IVSBroadcastSession
Catatan: Kami sangat menyarankan Anda memanggil metode ini sebagai bagian dari konfigurasi sesi siaran, sebelum sesi ditayangkan. Metode ini mahal (mengkodekan video), sehingga kinerja siaran langsung saat metode ini berjalan mungkin terdegradasi.
Contoh: Menghasilkan Gambar Statis untuk Video Latar Belakang
Menyediakan satu gambar ke sumber latar belakang menghasilkan GOP penuh dari gambar statis itu.
Berikut adalah contoh menggunakan CIImage:
// Create the background image source guard let source = session.createAppBackgroundImageSource(withAttemptTrim: true, onComplete: { error in print("Background Video Generation Done - Error: \(error.debugDescription)") }) else { return } // Create a CIImage of the color red. let ciImage = CIImage(color: .red) // Convert the CIImage to a CVPixelBuffer let attrs = [ kCVPixelBufferCGImageCompatibilityKey: kCFBooleanTrue, kCVPixelBufferCGBitmapContextCompatibilityKey: kCFBooleanTrue, kCVPixelBufferMetalCompatibilityKey: kCFBooleanTrue, ] as CFDictionary var pixelBuffer: CVPixelBuffer! CVPixelBufferCreate(kCFAllocatorDefault, videoConfig.width, videoConfig.height, kCVPixelFormatType_420YpCbCr8BiPlanarFullRange, attrs, &pixelBuffer) let context = CIContext() context.render(ciImage, to: pixelBuffer) // Submit to CVPixelBuffer and finish the source source.add(pixelBuffer) source.finish()
Sebagai alternatif, alih-alih membuat CIImage dengan warna solid, Anda dapat menggunakan gambar yang dibundel. Satu-satunya kode yang ditampilkan di sini adalah cara mengonversi UIImage ke CIImage untuk digunakan dengan sampel sebelumnya:
// Load the pre-bundled image and get it’s CGImage guard let cgImage = UIImage(named: "image")?.cgImage else { return } // Create a CIImage from the CGImage let ciImage = CIImage(cgImage: cgImage)
Contoh: Video dengan AVAssetImageGenerator
Anda dapat menggunakan an AVAssetImageGenerator untuk menghasilkan CMSampleBuffers dari AVAsset (meskipun bukan aliran HLSAVAsset):
// Create the background image source guard let source = session.createAppBackgroundImageSource(withAttemptTrim: true, onComplete: { error in print("Background Video Generation Done - Error: \(error.debugDescription)") }) else { return } // Find the URL for the pre-bundled MP4 file guard let url = Bundle.main.url(forResource: "sample-clip", withExtension: "mp4") else { return } // Create an image generator from an asset created from the URL. let generator = AVAssetImageGenerator(asset: AVAsset(url: url)) // It is important to specify a very small time tolerance. generator.requestedTimeToleranceAfter = .zero generator.requestedTimeToleranceBefore = .zero // At 30 fps, this will generate 4 seconds worth of samples. let times: [NSValue] = (0...120).map { NSValue(time: CMTime(value: $0, timescale: CMTimeScale(config.video.targetFramerate))) } var completed = 0 let context = CIContext(options: [.workingColorSpace: NSNull()]) // Create a pixel buffer pool to efficiently feed the source let attrs = [ kCVPixelBufferPixelFormatTypeKey: kCVPixelFormatType_420YpCbCr8BiPlanarFullRange, kCVPixelBufferCGImageCompatibilityKey: kCFBooleanTrue, kCVPixelBufferCGBitmapContextCompatibilityKey: kCFBooleanTrue, kCVPixelBufferMetalCompatibilityKey: kCFBooleanTrue, kCVPixelBufferWidthKey: videoConfig.width, kCVPixelBufferHeightKey: videoConfig.height, ] as CFDictionary var pool: CVPixelBufferPool! CVPixelBufferPoolCreate(kCFAllocatorDefault, nil, attrs, &pool) generator.generateCGImagesAsynchronously(forTimes: times) { requestTime, image, actualTime, result, error in if let image = image { // convert to CIImage then CVpixelBuffer let ciImage = CIImage(cgImage: image) var pixelBuffer: CVPixelBuffer! CVPixelBufferPoolCreatePixelBuffer(kCFAllocatorDefault, pool, &pixelBuffer) context.render(ciImage, to: pixelBuffer) source.add(pixelBuffer) } completed += 1 if completed == times.count { // Mark the source finished when all images have been processed source.finish() } }
Dimungkinkan untuk menghasilkan CVPixelBuffers menggunakan AVPlayer danAVPlayerItemVideoOutput. Namun, itu membutuhkan penggunaan a CADisplayLink dan mengeksekusi lebih dekat ke real-time, sementara AVAssetImageGenerator dapat memproses frame jauh lebih cepat.
Batasan
Aplikasi Anda memerlukan hak audio latar belakang
createAppBackgroundImageSourcedapat dipanggil hanya saat aplikasi Anda berada di latar depan, karena perlu akses ke GPU untuk menyelesaikannya.
createAppBackgroundImageSourceselalu mengkodekan ke GOP penuh. Misalnya, jika Anda memiliki interval keyframe 2 detik (default) dan berjalan pada 30 fps, itu mengkodekan kelipatan 60 frame.
-
Jika kurang dari 60 frame disediakan, frame terakhir diulang hingga 60 frame tercapai, terlepas dari nilai opsi trim.
-
Jika lebih dari 60 frame disediakan dan opsi trim adalah
true, N frame terakhir dijatuhkan, di mana N adalah sisa dari jumlah total frame yang dikirimkan dibagi dengan 60. -
Jika lebih dari 60 frame disediakan dan opsi trim adalah
false, frame terakhir diulang sampai kelipatan 60 frame berikutnya tercapai.