演示ios平台上的amr音频转码

来源:互联网 发布:java搜索引擎源代码 编辑:程序博客网 时间:2024/05/17 20:29
/*
 * 代码演示了:1.怎么使用ffmpeg;2.从确定格式到找到编解码器的过程;3.怎么解码一个音频;4.怎么编码出一个音频;
 * 实现把一个音频文件转码成amr文件
 * 只作为流程演示,细致有可能需要再作考虑
 **/


#import "ViewController.h"


extern "C" {
#include "ffmpeg/include/libavcodec/avcodec.h"
#include "ffmpeg/include/libavformat/avformat.h"
#include "ffmpeg/include/libswresample/swresample.h"
}


@interface ViewController ()
{
    AVFormatContext* _inFormatContext;
    AVFormatContext* _outFormatContext;
    AVCodecContext* _inCodecContext;
    AVCodecContext* _outCodecContext;
    AVCodec* _inCodec;
    AVCodec* _outCodec;
    SwrContext *_swr;
    int _audiostream_index;
    NSString* _infilepath;
};


@end


@implementation ViewController


- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    
//    NSString *nofoundfile = [NSHomeDirectory() stringByAppendingString:@"/Documents/allfile.txt"];
//    NSMutableArray* filearry = [[NSMutableArray alloc]initWithCapacity:400];
//    FILE* file = fopen([nofoundfile UTF8String], "r");
//    if (file) {
//        char temp[64] = {0};
//        while (fgets(temp, 63, file) != NULL) {
//            temp[strlen(temp)-1] = 0;
//            [filearry addObject:[NSString stringWithUTF8String:temp]];
//        }
//        fclose(file);
//    }
//    
//    if ([filearry count] > 0) {
//        NSString *dirPath = [NSHomeDirectory() stringByAppendingString:@"/Documents/music"];
//        NSString *realPath = [dirPath stringByExpandingTildeInPath];
//        NSFileManager *fileMgr = [NSFileManager defaultManager];
//        NSDirectoryEnumerator *fileEnum = [fileMgr enumeratorAtPath:realPath];
//        NSString *filename = [fileEnum nextObject];
//        while (filename) {
//            BOOL found = NO;
//            for (NSString* file in filearry) {
//                if ([file isEqualToString:filename]) {
//                    found = YES;
//                    break;
//                }
//            }
//            if (found) {
//                NSString *fullPath = [NSString stringWithFormat:@"%@/%@", realPath, filename];
//                [[NSFileManager defaultManager]removeItemAtPath:fullPath error:nil];
//            }
//            
//            filename = [fileEnum nextObject];
//        }
//    }
}


- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}


- (BOOL)openInCodec
{
    NSString* inpath = _infilepath;
    BOOL openSuccess = NO;
    int audio_stream_index = -1;
    do {
        _inFormatContext = avformat_alloc_context();
        int ret = avformat_open_input(&_inFormatContext, [inpath UTF8String], NULL, NULL);
        if (ret != 0) {
            NSLog(@"open input failed");
            break;
        }
        ret = avformat_find_stream_info(_inFormatContext, NULL);
        if (ret < 0) {
            NSLog(@"find stream info failed");
            break;
        }
        for (int pos = 0; pos < _inFormatContext->nb_streams; pos ++) {
            if (_inFormatContext->streams[pos]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
                audio_stream_index = pos;
                break;
            }
        }
        if (audio_stream_index == -1) {
            NSLog(@"no audio stream");
            break;
        }
        
        _inCodecContext = _inFormatContext->streams[audio_stream_index]->codec;
        _inCodec = avcodec_find_decoder(_inCodecContext->codec_id);
        if (_inCodec == NULL) {
            NSLog(@"no avcodec found");
            _inCodecContext = NULL;
            break;
        }
        ret = avcodec_open2(_inCodecContext, _inCodec, NULL);
        if (ret != 0) {
            NSLog(@"open codec failed");
            _inCodecContext = NULL;
            break;
        }
        _audiostream_index = audio_stream_index;
        
        openSuccess = YES;
    }while (0);
    
    if (!openSuccess) {
        [self destroyffmpeg];
    }
    
    return openSuccess;
}


