экспортировать массив UIImage в видео - соответствующим образом установить CMTime

У меня есть массив UIImage из 10 кадров. Я хочу экспортировать это как фильм продолжительностью 15 секунд. поэтому ему пришлось бы зацикливать эти 10 кадров в течение 15 секунд. между каждым кадром мне нужен интервал 0,2 секунды.

Мне удалось создать фильм из моего массива, но я не понимаю, как работает CMTime. Я пытался возиться с числами, но я не могу получить результат, который хочу. либо мой фильм слишком короткий, он воспроизводится слишком быстро и т. д.

Я прочитал это: Попытка понять CMTime и CMTimeMake но для меня это все равно не имеет смысла...

Мне нужно понять, как эти 3 переменные CMTime связаны друг с другом

CMTime frameTime = CMTimeMake(1, 5);
CMTime lastTime = CMTimeMake(i, 5);
CMTime presentTime = CMTimeAdd(lastTime, frameTime);

это код, который я использую

- (void)writeImageAsMovie:(NSArray *)array toPath:(NSURL*)path size:(CGSize)size {
    NSError *error = nil;
   self.videoWriter = [[AVAssetWriter alloc] initWithURL:path
                                                           fileType:AVFileTypeMPEG4
                                                              error:&error];
    NSParameterAssert(self.videoWriter);

    NSDictionary *videoSettings = [NSDictionary dictionaryWithObjectsAndKeys:
                                   AVVideoCodecH264, AVVideoCodecKey,
                                   [NSNumber numberWithInt:size.width], AVVideoWidthKey,
                                   [NSNumber numberWithInt:size.height], AVVideoHeightKey,
                                   nil];
    AVAssetWriterInput* writerInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo
                                                                          outputSettings:videoSettings];
    NSMutableDictionary *attributes = [[NSMutableDictionary alloc] init];
    [attributes setObject:[NSNumber numberWithUnsignedInt:kCVPixelFormatType_32ARGB] forKey:(NSString*)kCVPixelBufferPixelFormatTypeKey];
    [attributes setObject:[NSNumber numberWithUnsignedInt:size.width] forKey:(NSString*)kCVPixelBufferWidthKey];
    [attributes setObject:[NSNumber numberWithUnsignedInt:size.height] forKey:(NSString*)kCVPixelBufferHeightKey];

    AVAssetWriterInputPixelBufferAdaptor *adaptor = [AVAssetWriterInputPixelBufferAdaptor assetWriterInputPixelBufferAdaptorWithAssetWriterInput:writerInput sourcePixelBufferAttributes:attributes];
    NSParameterAssert(writerInput);
    NSParameterAssert([self.videoWriter canAddInput:writerInput]);
    [self.videoWriter addInput:writerInput];
    writerInput.expectsMediaDataInRealTime = YES;


    //Start a session:
    [self.videoWriter startWriting];
    [self.videoWriter startSessionAtSourceTime:kCMTimeZero];

    CVPixelBufferRef buffer = NULL;
    buffer = ([self pixelBufferFromCGImage:[[array objectAtIndex:0] CGImage] size:CGSizeMake(size.width, size.height)]);
    CVPixelBufferPoolCreatePixelBuffer (NULL, adaptor.pixelBufferPool, &buffer);

    [adaptor appendPixelBuffer:buffer withPresentationTime:kCMTimeZero];
    int i = 1;
    while (writerInput.readyForMoreMediaData)
    {
        CMTime frameTime = CMTimeMake(1, 15);
        CMTime lastTime= CMTimeMake(i, 15);
        CMTime presentTime= CMTimeAdd(lastTime, frameTime);

        if (i >= [array count]) {
            buffer = NULL;
        }
        else {
            buffer = [self pixelBufferFromCGImage:[[array objectAtIndex:i] CGImage] size:size];
        }

        if (buffer) {
            [adaptor appendPixelBuffer:buffer withPresentationTime:presentTime];
            i++;
        } else {

            [writerInput markAsFinished];
            [self.videoWriter finishWritingWithCompletionHandler:^{
                NSLog (@"Done");

            }];

            CVPixelBufferPoolRelease(adaptor.pixelBufferPool);
            break;
        }
    }

}

person Ramin Afshar    schedule 10.08.2014    source источник


Ответы (1)


Я боролся с CMTime и созданием фильма. В итоге я использовал:

CMTime presentTime = CMTimeMake(frameNum, (int32_t)fps);

Я думаю, что вам нужно 5 кадров в секунду (чтобы дать вам 0,2 с между кадрами), тогда вы должны добавить в общей сложности 75 кадров (для 15-секундного фильма). Вы бы показывали каждое изображение 7,5 раз (я знаю - должно быть целое число - возможно, выберите другую частоту кадров или длину фильма, если у вас есть 10 кадров), чтобы получить свой фильм.

Проработка: fps = 5, желаемая длина ролика 16 сек = 80 кадров. Добавьте каждое изображение в фильм 8 раз.

person CharlesA    schedule 10.08.2014
comment
Я попытался сделать то, что вы сказали, изменив переменную presentTime, но это не сработало. Думаю, мне нужно понять, как работают эти 3 переменные CMTime CMTime frameTime = CMTimeMake(1, 5); CMTime lastTime = CMTimeMake(i, 5); CMTime presentTime = CMTimeAdd(lastTime, frameTime); - person Ramin Afshar; 10.08.2014
comment
Хм. Если это поможет, я разместил код, который я использую, на Github — его файл APEncodeMovie здесь: github.com/cja1/tubenoise/blob/master/tubenoise/APEncodeMovie.m - person CharlesA; 11.08.2014