ffmpeg+sdl播放类
来源:互联网 发布:源码下载站网站源码 编辑:程序博客网 时间:2024/05/16 05:47
前段时间一直捣鼓ffmpeg,觉得还是VLC比较亲切,虽然我现在都不知道VLC怎么用了。
除了雷神的博客,主要参考的还是这个博客:http://blog.yundiantech.com/?log=index
自己在Qt下做了一个功能简单的播放类(播放,暂停,停止)。以后有时间再弄上快进,后退等。
/********************************************************************************* *Copyright(C),ForMySelf *FileName:GPlayer.h *Author:gongluck *Version:1.0 *Date: 2017-06-15 *Description:播放本地视频文件 *Others: *Function List: *History: 1.Date: 2017-06-15 Author: gongluck Modification: 很早之前做的了,现在整理一下 2.Date: 2017-06-16 Author: gongluck Modefication: 加上暂停等功能**********************************************************************************/#ifndef GPLAYER_H#define GPLAYER_H//Qt#include <QObject>#include <QImage>//stl#include <Queue>using namespace std;extern "C"{#include "libavcodec/avcodec.h"#include "libavformat/avformat.h"#include "libswscale/swscale.h"#include "libswresample/swresample.h"#include "SDL.h"#undef main}class GPlayer : public QObject{ Q_OBJECTpublic: explicit GPlayer(QObject *parent = 0); ~GPlayer(); bool SetFilename(const char* filename); bool PlayFile(const char* filename = NULL); bool Stop(); AVFormatContext* GetAVFormatCtx(){ return m_pFormatCtx; } AVCodecContext* GetVCodecCtx() { return m_pVCodecCtx; } AVCodecContext* GetACodecCtx() { return m_pACodecCtx; } queue<AVPacket>& GetVPacketQue(){ return m_VpacketQue; } queue<AVPacket>& GetAPacketQue(){ return m_ApacketQue; } int GetVIndex() { return m_vindex; } int GetAIndex() { return m_aindex; } int GetDstWidth() { return m_dstWidth; } int GetDstHeight() { return m_dstHeight; } void SetDstWidth(int width) { m_dstWidth = width; } void SetDstHeight(int height) { m_dstHeight = height; } SDL_AudioSpec GetAudioSpec() { return m_AudioSpec; } void SetPts(double pts) { m_pts = pts; } double GetPts() { return m_pts; } bool GetStopFlag() { return m_bStop; } void SetStopFlag(bool bStop) { m_bStop = bStop; } bool GetPauseFlag() { return m_bPause; } void SetPauseFlag(bool bPause) { if(bPause) SDL_PauseAudio(1); else SDL_PauseAudio(0); m_bPause = bPause; } bool GetPlayingFlag() { return m_bPlaying; } void SetPlayingFlag(bool bPause) { m_bPlaying = bPause; }signals: void sig_picture(QImage);public slots:protected: bool PreV(); bool PreA();private: bool m_bInit; char* m_filename; unsigned int m_filenameLength; AVFormatContext* m_pFormatCtx; AVCodecContext* m_pVCodecCtx; AVCodecContext* m_pACodecCtx; AVCodec* m_pVCodec; AVCodec* m_pACodec; SDL_AudioSpec m_AudioSpec; SDL_Thread* m_TReadPacket; SDL_Thread* m_TPlayVideo; queue<AVPacket> m_VpacketQue; queue<AVPacket> m_ApacketQue; int m_vindex; int m_aindex; int m_dstWidth; int m_dstHeight; double m_pts; bool m_bStop; bool m_bPause; bool m_bPlaying;};#endif // GPLAYER_H
/********************************************************************************* *Copyright(C),ForMySelf *FileName:GPlayer.cpp *Author:gongluck *Version:1.0 *Date: 2017-06-15 *Description:播放本地视频文件 *Others: *Function List: *History: 1.Date: 2017-06-15 Author: gongluck Modification: 很早之前做的了,现在整理一下 2.Date: 2017-06-16 Author: gongluck Modefication: 加上暂停等功能**********************************************************************************/#include "GPlayer.h"int SDLCALL ReadPacket(void *data){ AVPacket* packet = (AVPacket*)av_malloc(sizeof(AVPacket)); GPlayer* player = (GPlayer*)data; AVFormatContext* pFormatCtx = player->GetAVFormatCtx(); queue<AVPacket>& VpacketQue = player->GetVPacketQue(); queue<AVPacket>& ApacketQue = player->GetAPacketQue(); int vindex = player->GetVIndex(); int aindex = player->GetAIndex(); av_init_packet(packet); while(av_read_frame(pFormatCtx,packet) >= 0) { if(player->GetStopFlag()) break; while(player->GetPauseFlag()) { SDL_Delay(10); } if(packet->stream_index == vindex) { while(VpacketQue.size()>1023) { if(player->GetStopFlag()) break; SDL_Delay(10); } VpacketQue.push(*packet); } else if(packet->stream_index == aindex) { while(ApacketQue.size()>1023) { if(player->GetStopFlag()) break; SDL_Delay(10); } ApacketQue.push(*packet); } else { av_free_packet(packet); } } av_free(packet); return 0;}int SDLCALL PlayVideo(void *data){ AVFrame frame = {0}; AVFrame frameRGB = {0}; AVPacket packet = {0}; GPlayer* player = (GPlayer*)data; AVFormatContext* pFormatCtx = player->GetAVFormatCtx(); AVCodecContext* pVCodecCtx = player->GetVCodecCtx(); queue<AVPacket>& VpacketQue = player->GetVPacketQue(); int vindex = player->GetVIndex(); int got_picture = 0; struct SwsContext* img_convert_ctx = NULL; int size = 0; uint8_t* buf = NULL; img_convert_ctx = sws_getContext(pVCodecCtx->width,pVCodecCtx->height,pVCodecCtx->pix_fmt ,player->GetDstWidth(),player->GetDstHeight(),AV_PIX_FMT_RGB32,SWS_BICUBIC ,NULL,NULL,NULL); size = avpicture_get_size(AV_PIX_FMT_RGB32,player->GetDstWidth(),player->GetDstHeight()); buf = (uint8_t*)av_mallocz(sizeof(uint8_t) * size); avpicture_fill((AVPicture*)&frameRGB,buf,AV_PIX_FMT_RGB32,player->GetDstWidth(),player->GetDstHeight());//把buf和frameRGB绑定 while(true) { if(player->GetStopFlag()) break; else if(player->GetPauseFlag()) { SDL_Delay(10); continue; } if(VpacketQue.size() == 0) { SDL_Delay(10); continue; } packet = VpacketQue.front(); if(avcodec_decode_video2(pVCodecCtx,&frame,&got_picture,&packet)<0) { av_free_packet(&packet); VpacketQue.pop(); continue; } if(got_picture) { sws_scale(img_convert_ctx,frame.data,frame.linesize,0,pVCodecCtx->height,frameRGB.data,frameRGB.linesize); QImage img(buf,player->GetDstWidth(),player->GetDstHeight(),QImage::Format_RGB32);// while(frame.pkt_pts * av_q2d(pFormatCtx->streams[vindex]->time_base) > player->GetPts())// SDL_Delay(1); if(frame.pkt_pts * av_q2d(pFormatCtx->streams[vindex]->time_base) > player->GetPts()) SDL_Delay((frame.pkt_pts*av_q2d(pFormatCtx->streams[vindex]->time_base) - player->GetPts()) *1000); emit player->sig_picture(img); VpacketQue.pop(); } } return 0;}void SDLCALL audioCallback(void *userdata, Uint8 * stream, int len){ AVFrame frame = {0}; AVPacket packet = {0}; GPlayer* player = (GPlayer*)userdata; AVFormatContext* pFormatCtx = player->GetAVFormatCtx(); AVCodecContext* pACodecCtx = player->GetACodecCtx(); queue<AVPacket>& ApacketQue = player->GetAPacketQue(); int aindex = player->GetAIndex(); int got_picture = 0; SDL_AudioSpec audiospec = player->GetAudioSpec(); static struct SwrContext* swr_convert_ctx = swr_alloc_set_opts(NULL,av_get_default_channel_layout(audiospec.channels),AV_SAMPLE_FMT_S16,audiospec.freq ,av_get_default_channel_layout(pACodecCtx->channels),pACodecCtx->sample_fmt,pACodecCtx->sample_rate ,NULL,NULL); swr_init(swr_convert_ctx); int size = av_samples_get_buffer_size(NULL,audiospec.channels,audiospec.samples,AV_SAMPLE_FMT_S16,1); uint8_t* buf = (uint8_t*)av_mallocz(sizeof(uint8_t) * size); while(ApacketQue.size() == 0) { if(player->GetStopFlag()) break; SDL_Delay(10); } packet = ApacketQue.front(); if( avcodec_decode_audio4(pACodecCtx,&frame,&got_picture,&packet) < 0 ) { av_free_packet(&packet); ApacketQue.pop(); return ; } if(got_picture) { swr_convert(swr_convert_ctx,&buf,size,(const uint8_t**)frame.data,frame.nb_samples); SDL_memset(stream,0,len); SDL_MixAudio(stream,buf,len,SDL_MIX_MAXVOLUME); player->SetPts(frame.pkt_pts * av_q2d(pFormatCtx->streams[aindex]->time_base)); } av_free_packet(&packet); ApacketQue.pop(); if(player->GetPauseFlag()) SDL_PauseAudio(1); else SDL_PauseAudio(0);}GPlayer::GPlayer(QObject *parent) : QObject(parent) ,m_bInit(false) ,m_filename(NULL) ,m_filenameLength(0) ,m_pFormatCtx(NULL) ,m_vindex(-1) ,m_aindex(-1) ,m_pVCodecCtx(NULL) ,m_pVCodec(NULL) ,m_pACodecCtx(NULL) ,m_pACodec(NULL) ,m_AudioSpec{0} ,m_pts(0.0) ,m_bPause(false) ,m_bStop(false){ //初始化ffmpeg av_register_all(); //初始化SDL if(SDL_Init(SDL_INIT_AUDIO) != 0) { m_bInit = false; } else { m_bInit = true; }}GPlayer::~GPlayer(){ if(m_filename != NULL) { free(m_filename); m_filename = NULL; m_filenameLength = 0; }}bool GPlayer::SetFilename(const char* filename){ if(m_filename != NULL) { free(m_filename); m_filename = NULL; m_filenameLength = 0; } m_filenameLength = strlen(filename)+1; if(m_filenameLength<=0 || m_filenameLength>260) return false; m_filename = (char*)malloc(m_filenameLength); if(m_filename == NULL) return false; strncpy(m_filename,filename,m_filenameLength); return true;}bool GPlayer::PlayFile(const char* filename){ if(filename != NULL) { if(!SetFilename(filename)) return false; } if(m_pFormatCtx != NULL) goto ERROR; if(avformat_open_input(&m_pFormatCtx,m_filename,NULL,NULL)<0) goto ERROR; if(avformat_find_stream_info(m_pFormatCtx,NULL)<0) goto ERROR; if(!PreV() || !PreA()) goto ERROR; SetStopFlag(false); SetPauseFlag(false); SetPlayingFlag(true); m_TReadPacket = SDL_CreateThread(ReadPacket,"ReadPacket",this); m_TPlayVideo = SDL_CreateThread(PlayVideo,"PlayVideo",this); SDL_PauseAudio(0); return true;ERROR: if(m_pFormatCtx != NULL) avformat_close_input(&m_pFormatCtx); m_pVCodecCtx = m_pACodecCtx = NULL; m_pVCodec = m_pACodec = NULL; m_vindex = -1; m_aindex = -1; return false;}bool GPlayer::PreV(){ for(int i=0;i<m_pFormatCtx->nb_streams;++i) { if(m_pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) m_aindex = i; else if(m_pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) m_vindex = i; } if(m_vindex==-1 || m_aindex==-1) goto ERROR; m_pVCodecCtx = m_pFormatCtx->streams[m_vindex]->codec; m_pVCodec = avcodec_find_decoder(m_pVCodecCtx->codec_id); if(avcodec_open2(m_pVCodecCtx,m_pVCodec,NULL) <0) goto ERROR; m_pACodecCtx = m_pFormatCtx->streams[m_aindex]->codec; m_pACodec = avcodec_find_decoder(m_pACodecCtx->codec_id); if(avcodec_open2(m_pACodecCtx,m_pACodec,NULL) <0) goto ERROR; return true;ERROR: return false;}bool GPlayer::PreA(){ SDL_AudioSpec want = {0}; want.callback = audioCallback; want.channels = m_pACodecCtx->channels; want.format = AUDIO_S16SYS;//ffmpeg的格式与SDL的格式 不相同 want.freq = m_pACodecCtx->sample_rate; want.samples = m_pACodecCtx->frame_size;//!!! want.userdata = this; if(SDL_OpenAudio(&want,&m_AudioSpec) != 0) goto ERROR; return true;ERROR: return false;}bool GPlayer::Stop(){ m_bStop = true; m_bPlaying = false; SDL_CloseAudio(); if(m_pVCodecCtx != NULL) avcodec_close(m_pVCodecCtx); if(m_pACodecCtx != NULL) avcodec_close(m_pACodecCtx); if(m_pFormatCtx != NULL) avformat_close_input(&m_pFormatCtx); m_pFormatCtx = NULL; m_pVCodecCtx = NULL; m_pACodecCtx = NULL; m_pVCodec = NULL; m_pACodec = NULL; memset(&m_AudioSpec,0,sizeof(m_AudioSpec)); m_TReadPacket = NULL; m_TPlayVideo = NULL; while(!m_VpacketQue.empty()) { av_free_packet(&m_VpacketQue.front()); m_VpacketQue.pop(); } while(!m_ApacketQue.empty()) { av_free_packet(&m_ApacketQue.front()); m_ApacketQue.pop(); } m_vindex = -1; m_aindex = -1;// m_dstWidth = 0;// m_dstHeight = 0; m_pts = 0; return true;}
我自己最不喜欢别人不加注释,但是自己平常也不怎么写注释。
工程地址
阅读全文
1 0
- ffmpeg+sdl播放类
- ffmpeg SDL播放视频
- FFMPEG+SDL简单播放器
- FFMPEG+SDL简单播放器
- FFMPEG + SDL音频播放分析
- ffmpeg+SDl+ 播放器 -01
- FFMPEG + SDL音频播放分析
- FFMPEG + SDL音频播放分析
- MFC 播放视频 FFMPEG SDL
- FFMPEG + SDL音频播放分析
- ffmpeg+sdl音频播放器
- sdl+ffmpeg视频播放器
- FFmpeg+SDL视频播放(1)
- FFmpeg+SDL视频播放(2)
- FFmpeg+SDL视频播放(4)
- FFmpeg+SDL视频播放(3)
- FFMPEG + SDL音频播放分析
- 转 ffmpeg+sdl rstp 播放
- java NIO系列教程(二)
- Thinking in java-12 数据作用域问题
- Java 自定义类里面的对象自动赋初值
- 时间戳和日期互相转换
- 踩坑之_绑定远程服务
- ffmpeg+sdl播放类
- LeetCode 435. Non-overlapping Intervals
- java NIO系列教程(三)
- 电商业邮件营销| 六大事务性邮件,环环相扣打造极致用户体验!
- docker与CI/CD
- hibernate学习整理1
- 一个简单的jnative调用dll例子(含dll代码)
- 直接插入排序法
- 有采购光耦的吗,进来我们聊聊你们都是在哪里买的,价格怎么样,东芝光耦