開發RTSP 直播軟件 H264 AAC 編碼 live555 ffmpeg


上一篇對攝像頭預覽,拍照做了大概的介紹,現在已經可以拿到視頻幀了,在加上 RTSP 實現,就是直播的雛形,當然還要加上一些 WEB 管理和手機平台的支援,就是一整套直播軟件。

介紹一些基礎概念:RTP RTSP RTMP

RTP 實時傳輸協議,RTMP 以前  flash 用的視頻協議,RTSP 目前比較流行的 直播協議

 

H264 基礎概念:SPS 、PSS 、NAl 、NALU、 I幀 P 幀B 幀、fps 、pts 、dts

SPS Sequence Parameter Set 序列參數設置  PPS Picture Parameter Set 圖片參數設置

SPS PSS 在容器 mkv 文件中保存時僅存在於開頭時不是每一幀都會附加,但是在 RTSP 實時直播時,需要填充到 sdp 傳輸。

 

用到的軟件和第三方庫:ffmpeg live555 VLC

VLC 全平台播放器,win ubuntu mac os android 各個平台都有,功能強大,UI美觀,還沒有廣告。

live555 開源 RTP RTSP 項目

ffmpeg 開源編解碼器,多種格式轉換,加水印,ffplay 更是全能播放器(就是控制做的不行),解碼器需要自行編譯加入。

ffplay 在 win 上使用時,需要加一個環境變量,否則沒聲音 set SDL_AUDIODRIVER=directsound

1,在本機發布一個 ts 流,用 VLC 和 手機瀏覽器, 進行播放。

ffmpeg -i 1-21.rm -profile:v baseline -level 3.0 -s 640x360 -start_number 0 -hls_time 10 -hls_list_size 0 -f hls 1-12.m3u8

把 ffmpeg 拆分好的文件,復制到 webroot 目錄里面,然后使用 VLC 播放,也可以通過 html5 的 video 在手機上播放,手機上瀏覽器支持 ts 流比較好

2,RTSP 流 使用 live555 發布

http://live555.com/liveMedia/public/ 下載源碼,編譯安裝,不得不說有的時候在 ubuntu 上開發的確比 win 上簡單。

下載解壓后,執行 ./genMakefiles linux 在 make 會生成 mediaServer/live555MediaServer 運行它,在它的目錄放一些文件,這里放的是 mkv 的文件,這里還寫了支持的其它類型的文件。

然后使用 ffplay 進行播放。

使用 wireshark 抓包查看數據包

RTSP 文檔 https://www.rfc-editor.org/rfc/rfc2326.html 自己對照着看吧,如果完全自己從0開發,這些是需要知道的。

3,H264 ACC 編碼

要先找一些原始數據,才能開始編碼。直接從 DirectShow 中,的確是可以拿到數據,每次啟動什么的還是有點麻煩,所以先生成一些數據,使用 ffmpeg 提取視頻為圖片

ffmpeg -i 1.mp4 -r 25 -q:v 2 -f image2 image-%5d.jpg

從 1.mp4 中提取了圖片,幀率是 25 。

win 平台下載編譯好的 lib 比較省心 libffmpeg libjpeg

https://ffmpeg.zeranoe.com/builds/  下載 dev 、shared 2個,為啥要下載2個,因為這個運行的時候,需要 dll,(注意,里面沒有包含 x264)

linux 可以自行編譯,需要下載很多庫 x264 x265 啥的。

參考例子 ffmpeg-4.1/doc/examples$

編譯

gcc encode_video.c -lavcodec -lavutil  -o encode_video

gcc muxing.c -lavcodec -lavutil -lswscale -lswresample -lavformat -lm -o muxing

執行 ./encode_video 1.mp4 libx264  ./muxing 2.mp4

使用 ffplay 播放器打開

 

實際上這個是動的,不過 GIF 錄的不好。

H264 中要求是 YUV420P 格式,JPG 默認解碼 RGB  也可以解碼為 JCS_YCbCr 。YCbCr 和 YUV 幾種格式的區別,ffmpeg 中有以下幾種:

AV_PIX_FMT_YUV444P

AV_PIX_FMT_YUV422P

AV_PIX_FMT_YUV420P

 1 //rgb24 to yun420p
 2     sws_ctx = sws_getContext(frame->width, frame->height, AV_PIX_FMT_RGB24,
 3                 frame->width, frame->height, AV_PIX_FMT_YUV420P, SWS_BICUBIC,
 4                 NULL,NULL,NULL);
 5 
 6     struct dirent **namelist;
 7     int n;
 8 
 9     n = scandir(dir_path, &namelist, NULL, alphasort);
10     for(i = 0; i < n; i++)
11     {
12         if(0 != strcmp(".", namelist[i]->d_name) && 0 != strcmp("..", namelist[i]->d_name))
13         {
14             snprintf(file_image, sizeof(file_image), "%s/%s", dir_path, namelist[i]->d_name);
15 
16             printf("file_image:%s\n", file_image);
17             read_jpeg(file_image, &video_width, &video_height, &image_buff);
18 
19             uint8_t *indata[AV_NUM_DATA_POINTERS] = { 0 };
20             indata[0] = image_buff;
21             int inlinesize[AV_NUM_DATA_POINTERS] = { 0 };
22             inlinesize[0] = frame->width * 3;
23 
24             ret = sws_scale(sws_ctx, indata, inlinesize, 0, frame->height, frame->data, frame->linesize);
25             
26             /* make sure the frame data is writable */
27             ret = av_frame_make_writable(frame);
28             if (ret < 0) exit(1);
29 
30             frame->pts = i;
31 
32             /* encode the image */
33             encode(c, frame, pkt, f);
34 
35             free(image_buff);
36         }
37         free(namelist[i]);
38     }
39     free(namelist);
40     sws_freeContext(sws_ctx);
41 
42     closedir(dir);

 

