Ubuntu 下QT 创建FFMpeg SDL 开发环境遇到的问题 以及SDL_Init初始化失败返回-1

周六在家没什么事,就来公司加班。

最近正好在做音视频的项目,避免不了要和FFMpeg打些交道。之前没怎么接用过FFMpeg,之前就是简单的用FFmpeg拉了RTSP流,截个图 缩放什么的 更深入的功能没有做过。想借助这个时间好好学习下FFMpeg。本来想在windows下做的,需要下载visual studio .网上看了下 VS太大了 真的太大了 动不动10几个G 公司的网速下载 看了下 不到500K 放弃了 。

正好项目开发是在ubuntu下的 有VMware的ubuntu环境。 我自己都不知道什么时候装了QT。

QT本来就是跨平台的,网上搜了下 在Ubuntu下可以用QT+FFMpeg+SDL来做开发。

之前已经下了FFMpeg的源码了 ,只不过编译的是海思平台ARM版本的 需要重新编译成ubuntu版本。

编译脚本如下,默认配置

./configure --prefix=./install_ubunt \
    --disable-x86asm

接着 make make install  没啥问题 

接下来QT新建一个NON-QT的 plain C或者C++项目都可以 ,修改pro配置文件

如下图

 写了个测试程序 编译出错 更准确的应该是连接 如下图 莫名其妙的一大堆

 没咋搞过 百度,大概知道了原因 

pro文件 添加

LIBS += -lz  没问题 继续编译

又来了连接错误  如下图 


这次是找不到av开头的函数,继续百度 百度说要把libavformat.a放在最前面

果然 放在前面就没这个错误了   FFMpeg的代码顺利执行 没问题 。

接下来要把SDL也集成进来。官网直接下源码http://www.libsdl.org/download-2.0.php

下下来 配置下 make  make install 

有个比较吭的地方是 sdl的configure 不支持相对路径只能用绝对路径 没办法 

看这么一长串的目录都闹心,对了 说下 我习惯建一个build.sh 把这个配置写进去,直接执行对应的脚本,这样不同平台起一个不用的名字,比如arm平台需要修改编译链,增加删除裁剪一些功能什么的这,这样比较方便。

./configure --prefix=/home/jason/HS/Hi3531DV200_SDK_V2.0.0.3/mpp/sample/SDL2-2.0.16/install_ubuntu

OK  继续,改pro文件 把头文件的路径,lib都加进工程里面,网上copy一个简单的测试环境

编译 又是报错 SDL_SetVideoMode API什么的找不到,继续百度,百度说是这个API过期了,得用新的API好继续改 改好了 ok编译   又是 一连串红色错误 :

继续百度 

说是要LIBS += -ldl  ok  修改pro文件 编译 一切ok  运行  又出错了

继续百度 发现是 虚拟机下AUDIO设备不正常 所以失败了,SDL_Init那里 去掉 AUDIO 的flag  终于运行正常了。  看效果图 

完整的PRO配置如下:

TEMPLATE = app
CONFIG += console c++11
CONFIG -= app_bundle
CONFIG -= qt

SOURCES += main.cpp

INCLUDEPATH +=  /home/jason/HS/Hi3531DV200_SDK_V2.0.0.3/mpp/sample/FFmpeg-n4.3.2/install_ubunt/include
INCLUDEPATH +=  /home/jason/HS/Hi3531DV200_SDK_V2.0.0.3/mpp/sample/SDL2-2.0.16/install_ubuntu/include

LIBS +=     /home/jason/HS/Hi3531DV200_SDK_V2.0.0.3/mpp/sample/FFmpeg-n4.3.2/install_ubunt/lib/libavformat.a
LIBS +=     /home/jason/HS/Hi3531DV200_SDK_V2.0.0.3/mpp/sample/FFmpeg-n4.3.2/install_ubunt/lib/libavcodec.a

LIBS +=     /home/jason/HS/Hi3531DV200_SDK_V2.0.0.3/mpp/sample/FFmpeg-n4.3.2/install_ubunt/lib/libavdevice.a
LIBS +=     /home/jason/HS/Hi3531DV200_SDK_V2.0.0.3/mpp/sample/FFmpeg-n4.3.2/install_ubunt/lib/libavfilter.a

