1.下载sdl2,ffmpeg dev
2.qt的配置
win32: LIBS += -L$$PWD/libffmpeg/lib/ -lavcodec -lavdevice -lavfilter -lavformat -lavutil -lpostproc -lswscale
win32: LIBS += -L$$PWD/libSDL/lib/x86/ -lSDL2 -lSDL2main
INCLUDEPATH += $$PWD/libffmpeg/include
DEPENDPATH += $$PWD/libffmpeg/include
INCLUDEPATH += $$PWD/libSDL/include
DEPENDPATH += $$PWD/libSDL/include
3.类接口源码(参考了雷博士的源码)
#ifndef VIDEOPLAYER_H
#define VIDEOPLAYER_H
#ifdef _WIN32
//Windows
extern "C"
{
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
#include "SDL.h"
};
#else
//Linux...
#ifdef __cplusplus
extern "C"
{
#endif
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include <SDL2/SDL.h>
#ifdef __cplusplus
};
#endif
#endif
class VideoPlayer
{
public:
VideoPlayer(void* hwnd);
~VideoPlayer();
//init ffmpeg SDL
static int StaticInit();
//crate videoplayer
static VideoPlayer * CreateNew(void *hwnd);
//
int OpenVideo(const char * videopath);
//
int Play();
//
int Stop();
//
int Pause();
//
int Continue();
void test();
public:
static bool IsStaticInit;
AVFormatContext *pFormatCtx;
AVCodecContext *pCodecCtx;
int videoindex;
//--------------SDL---------
SDL_Texture* sdlTexture;
SDL_Renderer* sdlRenderer;
bool fPause;
bool fEndThread;
private:
uint8_t *out_buffer;
//AVPacket *packet;
//------------SDL----------------
int screen_w, screen_h;
SDL_Window *screen;
SDL_Rect sdlRect;
SDL_Thread *video_tid;
SDL_Event event;
char fVideoPath[512];
void * fHwnd;
};
#endif // VIDEOPLAYER_H
#include "videoplayer.h"
#include <QDebug>
bool VideoPlayer::IsStaticInit = false;
int video_refresh_thread(void *opaque)
{
VideoPlayer *vplayer = (VideoPlayer*)opaque;
if(vplayer == NULL){
return 0;
}
AVPacket * packet = (AVPacket *)av_malloc(sizeof(AVPacket));
AVFrame *pFrame, *pFrameYUV;
int ret, got_picture;
struct SwsContext *img_convert_ctx;
uint8_t *out_buffer;
pFrame = av_frame_alloc();
pFrameYUV = av_frame_alloc();
out_buffer = (uint8_t *)av_malloc(avpicture_get_size(AV_PIX_FMT_YUV420P, vplayer->pCodecCtx->width, vplayer->pCodecCtx->height));
avpicture_fill((AVPicture *)pFrameYUV, out_buffer, AV_PIX_FMT_YUV420P, vplayer->pCodecCtx->width, vplayer->pCodecCtx->height);
img_convert_ctx = sws_getContext(vplayer->pCodecCtx->width, vplayer->pCodecCtx->height, vplayer->pCodecCtx->pix_fmt, vplayer->pCodecCtx->width,vplayer-> pCodecCtx->height, AV_PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
while(!vplayer->fEndThread){
if(!vplayer->fPause){
if (av_read_frame(vplayer->pFormatCtx, packet) >= 0) {
if (packet->stream_index == vplayer->videoindex) {
ret = avcodec_decode_video2(vplayer->pCodecCtx, pFrame, &got_picture, packet);
if (ret < 0) {
printf("Decode Error.\n");
break;
}
if (got_picture) {
sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, vplayer->pCodecCtx->height, pFrameYUV->data, pFrameYUV->linesize);
//SDL---------------------------
SDL_UpdateTexture(vplayer->sdlTexture, NULL, pFrameYUV->data[0], pFrameYUV->linesize[0]);
SDL_RenderClear(vplayer->sdlRenderer);
//SDL_RenderCopy( sdlRenderer, sdlTexture, &sdlRect, &sdlRect );
SDL_RenderCopy(vplayer->sdlRenderer, vplayer->sdlTexture, NULL, NULL);
SDL_RenderPresent(vplayer->sdlRenderer);
//SDL End-----------------------
}
}
av_free_packet(packet);
}else{
break;
}
}
SDL_Delay(40);
}
if(vplayer->sdlRenderer)
SDL_RenderClear(vplayer->sdlRenderer);
sws_freeContext(img_convert_ctx);
av_frame_free(&pFrameYUV);
av_frame_free(&pFrame);
vplayer->fEndThread = false;
vplayer->fPause = false;
return 0;
}
VideoPlayer::VideoPlayer(void *hwnd):
fHwnd(hwnd),pFormatCtx(NULL),pCodecCtx(NULL),sdlRenderer(NULL),
sdlTexture(NULL),video_tid(NULL),fPause(false),fEndThread(false)
{
//03.申请context内存
pFormatCtx = avformat_alloc_context();
}
VideoPlayer::~VideoPlayer()
{
SDL_Quit();
Stop();
}
int VideoPlayer::StaticInit()
{
if(IsStaticInit){
return 0;
}
IsStaticInit = true;
//00.初始化SDL 视频、音频、定时器
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) {
printf("Could not initialize SDL - %s\n", SDL_GetError());
return -1;
}
//01.ffpeg初始化
av_register_all();
//02.网络初始化
return avformat_network_init();
}
int VideoPlayer::OpenVideo(const char *videopath)
{
strcpy(fVideoPath, videopath);
return 0;
}
int VideoPlayer::Play()
{
//04.打开视频
if (avformat_open_input(&pFormatCtx, fVideoPath, NULL, NULL) != 0) {
printf("Couldn't open input stream.\n");
return -1;
}
//05.获取视频信息
if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {
printf("Couldn't find stream information.\n");
return -1;
}
//06.获取视频流的序号
videoindex = -1;
for (unsigned int i = 0; i < pFormatCtx->nb_streams; i++)
if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
videoindex = i;
break;
}
//07.是否存在视频流
if (videoindex == -1) {
printf("Didn't find a video stream.\n");
return -1;
}
//08.视频编码方式
pCodecCtx = pFormatCtx->streams[videoindex]->codec;
AVCodec *pCodec;
pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
if (pCodec == NULL) {
printf("Codec not found.\n");
return -1;
}
if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) {
printf("Could not open codec.\n");
return -1;
}
//09.创建渲染器和纹理
sdlRenderer = SDL_CreateRenderer(screen, -1, 0);
sdlTexture = SDL_CreateTexture(sdlRenderer, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING, pCodecCtx->width, pCodecCtx->height);
video_tid = SDL_CreateThread(video_refresh_thread, NULL, (void*)this);
return 0;
}
int VideoPlayer::Stop()
{
if(video_tid){
fEndThread = true;
SDL_WaitThread(video_tid, NULL);
video_tid = NULL;
fEndThread = false;
}
if(sdlTexture){
SDL_DestroyTexture(sdlTexture);
sdlTexture = NULL;
}
if(sdlRenderer){
SDL_RenderClear(sdlRenderer);
SDL_DestroyRenderer(sdlRenderer);
sdlRenderer = NULL;
}
if(pCodecCtx){
avcodec_close(pCodecCtx);
pCodecCtx = NULL;
}
if(pFormatCtx){
avformat_close_input(&pFormatCtx);
pFormatCtx = NULL;
}
return 0;
}
int VideoPlayer::Pause()
{
fPause = true;
return 0;
}
int VideoPlayer::Continue()
{
fPause = false;
return 0;
}
void VideoPlayer::test()
{
SDL_Surface *sur = SDL_GetWindowSurface(screen);
;
SDL_BlitSurface( SDL_LoadBMP("d:/123.bmp") , NULL ,sur ,NULL);
SDL_UpdateWindowSurface(screen);//更新显示copy the window surface to the screen
}
VideoPlayer *VideoPlayer::CreateNew(void * hwnd)
{
SDL_Window *screen = SDL_CreateWindowFrom(hwnd);
if(screen){
VideoPlayer *vplayer = new VideoPlayer(hwnd);
vplayer->screen = screen;
return vplayer;
}else{
qDebug()<<SDL_GetError();
return NULL;
}
}