Tung Nguyen
Tung Nguyen

Reputation: 1

How to play H.265 websocket video with MobileVLCKit?

I want to play a HEVC (h.265) streaming video via WebSocket.

I created a custom InputStream to construct the VLCMedia object but the player does not work, only got a black view. Is there a different way to initialize the media object or stream the video properly using MobileVLCKit? I'm open to any alternative solutions for streaming the video.

import UIKit
import Starscream
import MobileVLCKit
import Foundation

class WebSocketInputStream: InputStream {
    
    private var buffer: Data = Data()  // Buffer to hold incoming WebSocket data
    private let bufferLock = NSLock()
    private var streamOpen = false
    
    // MARK: - Append WebSocket data to the buffer
    func append(_ data: Data) {
        bufferLock.lock()
        buffer.append(data)
        bufferLock.unlock()
    }
    
    // MARK: - InputStream methods
    override var hasBytesAvailable: Bool {
        // There are bytes available if the buffer is not empty
        bufferLock.lock()
        let available = !buffer.isEmpty
        bufferLock.unlock()
        return available
    }
    
    // Reads up to the specified max length into the provided buffer
    override func read(_ buffer: UnsafeMutablePointer<UInt8>, maxLength len: Int) -> Int {
        bufferLock.lock()
        let readLength = min(len, self.buffer.count)
        
        if readLength > 0 {
            self.buffer.copyBytes(to: buffer, count: readLength)
            self.buffer.removeFirst(readLength)
        }
        
        bufferLock.unlock()
        return readLength
    }
    
    // Open the stream
    override func open() {
        streamOpen = true
    }
    
    // Close the stream
    override func close() {
        streamOpen = false
        bufferLock.lock()
        buffer.removeAll()
        bufferLock.unlock()
    }
    
    // MARK: - Implement stream properties required by InputStream
    override var streamStatus: Stream.Status {
        return streamOpen ? .open : .closed
    }
    
    override var streamError: Error? {
        return nil  // No specific errors for this simple implementation
    }
    
    // You can override other methods as needed depending on your requirements.
}


class VideoViewController: UIViewController {
    var socket: WebSocket!
    var mediaPlayer: VLCMediaPlayer!
    var webSocketStream: WebSocketInputStream!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Setup the WebSocket connection
        setupWebSocket()
        
        // Initialize the VLC media player
        mediaPlayer = VLCMediaPlayer()
        
        let logger = VLCConsoleLogger()
        logger.level = .debug
        logger.formatter.contextFlags = .levelContextModule
        mediaPlayer.libraryInstance.loggers = [logger]

        // Set up media player view
        let vlcView = UIView(frame: self.view.bounds)
        self.view.addSubview(vlcView)
        mediaPlayer?.drawable = vlcView
    }
    
    func setupWebSocket() {
        // Configure WebSocket
        let request = URLRequest(url: URL(string: "wss://rec03ihanoi.vtscloud.vn:443/evup/1727065882jPWLbJ/d12aa2a31aa4xyzummuv07lWh")!)
        socket = WebSocket(request: request)
        socket.onEvent = { [weak self] event in
            switch event {
            case .connected:
                print("WebSocket connected")
                self?.socket.write(string: "")
                self?.startStreaming()
            case .binary(let data):
                print("WebSocket data")
                self?.handleWebSocketData(data: data)
            default:
                ()
            }
            
        }
        socket.connect()
    }
    
    func handleWebSocketData(data: Data) {
        // Append WebSocket data to the input stream
        if webSocketStream != nil {
            webSocketStream.append(data)
        }
    }
    
    func startStreaming() {
        // Create and open a WebSocketInputStream
        webSocketStream = WebSocketInputStream()
        webSocketStream.open()
        
        // Create a VLCMedia object with the custom input stream
        let vlcMedia = VLCMedia(stream: webSocketStream)
        vlcMedia.addOption("-vv")
        vlcMedia.addOption("--codec=h265")
        mediaPlayer.media = vlcMedia
        
        // Start the media player
        mediaPlayer.play()
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        socket.disconnect()  // Disconnect WebSocket when view disappears
        mediaPlayer.stop()    // Stop the media player when the view disappears
    }
}

Upvotes: 0

Views: 58

Answers (0)

Related Questions