• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

FFmpeg AAC 解码 PCM

武飞扬头像
Hanyang Li
帮助5

1. 概要与流程图

  1.1 AAC 转 PCM,需要解码库来实现,目前了解有三种方式,当前使用的是 FFmpeg 库解码

    1) faad    解码库网址:faad学新通https://sourceforge.net/projects/faac/files/faad2-src/

    2) fdk-aac 编解码库网址: fdk-aac学新通https://sourceforge.net/projects/opencore-amr/files/fdk-aac/

    3) FFmpeg  网址:ffmpeg学新通http://ffmpeg.org/download.html

  1.2 流程图: 

学新通

2. 封装解码管理器

  2.1 创建头文件,AACToPCMDeCoder.h

  1.  
    #import <Foundation/Foundation.h>
  2.  
     
  3.  
    NS_ASSUME_NONNULL_BEGIN
  4.  
     
  5.  
    @interface AACToPCMDeCoder : NSObject
  6.  
     
  7.  
    - (int) init:(const char *)inputFilePath outputFilePath:(const char *)outputFilePath;
  8.  
     
  9.  
    - (void)convertToPCM:(const uint8_t*)data withSize:(int) size;
  10.  
     
  11.  
    - (void)stop;
  12.  
     
  13.  
    @end
  14.  
     
  15.  
    NS_ASSUME_NONNULL_END
