Bu sorunun birkaç kez sorulmuş olduğunu gördüm, ancak bunların hiçbiri herhangi bir yanıt almamış görünüyor.AVFoundation - Bir AVAsset ve çıkış video dosyasını tersine çevir
Gereksinim, video dosyasıyla aynı sıkıştırma, biçim ve kare hızını koruyarak bir video dosyasını (sadece ters olarak oynatmak değil) tersine çevirip çıkarmaktır.
İdeal olarak, çözüm bunu bellekte veya arabellekte yapabilir ve kareleri görüntü dosyalarına (örneğin: AVAssetImageGenerator
kullanarak) üretmekten ve sonra yeniden derlemeyi (kaynak yoğun, güvenilir olmayan zamanlama sonuçları, çerçeve içinde değişiklikler) engelleyebilir. Orijinal görüntü kalitesi, vb.).
-
My katkısı: Bu hala çalışmıyorsa, ama en iyi şimdiye kadar denedim :
- Oku örnek çerçevelerinde
CMSampleBufferRef[]
dizisiAVAssetReader
kullanarak içine. AVAssetWriter
'u kullanarak ters sırayla geri yazın.- Sorun: Her çerçevenin zamanlaması
CMSampleBufferRef
'a kaydedilmiş gibi görünüyor, bu yüzden onları geriye eklemeler bile işe yaramayacaktır. - Sonraki, her çerçevenin zamanlama bilgilerini ters/ayna çerçevesiyle değiştirmeyi denedim.
- Sorun: Bu,
AVAssetWriter
ile bilinmeyen bir hataya neden oluyor. Sonraki Adım: Ben son birkaç gün içinde bu konuda çalıştı
AVAssetWriterInputPixelBufferAdaptor
- (AVAsset *)assetByReversingAsset:(AVAsset *)asset { NSURL *tmpFileURL = [NSURL URLWithString:@"/tmp/test.mp4"]; NSError *error; // initialize the AVAssetReader that will read the input asset track AVAssetReader *reader = [[AVAssetReader alloc] initWithAsset:asset error:&error]; AVAssetTrack *videoTrack = [[asset tracksWithMediaType:AVMediaTypeVideo] lastObject]; AVAssetReaderTrackOutput* readerOutput = [AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack:videoTrack outputSettings:nil]; [reader addOutput:readerOutput]; [reader startReading]; // Read in the samples into an array NSMutableArray *samples = [[NSMutableArray alloc] init]; while(1) { CMSampleBufferRef sample = [readerOutput copyNextSampleBuffer]; if (sample == NULL) { break; } [samples addObject:(__bridge id)sample]; CFRelease(sample); } // initialize the the writer that will save to our temporary file. CMFormatDescriptionRef formatDescription = CFBridgingRetain([videoTrack.formatDescriptions lastObject]); AVAssetWriterInput *writerInput = [[AVAssetWriterInput alloc] initWithMediaType:AVMediaTypeVideo outputSettings:nil sourceFormatHint:formatDescription]; CFRelease(formatDescription); AVAssetWriter *writer = [[AVAssetWriter alloc] initWithURL:tmpFileURL fileType:AVFileTypeMPEG4 error:&error]; [writerInput setExpectsMediaDataInRealTime:NO]; [writer addInput:writerInput]; [writer startSessionAtSourceTime:CMSampleBufferGetPresentationTimeStamp((__bridge CMSampleBufferRef)samples[0])]; [writer startWriting]; // Traverse the sample frames in reverse order for(NSInteger i = samples.count-1; i >= 0; i--) { CMSampleBufferRef sample = (__bridge CMSampleBufferRef)samples[i]; // Since the timing information is built into the CMSampleBufferRef // We will need to make a copy of it with new timing info. Will copy // the timing data from the mirror frame at samples[samples.count - i -1] CMItemCount numSampleTimingEntries; CMSampleBufferGetSampleTimingInfoArray((__bridge CMSampleBufferRef)samples[samples.count - i -1], 0, nil, &numSampleTimingEntries); CMSampleTimingInfo *timingInfo = malloc(sizeof(CMSampleTimingInfo) * numSampleTimingEntries); CMSampleBufferGetSampleTimingInfoArray((__bridge CMSampleBufferRef)sample, numSampleTimingEntries, timingInfo, &numSampleTimingEntries); CMSampleBufferRef sampleWithCorrectTiming; CMSampleBufferCreateCopyWithNewTiming( kCFAllocatorDefault, sample, numSampleTimingEntries, timingInfo, &sampleWithCorrectTiming); if (writerInput.readyForMoreMediaData) { [writerInput appendSampleBuffer:sampleWithCorrectTiming]; } CFRelease(sampleWithCorrectTiming); free(timingInfo); } [writer finishWriting]; return [AVAsset assetWithURL:tmpFileURL]; }
Video sıkıştırmanın çalışma şeklinden dolayı bunun mümkün olduğunu sanmıyorum ... anlayışımdan sadece bir anahtar kareden ileri gidebilirsin, ama geriye doğru değil .. anahtar kareleri arasındaki tüm kareleri hesaplamadan – Bastian
@Bastian Ne demek istediğin hakkında biraz bilgi verebilir misin? Dizide saklanan her çerçeve için ham örnek verisi (CMSampleBufferRef) var. –
Bunu okuyan herkese sadece bir FYI. Bunu anladım ve önümüzdeki birkaç gün içinde bir cevap yazacağım. Github ... –