在前幾篇文章當中,有提到過用源碼去搭建ffmpeg的命令環境開發,為啥要這樣去搭建環境,為什麼不用直接用下面這個命令在ubuntu下安裝多快,簡單又方便:
sudo apt install ffmpeg今天分享ffmepg第五彈:ffmpeg+qt+SDL的真正開發環境,就要用源碼安裝的方式去在qt裡面調用ffmpeg相關的庫;還記得之前源碼搭建創建的三個文件夾不:
bin ffmpeg_sources ffmpeg_buildbin文件夾下是編譯得到的二進位文件
txp@txp-virtual-machine:~/bin$ ls
ffmpeg ffplay ffprobe lame nasm
ndisasm x264ffmpeg_sources文件下是下載的各種庫的源碼:
txp@txp-virtual-machine:~/ffmpeg_sources$ ls
fdk-aac lame-3.100.tar.gz SDL2-2.0.14.tar.gz
ffmpeg libvpx SVT-AV1
ffmpeg-4.2.1 nasm-2.14.02 x264
ffmpeg-4.2.1.tar.bz2 nasm-2.14.02.tar.bz2 x265_git
ffmpeg-snapshot.tar.bz2 opus
lame-3.100 SDL2-2.0.14ffmpeg_build文件夾主要是ffmpeg的一些庫文件,等下下面演示的模板就要調用ffmpeg相關的庫:
txp@txp-virtual-machine:~/ffmpeg_build/lib$ ls
cmake libmp3lame.a libSDL2.la libswscale.a
libavcodec.a libmp3lame.la libSDL2main.a libvpx.a
libavdevice.a libopus.a libSDL2main.la libx264.a
libavfilter.a libopus.la libSDL2.so libx265.a
libavformat.a libpostproc.a libSDL2_test.a pkgconfig
libavutil.a libSDL2-2.0.so.0 libSDL2_test.la
libfdk-aac.a libSDL2-2.0.so.0.14.0 libSvtAv1Enc.a
libfdk-aac.la libSDL2.a libswresample.a因為我已經搭建好了開發環境,從現在來看的話,如果你直接用命令去安裝ffmpeg的話,到時候我們在qt的環境中去調用ffmpeg的庫,至少到目前為止我暫時不知道去如何配置相關路徑來調用ffmpeg的庫;所以我們明白了這點,那麼就擼起袖子肝就是。
二、 qt環境搭建玩過qt的朋友,對於這塊應該比我熟悉多了;不過有可能有一些朋友可能沒有接觸過qt的話,為此我還是簡單演示一下qt的安裝步驟:
首先我們要去qt的官網下載linux版本的源碼安裝包:版本下載地址:
https://download.qt.io/archive/qt/5.12/5.12.10/這裡我直接把qt的源碼包下載到samba服務共享文件下,當然你也可以直接在ubuntu下載:
然後我在share目錄創建一個qt文件夾,用存放qt安裝的地方,然後直接運行這個源碼文件:
接著就會出現qt的安裝界面:
最終qt就安裝完成了,但是如果你運行qt執行失敗的話(注意qtcreator的所放在的路線):
txp@txp-virtual-machine:~/share/qt/Qt5.12.10/Tools/QtCreator/bin$ sudo ./qtcreatorGot keys from plugin meta data ("xcb")
QFactoryLoader::QFactoryLoader() checking directory path "/home/txp/share/qt/Qt5.12.10/Tools/QtCreator/bin/platforms" ...
loaded library "/home/txp/share/qt/Qt5.12.10/Tools/QtCreator/lib/Qt/plugins/platforms/libqxcb.so"
loaded library "Xcursor"
Segmentation fault (core dumped)在這個腳本裡面添加一句話:
然後接著再安裝相關插件:
sudo apt install --reinstall libxcb-xinerama0然後我們執行一下,就可以成功打開qt了:
還有一種方法直接打開qt,因為按照上面的這種方式打開的話,每次都要跑到這個目錄去執行這條語句才行:
txp@txp-virtual-machine:~/share/qt/Qt5.12.10/Tools/QtCreator/bin$
sudo ./qtcreator現在我們只要執行下面這條語句就不用這麼麻煩了:
sudo chown -R txp:txp ~/.config/然後你就可以像在windows環境下去直接打開這個軟體就行:
三、牛刀小試,調用ffmpeg庫 3.1 示例模板,顯示列印ffmpeg的版本:
現在我們打開剛才安裝好的qt軟體,來創建一個工程:
最終一個工程項目就建立好了:
我們可以看到兩個文件,一個是以.pro結尾的qt工程管理配置文件,一個主源碼文件,現在我們就簡單使用ffmpeg庫來列印ffmpeg的版本號:
TEMPLATE = app
CONFIG += console
CONFIG -= app_bundle
CONFIG -= qt
SOURCES += \
main.c現在我們要加入ffmpeg_build目錄下的ffmpeg庫文件:
TEMPLATE = app
CONFIG += console
CONFIG -= app_bundle
CONFIG -= qt
SOURCES += \
main.c
INCLUDEPATH += /home/txp/ffmpeg_build/include
#LIBS += /home/txp/ffmpeg_build/lib/libSDL2.so
LIBS += /home/txp/ffmpeg_build/lib/libavcodec.a \
/home/txp/ffmpeg_build/lib/libavdevice.a \
/home/txp/ffmpeg_build/lib/libavfilter.a \
/home/txp/ffmpeg_build/lib/libavformat.a \
/home/txp/ffmpeg_build/lib/libavutil.a \
/home/txp/ffmpeg_build/lib/libswresample.a \
/home/txp/ffmpeg_build/lib/libswscale.a#include <stdio.h>
//包含ffmpeg頭⽂件
#include "libavutil/avutil.h"
int main()
{
printf("Hello FFMPEG, version is %s\n", av_version_info());
return 0;
}最終結果,顯示ffmpeg的版本為 4.2.1:
20:01:19: Starting /home/txp/share/qt/workspace/build-linux_1-ffmpeg-Desktop_Qt_5_12_10_GCC_64bit-Debug/linux_1-ffmpeg ...
Hello FFMPEG, version is 4.2.1
20:01:19: /home/txp/share/qt/workspace/build-linux_1-ffmpeg-Desktop_Qt_5_12_10_GCC_64bit-Debug/linux_1-ffmpeg exited with code 0注意:我們的ubuntu運行環境一定要是64位的,不然安裝不了這個版本的qt;還有一點,其實我們在.pro文件裡面,按鍵盤上的ctrl鍵然後把滑鼠放到庫文件路徑上,是可以打開裡面的:
3.2、搭建SDL,然後播放yuv格式的視頻文件:
關於什麼是SDL,這裡我就不造輪子了,可以參考雷神的文章介紹:
https://blog.csdn.net/leixiaohua1020/article/details/11954039
下面我們去SDL的官網下源碼包就行安裝:
https://www.libsdl.org/download-2.0.php開始安裝,先把這個源碼包放到ffmpeg_sources目錄下去,然後進行解壓:
txp@txp-virtual-machine:~/ffmpeg_sources$ tar zxf SDL2-2.0.14.tar.gz
txp@txp-virtual-machine:~/ffmpeg_sources$ ls
fdk-aac lame-3.100.tar.gz SDL2-2.0.14.tar.gz
ffmpeg libvpx SVT-AV1
ffmpeg-4.2.1 nasm-2.14.02 x264
ffmpeg-4.2.1.tar.bz2 nasm-2.14.02.tar.bz2 x265_git
ffmpeg-snapshot.tar.bz2 opus
lame-3.100 SDL2-2.0.14然後執行:
txp@txp-virtual-machine:~/ffmpeg_sources/SDL2-2.0.14$ ./autogen.sh
Generating build information using autoconf
This may take a while ...
Now you are ready to run ./configure這裡提示了你直接運行 ./configure:
./configure --prefix=/home/txp/ffmpeg_build --bindir=/home/txp/bintxp@txp-virtual-machine:~/ffmpeg_sources/SDL2-2.0.14$
make -j4
最後再執行sudo make install就行,SDL就安裝成功了:txp@txp-virtual-machine:~/ffmpeg_sources/SDL2-2.0.14$
sudo make install下面我再創建一個工程,具體過程我就再寫了,和第一個工程創建是一樣的:這裡我的main.c文件裡面的原始碼,大家先不用管代碼具體啥意思:
#include <stdio.h>
#include <string.h>
#include "SDL2/SDL.h"//包含SDL動態庫文件
//自定義消息類型
#define REFRESH_EVENT (SDL_USEREVENT + 1) // 請求畫面刷新事件
#define QUIT_EVENT (SDL_USEREVENT + 2) // 退出事件
//定義解析度
// YUV像素解析度
#define YUV_WIDTH 320
#define YUV_HEIGHT 240
//定義YUV格式
#define YUV_FORMAT SDL_PIXELFORMAT_IYUV
int s_thread_exit = 0; // 退出標誌 = 1則退出
int refresh_video_timer(void *data)
{
while (!s_thread_exit)
{
SDL_Event event;
event.type = REFRESH_EVENT;
SDL_PushEvent(&event);
SDL_Delay(40);
}
s_thread_exit = 0;
//push quit event
SDL_Event event;
event.type = QUIT_EVENT;
SDL_PushEvent(&event);
return 0;
}
#undef main
int main(int argc, char* argv[])
{
//初始化 SDL
if(SDL_Init(SDL_INIT_VIDEO))
{
fprintf( stderr, "Could not initialize SDL - %s\n", SDL_GetError());
return -1;
}
// SDL
SDL_Event event; // 事件
SDL_Rect rect; // 矩形
SDL_Window *window = NULL; // 窗口
SDL_Renderer *renderer = NULL; // 渲染
SDL_Texture *texture = NULL; // 紋理
SDL_Thread *timer_thread = NULL; // 請求刷新線程
uint32_t pixformat = YUV_FORMAT; // YUV420P,即是SDL_PIXELFORMAT_IYUV
// 解析度
// 1. YUV的解析度
int video_width = YUV_WIDTH;
int video_height = YUV_HEIGHT;
// 2.顯示窗口的解析度
int win_width = YUV_WIDTH;
int win_height = YUV_WIDTH;
// YUV文件句柄
FILE *video_fd = NULL;
const char *yuv_path = "yuv420p_320x240.yuv";
size_t video_buff_len = 0;
uint8_t *video_buf = NULL; //讀取數據後先把放到buffer裡面
// 我們測試的文件是YUV420P格式
uint32_t y_frame_len = video_width * video_height;
uint32_t u_frame_len = video_width * video_height / 4;
uint32_t v_frame_len = video_width * video_height / 4;
uint32_t yuv_frame_len = y_frame_len + u_frame_len + v_frame_len;
//創建窗口
window = SDL_CreateWindow("Simplest YUV Player",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
video_width, video_height,
SDL_WINDOW_OPENGL|SDL_WINDOW_RESIZABLE);
if(!window)
{
fprintf(stderr, "SDL: could not create window, err:%s\n",SDL_GetError());
goto _FAIL;
}
// 基於窗口創建渲染器
renderer = SDL_CreateRenderer(window, -1, 0);
// 基於渲染器創建紋理
texture = SDL_CreateTexture(renderer,
pixformat,
SDL_TEXTUREACCESS_STREAMING,
video_width,
video_height);
// 分配空間
video_buf = (uint8_t*)malloc(yuv_frame_len);
if(!video_buf)
{
fprintf(stderr, "Failed to alloce yuv frame space!\n");
goto _FAIL;
}
// 打開YUV文件
video_fd = fopen(yuv_path, "rb");
if( !video_fd )
{
fprintf(stderr, "Failed to open yuv file\n");
goto _FAIL;
}
// 創建請求刷新線程
timer_thread = SDL_CreateThread(refresh_video_timer,
NULL,
NULL);
while (1)
{
// 收取SDL系統裡面的事件
SDL_WaitEvent(&event);
if(event.type == REFRESH_EVENT) // 畫面刷新事件
{
video_buff_len = fread(video_buf, 1, yuv_frame_len, video_fd);
if(video_buff_len <= 0)
{
fprintf(stderr, "Failed to read data from yuv file!\n");
goto _FAIL;
}
// 設置紋理的數據 video_width = 320, plane
SDL_UpdateTexture(texture, NULL, video_buf, video_width);
// 顯示區域,可以通過修改w和h進行縮放
rect.x = 0;
rect.y = 0;
float w_ratio = win_width * 1.0 /video_width;
float h_ratio = win_height * 1.0 /video_height;
// 320x240 怎麼保持原視頻的寬高比例
rect.w = video_width * w_ratio;
rect.h = video_height * h_ratio;
// rect.w = video_width * 0.5;
// rect.h = video_height * 0.5;
// 清除當前顯示
SDL_RenderClear(renderer);
// 將紋理的數據拷貝給渲染器
SDL_RenderCopy(renderer, texture, NULL, &rect);
// 顯示
SDL_RenderPresent(renderer);
}
else if(event.type == SDL_WINDOWEVENT)
{
//If Resize
SDL_GetWindowSize(window, &win_width, &win_height);
printf("SDL_WINDOWEVENT win_width:%d, win_height:%d\n",win_width,
win_height );
}
else if(event.type == SDL_QUIT) //退出事件
{
s_thread_exit = 1;
}
else if(event.type == QUIT_EVENT)
{
break;
}
}
_FAIL:
s_thread_exit = 1; // 保證線程能夠退出
// 釋放資源
if(timer_thread)
SDL_WaitThread(timer_thread, NULL); // 等待線程退出
if(video_buf)
free(video_buf);
if(video_fd)
fclose(video_fd);
if(texture)
SDL_DestroyTexture(texture);
if(renderer)
SDL_DestroyRenderer(renderer);
if(window)
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}.pro文件配置成:
TEMPLATE = app
CONFIG += console
CONFIG -= app_bundle
CONFIG -= qt
SOURCES += \
main.c
INCLUDEPATH += /home/txp/ffmpeg_build/include
LIBS += /home/txp/ffmpeg_build/lib/libSDL2.so最終運行結果就可以看到在播放一個yuv格式的視頻文件了:
註:這裡的播放yuv格式的視頻文件,我是事先已經準備好的:
同時要注意我們要把播放的視頻文件放到工程目錄下,不然播放是不會成功的:
四、總結:
現在ffmpeg真正的開發環境已經搭建完了,其實上面搭建環境蠻折騰人的,特別是源碼安裝ffmpeg。好了今天的文章就分享到這裡了,如果你在看完文章後,有不懂的地方可以後臺私聊我。
我是txp,一個半路出家的程序猿打工仔,我們下期見!
站在巨人的肩膀上:
https://blog.csdn.net/u012768805/article/details/98756925
https://ke.qq.com/webcourse/index.html#cid=468797&term_id=100561187&taid=4217090949457725&vid=5285890812708218640
https://www.libsdl.org/download-2.0.php