c++ 編譯安裝ffmpeg


一,ubuntu源碼編譯安裝

1,如何安裝

參考:感謝原作者

基本操作就是:config,make,make install

需要注意的是,如何證明自己安裝成功了呢?大約是由於版本升級的原因,並不能按照原作者的方式去證實

2,安裝完成以后讓pkg-config幫我們管理各種頭文件和lib

配置方法:https://www.cnblogs.com/0-lingdu/p/10655176.html第15條

如何證明配置好了呢?

pkg-config --cflags libavformat
#能看到返回值啦

3,那么so庫怎么辦呢?

添加到環境變量:

sudo gedit /etc/ld.so.conf打開文本后,加入如下路徑:/usr/local/ffmpeg/lib/

#最后面的斜杠一定要帶上,別忘了!

4,配置完了以后,如何證明自己ffmpeg安裝成功了呢?

如下代碼是抄的(無法添加到代碼專用框里,將就一下,注意自己找個mp4文件,路徑要寫對):

#include <iostream>
#include <unistd.h>

extern "C"
{
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
}

#pragma comment(lib, "avformat.a")
#pragma comment(lib, "avutil.a")
#pragma comment(lib, "avcodec.a")

using namespace std;

int main()
{
av_register_all(); //ffmpeg程序的第一句,注冊庫

AVFormatContext *afc = NULL;

//打開視頻文件
int nRet = avformat_open_input(&afc, "test1.mp4", 0, 0);
if (nRet < 0)
{
cout << "找不到視頻文件" << endl;
}
else
{
cout << "視頻打開成功" << endl;
}
int durTime = afc->duration / AV_TIME_BASE; //視頻時間 4分20秒
unsigned int numberOfStream = afc->nb_streams; //包含流的個數2:一個視頻流一個音頻流

for (int i = 0; i < afc->nb_streams; i++)
{
AVCodecContext *acc = afc->streams[i]->codec;
if (acc->codec_type == AVMEDIA_TYPE_VIDEO) //如果是視頻類型
{
AVCodec *codec = avcodec_find_decoder(acc->codec_id);
if (!codec)
{
cout << "沒有該類型解碼器" << endl;
}

int ret = avcodec_open2(acc, codec, NULL);
if (ret != 0)
{
char buf[1024] = { 0 };
av_strerror(ret, buf, sizeof(buf));
}

cout << "解碼器打開成功" << endl;
}
}

if (afc)
{
avformat_close_input(&afc); //關閉視頻流
}

//system("pause");
pause();
return 0;
}

如何編譯:

g++ main.cpp -o main.out  `pkg-config --cflags --libs libavcodec libavdevice libavfilter libavformat libavutil libswresample libswscale `

執行結果返回:

視頻打開成功,解碼器打開成功,就可以了.

臨時添加環境變量:

echo $PATH  
#看看環境變量里都有啥
PATH="$PATH:/usr/local/ffmpeg/bin"
#往環境變量里加點東西

永久添加環境變量:

打開~/.bashrc文件最末添加命令:
PATH=$PATH:/usr/local/your_path

二,win10+vs2015配置ffmpeg開發環境

首先聲明一點哈,windows系統上配置ffmpeg開發環境和源碼編譯安裝ffmpeg不一樣。一開始本人各種查找win10源碼編譯ffmpeg各種教程各種復雜,后來才知道,官網提供現成的頭文件和庫文件,直接下下來用就可以了。囧。。

1,下載

官網鏈接

本人下載的時候是這樣的

算了,無法上傳圖片,本人下的是4.2.2 win64選項下的 Shared和Dev版本(后期兩個版本都用得到)

本地新建D:/ffmpeg文件夾,將下載的zip包放進去,解壓就會出現兩個文件夾:ffmpeg-4.2.2-win64-shared(內含bin)和ffmpeg-4.2.2-win64-dev(內含include和lib)

2,配置開發環境

打開vs2015,新建空項目,個人喜歡使用“release”和x64作為平台解決方案

