Qt +FFmpeg+SDL视频播放器

调用ffmpeg库对本地视频文件进行视频流解码,解码后的数据格式为yuv420p,调用sdl库,并传入Qt显示控件句柄给sdl进行渲染显示,代码如下:

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QLabel>
#include <QDebug>

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();

private:
    Ui::Widget *ui;

    QLabel *label;

    QRect rect;

    bool isplay;

private slots:
    void start_play();

    void pause_play();

    void stop_play();


};

#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"

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

#define SFM_REFRESH_EVENT  (SDL_USEREVENT + 1)

#define SFM_BREAK_EVENT  (SDL_USEREVENT + 2)

int thread_exit=0;
int thread_pause=0;

int wait_thread(void *)
{
    thread_exit=0;
    thread_pause=0;

    while (thread_exit==0)
    {
        if(!thread_pause)
        {
            SDL_Event event;
            event.type = SFM_REFRESH_EVENT;
            SDL_PushEvent(&event);
        }

        SDL_Delay(40);

    }

    SDL_Event event;
    event.type = SFM_BREAK_EVENT;
    SDL_PushEvent(&event);
    thread_exit=0;
    thread_pause=0;
    return 0;
}

#pragma execution_character_set("utf-8")  //加入这行
Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
    this->setFixedSize(661,465);
    label = new QLabel(this);
    label->resize(601,381);
    label->move(30,20);
    rect = label->geometry();//记录widget位置,恢复时使用
    isplay = false;
    connect(ui->start_Button,&QPushButton::clicked,this,&Widget::start_play);
    connect(ui->pause_Button,&QPushButton::clicked,this,&Widget::pause_play);
    connect(ui->stop_Button,&QPushButton::clicked,this,&Widget::stop_play);
}

Widget::~Widget()
{
    delete ui;
}

void Widget::start_play()
{
    //在播放过程中判断是否重复点击播放按钮
    if(!isplay)
    {
        isplay = true;
    }
    else
    {
        return;
    }

    AVFormatContext *inputctx;
    int i,videoindex;
    AVCodecContext *pCodecCtx;
    AVCodec *codec;
    AVFrame *pFrame,*pFrameYUV;
    uint8_t *outbuffer;
    AVPacket *packet;
    int ret,got_picture;

    int texture_w,texture_h;
    SDL_Window *screen;
    SDL_Renderer *render;
    SDL_Texture *texture;
    SDL_Thread *video_thread;
    SDL_Event event;
    SDL_Rect prect;

    struct SwsContext *img_convert_ctx;

    char filepath[] = "F:/1.wmv";
    av_register_all();
    avformat_network_init();
    inputctx = avformat_alloc_context();

    if(avformat_open_input(&inputctx,filepath,NULL,NULL)!=0)
    {
        qDebug()<<"打开视频流失败";
        return;
    }

    if(avformat_find_stream_info(inputctx,NULL)<0)
    {
        qDebug()<<"获取文件信息失败";
        return;
    }

    videoindex = -1;
    for(i = 0;i < inputctx->nb_streams;i++)
    {
        if(inputctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
        {
            videoindex = i;
            break;
        }

    }

    if(videoindex == -1)
    {
       qDebug()<<"没有发现视频流";
       return;
    }

    pCodecCtx = inputctx->streams[videoindex]->codec;
    codec  = avcodec_find_decoder(pCodecCtx->codec_id);
    if(NULL == codec)
    {
        qDebug()<<"没有查到解码器";
        return;
    }

    if(avcodec_open2(pCodecCtx,codec,NULL)<0)
    {
        qDebug()<<"打开解码器失败";
        return;
    }

    pFrame = av_frame_alloc();
    pFrameYUV = av_frame_alloc();


    outbuffer = (uint8_t *)av_malloc(avpicture_get_size(PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height));
    avpicture_fill((AVPicture *)pFrameYUV,outbuffer,PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height);

    img_convert_ctx = sws_getContext(pCodecCtx->width,pCodecCtx->height,pCodecCtx->pix_fmt,pCodecCtx->width,pCodecCtx->height
                                     ,PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);



    if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER))
    {
        qDebug()<<"初始化sdl失败";
        return;
    }

    texture_w = pCodecCtx->width;
    texture_h = pCodecCtx->height;

    screen = SDL_CreateWindowFrom((void *)label->winId());
    if(!screen)
    {
        qDebug()<<"创建窗口失败";
        return;
    }

    render = SDL_CreateRenderer(screen,-1,0);
    texture = SDL_CreateTexture(render,SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING,pCodecCtx->width,pCodecCtx->height);

    prect.x = 0;
    prect.y = 0;
    prect.w = pCodecCtx->width;
    prect.h = pCodecCtx->height;

    packet=(AVPacket *)av_malloc(sizeof(AVPacket));
    video_thread = SDL_CreateThread(wait_thread,NULL,NULL);

    while(1)
    {
        SDL_WaitEvent(&event);
        if(event.type==SFM_REFRESH_EVENT)
        {
            if(av_read_frame(inputctx, packet)>=0)
            {
                if(packet->stream_index==videoindex)
                {
                    ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet);
                    if(ret < 0)
                    {
                        qDebug()<<"解码失败";
                        return ;
                    }

                    if(got_picture)
                    {
                        sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameYUV->data, pFrameYUV->linesize);

                        SDL_UpdateTexture(texture, NULL, pFrameYUV->data[0], pFrameYUV->linesize[0] );
                        SDL_RenderClear(render);

                        SDL_RenderCopy(render, texture, NULL, NULL);
                        SDL_RenderPresent(render);

                    }
                }
                av_free_packet(packet);
            }
            else
            {
                thread_exit=1;
            }

        }
        else if(event.type==SDL_QUIT)
        {
            thread_exit=1;

        }
        else if(event.type==SFM_BREAK_EVENT)
        {
            break;
        }
    }

    SDL_DestroyWindow(screen);
    SDL_Quit();
    delete label;

    isplay = false;
    label = new QLabel(this);
    label->setGeometry(rect);
    label->show();

    av_frame_free(&pFrameYUV);
    av_frame_free(&pFrame);
    avcodec_close(pCodecCtx);
    avformat_close_input(&inputctx);

}

