国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

FFmpeg之視頻解碼

這篇具有很好參考價值的文章主要介紹了FFmpeg之視頻解碼。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

FFmpeg之視頻解碼

第一次寫CSDN,先熟悉熟悉FFmpeg

常用結(jié)構(gòu)體

1. AVFormatContext;   //為封裝上下文;
2. AVCodecContext;    //為解碼器上下文;
3. AVStream;				//為存放的是各種流,如:音頻流,視頻流,字母等;
4. SwsContext;           //為轉(zhuǎn)換上下文,主要用于將原始數(shù)據(jù)轉(zhuǎn)換成目標(biāo)格式的數(shù)據(jù);如:YUV或RGB;
5. AVCodec;      			//為解碼器;
6. AVpacket;      			//為數(shù)據(jù)包,用于將編碼數(shù)據(jù)發(fā)送給解碼器的;
7. AVFrame;				//存放一般存放解碼后的數(shù)據(jù);

常用方法函數(shù)

1. av_register_all();  
2. avformat_open_input();  
3. av_find_best_stream( ); 	//找到最你指定的那個流的序號;
4. avformat_find_stream_info( );  //該函數(shù)主要用于給每個媒體流(音頻/視頻)的AVStream結(jié)構(gòu)體賦值
5. avcodec_find_decoder(); //找到音頻或視頻流對應(yīng)的編碼格式的解碼器;
6. avcodec_parameters_to_context();  //將解碼器參數(shù)輔導(dǎo)解碼器上下文中
7. avcodec_open2();   //打開解碼器;
8. sws_getContext();  //設(shè)置原始數(shù)據(jù)(YUV)轉(zhuǎn)換成其他格式( RGB )的轉(zhuǎn)換上下文,并返回?fù)Q上下文。
9. av_read_frame();  //視頻是一幀的,音頻可以是多幀。
10. avcodec_decode_video2(); //對視頻解碼
11. sws_scale();   //將一幀原始數(shù)據(jù)(YUV)轉(zhuǎn)換成我們指定格式 (RGB )。

視頻解碼的一些基礎(chǔ)知識:

  1. 視頻流是按一定的順序排列 I 幀,P 幀 和 B 幀的。

     1. I 幀:為關(guān)鍵幀,它為幀內(nèi)壓縮,解碼后為一個完整的畫面,這是解碼的關(guān)鍵;
     2. P 幀:為前向預(yù)測幀,它自己解碼是無法完成一幀畫面,它的解碼需要依賴上一次解碼的 I 幀(或P幀);
     3. B 幀:為雙向預(yù)測內(nèi)插編碼幀,它以前面的I或P幀和后面的P幀為參考幀。
    

? 因此,重要性:I 幀 > P 幀 > B 幀。由于不同類型的幀的重要性不同,這意味著我們要按播放連貫的視頻,就必須按照一定規(guī)定來顯示這些幀,這就引來了兩個時間概念:解碼時間戳(DTS)和顯示時間戳(PTS)。
? 音頻同步的時候,也是以顯示時間戳為標(biāo)準(zhǔn)的。

  1. 視頻格式(AVPixelFormat)

     	AV_PIX_FMT_YUV420P,
     	AV_PIX_FMT_YUYV422,
     	AV_PIX_FMT_RGB24,
     	AV_PIX_FMT_RGBA,
        AV_PIX_FMT_NONE = -1,
        AV_PIX_FMT_YUV420P,   
        AV_PIX_FMT_YUYV422,  
        AV_PIX_FMT_RGB24,     
        AV_PIX_FMT_BGR24,     
        AV_PIX_FMT_YUV422P, 
        ……  //格式還有很多種,這里不在敘述。
    

代碼示例,Qt Creator中運行

	主要思想:用主線程顯示視頻(即widget.h和.cpp),用MyFFmpeg線程來實現(xiàn)文件的解碼;

FFmpeg之視頻解碼

widget.h

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
    void init_MyFFmpeg();
    void paintEvent(QPaintEvent* e);

private:
    MyFFmpeg *myFFmpeg;
     QPixmap pix;

private:
    Ui::Widget *ui;
};

widget.cpp

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    myFFmpeg=new MyFFmpeg();
	//收到myFFmpeg線程對象發(fā)來的圖片,就繪到widget上
    connect(myFFmpeg,&MyFFmpeg::emitImage,[=](QImage image,int time){
        pix = QPixmap::fromImage(image,Qt::AutoColor);
        qDebug()<<"time:"<<time;
        update(); //更新paintEvent時間
    });
    //啟動線程
    myFFmpeg->start();
}

Widget::~Widget(){
    delete ui;
}

