【问题标题】:Playing audio using ffmpeg and AVAudioPlayer使用 ffmpeg 和 AVAudioPlayer 播放音频
【发布时间】:2016-05-13 14:48:41
【问题描述】:

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

这是我现在拥有的 sn-p,在网络上进行了大量搜索后,包括 stackoverflow。我发现的最好的例子之一是here

我相信这是所有相关的代码。我添加了 cmets 是为了让您知道我在做什么以及我需要在哪里发生一些聪明的事情。

#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);

【问题讨论】:

    标签: ios objective-c xcode ffmpeg flac


    【解决方案1】:

    并没有真正找到解决这个特定问题的方法,但最终改用ap4y/OrigamiEngine。 我想使用 FFmpeg 的主要原因是在 iOS 和 tvOS 上播放不受支持的音频文件 (FLAC/OGG),而 OrigamiEngine 可以很好地完成这项工作。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-27
      • 2012-09-07
      • 2016-12-10
      相关资源
      最近更新 更多