【问题标题】:Record and play audio with AVAssetWriter使用 AVAssetWriter 录制和播放音频
【发布时间】:2012-06-26 13:39:49
【问题描述】:

我已经大大减少了这个问题,希望能得到一些帮助。

这个类基本上有两种方法,一种是开始录制音频(-recordMode),另一种是播放音频(playMode)。我目前在一个项目中有这个类,它有一个带有两个按钮的视图控制器,它们调用相应的方法(rec,play)。没有其他变量,类是自包含的。

但是它不会播放/录制任何东西,我不知道为什么。当我尝试播放文件时,我得到一个文件大小为 0 和一个错误,因为你当然不能用 nil 引用来初始化 AVAudioPlayer。但我不明白为什么文件是空的或者为什么self.outputPathnil

.h 文件

#import <AVFoundation/AVFoundation.h>

@interface MicCommunicator : NSObject<AVCaptureAudioDataOutputSampleBufferDelegate>

@property(nonatomic,retain) NSURL *outputPath;
@property(nonatomic,retain) AVCaptureSession * captureSession;
@property(nonatomic,retain) AVCaptureAudioDataOutput * output;

-(void)beginStreaming;
-(void)playMode;
-(void)recordMode;

@end

.m 文件:

@implementation MicCommunicator {
    AVAssetWriter *assetWriter;
    AVAssetWriterInput *assetWriterInput;
}

@synthesize captureSession = _captureSession;
@synthesize output = _output;
@synthesize outputPath = _outputPath;

-(id)init {
    if ((self = [super init])) {
        NSArray *searchPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
        self.outputPath = [NSURL fileURLWithPath:[[searchPaths objectAtIndex:0] stringByAppendingPathComponent:@"micOutput.output"]];

        AudioChannelLayout acl;
        bzero(&acl, sizeof(acl));
        acl.mChannelLayoutTag = kAudioChannelLayoutTag_Mono; //kAudioChannelLayoutTag_Stereo;
        NSDictionary *audioOutputSettings = [NSDictionary dictionaryWithObjectsAndKeys:
                                             [NSNumber numberWithInt: kAudioFormatULaw],AVFormatIDKey,        
                                             [NSNumber numberWithFloat:8000.0],AVSampleRateKey,//was 44100.0
                                             [NSData dataWithBytes: &acl length: sizeof( AudioChannelLayout ) ], AVChannelLayoutKey,
                                             [NSNumber numberWithInt:1],AVNumberOfChannelsKey,
                                             [NSNumber numberWithInt:8000.0],AVEncoderBitRateKey,
                                             nil];

        assetWriterInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeAudio outputSettings:audioOutputSettings];
        [assetWriterInput setExpectsMediaDataInRealTime:YES];

        assetWriter = [[AVAssetWriter assetWriterWithURL:_outputPath fileType:AVFileTypeWAVE error:nil] retain];
        [assetWriter addInput:assetWriterInput];
    }
    return self;
}

-(void)dealloc {
    [assetWriter release];
    [super dealloc];
}

//conveniance methods

-(void)playMode
{
    [self stopRecording];

    NSError *error;
    AVAudioPlayer * audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:self.outputPath error:&error];
    audioPlayer.numberOfLoops = -1;

    if (audioPlayer == nil){
        NSLog(@"error: %@",[error description]);        
    }else{ 
        NSLog(@"playing");  
        [audioPlayer play];
    }
}

-(void)recordMode
{
        [self beginStreaming];    
}

-(void)stopRecording
{
    [self.captureSession stopRunning];
    [assetWriterInput markAsFinished];
    [assetWriter  finishWriting];

    NSDictionary *outputFileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:[NSString stringWithFormat:@"%@",self.outputPath] error:nil];
    NSLog (@"done. file size is %llu", [outputFileAttributes fileSize]);
}

//starts audio recording
-(void)beginStreaming {
    self.captureSession = [[AVCaptureSession alloc] init];
    AVCaptureDevice *audioCaptureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];
    NSError *error = nil;
    AVCaptureDeviceInput *audioInput = [AVCaptureDeviceInput deviceInputWithDevice:audioCaptureDevice error:&error];
    if (audioInput)
        [self.captureSession addInput:audioInput];
    else {
        NSLog(@"No audio input found.");
        return;
    }

    AVCaptureAudioDataOutput *output = [[AVCaptureAudioDataOutput alloc] init];

    dispatch_queue_t outputQueue = dispatch_queue_create("micOutputDispatchQueue", NULL);
    [output setSampleBufferDelegate:self queue:outputQueue];
    dispatch_release(outputQueue);

    [self.captureSession addOutput:output];
    [assetWriter startWriting];
    [self.captureSession startRunning];
}

//callback
-(void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection {
    AudioBufferList audioBufferList;
    NSMutableData *data= [[NSMutableData alloc] init];
    CMBlockBufferRef blockBuffer;
    CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(sampleBuffer, NULL, &audioBufferList, sizeof(audioBufferList), NULL, NULL, 0, &blockBuffer);

    //for (int y = 0; y < audioBufferList.mNumberBuffers; y++) {
    //  AudioBuffer audioBuffer = audioBufferList.mBuffers[y];
    //  Float32 *frame = (Float32*)audioBuffer.mData;
    //          
    //  [data appendBytes:frame length:audioBuffer.mDataByteSize];
    //}

    // append [data bytes] to your NSOutputStream 


    // These two lines write to disk, you may not need this, just providing an example
    [assetWriter startSessionAtSourceTime:CMSampleBufferGetPresentationTimeStamp(sampleBuffer)];
    [assetWriterInput appendSampleBuffer:sampleBuffer];

    CFRelease(blockBuffer);
    blockBuffer=NULL;
    [data release];
}

@end

【问题讨论】:

  • 请再次检查代码,如果调用返回一些错误信息,如BOOL 状态或NSError,请检查或记录它。这将使您更接近问题的根源。你的回调被调用了吗?
  • 是的,我确实知道很多,因为我曾经让它将音频数据发送到另一个类以流式传输该音频数据。它会被一致地调用。就像我说的那样,这是一个愚蠢的版本,所以我删除了它。无论哪种方式,我都会通过这个并添加一些像你说的东西,谢谢你的建议
  • 嗯,如果我把 NSLog(@"number of buffers %d",y);在回调中的 for 循环中,它始终为 0。这意味着 mNumberBuffers 也是 0
  • 看起来像这样 (stackoverflow.com/a/4299665/530933) 可能是我的问题所在。看起来样本是 8 位的吧?
  • 好吧,它不是 8bits - NSLog(@"size of buffer %lu",audioBuffer.mDataByteSize); = 2048

标签: ios audio avassetwriter


【解决方案1】:

根据 Apple 支持:

因此这是错误 - 文件已创建,许多示例已成功写入,然后附加开始由于某种未知原因而失败。

似乎 AVAssetWriter 仅在这些设置下失败。

AudioQueue 应该用于 ulaw 音频

【讨论】:

  • Apple 修复过这个错误吗?
  • 真的不知道在这么晚的日期我没有办法检查。如果这些东西真的给您带来问题,建议您使用 Apple 提供的免费开发支持案例之一
  • @TigerCoding Apple 修复过错误吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-03
  • 1970-01-01
  • 2013-02-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多