一、基本介绍
该软件里推流和视频保存使用FFMPEG库完成,界面框架采用QT,视频和音频可以同步推流和录制,FFMPEG本身支持跨平台编译开发,QT也支持跨平台,在Android、Linux、windows都运行良好,只需要在不同平台编译对应的ffmpeg库即可,逻辑代码部分通用。
该源码在2021年完成了新版本的更新,支持桌面推流和视频录制,效果图在文章的第四章可以查看。
完整项目代码下载地址(下载即可编译运行): QT FFMPEG的推流客户端.7z_qt摄像头推流-直播技术文档类资源-CSDN下载
https://download.csdn.net/download/xiaolong1126626497/19323232
二、windows下软件运行效果
(1)主界面效果
(2)保存视频到本地,设置录制间隔为10秒一个视频
(3)推流视频到B站,必须保证RTMP地址是有效的,如果地址无效软件会自动退出
三、核心代码
代码里除了FFMEG代码之外,主要的核心代码是摄像头颜色转换代码,因为不同的摄像头输出的原始格式不一样,代码里还需要做颜色转换。
代码语言:javascript复制void VideoReadThread_0::slotOnProbeFrame(const QVideoFrame &frame)
{
QVideoFrame cloneFrame(frame);
cloneFrame.map(QAbstractVideoBuffer::ReadOnly);
// qDebug()<<"height:"<<cloneFrame.height();
// qDebug()<<"width:"<<cloneFrame.width();
//qDebug()<<"bytesPerLine:"<<cloneFrame.bytesPerLine();
//qDebug()<<"mappedBytes:"<<cloneFrame.mappedBytes();
//qDebug()<<"pixelFormat:"<<cloneFrame.pixelFormat();
unsigned char rgb_buffer[VIDEO_WIDTH*VIDEO_HEIGHT*3];
if(cloneFrame.pixelFormat()==QVideoFrame::Format_NV21)
{
NV21_TO_RGB24(cloneFrame.bits(),rgb_buffer,cloneFrame.width(),cloneFrame.height());
}
else if(cloneFrame.pixelFormat()==QVideoFrame::Format_YUYV)
{
yuyv_to_rgb(cloneFrame.bits(),rgb_buffer,cloneFrame.width(),cloneFrame.height());
}
else if(cloneFrame.pixelFormat()==QVideoFrame::Format_RGB24)
{
memcpy(rgb_buffer,cloneFrame.bits(),sizeof(rgb_buffer));
}
else if(cloneFrame.pixelFormat()==QVideoFrame::Format_BGR24)
{
memcpy(rgb_buffer,cloneFrame.bits(),sizeof(rgb_buffer));
}
else if(cloneFrame.pixelFormat()==QVideoFrame::Format_Jpeg)
{
}
else
{
qDebug("当前格式编码为%1,暂时不支持转换.n");
}
//加载图片数据
QImage image(rgb_buffer,
cloneFrame.width(),
cloneFrame.height(),
QImage::Format_RGB888);
if(cloneFrame.pixelFormat()==QVideoFrame::Format_BGR24)
{
image=image.rgbSwapped(); //BGR格式转RGB
image=image.mirrored(false, true);
}
if(cloneFrame.pixelFormat()==QVideoFrame::Format_Jpeg)
{
image.loadFromData((const uchar *)cloneFrame.bits(),cloneFrame.mappedBytes());
}
//绘制图片水印
QDateTime dateTime(QDateTime::currentDateTime());
//时间效果: 2020-03-05 16:25::04 周一
QString qStr="";
qStr =dateTime.toString("yyyy-MM-dd hh:mm:ss ddd");
QPainter pp(&image);
QPen pen = QPen(Qt::white);
pp.setPen(pen);
pp.drawText(QPointF(0,20),qStr);
//提取RGB数据
unsigned char *p=rgb_buffer;
for(int i=0;i<image.height();i )
{
for(int j=0;j<image.width();j )
{
QRgb rgb=image.pixel(j,i);
*p =qRed(rgb);
*p =qGreen(rgb);
*p =qBlue(rgb);
}
}
videoaudioencode_0.video_encode_mutex.lock();
RGB24_TO_YUV420(rgb_buffer,image.width(),image.height(),video_yuv420p_buff);
videoaudioencode_0.video_encode_mutex.unlock();
videoaudioencode_0.video_WaitConditon.wakeAll();
emit VideoDataOutput(image); //发送信号
cloneFrame.unmap();
}
xxx.pro工程文件代码:
代码语言:javascript复制QT = core gui
QT = multimediawidgets
QT = xml
QT = multimedia
QT = network
QT = widgets
QT = serialport
greaterThan(QT_MAJOR_VERSION, 4): QT = widgets
CONFIG = c 11
# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES = QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES = QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES =
Color_conversion.cpp
audio_video_encode_0.cpp
ffmpeg_code.cpp
main.cpp
widget.cpp
HEADERS =
Color_conversion.h
audio_video_encode_0.h
config.h
ffmpeg_code.h
widget.h
FORMS =
widget.ui
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS = target
RC_ICONS=log.ico
win32
{
message('运行win32版本')
INCLUDEPATH =$$PWD/ffmpeg-win32-shared-dll/include
LIBS =$$PWD/ffmpeg-win32-shared-dll/bin/av*
LIBS =$$PWD/ffmpeg-win32-shared-dll/bin/sw*
LIBS =$$PWD/ffmpeg-win32-shared-dll/bin/pos*
}
RESOURCES =
image.qrc