詳解 Qt與 ffmpeg 與 SDl 教程
Qt與 ffmpeg 與 SDl 教程是本文要介紹的內(nèi)容,從多個角度介紹本文,運用了qmake,先來看內(nèi)容。
1. 注釋
從“ #” 開始,到這一行結(jié)束。
2. 指定源文件
- SOURCES = *.cpp
對于多源文件,可用空格分開,如: SOURCES = 1.cpp 2.cpp3.cpp
或者每一個文件可以被列在一個分開的行里面,通過反斜線另起一行,就像這樣 :
- SOURCES = hello.cpp
- main.cpp
一個更冗長的方法是單獨地列出每一個文件,就像這樣:
- SOURCES+= hello.cpp
- SOURCES +=main.cpp
這種方法中使用“ +=” 比“ =” 更安全,因為它只是向已有的列表中添加新的文件,而不是替換整個列表。
3. 指定頭文件
HEADERS = hello.h 或者 HEADERS += hello.h
列出源文件的任何一個方法對頭文件也都適用。
4. 配置信息
CONFIG 用來告訴 qmake 關(guān)于應(yīng)用程序的配置信息。
- CONFIG+= qt warn_on release
在這里使用“ +=” ,是因為我們添加我們的配置選項到任何一個已經(jīng)存在中。這樣做比使用“ =” 那樣替換已經(jīng)指定的所有選項是更安全的。
A> qt 部分告訴 qmake 這個應(yīng)用程序是使用 Qt 來連編的。這也就是說 qmake 在連接和為編譯添加所需的包含路徑的時候會考慮到 Qt 庫的。
B> warn_on 部分告訴 qmake 要把編譯器設(shè)置為輸出警告信息的。
C> release 部分告訴 qmake 應(yīng)用程序必須被連編為一個發(fā)布的應(yīng)用程序。在開發(fā)過程中,程序員也可以使用 debug 來替換 release
5. 指定目標(biāo)文件名
- TARGET = filename
如果不設(shè)置該項目,目標(biāo)名會被自動設(shè)置為跟項目文件一樣的名稱
6. 添加界面文件 (ui)
- INTERFACES = filename.ui
7. 平臺相關(guān)性處理
我們在這里需要做的是根據(jù) qmake 所運行的平臺來使用相應(yīng)的作用域來進行處理。為 Windows 平臺添加的依賴平臺的文件的簡單的作用域看起來就像這樣:
- win32 {
- SOURCES += hello_win.cpp
- }
所以如果 qmake 運行在 Windows 上的時候,它就會把 hello_win.cpp 添加到源文件列表中。如果 qmake 運行在其它平臺上的時候,它會很簡單地把這部分忽略。
8. 如果一個文件不存在,停止 qmake
如果某一個文件不存在的 時候,你也許不想生成一個 Makefile 。我們可以通過使用 exists() 函數(shù)來檢查一個文件是否存在。我們可以通過使用 error() 函數(shù)把正在運 行的 qmake 停下來。這和作用域的工作方式一樣。只要很簡單地用這個函數(shù)來替換作用域條件。對 main.cpp 文件的檢查就像這樣:
- !exists( main.cpp ) {
- error( "No main.cpp file found")
- }
“!” 用來否定這個測試,比如,如果文件存在, exists( main.cpp) 是真,如果文件不存在, !exists( main.cpp ) 是真。
9. 檢查多于一個的條件
假設(shè)你使用 Windows 并且當(dāng)你在命令 行運行你的應(yīng)用程序的時候你想能夠看到 qDebug() 語句。除非你在連編你的程序的時候使用 console 設(shè)置,你不會看到輸出。我們可以很容易地把 console 添加到 CONFIG 行中,這樣在 Windows 下, Makefile 就會有這個設(shè)置。但是如果告訴你我們只是想在當(dāng)我們的應(yīng)用程序運行在 Windows 下并且當(dāng) debug 已經(jīng)在 CONFIG 行中的時候,添加 console 。這需要兩個嵌套的作用域;只要生成一個作用域,然后在它里面再生成 另一個。把設(shè)置放在最里面的作用域里,就像這樣:
- win32 {
- debug {
- CONFIG += console
- }
- }
嵌套的作用域可以使用冒號連接起來,像這樣:
- win32:debug {
- CONFIG += console
- }
10. 摸板
模板變量告訴 qmake 為這個應(yīng)用程序生成哪種 makefile 。下面是可供使用的選擇:
A> app - 建立一個應(yīng)用程序的 makefile 。這是默認(rèn)值,所以如果模板沒有被指定,這個將被使用。
B> lib - 建立一個庫的 makefile 。
C> vcapp - 建立一個應(yīng)用程序的 VisualStudio 項目文件。
D> vclib - 建立一個庫的 VisualStudio 項目文件。
E> subdirs - 這是一個特殊的模板,它可以創(chuàng)建一個能夠進入特定目錄并且為一個項目文件生成 makefile 并且為它調(diào)用 make 的 makefile 。
11、生成 Makefile
當(dāng)你已經(jīng)創(chuàng)建好你的項目文件,生成 Makefile 就很容易了,你所要做的就是先到你所生成的項目文件那里然后輸入:
Makefile 可以像這樣由“ .pro” 文件生成:
- qmake -oMakefile hello.pro
對于 VisualStudio 的用戶, qmake 也可以生成“ .dsp” 文件,例如:
- qmake -tvcapp -o hello.dsp hello.pro
參考文檔:詳解 QT 中.pro文件的寫法
Qmake 不僅僅只用于QT其他地方也用到了,根據(jù)模板的值可以生成app,lib,vclib等待makefile文件
(2)聲明其他的庫
如果你需要在工程中使用其他的庫 , 需要在工程文件里面指定
讓 qmake 找到庫的路徑和相應(yīng)需要連接的庫 , 可以在 LIBS 變量里面添加 . 庫的路徑要給出 , 或者常見的 unix 樣式的符號來指定庫和庫的路徑
例如下面的展示了如何使用指定的庫
- LIBS += -L/usr/local/lib -lmath
可以用類似的方法來指定頭文件的路徑 , 不過是使用 INCLUDEPATH 變量 , 如下面可能添加好幾個頭文件的路徑
- INCLUDEPATH = c:/msdev/include d:/stl/include
不過我的習(xí)慣是下面這樣的 , 比較清晰還有 , 最好 windows 的路徑不要有空格 , 中文也不要有 , 斜杠也推薦用 / 而不是 windows 的 \ 因為跟分行符號 \ 相同了 / 可以在 unix 和 windows 用 , 但是 \ 貌似到了 unix 或 linux 就不行了 , 所以用 / 是通用的
- INCLUDEPATH = c:/msdev/include \
- d:/stl/include
見別人是這樣添加到
在 .pro文件中添加LIBS += -lavformat -lavcodec -lavutil lz -lavutil -lm `sdl-config --cflags --libs`
(3)因為ffmpeg是c程序,所以在編譯的時候需要在頭文件中加入
- extern "C" {
- #include <ffmpeg/avcodec.h>
- #include <ffmpeg/avformat.h>
- }
注:這里的C是大寫。我之前好久沒動手編程,這也查了蠻久,打擊自信心啊!!!!
解釋如下:
1、extern 是 C/C++ 語言中表明函數(shù)和全局變量作用范圍(可見性)的關(guān)鍵字,該關(guān)鍵字告訴編譯器 其聲明的函數(shù)和變量可以在本模塊或其它模塊中使用;
2、與 extern 對應(yīng)的關(guān)鍵字是 static ,被它修飾的全局變量和函數(shù)只能在本模塊中使用。因此,一個函數(shù)或變量只可能被本模塊使用時,其不可能被 extern “C” 修飾;
3、被 extern "C" 修飾的變量和函數(shù)是按照 C 語言方式編譯和連接的;
4、C編譯器和c++編譯器對函數(shù)的翻譯不一樣,如:int root(int a,int b);c對應(yīng)的是_root,c++對應(yīng)的是_root_int_int,因為c不支持重載而c++支持,因此需要識別函數(shù)的參數(shù)。
(4)直接運行可執(zhí)行文件出現(xiàn)缺少minwm10.dll錯誤提示,將D:\Qt\2009.05\mingw\bin;D:\Qt\2009.05\qt\bin添加到環(huán)境變量就可以了。
(5)因為現(xiàn)在比較熟悉opencv,就用opencv+qt嘗試qt連接庫
- INCLUDEPATH += C:\OpenCV\cv\include \
- C:\OpenCV\cvaux\include \
- C:\OpenCV\cxcore\include \
- C:\OpenCV\otherlibs\highgui
- LIBS += C:\OpenCV\lib\cv.lib \
- C:\OpenCV\lib\cvaux.lib \
- C:\OpenCV\lib\cxcore.lib \
- C:\OpenCV\lib\highgui.lib \
程序可以編譯運行,但是出現(xiàn)could not initialize ole的錯誤,不知道該怎么解決,在網(wǎng)上沒查到有用的信息 !以后用的時候再解決這個問題,反正現(xiàn)在也可以編譯了。
#p#
(6)接著用同樣的方法改下.pro文件,添加頭文件和庫文件
- INCLUDEPATH +=
- D:\Qt\2009.05\ffmpeg\include\libavcodec \
- D:\Qt\2009.05\ffmpeg\include\libavdevice \
- D:\Qt\2009.05\ffmpeg\include\libavfilter \
- D:\Qt\2009.05\ffmpeg\include\libavformat \
- D:\Qt\2009.05\ffmpeg\include\libavutil \
- D:\Qt\2009.05\ffmpeg\include\libswscale \
- D:\Qt\2009.05\ffmpeg\include \
- LIBS +=
- D:\Qt\2009.05\ffmpeg\lib\avcodec.lib \
- D:\Qt\2009.05\ffmpeg\lib\avdevice.lib \
- D:\Qt\2009.05\ffmpeg\lib\avfilter.lib \
- D:\Qt\2009.05\ffmpeg\lib\avformat.lib \
- D:\Qt\2009.05\ffmpeg\lib\avutil.lib \
- D:\Qt\2009.05\ffmpeg\lib\swscale.lib \
(7)添加Sdl庫
同理在文件中添加
- D:\Qt\2009.05\SDL\include \
- D:\Qt\2009.05\SDL\lib\SDL.lib \
- D:\Qt\2009.05\SDL\lib\SDLmain.lib \
并加入頭文件
- #include <SDL.h>
- #include <SDL_thread.h>
編譯會出現(xiàn)一個錯誤
- undefined reference to `qMain(int, char**)'
這是因為sdl中的 SDL _main.h已經(jīng)定義了main,加上#undef main就可以解決了
(8)在av_register_all();時遇到 exited with code -1073741515錯誤
這是因為ffmpeg沒有配置好,出現(xiàn)這個錯誤的原因是沒有找到dll,dll一般是放在C:\WINDOWS\system32目錄下的,我把他ffmpeg的庫,復(fù)制到該目錄下就ok了 ×— —×
(9)將tutorial02.c的代碼改改,如下:
- #include <QtGui/QApplication>
- #include "mainwindow.h"
- #include <stdio.h>
- #include <QLabel>
- #include <QWidget>
- extern "C"{
- #include <avcodec.h>
- #include <avformat.h>
- #include <swscale.h>
- #include <SDL.h>
- #include <SDL_thread.h>
- }
- #ifdef __MINGW32__
- #undef main /* Prevents SDL from overriding main() */
- #endif
- int main(int argc, char *argv[])
- {
- QApplication a(argc, argv);
- AVFormatContext *pFormatCtx;
- int i, videoStream;
- AVCodecContext *pCodecCtx;
- AVCodec *pCodec;
- AVFrame *pFrame;
- AVPacket packet;
- int frameFinished;
- float aspect_ratio;
- static struct SwsContext *img_convert_ctx;
- static int sws_flags = SWS_BICUBIC;
- SDL_Overlay *bmp;
- SDL_Surface *screen;
- SDL_Rect rect;
- SDL_Event event;
- MainWindow w;
- QLabel *frame_pre;
- frame_pre = new QLabel;
- QWidget *widget_player;
- widget_player = new QWidget();
- widget_player->setAttribute(Qt::WA_PaintOnScreen);
- widget_player->setAttribute(Qt::WA_NoSystemBackground);
- widget_player->show();
- w.show();
- frame_pre->show();
- av_register_all();
- /*set sdl env*/
- char variable[64];
- #ifdef Q_OS_WIN
- sprintf(variable, "SDL_WINDOWID=0x%lx", widget_player->winId());
- #else
- sprintf(variable, "SDL_WINDOWID=0x%lx", this->winId());
- #endif
- putenv(variable);
- if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) {
- fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError());
- exit(1);
- }
- // Open video file
- if(av_open_input_file(&pFormatCtx, "D:\\Flyhigh.wmv", NULL, 0, NULL)!=0)
- return -1; // Couldn't open file
- // Retrieve stream information
- if(av_find_stream_info(pFormatCtx)<0)
- return -1; // Couldn't find stream information
- // Dump information about file onto standard error
- dump_format(pFormatCtx, 0, "D:\\Flyhigh.wmv", 0);
- // Find the first video stream
- videoStream=-1;
- for(i=0; i<pFormatCtx->nb_streams; i++)
- if(pFormatCtx->streams[i]->codec->codec_type==CODEC_TYPE_VIDEO) {
- videoStream=i;
- break;
- }
- if(videoStream==-1)
- return -1; // Didn't find a video stream
- // Get a pointer to the codec context for the video stream
- pCodecCtx=pFormatCtx->streams[videoStream]->codec;
- // Find the decoder for the video stream
- pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
- if(pCodec==NULL) {
- fprintf(stderr, "Unsupported codec!\n");
- return -1; // Codec not found
- }
- // Open codec
- if(avcodec_open(pCodecCtx, pCodec)<0)
- return -1; // Could not open codec
- // Allocate video frame
- pFrame=avcodec_alloc_frame();
- // Make a screen to put our video
- #ifndef __DARWIN__
- screen = SDL_SetVideoMode(pCodecCtx->width, pCodecCtx->height, 0, 0);
- #else
- screen = SDL_SetVideoMode(pCodecCtx->width, pCodecCtx->height, 24, 0);
- #endif
- if(!screen) {
- fprintf(stderr, "SDL: could not set video mode - exiting\n");
- exit(1);
- }
- // Allocate a place to put our YUV image on that screen
- bmp = SDL_CreateYUVOverlay(pCodecCtx->width,
- pCodecCtx->height,
- SDL_YV12_OVERLAY,
- screen);
- // Read frames and save first five frames to disk
- i=0;
- while(av_read_frame(pFormatCtx, &packet)>=0) {
- // Is this a packet from the video stream?
- if(packet.stream_index==videoStream) {
- // Decode video frame
- avcodec_decode_video(pCodecCtx, pFrame, &frameFinished,
- packet.data, packet.size);
- // Did we get a video frame?
- if(frameFinished) {
- SDL_LockYUVOverlay(bmp);
- AVPicture *pict;
- pict = new AVPicture;
- pict->data[0] = bmp->pixels[0];
- pict->data[1] = bmp->pixels[2];
- pict->data[2] = bmp->pixels[1];
- pict->linesize[0] = bmp->pitches[0];
- pict->linesize[1] = bmp->pitches[2];
- pict->linesize[2] = bmp->pitches[1];
- // Convert the image into YUV format that SDL uses
- if (pCodecCtx->pix_fmt == PIX_FMT_YUV420P) {
- /* as we only generate a YUV420P picture, we must convert it
- to the codec pixel format if needed */
- img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height,
- pCodecCtx->pix_fmt,
- pCodecCtx->width, pCodecCtx->height,
- PIX_FMT_YUV420P,
- sws_flags, NULL, NULL, NULL);
- if (img_convert_ctx == NULL) {
- fprintf(stderr, "Cannot initialize the conversion context\n");
- exit(1);
- }
- sws_scale(img_convert_ctx, pFrame->data, pFrame->linesize,
- 0, pCodecCtx->height, pict->data, pict->linesize);
- }
- // img_convert(&pict, PIX_FMT_YUV420P,
- // (AVPicture *)pFrame, pCodecCtx->pix_fmt,
- // pCodecCtx->width, pCodecCtx->height);
- SDL_UnlockYUVOverlay(bmp);
- rect.x = 0;
- rect.y = 0;
- rect.w = pCodecCtx->width;
- rect.h = pCodecCtx->height;
- SDL_DisplayYUVOverlay(bmp, &rect);
- }
- }
- // Free the packet that was allocated by av_read_frame
- av_free_packet(&packet);
- SDL_PollEvent(&event);
- switch(event.type) {
- case SDL_QUIT:
- SDL_Quit();
- exit(0);
- break;
- default:
- break;
- }
- }
- // Free the YUV frame
- av_free(pFrame);
- // Close the codec
- avcodec_close(pCodecCtx);
- // Close the video file
- av_close_input_file(pFormatCtx);
- return a.exec();
- }
就可以看到圖像了,哈哈。
小結(jié):關(guān)于Qt 與 ffmpeg 與 SDl 教程的內(nèi)容介紹完了,希望本文對你有幫助。更多內(nèi)容請參考編輯推薦。