void Widget::pause_play()
{
    if(ui->pause_Button->text() == "暂停")
    {
        thread_pause= 1;
        ui->pause_Button->setText("继续");
    }
    else
    {
        thread_pause= 0;
        ui->pause_Button->setText("暂停");
    }

}

void Widget::stop_play()
{
    thread_exit=1;
}

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Qt是一个跨平台的C++图形用户界面应用程序开发框架,可以用于开发微软Windows、Linux、Mac OS X以及手机、平板电脑等设备上的应用程序,具有开发效率高、代码简单明了、面向对象、可扩展性好等优点。 FFmpeg是一个开源的跨平台视频和频处理程序库,可以将视频、频等媒体文件进行编码、解码、转换等操作,支持多种格式的媒体文件,是许多流媒体播放器和视频编辑软件的核心。 SDL(Simple DirectMedia Layer)是一个跨平台的多媒体库,可以实现视频、频、键鼠输入等基本功能,是许多游戏、多媒体应用程序的核心。 QtFFmpegSDL这三个库可以用于开发多媒体应用程序,其中Qt可以提供图形用户界面的支持,FFmpeg可以处理媒体文件的编码、解码、转换等操作,SDL可以提供多媒体的播放和输入等功能,三者协同使用可以很好地实现多媒体应用程序的开发。 例如,可以利用Qt的GUI设计界面,使用FFmpeg处理视频文件的编码、解码等操作,再使用SDL实现视频和频的播放,从而开发一个具有图形用户界面的多媒体播放器,或者开发一个视频编辑软件,也可以开发一些与多媒体相关的游戏等等。 ### 回答2: Qt是一种跨平台的开发工具,便于开发高质量的GUI应用程序。FFmpeg是一个开源的跨平台视频处理工具库,可以进行视频编解码、剪辑、转码等操作。而SDL是一种跨平台的多媒体应用程序接口,在游戏开发中使用广泛。 在视频处理方面,Qt可以针对FFmpeg进行封装和使用,以实现生成、合并、转换视频文件等操作。同时,Qt还提供了许多图形界面组件,可以方便地实现视频的界面化处理。而使用SDL,则可在游戏中实现频播放和视频显示等功能,提高游戏体验。 当然,QtFFmpegSDL之间并不是互相独立的关系。它们可以结合使用,比如可以使用FFmpeg的库在Qt程序中解析视频文件,使用SDL实现视频播放等功能。同时,也可以利用Qt的图形界面组件快速地实现视频编辑软件,或者通过Qt的网络模块和TCP/IP协议结合FFmpeg实现实时视频流传输等操作。 总之,QtFFmpegSDL都是非常优秀的多媒体应用程序开发工具,它们可以帮助开发者轻松实现各种视频处理需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值