void Widget::paintEvent(QPaintEvent* e){
   QPainter painter(this);
   pix.scaled(this->size(),Qt::IgnoreAspectRatio);
   int x = this->width() - pix.width();
   int y = this->height() - pix.height();
   painter.drawPixmap(QPoint(x,y),pix);
}

MyFFmpeg.h文件

 class MyFFmpeg: public QThread
{
    Q_OBJECT
public:
    MyFFmpeg();
    ~MyFFmpeg();
    void  run() override;
    void init_MyFFmpeg();

signals:
	void emitImage(QImage image);
    
private:
    //ffmpeg相關(guān)變量預(yù)先定義與分配
        AVFormatContext *m_pAVFormatCtx;    //解封裝上下文
        SwsContext  *m_pSwsCtx;             //視頻轉(zhuǎn)碼上下文
        AVCodecContext *avCodecCtx;         //解碼上下文

        AVFrame *m_pAVFrame = 0;            // 解碼后的原始數(shù)據(jù)Frame
        AVFrame *m_pAVFrameRGB32 = 0;       // 轉(zhuǎn)換后的目標(biāo)格式Frame
        AVPacket *m_pAVPacket = 0;          // ffmpag單幀數(shù)據(jù)包

        int gotPicture = 0;          // 解碼時數(shù)據(jù)是否解碼成功
        int outBuffer_size = 0;            // 解碼后的數(shù)據(jù)長度
        uchar *outBuffer = 0;        // 解碼后的數(shù)據(jù)存放緩存區(qū)
        char m_errorBuff[1024];      //打開時發(fā)生的錯誤信息

        int m_totalMs;               //總時長
        int m_videoStreamId;           //視頻流
      
        int m_fps;                   //每秒的視頻幀數(shù)
        int m_pts;                   //獲得當(dāng)前解碼幀的時間

     
};

MyFFmpeg.cpp文件

MyFFmpeg::MyFFmpeg()
{
	init_MyFFmpeg();
	av_register_all(); 	 
}

void MyFFmpeg::run(){
	   const char* pathUrl="mmm.mkv";
         //打開文件,解封裝
         int ret = avformat_open_input(&m_pAVFormatCtx,pathUrl,NULL,NULL);
         if(ret!=0){
             av_strerror(ret,m_errorBuff,sizeof(m_errorBuff));
             qDebug()<<"Open failed: "<<m_errorBuff;
             exit(0);
         }
         m_totalMs = m_pAVFormatCtx->duration / (AV_TIME_BASE);  //獲取視頻的總時間
         
         //尋找視頻流序號
         //  m_videoStreamId = av_find_best_stream(m_pAVFormatCtx,AVMEDIA_TYPE_VIDEO,-1,-1,NULL,0);
         m_videoStreamId = -1;
         for(int i=0;i<m_pAVFormatCtx->nb_streams;i++)
         {
             if(m_pAVFormatCtx->streams[i]->codecpar->codec_type==AVMEDIA_TYPE_VIDEO)
             {
                 m_videoStreamId=i;
                 break;
             }
         }
         if(m_videoStreamId ==-1){
             qDebug()<<"can not find videoStream";
             exit(0);
         }
         
		 //尋找解碼器
         AVCodec *avCodec = avcodec_find_decoder( m_pAVFormatCtx->streams[m_videoStreamId]->codecpar->codec_id);
         //avCodecCtx = avcodec_alloc_context3(avCodec);
         avCodecCtx=m_pAVFormatCtx->streams[m_videoStreamId]->codec;
		//打開編碼器
         if(avcodec_open2(avCodecCtx,avCodec,NULL)<0){
             qDebug()<<"can not open codec";
             exit(0);
         }
         
		//進行格式轉(zhuǎn)換上下文設(shè)置,一般的pix_fmt都是AV_PIX_FMT_YUV420P 
		 avCodecCtx->pix_fmt=AV_PIX_FMT_YUV420P;  //這里我們手動給pix_fmt賦值A(chǔ)V_PIX_FMT_YUV420P, 
		 										 // 如果不賦值,下面sws_getContext就會崩掉,因為沒有這句話 pix_fmt=-1;
         m_pSwsCtx = sws_getContext(avCodecCtx->width, avCodecCtx->height, avCodecCtx->pix_fmt,
                                   avCodecCtx->width, avCodecCtx->height, AV_PIX_FMT_RGBA, SWS_FAST_BILINEAR,
                                   NULL, NULL, NULL);
		 outBuffer_size = av_image_get_buffer_size(AV_PIX_FMT_RGBA, avCodecCtx->width, avCodecCtx->height,1);
         outBuffer=(unsigned char*)malloc(outBuffer_size);
         
  		//將m_pAVFrameRGB32賦值, 并將m_pAVFrameRGB32的data變量指向outBuffer
         av_image_fill_arrays(m_pAVFrameRGB32->data,m_pAVFrameRGB32->linesize, outBuffer,
                             AV_PIX_FMT_RGBA, avCodecCtx->width, avCodecCtx->height, 1);
		 
		 //開始逐幀解碼視頻和音頻,這里我們之解碼視頻
         while(av_read_frame(m_pAVFormatCtx, m_pAVPacket)>=0)
         {
             //找到視頻流
             if(m_pAVPacket->stream_index==m_videoStreamId){
                 if(avcodec_decode_video2(avCodecCtx, m_pAVFrame, &gotPicture, m_pAVPacket)<0){
                     qDebug()<<"解碼視頻失敗";
                     exit(0);
                 }
                 if(gotPicture){
                 //對原始數(shù)據(jù)進行格式轉(zhuǎn)化
                 sws_scale(m_pSwsCtx, (const uint8_t* const *)m_pAVFrame->data, m_pAVFrame->linesize,0,
                             avCodecCtx->height, m_pAVFrameRGB32->data, m_pAVFrameRGB32->linesize);
                             
                 //接下來就是將m_pAVFrameRGB32上的數(shù)據(jù)在設(shè)備上顯示出來。
                 QImage imageshow(*m_pAVFrameRGB32->data, avCodecCtx->width, avCodecCtx->height,
                                 QImage::Format_RGB32);
                  //顯示當(dāng)前幀的時間,并轉(zhuǎn)化成秒
                  m_dts=m_pAVFrame->pts * av_q2d(m_pAVFormatCtx->streams[m_videoStreamId]->time_base);
                  //將線程中解碼好的圖片和顯示時間發(fā)送到主線程中
                  emitImage(imageshow, m_dts);
                  QThread::msleep(30);//延時使得畫面播放流暢
               }

             }
              av_packet_unref(m_pAVPacket); //引用計數(shù)減1;
         }
	//正常來講這里是要執(zhí)行下面著幾句話的,但是釋放內(nèi)存的,這個線程就會出現(xiàn)沖突,所以我們將這些話放在了析構(gòu)函數(shù)中
	 //avformat_free_context(m_pAVFormatCtx);
     //avcodec_free_context(&avCodecCtx);
     //av_frame_free(&m_pAVFrame);
     //av_frame_free(&m_pAVFrameRGB32);
     //av_packet_free(&m_pAVPacket);
     //qDebug()<<"音頻解碼結(jié)束";
}

