96SEO 2026-02-20 04:32 2
。

它支持TCP或UDP方式拉取实时流#xff0c;实时流我采用的是监控摄像头的RTSP流。
音频播放采用的是QAudioOutput#xff0c;视频经ffmpeg解码并由YUV转RGB后是在QOpenGLWidget下进行渲染显示。
本…前言
本工程qt用的版本是5.8-32位ffmpeg用的版本是较新的5.1版本。
它支持TCP或UDP方式拉取实时流实时流我采用的是监控摄像头的RTSP流。
音频播放采用的是QAudioOutput视频经ffmpeg解码并由YUV转RGB后是在QOpenGLWidget下进行渲染显示。
本工程的代码有注释可以通过本博客查看代码或者在播放最后的链接处下载工程demo。
on_btn_open_audio_clicked();void
on_btn_close_audio_clicked();void
on_btn_stop_record_clicked();private:Ui::MainWindow
ctaudioplayer.hMainWindow::MainWindow(QWidget
{ui-radioButton_TCP-setChecked(false);ui-radioButton_UDP-setChecked(true);
MainWindow::on_btn_play_clicked()
ui-lineEdit_Url-text();if(sUrl.isEmpty()){QMessageBox::critical(this,
错误:实时流url不能为空.);return;}if(nullptr
MediaThread;}else{if(m_pMediaThread-isRunning()){QMessageBox::critical(this,
错误:请先点击停止按钮关闭视频.);return;}}connect(m_pMediaThread,
false;if(ui-radioButton_TCP-isChecked()){bMediaInit
PROTOCOL_UDP);}if(bMediaInit){m_pMediaThread-startThread();}
MainWindow::on_btn_open_clicked()
QFileDialog::getOpenFileName(this,
QString::fromLocal8Bit(选择视频文件));if(sFileName.isEmpty()){QMessageBox::critical(this,
错误:文件不能为空.);return;}ui-lineEdit_File-setText(sFileName);}void
MainWindow::on_btn_play2_clicked()
ui-lineEdit_File-text();if(sFileName.isEmpty()){QMessageBox::critical(this,
MediaThread;}else{if(m_pMediaThread-isRunning()){QMessageBox::critical(this,
错误:请先点击停止按钮关闭视频.);return;}}connect(m_pMediaThread,
QImage)));if(m_pMediaThread-Init(sFileName)){m_pMediaThread-startThread();}
MainWindow::on_btn_stop_clicked()
QImage)));m_pMediaThread-stopThread();qDebug()
111;m_pMediaThread-quit();m_pMediaThread-wait();qDebug()
222;m_pMediaThread-DeInit();qDebug()
MainWindow::on_btn_record_clicked()
{if(m_pMediaThread)m_pMediaThread-startRecord();
MainWindow::on_btn_snapshot_clicked()
{if(m_pMediaThread)m_pMediaThread-Snapshot();
MainWindow::on_btn_open_audio_clicked()
{ctAudioPlayer::getInstance().isPlay(true);
MainWindow::on_btn_close_audio_clicked()
{ctAudioPlayer::getInstance().isPlay(false);
MainWindow::on_btn_stop_record_clicked()
{if(m_pMediaThread)m_pMediaThread-stopRecord();
2.以下是流媒体线程相关代码mediathread.h、mediathread.cpp
public:MediaThread();~MediaThread();bool
QTimeMediaThread::MediaThread()
{if(m_pFFmpeg){m_pFFmpeg-DeInit();delete
QImage)));}if(m_pFFmpeg-Init(sUrl,
000;m_pFFmpeg-DeInit();MY_DEBUG
QString(%1%2-%3-%4-%5%6%7.mp4).arg(sPath).arg(date.year()).
\arg(date.month()).arg(date.day()).arg(time.hour()).arg(time.minute()).
m_pMp4Recorder.Init(m_pFFmpeg-m_pAVFmtCxt,
stopRecord...;m_pMp4Recorder.DeInit();m_bRecord
{0};while(m_bRun){if(m_bPause){msleep(100);continue;}//获取播放器缓存大小if(m_pFFmpeg-m_bSupportAudioPlay){int
ctAudioPlayer::getInstance().getFreeSize();if(nFreeSize
m_nMinAudioPlayerSize){msleep(1);continue;}}AVPacket
0){msleep(10);continue;}//解码播放if
m_pFFmpeg-m_bSupportAudioPlay){if(m_pFFmpeg-Decode(pkt)){int
m_pFFmpeg-getAudioFrame(audioOut);//获取一帧音频的pcmif(nLen
0)ctAudioPlayer::getInstance().Write(audioOut,
nLen);}}else{//目前只支持录制视频if(m_bRecord){//MY_DEBUG
av_packet_clone(pkt);m_pMp4Recorder.saveOneFrame(*pPkt);av_packet_free(pPkt);}if(m_pFFmpeg-Decode(pkt)){m_pFFmpeg-getVideoFrame();}}av_packet_unref(pkt);}MY_DEBUG
3.以下是ffmpeg处理的相关代码ctffmpeg.h、ctffmpeg.cpp
libavutil/mathematics.h#include
libswresample/swresample.h#include
libavfilter/buffersink.h#include
libavfilter/buffersrc.h#include
public:ctFFmpeg();~ctFFmpeg();int
//流媒体的上下文private:AVCodecContext*
{DeInit();avformat_network_init();//初始化网络流//参数设置AVDictionary*
PROTOCOL_UDP)av_dict_set(pOptDict,
avformat_alloc_context();if(nullptr
av_frame_alloc();//加入中断处理m_nLastReadPacktTime
av_gettime();m_pAVFmtCxt-interrupt_callback.opaque
this;m_pAVFmtCxt-interrupt_callback.callback
avformat_open_input(m_pAVFmtCxt,
nRet;}//设置探测时间获取码流信息m_pAVFmtCxt-probesize
1024;m_pAVFmtCxt-max_analyze_duration
avformat_find_stream_info(m_pAVFmtCxt,
nRet;}//打印码流信息av_dump_format(m_pAVFmtCxt,
(m_pAVFmtCxt-streams[nIndex]-codecpar-codec_type
AVMEDIA_TYPE_VIDEO){m_nVideoIndex
(m_pAVFmtCxt-streams[nIndex]-codecpar-codec_type
AVMEDIA_TYPE_AUDIO){m_nAudioIndex
m_pVideoSwsContext){sws_freeContext(m_pVideoSwsContext);}MY_DEBUG
m_pAudioSwrContext){swr_free(m_pAudioSwrContext);m_pAudioSwrContext
m_pYuvFrame)av_free(m_pYuvFrame);MY_DEBUG
m_pPcmFrame)av_free(m_pPcmFrame);MY_DEBUG
m_pOutBuffer){av_free(m_pOutBuffer);}MY_DEBUG
m_pVideoCodecCxt){avcodec_close(m_pVideoCodecCxt);//avcodec_free_context(m_pVideoCodecCxt);m_pVideoCodecCxt
m_pAudioCodecCxt){avcodec_close(m_pAudioCodecCxt);//avcodec_free_context(m_pAudioCodecCxt);m_pAudioCodecCxt
m_pAVFmtCxt){avformat_close_input(m_pAVFmtCxt);MY_DEBUG
999;avformat_free_context(m_pAVFmtCxt);m_pAVFmtCxt
sizeof(AVPacket));if(!m_pAVFmtCxt){return
errorbuff[1024];av_strerror(nErr,
{m_mutex.lock();if(!m_pAVFmtCxt){m_mutex.unlock();return
avcodec_receive_frame(pCodecCxt,
0){m_mutex.unlock();qDebug()avcodec_receive_frame
const*)m_pYuvFrame-data,m_pYuvFrame-linesize,
m_pVideoCodecCxt-height,m_pFrameRGB-data,
m_pVideoCodecCxt-width,m_pVideoCodecCxt-height,
QImage::Format_ARGB32);//截图if(m_bSnapshot){QPixmap
QPixmap::fromImage(image);QString
QTime::currentTime();m_sSnapPath
QString(%1%2-%3-%4-%5%6%7.jpg).arg(sPath).arg(date.year()).
\arg(date.month()).arg(date.day()).arg(time.hour()).arg(time.minute()).
m_sSnapPath;pixPicture.save(m_sSnapPath,
sig_getImage(image);m_mutex.unlock();return
av_rescale_rnd(m_pPcmFrame-nb_samples,m_nAudioPlaySampleRate,m_nAudioSampleRate,AV_ROUND_ZERO);//重采样int
swr_convert(m_pAudioSwrContext,
**)m_pPcmFrame-data,m_pPcmFrame-nb_samples);if(nLen
av_samples_get_buffer_size(nullptr,
m_pAudioCodecCxt-channels,m_pPcmFrame-nb_samples,AV_SAMPLE_FMT_S16,0);m_mutex.unlock();return
avcodec_find_decoder(m_pAVFmtCxt-streams[m_nVideoIndex]-codecpar-codec_id);if(!pAVCodec){MY_DEBUG
pAVCodec-id;if(!m_pVideoCodecCxt)m_pVideoCodecCxt
avcodec_alloc_context3(nullptr);if(nullptr
-1;}avcodec_parameters_to_context(m_pVideoCodecCxt,
m_pAVFmtCxt-streams[m_nVideoIndex]-codecpar);if(m_pVideoCodecCxt){if
avcodec_open2(m_pVideoCodecCxt,
-1;}//申请并分配内存,初始化转换上下文,用于YUV转RGBm_pOutBuffer
(uint8_t*)av_malloc(av_image_get_buffer_size(AV_PIX_FMT_BGRA,m_pVideoCodecCxt-width,
-1;}av_image_fill_arrays(m_pFrameRGB-data,
sws_getContext(m_pVideoCodecCxt-width,
m_pVideoCodecCxt-height,m_pVideoCodecCxt-pix_fmt,
m_pVideoCodecCxt-height,AV_PIX_FMT_BGRA,
avcodec_find_decoder(m_pAVFmtCxt-streams[m_nAudioIndex]-codecpar-codec_id);if(!pAVCodec){MY_DEBUG
(!m_pAudioCodecCxt)m_pAudioCodecCxt
avcodec_alloc_context3(nullptr);if(nullptr
-1;}avcodec_parameters_to_context(m_pAudioCodecCxt,
m_pAVFmtCxt-streams[m_nAudioIndex]-codecpar);//打开音频解码器int
avcodec_open2(m_pAudioCodecCxt,
0){avcodec_close(m_pAudioCodecCxt);MY_DEBUG
m_pAudioSwrContext){if(m_pAudioCodecCxt-channel_layout
m_pAudioCodecCxt-channel_layout
3)m_pAudioCodecCxt-channel_layout
m_audioCodecContext-channel_layout:
m_pAudioCodecCxt-channel_layout;qDebug()
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
swr_init(m_pAudioSwrContext);if(nRet
(m_pAudioCodecCxt-sample_fmt)//样本大小{case
32;default:break;}m_nAudioSampleRate
m_pAudioCodecCxt-sample_rate;ctAudioPlayer::getInstance().m_nSampleRate
m_nAudioSampleRate;//采样率ctAudioPlayer::getInstance().m_nChannelCount
m_pAudioCodecCxt-channels;//通道数ctAudioPlayer::getInstance().m_nSampleSize
nSampleSize;//样本大小if(!ctAudioPlayer::getInstance().Init())return
4.以下是opengl处理的相关代码ctopenglwidget.h、ctopenglwidget.cpp
nullptr);~ctOpenglWidget();protected:void
commondef.hctOpenglWidget::ctOpenglWidget(QWidget
}ctOpenglWidget::~ctOpenglWidget()
ctOpenglWidget::paintEvent(QPaintEvent
painter;painter.begin(this);//清理屏幕painter.drawImage(QPoint(0,
m_image);//绘制FFMpeg解码后的视频painter.end();
ctOpenglWidget::slot_showImage(const
image.scaledToWidth(width(),Qt::SmoothTransformation);elsem_image
image.scaledToHeight(height(),Qt::SmoothTransformation);update();
4.以下是QAudioOutput音频播放器处理的相关代码ctaudioplayer.h、ctaudioplayer.cpp
public:ctAudioPlayer();~ctAudioPlayer();static
ctaudioplayer.hctAudioPlayer::ctAudioPlayer()
{}ctAudioPlayer::~ctAudioPlayer()
{DeInit();m_mutex.lock();MY_DEBUG
QAudioDeviceInfo::defaultOutputDevice();MY_DEBUG
m_audio_device.deviceName();if(m_audio_device.deviceName().isEmpty()){return
format;format.setSampleRate(m_nSampleRate);format.setSampleSize(m_nSampleSize);format.setChannelCount(m_nChannelCount);format.setCodec(audio/pcm);format.setByteOrder(QAudioFormat::LittleEndian);format.setSampleType(QAudioFormat::UnSignedInt);if(!m_audio_device.isFormatSupported(format)){MY_DEBUG
m_audio_device.nearestFormat(format);m_mutex.unlock();return
false;}if(m_pAudioOut){m_pAudioOut-stop();delete
QAudioOutput(format);m_pIODevice
m_pAudioOut-start();m_mutex.unlock();return
{m_mutex.lock();if(m_pAudioOut){m_pAudioOut-stop();delete
{m_mutex.lock();if(!m_pAudioOut){m_mutex.unlock();return;}if(bPlay)m_pAudioOut-resume();//恢复播放elsem_pAudioOut-suspend();//暂停播放m_mutex.unlock();
{m_mutex.lock();if(m_pIODevice)m_pIODevice-write(pData,
nDatasize);//将获取的音频写入到缓冲区中m_mutex.unlock();
{m_mutex.lock();if(!m_pAudioOut){m_mutex.unlock();return
m_pAudioOut-bytesFree();//剩余空间m_mutex.unlock();return
下载链接https://download.csdn.net/download/linyibin_123/87435635
https://blog.csdn.net/qq871580236/article/details/120364013
作为专业的SEO优化服务提供商,我们致力于通过科学、系统的搜索引擎优化策略,帮助企业在百度、Google等搜索引擎中获得更高的排名和流量。我们的服务涵盖网站结构优化、内容优化、技术SEO和链接建设等多个维度。
| 服务项目 | 基础套餐 | 标准套餐 | 高级定制 |
|---|---|---|---|
| 关键词优化数量 | 10-20个核心词 | 30-50个核心词+长尾词 | 80-150个全方位覆盖 |
| 内容优化 | 基础页面优化 | 全站内容优化+每月5篇原创 | 个性化内容策略+每月15篇原创 |
| 技术SEO | 基本技术检查 | 全面技术优化+移动适配 | 深度技术重构+性能优化 |
| 外链建设 | 每月5-10条 | 每月20-30条高质量外链 | 每月50+条多渠道外链 |
| 数据报告 | 月度基础报告 | 双周详细报告+分析 | 每周深度报告+策略调整 |
| 效果保障 | 3-6个月见效 | 2-4个月见效 | 1-3个月快速见效 |
我们的SEO优化服务遵循科学严谨的流程,确保每一步都基于数据分析和行业最佳实践:
全面检测网站技术问题、内容质量、竞争对手情况,制定个性化优化方案。
基于用户搜索意图和商业目标,制定全面的关键词矩阵和布局策略。
解决网站技术问题,优化网站结构,提升页面速度和移动端体验。
创作高质量原创内容,优化现有页面,建立内容更新机制。
获取高质量外部链接,建立品牌在线影响力,提升网站权威度。
持续监控排名、流量和转化数据,根据效果调整优化策略。
基于我们服务的客户数据统计,平均优化效果如下:
我们坚信,真正的SEO优化不仅仅是追求排名,而是通过提供优质内容、优化用户体验、建立网站权威,最终实现可持续的业务增长。我们的目标是与客户建立长期合作关系,共同成长。
Demand feedback