AVAssetWriter 및 AVAssetWriterInputs를 통해 비디오 + 오디오를 작성하는이 코드가 작동하지 않습니다. 왜?
AVAssetWriter 및 AVAssetWriterInputs를 사용하여 비디오 + 오디오를 작성하려고했습니다.
나는 사람들이 그것을 성취 할 수 있었다고 말하는 사람들의 포럼에서 여러 게시물을 읽었지만 그것은 나를 위해 작동하지 않습니다. 비디오를 작성하면 코드가 잘 작동합니다. 오디오를 추가하면 출력 파일이 손상되어 재생할 수 없습니다.
다음은 내 코드의 일부입니다.
AVCaptureVideoDataOutput 및 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를 여기에 연결합니다.
- (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;
}
녹화 시작 / 중지 기능
- (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 코드
- (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");
}
}
}
누군가이 코드에서 문제를 찾을 수 있다면 매우 기쁠 것입니다.
startVideoRecording에서 호출합니다 (언젠가는 이것을 호출한다고 가정합니다)
[_capSession startRunning] ;
In stopVideoRecording I do not call
[_videoWriterInput markAsFinished];
[_videoWriter endSessionAtSourceTime:lastSampleTime];
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.
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");
}
}
First, do not use [NSNumber numberWithInt:kCVPixelFormatType_32BGRA]
, as it is not the native format of the camera. use [NSNumber numberWithInt:kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange]
Also, you should always check before calling startWriting that it isn't already running. You do not need to set session end time, as stopWriting will do that.
'Program Tip' 카테고리의 다른 글
파이썬 db-api : fetchone vs fetchmany vs fetchall (0) | 2020.11.25 |
---|---|
성능 : 일반에서 파생 된 유형 (0) | 2020.11.25 |
웹 개발 및 디자인에 유용한 Vim 플러그인 (php, html, css, javascript)? (0) | 2020.11.25 |
Angularjs-간단한 양식 제출 (0) | 2020.11.25 |
Visual Studio가 새 .vsmdi 파일을 만드는 이유는 무엇입니까? (0) | 2020.11.25 |