#include "cvideoplayer.h"
QMutex g_lock;
// 音频处理回调函数。读队列获取音频包,解码,播放
// 此函数被SDL按需调用,此函数不在用户主线程中,因此数据需要保护
// \param[in] userdata用户在注册回调函数时指定的参数
// \param[out] stream 音频数据缓冲区地址,将解码后的音频数据填入此缓冲区
// \param[out] len 音频数据缓冲区大小,单位字节
// 回调函数返回后,stream指向的音频缓冲区将变为无效
void sdl_audio_callback(void *userdata, uint8_t *stream, int len)
{
cVideoPlayer *pPlayer = (cVideoPlayer*)userdata;
SDL_memset(stream, 0, len);
if(pPlayer && pPlayer->m_adq.size() > 0)
{
QMutexLocker guard(&g_lock);
audio_data_t* pAudioData = pPlayer->m_adq.dequeue();
if(pAudioData->size == 0)
return;
len = (len>pAudioData->size?pAudioData->size:len);
SDL_MixAudio(stream, (uint8_t *)pAudioData->data, len, SDL_MIX_MAXVOLUME);
delete pAudioData;
}
}
cVideoPlayer::cVideoPlayer(QWidget *parent, int nWidth, int nHeight) : QWidget(parent),
m_nSDLWidth(nWidth), m_nSDLHeight(nHeight)
{
this->resize(nWidth, nHeight);
}
cVideoPlayer::~cVideoPlayer()
{
m_bRun = false;
MY_DEBUG << "~cVideoPlayer 000";
if(nullptr != m_pSurface)
{
SDL_FreeSurface(m_pSurface);
m_pSurface = nullptr;
}
if(nullptr != m_pTexture)
{
SDL_DestroyTexture(m_pTexture);
m_pTexture = nullptr;
}
MY_DEBUG << "~cVideoPlayer 111";
if(nullptr != m_pRenderer)
{
SDL_DestroyRenderer(m_pRenderer);
m_pRenderer = nullptr;
}
MY_DEBUG << "~cVideoPlayer 222";
if(nullptr != m_pWindow)
{
SDL_DestroyWindow(m_pWindow);
m_pWindow = nullptr;
}
MY_DEBUG << "~cVideoPlayer 333";
SDL_CloseAudio();
SDL_Quit();
MY_DEBUG << "~cVideoPlayer 444";
if(nullptr != m_pFrame)
{
av_frame_free(&m_pFrame);
m_pFrame = nullptr;
}
if(nullptr != m_pYuvFrame)
{
av_frame_free(&m_pYuvFrame);
m_pYuvFrame = nullptr;
}
MY_DEBUG << "~cVideoPlayer 555";
if(nullptr != m_pVideoCodecCxt)
{
avcodec_close(m_pVideoCodecCxt);
//m_pVideoCodecCxt = nullptr; //设置为nullptr会导致崩溃
}
MY_DEBUG << "~cVideoPlayer 666";
if(m_pFormatCtx)
{
avformat_close_input(&m_pFormatCtx);
avformat_free_context(m_pFormatCtx);
m_pFormatCtx = nullptr;
}
MY_DEBUG << "~cVideoPlayer 777";
if(nullptr != m_pSwsCtx)
{
sws_freeContext(m_pSwsCtx);
m_pSwsCtx = nullptr;
}
MY_DEBUG << "~cVideoPlayer 888";
if(nullptr != m_pDstBuffer)
{
av_free(m_pDstBuffer);
}
MY_DEBUG << "~cVideoPlayer end";
}
bool cVideoPlayer::loadVideo(const QString &sUrl)
{
avformat_network_init();
if(sUrl.contains("rtsp://") || sUrl.contains("http://")) //实时流
m_nPlayWay = MEDIA_PLAY_STREAM;
else
m_nPlayWay = MEDIA_PLAY_FILE;
m_pFormatCtx = avformat_alloc_context();
if (avformat_open_input(&m_pFormatCtx, sUrl.toStdString().c_str(), nullptr, nullptr) != 0)
{
MY_DEBUG << "Failed to open video file";
return false;
}
if (avformat_find_stream_info(m_pFormatCtx, nullptr) < 0)
{
MY_DEBUG << "Failed to find stream information";
return false;
}
/*
m_nVideoIndex = -1;
for (unsigned int i = 0; i < m_pFormatCtx->nb_streams; i++)
{
if (m_pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
{
m_nVideoIndex = i;
break;
}
}*/
m_nVideoIndex = av_find_best_stream(m_pFormatCtx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
m_nAudioIndex = av_find_best_stream(m_pFormatCtx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);
if (m_nVideoIndex == -1)
{
MY_DEBUG << "Failed to find video stream";
return false;
}
//查找并打开视频解码器
m_pVideoCodecCxt = avcodec_alloc_context3(nullptr);
if (avcodec_parameters_to_context(m_pVideoCodecCxt, m_pFormatCtx->streams[m_nVideoIndex]->codecpar) != 0)
{
MY_DEBUG << "Failed to copy codec parameters to codec context";
return false;
}
const AVCodec *codec = avcodec_find_decoder(m_pVideoCodecCxt->codec_id);
if (codec == nullptr)
{
MY_DEBUG << "Failed to find video decoder";
return false;
}
if (avcodec_open2(m_pVideoCodecCxt, codec, nullptr) < 0)
{
MY_DEBUG << "Failed to open video decoder";
return false;
}
m_CodecId = codec->id;
//查找并打开音频解码器
if(m_nAudioIndex > 0)
{
//查找音频解码器
const AVCodec *pAVCodec = avcodec_find_decoder(m_pFormatCtx->streams[m_nAudioIndex]->codecpar->codec_id);
if(!pAVCodec)
{
MY_DEBUG << "audio decoder not found";
return false;
}
m_AudioCodecId = pAVCodec->id;
//音频解码器参数配置
if (!m_pAudioCodecCxt)
m_pAudioCodecCxt = avcodec_alloc_context3(nullptr);
if(nullptr == m_pAudioCodecCxt)
{
MY_DEBUG << "avcodec_alloc_context3 error m_pAudioCodecCxt=nullptr";
return false;
}
avcodec_parameters_to_context(m_pAudioCodecCxt, m_pFormatCtx->streams[m_nAudioIndex]->codecpar);
//打开音频解码器
int nRet = avcodec_open2(m_pAudioCodecCxt, pAVCodec, nullptr);
if(nRet < 0)
{
avcodec_close(m_pAudioCodecCxt);
MY_DEBUG << "avcodec_open2 error m_pAudioCodecCxt";
return false;
}
//音频重采样初始化
if (nullptr == m_pAudioSwrContext)
{
if(m_pAudioCodecCxt->channel_layout <= 0 || m_pAudioCodecCxt->channel_layout > 3)
m_pAudioCodecCxt->channel_layout = 1;
MY_DEBUG << "m_audioCodecContext->channel_layout:" << m_pAudioCodecCxt->channel_layout;
MY_DEBUG << "m_audioCodecContext->channels:" << m_pAudioCodecCxt->channels;
m_pAudioSwrContext = swr_alloc_set_opts(0,
m_pAudioCodecCxt->channel_layout,
AV_SAMPLE_FMT_S16,
m_pAudioCodecCxt->sample_rate,
av_get_default_channel_layout(m_pAudioCodecCxt->channels),
m_pAudioCodecCxt->sample_fmt,
m_pAudioCodecCxt->sample_rate,
0,
0);
auto nRet = swr_init(m_pAudioSwrContext);
if(nRet < 0)
{
MY_DEBUG << "swr_init error";
return false;
}
}
m_nAudioSampleRate = m_pAudioCodecCxt->sample_rate;
m_audioSpec.freq = m_nAudioSampleRate; // 采样率
m_audioSpec.format = AUDIO_S16SYS; // S表带符号,16是采样深度,SYS表采用系统字节序
m_audioSpec.channels = m_pAudioCodecCxt->channels; // 声道数
m_audioSpec.silence = 0; // 静音值
m_audioSpec.samples = m_pAudioCodecCxt->frame_size; // SDL声音缓冲区尺寸,单位是单声道采样点尺寸x通道数
m_audioSpec.callback = sdl_audio_callback; // 回调函数,若为NULL,则应使
没有合适的资源?快使用搜索试试~ 我知道了~
资源推荐
资源详情
资源评论
收起资源包目录
QT下使用ffmpeg+SDL实现音视频播放器,支持录像截图功能,提供工程源码下载 (450个子文件)
libSDL2.a 16.65MB
libSDL2_test.a 602KB
libSDL2.dll.a 550KB
libSDL2main.a 8KB
screenshot.bmp 5.93MB
SDL_config.h.cmake 18KB
cvideoplayer.cpp 16KB
mp4recorder.cpp 13KB
moc_mainwindow.cpp 5KB
moc_cvideoplayer.cpp 3KB
moc_mp4recorder.cpp 3KB
mainwindow.cpp 3KB
cteasyaacencoder.cpp 1KB
main.cpp 199B
Makefile.Debug 242KB
avcodec-59.dll 9.02MB
avcodec-59.dll 8.29MB
avcodec-59.dll 8.29MB
avformat-59.dll 5.52MB
avformat-59.dll 5.47MB
avformat-59.dll 5.47MB
avfilter-8.dll 2.92MB
avfilter-8.dll 2.64MB
avfilter-8.dll 2.64MB
SDL2.dll 2.39MB
SDL2.dll 2.39MB
SDL2.dll 2.19MB
SDL2.dll 2.19MB
SDL2.dll 2.19MB
avutil-57.dll 565KB
swscale-6.dll 545KB
avutil-57.dll 481KB
avutil-57.dll 481KB
libEasyAACEncoder.dll 474KB
swscale-6.dll 419KB
swscale-6.dll 419KB
libEasyAACEncoder.dll 219KB
swresample-4.dll 111KB
swresample-4.dll 105KB
swresample-4.dll 105KB
avdevice-59.dll 20KB
avdevice-59.dll 15KB
avdevice-59.dll 15KB
mySDLPlayer.exe 66KB
SDL_opengl_glext.h 844KB
SDL_opengles2_gl2ext.h 236KB
avcodec.h 111KB
avcodec.h 111KB
avformat.h 111KB
avformat.h 111KB
SDL_hints.h 108KB
SDL_egl.h 106KB
SDL_opengl.h 79KB
SDL_video.h 78KB
SDL_render.h 72KB
SDL_audio.h 58KB
SDL_events.h 46KB
avfilter.h 43KB
avfilter.h 43KB
SDL_haptic.h 42KB
SDL_opengles2_gl2.h 42KB
SDL_gamecontroller.h 39KB
SDL_joystick.h 38KB
pixfmt.h 36KB
pixfmt.h 36KB
opt.h 36KB
opt.h 36KB
SDL_surface.h 36KB
frame.h 31KB
frame.h 31KB
avio.h 31KB
avio.h 31KB
channel_layout.h 31KB
channel_layout.h 31KB
SDL_stdinc.h 29KB
SDL_rwops.h 27KB
swresample.h 25KB
swresample.h 25KB
SDL_pixels.h 24KB
hwcontext.h 24KB
hwcontext.h 24KB
packet.h 23KB
packet.h 23KB
mem.h 23KB
mem.h 23KB
SDL_system.h 20KB
intreadwrite.h 18KB
intreadwrite.h 18KB
avdevice.h 18KB
avdevice.h 18KB
SDL_hidapi.h 17KB
SDL_cpuinfo.h 17KB
SDL_thread.h 17KB
common.h 17KB
common.h 17KB
codec_id.h 17KB
codec_id.h 17KB
SDL_mouse.h 17KB
SDL_scancode.h 17KB
swscale.h 15KB
共 450 条
- 1
- 2
- 3
- 4
- 5
浅笑一斤
- 粉丝: 1w+
- 资源: 61
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功
- 1
- 2
- 3
- 4
- 5
前往页