Как открыть данные вместо стандартного URL в AVPlayer

Как я могу открыть видео файл данных вместо стандартного URL в AVPlayer?

let videoURL = URL(string: "https://example")

но вместо URL у меня есть только

var dataTs : Data = Data()

и я должен положить его в AVPlayerController

let player = AVPlayer(url: videoURL!)
playerViewController.player = player

1 ответ

Решение

Вам не нужно записывать данные во временный файл. Вместо этого вы можете использовать именованный канал. Это очень похоже на запись во временный файл, за исключением того, что оно не требует места для хранения и работает быстрее.

Если вы не знакомы с именованными каналами, они не такие сложные. Они выглядят и действуют как файлы, но вместо данных из файла, поступающих с носителя, они поступают из другого процесса или потока. Они созданы с помощью простого вызова функции, который выглядит следующим образом в Swift:

mkfifo("foo", 0o666) // Note: 0o666 is Swift notation for octal values

Вот как это будет работать в вашем случае: вы создаете именованный канал, как показано выше. Затем вы настраиваете очередь отправки, чтобы открыть файл и записать в него свои данные. Операция записи будет блокироваться до тех пор, пока что-то еще не появится, и откроет тот же файл для чтения из него. Когда это произойдет, ваша операция записи будет разблокирована и начнется отправка данных непосредственно во входящий запрос на чтение.

После того, как ваша отправка настроена и ожидает, просто продолжайте, как обычно, и передайте URL который указывает на вашу именованную трубу AVPlayer, AVPlayer будет думать, что он читает из файла, но он действительно читает данные из вашего dataTs объект.

Вы можете получить базовую рабочую версию с одной вспомогательной функцией, которая по существу преобразует Data возражать в URL для одноразового использования. Вот образец Swift:

func setupNamedPipe(withData data: Data) -> URL?
{
    // Build a URL for a named pipe in the documents directory
    let fifoBaseName = "avpipe"
    let fifoUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).last!.appendingPathComponent(fifoBaseName)

    // Ensure there aren't any remnants of the fifo from a previous run
    unlink(fifoUrl.path)

    // Create the FIFO pipe
    if mkfifo(fifoUrl.path, 0o666) != 0
    {
        print("Failed to create named pipe")
        return nil
    }

    // Run the code to manage the pipe on a dispatch queue
    DispatchQueue.global().async
    {
        print("Waiting for somebody to read...")
        let fd = open(fifoUrl.path, O_WRONLY)
        if fd != -1
        {
            print("Somebody is trying to read, writing data on the pipe")
            data.withUnsafeBytes { (bytes: UnsafePointer<UInt8>) -> Void in
                let num = write(fd, bytes, data.count)
                if num != data.count
                {
                    print("Write error")
                }
            }

            print("Closing the write side of the pipe")
            close(fd)
        }
        else
        {
            print("Failed to open named pipe for write")
        }

        print("Cleaning up the named pipe")
        unlink(fifoUrl.path)
    }

    return fifoUrl
}

Вот как вы бы это использовали:

var dataTs : Data = Data() // ...your data...

if let videoURL = setupNamedPipe(withData: dataTs)
{
    let player = AVPlayer(url: videoURL)
    playerViewController.player = player

    // ...do stuff...
}
Другие вопросы по тегам