日本黄色一级经典视频|伊人久久精品视频|亚洲黄色色周成人视频九九九|av免费网址黄色小短片|黄色Av无码亚洲成年人|亚洲1区2区3区无码|真人黄片免费观看|无码一级小说欧美日免费三级|日韩中文字幕91在线看|精品久久久无码中文字幕边打电话

<dd id="gzsy9"><strong id="gzsy9"><blockquote id="gzsy9"></blockquote></strong></dd>
      當(dāng)前位置:首頁 > 單片機(jī) > 碼農(nóng)愛學(xué)習(xí)
      [導(dǎo)讀]本篇,將通過Qt程序,設(shè)計一個RTSP視頻播放器,來播放網(wǎng)絡(luò)視頻,并增加啟動、暫停等操作按鈕。

      上篇文章,介紹了FFmpeg的交叉編譯,以及在嵌入式Linux平臺,運(yùn)行ffmpeg指令來播放視頻。

      本篇,將通過Qt程序,設(shè)計一個RTSP視頻播放器,來播放網(wǎng)絡(luò)視頻,并增加啟動、暫停等操作按鈕。

      1 FFMPEG 庫介紹

      1.1 ffmpeg的7個庫

      ffmpeg有7個library,分別是:

      • avutil
      • swscale
      • swresample
      • avcodec
      • avformat
      • avdevice
      • avfilter

      avutil 工具庫

      avutil是一個實用的工具庫用于輔助可移植的多媒體編程。它包含安全的可移植的字符串函數(shù),隨機(jī)數(shù)生成器,數(shù)據(jù)結(jié)構(gòu),附加的數(shù)學(xué)函數(shù),密碼學(xué)和多媒體相關(guān)功能(例如像素和樣本格式的枚舉)。它不是 libavcodec 和 libavformat 都需要的代碼庫。

      swscale 視頻像素數(shù)據(jù)格式轉(zhuǎn)換

      swscale庫執(zhí)行高度優(yōu)化的圖像縮放以及色彩空間和像素格式轉(zhuǎn)換操作,這個庫執(zhí)行以下轉(zhuǎn)換:

      • Recailing:是改變視頻大小的過程。有幾個重新縮放選項和算法可用。這通常是一個有損過程。

      • Pixel format conversion:是將圖像的圖像格式和色彩空間轉(zhuǎn)換的過程,例如從平面YUV420P 到RGB24 打包。它還處理打包方式轉(zhuǎn)換,即從Packed布局轉(zhuǎn)換為Planar布局。

        注意:如果源和目標(biāo)顏色空間不同,這通常是一個有損過程。

      swresample 音頻采樣數(shù)據(jù)格式轉(zhuǎn)換

      swresample庫執(zhí)行高度優(yōu)化的音頻重采樣,重矩陣化和樣本格式轉(zhuǎn)換操作,這個庫執(zhí)行以下轉(zhuǎn)換:

      • Resampling:是改變音頻碼率的過程,例如從一個高采樣率44100Hz轉(zhuǎn)化為8000Hz。音頻從高采樣率轉(zhuǎn)換為低采樣率是一個有損的過程。有幾種重采樣選項和算法可用。
      • Format conversion:是一個轉(zhuǎn)換樣本類型的過程,例如從有符號16-bit(int16_t)樣本轉(zhuǎn)換為無符號8-bit(uint8_t)或浮點樣本。它也處理打包方式轉(zhuǎn)換,如從Packed布局轉(zhuǎn)換為Planar布局。
      • Rematrixing:是改變通道布局的過程,例如從立體聲到單聲道。當(dāng)輸入通道不能映射到輸出流時,這個過程是有損的,因為它涉及不同的增益因子和混合。通過專用選項啟用各種其他音頻轉(zhuǎn)換(例如拉伸和填充)。

      avcodec 編解碼

      avcodec庫提供了一個通用的編碼/解碼框架,并且包含用于音頻、視頻、字幕流的多個編解器和解碼器享架構(gòu)提供從比特 I/O 到 DSP 優(yōu)化的各種服務(wù),使其適用于實現(xiàn)魯棒和快速的編解碼器以及實驗。

      avformat 封裝格式處理

      libavformat庫為音頻、視頻和字幕流的復(fù)用和解復(fù)用(muxing and demuxing)提供了一個通用框架。它包含多個用于媒體容器格式的多個復(fù)用器和解復(fù)用器,它還支持多種輸入和輸出協(xié)議來訪問媒體資源。

      avdevice 設(shè)備的輸入輸出

      avdevice 庫提供了一個通用框架,用于從許多常見的多媒體輸入/輸出設(shè)備進(jìn)行抓取和渲染,并支持多種輸入和輸出設(shè)備,包括 Video4Linux2、VfW、DShow 和 ALSA。

      avfilter 濾鏡特效處理

      avfilter 庫提供了一個通用的音頻/視頻過濾框架,其中包含多個過濾器、源和接收器。

      1.2 win平臺FFmpeg庫下載

      Win平臺的Qt Creator需要用到Visual Stdio的功能,我電腦的Visual Stdio的2015版(對應(yīng)的是msvc14),因此,我下載的FFmpeg是4.4版的,再高的版本就沒有msvc14的了。

      https://github.com/ShiftMediaProject/FFmpeg/releases/tag/4.4.r101753

      2 Qt程序設(shè)計

      2.1 RTSP解碼與視頻播放流程

      先來看下FFmpeg對RTSP解碼的處理流程:

      2.2 視頻解碼

      對照上面的流程圖,使用FFmpeg對RTSP視頻流的解碼如下:

      void VideoPlayer::run() {
          AVFormatContext *pFormatCtx; //音視頻封裝格式上下文結(jié)構(gòu)體 AVCodecContext  *pCodecCtx; //音視頻編碼器上下文結(jié)構(gòu)體 AVCodec *pCodec; //音視頻編碼器結(jié)構(gòu)體 AVFrame *pFrame; //存儲一幀解碼后像素數(shù)據(jù) AVFrame *pFrameRGB;
          AVPacket *pPacket; //存儲一幀壓縮編碼數(shù)據(jù) uint8_t *pOutBuffer; static struct SwsContext *pImgConvertCtx; avformat_network_init(); //初始化FFmpeg網(wǎng)絡(luò)模塊 av_register_all(); //初始化FFMPEG  調(diào)用了這個才能正常適用編碼器和解碼器 //Allocate an AVFormatContext. pFormatCtx = avformat_alloc_context(); //AVDictionary AVDictionary *avdic=nullptr; char option_key[]="rtsp_transport"; char option_value[]="udp";
          av_dict_set(&avdic,option_key,option_value,0); char option_key2[]="max_delay"; char option_value2[]="100";
          av_dict_set(&avdic,option_key2,option_value2,0); if (avformat_open_input(&pFormatCtx, m_strFileName.toLocal8Bit().data(), nullptr, &avdic) != 0)
          { printf("can't open the file. \n"); return;
          } if (avformat_find_stream_info(pFormatCtx, nullptr) < 0)
          { printf("Could't find stream infomation.\n"); return;
          } //查找視頻中包含的流信息,音頻流先不處理 int videoStreamIdx = -1;
          qDebug("apFormatCtx->nb_streams:%d", pFormatCtx->nb_streams); for (int i = 0; i < pFormatCtx->nb_streams; i++)
          { if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
              {
                  videoStreamIdx = i; //視頻流 }
          } if (videoStreamIdx == -1)
          { printf("Didn't find a video stream.\n"); //沒有找到視頻流 return;
          } //查找解碼器 qDebug("avcodec_find_decoder...");
          pCodecCtx = pFormatCtx->streams[videoStreamIdx]->codec;
          pCodec = avcodec_find_decoder(pCodecCtx->codec_id); if (pCodec == nullptr)
          { printf("Codec not found.\n"); return;
          }
          pCodecCtx->bit_rate =0; //初始化為0 pCodecCtx->time_base.num=1; //下面兩行:一秒鐘25幀 pCodecCtx->time_base.den=10;
          pCodecCtx->frame_number=1; //每包一個視頻幀 //打開解碼器 if (avcodec_open2(pCodecCtx, pCodec, nullptr) < 0)
          { printf("Could not open codec.\n"); return;
          } //將解碼后的YUV數(shù)據(jù)轉(zhuǎn)換成RGB32 pImgConvertCtx = sws_getContext(pCodecCtx->width, pCodecCtx->height,
                                           pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height,
                                           AV_PIX_FMT_RGB32, SWS_BICUBIC, nullptr, nullptr, nullptr); int numBytes = avpicture_get_size(AV_PIX_FMT_RGB32, pCodecCtx->width,pCodecCtx->height);
      
          pFrame     = av_frame_alloc();
          pFrameRGB  = av_frame_alloc();
          pOutBuffer = (uint8_t *) av_malloc(numBytes * sizeof(uint8_t));
          avpicture_fill((AVPicture *) pFrameRGB, pOutBuffer, AV_PIX_FMT_RGB32, pCodecCtx->width, pCodecCtx->height);
      
          pPacket = (AVPacket *) malloc(sizeof(AVPacket)); //分配一個packet int y_size = pCodecCtx->width * pCodecCtx->height;
          av_new_packet(pPacket, y_size); //分配packet的數(shù)據(jù) while (1)
          { if (av_read_frame(pFormatCtx, pPacket) < 0)
              { break; //這里認(rèn)為視頻讀取完了 } if (pPacket->stream_index == videoStreamIdx)
              { int got_picture; int ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture,pPacket); if (ret < 0)
                  { printf("decode error.\n"); return;
                  } if (got_picture)
                  {
                      sws_scale(pImgConvertCtx, (uint8_t const * const *) pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize); //把這個RGB數(shù)據(jù) 用QImage加載 QImage tmpImg((uchar *)pOutBuffer, pCodecCtx->width, pCodecCtx->height, QImage::Format_RGB32);
                      QImage image = tmpImg.copy(); //把圖像復(fù)制一份 傳遞給界面顯示 emit sig_GetOneFrame(image); //發(fā)送信號 }
              }
              av_free_packet(pPacket); //msleep(0.02); }
      
          av_free(pOutBuffer);
          av_free(pFrameRGB);
          avcodec_close(pCodecCtx);
          avformat_close_input(&pFormatCtx);
      }

      解碼出一幀圖像后,發(fā)送信號給圖像顯示線程顯示

      2.3 視頻顯示

      這里是圖像顯示的處理:

      void MainWindow::slotGetOneFrame(QImage img) {
          ui->labelCenter->clear(); if(m_kPlayState == RPS_PAUSE)
          { return;
          }
      
          m_Image = img;
          update(); //調(diào)用update將執(zhí)行paintEvent函數(shù) } void MainWindow::paintEvent(QPaintEvent *event) { QPainter painter(this); int showWidth = this->width() - 100; int showHeight = this->height() - 50;
      
          painter.setBrush(Qt::white);
          painter.drawRect(0, 0, this->width(), this->height()); //先畫成白色 if (m_Image.size().width() <= 0)
          { return;
          } //將圖像按比例縮放 QImage img = m_Image.scaled(QSize(showWidth, showHeight),Qt::KeepAspectRatio);
          img = img.mirrored(m_bHFlip, m_bVFlip); int x = this->width() - img.width(); int y = this->height() - img.height();
          x /= 2;
          y /= 2;
      
          painter.drawImage(QPoint(x-40,y+20),img); //畫出圖像 }

      2.4 按鍵操作處理

      客戶端界面中,有啟動、暫停播放和視頻畫面翻轉(zhuǎn)按鈕,對應(yīng)的處理邏輯如下:

      void MainWindow::on_pushButton_toggled(bool checked) { if (checked) //第一次按下為啟動,后續(xù)則為繼續(xù) { if(m_kPlayState == RPS_IDLE)
              {
                  ui->lineEditUrl->setEnabled(false);
                  m_strUrl = ui->lineEditUrl->text();
                  m_pPlayer->startPlay(m_strUrl);
      
                  ui->labelCenter->setText("rtsp網(wǎng)絡(luò)連接中...");
              }
              m_kPlayState = RPS_RUNNING;
              ui->pushButton->setText("暫停");
          } else {
              m_kPlayState = RPS_PAUSE;
              ui->pushButton->setText("播放");
          }
      } void MainWindow::on_checkBoxVFlip_clicked(bool checked) {
          m_bVFlip = checked;
      } void MainWindow::on_checkBoxHFlip_clicked(bool checked) {
          m_bHFlip = checked;
      }

      2.5 pro文件

      因為要用到FFmpeg庫,因此需要注意以下對FFmpeg庫的引用,需要修改Qt工程的pro文件

      QT       += core gui
      
      greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
      
      TARGET = rtspPlayer
      TEMPLATE = app
      
      SOURCES += main.cpp \
          videoplayer.cpp \
          mainwindow.cpp
      
      HEADERS  += \
          videoplayer.h \
          mainwindow.h
      
      FORMS    += \
          mainwindow.ui
      
      INCLUDEPATH+=$$PWD/ffmpeg/include
      
      LIBS += $$PWD/ffmpeg/lib/x64/avcodec.lib \
              $$PWD/ffmpeg/lib/x64/avdevice.lib \
              $$PWD/ffmpeg/lib/x64/avfilter.lib \
              $$PWD/ffmpeg/lib/x64/avformat.lib \
              $$PWD/ffmpeg/lib/x64/avutil.lib \
              $$PWD/ffmpeg/lib/x64/postproc.lib \
              $$PWD/ffmpeg/lib/x64/swresample.lib \
              $$PWD/ffmpeg/lib/x64/swscale.lib

      3 運(yùn)行測試

      3.1 Win平臺測試

      在Win10平臺上測試效果如下:

      3.2 嵌入式Linux平臺測試

      在嵌入式Linux平臺運(yùn)行,也需要先進(jìn)行FFmpeg運(yùn)行環(huán)境的搭建,上篇文章已介紹如何交叉編譯FFmpeg源碼以及在嵌入式Linux平臺搭建FFmpeg運(yùn)行環(huán)境。

      3.2.1 需要安裝4.4版本的庫

      由于不同版本FFmpeg的API函數(shù)有些差別,上篇使用的是較新版本的FFmpeg源碼,與4.4版本的可能不太一樣,因此,需要參考上篇文章,重新在嵌入式Linux環(huán)境中安裝4.4版本的FFmpeg。

      4.4版本的源碼可從如下鏈接下載:https://ffmpeg.org/download.html

      3.2.2 修改pro文件

      然后就是將Qt程序拷貝到Ubuntu中進(jìn)行交叉編譯,在編譯之前,還要修改pro文件,使程序能夠鏈接到linux版本的FFmpeg庫,具體的修改如下,主要路徑要修改為自己的ffmpeg庫的安裝位置。

      INCLUDEPATH+=$$PWD/../ffmpeg442_install/include \
                   $$PWD/../x264_install/include
      
      LIBS += $$PWD/../ffmpeg442_install/lib/libavcodec.so \
              $$PWD/../ffmpeg442_install/lib/libavdevice.so \
              $$PWD/../ffmpeg442_install/lib/libavfilter.so \
              $$PWD/../ffmpeg442_install/lib/libavformat.so \
              $$PWD/../ffmpeg442_install/lib/libavutil.so \
              $$PWD/../ffmpeg442_install/lib/libpostproc.so \
              $$PWD/../ffmpeg442_install/lib/libswresample.so \
              $$PWD/../ffmpeg442_install/lib/libswscale.so \
      		$$PWD/../x264_install/lib/libx264.so

      3.3 演示視頻

      4 總結(jié)

      本篇介紹了通過Qt程序,設(shè)計一個RTSP視頻播放器,運(yùn)行在嵌入式Linux平臺上,來播放網(wǎng)絡(luò)視頻,并增加啟動、暫停、畫面翻轉(zhuǎn)等操作按鈕。

      本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點,本站亦不保證或承諾內(nèi)容真實性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時聯(lián)系本站刪除。
      換一批
      延伸閱讀

      LED驅(qū)動電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

      關(guān)鍵字: 驅(qū)動電源

      在工業(yè)自動化蓬勃發(fā)展的當(dāng)下,工業(yè)電機(jī)作為核心動力設(shè)備,其驅(qū)動電源的性能直接關(guān)系到整個系統(tǒng)的穩(wěn)定性和可靠性。其中,反電動勢抑制與過流保護(hù)是驅(qū)動電源設(shè)計中至關(guān)重要的兩個環(huán)節(jié),集成化方案的設(shè)計成為提升電機(jī)驅(qū)動性能的關(guān)鍵。

      關(guān)鍵字: 工業(yè)電機(jī) 驅(qū)動電源

      LED 驅(qū)動電源作為 LED 照明系統(tǒng)的 “心臟”,其穩(wěn)定性直接決定了整個照明設(shè)備的使用壽命。然而,在實際應(yīng)用中,LED 驅(qū)動電源易損壞的問題卻十分常見,不僅增加了維護(hù)成本,還影響了用戶體驗。要解決這一問題,需從設(shè)計、生...

      關(guān)鍵字: 驅(qū)動電源 照明系統(tǒng) 散熱

      根據(jù)LED驅(qū)動電源的公式,電感內(nèi)電流波動大小和電感值成反比,輸出紋波和輸出電容值成反比。所以加大電感值和輸出電容值可以減小紋波。

      關(guān)鍵字: LED 設(shè)計 驅(qū)動電源

      電動汽車(EV)作為新能源汽車的重要代表,正逐漸成為全球汽車產(chǎn)業(yè)的重要發(fā)展方向。電動汽車的核心技術(shù)之一是電機(jī)驅(qū)動控制系統(tǒng),而絕緣柵雙極型晶體管(IGBT)作為電機(jī)驅(qū)動系統(tǒng)中的關(guān)鍵元件,其性能直接影響到電動汽車的動力性能和...

      關(guān)鍵字: 電動汽車 新能源 驅(qū)動電源

      在現(xiàn)代城市建設(shè)中,街道及停車場照明作為基礎(chǔ)設(shè)施的重要組成部分,其質(zhì)量和效率直接關(guān)系到城市的公共安全、居民生活質(zhì)量和能源利用效率。隨著科技的進(jìn)步,高亮度白光發(fā)光二極管(LED)因其獨特的優(yōu)勢逐漸取代傳統(tǒng)光源,成為大功率區(qū)域...

      關(guān)鍵字: 發(fā)光二極管 驅(qū)動電源 LED

      LED通用照明設(shè)計工程師會遇到許多挑戰(zhàn),如功率密度、功率因數(shù)校正(PFC)、空間受限和可靠性等。

      關(guān)鍵字: LED 驅(qū)動電源 功率因數(shù)校正

      在LED照明技術(shù)日益普及的今天,LED驅(qū)動電源的電磁干擾(EMI)問題成為了一個不可忽視的挑戰(zhàn)。電磁干擾不僅會影響LED燈具的正常工作,還可能對周圍電子設(shè)備造成不利影響,甚至引發(fā)系統(tǒng)故障。因此,采取有效的硬件措施來解決L...

      關(guān)鍵字: LED照明技術(shù) 電磁干擾 驅(qū)動電源

      開關(guān)電源具有效率高的特性,而且開關(guān)電源的變壓器體積比串聯(lián)穩(wěn)壓型電源的要小得多,電源電路比較整潔,整機(jī)重量也有所下降,所以,現(xiàn)在的LED驅(qū)動電源

      關(guān)鍵字: LED 驅(qū)動電源 開關(guān)電源

      LED驅(qū)動電源是把電源供應(yīng)轉(zhuǎn)換為特定的電壓電流以驅(qū)動LED發(fā)光的電壓轉(zhuǎn)換器,通常情況下:LED驅(qū)動電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

      關(guān)鍵字: LED 隧道燈 驅(qū)動電源
      關(guān)閉