一、前言
本地?cái)z像頭推流和本地桌面推流類(lèi)似,無(wú)非就是采集的設(shè)備源頭換成了本地?cái)z像頭設(shè)備而不是桌面,其他代碼完全一樣。采集本地?cái)z像頭實(shí)時(shí)視頻要注意的是如果設(shè)置分辨率和幀率,一定要是設(shè)備本身就支持的,如果不支持那就歇菜,比如設(shè)備本身最大分辨率到1280x720,你主動(dòng)設(shè)置要采集1080x720分辨率的圖像,那是采集不到的,會(huì)失敗的,如果默認(rèn)不設(shè)置,一般會(huì)采用640x480分辨率以及25幀率去采集。采集本地?cái)z像頭設(shè)備命令行是 ffmpeg -f dshow -i video=“USB Video Device”:audio=“麥克風(fēng) (USB Audio Device)” -vcodec libx264 -preset:v ultrafast -tune:v zerolatency -f rtsp rtsp://192.168.0.110:6907/stream ,可以指定帶上麥克風(fēng),這樣音視頻都有。
采集大致步驟:
- 查找格式 av_find_input_format,參數(shù) dshow/v4l2/avfoundation
- 打開(kāi)桌面 avformat_open_input,參數(shù) video=USB Video Device
- 查找視頻流 av_find_best_stream
- 查找解碼器 avcodec_find_decoder
- 打開(kāi)解碼器 avcodec_open2
- 循環(huán)讀取 av_read_frame
- 解碼視頻 avcodec_send_packet/avcodec_receive_frame
- 關(guān)閉釋放 avcodec_free_context/avformat_close_input
推流大致步驟:文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-449684.html
- 創(chuàng)建輸出 avformat_alloc_output_context2
- 創(chuàng)建視頻流 avformat_new_stream
- 打開(kāi)輸出 avio_open,參數(shù)填推流完整地址
- 寫(xiě)入開(kāi)始符 avformat_write_header
- 寫(xiě)入幀數(shù)據(jù) av_interleaved_write_frame
- 關(guān)閉釋放 avio_close/avformat_free_context
二、效果圖
文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-449684.html
三、體驗(yàn)地址
- 國(guó)內(nèi)站點(diǎn):https://gitee.com/feiyangqingyun
- 國(guó)際站點(diǎn):https://github.com/feiyangqingyun
- 個(gè)人作品:https://blog.csdn.net/feiyangqingyun/article/details/97565652
- 體驗(yàn)地址:https://pan.baidu.com/s/1d7TH_GEYl5nOecuNlWJJ7g 提取碼:01jf 文件名:bin_video_push。
四、相關(guān)代碼
void FFmpegThread::initInputFormat()
{
//本地?cái)z像頭/桌面錄屏
if (videoType == VideoType_Camera) {
#if defined(Q_OS_WIN)
//ifmt = av_find_input_format("vfwcap");
ifmt = av_find_input_format("dshow");
#elif defined(Q_OS_LINUX)
//可以打開(kāi)cheese程序查看本地?cái)z像頭(如果是在虛擬機(jī)中需要設(shè)置usb選項(xiàng)3.1)
//ifmt = av_find_input_format("v4l2");
ifmt = av_find_input_format("video4linux2");
#elif defined(Q_OS_MAC)
ifmt = av_find_input_format("avfoundation");
#endif
} else if (videoType == VideoType_Desktop) {
#if defined(Q_OS_WIN)
ifmt = av_find_input_format("gdigrab");
#elif defined(Q_OS_LINUX)
ifmt = av_find_input_format("x11grab");
#elif defined(Q_OS_MAC)
ifmt = av_find_input_format("avfoundation");
#endif
}
}
bool FFmpegThread::initInput()
{
//實(shí)例化格式處理上下文
formatCtx = avformat_alloc_context();
//設(shè)置超時(shí)回調(diào)(有些不存在的地址或者網(wǎng)絡(luò)不好的情況下要卡很久)
formatCtx->interrupt_callback.callback = FFmpegHelper::avinterruptCallBackFun;
formatCtx->interrupt_callback.opaque = this;
//打開(kāi)輸入(通過(guò)標(biāo)志位控制回調(diào)那邊做超時(shí)判斷)
//其他地方調(diào)用 formatCtx->url formatCtx->filename 可以拿到設(shè)置的地址(兩個(gè)變量值一樣)
tryOpen = true;
QByteArray urlData = VideoHelper::getRightUrl(videoType, videoUrl).toUtf8();
int result = avformat_open_input(&formatCtx, urlData.data(), ifmt, &options);
tryOpen = false;
if (result < 0) {
debug("打開(kāi)出錯(cuò)", "錯(cuò)誤: " + FFmpegHelper::getError(result));
return false;
}
//根據(jù)自己項(xiàng)目需要開(kāi)啟下面部分代碼加快視頻流打開(kāi)速度
//開(kāi)啟后由于值太小可能會(huì)出現(xiàn)部分視頻流獲取不到分辨率
if (decodeType == DecodeType_Fastest && videoType == VideoType_Rtsp) {
//接口內(nèi)部讀取的最大數(shù)據(jù)量(從源文件中讀取的最大字節(jié)數(shù))
//默認(rèn)值5000000導(dǎo)致這里卡很久最耗時(shí)(可以調(diào)小來(lái)加快打開(kāi)速度)
formatCtx->probesize = 50000;
//從文件中讀取的最大時(shí)長(zhǎng)(單位為 AV_TIME_BASE units)
formatCtx->max_analyze_duration = 5 * AV_TIME_BASE;
//內(nèi)部讀取的數(shù)據(jù)包不放入緩沖區(qū)
//formatCtx->flags |= AVFMT_FLAG_NOBUFFER;
//設(shè)置解碼錯(cuò)誤驗(yàn)證過(guò)濾花屏
//formatCtx->error_recognition |= AV_EF_EXPLODE;
}
//獲取流信息
result = avformat_find_stream_info(formatCtx, NULL);
if (result < 0) {
debug("找流失敗", "錯(cuò)誤: " + FFmpegHelper::getError(result));
return false;
}
//解碼格式
formatName = formatCtx->iformat->name;
//某些格式比如視頻流不做音視頻同步(響應(yīng)速度快)
if (formatName == "rtsp" || videoUrl.endsWith(".sdp")) {
useSync = false;
}
//設(shè)置了最快速度則不啟用音視頻同步
if (decodeType == DecodeType_Fastest) {
useSync = false;
}
//有些格式不支持硬解碼
if (formatName.contains("rm") || formatName.contains("avi") || formatName.contains("webm")) {
hardware = "none";
}
//本地?cái)z像頭設(shè)備解碼出來(lái)的直接就是yuv顯示不需要硬解碼
if (videoType == VideoType_Camera || videoType == VideoType_Desktop) {
useSync = false;
hardware = "none";
}
//過(guò)低版本不支持硬解碼
#if (FFMPEG_VERSION_MAJOR < 3)
hardware = "none";
#endif
//獲取文件時(shí)長(zhǎng)(這里獲取到的是秒)
double length = (double)formatCtx->duration / AV_TIME_BASE;
duration = length * 1000;
this->checkVideoType();
//有時(shí)候網(wǎng)絡(luò)地址也可能是純音頻
if (videoType == VideoType_FileHttp) {
onlyAudio = VideoHelper::getOnlyAudio(videoUrl, formatName);
}
if (getIsFile()) {
//文件必須要音視頻同步
useSync = true;
//發(fā)送文件時(shí)長(zhǎng)信號(hào)
emit receiveDuration(duration > 0 ? duration : 0);
}
QString msg = QString("格式: %1 時(shí)長(zhǎng): %2 秒 加速: %3").arg(formatName).arg(duration / 1000).arg(hardware);
debug("媒體信息", msg);
return true;
}
五、功能特點(diǎn)
5.1 文件推流
- 指定網(wǎng)卡和監(jiān)聽(tīng)端口,接收網(wǎng)絡(luò)請(qǐng)求推送音視頻等各種文件。
- 實(shí)時(shí)統(tǒng)計(jì)顯示每個(gè)文件對(duì)應(yīng)的訪問(wèn)數(shù)量、總訪問(wèn)數(shù)量、不同IP地址訪問(wèn)數(shù)量。
- 可指定多種模式,0-直接播放、1-下載播放。
- 實(shí)時(shí)打印顯示各種收發(fā)請(qǐng)求和應(yīng)答數(shù)據(jù)。
- 每個(gè)文件對(duì)應(yīng)MD5加密的唯一標(biāo)識(shí)符,用于請(qǐng)求地址后綴區(qū)分訪問(wèn)哪個(gè)文件。
- 支持各種瀏覽器(谷歌chromium/微軟edge/火狐firefox等)、各種播放器(vlc/mpv/ffplay/potplayer/mpchc等)打開(kāi)請(qǐng)求。
- 播放過(guò)程中可以任意切換播放進(jìn)度,支持倍速播放。
- 需要推流的文件名稱(chēng)歷史記錄自動(dòng)存儲(chǔ)和打開(kāi)加載應(yīng)用。
- 切換文件獲取訪問(wèn)地址,自動(dòng)拷貝地址到剪切板方便直接粘貼測(cè)試使用。
- 極低CPU占用,128路1080P同時(shí)推流不到1%CPU占用,異步發(fā)送數(shù)據(jù)機(jī)制。
- 純QTcpSocket通信,不依賴(lài)流媒體服務(wù)程序,核心源碼不到500行,注釋詳細(xì),功能完整。
- 支持Qt4/Qt5/Qt6任意版本,支持任意系統(tǒng)(windows/linux/macos/android/嵌入式linux等)。
5.2 網(wǎng)絡(luò)推流
- 支持各種本地視頻文件和網(wǎng)絡(luò)視頻文件。
- 支持各種網(wǎng)絡(luò)視頻流,網(wǎng)絡(luò)攝像頭,協(xié)議包括rtsp、rtmp、http。
- 支持將本地?cái)z像頭設(shè)備推流,可指定分辨率和幀率等。
- 支持將本地桌面推流,可指定屏幕區(qū)域和幀率等。
- 自動(dòng)啟動(dòng)流媒體服務(wù)程序,默認(rèn)mediamtx(原rtsp-simple-server),可選用srs、EasyDarwin、LiveQing、ZLMediaKit等。
- 可實(shí)時(shí)切換預(yù)覽視頻文件。
- 推流的清晰度和質(zhì)量可調(diào)。
- 可動(dòng)態(tài)添加文件、目錄、地址。
- 視頻文件自動(dòng)循環(huán)推流,如果視頻源是視頻流,在掉線后會(huì)自動(dòng)重連。
- 網(wǎng)絡(luò)視頻流自動(dòng)重連,重連成功自動(dòng)繼續(xù)推流。
- 網(wǎng)絡(luò)視頻流實(shí)時(shí)性極高,延遲極低,延遲時(shí)間大概在100ms左右。
- 推流后除了用rtmp地址訪問(wèn)以外,還支持直接hls/webrtc訪問(wèn),可以直接瀏覽器打開(kāi)看實(shí)時(shí)畫(huà)面。
- 支持Qt4/Qt5/Qt6任意版本,支持任意系統(tǒng)(windows/linux/macos/android/嵌入式linux等)。
到了這里,關(guān)于Qt音視頻開(kāi)發(fā)44-本地?cái)z像頭推流(支持分辨率/幀率等設(shè)置/實(shí)時(shí)性極高)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!