- (BOOL)openOutCodec
{
    NSString* outpath = [NSHomeDirectory()stringByAppendingString:@"/Documents/out.amr"];
    NSString* outfilepath = outpath;
    BOOL openSuccess = NO;
    do {
        int ret = avformat_alloc_output_context2(&_outFormatContext, NULL, "amr", [outfilepath UTF8String]);
        if (ret < 0) {
            NSLog(@"alloc output format failed");
            break;
        }
        AVOutputFormat* outFormat = _outFormatContext->oformat;
        outFormat->audio_codec = AV_CODEC_ID_AMR_NB;
        outFormat->video_codec = AV_CODEC_ID_NONE;
        
        _outCodec = avcodec_find_encoder(outFormat->audio_codec);
        if (_inCodec == NULL) {
            NSLog(@"no encoder found");
            break;
        }
        AVStream* audioStream = avformat_new_stream(_outFormatContext, _outCodec);
        if (audioStream == NULL) {
            NSLog(@"new stream failed");
            break;
        }
        audioStream->id = 0;
        audioStream->index = 0;
        _outCodecContext = audioStream->codec;
        if (_outCodecContext == NULL) {
            NSLog(@"no codecContext in stream");
            break;
        }
        _outCodecContext->sample_fmt = AV_SAMPLE_FMT_S16;
        _outCodecContext->channels = 1;
        _outCodecContext->channel_layout = av_get_default_channel_layout(1);
        _outCodecContext->sample_rate = 8000;
        _outCodecContext->bit_rate = 12200;
        if (outFormat->flags & AVFMT_GLOBALHEADER) {
            _outCodecContext->flags |= CODEC_FLAG_GLOBAL_HEADER;
        }
        
        ret = avcodec_open2(_outCodecContext, _outCodec, NULL);
        if (ret < 0) {
            NSLog(@"open encoder failed");
            break;
        }
        
        av_dump_format(_outFormatContext, 0, [outfilepath UTF8String], 1);
        
        if (!(_outFormatContext->flags & AVFMT_NOFILE)) {
            ret = avio_open2(&_outFormatContext->pb, [outfilepath UTF8String], AVIO_FLAG_WRITE, &_outFormatContext->interrupt_callback, NULL);
            if (ret < 0) {
                NSLog(@"avio_open2 failed: %d(%s)", ret, av_err2str(ret));
                break;
            }
        }
        
        AVDictionary* dict = NULL;
        ret = avformat_write_header(_outFormatContext, &dict);
        if (ret < 0) {
            NSLog(@"write header failed: %d(%s)", ret, av_err2str(ret));
            break;
        }
        
        openSuccess = YES;
    }while (0);
    
    if (!openSuccess) {
        [self destroyffmpeg];
    }
    
    return openSuccess;
}


- (void)deletetSwr
{
    if (_swr) {
        swr_free(&_swr);
        _swr = NULL;
    }
}


