Tôi đã cố gắng để viết một video + âm thanh bằng cách sử dụng AVAssetWriter và AVAssetWriterInputs.Mã này để ghi video + âm thanh qua AVAssetWriter và AVAssetWriterInputs không hoạt động. Tại sao?
Tôi đọc nhiều bài viết trong diễn đàn này của những người nói rằng họ đã có thể thực hiện điều đó, nhưng nó không làm việc cho tôi. Nếu tôi chỉ viết video thì mã sẽ hoạt động rất tốt. Khi tôi thêm âm thanh, tập tin đầu ra bị hỏng và không thể sao chép được.
Dưới đây là một phần của mã của tôi:
Thiết lập AVCaptureVideoDataOutput và 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);
Thiết lập AVAssetWriter và kết hợp cả hai AVAssetWriterInputs âm thanh và video với nó:
- (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;
}
ở đây chức năng để bắt đầu/dừng quay video
- (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");
}
}
Và cuối cùng mã 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");
}
}
}
tôi sẽ rất vui mừng nếu ai đó có thể tìm thấy đó là vấn đề trong mã này.
Tôi gặp sự cố với cài đặt âm thanh của mình với mã rất giống với mã của bạn. Ứng dụng của tôi sẽ ghi lại video nhưng ngay sau khi tôi nói cho AVAssetWritterInput tôi đã tạo cho âm thanh để nối thêm SampleBuffer: nó cho tôi biết 'Bộ đệm đầu vào phải ở định dạng không nén khi outputSettings không phải là nil'.Bạn đã bao giờ gặp vấn đề này chưa? Đó là lái xe hơi hấp dẫn của tôi! – Baza207
Xin chào kalos, đầu vào âm thanh trong ví dụ của bạn là từ micrô hoặc bản thân ứng dụng? – justicepenny
@kalos brother, bạn có thể cho tôi biết cách chúng tôi có thể sử dụng videoURL hay không. – morroko