MyFFmpeg::~MyFFmpeg()
{ //釋放內(nèi)存
     avformat_free_context(m_pAVFormatCtx);
     avcodec_free_context(&avCodecCtx);
     av_frame_free(&m_pAVFrame);
     av_frame_free(&m_pAVFrameRGB32);
     av_packet_free(&m_pAVPacket);
     qDebug()<<"音頻解碼結(jié)束";
}

void MyFFmpeg::init_MyFFmpeg()
{
	m_pAVFormatCtx = avformat_alloc_context();	 
    m_pAVFrame = av_frame_alloc();
    m_pAVPacket = av_packet_alloc();
    m_pAVFrameRGB32 = av_frame_alloc();    
}    
//

總結(jié)一下,這里也才了一個坑,就是
FFmpeg之視頻解碼
問題就是sws_getContext()中, avCodecCtx->pix_fmt=-1,導(dǎo)致系統(tǒng)崩潰,文章來源地址http://www.zghlxwxcb.cn/news/detail-405302.html

avCodecCtx->pix_fmt=AV_PIX_FMT_YUV420P;  //必需在這里可以賦值 AV_PIX_FMT_YUV420P
 m_pSwsCtx = sws_getContext(avCodecCtx->width, avCodecCtx->height, avCodecCtx->pix_fmt,
                                   avCodecCtx->width, avCodecCtx->height, AV_PIX_FMT_RGBA, SWS_FAST_BILINEAR,
                                   NULL, NULL, NULL);
	第一次寫博客,參考了別人的一些經(jīng)驗,然后自己整理加自己的理解,主要是給自己記筆記,當(dāng)然也供小伙伴們參考,如果有錯誤,請諒解!??!