LIBS +=     /home/jason/HS/Hi3531DV200_SDK_V2.0.0.3/mpp/sample/FFmpeg-n4.3.2/install_ubunt/lib/libavutil.a
LIBS +=     /home/jason/HS/Hi3531DV200_SDK_V2.0.0.3/mpp/sample/FFmpeg-n4.3.2/install_ubunt/lib/libswresample.a
LIBS +=     /home/jason/HS/Hi3531DV200_SDK_V2.0.0.3/mpp/sample/FFmpeg-n4.3.2/install_ubunt/lib/libswscale.a
LIBS +=     /home/jason/HS/Hi3531DV200_SDK_V2.0.0.3/mpp/sample/SDL2-2.0.16/install_ubuntu/lib/libSDL2.a
LIBS +=     /home/jason/HS/Hi3531DV200_SDK_V2.0.0.3/mpp/sample/SDL2-2.0.16/install_ubuntu/lib/libSDL2main.a
LIBS +=     /home/jason/HS/Hi3531DV200_SDK_V2.0.0.3/mpp/sample/SDL2-2.0.16/install_ubuntu/lib/libSDL2_test.a

LIBS += -lpthread
LIBS += -lxcb -lm

LIBS += -lz
LIBS += -ldl

 main.cpp如下:

#include <iostream>

using namespace std;


#include<stdlib.h>

#include <sys/stat.h>
#include <unistd.h>

#define RTSPSOURCE1  "rtsp://uer:gd123456@192.168.2.121:554/Streaming/Channels/101"	//720P

extern "C"
{
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
#include "libavdevice/avdevice.h"
#include "SDL2/SDL.h"
}


void SaveFrame(AVFrame *frame,int width, int height ,int iFrame)
{
    FILE *fp;
    char filename[100]={0};
    int y = 0;

    sprintf(filename,"frame_%d.ppm",iFrame);
    fp = fopen(filename,"wb");
    if(fp == NULL)
    {
        cout<<"fp is null "<<endl;
        return;
    }

    fprintf(fp,"P6\n%d %d\n255\n",width,height);

    for(y=0;y<height;y++)
    {
        fwrite(frame->data[0]+y*frame->linesize[0],1,width*3,fp);
    }
    fclose(fp);
    cout<<"fp is end "<<endl;
}

