(转载)带简单控制的播放器

https://blog.csdn.net/aqiasi007/article/details/100994012

#pragma once

#include <QWidget>
#include "ui_PlayerSDL.h"
#include <QLabel>
#include <QDebug>

class PlayerSDL : public QWidget
{
    Q_OBJECT

public:
    PlayerSDL(QWidget *parent = Q_NULLPTR);
    ~PlayerSDL();

private:
    Ui::PlayerSDL ui;

    QLabel *label;
    QRect rect;
    bool isplay;
private slots:
    void start_play();
    void pause_play();
    void stop_play();
};
#include "PlayerSDL.h"
#include <QPushButton>

extern "C"
{
#include "SDL.h"
#include "libavformat/avformat.h"
#include "libavcodec/avcodec.h"
#include "libswscale/swscale.h"
#include "libavutil/pixfmt.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")  //加入这行


PlayerSDL::PlayerSDL(QWidget *parent)
    : QWidget(parent)
{
    ui.setupUi(this);

    this->setFixedSize(653, 465);
    label = new QLabel(this);
    label->resize(601, 381);
    label->move(30, 20);
    rect = label->geometry();//记录widget位置,恢复时使用
    isplay = false;
    connect(ui.start_Button, SIGNAL(clicked()), this, SLOT(start_play()));
    connect(ui.pause_Button, SIGNAL(clicked()), this, SLOT(pause_play()));
    connect(ui.stop_Button, SIGNAL(clicked()), this, SLOT(stop_play()));
}

PlayerSDL::~PlayerSDL()
{
}

void PlayerSDL::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[] = "./1.mp4";
    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(AV_PIX_FMT_YUVJ420P, pCodecCtx->width, pCodecCtx->height));
    avpicture_fill((AVPicture *)pFrameYUV, outbuffer, AV_PIX_FMT_YUVJ420P, pCodecCtx->width, pCodecCtx->height);

    img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height
        , AV_PIX_FMT_YUVJ420P, 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 PlayerSDL::pause_play()
{
    if (ui.pause_Button->text() == "暂停")
    {
        thread_pause = 1;
        ui.pause_Button->setText("继续");
    }
    else
    {
        thread_pause = 0;
        ui.pause_Button->setText("暂停");
    }
    
}

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

 

posted @ 2021-12-03 15:31  泽良_小涛  阅读(33)  评论(0编辑  收藏  举报