学新通

  2.2 实现头文件,AACToPCMDeCoder.m

  1.  
    #import "AACToPCMDeCoder.h"
  2.  
    #import "avformat.h"
  3.  
    #import "swscale.h"
  4.  
    #import "swresample.h"
  5.  
    #import "imgutils.h"
  6.  
    #import "FileTool.h"
  7.  
     
  8.  
    @interface AACToPCMDeCoder(){
  9.  
    AVFormatContext *format_ctx;
  10.  
    AVCodecContext *codec_ctx;
  11.  
    AVCodec *codec;
  12.  
    AVPacket *packet;
  13.  
    struct SwrContext *swr_ctx;
  14.  
    AVCodecParserContext *codec_parser_ctx;
  15.  
    AVFrame *frame_src;
  16.  
    FileTool *file_tool;
  17.  
    uint8_t *buffer_src;
  18.  
    int nb_samples;
  19.  
    int buffer_size;
  20.  
    }
  21.  
     
  22.  
    @end
  23.  
     
  24.  
    @implementation AACToPCMDeCoder
  25.  
     
  26.  
    /// 初始化
  27.  
    /// - Parameters:
  28.  
    /// - inputFilePath: 输入文件路近
  29.  
    /// - outputFilePath: 输出文件路径
  30.  
    - (int)init:(const char *)inputFilePath outputFilePath:(const char *)outputFilePath{
  31.  
    format_ctx = NULL;
  32.  
    codec = NULL;
  33.  
    codec_ctx = NULL;
  34.  
    codec_parser_ctx = NULL;
  35.  
    frame_src = NULL;
  36.  
    swr_ctx = NULL;
  37.  
    file_tool = NULL;
  38.  
    buffer_src = NULL;
  39.  
    nb_samples = 0;
  40.  
    buffer_size = 0;
  41.  
    // 获取输入文件的 AVFormatContext
  42.  
    int ret = avformat_open_input(&format_ctx, inputFilePath, NULL, NULL);
  43.  
    if(ret < 0){
  44.  
    fprintf(stderr, "avformat_open_input function open failed. \n");
  45.  
    return ret;
  46.  
    }
  47.  
    // 获取流信息
  48.  
    ret = avformat_find_stream_info(format_ctx, NULL);
  49.  
    if(ret < 0){
  50.  
    fprintf(stderr, "avformat_find_stream_info function find failed. \n");
  51.  
    return ret;
  52.  
    }
  53.  
    // 获取音频流下标
  54.  
    int index = av_find_best_stream(format_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);
  55.  
    if(index < 0){
  56.  
    fprintf(stderr, "av_find_best_stream function find strean failed. \n");
  57.  
    return -1;
  58.  
    }
  59.  
    // 获取解码器上下文
  60.  
    codec_ctx = avcodec_alloc_context3(NULL);
  61.  
    if(!codec_ctx){
  62.  
    fprintf(stderr, "avcodec_alloc_context3 function failed. \n");
  63.  
    return -1;
  64.  
    }
  65.  
     
  66.  
    //codec_ctx->pkt_timebase = format_ctx->streams[index]->time_base;
  67.  
    // 视频流信息赋值到 CodecContext stream->codecpar
  68.  
    ret = avcodec_parameters_to_context(codec_ctx, format_ctx->streams[index]->codecpar);
  69.  
    if(ret < 0){
  70.  
    fprintf(stderr, "avcodec_parameters_to_context function failed. \n");
  71.  
    return ret;
  72.  
    }
  73.  
    // 查找解码器
  74.  
    codec = avcodec_find_decoder(codec_ctx->codec_id);
  75.  
    if(!codec){
  76.  
    fprintf(stderr, "avcodec_find_decoder function find failed. \n");
  77.  
    return -1;
  78.  
    }
  79.  
     
  80.  
    // 打开解码器
  81.  
    ret = avcodec_open2(codec_ctx, codec, NULL);
  82.  
    if(ret < 0){
  83.  
    fprintf(stderr, "avcodec_open2 function open failed. \n");
  84.  
    return ret;
  85.  
    }
  86.  
     
  87.  
    // 初始化 Codec 内容解析器,用于传输的数据缓存
  88.  
    codec_parser_ctx = av_parser_init(codec_ctx->codec_id);
  89.  
    if(!codec_parser_ctx){
  90.  
    fprintf(stderr, "av_parser_init function failed. \n");
  91.  
    return -1;
  92.  
    }
  93.  
     
  94.  
    // 初始化传输的数据整理为包
  95.  
    packet = av_packet_alloc();
  96.  
    if(!packet){
  97.  
    fprintf(stderr, "av_packet_alloc function failed. \n");
  98.  
    return -1;
  99.  
    }
  100.  
     
  101.  
    // 初始化 frame,用于存储解码后的数据
  102.  
    frame_src = av_frame_alloc();
  103.  
    if(!frame_src){
  104.  
    fprintf(stderr, "av_frame_alloc function frame failed. \n");
  105.  
    return -1;
  106.  
    }
  107.  
    frame_src->format = AV_SAMPLE_FMT_S16; // 采样格式 AV_SAMPLE_FMT_S16
  108.  
    frame_src->channels = codec_ctx->channels; // 通道数
  109.  
    frame_src->channel_layout = codec_ctx->channel_layout; // 声道布局
  110.  
    frame_src->sample_rate = codec_ctx->sample_rate; // 采样率
  111.  
    frame_src->nb_samples = codec_ctx->frame_size; // 样本
  112.  
    ret = av_frame_get_buffer(frame_src, 0); // 获取 s16 格式帧数据
  113.  
    if(ret < 0){
  114.  
    fprintf(stderr, "frame_s16 av_frame_get_buffer function failed \n");
  115.  
    return ret;
  116.  
    }
  117.  
    // 转换写文件的 frame_s16->nb_samples * av_get_bytes_per_sample(frame_s16->format) * frame_s16->channels
  118.  
    // 解码后 pcm 大小 buffer 4096
  119.  
    buffer_size = av_samples_get_buffer_size(&nb_samples, frame_src->channels, frame_src->nb_samples, frame_src->format, 0);
  120.  
    // 解码一帧的数据
  121.  
    buffer_src = av_malloc(buffer_size);
  122.  
     
  123.  
    // 获取 samples 4096
  124.  
    // nb_samples = av_samples_alloc(&buffer_src, NULL, frame_src->channels, frame_src->nb_samples, frame_src->format, 0);
  125.  
     
  126.  
    // 重采样
  127.  
    // 获取转换帧内容
  128.  
    swr_ctx = swr_alloc_set_opts(NULL,
  129.  
    frame_src->channel_layout,
  130.  
    frame_src->format,
  131.  
    frame_src->sample_rate,
  132.  
    codec_ctx->channel_layout,
  133.  
    codec_ctx->sample_fmt,
  134.  
    codec_ctx->sample_rate,
  135.  
    0, NULL);
  136.  
    ret = swr_init(swr_ctx);
  137.  
    if(ret < 0){
  138.  
    fprintf(stderr, "sws_getContext function failed. \n");
  139.  
    return ret;
  140.  
    }
  141.  
     
  142.  
    // 创建输出文件
  143.  
    file_tool = [[FileTool alloc]init];
  144.  
    // 打开输出文件
  145.  
    ret = (int)[file_tool open:outputFilePath model: FILE_MODE_WRITE];
  146.  
    if(ret < 0){
  147.  
    fprintf(stderr, "Open output file failed. \n");
  148.  
    return ret;
  149.  
    }
  150.  
     
  151.  
    // 打印输入流信息
  152.  
    av_dump_format(format_ctx, 0, inputFilePath, 0);
  153.  
    // 打印输出流信息
  154.  
    printf("Output\n%s\n",outputFilePath);
  155.  
    printf("AACToPCMDeCoder init success.\n");
  156.  
    return ret;
  157.  
    }
  158.  
     
  159.  
    /// 解码
  160.  
    /// - Parameters:
  161.  
    /// - data: 数据 ( AAC)
  162.  
    /// - size: 数据大小
  163.  
    - (void)convertToPCM:(const uint8_t *)data withSize:(int)size{
  164.  
    int current_size = size;
  165.  
    while (current_size > 0) {
  166.  
    int parser_size = av_parser_parse2(codec_parser_ctx, codec_ctx, &packet->data, &packet->size,
  167.  
    data, current_size, AV_NOPTS_VALUE, AV_NOPTS_VALUE, AV_NOPTS_VALUE);
  168.  
    data = parser_size;
  169.  
    current_size -= parser_size;
  170.  
    // 判断不是一帧数据,则继续
  171.  
    if(!packet->size){
  172.  
    continue;
  173.  
    }else{
  174.  
    int ret = avcodec_send_packet(codec_ctx, packet);
  175.  
    if(ret == 0){
  176.  
    ret = avcodec_receive_frame(codec_ctx, frame_src);
  177.  
    // 编码成功
  178.  
    if(ret == 0){
  179.  
    //解码后的帧进行转换,存储
  180.  
    [self convertToPCMData:frame_src];
  181.  
    }
  182.  
    }
  183.  
    av_packet_unref(packet);
  184.  
    }
  185.  
    }
  186.  
    }
  187.  
     
  188.  
    /// 转换 PCM 数据,写入文件
  189.  
    /// - Parameter frame: 解码得到的帧
  190.  
    -(void)convertToPCMData:(AVFrame *)frame{
  191.  
    // 转换数据
  192.  
    int ret = swr_convert(swr_ctx, &buffer_src, nb_samples, (const uint8_t **)frame->data, frame->nb_samples);
  193.  
    if(ret <= 0){
  194.  
    fprintf(stderr, "swr_convert function failed. \n");
  195.  
    }
  196.  
    // 写入文件
  197.  
    [file_tool write:buffer_src length:buffer_size];
  198.  
    }
  199.  
     
  200.  
    /// 停止
  201.  
    - (void)stop{
  202.  
    // 退出循环解码时,看解码器中是否还有缓存数据,有数据继续执行解码
  203.  
    while (true) {
  204.  
    int ret = avcodec_send_packet(codec_ctx, packet);
  205.  
    if(ret != 0){
  206.  
    break;
  207.  
    }
  208.  
    ret = avcodec_receive_frame(codec_ctx, frame_src);
  209.  
    if(ret == 0){
  210.  
    //解码后的帧进行转换,存储
  211.  
    [self convertToPCMData:frame_src];
  212.  
    }
  213.  
    av_packet_unref(packet);
  214.  
    }
  215.  
    }
  216.  
     
  217.  
    /// 关闭置空数据
  218.  
    - (void)close{
  219.  
    if(codec_parser_ctx){
  220.  
    av_parser_close(codec_parser_ctx);
  221.  
    codec_parser_ctx = NULL;
  222.  
    }
  223.  
    if(codec_ctx){
  224.  
    avcodec_close(codec_ctx);
  225.  
    avcodec_free_context(&codec_ctx);
  226.  
    codec_ctx = NULL;
  227.  
    }
  228.  
    if(swr_ctx){
  229.  
    swr_free(&swr_ctx);
  230.  
    swr_ctx = NULL;
  231.  
    }
  232.  
    if(format_ctx){
  233.  
    if(format_ctx->pb){
  234.  
    avio_close(format_ctx->pb);
  235.  
    }
  236.  
    //avformat_close_input(&format_ctx);
  237.  
    avformat_free_context(format_ctx);
  238.  
    format_ctx = NULL;
  239.  
    }
  240.  
    if(packet){
  241.  
    av_packet_free(&packet);
  242.  
    packet = NULL;
  243.  
    }
  244.  
    if(frame_src){
  245.  
    av_frame_free(&frame_src);
  246.  
    frame_src = NULL;
  247.  
    }
  248.  
    if(file_tool){
  249.  
    file_tool = NULL;
  250.  
    }
  251.  
    if(buffer_src){
  252.  
    av_free(buffer_src);
  253.  
    buffer_src = NULL;
  254.  
    }
  255.  
    printf("AACToPCMDeCoder stop.\n");
  256.  
    }
  257.  
     
  258.  
    // 释放数据
  259.  
    - (void)dealloc{
  260.  
    [self close];
  261.  
    }
  262.  
     
  263.  
    @end
