AVFoundation 添加视频第一帧

6
我正在尝试控制我的应用程序生成的视频在iOS上的照片应用中的显示方式。我制作的所有视频都以黑色帧开始,然后淡入淡出等。当这些保存到照片时,苹果会将第一帧(一个黑色正方形)用作照片中的缩略图。我想更改这个,以便我可以设置自己的缩略图,让人们轻松识别视频。
由于我找不到任何内置的API来实现这一点,我正在试图通过将我生成的缩略图添加为视频的第一帧来进行“黑客攻击”。我正在尝试使用AVFoundation来实现这一点,但遇到了一些问题。
我的代码抛出以下错误:[AVAssetReaderTrackOutput copyNextSampleBuffer] cannot copy next sample buffer before adding this output to an instance of AVAssetReader (using -addOutput:) and calling -startReading on that asset reader',尽管我已经调用了该方法。
以下是我的代码:
AVAsset *asset = [[AVURLAsset alloc] initWithURL:fileUrl options:nil];
UIImage *frame = [self generateThumbnail:asset];

NSDictionary *videoSettings = [NSDictionary dictionaryWithObjectsAndKeys:
                               AVVideoCodecH264, AVVideoCodecKey,
                               [NSNumber numberWithInt:640], AVVideoWidthKey,
                               [NSNumber numberWithInt:360], AVVideoHeightKey,
                               nil];

AVAssetReader *assetReader = [AVAssetReader assetReaderWithAsset:asset error:nil];
AVAssetReaderOutput *readerOutput = [AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack:[asset.tracks firstObject]
                                                                               outputSettings:nil];
[assetReader addOutput:readerOutput];

AVAssetWriter *videoWriter = [[AVAssetWriter alloc] initWithURL:path
                                                       fileType:AVFileTypeMPEG4
                                                          error:nil];
NSParameterAssert(videoWriter);

AVAssetWriterInput* writerInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo
                                                                     outputSettings:videoSettings];

AVAssetWriterInputPixelBufferAdaptor *adaptor = [AVAssetWriterInputPixelBufferAdaptor
                                                 assetWriterInputPixelBufferAdaptorWithAssetWriterInput:writerInput
                                                 sourcePixelBufferAttributes:nil];

NSParameterAssert(writerInput);
NSParameterAssert([videoWriter canAddInput:writerInput]);

[videoWriter addInput:writerInput];

[assetReader startReading];
[videoWriter startWriting];
[videoWriter startSessionAtSourceTime:kCMTimeZero];

CVPixelBufferRef buffer = [self pixelBufferFromCGImage:frame.CGImage andSize:frame.size];

BOOL append_ok = NO;
while (!append_ok) {
    if (adaptor.assetWriterInput.readyForMoreMediaData) {
        append_ok = [adaptor appendPixelBuffer:buffer withPresentationTime:kCMTimeZero];
        CVPixelBufferPoolRef bufferPool = adaptor.pixelBufferPool;
        NSParameterAssert(bufferPool != NULL);

        [NSThread sleepForTimeInterval:0.05];
    } else {
        [NSThread sleepForTimeInterval:0.1];
    }
}
CVBufferRelease(buffer);

dispatch_queue_t mediaInputQueue = dispatch_queue_create("mediaInputQueue", NULL);
[writerInput requestMediaDataWhenReadyOnQueue:mediaInputQueue usingBlock:^{
    CMSampleBufferRef nextBuffer;
    while (writerInput.readyForMoreMediaData) {
        nextBuffer = [readerOutput copyNextSampleBuffer];
        if(nextBuffer) {
            NSLog(@"Wrote: %zu bytes", CMSampleBufferGetTotalSampleSize(nextBuffer));
            [writerInput appendSampleBuffer:nextBuffer];
        } else {
            [writerInput markAsFinished];
            [videoWriter finishWritingWithCompletionHandler:^{
                //int res = videoWriter.status;
            }];
            break;
        }
    }
}];

我尝试了一些变化,但都没有成功。我曾经看到过由于文件格式引起的崩溃。我正在使用一个mp4文件(不确定如何找出它的压缩状态或是否受支持),但即使使用未压缩的.mov文件(通过在Mac上使用Photo Booth制作),我也无法使它工作。

你有什么想法我做错了什么吗?


另外,检查一下writer.inputs和reader.outputs是否正确。 - onmyway133
2个回答

8

我遇到了同样的问题。

您的assetReader在函数结束后被ARC释放。但是来自readerOutput的块继续尝试读取内容。

当assetReader消失时,readerOutput与其断开连接,因此出现了需要将其重新连接到assetReader的错误。

解决方法是确保assetReader没有被释放。例如,将其放在属性中。


0

另一种选择:

你可以在requestMediaDataWhenReadyOnQueue块中捕获assetReader,例如通过在该块内从assetReader中提取readerOutput。

根据你的架构,不为内存管理添加额外属性可能是更清晰的解决方案。

我在Swift中实现了这种方法,它运行良好。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接