Я видел этот вопрос несколько раз, но ни у кого из них нет рабочих ответов.AVFoundation - Обратный AVAsset и выходной видеофайл
Требование состоит в том, чтобы отменить и вывести видеофайл (а не просто воспроизвести его в обратном порядке), сохраняя в качестве исходного видео одинаковое сжатие, формат и частоту кадров.
В идеале решение могло бы сделать это все в памяти или буфере и не генерировать кадры в файлы изображений (например: AVAssetImageGenerator
), а затем перекомпилировать его (ресурсоемкие, ненадежные результаты синхронизации, изменения в кадрах/качество изображения от оригинала и т. д.).
-
Моего вклад: Это все еще не работает, но лучший, что я пытался до сих пор:
- чтения в выборке кадров в массиве
CMSampleBufferRef[]
с помощьюAVAssetReader
. - Запишите его в обратном порядке, используя
AVAssetWriter
. - Проблема: Кажется, что синхронизация для каждого кадра сохраняется в
CMSampleBufferRef
, поэтому даже добавление их назад не будет работать. - Далее я попытался изменить временную информацию каждого кадра с помощью обратного/зеркального фрейма.
- Проблема: Это вызывает неизвестную ошибку с
AVAssetWriter
. Следующий шаг: Я буду смотреть в
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]; }
Я не думаю, что это возможно из-за того, как работает сжатие видео ... из моего понимания вы можете перейти только с ключевого кадра, но не назад .. без вычисления всех кадров между ключевыми кадрами – Bastian
@Bastian можете ли вы немного рассказать о том, что вы имеете в виду? У меня есть исходные данные образца (CMSampleBufferRef) для каждого кадра, хранящегося в массиве. –
Просто FYI для всех, кто это читает. Я понял это и буду отвечать за ответ в ближайшие дни. –