- (void)convert
{
    BOOL eof = NO;
    while (1) {
        AVPacket packet;
        int ret = av_read_frame(_inFormatContext, &packet);
        if (ret < 0) {
            if (ret == AVERROR_EOF || url_feof(_inFormatContext->pb)) {
                NSLog(@"read_frame eof");
                eof = YES;
                break;
            }
            else {
                NSLog(@"av_read_frame failed, %d(%s)", ret, av_err2str(ret));
                break;
            }
        }
        
        if (packet.stream_index == _audiostream_index) {
            int size = packet.size;
            AVFrame frame;
            AVPacket encodePacket;
            void* out_buffer = NULL;
            while (size > 0) {
//                av_frame_unref(&frame);
                int gotframe = 0;
                int len = avcodec_decode_audio4(_inCodecContext, &frame, &gotframe, &packet);
                if (len < 0) {
                    NSLog(@"audio decode failed");
                    break;
                }
                if (gotframe) {
                    bool needConvert = true;
                    int targetSampelrate = 8000;
                    int targetChannels = 1;
                    if (needConvert)  {
                        int out_size = av_samples_get_buffer_size(NULL, targetChannels, frame.nb_samples, AV_SAMPLE_FMT_S16, 0);
                        if (out_size >= 0) {
//                            if (_swr) {  // more think here for if
//                                [self deletetSwr];
//                            }
                            bool initswr = true;
                            if (_swr == NULL) {
                                uint64_t in_channel_layout = av_get_default_channel_layout(av_frame_get_channels(&frame));
                                uint64_t out_channel_layout = av_get_default_channel_layout(targetChannels);
                                int inSamplerate = frame.sample_rate;
                                _swr = swr_alloc_set_opts(NULL,
                                                          out_channel_layout, (enum AVSampleFormat )AV_SAMPLE_FMT_S16, targetSampelrate,
                                                          in_channel_layout, (enum AVSampleFormat)frame.format, inSamplerate, 0, NULL);
                                int ret = swr_init(_swr);
                                if (ret != 0) {
                                    initswr = false;
                                }
                            }
                            if (_swr && initswr) {
                                if (frame.extended_data && frame.data[0] && frame.linesize[0] > 0) {
                                    out_buffer = av_malloc(out_size);
                                    if (out_buffer) {
                                        int convertSamples = swr_convert(_swr, (uint8_t**)(&out_buffer), frame.nb_samples, (const uint8_t**)frame.extended_data, frame.nb_samples);
                                        int len = convertSamples * targetChannels * av_get_bytes_per_sample(AV_SAMPLE_FMT_S16);
                                        
                                        int nb_samples = _outCodecContext->frame_size / 1;
                                        int buffer_size = av_samples_get_buffer_size( NULL, _outCodecContext->channels, nb_samples, AV_SAMPLE_FMT_S16, 0 );
                                        
                                        AVFrame* decodeframe = avcodec_alloc_frame();
                                        decodeframe->nb_samples = nb_samples;
                                        ret = avcodec_fill_audio_frame( decodeframe, _outCodecContext->sample_fmt, AV_SAMPLE_FMT_S16, (const uint8_t *)out_buffer, buffer_size, 0 );
                                        
                                        
                                        if( ret < 0 )
                                        {
                                            NSLog( @"avcodec_fill_audio_frame error!");
                                            break;
                                        }
                                        
                                        encodePacket.data = NULL;
                                        encodePacket.size = 0;
                                        av_init_packet(&encodePacket);
                                        ret = avcodec_encode_audio2(_outCodecContext, &encodePacket, decodeframe, &gotframe);
                                        if (ret < 0) {
                                            NSLog(@"encode audio fail: %d(%s)", ret, av_err2str(ret));
                                            break;
                                        }
                                        if (gotframe == 0) {
                                            NSLog(@"did not got frame");
                                            break;
                                        }
                                        encodePacket.stream_index = 0;
                                        ret = av_write_frame(_outFormatContext, &encodePacket);
                                        if (ret < 0) {
                                            NSLog(@"av_write_frame failed: %d(%s)", ret, av_err2str(ret));
                                            break;
                                        }
                                        
                                        size -= len;
                                    }
                                }
                            }
                        }
                    }
                }
            }
            av_free_packet(&encodePacket);
            if (out_buffer) {
                av_free(out_buffer);
            }
        }
    }
    if (eof) {
        av_write_trailer(_outFormatContext);
    }
}


- (void)ffmpegInit
{
    static int times = 0;
    if (times == 0) {
        times = 1;
        av_register_all();
        avcodec_register_all();
    }
}


- (void)destroyffmpeg
{
    if (_inFormatContext) {
        avformat_close_input(&_inFormatContext);
        avformat_free_context(_inFormatContext);
        _inFormatContext = NULL;
    }
    if (_outFormatContext) {
        avformat_free_context(_outFormatContext);
        _outFormatContext = NULL;
    }
    if (_inCodecContext) {
        avcodec_close(_inCodecContext);
        _inCodecContext = NULL;
    }
    if (_outCodecContext) {
        avcodec_close(_outCodecContext);
        _outCodecContext = NULL;
    }
    [self deletetSwr];
    _audiostream_index = -1;
}


-(IBAction)amrConvertBtnClicked:(id)sender
{
    NSLog(@"amr convert start");
    
    NSString *dir = [[[NSBundle mainBundle] resourcePath] stringByAppendingFormat:@"/music"];
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSArray *arrFiles = [fileManager subpathsAtPath:dir];
    if ([arrFiles count] <= 0) {
        NSLog(@"no src file");
        return;
    }
    NSString *path = [NSString stringWithFormat:@"%@/%@",dir,[arrFiles objectAtIndex:0]];
    _infilepath = [[NSString alloc]initWithString:path];
    
    [self ffmpegInit];
    [self destroyffmpeg];
    
    if ([self openInCodec]) {
        if ([self openOutCodec]) {
            [self convert];
        }
    }
}


@end
0 0
原创粉丝点击