基于QT+ffmpeg+SDL2的流媒体播放器

最下方有我借鉴了雷神以及一位大哥的文章后自己写的简易播放器。免费下载。仅供大家参考。

下面的文章是雷神的文章:

最简单的基于FFMPEG+SDL的视频播放器 ver2 (采用SDL2.0)_雷霄骅的博客-CSDN博客_ffmpeg sdl之前做过一个FFMPEG+SDL的简单播放器:《100行代码实现最简单的基于FFMPEG+SDL的视频播放器》。最近有不少人反映SDL已经升级到2.0版本了,甚至官网的Wiki上都只有SDL2.0的文档了,因此下载了SDL 2.0 并且进行了简单的研究。随后对此前的播放器进行了修改,将SDL1.2换成了SDL2.0。注:《100行代码实现最简单的基于FFMPEG+SDL的视频播放器》文章中提到的很多知识这里不再重复。本文重点记录SDL1.2与SDL2.0的不同。https://blog.csdn.net/leixiaohua1020/article/details/38868499以及我所借鉴的另一位大哥的文章:

QT、FFmpeg、SDL2视频播放器(一)_倾我一生来读的博客-CSDN博客_qt sdl2之前使用ffmpeg和sdl2制作过一个简单的视频播放器,视频的播放暂停完全是sdl event控制,现在希望将sdl嵌入到QT 窗口中,通过一系列qt按钮实现播放、暂停的控制。1 核心思想1 QT多线程因为视频解码过程消耗资源较多,必须单独开启一个线程来负责视频解码,主线程负责渲染以及控制,否则视频播放的过程中UI会卡住,无法响应用户事件。QT实现多线程有两种方法:第一种是创建一个线程,类继承QThread,并且重写run方法,主线程中创建线程对象,使用start()方法启动线程,该部分网络上资料https://blog.csdn.net/qq_38694388/article/details/120684650?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522165191343016782391899854%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=165191343016782391899854&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-4-120684650-null-null.nonecase&utm_term=%E6%92%AD%E6%94%BE%E5%99%A8&spm=1018.2226.3001.4450Player.h

class Player:public QObject
{
    Q_OBJECT
public:
    Player(QObject *parent = nullptr);
public:
    bool isPlay;
    bool isPause;
    float seekPos;
    bool doSeek;

signals:
    void sigGetFrame(AVFrame *pFrame);
    void sigGetVideoInfo(int mWidth,int mHeight);
    void sigGetCurrentPts(long totalTime, long currentTime);

public slots:
    void slotDoWork(const QString &add);
};

Player.cpp

#include "Player.h"
#include"CCycleBuffer.h"
static  Uint8  *audio_chunk;
static  Uint32  audio_len;
static  Uint8  *audio_pos;
CCycleBuffer* pSoundBuf;
#define MAX_AUDIO_FRAME_SIZE 192000 // 1 second of 48khz 32bit audio
void mSleep(int msec)
{
    QTime n=QTime::currentTime();
    QTime now;
    do
    {
        now=QTime::currentTime();
    }while (n.msecsTo(now)<=msec);
}

Player::Player(QObject *parent):QObject (parent)
{

}

