AVFoundation 将第一帧添加到视频
Posted
技术标签:
【中文标题】AVFoundation 将第一帧添加到视频【英文标题】:AVFoundation add first frame to video 【发布时间】:2014-12-22 18:37:32 【问题描述】:我正在尝试控制我的应用生成的视频在 ios 上的照片应用中的显示方式。我制作的所有视频都以黑框开始,然后淡入淡出,等等。当这些视频保存到照片时,Apple 会拍摄第一帧(黑色方块)并将其用作照片中的缩略图。我想更改此设置,以便我可以设置自己的缩略图,以便人们轻松识别视频。
由于我找不到任何内置的 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 是否正确 【参考方案1】:刚刚遇到同样的问题。
您的assetReader 在ARC 函数结束后被释放。但是来自 readerOutput 的块读取缓冲区继续尝试读取内容。
当assetReader 消失时,readerOutput 与它断开连接,因此错误表明您需要将其连接回assetReader。
修复方法是确保不释放assetReader。例如。把它放在一个属性中。
【讨论】:
【参考方案2】:作为替代方案:
您可以在requestMediaDataWhenReadyOnQueue
块内捕获assetReader
,例如从该块内的assetReader
提取readerOutput。
根据您的架构,不具有仅用于内存管理的附加属性可能是一种更简洁的解决方案。
我迅速实施了这种方法,效果很好。
【讨论】:
以上是关于AVFoundation 将第一帧添加到视频的主要内容,如果未能解决你的问题,请参考以下文章