《FFmpeg開發實戰:從零基礎到短視頻上線》一書的“10.2.2 FFmpeg向網絡推流”介紹瞭如何使用FFmpeg代碼向網絡推送視頻流,當時的例程採用了RTSP方式推流,在向RTSP地址時推流是正常的,但向RTMP地址推流時出現了問題,下面就介紹瞭如何使用FFmpeg代碼向RTMP地址推送視頻流。
一、FFmpeg推流環境的區別
首先注意RTSP推流地址以“ rtsp:// ”開頭,且RTSP地址的默認端口號為8554。而RTMP推流地址以“ rtmp:// ”開頭,且RTMP地址的默認端口號為1935。
其次注意FFmpeg從6.1開始對RTMP協議做了增強支持,主要是支持HEVC、VP9和AV1等編碼格式通過RTMP協議進行推流,所以建議將編譯環境的FFmpeg版本升級到6.1或者更高版本。
二、FFmpeg推流代碼的適配
FFmpeg推流代碼對於RTSP地址和RTMP地址主要有下列兩點適配區別:
1、調用avformat_alloc_output_context2函數分配音視頻文件封裝實例的時候,第三個輸入參數對於RTSP地址而言要填rtsp,對於RTMP地址而言要填flv。比如以下代碼通過判斷推流地址的協議類型來決定avformat_alloc_output_context2的第三個參數要填何值。
int ret = 0;
// 分配音視頻文件的封裝實例(注意rtmp協議的第三個參數填flv,rtsp協議的第三個參數填rtsp)
if (strstr(dest_name, "rtmp") != NULL) {
ret = avformat_alloc_output_context2(&out_fmt_ctx, NULL, "flv", dest_name);
} else {
ret = avformat_alloc_output_context2(&out_fmt_ctx, NULL, "rtsp", dest_name);
}
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Can't alloc output_file %s.\n", dest_name);
return -1;
}
av_log(NULL, AV_LOG_INFO, "Success open push url %s.\n", dest_name);
2、調用avformat_alloc_output_context2函數之後,還要依據推流地址的協議類型來決定是否接着調用avio_open函數打開輸出流,對於RTSP地址而言不必調用avio_open,對於RTMP地址而言必須調用avio_open。具體的判斷與調用代碼如下所示:
// 打開輸出流(注意rtsp推流不要調用avio_open,但rtmp推流要調用avio_open)
if (strstr(dest_name, "rtmp") != NULL) {
ret = avio_open(&out_fmt_ctx->pb, dest_name, AVIO_FLAG_READ_WRITE);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Can't open output_file %s.\n", dest_name);
return -1;
}
}
按照以上兩點代碼修改了《FFmpeg開發實戰:從零基礎到短視頻上線》隨書源碼第十章的推流程序代碼chapter10/pushvideo.c後,先按照之前的文章《詳解MediaMTX的推拉流》啓動電腦本地的流媒體服務器MediaMTX,再執行下面的編譯命令。
gcc pushvideo.c -o pushvideo -I/usr/local/ffmpeg/include -L/usr/local/ffmpeg/lib -lavformat -lavdevice -lavfilter -lavcodec -lavutil -lswscale -lswresample -lpostproc -lm
編譯完成後執行以下命令啓動測試程序,期望把2018.mp4推給RTMP協議的推流地址rtmp://127.0.0.1:1935/stream。
./pushvideo ../file/2018.mp4 rtmp://127.0.0.1:1935/stream
接着打開另一個MSYS窗口,同樣進入該書第十章的源碼目錄chapter10,執行下面的編譯命令。
gcc pullvideo.c -o pullvideo -I/usr/local/ffmpeg/include -L/usr/local/ffmpeg/lib -I/usr/local/sdl2/include -L/usr/local/sdl2/lib -lsdl2 -lavformat -lavdevice -lavfilter -lavcodec -lavutil -lswscale -lswresample -lpostproc -lm
編譯完成後執行以下命令啓動測試程序,期望從 http://127.0.0.1:8888/stream/index.m3u8 拉取視頻流並彈窗播放。
./pullvideo http://127.0.0.1:8888/stream/index.m3u8
然後果真彈出一個SDL窗口,正在播放從HLS服務拉取的視頻畫面,説明修改後的推流代碼成功支持了RTMP協議。
更多詳細的FFmpeg開發知識參見《FFmpeg開發實戰:從零基礎到短視頻上線》一書。