2016-02-04 4 views
2

Я пытаюсь читать аудиофайл (который не поддерживается iOS) с помощью ffmpeg, а затем воспроизводить его с помощью AVAudioPlayer. Мне потребовалось некоторое время, чтобы получить ffmpeg, встроенный в проект iOS, но я, наконец, использовал kewlbear/FFmpeg-iOS-build-script.Воспроизведение аудио с использованием ffmpeg и AVAudioPlayer

Это фрагмент, который у меня есть сейчас, после многого поиска в Интернете, включая stackoverflow. Одним из лучших примеров я нашел here.

Я считаю, что это все соответствующий код. Я добавил комментарии, чтобы вы знали, что я делаю, и где мне нужно что-то умное.

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

ответ

0

Не действительно нашел решение этой конкретной проблемы, но в конечном итоге с помощью ap4y/OrigamiEngine вместо этого. Моя основная причина, по которой я хотел использовать FFmpeg, - это воспроизведение неподдерживаемых аудиофайлов (FLAC/OGG) на iOS и tvOS, а OrigamiEngine отлично справляется с этой задачей.

Смежные вопросы