首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

使用 FFmpeg 庫分離多媒體檔案中的 H.264 視頻碼流

     編輯:關於C語言

前言

延續音頻碼流分離的主題,本文聚焦於 H.264 視頻碼流的提取。同樣基於 av_read_frame() 獲取 AVPacket,但 H.264 在 FLV、MP4 等容器中的封裝特性導致直接存儲無法播放,需經過兩步關鍵處理:補全 SPS/PPS 並轉換為 Annex B 格式(起始碼 0x00000001)。

容器格式對 H.264 分離的影響

  • MPEG2 / TS 容器:直接存儲 AVPacket 可播放,因 TS 封裝已包含起始碼或 PES 頭。
  • FLV、MP4 容器:直接存儲不可播放。這兩類容器屬於「特殊容器」,採用「長度前綴」而非「起始碼」分隔 NALU。

關鍵步驟一:提取並寫入 SPS/PPS(序列/圖像參數集)

H.264 解碼器初始化需要 SPS 與 PPS,它們存儲在 AVCodecContext->extradata 中。但在 FLV/MP4 中,extradata 格式為 AVCC(長度前綴),需轉換為 Annex B 格式(起始碼分隔)才能被標準解碼器識別。

FFmpeg 提供了 h264_mp4toannexb Bitstream Filter(BSF)專門完成此轉換。核心代碼邏輯如下:

// 初始化 BSF 上下文
AVBitStreamFilterContext* bsfc = av_bitstream_filter_init("h264_mp4toannexb");

// 執行轉換:輸入 extradata,輸出帶起始碼的 SPS/PPS 數據
unsigned char *dummy = NULL;
int dummy_len = 0;
av_bitstream_filter_filter(bsfc, 
    fmt_ctx->streams[video_stream_index]->codec, 
    NULL, 
    &dummy, &dummy_len, 
    NULL, 0, 0);

// 寫入文件(已包含起始碼的 SPS/PPS)
fwrite(fmt_ctx->streams[video_stream_index]->codec->extradata,
       fmt_ctx->streams[video_stream_index]->codec->extradata_size, 1, fp);

av_bitstream_filter_close(bsfc);
free(dummy);

關鍵步驟二:將 AVPacket 轉為標準 NALU 格式(替換長度前綴為起始碼)

分析 FLV/MP4 中的 AVPacket->data 發現:前 4 字節為 NALU 長度(大端序),第 5 字節起才是真正的 NALU 數據(不含起始碼)。標準 H.264 碼流要求每個 NALU 以 0x00 0x00 0x00 0x01 起始。

處理邏輯極簡單:

char nal_start[] = {0, 0, 0, 1};
fwrite(nal_start, 4, 1, fp);           // 寫入起始碼
fwrite(pkt->data + 4, pkt->size - 4, 1, fp); // 跳過長度字段,寫入 NALU 本體

完整處理流程圖解

  1. 打開輸入文件,找到視頻流索引
  2. 初始化 h264_mp4toannexb BSF
  3. 寫入經 BSF 轉換後的 extradata(含 SPS/PPS + 起始碼)
  4. 循環調用 av_read_frame() 獲取視頻幀
  5. 每幀:寫入起始碼 + pkt->data+4(去除長度前綴)
  6. 釋放資源,關閉文件

常見坑點提示

  • 舊版 FFmpeg 使用 av_bitstream_filter_filter,新版(4.0+)建議改用 av_bsf_send_packet/av_bsf_receive_packet API。
  • 若輸入本身就是 Annex B 格式(如 .h264、.ts),不可再次應用 BSF,否則會導致起始碼重複。
  • 需正確處理 AVPacket 的引用計數(av_packet_ref/av_packet_unref),避免內存洩漏。

本文轉載自 “leixiaohua1020視音頻技術” 博客,原文地址:https://leixiaohua1020.blog.51cto.com/3974648/1303852

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved