如何在 iOS 中添加带有 PCM 数据/缓冲区的可播放(例如 wav、wmv)标头? [英] How to add playable(such as wav,wmv) header with PCM data/buffer in iOS?

查看:13
本文介绍了如何在 iOS 中添加带有 PCM 数据/缓冲区的可播放(例如 wav、wmv)标头?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在原始 PCM 数据之上添加 wav 标头,以使其可通过 AVAudioPlayer 播放.但是我找不到任何解决方案或源代码来使用 Objective-C/Swift 在 iOS 上做到这一点.虽然我发现 this 但它没有正确答案.

I am trying to add a wav header on top of raw PCM data to make it playable via AVAudioPlayer. But i couldn't find any solution or source code to do that on iOS using Objective-C/Swift. Though i found this but it doesn't have correct answer.

但我发现了一段代码 here 是 C 语言,也包含一些问题.从该代码生成的 wav 文件无法正常播放.

But i found a piece of code here which is in C and also contains some issue. The wav file doesn't play properly which is generated from that code.

我已经在下面给出了我迄今为止编码的代码.

I have given my codes below which i have coded so far.

int NumChannels = AUDIO_CHANNELS_PER_FRAME;
short BitsPerSample = AUDIO_BITS_PER_CHANNEL;
int SamplingRate = AUDIO_SAMPLE_RATE;
int numOfSamples = [[NSData dataWithContentsOfFile:filePath] length];

int ByteRate = NumChannels*BitsPerSample*SamplingRate/8;
short BlockAlign = NumChannels*BitsPerSample/8;
int DataSize = NumChannels*numOfSamples*BitsPerSample/8;
int chunkSize = 16;
int totalSize = 36 + DataSize;
short audioFormat = 1;

if((fout = fopen([wavFilePath cStringUsingEncoding:1], "w")) == NULL)
{
    printf("Error opening out file ");
}

fwrite("RIFF", sizeof(char), 4,fout);
fwrite(&totalSize, sizeof(int), 1, fout);
fwrite("WAVE", sizeof(char), 4, fout);
fwrite("fmt ", sizeof(char), 3, fout);
fwrite(&chunkSize, sizeof(int),1,fout);
fwrite(&audioFormat, sizeof(short), 1, fout);
fwrite(&NumChannels, sizeof(short),1,fout);
fwrite(&SamplingRate, sizeof(int), 1, fout);
fwrite(&ByteRate, sizeof(int), 1, fout);
fwrite(&BlockAlign, sizeof(short), 1, fout);
fwrite(&BitsPerSample, sizeof(short), 1, fout);
fwrite("data", sizeof(char), 3, fout);
fwrite(&DataSize, sizeof(int), 1, fout);

文件播放速度太快,声音失真,仅播放前 10 到 20(大约)秒.我认为,wav 标头未正确生成(因为我能够使用 AudioUnit/AudioQueue 播放相同的 PCM 数据/缓冲区).那么我的代码中缺少什么?任何帮助将不胜感激.

The file is playing too fast, the sound is distorted and only first 10 to 20(around) seconds are playing. I think, the wav header isn't generating correctly(Because i am able to play same PCM data/buffer using AudioUnit/AudioQueue). So what i am missing in my code ? Any help would be highly appreciated.

提前致谢.

推荐答案

好的,如果它对其他人有帮助,我正在回答我自己的问题.经过几天的不懈努力,我终于让它工作了.下面是一个用 Objective-C 和 C 编写的完整函数.它以文件路径作为参数,其中包含直接从麦克风捕获的 RAW PCM 数据,并返回一个文件路径,其中包含 PCM 数据,后跟适当的 wav 标头信息.然后您可以使用 AVAudioPlayer 或 AVPlayer 播放该文件.这是代码...

OK, I am answering my own question if it helps someone else. After few days of tireless trying, at last i have got it working. Below is a complete Function written with Objective-C and C. It takes a file path as a parameter which contains RAW PCM data directly captured from microphone and returns a file path which contains PCM data followed by appropriate wav header info. Then you can play that file with AVAudioPlayer or AVPlayer. Here is the code...

- (NSURL *) getAndCreatePlayableFileFromPcmData:(NSString *)filePath
{
    NSString *wavFileName = [[filePath lastPathComponent] stringByDeletingPathExtension];
    NSString *wavFileFullName = [NSString stringWithFormat:@"%@.wav",wavFileName];

    [self createFileWithName:wavFileFullName];
    NSArray *dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *docsDir = [dirPaths objectAtIndex:0];
    NSString *wavFilePath = [docsDir stringByAppendingPathComponent:wavFileFullName];

    NSLog(@"PCM file path : %@",filePath);

    FILE *fout;

    short NumChannels = AUDIO_CHANNELS_PER_FRAME;
    short BitsPerSample = AUDIO_BITS_PER_CHANNEL;
    int SamplingRate = AUDIO_SAMPLE_RATE;
    int numOfSamples = [[NSData dataWithContentsOfFile:filePath] length];

    int ByteRate = NumChannels*BitsPerSample*SamplingRate/8;
    short BlockAlign = NumChannels*BitsPerSample/8;
    int DataSize = NumChannels*numOfSamples*BitsPerSample/8;
    int chunkSize = 16;
    int totalSize = 46 + DataSize;
    short audioFormat = 1;

    if((fout = fopen([wavFilePath cStringUsingEncoding:1], "w")) == NULL)
    {
        printf("Error opening out file ");
    }

    fwrite("RIFF", sizeof(char), 4,fout);
    fwrite(&totalSize, sizeof(int), 1, fout);
    fwrite("WAVE", sizeof(char), 4, fout);
    fwrite("fmt ", sizeof(char), 4, fout);
    fwrite(&chunkSize, sizeof(int),1,fout);
    fwrite(&audioFormat, sizeof(short), 1, fout);
    fwrite(&NumChannels, sizeof(short),1,fout);
    fwrite(&SamplingRate, sizeof(int), 1, fout);
    fwrite(&ByteRate, sizeof(int), 1, fout);
    fwrite(&BlockAlign, sizeof(short), 1, fout);
    fwrite(&BitsPerSample, sizeof(short), 1, fout);
    fwrite("data", sizeof(char), 4, fout);
    fwrite(&DataSize, sizeof(int), 1, fout);

    fclose(fout);

    NSMutableData *pamdata = [NSMutableData dataWithContentsOfFile:filePath];
    NSFileHandle *handle;
    handle = [NSFileHandle fileHandleForUpdatingAtPath:wavFilePath];
    [handle seekToEndOfFile];
    [handle writeData:pamdata];
    [handle closeFile];

    return [NSURL URLWithString:wavFilePath];
}

但该功能仅适用于以下音频设置.

But that function only works with the following audio settings.

// Audio settings.
#define AUDIO_SAMPLE_RATE 8000
#define AUDIO_FRAMES_PER_PACKET 1
#define AUDIO_CHANNELS_PER_FRAME 1
#define AUDIO_BITS_PER_CHANNEL 16
#define AUDIO_BYTES_PER_PACKET 2
#define AUDIO_BYTES_PER_FRAME 2

这篇关于如何在 iOS 中添加带有 PCM 数据/缓冲区的可播放(例如 wav、wmv)标头?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