到了這里,關(guān)于FFmpeg之視頻解碼的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • python 第一次作業(yè)

    python 第一次作業(yè)

    因為筆者有一些 c/c++ 語言的基礎(chǔ),所以應(yīng)該學(xué) python 會稍微簡單一些 輸入的時候所有的輸入都是字符串類型,我們需要進行類型轉(zhuǎn)換 參見資源里面的第三題和第四題,為了方便起見,直接把代碼貼在下面

    2024年03月25日
    瀏覽(22)
  • shell第一次作業(yè)

    shell第一次作業(yè)

    1、判斷當(dāng)前磁盤剩余空間是否有20G,如果小于20G,則將報警郵件發(fā)送給管理員,每天檢查次磁盤剩余空間。 2、判斷web服務(wù)是否運行 ? ?1、查看進程的方式判斷該程序是否運行, ? ?2、通過查看端口的方式判斷該程序是否運行,如果沒有運行,則啟動該服務(wù)并配置防火墻規(guī)

    2024年02月09日
    瀏覽(24)
  • 第一次作業(yè)

    第一次作業(yè)

    作業(yè)內(nèi)容:1,atd和crond的區(qū)別 ? ? ? ? ? ? ? ? ? 2,指定在2023/08/26 09:00將時間寫入testmail.txt文件中 ? ? ? ? ? ? ? ? ? 3,指定在每天凌晨4:00將該時間點之前的系統(tǒng)日志信息備份到個目錄下(/var/log/messages ),備份后日志文件名顯示格式logfileYY-MM-DD HH-MM 1、運行方式不同

    2023年04月20日
    瀏覽(21)
  • 第一次博客作業(yè)

    第一次博客作業(yè)

    這學(xué)期才開始接觸Java,之前只學(xué)了C語言,所以一開始寫題目的代碼的時候?qū)ava的眾多函數(shù)和語法不是太熟悉,一開始就上手寫代碼有點不適應(yīng)。 ?? 關(guān)于類: 1、類似C中的struct,構(gòu)造函數(shù)、內(nèi)置方法(函數(shù) )都比較相似 2、盡量避免代碼的重復(fù),把private和public的方法搞清晰。

    2024年02月08日
    瀏覽(24)
  • jQuery第一次接觸

    jQuery是一個輕量級js庫 1.下載jquery庫,網(wǎng)址Download jQuery | jQuery npm i jquery 2.還可以從cdn中載入jquery script src=\\\"https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js\\\" 3.j代表js,query代表查詢,jQuery可以進行查詢的js語言,主要用來查詢html元素 4.基礎(chǔ)語法$(selector).action(),其中selector代表要進行操

    2024年02月12日
    瀏覽(31)
  • 數(shù)據(jù)庫第一次作業(yè)

    數(shù)據(jù)庫第一次作業(yè)

    1.創(chuàng)建一個英雄表 create table t_hero ( ? ? ?id int primary key auto_increment, ? ? ?name varchar(10) unique not null, ? ? ?gender char(5) check (gender in (\\\'男\(zhòng)\\',\\\'女\\\')), ? ? ?grade char(5) default \\\'5星\\\', ? ? ?`groups` char(5) check (`groups` in (\\\'毀滅\\\',\\\'巡獵\\\',\\\'智識\\\',\\\'存護\\\',\\\'虛無\\\',\\\'豐饒\\\')), ? ? ?tel char(11) ? default \\\'

    2024年01月18日
    瀏覽(66)
  • git教程(第一次使用)

    git教程(第一次使用)

    下載地址 windows:https://gitforwindows.org/ mac:http://sourceforge.net/projects/git-osx-installer/ (1)配置用戶信息 –global 是指所有倉庫都是用這個用戶信息配置 (2)查看配置信息 輸出如下所示: 解決合并沖突時使用哪種差異分析工具,改用vimdiff (3)配置免密碼訪問gitee倉庫 連續(xù)按三

    2024年02月14日
    瀏覽(30)
  • 網(wǎng)絡(luò)安全第一次作業(yè)

    網(wǎng)絡(luò)安全第一次作業(yè)

    1、什么是防火墻 防火墻是一種網(wǎng)絡(luò)安全系統(tǒng),它根據(jù)預(yù)先確定的安全規(guī)則監(jiān)視和控制傳入和傳出的網(wǎng)絡(luò)流量。其主要目的是阻止對計算機或網(wǎng)絡(luò)的未經(jīng)授權(quán)的訪問,同時允許合法通信通過。 防火墻可以在硬件、軟件或兩者的組合中實現(xiàn),并且可以配置為根據(jù)各種條件(如

    2024年02月07日
    瀏覽(38)
  • Java第一次blog

    Java第一次blog

    7-1 答題判題程序-1 這些題目主要用到 對象與類的處理: 對象是現(xiàn)實世界或抽象概念中的實體在計算機程序中的表示。 類則是具有相同屬性和方法的對象的集合,是創(chuàng)建對象的模板。通過類,我們可以定義一類對象的共同特征和行為。 1. 字符串處理: 需要對輸入的題目信息

    2024年04月22日
    瀏覽(17)
  • 第一次樣式異常之后正常

    第一次樣式異常之后正常

    ? ?解決方法 : 添加一個 :key=\\\"Math.random()\\\" ?

    2023年04月15日
    瀏覽(27)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包