学新通

3. 测试函数及输出日志

  3.1 测试函数 onClickAACToPCM,ViewController.m

  1.  
    #import "ViewController.h"
  2.  
    #import "UIView Category.h"
  3.  
    #import "PathTool.h"
  4.  
    #import "FileTool.h"
  5.  
    #import "MediaFileSeparation.h"
  6.  
    #import "H264ToYUVDeCoder.h"
  7.  
    #import "YUVToH264EnCoder.h"
  8.  
    #import "YUVPlayer.h"
  9.  
    #import "AACToPCMDeCoder.h"
  10.  
     
  11.  
    @interface ViewController ()<YUVPlayerDelegate>
  12.  
    @property(nonatomic, strong) UIImageView *imageView;
  13.  
    @end
  14.  
     
  15.  
    @implementation ViewController
  16.  
    @synthesize imageView;
  17.  
     
  18.  
    - (void)viewDidLoad {
  19.  
    [super viewDidLoad];
  20.  
    }
  21.  
     
  22.  
    /// 分离视频文件
  23.  
    /// - Parameter sender: UI 按钮
  24.  
    - (IBAction)onClickMediaFileSeparation:(id)sender {
  25.  
    // 输入文件
  26.  
    NSString * inFilePath = [PathTool bundlePath:@"input.mp4"];
  27.  
    // 输出文件(一般 mp4 音频流为 aac 格式 "aac" = "adts")
  28.  
    NSString * outFilePathAudio = [PathTool documentsPath:@"output"];
  29.  
    // 输出文件(一般 mp4 视频流为 h264 或者 hevc)
  30.  
    NSString * outFilePathVideo = [PathTool documentsPath:@"output"];
  31.  
    // 创建分离视频文件类
  32.  
    __block MediaFileSeparation *mediaFileSeparation = [[MediaFileSeparation alloc] init];
  33.  
    // 初始化数据,传入输入输出文件
  34.  
    int ret = [mediaFileSeparation init: inFilePath.UTF8String videoFilePath: (char *)outFilePathAudio.UTF8String audioFilePath: (char *)outFilePathVideo.UTF8String];
  35.  
    // 当返回值小于 0 时,初始化失败
  36.  
    if(ret < 0){
  37.  
    return;
  38.  
    }
  39.  
    dispatch_async(dispatch_get_global_queue(DISPATCH_BLOCK_DETACHED, 0), ^{
  40.  
    // 循环拆分数据
  41.  
    [mediaFileSeparation convertFrames];
  42.  
    // 结束
  43.  
    [mediaFileSeparation stop];
  44.  
    // 释放数据
  45.  
    mediaFileSeparation = nil;
  46.  
    });
  47.  
    }
  48.  
     
  49.  
    /// H264 解码 YUV
  50.  
    /// - Parameter sender: UI 按钮
  51.  
    - (IBAction)onClickH264ToYUV:(id)sender {
  52.  
    // 输入文件
  53.  
    NSString *inputFilePath = [PathTool documentsPath:@"output.hevc"];
  54.  
    // 输出文件
  55.  
    NSString *outputFilePath = [PathTool documentsPath:@"output.yuv"];
  56.  
    // 初始化文件管理器
  57.  
    __block FileTool *fileTool = [[FileTool alloc] init];
  58.  
    // 打开文件
  59.  
    int ret = (int)[fileTool open:inputFilePath.UTF8String model: FILE_MODE_READ];
  60.  
    // 小于 0,打开文件异常
  61.  
    if(ret < 0){
  62.  
    return;
  63.  
    }
  64.  
    // 初始化 H264 解码 YUV 管理器
  65.  
    __block H264ToYUVDeCoder *h264ToYUVDeCoder = [[H264ToYUVDeCoder alloc]init];
  66.  
    // 传入输入输出文件路径
  67.  
    ret = [h264ToYUVDeCoder init:inputFilePath.UTF8String outputFilePath:outputFilePath.UTF8String];
  68.  
    // 当返回值小于 0 时,初始化失败
  69.  
    if(ret < 0){
  70.  
    return;
  71.  
    }
  72.  
    //Stream #0:0: Video: hevc, yuv420p(tv), 848x480, 25 fps, 25 tbr, 1200k tbn, 25 tbc
  73.  
    // __weak ViewController *vc = self;
  74.  
    // 开启子线程,进行解码操作
  75.  
    dispatch_async(dispatch_get_global_queue(DISPATCH_BLOCK_DETACHED, 0), ^{
  76.  
    // 定义输入读取数据大小
  77.  
    int length = 1024 * 6;
  78.  
    uint8_t frame[length];
  79.  
    while(true){
  80.  
    // 读取输入数据
  81.  
    int size = (int)[fileTool read:frame length:length];
  82.  
    // 读完文件,则跳出循环
  83.  
    if(size <= 0){
  84.  
    break;
  85.  
    }
  86.  
    // 解码数据
  87.  
    [h264ToYUVDeCoder convertToYUV:frame withSize:length];
  88.  
    }
  89.  
    // 停止
  90.  
    [h264ToYUVDeCoder stop];
  91.  
    // 释放解码器数据
  92.  
    h264ToYUVDeCoder = nil;
  93.  
    // 释放文件资源
  94.  
    fileTool = nil;
  95.  
    });
  96.  
    }
  97.  
     
  98.  
    /// YUV 编码 H264
  99.  
    /// - Parameter sender: UI 按钮
  100.  
    - (IBAction)onClickYUVToH264:(id)sender {
  101.  
    // 输入文件
  102.  
    NSString *inputFilePath = [PathTool documentsPath:@"output.yuv"];
  103.  
    // 输出文件
  104.  
    NSString *outputFilePath = [PathTool documentsPath:@"output.h264"];
  105.  
    // 初始化文件管理器
  106.  
    __block FileTool *fileTool = [[FileTool alloc]init];
  107.  
    // 打开文件
  108.  
    int ret = (int)[fileTool open:inputFilePath.UTF8String model:FILE_MODE_READ];
  109.  
    // 当返回值小于 0 时,初始化失败
  110.  
    if(ret < 0){
  111.  
    return;
  112.  
    }
  113.  
    // 初始化 YUV 编码 H264 管理器
  114.  
    __block YUVToH264EnCoder *yuvToH264EnCoder = [[YUVToH264EnCoder alloc]init];
  115.  
    // 传入输出文件路径,宽和高
  116.  
    ret = [yuvToH264EnCoder init: outputFilePath.UTF8String width:848 height:480];
  117.  
    // 当返回值小于 0 时,初始化失败
  118.  
    if(ret < 0){
  119.  
    return;
  120.  
    }
  121.  
    // 开启子线程,进行编码操作
  122.  
    dispatch_async(dispatch_get_global_queue(DISPATCH_BLOCK_DETACHED, 0), ^{
  123.  
    // 定义输入读取数据大小,如果根据初始化得到的 yuv 数据大小,读取 610560 个数据点,fread 会卡住,只能分段读取进行缓存处理
  124.  
    int length = 1024 * 8;
  125.  
    uint8_t frame[length];
  126.  
    while (true) {
  127.  
    // 读取输入数据
  128.  
    int size = (int)[fileTool read:frame length:length];
  129.  
    // 读完文件,则跳出循环
  130.  
    if(size <= 0){
  131.  
    break;
  132.  
    }
  133.  
    [yuvToH264EnCoder convertCacheData:frame withSize:size];
  134.  
    }
  135.  
    // 停止
  136.  
    [yuvToH264EnCoder stop];
  137.  
    // 释放解码器数据
  138.  
    yuvToH264EnCoder = nil;
  139.  
    // 释放文件资源
  140.  
    fileTool = nil;
  141.  
    });
  142.  
    }
  143.  
    /// 播放 YUV
  144.  
    /// - Parameter sender: UI 按钮
  145.  
    - (IBAction)onClickYUVPlayer:(id)sender {
  146.  
    // 输入文件
  147.  
    NSString *inputFilePath = [PathTool documentsPath:@"output.yuv"];
  148.  
    // 初始化文件管理器
  149.  
    __block FileTool *fileTool = [[FileTool alloc] init];
  150.  
    // 打开文件
  151.  
    int ret = (int)[fileTool open:inputFilePath.UTF8String model:FILE_MODE_READ];
  152.  
    // 返回值小于 0,打开文件失败
  153.  
    if(ret < 0){
  154.  
    return;
  155.  
    }
  156.  
    // 初始化 YUV 转 RGB 管理器
  157.  
    __block YUVPlayer *yuvPlayer = [[YUVPlayer alloc]init];
  158.  
    // delegate 回调
  159.  
    yuvPlayer.delegate = self;
  160.  
    // 添加 ImageView,用来播放画面
  161.  
    [self setupImageView];
  162.  
    // 传入宽高
  163.  
    ret = [yuvPlayer init:848 height:480];
  164.  
    // 返回值小于 0,初始化失败
  165.  
    if(ret < 0){
  166.  
    return;
  167.  
    }
  168.  
    // 开启子线程进行转码渲染
  169.  
    dispatch_async(dispatch_get_global_queue(DISPATCH_BLOCK_DETACHED, 0), ^{
  170.  
    // 定义输入读取数据大小
  171.  
    int length = 1024 * 8;
  172.  
    uint8_t frame[length];
  173.  
    while (true) {
  174.  
    // 读取输入数据
  175.  
    int size = (int)[fileTool read:frame length:length];
  176.  
    // 读完文件,则跳出循环
  177.  
    if(size <= 0){
  178.  
    break;
  179.  
    }
  180.  
    // 缓存并播放数据
  181.  
    [yuvPlayer cacheData:frame withSize:size];
  182.  
    }
  183.  
    // 释放播放器数据
  184.  
    yuvPlayer = nil;
  185.  
    // 释放文件资源
  186.  
    fileTool = nil;
  187.  
    });
  188.  
    }
  189.  
     
  190.  
    // ImageView
  191.  
    -(void)setupImageView{
  192.  
    if(!imageView){
  193.  
    CGFloat width = 320;
  194.  
    CGFloat height = 180;
  195.  
    CGFloat x = (self.view.width - width) * 0.5;
  196.  
    CGFloat y = (self.view.height - height) * 0.85;
  197.  
    // 显示画面
  198.  
    imageView = [[UIImageView alloc]initWithFrame:CGRectMake(x, y, width, height)];
  199.  
    imageView.backgroundColor = UIColor.blackColor;
  200.  
    imageView.contentMode = UIViewContentModeScaleToFill;
  201.  
    [self.view addSubview:imageView];
  202.  
    }
  203.  
    }
  204.  
     
  205.  
    // 更新 Image
  206.  
    - (void)showImage:(UIImage *)image{
  207.  
    dispatch_async(dispatch_get_main_queue(), ^{
  208.  
    self.imageView.image = image;
  209.  
    });
  210.  
    }
  211.  
     
  212.  
    /// AAC 解码 PCM
  213.  
    /// - Parameter sender: UI 按钮
  214.  
    - (IBAction)onClickAACToPCM:(id)sender {
  215.  
    // 输入文件
  216.  
    NSString *inputFilePath = [PathTool documentsPath:@"output.aac"];
  217.  
    // 输出文件
  218.  
    NSString *outputFilePath = [PathTool documentsPath:@"output.pcm"];
  219.  
    // 初始化文件管理器
  220.  
    __block FileTool *fileTool = [[FileTool alloc]init];
  221.  
    // 打开文件
  222.  
    int ret = (int)[fileTool open:inputFilePath.UTF8String model:FILE_MODE_READ];
  223.  
    // 返回值小于 0,打开文件异常
  224.  
    if(ret < 0){
  225.  
    return;
  226.  
    }
  227.  
    // 初始化 AAC 解码 PCM 管理器
  228.  
    __block AACToPCMDeCoder *aacToPCMDeCoder =[[AACToPCMDeCoder alloc]init];
  229.  
    // 传入输入输出文件路径
  230.  
    ret = [aacToPCMDeCoder init:inputFilePath.UTF8String outputFilePath:outputFilePath.UTF8String];
  231.  
    // 返回值小于 0 时,初始化失败
  232.  
    if(ret < 0){
  233.  
    return;
  234.  
    }
  235.  
    // 开启子线程,进行解码操作
  236.  
    dispatch_async(dispatch_get_global_queue(DISPATCH_BLOCK_DETACHED, 0), ^{
  237.  
    // 定义输入读取数据大小
  238.  
    int length = 1024 * 4;
  239.  
    uint8_t data[length];
  240.  
    while (true) {
  241.  
    // 读取输入数据
  242.  
    int size = (int)[fileTool read:data length:length];
  243.  
    // 读完文件,则跳出循环
  244.  
    if(size <= 0){
  245.  
    break;
  246.  
    }
  247.  
    // 解码数据
  248.  
    [aacToPCMDeCoder convertToPCM:data withSize:size];
  249.  
    }
  250.  
    // 停止
  251.  
    [aacToPCMDeCoder stop];
  252.  
    // 释放解码器数据
  253.  
    aacToPCMDeCoder = nil;
  254.  
    // 释放文件资源
  255.  
    fileTool = nil;
  256.  
    });
  257.  
    }
  258.  
     
  259.  
    @end
学新通

  3.2 输出执行成功日志:

  1.  
    [aac @ 0x7fc1d080a400] Estimating duration from bitrate, this may be inaccurate
  2.  
    Input #0, aac, from '/Users/lihanyang/Library/Developer/CoreSimulator/Devices/B317C1BE-A990-4626-A914-C372CA6B59C2/data/Containers/Data/Application/A4D1100F-BF59-4AB3-A573-1E09A34E0EFB/Documents/output.aac':
  3.  
    Duration: 00:03:19.74, bitrate: 52 kb/s
  4.  
    Stream #0:0: Audio: aac, 44100 Hz, stereo, fltp, 52 kb/s
  5.  
    Output
  6.  
    /Users/lihanyang/Library/Developer/CoreSimulator/Devices/B317C1BE-A990-4626-A914-C372CA6B59C2/data/Containers/Data/Application/A4D1100F-BF59-4AB3-A573-1E09A34E0EFB/Documents/output.pcm
  7.  
    AACToPCMDeCoder init success.
  8.  
    AACToPCMDeCoder stop.

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhfhjkkg
系列文章
更多 icon
同类精品
更多 icon
继续加载