int main()
{
    AVFormatContext *pFormatCtx = NULL;
    AVDictionary *options = NULL;
    AVPacket *packet = NULL;
    AVCodecContext* avc_cxt = NULL;
    AVFrame* frame = NULL;
    AVFrame* frameRGB = NULL;
    AVCodec* codec    ;
    struct SwsContext *sws_ctx = NULL;
    int ret = 0,i = 0;
    char *input_file = RTSPSOURCE1;
    int videoindex = -1;
    uint8_t *buffer = NULL;
    int bytes = 0;
    int gotFrame = 0;
    int w_width = 1280;
    int w_height = 720;
    Uint32 pixformat;

	SDL_Rect rect;
    SDL_Window *win = NULL;
    SDL_Renderer *renderer = NULL;
    SDL_Texture *texture = NULL;

    ret = SDL_Init(SDL_INIT_VIDEO);
    if (ret) {
		cout<<"SDL init error :"<<ret<<endl;
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Could not initialize SDL - %s\n", SDL_GetError());
        return ret;
    }


    av_dict_set(&options, "buffer_size", "1024000", 0); //Buffer size


    av_dict_set(&options, "rtsp_transport", "tcp", 0); //UDP or TCP

    av_dict_set(&options, "stimeout", "5000000", 0); //Timeout value :us
    av_dict_set(&options, "max_delay", "500000", 0); //Max delay time:us

    pFormatCtx = avformat_alloc_context(); //Init handle


    //Open file or stream URL
    ret = avformat_open_input(&pFormatCtx, input_file, NULL, &options);
    if(ret != 0)
    {
        cout<<"open file failed:"<<input_file<<endl;
    }


    //Get video info
    if (avformat_find_stream_info(pFormatCtx, NULL)<0)
    {
        printf("Couldn't find stream information.\n");

        goto EXIT;
    }

    //Check if has video info


    for (i = 0; i<pFormatCtx->nb_streams; i++)
    if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
    {
        videoindex = i;
        break;
    }
    if (videoindex == -1)
    {
        printf("Didn't find a video stream.\n");

        goto EXIT;
    }

    av_dump_format(pFormatCtx,0,input_file,0);

    avc_cxt = pFormatCtx->streams[videoindex]->codec;

    codec = avcodec_find_decoder(avc_cxt->codec_id);
    if(!codec){
        av_log(NULL,AV_LOG_ERROR,"No decoder ");
        goto EXIT;
    }
    ret = avcodec_open2(avc_cxt,codec,NULL);
    if(ret < 0){
        av_log(NULL,AV_LOG_ERROR,"Can not open decoder");
        goto EXIT;
    }

    frame = av_frame_alloc();

    frameRGB = av_frame_alloc();
    if(frameRGB == NULL)
    {
        goto EXIT;
    }

    packet = (AVPacket *)av_malloc(sizeof(AVPacket)); //Malloc packet

    bytes= avpicture_get_size(AV_PIX_FMT_RGB24,avc_cxt->width,avc_cxt->height);
    buffer = (uint8_t*)av_malloc(bytes*sizeof(uint8_t));
    avpicture_fill((AVPicture *)frameRGB,buffer,AV_PIX_FMT_RGB24,avc_cxt->width,avc_cxt->height);

    frameRGB->width = avc_cxt->width;
    frameRGB->height = avc_cxt->height;
    sws_ctx = sws_getContext(avc_cxt->width,avc_cxt->height,avc_cxt->pix_fmt,
                 frameRGB->width,frameRGB->height,AV_PIX_FMT_RGB24,SWS_BICUBIC,NULL,NULL,NULL);

    win = SDL_CreateWindow("Media Player",
                           SDL_WINDOWPOS_UNDEFINED,
                           SDL_WINDOWPOS_UNDEFINED,
                           w_width, w_height,
                           SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
    if (!win) {
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to create window by SDL");
        goto EXIT;
    }

    renderer = SDL_CreateRenderer(win, -1, 0);
    if (!renderer) {
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to create Renderer by SDL");
        goto EXIT;
    }

    pixformat = SDL_PIXELFORMAT_IYUV;//YUV\u683c\u5f0f

    texture = SDL_CreateTexture(renderer,
                                pixformat,
                                SDL_TEXTUREACCESS_STREAMING,
                                w_width,
                                w_height);



    while(1)
    {
        if (av_read_frame(pFormatCtx, packet) >= 0)
        {
                if (packet->stream_index == videoindex)
            {
                //cout<<"packet size is :"<<packet->size<<endl;
                avcodec_decode_video2(avc_cxt,frame,&gotFrame,packet);
                if(gotFrame)
                {

                    if(i++ % 25 == 0)
                    {
                        ret = sws_scale(sws_ctx, (uint8_t const * const *)frame->data,
                                frame->linesize, 0, frame->height,
                                frameRGB->data, frameRGB->linesize);
                        cout<<"ret :"<<ret<<endl;
                        SaveFrame(frameRGB,avc_cxt->width,avc_cxt->height,i);
                        if(i>200)
                        {
                            //goto EXIT;
                        }
                    }

                SDL_UpdateYUVTexture(texture, NULL,
                                     frame->data[0], frame->linesize[0],
                                     frame->data[1], frame->linesize[1],
                                     frame->data[2], frame->linesize[2]);
 
                // Set Size of Window
                rect.x = 0;
                rect.y = 0;
                rect.w = frameRGB->width;
                rect.h = frameRGB->height;
 

                SDL_RenderClear(renderer);
                SDL_RenderCopy(renderer, texture, NULL, &rect);
                SDL_RenderPresent(renderer);					

                }
                else
                {
                    cout<<"avcodec_decode_video2 failed size is:"<<packet->size<<endl;
                }
                av_frame_unref(frame);

            }
            av_packet_unref(packet);

	        SDL_Event event;
	        SDL_PollEvent(&event);
	        switch (event.type) {
	            case SDL_QUIT:
	                goto EXIT;
	            default:
	                break;
	        }			
        }

    }
	
	EXIT:

	av_free(buffer);

	av_free(packet);
	av_frame_free(&frameRGB);
	av_frame_free(&frame);
	avformat_close_input(&pFormatCtx);

	if (win) {
		SDL_DestroyWindow(win);
	}

	if (renderer) {
		SDL_DestroyRenderer(renderer);
	}

	if (texture) {
		SDL_DestroyTexture(texture);
	}

	SDL_Quit();


    printf("%s This is a test \n",__FUNCTION__);
    return 0;
}






 SaveFrame是之前测试保存图片用的  

前文提到SDL_Init里面有SDL_INIT_AUDIO 的时候回初始化失败 返回-1 

网上搜了下 说要装两个东东 如下:

 sudo apt-get install libasound2-dev libpulse-dev

 下载完之后,SDL make clean 重新 build make make install 即可解决 返回-1 的问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

QMCY_jason

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值