中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

FFMPEG Tips (3) 如何讀取每一幀的信息

發布時間:2020-07-12 11:33:32 來源:網絡 閱讀:14336 作者:Jhuster 欄目:開發技術

本文是我的《FFMPEG Tips》系列的第三篇文章,上篇文章 介紹了如何提取整個音視頻碼流的媒體信息,包括:封裝格式、編碼格式、視頻的分辨率、幀率、碼率、音頻的采樣率、位寬、通道數等等,而本文則關注得更細一點,看看如何利用 ffmpeg 讀取碼流中每一幀的信息。


1.  碼流中每一幀的哪些信息值得關注 ?


[ ]  音頻幀還是視頻幀

[ ]  關鍵幀還是非關鍵幀

[ ]  幀的數據和大小

[ ]  時間戳信息


2.  為什么要關注這些信息 ?


[ ]  音頻幀還是視頻幀 -> 分別送入音頻/視頻×××

[ ]  關鍵幀還是非關鍵幀 -> 追幀優化

[ ]  幀的數據和大小 -> 取出幀的內容

[ ]  時間戳信息 -> 音視頻同步


3. 如何從 ffmpeg 取出這些信息 ?


ffmpeg 提供了一個函數 av_read_frame 來完成解封裝的過程,它會從碼流里面提取每一個音頻、視頻幀,它使用了結構體 AVPacket 來記錄每一幀的信息。


讀取一幀數據的代碼示例如下(ic 即為 AVFormatContext 對象,碼流的上下文句柄):


AVPacket avpkt;
av_init_packet(&avpkt);

while (!interrupt) {
    int ret = av_read_frame(ic, &avpkt);
    if (ret < 0) {
        break;
    }
    // processing
}

av_free_packet(&avpkt);


每循環一次,就從碼流中解封裝并且提取了一幀數據,并存放在了 AVPacket 結構體中。


3.1 如何判斷是音頻幀還是視頻幀


上一篇文章我們提到過,使用下面的方法,獲取碼流中的 video_stream_idx 和 audio_stream_idx


int video_stream_idx = av_find_best_stream(ic, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);

int audio_stream_idx = av_find_best_stream(ic, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);


那么,此時就派上用場了,每一個 AVPacket 都有一個成員變量:stream_index,由該成員變量即可判斷這個 Packet 到底是音頻還是視頻了:


if (avpkt.stream_index == video_stream_idx) {
    LOGD("read a video frame");
} else if (avpkt.stream_index == audio_stream_idx) {
    LOGD("read audio frame);
}


3.2 如何判斷是否為關鍵幀


判斷是否為關鍵幀的方法也比較簡單,示例如下:


if (avpkt.flags & AV_PKT_FLAG_KEY) {
    LOGD("read a key frame");
}


3.3 如何獲取幀的數據和大小


幀的數據和大小直接定義在 AVPacket 結構體中,對應的成員變量如下:


// 壓縮編碼的數據,一幀音頻/視頻
uint8_t *data;

// 數據的大小
int size;


3.4 如何獲取幀的時間戳信息


每一個幀都可能攜帶有 2 個時間戳信息,一個是解碼時間戳 dts,一個是顯示時間戳 pts,解碼時間戳告訴我們什么時候需要解碼,顯示時間戳告訴我們什么時候需要顯示,只有在碼流中存在 B 幀的情況下,這兩個時間戳才會不一致。


這些時間戳信息不一定存在于碼流中(取決于生產端),如果不存在,則其值為:AV_NOPTS_VALUE

一定要選擇正確地方式打印時間戳,時間戳是使用 long long 來表示的,即 int64_t,因此打印的時候,需要使用 “%lld” 來打印,例如:


while (!interrupt) {
    int ret = av_read_frame(player->ic, &avpkt);
    if (ret < 0) {
        break;
    }
    if (avpkt.stream_index == video_stream_idx) {
        LOGD("read video frame, timestamp = %lld \n”, avpkt.pts);
    } else if (avpkt.stream_index == audio_stream_idx) {
        LOGD("read audio frame, timestamp = %lld \n”, avpkt.pts);
    }
}


由此,我們就可以通過這些 log 信息調試一下某一段音視頻流的時間戳是否正確,比如是否出現了時間戳的回滾和錯亂,則必然會導致播放端出現音視頻不同步或者顯示異常等情況。


4. 小結


關于如何使用 FFMPEG 如何讀取每一幀的信息就介紹到這兒了,文章中有不清楚的地方歡迎留言或者來信 lujun.hust@gmail.com 交流,關注我的新浪微博 @盧_俊 或者 微信公眾號 @Jhuster 獲取最新的文章和資訊。

FFMPEG Tips (3) 如何讀取每一幀的信息

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

寿阳县| 永吉县| 栖霞市| 颍上县| 万年县| 沽源县| 临颍县| 固原市| 沾化县| 成都市| 漳州市| 紫金县| 苍溪县| 台北县| 锦州市| 将乐县| 临江市| 乐安县| 义乌市| 山阴县| 高雄县| 盐亭县| 南靖县| 平湖市| 深水埗区| 大竹县| 衡阳市| 庐江县| 阿图什市| 苍山县| 新巴尔虎左旗| 德化县| 仁寿县| 屏南县| 会理县| 北票市| 上栗县| 漳平市| 石棉县| 巴塘县| 平安县|