void Player::slotDoWork(const QString &add)
{
    AVFormatContext *avFormatContext = nullptr;
    AVPacket *packet = (AVPacket *)malloc(sizeof(AVPacket));
    AVFrame	*pFrame = nullptr,*audioFrame=nullptr;
    //SDL_AudioSpec wanted_spec;
    //pSoundBuf = new CCycleBuffer(192000 * 10);
    int audioStream= -1;
    int videoStream = -1;
    int err = -1;
    QByteArray ba=nullptr;
    ba=add.toLatin1();
    char * fileName = ba.data();
    isPlay = true;
    isPause = false;
    doSeek = false;
    int64_t in_channel_layout;
    struct SwrContext *au_convert_ctx;
    av_register_all();
    avformat_network_init();
    avFormatContext = avformat_alloc_context();
    if (!avFormatContext) {
        av_log(nullptr, AV_LOG_FATAL, "Could not allocate context.\n");
    }
    AVDictionary *dic=NULL;
    int ret=av_dict_set(&dic,"bufsize","655360",0);
    if(avformat_open_input(&avFormatContext, fileName, nullptr, &dic) != 0){
        qDebug() << "Couldn't open file";
    }
    // Retrieve stream information
    if(avformat_find_stream_info(avFormatContext, nullptr)<0){
        qDebug() << "Couldn't find stream information";
        return;
    }
    av_dump_format(avFormatContext, 0, fileName, false);
    for(unsigned int i=0; i < avFormatContext->nb_streams; i++){
        if(avFormatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO){
            audioStream = static_cast<int>(i);
        }
        else if(avFormatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO){
            videoStream = static_cast<int>(i);
        }
    }

    if(audioStream == -1 && videoStream == -1){
        qDebug() << "Didn't find a audio stream";
        return;
    }

    pFrame = av_frame_alloc();
    //视频
    AVCodecContext *pVideoCodecContext = nullptr,*pAudioCodecContext=nullptr;
    AVCodec			*pCodecVideo,*pCodecAudio;
    AVCodecParameters *pVideoChannelCodecPara = nullptr,*pAudioChannelCodecPara = nullptr;
//    pAudioCodecContext=avFormatContext->streams[audioStream]->codec;
//    pCodecAudio=avcodec_find_decoder(pAudioCodecContext->codec_id);
//    if (avcodec_open2(pAudioCodecContext, pCodecAudio, NULL) < 0)
//        {
//            printf("Could not open audio codec.\n");
//        }
//    audioFrame=av_frame_alloc();
    if(videoStream != -1)
    {
        //视频
        pVideoChannelCodecPara = avFormatContext->streams[videoStream]->codecpar;
        pVideoCodecContext =  avcodec_alloc_context3(nullptr);
        if (!pVideoCodecContext){
            qDebug() <<  "avcodec_alloc_context3";
            return;
        }

        err = avcodec_parameters_to_context(pVideoCodecContext, pVideoChannelCodecPara);
        if (err < 0){
            qDebug() << "avcodec_parameters_to_context";
            return;
        }

        pCodecVideo = avcodec_find_decoder(pVideoChannelCodecPara->codec_id);
        if(pCodecVideo == nullptr){
            qDebug() <<  "avcodec_find_decoder";
            return;
        }

        qDebug() << "编解码器名:" << pCodecVideo->long_name;

        err = avcodec_open2(pVideoCodecContext, pCodecVideo, nullptr);
        if(err){
            qDebug() << "avcodec_open2";
            return;
        }

        emit sigGetVideoInfo(pVideoCodecContext->width, pVideoCodecContext->height);
        qDebug() << "视频宽度:" << pVideoCodecContext->width << "高度:" << pVideoCodecContext->height;
    }
    av_init_packet(packet);

    for (;;) {
        //Play
        //SDL_PauseAudio(0);
        if (isPause)
        {
            mSleep(1000);
        }

        else if (doSeek)
        {
            int64_t stamp = 0;
            stamp = seekPos * avFormatContext->streams[videoStream]->duration;//当前它实际的位置
            int ret = av_seek_frame(avFormatContext, videoStream, stamp,
                AVSEEK_FLAG_BACKWARD | AVSEEK_FLAG_FRAME);//将视频移至到当前点击滑动条位置

            emit sigGetCurrentPts(avFormatContext->duration * av_q2d(pVideoCodecContext->time_base),
                                  stamp * av_q2d(pVideoCodecContext->time_base));
            stamp * av_q2d(pVideoCodecContext->time_base);
            qDebug() << seekPos;
            doSeek = false;
            mSleep(50);
        }
        else
        {
            if(av_read_frame(avFormatContext, packet) < 0){
                goto end;
            }
            if(packet->stream_index == videoStream)
            {
                err = avcodec_send_packet(pVideoCodecContext, packet);
                if(err != 0){
                    if(AVERROR(EAGAIN) == err)
                        continue;
                    qDebug() << "发送视频帧失败!"<<  err;
                }
                //解码
                while(avcodec_receive_frame(pVideoCodecContext, pFrame) == 0){
                    emit sigGetFrame(pFrame);
                    mSleep(15);
                    emit sigGetCurrentPts(avFormatContext->duration * av_q2d(pVideoCodecContext->time_base),
                                          pFrame->pts * av_q2d(pVideoCodecContext->time_base));
                    mSleep(20);
                }
            }

            else
            {
                 av_packet_unref(packet); // 注意清理,容易造成内存泄漏
                 continue;
            }
            if (!isPlay)
            {
                goto end;
            }
        }
    }
end:
    av_frame_free(&pFrame);
    avformat_close_input(&avFormatContext);
    avcodec_close(pVideoCodecContext);
    avformat_close_input(&avFormatContext);
    qDebug() << "end of play";
}

 这是我自己写的播放器的运行图片

项目下载地址我放在我自己资源里面,免费下载的,库文件可能需要大家下载一下。

免费下载,仅供参考,更深度学习请移步雷神博客。

ffmpeg+SDL2的简易流媒体播放器,仅供大家参考学习。缺少dll库,在我资源里面下载ffmpeg+SDL2较新发布那个有。-编解码文档类资源-CSDN下载

  • 0
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 8
    评论
### 回答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都是非常优秀的多媒体应用程序开发工具,它们可以帮助开发者轻松实现各种音视频处理需求。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

美丽的欣情

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

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

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

打赏作者

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

抵扣说明:

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

余额充值