3 votes

Attribuer AVAsset à partir de NSData

Puis-je initialiser AVAsset à partir de NSData .. Je sais que je peux initialiser AVData à partir d'une URL en utilisant une fonction comme

 [[AVURLAsset alloc] initWithURL:url options:nil];

Quelqu'un peut-il me suggérer un moyen similaire d'assigner directement AVAsset à partir de NSData ?

4voto

À ma connaissance, non. AVAsset représente des éléments de la bibliothèque multimédia (interne) d'un appareil, donc l'initialiser en utilisant vos propres données n'aurait pas beaucoup de sens. Peut-être vaut-il la peine de mentionner que cette classe n'a pas d'initialiseur public pour NSData.

Je soupçonne que vous devrez probablement redessiner la logique de votre code si vous en avez besoin.

3voto

iamacomputer Points 166

La réponse acceptée est incorrecte.

Il est possible de créer un AVAsset à partir d'un NSData via une implémentation de AVAssetResourceLoaderDelegate.

Implémentez spécifiquement :

func resourceLoader(_ resourceLoader: AVAssetResourceLoader, shouldWaitForLoadingOfRequestedResource loadingRequest: AVAssetResourceLoadingRequest) -> Bool

Il doit :

  1. remplir correctement la requête d'informations sur le contenu de loadingRequest. Astuce, utilisez loadingRequest.contentInformationRequest.contentType = AVFileType.mycontenttype.rawValue
  2. répondre avec les données correctement

Je posterai du code plus tard, mais vous pouvez rechercher des exemples sur "AVAssetResourceLoaderDelegate github"

0voto

padam thapa Points 725

Ceci est une solution alternative à la façon dont je l'ai résolue. Indirectement, j'ai initialisé en écrivant/sauvegardant d'abord NSData dans le répertoire local, puis j'ai initialisé AVAsset à partir de ce chemin de fichier.

AVAsset *asset = [AVAsset assetWithURL:[NSURL fileURLWithPath:locationUrl]];

Vous pouvez essayer d'écrire vos nsdata dans le chemin de fichier d'abord, puis initialiser à partir de ce chemin vers AVAsset.

[videoData writeToFile: locationUrl atomically:YES];

Assurez-vous simplement que l'URL de l'emplacement du fichier est correcte et testez également pour confirmer si les données sont enregistrées à ce chemin de fichier en cas d'erreur lors du chargement. Enfin, n'oubliez pas de nettoyer vos fichiers si vous n'en avez plus besoin.

0voto

thilo Points 163

Non sûr de la différence entre NSData et Data,

mais j'utilise une sous-classe AVDataAsset qui a installé un AVAssetResourceLoaderDelegate pour résoudre le problème comme suggéré par @iamacomputer comme ci-dessous:

class AVDataAsset: AVURLAsset,  AVAssetResourceLoaderDelegate {
    private let myUrl:   URL
    private var mediaData = Data()

    init(url: URL,data: Data?) {
        myUrl = url
        let retURL: URL
        if let data {
            mediaData = data
            guard var components = URLComponents(url: url, resolvingAgainstBaseURL: false) else {
                fatalError()
            }
            components.scheme = (components.scheme ?? "") + "SchemeSuffix"
            guard let newURL = components.url else {
                fatalError()
            }
            retURL = newURL
        } else {
            retURL = url
        }
        super.init(url:   retURL, options: nil)
        self.resourceLoader.setDelegate(self, queue: DispatchQueue.main)
//        print("Size: \(mediaData.count)")
    }
    func resourceLoader(_ resourceLoader: AVAssetResourceLoader, shouldWaitForLoadingOfRequestedResource loadingRequest: AVAssetResourceLoadingRequest) -> Bool {
        let request = loadingRequest
        if let ri = request.contentInformationRequest  {
            ri.isByteRangeAccessSupported = true
            ri.contentType = "video/quicktime"
            ri.contentLength = Int64(mediaData.count)
        }
        if let dataRequest = request.dataRequest {
            let downloadedData          = self.mediaData
            let downloadedDataLength    = Int64(downloadedData.count)
            let requestCurrentOffset    = dataRequest.currentOffset
            let requestRequestedOffset  = dataRequest.requestedOffset
            let requestRequestedLength  = Int64(dataRequest.requestedLength)
            let downloadedUnreadDataLength  = downloadedDataLength - requestCurrentOffset
            let requestUnreadDataLength     = requestRequestedOffset + requestRequestedLength - requestCurrentOffset
            let respondDataLength           = min(requestUnreadDataLength, downloadedUnreadDataLength)

            dataRequest.respond(with: downloadedData.subdata(in:
                                                                Range(NSMakeRange(Int(requestCurrentOffset), Int(respondDataLength)))!))
        }
        request.finishLoading()

        return true

    }
}

let url = URL(string: "file:///Users/thilo/Desktop/Input/IMG_0128%20copy.MOV")!

guard let data = try? Data(contentsOf: url)
    else { fatalError() }

let dataAsset = AVDataAsset(url: url, data: data)
Task{
    let asset = dataAsset
    if let tracks = try? await asset.load(.tracks),
       let frameRate = try? await tracks[0].load(.minFrameDuration),
       let duration = try? await asset.load(.duration) {
        print("frame: \(1/frameRate.seconds) Dura: \(duration.seconds)")
    }
}

print("Done AVDataAsset")

Évidemment, certains éléments sont codés en dur ici et doivent être modifiés mais le principe devrait être clair.

Il est également bon de noter que le schéma d'URL ne doit pas être un schéma connu pour que le délégué soit appelé (+SchemeSuffix le fait)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X