繁体   English   中英

使用ffmpeg和AVAudioPlayer播放音频

[英]Playing audio using ffmpeg and AVAudioPlayer

我正在尝试使用ffmpeg读取音频文件(iOS不支持),然后使用AVAudioPlayer播放它。 我花了一段时间才能在iOS项目中构建ffmpeg,但是最终我还是使用kewlbear / FFmpeg-iOS-build-script

经过大量的网络搜索,包括stackoverflow,这是我现在的片段。 我发现的最好的例子之一就是这里

我相信这是所有相关的代码。 我添加了评论,以使您知道我在做什么以及我需要在哪里进行一些聪明的事情。

#import "FFmpegWrapper.h"
#import <AVFoundation/AVFoundation.h>

AVFormatContext *formatContext = NULL;
AVStream *audioStream = NULL;

av_register_all();
avformat_network_init();
avcodec_register_all();

// this is a file locacted on my NAS
int opened = avformat_open_input(&formatContext, @"http://192.168.1.70:50002/m/NDLNA/43729.flac", NULL, NULL);

// can't open file
if(opened == 1) {
    avformat_close_input(&formatContext);
}

int streamInfoValue = avformat_find_stream_info(formatContext, NULL);

// can't open stream
if (streamInfoValue < 0)
{
    avformat_close_input(&formatContext);
}

// number of streams available
int inputStreamCount = formatContext->nb_streams;

for(unsigned int i = 0; i<inputStreamCount; i++)
{
    // I'm only interested in the audio stream
    if(formatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
    {
        // found audio stream
        audioStream = formatContext->streams[i];
    }
}

if(audioStream == NULL) {
    // no audio stream        
}

AVFrame* frame = av_frame_alloc();

AVCodecContext* codecContext = audioStream->codec;

codecContext->codec = avcodec_find_decoder(codecContext->codec_id);
if (codecContext->codec == NULL)
{
    av_free(frame);
    avformat_close_input(&formatContext);
    // no proper codec found
}
else if (avcodec_open2(codecContext, codecContext->codec, NULL) != 0)
{
    av_free(frame);
    avformat_close_input(&formatContext);
    // could not open the context with the decoder
}

// this is displaying: This stream has 2 channels and a sample rate of 44100Hz
// which makes sense
NSLog(@"This stream has %d channels and a sample rate of %dHz", codecContext->channels, codecContext->sample_rate);

AVPacket packet;
av_init_packet(&packet);

// this is where I try to store in the sound data
NSMutableData *soundData = [[NSMutableData alloc] init];

while (av_read_frame(formatContext, &packet) == 0)
{
    if (packet.stream_index == audioStream->index)
    {
        // Try to decode the packet into a frame
        int frameFinished = 0;
        avcodec_decode_audio4(codecContext, frame, &frameFinished, &packet);

        // Some frames rely on multiple packets, so we have to make sure the frame is finished before
        // we can use it
        if (frameFinished)
        {
            // this is where I think something clever needs to be done
            // I need to store some bytes, but I can't figure out what exactly and what length?
            // should the length be multiplied by the of the number of channels?
            NSData *frameData = [[NSData alloc] initWithBytes:packet.buf->data length:packet.buf->size];
            [soundData appendData: frameData];
        }
    }

    // You *must* call av_free_packet() after each call to av_read_frame() or else you'll leak memory
    av_free_packet(&packet);
}

// first try to write it to a file, see if that works
// this is indeed writing bytes, but it is unplayable
[soundData writeToFile:@"output.wav" atomically:YES];

NSError *error;

// this is my final goal, playing it with the AVAudioPlayer, but this is giving unclear errors
AVAudioPlayer *player = [[AVAudioPlayer alloc] initWithData:soundData error:&error];

if(player == nil) {
    NSLog(error.description); // Domain=NSOSStatusErrorDomain Code=1954115647 "(null)"
} else {
    [player prepareToPlay];
    [player play]; 
}

// Some codecs will cause frames to be buffered up in the decoding process. If the CODEC_CAP_DELAY flag
// is set, there can be buffered up frames that need to be flushed, so we'll do that
if (codecContext->codec->capabilities & CODEC_CAP_DELAY)
{
    av_init_packet(&packet);
    // Decode all the remaining frames in the buffer, until the end is reached
    int frameFinished = 0;
    while (avcodec_decode_audio4(codecContext, frame, &frameFinished, &packet) >= 0 && frameFinished)
    {
    }
}

av_free(frame);
avcodec_close(codecContext);

avformat_close_input(&formatContext);

尚未真正找到解决此特定问题的解决方案,但最终改用ap4y / OrigamiEngine 我想使用FFmpeg的主要原因是要在iOS和tvOS上播放不受支持的音频文件(FLAC / OGG),而OrigamiEngine可以正常工作。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM