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

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

最简单的基于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下载

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