(转载)带简单控制的播放器
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; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!