Sto provando a combinare un singolo video con una singola immagine. Questo non sta cercando di combinare più immagini in un unico video comeCome unire * Immagine singola * con un video
Sto usando AVMutableComposition
di combinare le tracce . La mia app ha la capacità di combinare video e immagini (ma così com'è, la combinazione dei video va bene!) Tento di usare AVAssetWriter
per trasformare una singola immagine in un video (credo che questo sia il mio problema ma non sicuro al 100%). Quindi l'ho salvato nell'app (documents directory
). Da lì, accedo alla mia fusione e unisco un video e l'immagine che ora è stata trasformata nel video.
flusso: seleziona
utente immagine ->
immagine in AVAssetWriter cambiare al video ->
Unire un video che ho già preimpostato con il video ->
Risultato: crea 1 video dall'immagine selezionata e il video preimpostato.
Il problema con quello che ho: il mio codice fornisce uno spazio vuoto dove dovrebbe essere l'immagine all'interno del video. Come in, il file ImageConverter che ho, lo convertirà in video, ma vedrò solo l'ULTIMO frame come immagine, mentre ogni altro frame è trasparente, come se l'immagine non fosse lì. Quindi se converto l'immagine in un video per 5 secondi (diciamo a 30 fotogrammi/sec), vedrò uno spazio vuoto per (30 * 5) -1 fotogrammi e poi quell'ultimo fotogramma, l'immagine apparirà finalmente. Sto solo cercando indicazioni su come realizzare una singola immagine in un video O unire un video e un'immagine insieme SENZA convertire l'immagine in un video. Grazie!
unire i file qui
func merge() {
if let firstAsset = controller.firstAsset, secondAsset = self.asset {
// 1 - Create AVMutableComposition object. This object will hold your AVMutableCompositionTrack instances.
let mixComposition = AVMutableComposition()
let firstTrack = mixComposition.addMutableTrackWithMediaType(AVMediaTypeVideo,
preferredTrackID: Int32(kCMPersistentTrackID_Invalid))
do {
try firstTrack.insertTimeRange(CMTimeRangeMake(kCMTimeZero, CMTime(seconds: 8, preferredTimescale: 600)),
ofTrack: firstAsset.tracksWithMediaType(AVMediaTypeVideo)[0] ,
atTime: kCMTimeZero)
} catch _ {
print("Failed to load first track")
}
do {
//HERE THE TIME IS 0.666667, BUT SHOULD BE 0
print(CMTimeGetSeconds(secondAsset.duration), CMTimeGetSeconds(firstTrack.timeRange.duration))
try firstTrack.insertTimeRange(CMTimeRangeMake(kCMTimeZero, secondAsset.duration),
ofTrack: secondAsset.tracksWithMediaType(AVMediaTypeVideo)[0],
atTime: firstTrack.timeRange.duration)
} catch _ {
print("Failed to load second track")
}
do {
try firstTrack.insertTimeRange(CMTimeRangeMake(CMTime(seconds: 8+CMTimeGetSeconds(secondAsset.duration), preferredTimescale: 600), firstAsset.duration),
ofTrack: firstAsset.tracksWithMediaType(AVMediaTypeVideo)[0] ,
atTime: firstTrack.timeRange.duration+secondTrack.timeRange.duration)
} catch _ {
print("failed")
}
// 3 - Audio track
if let loadedAudioAsset = controller.audioAsset {
let audioTrack = mixComposition.addMutableTrackWithMediaType(AVMediaTypeAudio, preferredTrackID: 0)
do {
try audioTrack.insertTimeRange(CMTimeRangeMake(kCMTimeZero, firstAsset.duration),
ofTrack: loadedAudioAsset.tracksWithMediaType(AVMediaTypeAudio)[0] ,
atTime: kCMTimeZero)
} catch _ {
print("Failed to load Audio track")
}
}
// 4 - Get path
let documentDirectory = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0]
let dateFormatter = NSDateFormatter()
dateFormatter.dateStyle = .LongStyle
dateFormatter.timeStyle = .ShortStyle
let date = dateFormatter.stringFromDate(NSDate())
let savePath = (documentDirectory as NSString).stringByAppendingPathComponent("mergeVideo.mov")
let url = NSURL(fileURLWithPath: savePath)
_ = try? NSFileManager().removeItemAtURL(url)
// 5 - Create Exporter
print("exporting")
guard let exporter = AVAssetExportSession(asset: mixComposition, presetName: AVAssetExportPresetHighestQuality) else { return }
exporter.outputURL = url
exporter.outputFileType = AVFileTypeQuickTimeMovie
exporter.shouldOptimizeForNetworkUse = false
exporter.videoComposition = mainComposition
// 6 - Perform the Export
controller.currentlyEditing = true
exporter.exportAsynchronouslyWithCompletionHandler() {
dispatch_async(dispatch_get_main_queue()) { _ in
print("done")
self.controller.currentlyEditing = false
self.controller.merged = true
self.button.blurView.superview?.hidden = true
self.controller.player.replaceCurrentItemWithPlayerItem(AVPlayerItem(URL: url))
self.controller.firstAsset = AVAsset(URL: url)
}
}
}
}
func exportDidFinish(session: AVAssetExportSession) {
if session.status == AVAssetExportSessionStatus.Failed {
print(session.error)
}
if session.status == AVAssetExportSessionStatus.Completed {
print("succed")
}
}
Converti immagine Qui
class MyConverter: NSObject {
var image:UIImage!
convenience init(image:UIImage) {
self.init()
self.image = image
}
var outputURL: NSURL {
let documentDirectory = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0]
let savePath = (documentDirectory as NSString).stringByAppendingPathComponent("mergeVideo-pic.mov")
return getURL(savePath)
}
func getURL(path:String) -> NSURL {
let movieDestinationUrl = NSURL(fileURLWithPath: path)
_ = try? NSFileManager().removeItemAtURL(movieDestinationUrl)
let url = NSURL(fileURLWithPath: path)
return url
}
func build(completion:() -> Void) {
guard let videoWriter = try? AVAssetWriter(URL: outputURL, fileType: AVFileTypeQuickTimeMovie) else {
fatalError("AVAssetWriter error")
}
let outputSettings = [AVVideoCodecKey : AVVideoCodecH264, AVVideoWidthKey : NSNumber(float: Float(image.size.width)), AVVideoHeightKey : NSNumber(float: Float(image.size.height))]
guard videoWriter.canApplyOutputSettings(outputSettings, forMediaType: AVMediaTypeVideo) else {
fatalError("Negative : Can't apply the Output settings...")
}
let videoWriterInput = AVAssetWriterInput(mediaType: AVMediaTypeVideo, outputSettings: outputSettings)
let sourcePixelBufferAttributesDictionary = [kCVPixelBufferPixelFormatTypeKey as String : NSNumber(unsignedInt: kCVPixelFormatType_32ARGB), kCVPixelBufferWidthKey as String: NSNumber(float: Float(image.size.width)), kCVPixelBufferHeightKey as String: NSNumber(float: Float(image.size.height))]
let pixelBufferAdaptor = AVAssetWriterInputPixelBufferAdaptor(assetWriterInput: videoWriterInput, sourcePixelBufferAttributes: sourcePixelBufferAttributesDictionary)
if videoWriter.canAddInput(videoWriterInput) {
videoWriter.addInput(videoWriterInput)
}
if videoWriter.startWriting() {
videoWriter.startSessionAtSourceTime(kCMTimeZero)
assert(pixelBufferAdaptor.pixelBufferPool != nil)
}
let media_queue = dispatch_queue_create("mediaInputQueue", nil)
videoWriterInput.requestMediaDataWhenReadyOnQueue(media_queue, usingBlock: {() -> Void in
var appendSucceeded = true
//Time HERE IS ZERO, but in Merge file, it is 0.66667
let presentationTime = CMTimeMake(0, 600)
var pixelBuffer: CVPixelBuffer? = nil
let status: CVReturn = CVPixelBufferPoolCreatePixelBuffer(kCFAllocatorDefault, pixelBufferAdaptor.pixelBufferPool!, &pixelBuffer)
if let pixelBuffer = pixelBuffer where status == 0 {
let managedPixelBuffer = pixelBuffer
CVPixelBufferLockBaseAddress(managedPixelBuffer, 0)
let data = CVPixelBufferGetBaseAddress(managedPixelBuffer)
let rgbColorSpace = CGColorSpaceCreateDeviceRGB()
let context = CGBitmapContextCreate(data, Int(self.image.size.width), Int(self.image.size.height), 8, CVPixelBufferGetBytesPerRow(managedPixelBuffer), rgbColorSpace, CGImageAlphaInfo.PremultipliedFirst.rawValue)
CGContextClearRect(context, CGRectMake(0, 0, CGFloat(self.image.size.width), CGFloat(self.image.size.height)))
CGContextDrawImage(context, CGRectMake(0, 0, self.image.size.width, self.image.size.height), self.image.CGImage)
CVPixelBufferUnlockBaseAddress(managedPixelBuffer, 0)
appendSucceeded = pixelBufferAdaptor.appendPixelBuffer(pixelBuffer, withPresentationTime: presentationTime)
} else {
print("Failed to allocate pixel buffer")
appendSucceeded = false
}
if !appendSucceeded {
print("append failed")
}
videoWriterInput.markAsFinished()
videoWriter.finishWritingWithCompletionHandler {() -> Void in
print("FINISHED!!!!!")
completion()
}
})
}
}
Nota: ho scoperto che se faccio un print(presentationTime)
all'interno del ImageConverter la stampa 0, e quindi stampare l'ora della durata all'interno della fusione, ottengo 0.666667
Nota: Nessuna risposta ancora, ma continuerò a rendere questa domanda una taglia finché non trovo una risposta o qualcun altro mi aiuta! Grazie!
Sono completamente grato per il tuo tentativo di risolvere il mio problema con la combinazione del codice Obj-C e Swift. Non sono stato in grado di testare questo codice, ma poiché ho solo 15 ore rimanenti e hai dato la risposta più approfondita, sceglierò la tua. Apprezzo il vostro aiuto! Grazie mille! – impression7vx
Questo ha funzionato alla grande! Ma potresti spiegare perché devo aggiungere al momento Zero e alla fine? Ha senso, ma perché non posso semplicemente aggiungere qualcosa con PresentationTime? – impression7vx
Non ne sono completamente sicuro. La mia ipotesi migliore è internamente il modo in cui funziona è che mostrerà un frame finché non avrà un nuovo frame per sostituirlo. Quindi devi aggiungerlo all'inizio per farlo visualizzare subito, e quindi devi aggiungerlo al tempo di presentazione per segnalare la fine (quindi sa per quanto tempo mostrare il primo fotogramma). Se aggiungi solo un fotogramma al momento della presentazione, questo mostrerà solo fino a quando il video non termina e nulla prima. – gadu