iOS-FFmpeg實現(xiàn)簡單播放器(編譯fak-aac+x264+sdl)

音視頻文章匯總,本文介紹編譯ffmpeg纹冤、fdk-aac哄啄、x264和sdl,實現(xiàn)簡單軟解碼OpenGL渲染視頻播放器问顷。

iOS編譯FFmpeg有兩種方式
1.下載編譯好的FFmpeg靜態(tài)庫拖入Xcode工程中
2.編譯ffmpeg源碼,可以更改源碼,通過腳本編譯自己的架構(gòu),更為靈活,包含fdk-aac庫乞而,x264,sdl2等。

本文介紹自己編譯sdl2慢显,fdk-aac,x264爪模,ffmpeg源碼集成到Xcode工程中,其中fdk-aac荚藻,x264嵌套編譯進ffmpeg中屋灌,并使用sdl播放音頻,OPenGLES渲染視頻實現(xiàn)簡單播放器

1.編譯SDL

I.從SDL官網(wǎng)下載SDL源碼(百度網(wǎng)盤放一份[2.0.16])(鏈接:https://pan.baidu.com/s/11JeLkg82rdjnaBCD7q3_wg 密碼:hv8j)

圖片.png

II.解壓后打開Xcode文件夾中的SDL.xcodeproj,選擇靜態(tài)庫Static Library-iOS,Build選擇Any iOS Devices(arm64,armv7)

圖片.png

圖片.png

III.Cmd + B編譯后应狱,在Products文件夾下面生成libSDL2.a靜態(tài)庫放入lib文件夾中共郭,頭文件放入include文件夾中,后續(xù)拖入Xcode工程中使用

圖片.png
圖片.png
圖片.png

2.編譯FDK-AAC

I.從官網(wǎng)下載穩(wěn)定的FDK-AAC版本2.0.2源碼(百度網(wǎng)盤放一份鏈接:https://pan.baidu.com/s/1dA7vRHxku6ox06vSzP1Xbg 密碼:w4bu),直接下載或git clone git://git.code.sf.net/p/opencore-amr/fdk-aac opencore-amr-fdk-aac,opencore-amr-fdk-aac修改文件夾名稱為fdk-aac-2.0.2

圖片.png
圖片.png
圖片.png

II.在同級目錄下創(chuàng)建腳本文件build_aac.h,文件內(nèi)容如下,在終端執(zhí)行此腳本./build_aac.h,若報錯zsh: permission denied: ./build_aac.sh,則可能會存在權(quán)限問題疾呻,執(zhí)行chmod -R 777 build_aac.sh命令即可

CONFIGURE_FLAGS="--enable-static --with-pic=yes --disable-shared"
#指定編譯平臺
ARCHS="arm64 armv7"
# 源碼位置
SOURCE="fdk-aac-2.0.2"
FAT="fdk-aac-ios"
SCRATCH="scratch"
# must be an absolute path
THIN=`pwd`/"thin"
COMPILE="y"
LIPO="y"

if [ "$*" ]
then
    if [ "$*" = "lipo" ]
    then
        COMPILE=
    else
        ARCHS="$*"
        if [ $# -eq 1 ]
        then
            # skip lipo
            LIPO=
        fi
    fi
fi

if [ "$COMPILE" ]
then
    CWD=`pwd`
    for ARCH in $ARCHS
    do
        echo "building $ARCH..."
        mkdir -p "$SCRATCH/$ARCH"
        cd "$SCRATCH/$ARCH"
        CFLAGS="-arch $ARCH"
        if [ "$ARCH" = "i386" -o "$ARCH" = "x86_64" ]
        then
            PLATFORM="iPhoneSimulator"
            CPU=
            if [ "$ARCH" = "x86_64" ]
            then
                CFLAGS="$CFLAGS -mios-simulator-version-min=7.0"
                HOST="--host=x86_64-apple-darwin"
            else
                CFLAGS="$CFLAGS -mios-simulator-version-min=7.0"
                HOST="--host=i386-apple-darwin"
            fi
        else
            PLATFORM="iPhoneOS"
            if [ $ARCH = arm64 ]
            then
                HOST="--host=aarch64-apple-darwin"
            else
                HOST="--host=arm-apple-darwin"
            fi
            CFLAGS="$CFLAGS -fembed-bitcode"
        fi

        XCRUN_SDK=`echo $PLATFORM | tr '[:upper:]' '[:lower:]'`
        CC="xcrun -sdk $XCRUN_SDK clang -Wno-error=unused-command-line-argument-hard-error-in-future"
        AS="$CWD/$SOURCE/extras/gas-preprocessor.pl $CC"
        CXXFLAGS="$CFLAGS"
        LDFLAGS="$CFLAGS"

        $CWD/$SOURCE/configure \
            $CONFIGURE_FLAGS \
            $HOST \
            $CPU \
            CC="$CC" \
            CXX="$CC" \
            CPP="$CC -E" \
            AS="$AS" \
            CFLAGS="$CFLAGS" \
            LDFLAGS="$LDFLAGS" \
            CPPFLAGS="$CFLAGS" \
            --prefix="$THIN/$ARCH" || exit 1
        make -j8 install || exit 1
        cd $CWD
    done
fi

#合并各個架構(gòu)平臺的庫文件
if [ "$LIPO" ]
then
    echo "building fat binaries..."
    mkdir -p $FAT/lib
    set - $ARCHS
    CWD=`pwd`
    cd $THIN/$1/lib
    for LIB in *.a
    do
        cd $CWD
        lipo -create `find $THIN -name $LIB` -output $FAT/lib/$LIB
    done
    
    cd $CWD
    cp -rf $THIN/$1/include $FAT
fi
圖片.png

若報錯fdk-aac-2.0.2/configure: No such file or directory落塑,則用我網(wǎng)盤中的解壓文件,里面包含了configure執(zhí)行文件罐韩,執(zhí)行./build.sh后,

圖片.png

III.編譯完成后污朽,在fdk-aac-ios文件夾中就會生成include和lib文件夾

圖片.png

3.編譯X264

I.訪問X264官網(wǎng),通過https://www.videolan.org/developers/x264.html下載X264源碼(百度網(wǎng)盤放一份鏈接:鏈接:https://pan.baidu.com/s/1FpiV4qrErOBdgoVBYYIAbw 密碼:wef1)

II.在同級目錄下新建build_x264.sh腳本文件散吵,文件內(nèi)容如下,執(zhí)行./build_x264.sh,若有權(quán)限問題蟆肆,執(zhí)行chmod -R 777 build_x264.sh

圖片.png
CONFIGURE_FLAGS="--enable-static --enable-pic --disable-cli --disable-shared"
# 指定架構(gòu)平臺
ARCHS="arm64 armv7"
#源碼位置
SOURCE="x264"
FAT="x264-iOS"
SCRATCH="scratch-x264"
THIN=`pwd`/"thin-x264"

COMPILE="y"
LIPO="y"

if [ "$*" ]
then
    if [ "$*" = "lipo" ]
    then
        COMPILE=
    else
        ARCHS="$*"
        if [ $# -eq 1 ]
        then
            LIPO=
        fi
    fi
fi

if [ "$COMPILE" ]
then
    CWD=`pwd`
    for ARCH in $ARCHS
    do
        echo "building $ARCH..."
        mkdir -p "$SCRATCH/$ARCH"
        cd "$SCRATCH/$ARCH"
        CFLAGS="-arch $ARCH"
        ASFLAGS=
        if [ "$ARCH" = "i386" -o "$ARCH" = "x86_64" ]
        then
            PLATFORM="iPhoneSimulator"
            CPU=
            if [ "$ARCH" = "x86_64" ]
            then
                CFLAGS="$CFLAGS -mios-simulator-version-min=9.0"
                HOST=
            else
                CFLAGS="$CFLAGS -mios-simulator-version-min=9.0"
                HOST="--host=i386-apple-darwin"
            fi
        else
            PLATFORM="iPhoneOS"
            if [ $ARCH = "arm64" ]
            then
                HOST="--host=aarch64-apple-darwin"
                XARCH="-arch aarch64"
            else
                HOST="--host=arm-apple-darwin"
                XARCH="-arch arm"
            fi

            CFLAGS="$CFLAGS -fembed-bitcode -mios-version-min=9.0"
            ASFLAGS="$CFLAGS"
        fi
  
        XCRUN_SDK=`echo $PLATFORM | tr '[:upper:]' '[:lower:]'`
        CC="xcrun -sdk $XCRUN_SDK clang"
        if [ $PLATFORM = "iPhoneOS" ]
        then
            export AS="$CWD/$SOURCE/tools/gas-preprocessor.pl $XARCH -- $CC"
        else
            export -n AS
        fi
        CXXFLAGS="$CFLAGS"
        LDFLAGS="$CFLAGS"
        CC=$CC $CWD/$SOURCE/configure \
            $CONFIGURE_FLAGS \
            $HOST \
            --extra-cflags="$CFLAGS" \
            --extra-asflags="$ASFLAGS" \
            --extra-ldflags="$LDFLAGS" \
            --prefix="$THIN/$ARCH" || exit 1
            
        make -j8 install || exit 1
        cd $CWD
    done
fi

if [ "$LIPO" ]
then
    echo "building fat binaries..."
    mkdir -p $FAT/lib
    set - $ARCHS
    CWD=`pwd`
    cd $THIN/$1/lib
    for LIB in *.a
    do
        cd $CWD
        lipo -create `find $THIN -name $LIB` -output $FAT/lib/$LIB
    done

    cd $CWD
    cp -rf $THIN/$1/include $FAT
fi

III.編譯完成后矾睦,庫文件在文件夾x264-iOS中

圖片.png

4.編譯FFmpeg源碼并嵌套fdk-aac,x264

I.從官網(wǎng)下載FFmpeg_4.3.2版本源碼(百度網(wǎng)盤放一份炎功,鏈接:https://pan.baidu.com/s/11ElqpUwByUG6565W09-unA 密碼:9k9c)

II.下載gas-preprocessor

拷貝gas-preprocessor.pl到/usr/local/bin目錄下
添加可讀可寫可執(zhí)行權(quán)限枚冗,后面運行 FFmpeg-iOS-build-script 這個自動編譯腳本需要 gas-preprocessor
sudo chmod 777 /usr/local/bin/gas-preprocessor.pl

III.安裝yasmbrew install yasm

IV.下載自動編譯腳本FFmpeg-iOS-build-script

修改build-ffmpeg.sh文件為最新的版本4.3.2,修改CONFIGURE_FLAGS值中增加禁止生成可執(zhí)行文件ffmpeg,ffplay,ffprobe蛇损,fdk-aac需要增加--enable-nonfree選項,fdk-aac和x264文件絕對路徑要一致


圖片.png
圖片.png
圖片.png
# absolute path to x264 library
#X264=`pwd`/fat-x264
X264=`pwd`/X264/x264-iOS

#FDK_AAC=`pwd`/../fdk-aac-build-script-for-iOS/fdk-aac-ios
FDK_AAC=`pwd`/FDK-AAC/fdk-aac-ios

CONFIGURE_FLAGS="--enable-cross-compile --disable-debug --disable-programs \
                 --disable-doc --enable-pic --enable-nonfree --disable-ffmpeg --disable-ffplay --disable-ffprobe"

V.在當(dāng)前目錄下執(zhí)行./build-ffmpeg.sh,編譯完后生成FFmpeg-iOS文件夾赁温,include中是頭文件和lib中是靜態(tài)庫.a文件

圖片.png

5.使用

將編譯好的sdl,fdk-aac,x264,ffmpeg頭文件和庫文件(include和lib文件夾)


圖片.png

導(dǎo)入Xcode工程中并設(shè)置Header Search Path為

$(PROJECT_DIR)/FFmpeg_zero/FFmpeg-iOS/include
$(PROJECT_DIR)/FFmpeg_zero/SDL/include
$(PROJECT_DIR)/FFmpeg_zero/x264-iOS/include
$(PROJECT_DIR)/FFmpeg_zero/fdk-aac-ios/include
圖片.png

導(dǎo)入依賴的庫AVFoudation.framework,CoreMedia.framework,VideoToolBox.framework,AudioToolBox.framework,lbz.tbd,libbz2.tbd,libiconv.tbd


圖片.png

使用ffmpeg庫獲取ffmpeg版本號


圖片.png

6.以上僅僅使用了ffmpeg淤齐,但沒有使用sdl2,fdk-aac,x264,若使用還需導(dǎo)入UIKit.framework股囊、Foundation.framework、CoreMotion.framework更啄、MediaPlayer.framework稚疹、GameController.framework、CoreHaptics.framework祭务,若使用OpenGL繪制視頻幀内狗,還需導(dǎo)入OpenGLES.framework怪嫌、QuartzCore.framework。Demo github地址[鏈接: https://pan.baidu.com/s/1bcEYEyWFstmit2WSomSptA 提取碼: 03os]

集成后可使用ffmpeg進行軟解碼柳沙,sdl播放音頻岩灭,OpenGLES繪制視頻實現(xiàn)一個簡單播放器

7.使用ffmpeg解碼音視頻,分為三步,解封裝偎行,解碼視頻川背,解碼音頻

開啟子線程讀取到MP4文件后,從MP4文件中解封裝出h264文件和aac文件分別解碼為YUV原始視頻幀和pcm原始音頻,將解封裝出來的h264文件放入_vPktList蛤袒,aac文件放入_aPktList

I.ffmpeg解封裝熄云,解封裝出視頻文件和音頻文件按序分裂存儲到各自的list中

        //創(chuàng)建解封裝上下文、打開文件
        ret = avformat_open_input(&_fmtCtx,_filename,nullptr,nullptr);
        END(avformat_open_input);
        //檢索流信息
        ret = avformat_find_stream_info(_fmtCtx,nullptr);
        END(avformat_find_stream_info);
        //打印流信息到控制臺
        av_dump_format(_fmtCtx,0,_filename,0);
        fflush(stderr);
        //初始化音頻信息
        _hasAudio = initAudioInfo() >= 0;
        //初始化視頻信息
        _hasVideo = initVideoInfo() >= 0;
        if(!_hasAudio && !_hasVideo)
        {
            fataError();
            return;
        }
        //初始化完畢妙真,發(fā)送信號
          initFinished(self);
        //改變狀態(tài) 要在讀取線程的前面缴允,否則導(dǎo)致解碼循環(huán)提前退出,解碼循環(huán)讀取到時Stop狀態(tài)直接break珍德,再也不進入 無法解碼 一直黑屏或沒有聲音练般,
        //也可能SDL音頻子線程一開始在Stopped,就退出了
        setState(VideoPlayer::Playing);
        //音頻解碼子線程開始工作:開始播放pcm
        SDL_PauseAudio(0);
        //視頻解碼子線程開始工作:開啟新的線程去解碼視頻數(shù)據(jù)
        std::thread([this](){
            decodeVideo();
        }).detach();
        //從輸入文件中讀取數(shù)據(jù)
        //確保每次讀取到的pkt都是新的锈候,在while循環(huán)外面薄料,則每次加入list中的pkt都不會將一模一樣,不為最后一次讀取到的pkt泵琳,為全新的pkt摄职,調(diào)用了拷貝構(gòu)造函數(shù)
        AVPacket pkt;
        while(_state != Stopped){
            //處理seek操作
            if(_seekTime >= 0){
                int streamIdx;
                if(_hasAudio){//優(yōu)先使用音頻流索引
                cout << "seek優(yōu)先使用,音頻流索引" << _aStream->index << endl;
                  streamIdx = _aStream->index;
                }else{
                cout << "seek優(yōu)先使用获列,視頻流索引" << _vStream->index << endl;
                  streamIdx = _vStream->index;
                }
                //現(xiàn)實時間 -> 時間戳
                AVRational time_base = _fmtCtx->streams[streamIdx]->time_base;
                int64_t ts = _seekTime/av_q2d(time_base);
                ret = av_seek_frame(_fmtCtx,streamIdx,ts,AVSEEK_FLAG_BACKWARD);
                if(ret < 0){//seek失敗
                    cout << "seek失敗" << _seekTime << ts << streamIdx << endl;
                    _seekTime = -1;
                }else{//seek成功
                    //記錄seek到了哪一幀谷市,有可能是P幀或B,會導(dǎo)致seek向前找到I幀,此時就會比實際seek的值要提前幾幀击孩,現(xiàn)象是調(diào)到seek的幀時會快速的閃現(xiàn)I幀到seek的幀
                    //清空之前讀取的數(shù)據(jù)包
                    clearAudioPktList();
                    clearVideoPktList();
                    _vSeekTime = _seekTime;
                    _aSeekTime = _seekTime;
                    _seekTime = -1;
                    //恢復(fù)時鐘
                    _aTime = 0;
                    _vTime = 0;
                }
            }

            int vSize = _vPktList.size();
            int aSize = _aPktList.size();
            //不要將文件中的壓縮數(shù)據(jù)一次性讀取到內(nèi)存中迫悠,控制下大小
            if(vSize >= VIDEO_MAX_PKT_SIZE || aSize >= AUDIO_MAX_PKT_SIZE){
                continue;
            }
            ret = av_read_frame(_fmtCtx,&pkt);
            if(ret == 0){
                if(pkt.stream_index == _aStream->index){//讀取到的是音頻數(shù)據(jù)
                    addAudioPkt(pkt);
                }else if(pkt.stream_index == _vStream->index){//讀取到的是視頻數(shù)據(jù)
                    addVideoPkt(pkt);
                }else{//如果不是音頻、視頻流巩梢,直接釋放创泄,防止內(nèi)存泄露
                    av_packet_unref(&pkt);
                }
            }else if(ret == AVERROR_EOF){//讀到了文件尾部
                if(vSize == 0 && aSize == 0){
                    //說明文件正常播放完畢
                    _fmtCtxCanFree = true;
                    break;
                }
                //讀取到文件尾部依然要在while循環(huán)中轉(zhuǎn)圈圈,若break跳出循環(huán)括蝠,則無法seek往回讀了
            }else{
                ERROR_BUF;
                cout << "av_read_frame error" << errbuf;
                continue;
            }
        }
        if(_fmtCtxCanFree){//正常讀取到文件尾部
            stop();
        }else{
            //標(biāo)記一下:_fmtCtx可以釋放了
            _fmtCtxCanFree = true;
        }

II.解碼音頻验烧,從_aPktList中取出一個一個的音頻pkt進行解碼,解碼出pcm回調(diào)到SDL音頻緩沖區(qū)進行播放,SDL支持的播放格式為s16le又跛,此時需進行音頻重采樣碍拆,將fltp格式轉(zhuǎn)為s16le格式,采樣率由48000轉(zhuǎn)為44100,雙聲道不變

int VideoPlayer::decodeAudio(){
    _aMutex.lock();
    //_aPktList中如果是空的感混,就進入等待端幼,等待_aPktList中新加入解封裝后的pkt發(fā)送信號signal通知到這兒,
    //有可能解封裝很快就都解完成了弧满,后面都沒有新的pkt爽柒,也不會發(fā)送信號了,就會一直在這兒等
    if(_aPktList.empty()){
        cout << "_aPktList為空" << _aPktList.size() << endl;
        _aMutex.unlock();
        return 0;
    }
    //取出list中的頭部pkt
    AVPacket &pkt = _aPktList.front();

    //音頻包應(yīng)該在多少秒播放
    if(pkt.pts != AV_NOPTS_VALUE){
      _aTime = av_q2d(_aStream->time_base) * pkt.pts;
      //通知外界:播放時間發(fā)生了改變
        timeChanged(self);
    }
    //如果是視頻喉童,不能在這個位置判斷(不能提前釋放pkt,不然會導(dǎo)致B幀廊勃、P幀解碼失敗钢颂,畫面撕裂)
    //發(fā)現(xiàn)音頻的時間是早于seekTime的,就丟棄募谎,防止到seekTime的位置閃現(xiàn)
    if(_aSeekTime >= 0){
        if(_aTime < _aSeekTime){
            //釋放pkt
            av_packet_unref(&pkt);
            _aPktList.pop_front();
             _aMutex.unlock();
            return 0;
        }else{
            _aSeekTime = -1;
        }
    }
    // 發(fā)送壓縮數(shù)據(jù)到解碼器
    int ret = avcodec_send_packet(_aDecodeCtx, &pkt);
    //釋放pkt
    av_packet_unref(&pkt);
    //刪除頭部pkt,寫成引用類型扶关,不能立刻就從list中pop_front刪掉這個pkt對象的內(nèi)存,后面還會用到数冬,用完之后才能刪
    _aPktList.pop_front();
    _aMutex.unlock();
    RET(avcodec_send_packet);
    // 獲取解碼后的數(shù)據(jù)
    ret = avcodec_receive_frame(_aDecodeCtx, _aSwrInFrame);
    if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
        return 0;
    } else RET(avcodec_receive_frame);
    //由于解碼出來的pcm和SDL要求的pcm格式可能不一致节槐,需要進行音頻重采樣
    //重采樣輸出的樣本數(shù) 向上取整  48000 1024 44100  outSamples
    int outSamples = av_rescale_rnd(_aSwrOutSpec.sampleRate, _aSwrInFrame->nb_samples, _aSwrInSpec.sampleRate, AV_ROUND_UP);
    // 重采樣(返回值轉(zhuǎn)換后的樣本數(shù)量)_aSwrOutFrame->data必須初始化,否則重采樣轉(zhuǎn)化的pcm樣本不知道放在那兒
    ret = swr_convert(_aSwrCtx,_aSwrOutFrame->data, outSamples,(const uint8_t **) _aSwrInFrame->data, _aSwrInFrame->nb_samples);
    RET(swr_convert);
    //ret為每一個聲道的樣本數(shù) * 聲道數(shù) * 每一個樣本的大小 = 重采樣后的pcm的大小
    return  ret * _aSwrOutSpec.bytesPerSampleFrame;
}

III.解碼視頻拐纱,解碼出原始的YUV420P視頻文件铜异,使用OpenGL進行渲染

    while (true) {
        //如果是暫停狀態(tài),并且沒有seek操作,暫停狀態(tài)也能seek
        if(_state == Paused && _vSeekTime == -1) continue;
        //如果是停止?fàn)顟B(tài)秸架,會調(diào)用free揍庄,就不用再去解碼,重采樣东抹,渲染币绩,導(dǎo)致訪問釋放了的內(nèi)存空間,會閃退
        if(_state == Stopped){
            _vCanFree = true;
            break;
        }
        _vMutex.lock();
        if(_vPktList.empty()){
            _vMutex.unlock();
            continue;
        }
        //取出頭部的視頻包
        AVPacket pkt = _vPktList.front();
        _vPktList.pop_front();
        _vMutex.unlock();
        //發(fā)送數(shù)據(jù)到解碼器
        int ret = avcodec_send_packet(_vDecodeCtx,&pkt);
        //視頻時鐘 視頻用dts府阀,音頻用pts
        if(pkt.dts != AV_NOPTS_VALUE){
            _vTime = av_q2d(_vStream->time_base) * pkt.pts;
        }
        //釋放pkt
        av_packet_unref(&pkt);
        CONTINUE(avcodec_send_packet);
        while (true) {
            //獲取解碼后的數(shù)據(jù)
            ret = avcodec_receive_frame(_vDecodeCtx,_vSwsInFrame);
            if(ret == AVERROR(EAGAIN) || ret == AVERROR_EOF){
                break;//結(jié)束本次循環(huán),重新從_vPktList取出包進行解碼
            }else BREAK(avcodec_receive_frame);

            //一定要在解碼成功后芽突,再進行下面的判斷,防止seek時试浙,到達的是p幀,但前面的I幀已經(jīng)被釋放了寞蚌,無法參考田巴,這一幀的解碼就會出現(xiàn)撕裂現(xiàn)象
            //發(fā)現(xiàn)視頻的時間是早于seekTime的,就丟棄挟秤,防止到seekTime的位置閃現(xiàn)
            if(_vSeekTime >= 0){
                if(_vTime < _vSeekTime){
                    continue;
                }else{
                    _vSeekTime = -1;
                }
            }
            //OPENGL渲染
            char *buf = (char *)malloc(_vSwsInFrame->width * _vSwsInFrame->height * 3 / 2);
            AVPicture *pict;
            int w, h;
            char *y, *u, *v;
            pict = (AVPicture *)_vSwsInFrame;//這里的frame就是解碼出來的AVFrame
            w = _vSwsInFrame->width;
            h = _vSwsInFrame->height;
            y = buf;
            u = y + w * h;
            v = u + w * h / 4;
            for (int i=0; i<h; i++)
                memcpy(y + w * i, pict->data[0] + pict->linesize[0] * i, w);
            for (int i=0; i<h/2; i++)
                memcpy(u + w / 2 * i, pict->data[1] + pict->linesize[1] * i, w / 2);
            for (int i=0; i<h/2; i++)
                memcpy(v + w / 2 * i, pict->data[2] + pict->linesize[2] * i, w / 2);
            if(_hasAudio){//有音頻
                //如果視頻包多早解碼出來壹哺,就要等待對應(yīng)的音頻時鐘到達
                //有可能點擊停止的時候,正在循環(huán)里面艘刚,停止后sdl free掉了管宵,就不會再從音頻list中取出包,_aClock就不會增大,下面while就死循環(huán)了箩朴,一直出不來岗喉,所以加Playing判斷
                printf("vTime=%lf, aTime=%lf, vTime-aTime=%lf\n", _vTime, _aTime, _vTime - _aTime);
                while(_vTime > _aTime && _state == Playing){
                }
            }else{
                //沒有音頻的情況
            }
            //OPenGLES渲染
            playerDoDraw(self,buf,_vSwsInFrame->width,_vSwsInFrame->height);
            //若立即釋放 會崩潰 原因是渲染并沒有那么快,OPENGL還沒有渲染完畢炸庞,但是這塊內(nèi)存已經(jīng)被free掉了
            //放到OPGLES glview中等待一幀渲染完畢后钱床,再釋放,此處不能釋放
        }
    }

IV.SDL播放pcm音頻

SDL通過回調(diào)的方式開啟子線程播放音頻


圖片.png
   //SDL緩沖區(qū)找解碼器拉取符合播放格式的音頻PCM流
   //清零(靜音處理)
    SDL_memset(stream,0,len);
   //len:SDL音頻緩沖區(qū)剩余的大小(音頻緩沖區(qū)還未填充的大小)
    while (len > 0) {
        //說明當(dāng)前PCM的數(shù)據(jù)已經(jīng)全部拷貝到SDL音頻緩沖區(qū)了
        //需要解碼下一個pkt,獲取新的PCM數(shù)據(jù)
        if(_aSwrOutIdx >= _aSwrOutSize){
            //全新PCM數(shù)據(jù)的大小
            _aSwrOutSize = decodeAudio();
            //索引清零
            _aSwrOutIdx = 0;
            //沒有解碼出PCM數(shù)據(jù)埠居,那就靜音處理
            if(_aSwrOutSize <= 0){
               //出錯了查牌,或者還沒有解碼出PCM數(shù)據(jù),假定1024個字節(jié)靜音處理
                //假定1024個字節(jié)
                _aSwrOutSize = 1024;
                //給PCM填充0(靜音)
                memset(_aSwrOutFrame->data[0],0,_aSwrOutSize);
            }
        }
        //本次需要填充到stream中的數(shù)據(jù)大小
        int fillLen = _aSwrOutSize - _aSwrOutIdx;
        fillLen = std::min(fillLen,len);
        //獲取音量
        int volumn = _mute ? 0:(_volumn * 1.0/Max) * SDL_MIX_MAXVOLUME;
        //將一個pkt包解碼后的pcm數(shù)據(jù)填充到SDL的音頻緩沖區(qū)
        SDL_MixAudio(stream,_aSwrOutFrame->data[0]+_aSwrOutIdx,fillLen,volumn);
        //移動偏移量?
        len -= fillLen;//SDL緩沖區(qū)剩余的大小
        stream += fillLen;//stream的位置向后移動
        _aSwrOutIdx += fillLen;//_aSwrOutIdx在_aSwrOutFrame->data[0]中的位置向后移動
    }

V.播放視頻滥壕,通過OPENGL方式渲染原始YUV420P幀

- (void)displayYUV420pData:(void *)data width:(NSInteger)w height:(NSInteger)h
{
    //保存?zhèn)鬟f的yuv原始數(shù)據(jù) render渲染完后釋放free,能來到這兒纸颜,說明渲染下一幀(可能是第一幀),先釋放掉上一幀的數(shù)據(jù)data指向的內(nèi)存空間捏浊,指針指向NULL
    if(_pYuvData != NULL){
        free(_pYuvData);
        _pYuvData = NULL;
    }
    _pYuvData = data;
    dispatch_async(dispatch_get_main_queue(), ^{
        @synchronized(self)
        {
            if (w != _videoW || h != _videoH)
            {
                [self setVideoSize:w height:h];
            }
            [EAGLContext setCurrentContext:_glContext];
            
            glBindTexture(GL_TEXTURE_2D, _textureYUV[TEXY]);
            
            //glTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* pixels);
            
            glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RED_EXT, GL_UNSIGNED_BYTE, _pYuvData);
            
            glBindTexture(GL_TEXTURE_2D, _textureYUV[TEXU]);
            glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w/2, h/2, GL_RED_EXT, GL_UNSIGNED_BYTE, _pYuvData + w * h);
            
            glBindTexture(GL_TEXTURE_2D, _textureYUV[TEXV]);
            glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w/2, h/2, GL_RED_EXT, GL_UNSIGNED_BYTE, _pYuvData + w * h * 5 / 4);
            
            [self render];
        }
    });
    
#ifdef DEBUG
    
    dispatch_async(dispatch_get_main_queue(), ^{
        GLenum err = glGetError();
        if (err != GL_NO_ERROR)
        {
            printf("GL_ERROR=======>%d\n", err);
        }
        struct timeval nowtime;
        gettimeofday(&nowtime, NULL);
        if (nowtime.tv_sec != _time.tv_sec)
        {
            memcpy(&_time, &nowtime, sizeof(struct timeval));
            _frameRate = 1;
        }
        else
        {
            _frameRate++;
        }
    });
#endif
}
- (void)render
{
    [EAGLContext setCurrentContext:_glContext];
    CGSize size = self.bounds.size;
    glViewport(1, 1, size.width*_viewScale-2, size.height*_viewScale-2);
    static const GLfloat squareVertices[] = {
        -1.0f, -1.0f,
        1.0f, -1.0f,
        -1.0f,  1.0f,
        1.0f,  1.0f,
    };
    
    static const GLfloat coordVertices[] = {
        0.0f, 1.0f,
        1.0f, 1.0f,
        0.0f,  0.0f,
        1.0f,  0.0f,
    };
    
    // Update attribute values
    glVertexAttribPointer(ATTRIB_VERTEX, 2, GL_FLOAT, 0, 0, squareVertices);
    glEnableVertexAttribArray(ATTRIB_VERTEX);
    
    glVertexAttribPointer(ATTRIB_TEXTURE, 2, GL_FLOAT, 0, 0, coordVertices);
    glEnableVertexAttribArray(ATTRIB_TEXTURE); 
    
    // Draw
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    glBindRenderbuffer(GL_RENDERBUFFER, _renderBuffer);
    [_glContext presentRenderbuffer:GL_RENDERBUFFER];
}

0.gif

1.gif

完整播放器Demo的github鏈接FFmpeg_Player(百度網(wǎng)盤放一份懂衩,鏈接: https://pan.baidu.com/s/1ChXSBYW5REHWpCGys6bTmw 提取碼: b4hg)
圖片.png

8.編譯fat binary,分別編譯可跑模擬器版本i386,x86_64環(huán)境,SDL2使用Xcode進行編譯,需要將胖二進制文件拖入Demo中,分別對fdk-aac,x264,sdl2,ffmpeg進行替換(胖二進制文件百度網(wǎng)盤放一份金踪,鏈接: https://pan.baidu.com/s/14BIW-PvKf2xDKxfxoY9_Gw 提取碼: wcp2)

模擬器ffmpeg.gif

配置參數(shù)可精簡和優(yōu)化ffmpeg,在ffmpeg目錄中浊洞,終端執(zhí)行./configure --help列出全部參數(shù)

Help options:
  --help                   print this message
  --quiet                  Suppress showing informative output
  --list-decoders          show all available decoders
  --list-encoders          show all available encoders
  --list-hwaccels          show all available hardware accelerators
  --list-demuxers          show all available demuxers
  --list-muxers            show all available muxers
  --list-parsers           show all available parsers
  --list-protocols         show all available protocols
  --list-bsfs              show all available bitstream filters
  --list-indevs            show all available input devices
  --list-outdevs           show all available output devices
  --list-filters           show all available filters

Standard options:
  --logfile=FILE           log tests and output to FILE [ffbuild/config.log]
  --disable-logging        do not log configure debug information
  --fatal-warnings         fail if any configure warning is generated
  --prefix=PREFIX          install in PREFIX [/usr/local]
  --bindir=DIR             install binaries in DIR [PREFIX/bin]
  --datadir=DIR            install data files in DIR [PREFIX/share/ffmpeg]
  --docdir=DIR             install documentation in DIR [PREFIX/share/doc/ffmpeg]
  --libdir=DIR             install libs in DIR [PREFIX/lib]
  --shlibdir=DIR           install shared libs in DIR [LIBDIR]
  --incdir=DIR             install includes in DIR [PREFIX/include]
  --mandir=DIR             install man page in DIR [PREFIX/share/man]
  --pkgconfigdir=DIR       install pkg-config files in DIR [LIBDIR/pkgconfig]
  --enable-rpath           use rpath to allow installing libraries in paths
                           not part of the dynamic linker search path
                           use rpath when linking programs (USE WITH CARE)
  --install-name-dir=DIR   Darwin directory name for installed targets

Licensing options:
  --enable-gpl             allow use of GPL code, the resulting libs
                           and binaries will be under GPL [no]
  --enable-version3        upgrade (L)GPL to version 3 [no]
  --enable-nonfree         allow use of nonfree code, the resulting libs
                           and binaries will be unredistributable [no]

Configuration options:
  --disable-static         do not build static libraries [no]
  --enable-shared          build shared libraries [no]
  --enable-small           optimize for size instead of speed
  --disable-runtime-cpudetect disable detecting CPU capabilities at runtime (smaller binary)
  --enable-gray            enable full grayscale support (slower color)
  --disable-swscale-alpha  disable alpha channel support in swscale
  --disable-all            disable building components, libraries and programs
  --disable-autodetect     disable automatically detected external libraries [no]

Program options:
  --disable-programs       do not build command line programs
  --disable-ffmpeg         disable ffmpeg build
  --disable-ffplay         disable ffplay build
  --disable-ffprobe        disable ffprobe build

Documentation options:
  --disable-doc            do not build documentation
  --disable-htmlpages      do not build HTML documentation pages
  --disable-manpages       do not build man documentation pages
  --disable-podpages       do not build POD documentation pages
  --disable-txtpages       do not build text documentation pages

Component options:
  --disable-avdevice       disable libavdevice build
  --disable-avcodec        disable libavcodec build
  --disable-avformat       disable libavformat build
  --disable-swresample     disable libswresample build
  --disable-swscale        disable libswscale build
  --disable-postproc       disable libpostproc build
  --disable-avfilter       disable libavfilter build
  --enable-avresample      enable libavresample build (deprecated) [no]
  --disable-pthreads       disable pthreads [autodetect]
  --disable-w32threads     disable Win32 threads [autodetect]
  --disable-os2threads     disable OS/2 threads [autodetect]
  --disable-network        disable network support [no]
  --disable-dct            disable DCT code
  --disable-dwt            disable DWT code
  --disable-error-resilience disable error resilience code
  --disable-lsp            disable LSP code
  --disable-lzo            disable LZO decoder code
  --disable-mdct           disable MDCT code
  --disable-rdft           disable RDFT code
  --disable-fft            disable FFT code
  --disable-faan           disable floating point AAN (I)DCT code
  --disable-pixelutils     disable pixel utils in libavutil

Individual component options:
  --disable-everything     disable all components listed below
  --disable-encoder=NAME   disable encoder NAME
  --enable-encoder=NAME    enable encoder NAME
  --disable-encoders       disable all encoders
  --disable-decoder=NAME   disable decoder NAME
  --enable-decoder=NAME    enable decoder NAME
  --disable-decoders       disable all decoders
  --disable-hwaccel=NAME   disable hwaccel NAME
  --enable-hwaccel=NAME    enable hwaccel NAME
  --disable-hwaccels       disable all hwaccels
  --disable-muxer=NAME     disable muxer NAME
  --enable-muxer=NAME      enable muxer NAME
  --disable-muxers         disable all muxers
  --disable-demuxer=NAME   disable demuxer NAME
  --enable-demuxer=NAME    enable demuxer NAME
  --disable-demuxers       disable all demuxers
  --enable-parser=NAME     enable parser NAME
  --disable-parser=NAME    disable parser NAME
  --disable-parsers        disable all parsers
  --enable-bsf=NAME        enable bitstream filter NAME
  --disable-bsf=NAME       disable bitstream filter NAME
  --disable-bsfs           disable all bitstream filters
  --enable-protocol=NAME   enable protocol NAME
  --disable-protocol=NAME  disable protocol NAME
  --disable-protocols      disable all protocols
  --enable-indev=NAME      enable input device NAME
  --disable-indev=NAME     disable input device NAME
  --disable-indevs         disable input devices
  --enable-outdev=NAME     enable output device NAME
  --disable-outdev=NAME    disable output device NAME
  --disable-outdevs        disable output devices
  --disable-devices        disable all devices
  --enable-filter=NAME     enable filter NAME
  --disable-filter=NAME    disable filter NAME
  --disable-filters        disable all filters

External library support:

  Using any of the following switches will allow FFmpeg to link to the
  corresponding external library. All the components depending on that library
  will become enabled, if all their other dependencies are met and they are not
  explicitly disabled. E.g. --enable-libwavpack will enable linking to
  libwavpack and allow the libwavpack encoder to be built, unless it is
  specifically disabled with --disable-encoder=libwavpack.

  Note that only the system libraries are auto-detected. All the other external
  libraries must be explicitly enabled.

  Also note that the following help text describes the purpose of the libraries
  themselves, not all their features will necessarily be usable by FFmpeg.

  --disable-alsa           disable ALSA support [autodetect]
  --disable-appkit         disable Apple AppKit framework [autodetect]
  --disable-avfoundation   disable Apple AVFoundation framework [autodetect]
  --enable-avisynth        enable reading of AviSynth script files [no]
  --disable-bzlib          disable bzlib [autodetect]
  --disable-coreimage      disable Apple CoreImage framework [autodetect]
  --enable-chromaprint     enable audio fingerprinting with chromaprint [no]
  --enable-frei0r          enable frei0r video filtering [no]
  --enable-gcrypt          enable gcrypt, needed for rtmp(t)e support
                           if openssl, librtmp or gmp is not used [no]
  --enable-gmp             enable gmp, needed for rtmp(t)e support
                           if openssl or librtmp is not used [no]
  --enable-gnutls          enable gnutls, needed for https support
                           if openssl, libtls or mbedtls is not used [no]
  --disable-iconv          disable iconv [autodetect]
  --enable-jni             enable JNI support [no]
  --enable-ladspa          enable LADSPA audio filtering [no]
  --enable-libaom          enable AV1 video encoding/decoding via libaom [no]
  --enable-libaribb24      enable ARIB text and caption decoding via libaribb24 [no]
  --enable-libass          enable libass subtitles rendering,
                           needed for subtitles and ass filter [no]
  --enable-libbluray       enable BluRay reading using libbluray [no]
  --enable-libbs2b         enable bs2b DSP library [no]
  --enable-libcaca         enable textual display using libcaca [no]
  --enable-libcelt         enable CELT decoding via libcelt [no]
  --enable-libcdio         enable audio CD grabbing with libcdio [no]
  --enable-libcodec2       enable codec2 en/decoding using libcodec2 [no]
  --enable-libdav1d        enable AV1 decoding via libdav1d [no]
  --enable-libdavs2        enable AVS2 decoding via libdavs2 [no]
  --enable-libdc1394       enable IIDC-1394 grabbing using libdc1394
                           and libraw1394 [no]
  --enable-libfdk-aac      enable AAC de/encoding via libfdk-aac [no]
  --enable-libflite        enable flite (voice synthesis) support via libflite [no]
  --enable-libfontconfig   enable libfontconfig, useful for drawtext filter [no]
  --enable-libfreetype     enable libfreetype, needed for drawtext filter [no]
  --enable-libfribidi      enable libfribidi, improves drawtext filter [no]
  --enable-libglslang      enable GLSL->SPIRV compilation via libglslang [no]
  --enable-libgme          enable Game Music Emu via libgme [no]
  --enable-libgsm          enable GSM de/encoding via libgsm [no]
  --enable-libiec61883     enable iec61883 via libiec61883 [no]
  --enable-libilbc         enable iLBC de/encoding via libilbc [no]
  --enable-libjack         enable JACK audio sound server [no]
  --enable-libklvanc       enable Kernel Labs VANC processing [no]
  --enable-libkvazaar      enable HEVC encoding via libkvazaar [no]
  --enable-liblensfun      enable lensfun lens correction [no]
  --enable-libmodplug      enable ModPlug via libmodplug [no]
  --enable-libmp3lame      enable MP3 encoding via libmp3lame [no]
  --enable-libopencore-amrnb enable AMR-NB de/encoding via libopencore-amrnb [no]
  --enable-libopencore-amrwb enable AMR-WB decoding via libopencore-amrwb [no]
  --enable-libopencv       enable video filtering via libopencv [no]
  --enable-libopenh264     enable H.264 encoding via OpenH264 [no]
  --enable-libopenjpeg     enable JPEG 2000 de/encoding via OpenJPEG [no]
  --enable-libopenmpt      enable decoding tracked files via libopenmpt [no]
  --enable-libopus         enable Opus de/encoding via libopus [no]
  --enable-libpulse        enable Pulseaudio input via libpulse [no]
  --enable-librabbitmq     enable RabbitMQ library [no]
  --enable-librav1e        enable AV1 encoding via rav1e [no]
  --enable-librsvg         enable SVG rasterization via librsvg [no]
  --enable-librubberband   enable rubberband needed for rubberband filter [no]
  --enable-librtmp         enable RTMP[E] support via librtmp [no]
  --enable-libshine        enable fixed-point MP3 encoding via libshine [no]
  --enable-libsmbclient    enable Samba protocol via libsmbclient [no]
  --enable-libsnappy       enable Snappy compression, needed for hap encoding [no]
  --enable-libsoxr         enable Include libsoxr resampling [no]
  --enable-libspeex        enable Speex de/encoding via libspeex [no]
  --enable-libsrt          enable Haivision SRT protocol via libsrt [no]
  --enable-libssh          enable SFTP protocol via libssh [no]
  --enable-libtensorflow   enable TensorFlow as a DNN module backend
                           for DNN based filters like sr [no]
  --enable-libtesseract    enable Tesseract, needed for ocr filter [no]
  --enable-libtheora       enable Theora encoding via libtheora [no]
  --enable-libtls          enable LibreSSL (via libtls), needed for https support
                           if openssl, gnutls or mbedtls is not used [no]
  --enable-libtwolame      enable MP2 encoding via libtwolame [no]
  --enable-libv4l2         enable libv4l2/v4l-utils [no]
  --enable-libvidstab      enable video stabilization using vid.stab [no]
  --enable-libvmaf         enable vmaf filter via libvmaf [no]
  --enable-libvo-amrwbenc  enable AMR-WB encoding via libvo-amrwbenc [no]
  --enable-libvorbis       enable Vorbis en/decoding via libvorbis,
                           native implementation exists [no]
  --enable-libvpx          enable VP8 and VP9 de/encoding via libvpx [no]
  --enable-libwavpack      enable wavpack encoding via libwavpack [no]
  --enable-libwebp         enable WebP encoding via libwebp [no]
  --enable-libx264         enable H.264 encoding via x264 [no]
  --enable-libx265         enable HEVC encoding via x265 [no]
  --enable-libxavs         enable AVS encoding via xavs [no]
  --enable-libxavs2        enable AVS2 encoding via xavs2 [no]
  --enable-libxcb          enable X11 grabbing using XCB [autodetect]
  --enable-libxcb-shm      enable X11 grabbing shm communication [autodetect]
  --enable-libxcb-xfixes   enable X11 grabbing mouse rendering [autodetect]
  --enable-libxcb-shape    enable X11 grabbing shape rendering [autodetect]
  --enable-libxvid         enable Xvid encoding via xvidcore,
                           native MPEG-4/Xvid encoder exists [no]
  --enable-libxml2         enable XML parsing using the C library libxml2, needed
                           for dash demuxing support [no]
  --enable-libzimg         enable z.lib, needed for zscale filter [no]
  --enable-libzmq          enable message passing via libzmq [no]
  --enable-libzvbi         enable teletext support via libzvbi [no]
  --enable-lv2             enable LV2 audio filtering [no]
  --disable-lzma           disable lzma [autodetect]
  --enable-decklink        enable Blackmagic DeckLink I/O support [no]
  --enable-mbedtls         enable mbedTLS, needed for https support
                           if openssl, gnutls or libtls is not used [no]
  --enable-mediacodec      enable Android MediaCodec support [no]
  --enable-mediafoundation enable encoding via MediaFoundation [auto]
  --enable-libmysofa       enable libmysofa, needed for sofalizer filter [no]
  --enable-openal          enable OpenAL 1.1 capture support [no]
  --enable-opencl          enable OpenCL processing [no]
  --enable-opengl          enable OpenGL rendering [no]
  --enable-openssl         enable openssl, needed for https support
                           if gnutls, libtls or mbedtls is not used [no]
  --enable-pocketsphinx    enable PocketSphinx, needed for asr filter [no]
  --disable-sndio          disable sndio support [autodetect]
  --disable-schannel       disable SChannel SSP, needed for TLS support on
                           Windows if openssl and gnutls are not used [autodetect]
  --disable-sdl2           disable sdl2 [autodetect]
  --disable-securetransport disable Secure Transport, needed for TLS support
                           on OSX if openssl and gnutls are not used [autodetect]
  --enable-vapoursynth     enable VapourSynth demuxer [no]
  --enable-vulkan          enable Vulkan code [no]
  --disable-xlib           disable xlib [autodetect]
  --disable-zlib           disable zlib [autodetect]

  The following libraries provide various hardware acceleration features:
  --disable-amf            disable AMF video encoding code [autodetect]
  --disable-audiotoolbox   disable Apple AudioToolbox code [autodetect]
  --enable-cuda-nvcc       enable Nvidia CUDA compiler [no]
  --disable-cuda-llvm      disable CUDA compilation using clang [autodetect]
  --disable-cuvid          disable Nvidia CUVID support [autodetect]
  --disable-d3d11va        disable Microsoft Direct3D 11 video acceleration code [autodetect]
  --disable-dxva2          disable Microsoft DirectX 9 video acceleration code [autodetect]
  --disable-ffnvcodec      disable dynamically linked Nvidia code [autodetect]
  --enable-libdrm          enable DRM code (Linux) [no]
  --enable-libmfx          enable Intel MediaSDK (AKA Quick Sync Video) code via libmfx [no]
  --enable-libnpp          enable Nvidia Performance Primitives-based code [no]
  --enable-mmal            enable Broadcom Multi-Media Abstraction Layer (Raspberry Pi) via MMAL [no]
  --disable-nvdec          disable Nvidia video decoding acceleration (via hwaccel) [autodetect]
  --disable-nvenc          disable Nvidia video encoding code [autodetect]
  --enable-omx             enable OpenMAX IL code [no]
  --enable-omx-rpi         enable OpenMAX IL code for Raspberry Pi [no]
  --enable-rkmpp           enable Rockchip Media Process Platform code [no]
  --disable-v4l2-m2m       disable V4L2 mem2mem code [autodetect]
  --disable-vaapi          disable Video Acceleration API (mainly Unix/Intel) code [autodetect]
  --disable-vdpau          disable Nvidia Video Decode and Presentation API for Unix code [autodetect]
  --disable-videotoolbox   disable VideoToolbox code [autodetect]

Toolchain options:
  --arch=ARCH              select architecture []
  --cpu=CPU                select the minimum required CPU (affects
                           instruction selection, may crash on older CPUs)
  --cross-prefix=PREFIX    use PREFIX for compilation tools []
  --progs-suffix=SUFFIX    program name suffix []
  --enable-cross-compile   assume a cross-compiler is used
  --sysroot=PATH           root of cross-build tree
  --sysinclude=PATH        location of cross-build system headers
  --target-os=OS           compiler targets OS []
  --target-exec=CMD        command to run executables on target
  --target-path=DIR        path to view of build directory on target
  --target-samples=DIR     path to samples directory on target
  --tempprefix=PATH        force fixed dir/prefix instead of mktemp for checks
  --toolchain=NAME         set tool defaults according to NAME
                           (gcc-asan, clang-asan, gcc-msan, clang-msan,
                           gcc-tsan, clang-tsan, gcc-usan, clang-usan,
                           valgrind-massif, valgrind-memcheck,
                           msvc, icl, gcov, llvm-cov, hardened)
  --nm=NM                  use nm tool NM [nm -g]
  --ar=AR                  use archive tool AR [ar]
  --as=AS                  use assembler AS []
  --ln_s=LN_S              use symbolic link tool LN_S [ln -s -f]
  --strip=STRIP            use strip tool STRIP [strip]
  --windres=WINDRES        use windows resource compiler WINDRES [windres]
  --x86asmexe=EXE          use nasm-compatible assembler EXE [nasm]
  --cc=CC                  use C compiler CC [gcc]
  --cxx=CXX                use C compiler CXX [g++]
  --objcc=OCC              use ObjC compiler OCC [gcc]
  --dep-cc=DEPCC           use dependency generator DEPCC [gcc]
  --nvcc=NVCC              use Nvidia CUDA compiler NVCC or clang []
  --ld=LD                  use linker LD []
  --pkg-config=PKGCONFIG   use pkg-config tool PKGCONFIG [pkg-config]
  --pkg-config-flags=FLAGS pass additional flags to pkgconf []
  --ranlib=RANLIB          use ranlib RANLIB [ranlib]
  --doxygen=DOXYGEN        use DOXYGEN to generate API doc [doxygen]
  --host-cc=HOSTCC         use host C compiler HOSTCC
  --host-cflags=HCFLAGS    use HCFLAGS when compiling for host
  --host-cppflags=HCPPFLAGS use HCPPFLAGS when compiling for host
  --host-ld=HOSTLD         use host linker HOSTLD
  --host-ldflags=HLDFLAGS  use HLDFLAGS when linking for host
  --host-extralibs=HLIBS   use libs HLIBS when linking for host
  --host-os=OS             compiler host OS []
  --extra-cflags=ECFLAGS   add ECFLAGS to CFLAGS []
  --extra-cxxflags=ECFLAGS add ECFLAGS to CXXFLAGS []
  --extra-objcflags=FLAGS  add FLAGS to OBJCFLAGS []
  --extra-ldflags=ELDFLAGS add ELDFLAGS to LDFLAGS []
  --extra-ldexeflags=ELDFLAGS add ELDFLAGS to LDEXEFLAGS []
  --extra-ldsoflags=ELDFLAGS add ELDFLAGS to LDSOFLAGS []
  --extra-libs=ELIBS       add ELIBS []
  --extra-version=STRING   version string suffix []
  --optflags=OPTFLAGS      override optimization-related compiler flags
  --nvccflags=NVCCFLAGS    override nvcc flags []
  --build-suffix=SUFFIX    library name suffix []
  --enable-pic             build position-independent code
  --enable-thumb           compile for Thumb instruction set
  --enable-lto             use link-time optimization
  --env="ENV=override"     override the environment variables

Advanced options (experts only):
  --malloc-prefix=PREFIX   prefix malloc and related names with PREFIX
  --custom-allocator=NAME  use a supported custom allocator
  --disable-symver         disable symbol versioning
  --enable-hardcoded-tables use hardcoded tables instead of runtime generation
  --disable-safe-bitstream-reader
                           disable buffer boundary checking in bitreaders
                           (faster, but may crash)
  --sws-max-filter-size=N  the max filter size swscale uses [256]

Optimization options (experts only):
  --disable-asm            disable all assembly optimizations
  --disable-altivec        disable AltiVec optimizations
  --disable-vsx            disable VSX optimizations
  --disable-power8         disable POWER8 optimizations
  --disable-amd3dnow       disable 3DNow! optimizations
  --disable-amd3dnowext    disable 3DNow! extended optimizations
  --disable-mmx            disable MMX optimizations
  --disable-mmxext         disable MMXEXT optimizations
  --disable-sse            disable SSE optimizations
  --disable-sse2           disable SSE2 optimizations
  --disable-sse3           disable SSE3 optimizations
  --disable-ssse3          disable SSSE3 optimizations
  --disable-sse4           disable SSE4 optimizations
  --disable-sse42          disable SSE4.2 optimizations
  --disable-avx            disable AVX optimizations
  --disable-xop            disable XOP optimizations
  --disable-fma3           disable FMA3 optimizations
  --disable-fma4           disable FMA4 optimizations
  --disable-avx2           disable AVX2 optimizations
  --disable-avx512         disable AVX-512 optimizations
  --disable-aesni          disable AESNI optimizations
  --disable-armv5te        disable armv5te optimizations
  --disable-armv6          disable armv6 optimizations
  --disable-armv6t2        disable armv6t2 optimizations
  --disable-vfp            disable VFP optimizations
  --disable-neon           disable NEON optimizations
  --disable-inline-asm     disable use of inline assembly
  --disable-x86asm         disable use of standalone x86 assembly
  --disable-mipsdsp        disable MIPS DSP ASE R1 optimizations
  --disable-mipsdspr2      disable MIPS DSP ASE R2 optimizations
  --disable-msa            disable MSA optimizations
  --disable-msa2           disable MSA2 optimizations
  --disable-mipsfpu        disable floating point MIPS optimizations
  --disable-mmi            disable Loongson SIMD optimizations
  --disable-fast-unaligned consider unaligned accesses slow

Developer options (useful when working on FFmpeg itself):
  --disable-debug          disable debugging symbols
  --enable-debug=LEVEL     set the debug level []
  --disable-optimizations  disable compiler optimizations
  --enable-extra-warnings  enable more compiler warnings
  --disable-stripping      disable stripping of executables and shared libraries
  --assert-level=level     0(default), 1 or 2, amount of assertion testing,
                           2 causes a slowdown at runtime.
  --enable-memory-poisoning fill heap uninitialized allocated space with arbitrary data
  --valgrind=VALGRIND      run "make fate" tests through valgrind to detect memory
                           leaks and errors, using the specified valgrind binary.
                           Cannot be combined with --target-exec
  --enable-ftrapv          Trap arithmetic overflows
  --samples=PATH           location of test samples for FATE, if not set use
                           $FATE_SAMPLES at make invocation time.
  --enable-neon-clobber-test check NEON registers for clobbering (should be
                           used only for debugging purposes)
  --enable-xmm-clobber-test check XMM registers for clobbering (Win64-only;
                           should be used only for debugging purposes)
  --enable-random          randomly enable/disable components
  --disable-random
  --enable-random=LIST     randomly enable/disable specific components or
  --disable-random=LIST    component groups. LIST is a comma-separated list
                           of NAME[:PROB] entries where NAME is a component
                           (group) and PROB the probability associated with
                           NAME (default 0.5).
  --random-seed=VALUE      seed value for --enable/disable-random
  --disable-valgrind-backtrace do not print a backtrace under Valgrind
                           (only applies to --disable-optimizations builds)
  --enable-ossfuzz         Enable building fuzzer tool
  --libfuzzer=PATH         path to libfuzzer
  --ignore-tests=TESTS     comma-separated list (without "fate-" prefix
                           in the name) of tests whose result is ignored
  --enable-linux-perf      enable Linux Performance Monitor API
  --disable-large-tests    disable tests that use a large amount of memory

NOTE: Object files are built at the place where configure is launched.
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市胡岔,隨后出現(xiàn)的幾起案子法希,更是在濱河造成了極大的恐慌,老刑警劉巖靶瘸,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件苫亦,死亡現(xiàn)場離奇詭異,居然都是意外死亡怨咪,警方通過查閱死者的電腦和手機屋剑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來诗眨,“玉大人唉匾,你說我怎么就攤上這事〗吵” “怎么了巍膘?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長芋簿。 經(jīng)常有香客問我峡懈,道長,這世上最難降的妖魔是什么与斤? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任肪康,我火速辦了婚禮荚恶,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘梅鹦。我一直安慰自己裆甩,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布齐唆。 她就那樣靜靜地躺著嗤栓,像睡著了一般。 火紅的嫁衣襯著肌膚如雪箍邮。 梳的紋絲不亂的頭發(fā)上茉帅,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天,我揣著相機與錄音锭弊,去河邊找鬼堪澎。 笑死,一個胖子當(dāng)著我的面吹牛味滞,可吹牛的內(nèi)容都是我干的樱蛤。 我是一名探鬼主播,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼剑鞍,長吁一口氣:“原來是場噩夢啊……” “哼昨凡!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起蚁署,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤便脊,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后光戈,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體哪痰,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年久妆,在試婚紗的時候發(fā)現(xiàn)自己被綠了晌杰。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡筷弦,死狀恐怖肋演,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情奸笤,我是刑警寧澤,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布哼鬓,位于F島的核電站监右,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏异希。R本人自食惡果不足惜健盒,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一绒瘦、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧扣癣,春花似錦惰帽、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至士嚎,卻和暖如春呜魄,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背莱衩。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工爵嗅, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人笨蚁。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓睹晒,卻偏偏與公主長得像,于是被迫代替她去往敵國和親括细。 傳聞我的和親對象是個殘疾皇子伪很,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,916評論 2 344

推薦閱讀更多精彩內(nèi)容