• 详细介绍Qt,ffmpeg 和SDL开发


     
     
    Qt ffmpeg SDl 教程是本文要介绍的内容,从多个角度介绍本文,运用了qmake,先来看内容。
    1.  注释
    从“ #” 开始,到这一行结束。
    2.  指定源文件
    1.           SOURCES = *.cpp  
    对于多源文件,可用空格分开,如: SOURCES = 1.cpp 2.cpp3.cpp
    或者每一个文件可以被列在一个分开的行里面,通过反斜线另起一行,就像这样 :
    1.           SOURCES = hello.cpp   
    2.                main.cpp  
    一个更冗长的方法是单独地列出每一个文件,就像这样:
    1.           SOURCES+= hello.cpp   
    2.           SOURCES +=main.cpp  
    这种方法中使用“ +=” 比“ =” 更安全,因为它只是向已有的列表中添加新的文件,而不是替换整个列表。
    3.  指定头文件
    HEADERS = hello.h 或者 HEADERS += hello.h
    列出源文件的任何一个方法对头文件也都适用。
    4.  配置信息
    CONFIG 用来告诉 qmake 关于应用程序的配置信息。
    1.           CONFIG+= qt warn_on release  
    在这里使用“ +=” ,是因为我们添加我们的配置选项到任何一个已经存在中。这样做比使用“ =” 那样替换已经指定的所有选项是更安全的。
    A> qt 部分告诉 qmake 这个应用程序是使用 Qt 来连编的。这也就是说 qmake 在连接和为编译添加所需的包含路径的时候会考虑到 Qt 库的。
    B> warn_on 部分告诉 qmake 要把编译器设置为输出警告信息的。
    C> release 部分告诉 qmake 应用程序必须被连编为一个发布的应用程序。在开发过程中,程序员也可以使用 debug 来替换 release
    5.  指定目标文件名
    1.           TARGET = filename  
    如果不设置该项目,目标名会被自动设置为跟项目文件一样的名称
    6.  添加界面文件 (ui)
    1.           INTERFACES = filename.ui  
    7.  平台相关性处理
    我们在这里需要做的是根据 qmake 所运行的平台来使用相应的作用域来进行处理。为 Windows 平台添加的依赖平台的文件的简单的作用域看起来就像这样:
    1.           win32 {   
    2.           SOURCES += hello_win.cpp   
    3.           }  
    所以如果 qmake 运行在 Windows 上的时候,它就会把 hello_win.cpp 添加到源文件列表中。如果 qmake 运行在其它平台上的时候,它会很简单地把这部分忽略。
    8.  如果一个文件不存在,停止 qmake
    如果某一个文件不存在的 时候,你也许不想生成一个 Makefile 。我们可以通过使用 exists() 函数来检查一个文件是否存在。我们可以通过使用 error() 函数把正在运 行的 qmake 停下来。这和作用域的工作方式一样。只要很简单地用这个函数来替换作用域条件。对 main.cpp 文件的检查就像这样:
    1.           !exists( main.cpp ) {   
    2.             error( "No main.cpp file found")   
    3.           }  
    “!” 用来否定这个测试,比如,如果文件存在, exists( main.cpp) 是真,如果文件不存在, !exists( main.cpp ) 是真。
    9.  检查多于一个的条件
    假设你使用 Windows 并且当你在命令 行运行你的应用程序的时候你想能够看到 qDebug() 语句。除非你在连编你的程序的时候使用 console 设置,你不会看到输出。我们可以很容易地把 console 添加到 CONFIG 行中,这样在 Windows 下, Makefile 就会有这个设置。但是如果告诉你我们只是想在当我们的应用程序运行在 Windows 下并且当 debug 已经在 CONFIG 行中的时候,添加 console 。这需要两个嵌套的作用域;只要生成一个作用域,然后在它里面再生成 另一个。把设置放在最里面的作用域里,就像这样:
    1.           win32 {   
    2.             debug {   
    3.                CONFIG += console   
    4.             }   
    5.           }  
    嵌套的作用域可以使用冒号连接起来,像这样:
    1.           win32:debug {   
    2.           CONFIG += console   
    3.           }  
    10.  摸板
    模板变量告诉 qmake 为这个应用程序生成哪种 makefile 。下面是可供使用的选择:
    A> app - 建立一个应用程序的 makefile 。这是默认值,所以如果模板没有被指定,这个将被使用。
    B> lib - 建立一个库的 makefile 。
    C> vcapp - 建立一个应用程序的 VisualStudio 项目文件。
    D> vclib - 建立一个库的 VisualStudio 项目文件。
    E> subdirs - 这是一个特殊的模板,它可以创建一个能够进入特定目录并且为一个项目文件生成 makefile 并且为它调用 make 的 makefile 。
    11、生成 Makefile
    当你已经创建好你的项目文件,生成 Makefile 就很容易了,你所要做的就是先到你所生成的项目文件那里然后输入:
    Makefile 可以像这样由“ .pro” 文件生成:
    1.           qmake -oMakefile hello.pro  
    对于 VisualStudio 的用户, qmake 也可以生成“ .dsp” 文件,例如:
    1.           qmake -tvcapp -o hello.dsp hello.pro  
    Qmake 不仅仅只用于QT其他地方也用到了,根据模板的值可以生成app,lib,vclib等待makefile文件
    (2)声明其他的库
    如果你需要在工程中使用其他的库 , 需要在工程文件里面指定
    让 qmake 找到库的路径和相应需要连接的库 , 可以在 LIBS 变量里面添加 . 库的路径要给出 , 或者常见的 unix 样式的符号来指定库和库的路径
    例如下面的展示了如何使用指定的库
    1.           LIBS += -L/usr/local/lib -lmath  
    可以用类似的方法来指定头文件的路径 , 不过是使用 INCLUDEPATH 变量 , 如下面可能添加好几个头文件的路径
    1.           INCLUDEPATH = c:/msdev/include d:/stl/include  
    不过我的习惯是下面这样的 , 比较清晰还有 , 最好 windows 的路径不要有空格 , 中文也不要有 , 斜杠也推荐用 / 而不是 windows 的 因为跟分行符号 相同了 / 可以在 unix 和 windows 用 , 但是 貌似到了 unix 或 linux 就不行了 , 所以用 / 是通用的
    1.           INCLUDEPATH = c:/msdev/include    
    2.                                       d:/stl/include  
    见别人是这样添加到
    在 .pro文件中添加LIBS += -lavformat  -lavcodec -lavutil lz -lavutil -lm `sdl-config --cflags --libs`
    (3)因为ffmpeg是c程序,所以在编译的时候需要在头文件中加入
    1.           extern "C" {  
    2.           #include <ffmpeg/avcodec.h> 
    3.           #include <ffmpeg/avformat.h> 
    4.           }  
    注:这里的C是大写。我之前好久没动手编程,这也查了蛮久,打击自信心啊!!!!
    解释如下:
    1 、extern 是 C/C++ 语言中表明函数和全局变量作用范围(可见性)的关键字,该关键字告诉编译器其声明的函数和变量可以在本模块或其它模块中使用;
    2 、与 extern 对应的关键字是 static ,被它修饰的全局变量和函数只能在本模块中使用。因此,一个函数或变量只可能被本模块使用时,其不可能被 extern “C” 修饰;
    3 、被 extern "C" 修饰的变量和函数是按照 C 语言方式编译和连接的;
    4 、C编译器和c++编译器对函数的翻译不一样,如:int  root(int a,int b);c对应的是_root,c++对应的是_root_int_int,因为c不支持重载而c++支持,因此需要识别函数的参数。
    (4)直接运行可执行文件出现缺少minwm10.dll错误提示,将D:Qt2009.05mingwin;D:Qt2009.05qtin添加到环境变量就可以了。
    (5)因为现在比较熟悉opencv,就用opencv+qt尝试qt连接库
    1.           INCLUDEPATH +=   C:OpenCVcvinclude   
    2.             C:OpenCVcvauxinclude   
    3.             C:OpenCVcxcoreinclude   
    4.             C:OpenCVotherlibshighgui  
    5.           LIBS +=   C:OpenCVlibcv.lib   
    6.             C:OpenCVlibcvaux.lib   
    7.             C:OpenCVlibcxcore.lib   
    8.             C:OpenCVlibhighgui.lib   
    程序可以编译运行,但是出现could not initialize ole的错误,不知道该怎么解决,在网上没查到有用的信息 !以后用的时候再解决这个问题,反正现在也可以编译了。
    (6)接着用同样的方法改下.pro文件,添加头文件和库文件
    1.           INCLUDEPATH +=   
    2.            
    3.                          D:Qt2009.05ffmpegincludelibavcodec   
    4.                          D:Qt2009.05ffmpegincludelibavdevice   
    5.                          D:Qt2009.05ffmpegincludelibavfilter   
    6.                          D:Qt2009.05ffmpegincludelibavformat   
    7.                          D:Qt2009.05ffmpegincludelibavutil   
    8.                          D:Qt2009.05ffmpegincludelibswscale   
    9.                          D:Qt2009.05ffmpeginclude   
    10.       LIBS +=   
    11.        
    12.       D:Qt2009.05ffmpeglibavcodec.lib   
    13.       D:Qt2009.05ffmpeglibavdevice.lib   
    14.       D:Qt2009.05ffmpeglibavfilter.lib   
    15.       D:Qt2009.05ffmpeglibavformat.lib   
    16.       D:Qt2009.05ffmpeglibavutil.lib   
    17.       D:Qt2009.05ffmpeglibswscale.lib   
    (7)添加Sdl库
    同理在文件中添加
    1.           D:Qt2009.05SDLinclude    
    2.           D:Qt2009.05SDLlibSDL.lib   
    3.           D:Qt2009.05SDLlibSDLmain.lib   
    并加入头文件
    1.           #include <SDL.h> 
    2.           #include <SDL_thread.h>  
    编译会出现一个错误
    1.           undefined reference to `qMain(int, char**)'  
    这是因为sdl中的 SDL _main.h已经定义了main,加上#undef main就可以解决了
    (8)在av_register_all();时遇到 exited with code -1073741515错误
    这是因为ffmpeg没有配置好,出现这个错误的原因是没有找到dll,dll一般是放在C:WINDOWSsystem32目录下的,我把他ffmpeg的库,复制到该目录下就ok了 ×— —×
    (9)将tutorial02.c的代码改改,如下:
    1.           #include <QtGui/QApplication> 
    2.           #include "mainwindow.h"  
    3.           #include <stdio.h> 
    4.           #include <QLabel> 
    5.           #include <QWidget>   
    6.            
    7.           extern "C"{  
    8.           #include <avcodec.h> 
    9.           #include <avformat.h> 
    10.       #include <swscale.h> 
    11.       #include <SDL.h> 
    12.       #include <SDL_thread.h> 
    13.       }   
    14.        
    15.       #ifdef __MINGW32__  
    16.       #undef main /* Prevents SDL from overriding main() */  
    17.       #endif   
    18.        
    19.       int main(int argc, char *argv[])  
    20.       {   
    21.            QApplication a(argc, argv);   
    22.        
    23.            AVFormatContext *pFormatCtx;  
    24.            int             i, videoStream;  
    25.            AVCodecContext  *pCodecCtx;  
    26.            AVCodec         *pCodec;  
    27.            AVFrame         *pFrame;  
    28.            AVPacket        packet;  
    29.            int             frameFinished;  
    30.            float           aspect_ratio;  
    31.            static struct   SwsContext *img_convert_ctx;  
    32.            static int sws_flags = SWS_BICUBIC;   
    33.        
    34.            SDL_Overlay     *bmp;  
    35.            SDL_Surface     *screen;  
    36.            SDL_Rect        rect;  
    37.            SDL_Event       event;   
    38.        
    39.            MainWindow w;  
    40.            QLabel *frame_pre;  
    41.            frame_pre = new QLabel;  
    42.            QWidget *widget_player;  
    43.            widget_player = new QWidget();  
    44.            widget_player->setAttribute(Qt::WA_PaintOnScreen);  
    45.            widget_player->setAttribute(Qt::WA_NoSystemBackground);  
    46.            widget_player->show();  
    47.            w.show();  
    48.            frame_pre->show();   
    49.        
    50.            av_register_all();   
    51.        
    52.           /*set sdl env*/  
    53.           char variable[64];  
    54.           #ifdef Q_OS_WIN  
    55.           sprintf(variable, "SDL_WINDOWID=0x%lx", widget_player->winId());  
    56.           #else  
    57.           sprintf(variable, "SDL_WINDOWID=0x%lx", this->winId());  
    58.           #endif  
    59.           putenv(variable);   
    60.        
    61.           if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) {  
    62.               fprintf(stderr, "Could not initialize SDL - %s
    ", SDL_GetError());  
    63.               exit(1);  
    64.             }   
    65.        
    66.           // Open video file  
    67.           if(av_open_input_file(&pFormatCtx, "D:\Flyhigh.wmv", NULL, 0, NULL)!=0)  
    68.             return -1; // Couldn't open file   
    69.        
    70.           // Retrieve stream information  
    71.           if(av_find_stream_info(pFormatCtx)<0)  
    72.              return -1; // Couldn't find stream information   
    73.        
    74.           // Dump information about file onto standard error  
    75.           dump_format(pFormatCtx, 0, "D:\Flyhigh.wmv", 0);   
    76.        
    77.           // Find the first video stream  
    78.           videoStream=-1;  
    79.           for(i=0; i<pFormatCtx->nb_streams; i++)  
    80.               if(pFormatCtx->streams[i]->codec->codec_type==CODEC_TYPE_VIDEO) {  
    81.                 videoStream=i;  
    82.                 break;  
    83.               }  
    84.           if(videoStream==-1)  
    85.                return -1; // Didn't find a video stream   
    86.        
    87.           // Get a pointer to the codec context for the video stream  
    88.           pCodecCtx=pFormatCtx->streams[videoStream]->codec;   
    89.        
    90.           // Find the decoder for the video stream  
    91.           pCodec=avcodec_find_decoder(pCodecCtx->codec_id);  
    92.             if(pCodec==NULL) {  
    93.               fprintf(stderr, "Unsupported codec!
    ");  
    94.               return -1; // Codec not found  
    95.             }   
    96.        
    97.           // Open codec  
    98.           if(avcodec_open(pCodecCtx, pCodec)<0)  
    99.             return -1; // Could not open codec   
    100.    
    101.       // Allocate video frame  
    102.       pFrame=avcodec_alloc_frame();   
    103.    
    104.       // Make a screen to put our video  
    105.       #ifndef __DARWIN__  
    106.               screen = SDL_SetVideoMode(pCodecCtx->width, pCodecCtx->height, 0, 0);  
    107.       #else  
    108.               screen = SDL_SetVideoMode(pCodecCtx->width, pCodecCtx->height, 24, 0);  
    109.       #endif  
    110.       if(!screen) {  
    111.           fprintf(stderr, "SDL: could not set video mode - exiting
    ");  
    112.           exit(1);  
    113.         }   
    114.    
    115.       // Allocate a place to put our YUV image on that screen  
    116.       bmp = SDL_CreateYUVOverlay(pCodecCtx->width,  
    117.                                          pCodecCtx->height,  
    118.                                          SDL_YV12_OVERLAY,  
    119.                                          screen);   
    120.    
    121.       // Read frames and save first five frames to disk  
    122.       i=0;   
    123.    
    124.       while(av_read_frame(pFormatCtx, &packet)>=0) {  
    125.       // Is this a packet from the video stream?  
    126.       if(packet.stream_index==videoStream) {  
    127.       // Decode video frame  
    128.       avcodec_decode_video(pCodecCtx, pFrame, &frameFinished,  
    129.                                      packet.data, packet.size);  
    130.       // Did we get a video frame?  
    131.       if(frameFinished) {  
    132.                         SDL_LockYUVOverlay(bmp);  
    133.                         AVPicture *pict;  
    134.                         pict = new AVPicture;  
    135.                         pict->data[0] = bmp->pixels[0];  
    136.                         pict->data[1] = bmp->pixels[2];  
    137.                         pict->data[2] = bmp->pixels[1];   
    138.    
    139.                         pict->linesize[0] = bmp->pitches[0];  
    140.                         pict->linesize[1] = bmp->pitches[2];  
    141.                         pict->linesize[2] = bmp->pitches[1];   
    142.    
    143.                         // Convert the image into YUV format that SDL uses  
    144.                         if (pCodecCtx->pix_fmt == PIX_FMT_YUV420P) {  
    145.                         /* as we only generate a YUV420P picture, we must convert it  
    146.                           to the codec pixel format if needed */  
    147.                         img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height,  
    148.                                                                 pCodecCtx->pix_fmt,  
    149.                                                                  pCodecCtx->width, pCodecCtx->height,  
    150.                                                                  PIX_FMT_YUV420P,  
    151.                                                                  sws_flags, NULL, NULL, NULL);  
    152.                             if (img_convert_ctx == NULL) {  
    153.                                  fprintf(stderr, "Cannot initialize the conversion context
    ");  
    154.                                  exit(1);  
    155.                                  }  
    156.                             sws_scale(img_convert_ctx, pFrame->data, pFrame->linesize,  
    157.                                              0, pCodecCtx->height, pict->data, pict->linesize);  
    158.                           }  
    159.   //                    img_convert(&pict, PIX_FMT_YUV420P,  
    160.   //                                (AVPicture *)pFrame, pCodecCtx->pix_fmt,  
    161.   //                                pCodecCtx->width, pCodecCtx->height);  
    162.                         SDL_UnlockYUVOverlay(bmp);  
    163.                         rect.x = 0;  
    164.                         rect.y = 0;  
    165.                         rect.w = pCodecCtx->width;  
    166.                         rect.h = pCodecCtx->height;  
    167.                         SDL_DisplayYUVOverlay(bmp, &rect);  
    168.                       }  
    169.             }   
    170.                     // Free the packet that was allocated by av_read_frame  
    171.                     av_free_packet(&packet);  
    172.                     SDL_PollEvent(&event);  
    173.                     switch(event.type) {  
    174.                     case SDL_QUIT:  
    175.                       SDL_Quit();  
    176.                       exit(0);  
    177.                       break;  
    178.                       default:  
    179.                       break;  
    180.                     }   
    181.        }  
    182.        // Free the YUV frame  
    183.        av_free(pFrame);   
    184.    
    185.        // Close the codec  
    186.        avcodec_close(pCodecCtx);   
    187.    
    188.        // Close the video file  
    189.        av_close_input_file(pFormatCtx);  
    190.        return a.exec();  
    191.   
    就可以看到图像了,哈哈。
  • 相关阅读:
    Java多线程(二)关于多线程的CPU密集型和IO密集型这件事
    Java 过一下基础
    日历打印用java实现
    DAY8-打卡第八天-2018-1-18
    web-day1-初识标识符
    DAY7-图形界面第一弹-2018-1-17
    四种排序方法用java实现
    DAY6-小变化(java提示框)-2018-1-16
    DAY5-小别-2018-1-15
    DAY4-打卡第四天-2018-1-12
  • 原文地址:https://www.cnblogs.com/snake-hand/p/3167848.html
Copyright © 2020-2023  润新知