91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

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

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

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

广昌县| 肇东市| 中宁县| 辉县市| 楚雄市| 阿荣旗| 寿阳县| 南皮县| 中宁县| 齐河县| 上犹县| 健康| 南溪县| 德阳市| 上高县| 延吉市| 潍坊市| 灵台县| 砀山县| 鹤庆县| 邢台市| 延津县| 峨眉山市| 砚山县| 甘孜| 青冈县| 资源县| 唐山市| 辽阳市| 沭阳县| 五常市| 肥东县| 南康市| 榆树市| 棋牌| 新和县| 景泰县| 芜湖市| 永平县| 阜南县| 唐山市|