1),添加ffmpeg的頭文件:項目--屬性--c++--附加包含目錄 ,新增一項“D:\ffmpeg\ffmpeg-4.2.2-win64-dev\include”。

2),添加lib:項目--屬性--鏈接器--常規--附加庫目錄,新增一項“D:\ffmpeg\ffmpeg-4.2.2-win64-dev\lib”。如果是其他項目,還需要在項目--屬性--鏈接器--輸入--附加依賴項 中輸入具體的lib名稱(比如opencv),但是,我們的ffmpeg這樣做好像並不管用哦,那咋整?

建議如下操作,具體原因不詳,但是能跑。

#pragma comment(lib,"avutil.lib")
#pragma comment(lib,"avformat.lib")
#pragma comment(lib,"avcodec.lib")
#pragma comment(lib,"swscale.lib")
//在代碼中明確地關聯lib也是可以的

extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include <libavutil/pixfmt.h>
}
//順帶一提,ffmpeg的頭文件需要按照c語言的規則引進來

3),關聯dll動態庫:上述一通操作以后,編譯應該是問題不大,可以生成exe文件,但是我們還是無法運行,提示缺少好幾個動態庫,那么我們就只能,把D:\ffmpeg\ffmpeg-4.2.2-win64-shared\bin里面所有的dll文件復制到運行環境下(和生成的exe同一個目錄下),我非常納悶ffmpeg為什么不把include,lib和bin放到同一個zip包中供大家下載,我也不確定把shared版本的dll粗暴地復制到dev版本的代碼環境中是不是一點問題都沒有,只不過在我自己的例子中,能跑。嗯嗯,估計是問題不大。不過話說回來,ffmpeg是我非常喜歡的一個包,我能感覺到它的開發者肯定是非常愛干凈愛整潔的人,也很細致貼心,,比心,,,不管是ubuntu還是windows上,編譯起來都沒有什么糟心的問題,點贊。。

3,編譯運行的代碼實例

此處感謝原作者

但是原作者的代碼我跑不起來,修改了一處代碼:

if (avformat_open_input(&pFormatCtx, input, NULL, 0) != 0)

下面貼的是本人能跑起來的版本:

//main.cpp
//#include <stdio.h>
//#include <stdlib.h>
#include <iostream>

#pragma comment(lib,"avutil.lib")
#pragma comment(lib,"avformat.lib")
#pragma comment(lib,"avcodec.lib")
#pragma comment(lib,"swscale.lib")

extern "C"
{

    //編碼
#include "libavcodec/avcodec.h"
    //封裝格式處理
#include "libavformat/avformat.h"
    //像素處理
#include "libswscale/swscale.h"
};


