開發一個基於IP攝像機的實時視頻監控系統,核心流程:獲取幀數據 → FFmpeg解碼 → 格式轉換 → x264編碼 → Live555 RTP推流。技術棧涉及FFmpeg、libx264、Live555、Windows SDK,開發周期約半個月,過程坎坷但收穫巨大。
現象:引用SDK庫函數報「無法解析的外部符號」,明明已添加庫文件和頭文件。
根因:C++編譯器對函數名進行了Name Mangling,而C語言編譯的SDK導出符號未修飾。
解決:在包含C庫頭文件時包裹extern "C":
#ifdef __cplusplus
extern "C" {
#endif
#include "sdk_header.h"
#ifdef __cplusplus
}
#endif
現象:error C2664: LoadLibraryW 不能將 const char[14] 轉換為 LPCWSTR
根因:項目設置為Unicode字符集,但代碼使用窄字符串調用API。
解決:項目屬性 → 配置屬性 → 常規 → 字符集 → 改為「不使用Unicode」或統一使用TEXT()宏/L""寬字符串。
現象:FFmpeg解碼JPEG輸出為YUV422P,但x264編碼器要求YUV420P。直接使用sws_scale轉換程序崩潰。
根因:數據平面指針設置錯誤。參考代碼僅設置data[0](適用RGB24單平面),YUV422/420需設置三個平面data[0]、data[1]、data[2]及對應linesize。
正確代碼:
ctx->pic_src.data[0] = (uint8_t*)pFrame->data[0];
ctx->pic_src.data[1] = (uint8_t*)pFrame->data[1];
ctx->pic_src.data[2] = (uint8_t*)pFrame->data[2];
ctx->pic_src.data[3] = 0;
ctx->pic_src.linesize[0] = pFrame->linesize[0];
ctx->pic_src.linesize[1] = pFrame->linesize[1];
ctx->pic_src.linesize[2] = pFrame->linesize[2];
ctx->pic_src.linesize[3] = 0;
int rs = sws_scale(ctx->sws, ctx->pic_src.data, ctx->pic_src.linesize,
0, ctx->rows, ctx->pic_target.data, ctx->pic_target.linesize);
x264崩潰:同上,因輸入數據非標準YUV420導致x264_encoder_encode崩潰,修正sws_scale參數後解決。
Live555黑屏:編碼數據寫文件正常,但推流黑屏且運行一段時間崩潰。
關鍵發現:在獲取YUV420數據後過早調用av_free(pFrame)釋放幀內存,導致編碼器讀取到已釋放的內存區域。註釋掉該釋放調用後畫面正常輸出(但引入內存洩漏,每秒約1MB,後續優化)。
IP攝像機 → [獲取幀] → FFmpeg解碼(JPEG→YUV422)
→ sws_scale格式轉換(YUV422→YUV420)
→ libx264編碼(H.264)
→ Live555 RTP/RTCP推流 → 客戶端播放
AVFrame引用計數,使用av_frame_unref替代直接av_free。