這個是 修改自  encode_video.c 把 上面拆分的 jpg 圖片合成 264 編碼,編譯方式:gcc encode_video_h264.c -lavcodec -lavutil -lswscale -lswresample -lavformat -ljpeg

這里使用讀取文件夾內的所有 jpg ,read_jpeg() 是一個用 libjpeg 實現的,得到 jpeg 解碼 RGB 數據的方法,但是 編碼器需要 YUV420P 所以使用 sws_scale 進行轉換。

將轉換好的 xin.264 文件復制到  mediaServer 下面,啟動 live555MediaServer 用 VLC 播放。

 

vs2010 編譯 live555 下載並解壓 live.2020.03.06.tar.gz

方法1,編輯 win32config

TOOLS32 = c:\Program Files\DevStudio\Vc 修改為 vs 的路徑 C:\Program Files\Microsoft Visual Studio 10.0\VC

LINK_OPTS_0 = $(linkdebug) msvcrt.lib

執行 genWindowsMakefiles

新建一個 vs_build.bat 

call "C:\Program Files\Microsoft Visual Studio 10.0\VC\vcvarsall.bat"
cd liveMedia
nmake /B -f liveMedia.mak
cd ../groupsock
nmake /B -f groupsock.mak
cd ../UsageEnvironment
nmake /B -f UsageEnvironment.mak
cd ../BasicUsageEnvironment
nmake /B -f BasicUsageEnvironment.mak
cd ../testProgs
nmake /B -f testProgs.mak
cd ../mediaServer
nmake /B -f mediaServer.mak

運行這個批處理,完成以后,就會生成 庫文件和exe

 新建一個空白的 vc++ 工程,復制,生成的頭文件和庫 和 testOnDemandRTSPServer.cpp 配置好工程,編譯生成 exe 放個測試  test.264 運行,能正常播放。

 

方法2,直接使用 vs2010 新建一個 win32 項目 ,選擇 靜態庫 ,無編譯頭

添加一些頭文件。這里4個 lib 項目,合在一起了,添加一個 NO_OPENSSL 宏 禁用 openssl 。

編譯出來了,比那個 方法1強多了,修改調試都方便。

編譯 jpegsr6.zip  解壓 jconfig.vc  改名為 jconfig.h  新建  vs_build.bat

1 call "C:\Program Files\Microsoft Visual Studio 10.0\VC\vcvarsall.bat"
2 nmake /f makefile.vc nodebug=1

libjpeg.lib 和一些頭文件

重新編序 ffmpeg 並加入 https://www.videolan.org/developers/x264.html

 

windows 下編譯的問題:

1,找不到 dirent.h  解決方法,https://github.com/jacksoja/dirent 添加頭文件

2,error C1083: 無法打開包括文件:“inttypes.h”: No such file or directory 解決方法, https://github.com/chemeris/msinttypes 添加頭文件 刪除 stdint.h

 

 

live555 源碼添加 live 直播支持,以 h264 為例 H264VideoFileServerMediaSubsession

createNewStreamSource() 這里是生成 source 數據源的,里面使用一個 ByteStreamFileSource 進行構造。

Medium => MediaSource => FramedSource => FramedFileSource => ByteStreamFileSource => File

Medium => MediaSource => FramedSource => FramedFilter => MPEGVideoStreamFramer => H264or5VideoStreamFramer => H264VideoStreamFramer => ByteStreamFileSource

添加為 H264VideoStreamFramer 從 實時流中讀取數據的方法。

添加類  class LiveStreamH264Source: public FramedSource 用來提供數據 ,提供數據錄入,數據讀出,數據緩存。

添加類  H264VideoLiveFramer: public MPEGVideoStreamFramer 用來處理 source 獲取 sps pps ,sdp

添加類  class H264VideoLiveMediaSubsession: public OnDemandServerMediaSubsession 用來管理會話

重新 編譯運行

新添加的 live h264 已經出來了 ,重新實現 LiveStreamH264Source 中提供,讀流,寫流的操作方法即可。

視頻幀 RGB 轉為 H264 在填充流,參考上面的 RGB 編碼 h264。

 總結:

ffmpeg 實現 RGB 的 h264編碼 和 PCM aac 編碼

DirectShow 實現 windows 平台下,視頻幀圖像采集,音頻 PCM 錄制

送到 live555 通過 RTSP RTP 傳輸,在理想點就是實現 P2P 以減少服務器壓力。

最終成果 gif 動畫:

 

 

VLC 播放的有點色塊,ffplay 的沒事。

后記:

為啥圖像是倒的?

這說明真的是用 DirectShow 做的,SampleGrabberCallback::BufferCB 采集到的數據對 BMP 親合力比較強, 而 BMP 是比左下角開始掃的,而且每行做了4整數對齊。

解決方法是嗎? 多簡單,把攝像頭反着裝就行了,哈哈。

副產品,基於 SDL2 的查看器,調節正常了

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM