美文网首页iOS进阶+实战
《音视频开发进阶指南》读书笔记(二) —— 移动端环境搭建

《音视频开发进阶指南》读书笔记(二) —— 移动端环境搭建

作者: Hsusue | 来源:发表于2019-05-13 22:28 被阅读58次

    第一章 音视频基础概念

    《音视频开发进阶指南》作者人很好,又是个大牛,仰慕男神。

    在学第二章时,编译过程遇到问题,调了5个小时都没弄好。然后加了他微信,感谢百忙之中抽时间给我讲解低级问题。


    2019.5.17 更新

    大佬说本文有点范,复述书上的内容比较多,让我加点自己的思考。这章就是通过交叉编译编译出一些常用第三方库,是章傻瓜式教程。所以考虑第三章如果也没什么说的话,就不复述了。

    当然,这些库在网上通常很好找。有人就问了,直接拉进项目用不就好了,为什么还要花成本去学习交叉编译(笔者零基础学起来很吃力,书上还有由于版本更新或者运行环境问题而废弃的命令)?

    当然常用的库网上都有资源,应付日常的开发没问题。所以直接跳过这章也不是不行。但第三章,FFmpeg 会集成编译出的第三方库。所以,如果你要自定义FFmpeg,网上如果找不到相应的资源,就需要自己动手。从这个角度看,这章可以先跳过,以后有需要再学。


    第二章 移动端环境搭建

    本章会讲解交叉编译,最后会使用 LAME 这个开源的 MP3 编码库在 iOS 平台和 Android 平台上将一个 PCM 文件编码为 MP3 文件,最终将编码后的 MP3 文件发送到电脑上即可进行播放。

    2.1 在 iOS 上如何搭建一个基础项目

    首先创建一个名为 ktv 的项目,并且pod进两个库。

    target 'KTV' do
        pod 'Mantle', '1.5'
        pod 'AFNetworking', '2.6.0'
    end
    

    然后增加 C++ 支持,编写一个类Mp3Encoder,负责将 PCM 数据编码为 MP3 文件。然后把控制器文件后缀改为.mm

    image.png

    关于OC 和 C++混编,推荐看这篇文章聊聊你不知道的 Objective-C++


    下面分别是Mp3Encoder.hppMp3Encoder.cppViewController.mm目前的代码。

    #ifndef Mp3Encoder_hpp
    #define Mp3Encoder_hpp
    
    #include <stdio.h>
    
    class Mp3Encoder
    {
    public:
        void func();
    
    };
    
    #endif /* Mp3Encoder_hpp */
    
    #include "Mp3Encoder.hpp"
    
    void Mp3Encoder::func() {
        printf("C++");
    }
    
    
    #import "ViewController.h"
    #import <iostream>
    #include "Mp3Encoder.hpp"
    #import <AFNetworking.h>
    
    @interface ViewController ()
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        Mp3Encoder *encoder = new Mp3Encoder();
        encoder->func();
        
    }
    @end
    

    2.3 交叉编译的原理与实践

    在音视频的开发中,第三方库都是需要进行交叉编译的。

    2.3.1 交叉编译的原理

    • 编译的过程:使用本机器的编译器,将源代码编译链接成为一个可以在本机器上运行的程序。

    • 交叉编译:在一个平台上生成另外一个平台的可执行代码。两个平台有不同的机器指令。交叉编译详解

    书本理论这里看不太懂,笔者也是这学期刚学的编译原理。编译可以分为前端后端两部分。

    image.png

    在后端可以将中间代码生成对应设备的机器码。

    image.png

    所以目的就是在电脑上生成ARM CPU的可执行代码。

    2.3.2 iOS 平台交叉编译的实践

    随着时间的推移,iPhone平台对应的指令集也在变。

    • armv6:iPhone、iPhone2、iPhone 3G
    • armv7:iPhone 4、iPhone 4S
    • armv7s:iPhone 5、iPhone 5S
    • arm64:iPhone 5S、iPhone 6(P)、iPhone6S(P)、iPhone7(P)

    机器对指令集的支持是向下兼容的,因此armv7的指令集是可以运行在 iPhone 5S中的,只是效率没那么高。


    1. LAME 的交叉编译

    若要在移动端平台上编码 MP3 文件,使用 LAME 成为唯一的选择。

    先(科学上网)下载最新的 LAME 版本。https://sourceforge.net/projects/lame/files/lame/3.99/

    编译LAME的步骤,照书上给出的步骤,运行脚本报错。

    ./configure \
    --disable-shared \
    --disable-frontend \
    --host=arm-apple-darwin \
    --prefix="/Users/hsusue/Downloads/音视频/cross_compile_project-master/ffmpeg_2.8.5_android/external_libs/lame/thin-lame/arm64" \
    CC="xcrun -sdk iphoneos clang -arch arm64" \
    CFLAGS="-arch arm64 -fembed-bitcode -miphoneos-version-min=7.0" \
    LDFLAGS="-arch arm64 -fembed-bitcode -miphoneos-version-min=7.0"
    
    make clean
    make -j8
    make install
    
    
    image.png

    跟作者沟通后(作者人很好,很热情),得知作者github有这脚本(LAME脚本居然只在安卓文件夹中)。下载来对比脚本一样,但却能运行。。。搞不懂

    先cd进文件夹中,然后运行test.sh

    cd /所在目录/cross_compile_project-master/ffmpeg_2.8.5_android/external_libs/lame
    

    其实,这就是个静态库。实在不想编译,可以下载别人编译好的静态库直接拉进项目用。


    1. FDK_AAC 的交叉编译

    FDK_AAC 是用来编码和解码 AAC 格式音频文件的开源库, Android 系统编码和解码 AAC 所用的就是这个库。

    先(科学上网)下载最新的 LAME 版本。
    https://sourceforge.net/p/opencore-amr/fdk-aac/ci/v0.1.4/tree/

    还要下载gas-preprocessor.pl,然后复制到/usr/bin目录下。

    Mac中修改 usr/bin 目录权限

    然后在根目录下建立build_armv7.sh脚本。

    ./configure \
    --enable-static \
    --disable-shared \
    --host=arm-apple-darwin \
    --prefix="/Users/hsusue/Downloads/音视频/FDK_AAC/opencore-amr-fdk-aac-83ac4a9860cd81f793cb4620952fbf795a281b49/thin/armv7" \
    CC="xcrun -sdk iphoneos clang" \
    AS="gas-preprocessor.pl $ CC" \
    CFLAGS="-arch armv7 -mios-simulator-version-min=7.0" \
    LDFLAGS="-arch armv7 -mios-simulator-version-min=7.0"
    
    make clean
    make -j8
    make install
    

    历史还是惊人的相似

    image.png

    还是去用作者的脚本吧,路径是/所在目录/cross_compile_project-master/FFmpeg-Compile-Source/build-fdk-aac/fdk-aac-0.1.4


    1. X264 的交叉编译

    X264 是一个开源的 H.264/MPEG-4 AVC 视频编码函数库,是最好的有损视频编码器之一。

    书上的方法和前面大同小异,但还是用书本作者的脚本吧。弃疗了。


    2.3.4 使用 LAME 编码 MP3 文件

    文章开头的项目,只简单把OC 和 C++ 混编。下面加入编码 MP3 文件的功能。当点击按钮的时候,输入的是一个 PCM 文件的路径和一个 MP3 文件的路径,等运行完毕,电脑上的播放器直接就可以播放该 MP3 文件。

    1. 首先把编译出的lame.hlame.a文件拖进项目中。

    2. 完善头文件Mp3Encoder.hpp

    #ifndef Mp3Encoder_hpp
    #define Mp3Encoder_hpp
    
    #include <stdio.h>
    #include "pc_lame/include/lame/lame.h"
    
    class Mp3Encoder
    {
        private:
        FILE* pcmFile;
        FILE* mp3File;
        lame_t lameClient;
        
        public:
        Mp3Encoder();
        ~Mp3Encoder();
        int Init(const char* pcmFilePath, const char *mp3FilePath, int sampleRate, int channels, int bitRate);
        void Encode();
        void Destory();
    
    };
    
    
    1. 完善实现文件
    #include "Mp3Encoder.hpp"
    
    int Mp3Encoder::Init(const char *pcmFilePath, const char *mp3FilePath, int sampleRate, int channels, int bitRate) {
        int ret = -1;
        pcmFile = fopen(pcmFilePath, "rb");
        if (pcmFile) {
            mp3File = fopen(mp3FilePath, "wb");
            if (mp3File) {
                lameClient = lame_init();
                lame_set_in_samplerate(lameClient, sampleRate);
                lame_set_out_samplerate(lameClient, sampleRate);
                lame_set_num_channels(lameClient, channels);
                lame_set_brate(lameClient, bitRate / 1000);
                lame_init_params(lameClient);
                ret = 0;
            }
        }
        return ret;
    }
    
    void Mp3Encoder::Encode() {
        int bufferSize = 1024 * 256;
        short* buffer = new short[bufferSize / 2];
        short* leftBuffer = new short[bufferSize / 4];
        short* rightBuffer = new short[bufferSize / 4];
        unsigned char* mp3_buffer = new unsigned char[bufferSize];
        size_t readBufferSize = 0;
        while ((readBufferSize = fread(buffer, 2, bufferSize / 2, pcmFile))) {
            for (int i = 0; i < readBufferSize; i++) {
                if (i % 2 == 0) {
                    leftBuffer[i / 2] = buffer[i];
                } else {
                    rightBuffer[i / 2] = buffer[i];
                }
            }
            size_t wroteSize = lame_encode_buffer(lameClient, (short int *) leftBuffer, (short int *) rightBuffer, (int)(readBufferSize / 2), mp3_buffer, bufferSize);
            fwrite(mp3_buffer, 1, wroteSize, mp3File);
        }
        delete[] buffer;
        delete[] leftBuffer;
        delete[] rightBuffer;
        delete[] mp3_buffer;
    }
    
    void Mp3Encoder::Destory() {
        if (pcmFile) {
            fclose(pcmFile);
        }
        
        if (mp3File) {
            fclose(mp3File);
            lame_close(lameClient);
        }
    }
    
    Mp3Encoder::Mp3Encoder() {
        
    }
    
    1. iOS 集成

    4.1 拉一个pcm文件进项目沙盒 , 下载路径

    4.2 创建一个按钮,点击时构建编码器,执行编码方法,最后释放。

    - (IBAction)btnClick:(UIButton *)sender {
    
        Mp3Encoder *encoder = new Mp3Encoder();
    
        // 源文件的的路径
        const char* pcmFilePath = [[[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:@"16k.pcm"] cStringUsingEncoding:NSUTF8StringEncoding];
        NSLog(@"%@", [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:@"16k.pcm"]);
    
        // 要生成的mp3文件的路径
        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
        NSString *documentsDirectory = [paths objectAtIndex:0];
        NSString *docStr = [documentsDirectory stringByAppendingPathComponent:@"16k.mp3"];
        NSLog(@"%@", docStr);
        const char *mp3FilePath = [docStr cStringUsingEncoding:NSUTF8StringEncoding];
    
        int sampleRate = 44100;
        int channels = 2;
        int bitRate = 128 * 1024;
        // 初始化解码器,传入源文件路径,生成的文件路径,采样频率,声道数,码率
        encoder->Init(pcmFilePath, mp3FilePath, sampleRate, channels, bitRate);
    
        // 编码
        encoder->Encode();
    
        //关闭文件
        encoder->Destory();
        delete encoder;
    
    }
    

    这一章到这就结束了。主要介绍了如何创建一个项目,增加C++支持,学习了交叉编译,最终完成了编码 MP3 音频文件。


    参考

    • [1] 展晓凯,魏晓红.音视频开发进阶指南(基于Android与iOS平台的实践)[M].北京:机械工业出版社,2018:14-42.

    相关文章

      网友评论

        本文标题:《音视频开发进阶指南》读书笔记(二) —— 移动端环境搭建

        本文链接:https://www.haomeiwen.com/subject/pqjlaqtx.html