这code通过AVAssetWriter和AVAssetWriterInputs工作不写图像+声音。为什么? [英] This code to write video+audio through AVAssetWriter and AVAssetWriterInputs is not working. Why?
问题描述
我一直在试图编写使用AVAssetWriter和AVAssetWriterInputs视频+音频。
I've been trying to write a video+audio using AVAssetWriter and AVAssetWriterInputs.
我看了这个论坛的人说他们是能够完成的多个职位,但它不是为我工作。
如果我只是写视频,然后在code为做它的工作非常出色。当我添加音频输出文件被损坏,无法复制。
I read multiple posts in this forum of people saying they were able to accomplish that, but it is not working for me. If I just write video then the code is doing its job very well. When I add audio the output file is corrupted and cannot be reproduced.
下面是我的code的一部分:
Here is part of my code:
设置AVCaptureVideoDataOutput和AVCaptureAudioDataOutput:
Setting up AVCaptureVideoDataOutput and AVCaptureAudioDataOutput:
NSError *error = nil;
// Setup the video input
AVCaptureDevice *videoDevice = [AVCaptureDevice defaultDeviceWithMediaType: AVMediaTypeVideo];
// Create a device input with the device and add it to the session.
AVCaptureDeviceInput *videoInput = [AVCaptureDeviceInput deviceInputWithDevice:videoDevice error:&error];
// Setup the video output
_videoOutput = [[AVCaptureVideoDataOutput alloc] init];
_videoOutput.alwaysDiscardsLateVideoFrames = NO;
_videoOutput.videoSettings =
[NSDictionary dictionaryWithObject:
[NSNumber numberWithInt:kCVPixelFormatType_32BGRA] forKey:(id)kCVPixelBufferPixelFormatTypeKey];
// Setup the audio input
AVCaptureDevice *audioDevice = [AVCaptureDevice defaultDeviceWithMediaType: AVMediaTypeAudio];
AVCaptureDeviceInput *audioInput = [AVCaptureDeviceInput deviceInputWithDevice:audioDevice error:&error ];
// Setup the audio output
_audioOutput = [[AVCaptureAudioDataOutput alloc] init];
// Create the session
_capSession = [[AVCaptureSession alloc] init];
[_capSession addInput:videoInput];
[_capSession addInput:audioInput];
[_capSession addOutput:_videoOutput];
[_capSession addOutput:_audioOutput];
_capSession.sessionPreset = AVCaptureSessionPresetLow;
// Setup the queue
dispatch_queue_t queue = dispatch_queue_create("MyQueue", NULL);
[_videoOutput setSampleBufferDelegate:self queue:queue];
[_audioOutput setSampleBufferDelegate:self queue:queue];
dispatch_release(queue);
设置AVAssetWriter以及音频和视频AVAssetWriterInputs它关联:
Setting up AVAssetWriter and associating both audio and video AVAssetWriterInputs to it:
-(BOOL) setupWriter{
NSError *error = nil;
_videoWriter = [[AVAssetWriter alloc] initWithURL:videoURL fileType:AVFileTypeQuickTimeMovie
error:&error];
NSParameterAssert(_videoWriter);
// Add video input
NSDictionary *videoCompressionProps = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithDouble:128.0*1024.0], AVVideoAverageBitRateKey,
nil ];
NSDictionary *videoSettings = [NSDictionary dictionaryWithObjectsAndKeys:
AVVideoCodecH264, AVVideoCodecKey,
[NSNumber numberWithInt:192], AVVideoWidthKey,
[NSNumber numberWithInt:144], AVVideoHeightKey,
videoCompressionProps, AVVideoCompressionPropertiesKey,
nil];
_videoWriterInput = [[AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo
outputSettings:videoSettings] retain];
NSParameterAssert(_videoWriterInput);
_videoWriterInput.expectsMediaDataInRealTime = YES;
// Add the audio input
AudioChannelLayout acl;
bzero( &acl, sizeof(acl));
acl.mChannelLayoutTag = kAudioChannelLayoutTag_Mono;
NSDictionary* audioOutputSettings = nil;
// Both type of audio inputs causes output video file to be corrupted.
if( NO ) {
// should work from iphone 3GS on and from ipod 3rd generation
audioOutputSettings = [NSDictionary dictionaryWithObjectsAndKeys:
[ NSNumber numberWithInt: kAudioFormatMPEG4AAC ], AVFormatIDKey,
[ NSNumber numberWithInt: 1 ], AVNumberOfChannelsKey,
[ NSNumber numberWithFloat: 44100.0 ], AVSampleRateKey,
[ NSNumber numberWithInt: 64000 ], AVEncoderBitRateKey,
[ NSData dataWithBytes: &acl length: sizeof( acl ) ], AVChannelLayoutKey,
nil];
} else {
// should work on any device requires more space
audioOutputSettings = [ NSDictionary dictionaryWithObjectsAndKeys:
[ NSNumber numberWithInt: kAudioFormatAppleLossless ], AVFormatIDKey,
[ NSNumber numberWithInt: 16 ], AVEncoderBitDepthHintKey,
[ NSNumber numberWithFloat: 44100.0 ], AVSampleRateKey,
[ NSNumber numberWithInt: 1 ], AVNumberOfChannelsKey,
[ NSData dataWithBytes: &acl length: sizeof( acl ) ], AVChannelLayoutKey,
nil ];
}
_audioWriterInput = [[AVAssetWriterInput
assetWriterInputWithMediaType: AVMediaTypeAudio
outputSettings: audioOutputSettings ] retain];
_audioWriterInput.expectsMediaDataInRealTime = YES;
// add input
[_videoWriter addInput:_videoWriterInput];
[_videoWriter addInput:_audioWriterInput];
return YES;}
下面是功能开始/停止视频录制
here are functions to start/stop video recording
-(void) startVideoRecording
{
if( !_isRecording )
{
NSLog(@"start video recording...");
if( ![self setupWriter] )
return;
_isRecording = YES;
}
}
-(void) stopVideoRecording
{
if( _isRecording )
{
_isRecording = NO;
[_videoWriterInput markAsFinished];
[_videoWriter endSessionAtSourceTime:lastSampleTime];
[_videoWriter finishWriting];
NSLog(@"video recording stopped");
}
}
和最后CaptureOutput code
And finally the CaptureOutput code
- (void)captureOutput:(AVCaptureOutput *)captureOutput
didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
fromConnection:(AVCaptureConnection *)connection
{
if( !CMSampleBufferDataIsReady(sampleBuffer) )
{
NSLog( @"sample buffer is not ready. Skipping sample" );
return;
}
if( _isRecording == YES )
{
lastSampleTime = CMSampleBufferGetPresentationTimeStamp(sampleBuffer);
if( _videoWriter.status != AVAssetWriterStatusWriting )
{
[_videoWriter startWriting];
[_videoWriter startSessionAtSourceTime:lastSampleTime];
}
if( captureOutput == _videoOutput )
[self newVideoSample:sampleBuffer];
/*
// If I add audio to the video, then the output file gets corrupted and it cannot be reproduced
else
[self newAudioSample:sampleBuffer];
*/
}
}
-(void) newVideoSample:(CMSampleBufferRef)sampleBuffer
{
if( _isRecording )
{
if( _videoWriter.status > AVAssetWriterStatusWriting )
{
NSLog(@"Warning: writer status is %d", _videoWriter.status);
if( _videoWriter.status == AVAssetWriterStatusFailed )
NSLog(@"Error: %@", _videoWriter.error);
return;
}
if( ![_videoWriterInput appendSampleBuffer:sampleBuffer] )
NSLog(@"Unable to write to video input");
}
}
-(void) newAudioSample:(CMSampleBufferRef)sampleBuffer
{
if( _isRecording )
{
if( _videoWriter.status > AVAssetWriterStatusWriting )
{
NSLog(@"Warning: writer status is %d", _videoWriter.status);
if( _videoWriter.status == AVAssetWriterStatusFailed )
NSLog(@"Error: %@", _videoWriter.error);
return;
}
if( ![_audioWriterInput appendSampleBuffer:sampleBuffer] )
NSLog(@"Unable to write to audio input");
}
我将非常高兴,如果有人能找到它在这个code中的问题。
I would be very glad if someone could find which is the problem in this code.
推荐答案
在startVideoRecording我打电话(我假设你在某些时候调用这个)
In startVideoRecording I call (I assume you are calling this at some point)
[_capSession startRunning] ;
在stopVideoRecording我不叫
In stopVideoRecording I do not call
[_videoWriterInput markAsFinished];
[_videoWriter endSessionAtSourceTime:lastSampleTime];
该markAsFinished则多为与块式拉法使用。见requestMediaDataWhenReadyOnQueue:usingBlock在AVAssetWriterInput一个解释。图书馆应计算交织缓冲区适当的时机。
The markAsFinished is more for use with the block style pull method. See requestMediaDataWhenReadyOnQueue:usingBlock in AVAssetWriterInput for an explanation. The library should calculate the proper timing for interleaving the buffers.
您不需要调用endSessionAtSrouceTime。在样本数据的最后一个时间标记将在调用之后使用
You do not need to call endSessionAtSrouceTime. The last time stamp in the sample data will be used after the call to
[_videoWriter finishWriting];
我也明确地检查捕获的输出类型。
I also explicitly check for the type of capture output.
else if( captureOutput == _audioOutput) {
[self newAudioSample:sampleBuffer];
}
下面是我。音频和视频,我来通过。这是可能的,我改变一些东西。如果这不会为你工作,那么我会后我的一切。
Here is what I have. The audio and video come through for me. It is possible I changed something. If this does not work for you then I will post everything I have.
-(void) startVideoRecording
{
if( !_isRecording )
{
NSLog(@"start video recording...");
if( ![self setupWriter] ) {
NSLog(@"Setup Writer Failed") ;
return;
}
[_capSession startRunning] ;
_isRecording = YES;
}
}
-(void) stopVideoRecording
{
if( _isRecording )
{
_isRecording = NO;
[_capSession stopRunning] ;
if(![_videoWriter finishWriting]) {
NSLog(@"finishWriting returned NO") ;
}
//[_videoWriter endSessionAtSourceTime:lastSampleTime];
//[_videoWriterInput markAsFinished];
//[_audioWriterInput markAsFinished];
NSLog(@"video recording stopped");
}
}
这篇关于这code通过AVAssetWriter和AVAssetWriterInputs工作不写图像+声音。为什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!