- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在尝试将多个视频文件合并到一个具有特定编解码器设置的文件中。我曾经为此使用 AVAssetExportSession
,但现在我需要比 AVAssetExportSession
提供更多的编解码器控制。
下面我发布了处理视频文件组合的 createFinalVideo:
函数。
我采用的方法是尝试使用 AVAssetWriter
写入同一个文件,同时在应该附加下一个视频的位置简单地启动 session 。我知道这不会起作用,因为 AVAssetWriter
显然不允许这种行为。
以前,我在 for 循环之外定义了 AVAssetWriter
,并且我试图为每个视频文件添加一个新输入(for 循环的每次传递)。但是,AVAssetWriter
似乎不允许在 [AVAssetWriter startWriting]
被调用后添加新输入。
我的问题是如何以正确的方式做我想做的事情?
/**
* Final video creation. Merges audio-only and video-only files.
**/
-(void)createFinalVideo:(id)args
{
ENSURE_SINGLE_ARG(args, NSDictionary);
// presentation id
NSString * presID = [args objectForKey:@"presID"];
// array of video paths
NSArray * videoPathsArray = [args objectForKey:@"videoPaths"];
videoSuccessCallback = [args objectForKey:@"videoSuccess"];
videoCancelCallback = [args objectForKey:@"videoCancel"];
videoErrorCallback = [args objectForKey:@"videoError"];
NSError * error = nil;
NSFileManager * fileMgr = [NSFileManager defaultManager];
NSString * bundleDirectory = [[NSBundle mainBundle] bundlePath];
NSString * documentsDirectory = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"];
/*********************************************************************/
/* BEGIN: merge all videos into a final MP4 */
/*********************************************************************/
// create the final video output file as MP4 file
NSString * finalOutputFilePath = [NSString stringWithFormat:@"%@/%@/final_video.mp4", documentsDirectory, presID];
NSURL * finalOutputFileUrl = [NSURL fileURLWithPath:finalOutputFilePath];
// delete file if it exists
if ([fileMgr fileExistsAtPath:finalOutputFilePath]) {
[fileMgr removeItemAtPath:finalOutputFilePath error:nil];
}
float renderWidth = 640, renderHeight = 480;
NSDictionary *videoCleanApertureSettings = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:renderWidth], AVVideoCleanApertureWidthKey,
[NSNumber numberWithInt:renderHeight], AVVideoCleanApertureHeightKey,
[NSNumber numberWithInt:10], AVVideoCleanApertureHorizontalOffsetKey,
[NSNumber numberWithInt:10], AVVideoCleanApertureVerticalOffsetKey,
nil];
NSDictionary *codecSettings = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:1960000], AVVideoAverageBitRateKey,
[NSNumber numberWithInt:24],AVVideoMaxKeyFrameIntervalKey,
videoCleanApertureSettings, AVVideoCleanApertureKey,
AVVideoProfileLevelH264Baseline30, AVVideoProfileLevelKey,
nil];
NSDictionary *videoCompressionSettings = [NSDictionary dictionaryWithObjectsAndKeys:
AVVideoCodecH264, AVVideoCodecKey,
codecSettings,AVVideoCompressionPropertiesKey,
[NSNumber numberWithInt:renderWidth], AVVideoWidthKey,
[NSNumber numberWithInt:renderHeight], AVVideoHeightKey,
AVVideoScalingModeResizeAspect, AVVideoScalingModeKey,
nil];
NSError *aerror = nil;
// next start time for adding to the compositions
CMTime nextStartTime = kCMTimeZero;
// loop through the video paths and add videos to the composition
for (NSString * path in videoPathsArray) {
// wait for each video to finish writing before continuing
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
// create video writer
AVAssetWriter *videoWriter = [[AVAssetWriter alloc] initWithURL:finalOutputFileUrl fileType:AVFileTypeQuickTimeMovie error:nil];
NSParameterAssert(videoWriter);
NSLog(@"at the top of the for loop");
NSLog(@"%@", path);
AVAssetWriterInput* videoWriterInput = [AVAssetWriterInput
assetWriterInputWithMediaType:AVMediaTypeVideo
outputSettings:videoCompressionSettings];
NSParameterAssert(videoWriterInput);
NSParameterAssert([videoWriter canAddInput:videoWriterInput]);
videoWriterInput.expectsMediaDataInRealTime = YES;
[videoWriter addInput:videoWriterInput];
AVAssetWriterInput* audioWriterInput = [AVAssetWriterInput
assetWriterInputWithMediaType:AVMediaTypeAudio
outputSettings:nil];
NSParameterAssert(audioWriterInput);
NSParameterAssert([videoWriter canAddInput:audioWriterInput]);
audioWriterInput.expectsMediaDataInRealTime = NO;
[videoWriter addInput:audioWriterInput];
[videoWriter startWriting];
// video setup
AVAsset *avAsset = [[AVURLAsset alloc] initWithURL:[NSURL fileURLWithPath:path] options:nil];
AVAssetReader *reader = [[AVAssetReader alloc] initWithAsset:avAsset error:&aerror];
AVAssetTrack *videoTrack = [[avAsset tracksWithMediaType:AVMediaTypeVideo]objectAtIndex:0];
CMTime videoDuration = avAsset.duration;
// Wait until the duration is actually available
int durationAttempts = 5;
while(CMTimeGetSeconds(videoDuration) == 0 && durationAttempts > 0) {
durationAttempts--;
[NSThread sleepForTimeInterval:0.3];
videoDuration = avAsset.duration;
}
NSLog(@"[INFO] MODULE-VIDUTILS video duration in secs: %f", CMTimeGetSeconds(videoDuration));
//videoWriterInput.transform = videoTrack.preferredTransform;
NSDictionary *videoOptions = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange] forKey:(id)kCVPixelBufferPixelFormatTypeKey];
AVAssetReaderTrackOutput *asset_reader_output = [[AVAssetReaderTrackOutput alloc] initWithTrack:videoTrack outputSettings:videoOptions];
[reader addOutput:asset_reader_output];
//audio setup
AVAssetReader *audioReader = [AVAssetReader assetReaderWithAsset:avAsset error:nil];
AVAssetTrack* audioTrack = [[avAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];
AVAssetReaderOutput *readerOutput = [AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack:audioTrack outputSettings:nil];
[audioReader addOutput:readerOutput];
NSLog(@"startSessionAtSourceTime: %f", CMTimeGetSeconds(nextStartTime));
[videoWriter startSessionAtSourceTime:nextStartTime];
// set next start time
nextStartTime = CMTimeAdd(nextStartTime, videoDuration);
[reader startReading];
dispatch_queue_t _processingQueue = dispatch_queue_create("AVAssetWriterQueue", DISPATCH_QUEUE_SERIAL);
[videoWriterInput requestMediaDataWhenReadyOnQueue:_processingQueue usingBlock:^{
while ([videoWriterInput isReadyForMoreMediaData]) {
CMSampleBufferRef sampleBuffer;
if ([reader status] == AVAssetReaderStatusReading &&
(sampleBuffer = [asset_reader_output copyNextSampleBuffer])) {
BOOL result = [videoWriterInput appendSampleBuffer:sampleBuffer];
CFRelease(sampleBuffer);
if (!result) {
[reader cancelReading];
NSLog(@"NO RESULT");
NSLog (@"[INFO] MODULE-VIDUTILS createFinalVideo AVAssetWriterInputStatusFailed: %@", videoWriter.error);
if (videoErrorCallback != nil) {
[self _fireEventToListener:@"videoError" withObject:nil listener:videoErrorCallback thisObject:nil];
}
return;
break;
}
} else {
[videoWriterInput markAsFinished];
switch ([reader status]) {
case AVAssetReaderStatusReading:
// the reader has more for other tracks, even if this one is done
break;
case AVAssetReaderStatusCompleted:
[audioReader startReading];
[videoWriter startSessionAtSourceTime:nextStartTime];
NSLog(@"Request");
NSLog(@"Asset Writer ready :%d", audioWriterInput.readyForMoreMediaData);
while (audioWriterInput.readyForMoreMediaData) {
CMSampleBufferRef nextBuffer;
if ([audioReader status] == AVAssetReaderStatusReading && (nextBuffer = [readerOutput copyNextSampleBuffer])) {
NSLog(@"Ready");
if (nextBuffer) {
NSLog(@"NextBuffer");
[audioWriterInput appendSampleBuffer:nextBuffer];
}
} else {
[audioWriterInput markAsFinished];
//dictionary to hold duration
if ([audioReader status] == AVAssetReaderStatusCompleted) {
NSLog (@"[INFO] MODULE-VIDUTILS createFinalVideo AVAssetReaderStatusCompleted");
[videoWriter finishWritingWithCompletionHandler:^{
switch([videoWriter status]) {
case AVAssetWriterStatusCompleted:
NSLog (@"[INFO] MODULE-VIDUTILS createFinalVideo AVAssetWriterStatusCompleted");
dispatch_semaphore_signal(semaphore);
break;
case AVAssetWriterStatusCancelled:
NSLog (@"[INFO] MODULE-VIDUTILS createFinalVideo AVAssetWriterStatusCancelled");
if (videoSuccessCallback != nil) {
[self _fireEventToListener:@"videoCancel" withObject:nil listener:videoCancelCallback thisObject:nil];
}
return;
break;
case AVAssetWriterStatusFailed:
NSLog (@"[INFO] MODULE-VIDUTILS createFinalVideo AVAssetWriterStatusFailed");
if (videoSuccessCallback != nil) {
[self _fireEventToListener:@"videoError" withObject:nil listener:videoErrorCallback thisObject:nil];
}
return;
break;
}
}];
break;
}
}
}
break;
case AVAssetReaderStatusFailed:
NSLog (@"[INFO] MODULE-VIDUTILS createFinalVideo AVAssetReaderStatusFailed, @%", reader.error);
if (videoSuccessCallback != nil) {
[self _fireEventToListener:@"videoError" withObject:nil listener:videoErrorCallback thisObject:nil];
}
[videoWriter cancelWriting];
return;
break;
}
break;
}
}
}];
// wait for the writing to finish
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
NSLog(@"Write Ended");
}
NSLog(@"got here -- should have waited for all videos to complete first");
// call success if we got here
if (videoSuccessCallback != nil) {
[self _fireEventToListener:@"videoSuccess" withObject:nil listener:videoSuccessCallback thisObject:nil];
}
}
最佳答案
我找到了一个名为 SDAVAssetExportSession
的 AVAssetExportSession
的替代品允许您指定设置而不是使用预设。
关于ios - 结合视频文件与 AVAssetWriter,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23503039/
有人知道如何在 AVFoundation 中使用 AVAssetWriter 将未压缩的帧存储到 mov 中吗?对于 ProRes4444 内容,我实际上使用了以下片段: NSDictionary *
我在iOS上使用AVAssetWriter编码MP4视频。我目前正在使用AVAssetWriterInputPixelBufferAdaptor传递数据,但是在这方面我很灵活。 如何指定哪些输入框是关
我使用以下代码附加PixelBuffer,但输出视频是黑屏(CIImage 是正常的)。我认为问题出现在 newPixelBuffer 中。 func recordRealTimeFilterVide
为什么当您加载纵向 JPGS 并尝试使用 AVAssetWriter 时,生成的 mov 文件旋转了 90? 其他人看到了吗? 最佳答案 如果肖像 jpg 是在 iphone 上制作的,则它们的原始像
此代码适用于从图像创建视频。 AVAssetWritter 工作正常,没有错误并导出输出视频 - (.mov)。但在某些图像大小的情况下它会失败。120 x 160 - 失败180 x 640、240
我正在尝试将多个视频文件合并到一个具有特定编解码器设置的文件中。我曾经为此使用 AVAssetExportSession,但现在我需要比 AVAssetExportSession 提供更多的编解码器控
我正在 iOS 上编写一个视频编辑小应用。我关注了 this question 中评价最高的答案想用AVAssetwriter,最后写入还是失败了。当我进入 complete 回调时 [videoWr
创建 assetwriter 后,我的 friend 在他的设备上收到此错误 - 日志:AVAssetWriter:0x1e051900,outputURL = file://localhost/va
我有以下代码在 AVAssetWriter 中写入日期元数据,这在 iOS 13 中完全错误。需要知道这是 iOS 13 错误还是我做错了什么。 private var metadataIt
我正在完成一个将电影保存到相册的 iPhone 应用程序。电影源是一组图像。我用它制作电影并将它们很好地放入相册,但它总是在开始时有一个额外的绿色框架。 有什么想法吗? 我重新阅读了 Apple
我正在尝试使用 OSX AVAsset 类从电影文件中读取视频帧,调整颜色,然后将它们写出到新的电影文件中。我已经完成了所有工作,除了出于某种奇怪的原因,当我正在阅读以每秒 29.97 帧播放的视频时
我有几种方法可以将 mov 文件中的视频写入临时目录,但在大约 15 秒后。我收到错误: 收到内存警告。 收到内存警告。 收到内存警告。 收到内存警告。 然后应用程序崩溃了。我被卡住了,不知道出了什么
你好,我是 ios 开发的新手,我遇到了一些问题 我做了一些 AVAssetWriter 的设置,比如对象(我用它来写像素图作为视频的帧 - 它工作正常) self.assetWriter =
我录制音频和视频文件。用户可以只从视频切换到音频,也可以从音频切换到视频。但是当我从音频切换到视频时,第一帧是黑色的。 切换 func switch_to_audio(){ capture_s
我正在使用 AVAssetWriter 通过委托(delegate)从 ARSession 写入视频帧。 func session(_ session: ARSession, didUpdate fr
我正在开发一个使用 AVAssetWriter 录制视频的应用程序(源媒体是从 captureOutput(_ output: AVCaptureOutput, didOutput sampleBuf
我正在制作一个录制视频的应用程序。到目前为止,我已经能够使用 AVCaptureMovieFileOutput 成功录制视频和音频,但是,我现在需要实时编辑视频帧以将一些数据叠加到视频上。我开始切换到
是否可以在 iPhone 上使用 avassetwriter 合成绿屏图像——绿色背景下的动画 Actor 和背景照片并制作视频。 我有一个应用程序可以在绿色背景下创建动画角色的一系列屏幕截图。我想将
我正在使用 AVAssetWriter 将音频(和/或视频)写入 quicktime 电影格式。如何在不停止 session (即继续记录)的情况下定期(每隔几分钟)保存(或备份)此文件? 这是我在录
如果我包含的图像没有填满整个渲染区域,我用 AVAssetWriter 编写的每个文件都有黑色背景。有什么方法可以写透明吗?这是我用来获取像素缓冲区的方法: - (CVPixelBufferRef)p
我是一名优秀的程序员,十分优秀!