int main(int argc, char* argv[])
{
    //獲取輸入輸出文件名
    const char *input = "1.mp4";
    const char *output = "test.yuv";

    //1.注冊所有組件
    av_register_all();

    //封裝格式上下文,統領全局的結構體,保存了視頻文件封裝格式的相關信息
    AVFormatContext *pFormatCtx = avformat_alloc_context();

    //2.打開輸入視頻文件
    if (avformat_open_input(&pFormatCtx, input, NULL, 0) != 0)
    {
        printf("%s", "無法打開輸入視頻文件");
        return -1;
    }

    //3.獲取視頻文件信息
    if (avformat_find_stream_info(pFormatCtx, NULL) < 0)
    {
        printf("%s", "無法獲取視頻文件信息");
        return -1;
    }

    //獲取視頻流的索引位置
    //遍歷所有類型的流(音頻流、視頻流、字幕流),找到視頻流
    int v_stream_idx = -1;
    int i = 0;
    //number of streams
    for (; i < pFormatCtx->nb_streams; i++)
    {
        //流的類型
        if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
        {
            v_stream_idx = i;
            break;
        }
    }

    if (v_stream_idx == -1)
    {
        printf("%s", "找不到視頻流\n");
        return -1;
    }

    //只有知道視頻的編碼方式,才能夠根據編碼方式去找到解碼器
    //獲取視頻流中的編解碼上下文
    AVCodecContext *pCodecCtx = pFormatCtx->streams[v_stream_idx]->codec;
    //4.根據編解碼上下文中的編碼id查找對應的解碼
    AVCodec *pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
    if (pCodec == NULL)
    {
        printf("%s", "找不到解碼器\n");
        return -1;
    }

    //5.打開解碼器
    if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0)
    {
        printf("%s", "解碼器無法打開\n");
        return -1;
    }

    //輸出視頻信息
    printf("視頻的文件格式:%s", pFormatCtx->iformat->name);
    printf("視頻時長:%d", (pFormatCtx->duration) / 1000000);
    printf("視頻的寬高:%d,%d", pCodecCtx->width, pCodecCtx->height);
    printf("解碼器的名稱:%s", pCodec->name);

    //准備讀取
    //AVPacket用於存儲一幀一幀的壓縮數據(H264)
    //緩沖區,開辟空間
    AVPacket *packet = (AVPacket*)av_malloc(sizeof(AVPacket));

    //AVFrame用於存儲解碼后的像素數據(YUV)
    //內存分配
    AVFrame *pFrame = av_frame_alloc();
    //YUV420
    AVFrame *pFrameYUV = av_frame_alloc();
    //只有指定了AVFrame的像素格式、畫面大小才能真正分配內存
    //緩沖區分配內存
    uint8_t *out_buffer = (uint8_t *)av_malloc(avpicture_get_size(AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height));
    //初始化緩沖區
    avpicture_fill((AVPicture *)pFrameYUV, out_buffer, AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height);

    //用於轉碼(縮放)的參數,轉之前的寬高,轉之后的寬高,格式等
    struct SwsContext *sws_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt,
        pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_YUV420P,
        SWS_BICUBIC, NULL, NULL, NULL);
    int got_picture, ret;

    FILE *fp_yuv = fopen(output, "wb+");

    int frame_count = 0;

    //6.一幀一幀的讀取壓縮數據
    while (av_read_frame(pFormatCtx, packet) >= 0)
    {
        //只要視頻壓縮數據(根據流的索引位置判斷)
        if (packet->stream_index == v_stream_idx)
        {
            //7.解碼一幀視頻壓縮數據,得到視頻像素數據
            ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet);
            if (ret < 0)
            {
                printf("%s", "解碼錯誤");
                return -1;
            }

            //為0說明解碼完成,非0正在解碼
            if (got_picture)
            {
                //AVFrame轉為像素格式YUV420,寬高
                //2 6輸入、輸出數據
                //3 7輸入、輸出畫面一行的數據的大小 AVFrame 轉換是一行一行轉換的
                //4 輸入數據第一列要轉碼的位置 從0開始
                //5 輸入畫面的高度
                sws_scale(sws_ctx, pFrame->data, pFrame->linesize, 0, pCodecCtx->height,
                    pFrameYUV->data, pFrameYUV->linesize);

                //輸出到YUV文件
                //AVFrame像素幀寫入文件
                //data解碼后的圖像像素數據(音頻采樣數據)
                //Y 亮度 UV 色度(壓縮了) 人對亮度更加敏感
                //U V 個數是Y的1/4
                int y_size = pCodecCtx->width * pCodecCtx->height;
                fwrite(pFrameYUV->data[0], 1, y_size, fp_yuv);
                fwrite(pFrameYUV->data[1], 1, y_size / 4, fp_yuv);
                fwrite(pFrameYUV->data[2], 1, y_size / 4, fp_yuv);

                frame_count++;
                printf("解碼第%d幀\n", frame_count);
            }
        }

        //釋放資源
        av_free_packet(packet);
    }

    fclose(fp_yuv);

    av_frame_free(&pFrame);

    avcodec_close(pCodecCtx);

    avformat_free_context(pFormatCtx);


    return 0;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM