REMARQUE: - Fusionnez les vidéos côte à côte sans perdre la qualité vidéo
Je pense que c'est une question très très importante , après de nombreuses recherches et recherches sur Google, je n'ai trouvé aucun matériel utile lié à cette question.
Je travaille sur un projet dans lequel je dois FUSIONNER des vidéos côte à côte dans un seul fichier.
I avait fait Vidéos fusionnées à l'aide d'AVFoundation , mais le problème est que FIRST Video s'affiche en superposition à une SECOND vidéo (ne fusionne pas correctement comme SMULE App / Karaoke App ou Tiktok App ).
func mergeVideosFilesWithUrl(savedVideoUrl: URL, newVideoUrl: URL, audioUrl:URL) { let savePathUrl : NSURL = NSURL(fileURLWithPath: NSHomeDirectory() + "/Documents/camRecordedVideo.mp4") do { // delete old video try FileManager.default.removeItem(at: savePathUrl as URL) } catch { print(error.localizedDescription) } var mutableVideoComposition : AVMutableVideoComposition = AVMutableVideoComposition() var mixComposition : AVMutableComposition = AVMutableComposition() let aNewVideoAsset : AVAsset = AVAsset(url: newVideoUrl) let asavedVideoAsset : AVAsset = AVAsset(url: savedVideoUrl) let aNewVideoTrack : AVAssetTrack = aNewVideoAsset.tracks(withMediaType: AVMediaType.video)[0] let aSavedVideoTrack : AVAssetTrack = asavedVideoAsset.tracks(withMediaType: AVMediaType.video)[0] let mutableCompositionNewVideoTrack : AVMutableCompositionTrack = mixComposition.addMutableTrack(withMediaType: AVMediaType.video, preferredTrackID: kCMPersistentTrackID_Invalid)! do{ try mutableCompositionNewVideoTrack.insertTimeRange(CMTimeRangeMake(start: CMTime.zero, duration: aNewVideoAsset.duration), of: aNewVideoTrack, at: CMTime.zero) }catch { print("Mutable Error") } let mutableCompositionSavedVideoTrack : AVMutableCompositionTrack = mixComposition.addMutableTrack(withMediaType: AVMediaType.video, preferredTrackID: kCMPersistentTrackID_Invalid)! do{ try mutableCompositionSavedVideoTrack.insertTimeRange(CMTimeRangeMake(start: CMTime.zero, duration: asavedVideoAsset.duration), of: aSavedVideoTrack , at: CMTime.zero) }catch{ print("Mutable Error") } let mainInstruction = AVMutableVideoCompositionInstruction() mainInstruction.timeRange = CMTimeRangeMake(start: CMTime.zero, duration: CMTimeMaximum(aNewVideoAsset.duration, asavedVideoAsset.duration) ) let newVideoLayerInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: mutableCompositionNewVideoTrack) let newScale : CGAffineTransform = CGAffineTransform.init(scaleX: 0.7, y: 0.7) let newMove : CGAffineTransform = CGAffineTransform.init(translationX: 230, y: 230) newVideoLayerInstruction.setTransform(newScale.concatenating(newMove), at: CMTime.zero) let savedVideoLayerInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: mutableCompositionSavedVideoTrack) let savedScale : CGAffineTransform = CGAffineTransform.init(scaleX: 1.2, y: 1.5) let savedMove : CGAffineTransform = CGAffineTransform.init(translationX: 0, y: 0) savedVideoLayerInstruction.setTransform(savedScale.concatenating(savedMove), at: CMTime.zero) mainInstruction.layerInstructions = [newVideoLayerInstruction, savedVideoLayerInstruction] mutableVideoComposition.instructions = [mainInstruction] mutableVideoComposition.frameDuration = CMTimeMake(value: 1, timescale: 30) mutableVideoComposition.renderSize = CGSize(width: 1240 , height: self.camPreview.frame.height) finalPath = savePathUrl.absoluteString let assetExport: AVAssetExportSession = AVAssetExportSession(asset: mixComposition, presetName: AVAssetExportPresetHighestQuality)! assetExport.videoComposition = mutableVideoComposition assetExport.outputFileType = AVFileType.mov assetExport.outputURL = savePathUrl as URL assetExport.shouldOptimizeForNetworkUse = true assetExport.exportAsynchronously { () -> Void in switch assetExport.status { case AVAssetExportSession.Status.completed: print("success") case AVAssetExportSession.Status.failed: print("failed \(assetExport.error)") case AVAssetExportSession.Status.cancelled: print("cancelled \(assetExport.error)") default: print("complete") } } }
Et ce que je veux
Comme je ne sais pas quelle est la meilleure approche pour réaliser une VIDEO SIDE BY SIDE / DUET VIDEO ... Pour l'instant, j'ai utilisé AVFoundation. Je n'ai utilisé aucun framework tiers ni aucun POD.
Je voudrais demander, quelle est la MEILLEURE approche pour mettre en œuvre cela? Les vidéos doivent fusionner du côté du serveur ou d'une application? Quelle approche dois-je utiliser également?
Toute aide serait très appréciée. Merci
3 Réponses :
Pour y parvenir, je créerais un nouvel objet AVMutableComposition
contenant 2 pistes, et définirais une transformation sur chacune pour les placer côte à côte:
let exporter = AVAssetExportSession(asset:<yourAsset>, presetName:<yourPresetName>) exporter.exportAsynchronously(completionHandler: <yourCompletionHandler>)
Ensuite. enregistrez-le en utilisant:
let composition = AVMutableComposition(urlAssetInitializationOptions: <your options>) let videoTrackA = composition.addMutableTrack(withMediaType:.video, preferredTrackID:kCMPersistentTrackID_Invalid); let videoTrackB = composition.addMutableTrack(withMediaType:.video, preferredTrackID:kCMPersistentTrackID_Invalid); videoTrackA.preferredTransform = CGAffineTransform(translationX: <yourX_for_A>, y:0.0) videoTrackB.preferredTransform = CGAffineTransform(translationX: <yourX_for_B>, y:0.0)
(code Swift non testé).
Salut monsieur, pouvez-vous m'expliquer un peu plus? S'il vous plaît
Pouvez-vous s'il vous plaît revoir mon code?
Vous devriez maintenant travailler sur un échantillon minimal: ajoutez simplement vos 2 pistes vidéo à votre composition (pas de calque 'instructions', pas d'audio). Ensuite, assurez-vous que les pistes sont ajoutées à votre composition, exportez-la dans un fichier et ouvrez le fichier exporté dans Quicktime Player 7. Ensuite, ouvrez la fenêtre Movie Properties
(raccourci ⌘ + J) et vérifiez le propriétés de vos 2 pistes vidéo. Ajustez si nécessaire.
Pour la 1ère vidéo mutableCompositionNewVideoTrack.preferredTransform = CGAffineTransform.init (translationX: 0.0, y: 0.0)
Pour la 2ème vidéo mutableCompositionSavedVideoTrack.preferredTransform = CGAffineTransform.init (translationX: self.camPreview.frame.width / 2, y: 0.0)
En utilisant Transform ci-dessus, vous ne recevez toujours qu'une seule vidéo .. Y a-t-il une erreur appropriée?
Dans le code ci-dessus, la mise à l'échelle est codée en dur, cela ne fonctionnera correctement que dans un scénario spécifique. Vous devez agrandir ou réduire les deux vidéos en général.
en fait, AVAssetExportSession
est pour des besoins simples, et c'est trop simple pour votre situation.
Vous devez utiliser AVAssetWriter .
Vous ajoutez AVAssetWriterInput à votre AVAssetWriter
. < / p>
Vous pouvez configurer le trasnform de AVAssetWriterInput
en utilisant sa propriété transform
.
Ensuite, vous alimentez votre AVAssetWriterInput
avec CMSampleBuffer (chaque tampon d'images) en utilisant des appels append
.
Consultez la documentation Apple complète pour un exemple détaillé: https://developer.apple.com/library/archive/documentation/AudioVideo/Conceptual/AVFoundationPG/Articles/05_Export.html#//apple_ref/doc/uid / TP40010188-CH9-SW2
Cela dépend de la largeur de la taille de l'image vidéo (taille du rendu), si la largeur de rendu de l'image est de 800. vous devez traduire la seconde vidéo fusionnée en 400, (moitié moitié). Et vous devez de la même manière réduire ou augmenter. comme indiqué dans l'exemple d'extrait de code ci-dessous.
var renderSize = CGSize(width: 800, height: 534) // 534 let assetInfo = AVMutableComposition.orientationFromTransform(firstTrack.preferredTransform) renderSize = assetInfo.isPortrait ? CGSize(width: renderSize.height, height: renderSize.width) : CGSize(width: renderSize.width, height: renderSize.height) let scaleRatioX = (renderSize.width / 2) / firstTrack.naturalSize.width let scaleRatioY = (renderSize.height) / firstTrack.naturalSize.height let scaleRatio2X = (renderSize.width / 2) / secondTrack.naturalSize.width let scaleRatio2Y = renderSize.height / secondTrack.naturalSize.height print("Scale Video 1 : \(scaleRatioX), \(scaleRatioY)") // print("Scale Video 1 : \(scaleRatioY), \(scaleRatioX)") print("Scale Video 2 : \(scaleRatio2X), \(scaleRatio2Y)") // let scale = CGAffineTransform(scaleX: scaleRatioY, y: scaleRatioX) // 1, 1 let scale = CGAffineTransform(scaleX: scaleRatioX, y: scaleRatioY) let move = CGAffineTransform(translationX: 0, y: 0) firstlayerInstruction.setTransform(scale.concatenating(move), at: .zero) let secondlayerInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: secondTrack) let secondScale = CGAffineTransform(scaleX: scaleRatio2X, y: scaleRatio2Y) // 0.13, 0.13 let secondMove = CGAffineTransform(translationX: 400, y: 0) // 160, 0 secondlayerInstruction.setTransform(secondScale.concatenating(secondMove), at: .zero)
Ceci est un tout nouveau projet de plateforme de chant qui commence - LiveJam. github.com/richardaum/livejam Jetez un œil et pensez à nous soutenir - nous recherchons des contributeurs experts et vous pourriez être l'un de nous.