本篇內(nèi)容主要講解“Qt ffmpeg控制播放怎么實(shí)現(xiàn)”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“Qt ffmpeg控制播放怎么實(shí)現(xiàn)”吧!
創(chuàng)新互聯(lián)建站主營浉河網(wǎng)站建設(shè)的網(wǎng)絡(luò)公司,主營網(wǎng)站建設(shè)方案,成都app軟件開發(fā),浉河h5微信小程序定制開發(fā)搭建,浉河網(wǎng)站營銷推廣歡迎浉河等地區(qū)企業(yè)咨詢
很多人在用ffmpeg做視頻流解碼的時(shí)候,都會(huì)遇到一個(gè)問題,如何暫停,如果打開的是本地視頻文件,暫停你只需要停止解碼即可,但是視頻流你會(huì)發(fā)現(xiàn)根本沒用,一旦你停止了解碼,下次重新解碼的時(shí)候,居然還是以前的圖片,他是從你最后暫停開始的地方重新解碼的,這就懵逼了,為啥呢?我個(gè)人的理解是視頻流這玩意,一旦你打開了,他就源源不斷涌過來,你不處理,他就越來越多,你必須要讀取他,從緩沖區(qū)拿走這些數(shù)據(jù)才行,所以如果想要暫停視頻流,正確的做法是照常解碼,只是不處理和繪制圖片就行,說白了其實(shí)就是偽暫停,看起來是暫停了,其實(shí)后臺(tái)還在不斷的解碼中。
用ffmpeg播放本地文件的時(shí)候,如果不加延時(shí),你會(huì)發(fā)現(xiàn)刷刷幾秒鐘就播放完了,具體看電腦的性能,性能好的電腦也就幾秒鐘播放一個(gè)5分鐘的視頻,是不是會(huì)覺得很奇怪呢,怎么播放的這么快呢,其實(shí)ffmpeg解碼只管解碼,瘋狂解碼模式,使命的干,榨干你的CPU或者GPU資源(如果開啟了硬解碼則走GPU),解碼后的每一幀都帶有pts dts等信息,需要自己根據(jù)這些信息來做延時(shí)處理,比如還沒到下一幀的時(shí)候,你就延時(shí)一段時(shí)間再去解碼,至于延時(shí)多久有一個(gè)通用的計(jì)算方法,在打開流后記住開始的時(shí)間。然后解碼中取出對(duì)應(yīng)流(視頻流或者音頻流等)的基準(zhǔn)時(shí)間time_base,調(diào)用av_rescale_q計(jì)算出pts時(shí)間,然后用av_gettime() - startTime得到當(dāng)前的時(shí)間,用pts_time - now_time得到時(shí)間差值,如果是正數(shù),則這個(gè)時(shí)間就是需要延時(shí)的微秒數(shù),注意是微秒數(shù)而不是毫秒數(shù)哦,直接調(diào)用av_usleep來延時(shí)即可。
多線程實(shí)時(shí)播放視頻流+本地視頻+USB攝像頭等。
支持windows+linux+mac,支持ffmpeg3和ffmpeg4,支持32位和64位。
多線程顯示圖像,不卡主界面。
自動(dòng)重連網(wǎng)絡(luò)攝像頭。
可設(shè)置邊框大小即偏移量和邊框顏色。
可設(shè)置是否繪制OSD標(biāo)簽即標(biāo)簽文本或圖片和標(biāo)簽位置。
可設(shè)置兩種OSD位置和風(fēng)格。
可設(shè)置是否保存到文件以及文件名。
可直接拖曳文件到ffmpegwidget控件播放。
支持h365視頻流+rtmp等常見視頻流。
可暫停播放和繼續(xù)播放。
支持存儲(chǔ)單個(gè)視頻文件和定時(shí)存儲(chǔ)視頻文件。
自定義頂部懸浮條,發(fā)送單擊信號(hào)通知,可設(shè)置是否啟用。
可設(shè)置畫面拉伸填充或者等比例填充。
可設(shè)置解碼是速度優(yōu)先、質(zhì)量優(yōu)先、均衡處理。
可對(duì)視頻進(jìn)行截圖(原始圖片)和截屏。
錄像文件存儲(chǔ)支持裸流和MP4文件。
支持qsv、dxva2、d3d11va等硬解碼。
支持opengl繪制視頻數(shù)據(jù),極低CPU占用。
支持嵌入式linux,交叉編譯即可。
void FFmpegWidget::updateImage(const QImage &image) { //暫?;蛘卟豢梢?nbsp;rtsp視頻流需要停止繪制 if (!this->property("isPause").toBool() && this->isVisible() && thread->isRunning()) { //拷貝圖片有個(gè)好處,當(dāng)處理器比較差的時(shí)候,圖片不會(huì)產(chǎn)生斷層,缺點(diǎn)是占用時(shí)間 //默認(rèn)QImage類型是淺拷貝,可能正在繪制的時(shí)候,那邊已經(jīng)更改了圖片的上部分?jǐn)?shù)據(jù) this->image = copyImage ? image.copy() : image; this->update(); } } void FFmpegWidget::updateFrame(AVFrame *frame) { #ifdef opengl //暫停或者不可見 rtsp視頻流需要停止繪制 if (!this->property("isPause").toBool() && (yuvWidget->isVisible() || nv12Widget->isVisible()) && thread->isRunning()) { //采用了硬件加速的直接用nv12渲染,否則采用yuv渲染 if (thread->getHardware() == "none") { yuvWidget->setFrameSize(frame->width, frame->height); yuvWidget->updateTextures(frame->data[0], frame->data[1], frame->data[2], frame->linesize[0], frame->linesize[1], frame->linesize[2]); } else { nv12Widget->setFrameSize(frame->width, frame->height); nv12Widget->updateTextures(frame->data[0], frame->data[1], frame->linesize[0], frame->linesize[1]); } } #endif } void FFmpegThread::delayTime(int streamIndex, AVPacket *packet) { //視頻流不用延時(shí) if (isRtsp) { return; } //沒有視頻時(shí)長的文件和asf的本地文件采用另外的延時(shí)計(jì)算 if (streamIndex == videoStreamIndex) { if (interval != 1 || videoTime < 0 || url.toLower().endsWith("asf")) { sleepVideo(); return; } } qint64 offset_time = getDelayTime(streamIndex, packet); if (offset_time > 0) { av_usleep(offset_time); } } qint64 FFmpegThread::getDelayTime(int streamIndex, AVPacket *packet) { AVRational time_base = formatCtx->streams[streamIndex]->time_base; AVRational time_base_q = {1, AV_TIME_BASE}; int64_t pts_time = av_rescale_q(packet->pts, time_base, time_base_q); int64_t now_time = av_gettime() - startTime; int64_t offset_time = pts_time - now_time; return offset_time; }
到此,相信大家對(duì)“Qt ffmpeg控制播放怎么實(shí)現(xiàn)”有了更深的了解,不妨來實(shí)際操作一番吧!這里是創(chuàng)新互聯(lián)網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!