日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

使用librtmp实现本地推流

發(fā)布時間:2023/12/31 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 使用librtmp实现本地推流 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

這個文檔詳細(xì)介紹了,如何在本地ubuntu上搭建自己的流服務(wù)器。并通過librtmp進(jìn)行測試。

1.0 背景

客戶需要我們提供rtmp推流的源代碼,然后他們DVR的供應(yīng)商會負(fù)責(zé)移植到盒子中。這個demo演示了如何用c實現(xiàn)rtmp推流。

2.0 安裝配置流服務(wù)器

下面詳細(xì)介紹如何在ubuntu14.04上安裝配置流服務(wù)器

2.1 安裝 nginx

$ sudo apt-get install build-essential libpcre3 libpcre3-dev libssl-dev $ wget http://nginx.org/download/nginx-1.15.1.tar.gz $ wget https://github.com/sergey-dryabzhinsky/nginx-rtmp-module/archive/dev.zip $ tar -zxvf nginx-1.15.1.tar.gz $ unzip dev.zip $ cd nginx-1.15.1 $ ./configure --with-http_ssl_module --add-module=../nginx-rtmp-module-dev $ make $ sudo make install

啟動測試下

$ sudo /usr/local/nginx/sbin/nginx

瀏覽器訪問 http://127.0.0.1
測試ngix正常啟動了

2.2 安裝nginx rtmp服務(wù)插件:

vim /usr/local/nginx/conf/nginx.conf

把下面這段添加到末尾

rtmp {server {listen 1935;chunk_size 4096;application live {live on;record off;}} }

上面配置了rtmp的默認(rèn)端口是1935,以及rtmp app的名字,這里叫“l(fā)ive”

2.3 重啟nginx

$ sudo /usr/local/nginx/sbin/nginx -s stop $ sudo /usr/local/nginx/sbin/nginx

2.4 測試效果

為了測試我們的流服務(wù)器,我們需要安裝ffmpeg來往上面推視頻流,然后瀏覽器拉流查看播放結(jié)果。

2.4.1 安裝ffmpeg

$ sudo add-apt-repository ppa:mc3man/trusty-media $ sudo apt-get update $ sudo apt-get install ffmpeg

2.4.2 測試

從 https://sample-videos.com 下載一個mp4文件。
然后用 ffmpeg 推流,如下命令:

$ ffmpeg -re -i ./sample.mp4 -vcodec libx264 -vprofile baseline -acodec aac -ar 44100 -strict -2 -ac 1 -f flv -s 1280x720 -q 10 rtmp://localhost:1935/live/testav

最后在瀏覽器中輸入:rtmp://127.0.0.1/live/testav 查看推流結(jié)果。第一次運行瀏覽器可能會要求你安裝flash插件,點擊“安裝”即可。

3.0 使用librtmp推流

以上,是利用ffmpeg工具實現(xiàn)的推流,下面介紹如何用c代碼實現(xiàn)推流。我們嘗試把一個flv文件推到服務(wù)器上,并且用瀏覽器播放。

3.1 下載編譯librtmp

首先,下載librtmp的源碼。

git clone git://git.ffmpeg.org/rtmpdump

新建一個文件夾,用來存放我們的測試代碼main函數(shù),以及Makefile,首先是測試代碼,保存為rtmp_push.c

#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h>#include "librtmp/rtmp_sys.h" #include "librtmp/log.h"typedef struct FINT16 {unsigned char Byte1;unsigned char Byte2; }fint16;typedef struct FINT24 {unsigned char Byte1;unsigned char Byte2;unsigned char Byte3; }fint24;typedef struct FINT32 {unsigned char Byte1;unsigned char Byte2;unsigned char Byte3;unsigned char Byte4; }fint32;typedef struct FLVHEADER {unsigned char F;unsigned char L;unsigned char V;unsigned char type;unsigned char info;fint32 len; }FlvHeader;typedef struct TAGHEADER {unsigned char type;fint24 datalen;fint32 timestamp;fint24 streamsid; }TagHeader;typedef struct VIDEODATAPRE {unsigned char FrameTypeAndCodecid;unsigned char AVCPacketType;fint24 CompositionTime; }VideoData;#pragma pack()#define FINT16TOINT(x) ((x.Byte1<<8 & 0xff00) | (x.Byte2 & 0xff)) #define FINT24TOINT(x) ((x.Byte1<<16 & 0xff0000) | (x.Byte2<<8 & 0xff00) | (x.Byte3 & 0xff)) #define FINT32TOINT(x) ((x.Byte1<<24 & 0xff000000) | (x.Byte2<<16 & 0xff0000) | (x.Byte3<<8 & 0xff00) | (x.Byte4 & 0xff))int main(int argc, char **argv) { int res = 0; RTMP* rtmp = RTMP_Alloc(); RTMP_Init(rtmp);res = RTMP_SetupURL(rtmp, "rtmp://127.0.0.1/live/testav");//推流地址 if (res == FALSE) { printf("RTMP_SetupURL error.\n"); } RTMP_EnableWrite(rtmp);//推流要設(shè)置寫 res = RTMP_Connect(rtmp, NULL); if (res == FALSE) { printf("RTMP_Connect error.\n"); } res = RTMP_ConnectStream(rtmp,0); if (res == FALSE) { printf("RTMP_ConnectStream error.\n"); }//推流 FILE *fp_push=fopen("save.flv","rb");//本地用作推流的flv視頻文件 FlvHeader flvheader; fread(&flvheader, sizeof(flvheader), 1, fp_push); int32_t preTagLen = 0;//前一個Tag長度 fread(&preTagLen, 4, 1, fp_push); TagHeader tagHeader; uint32_t begintime=RTMP_GetTime(),nowtime,pretimetamp = 0;while (1) { fread(&tagHeader, sizeof(tagHeader), 1, fp_push); if(tagHeader.type != 0x09) { int num = FINT24TOINT(tagHeader.datalen); fseek(fp_push, FINT24TOINT(tagHeader.datalen)+4, SEEK_CUR); continue; } fseek(fp_push, -sizeof(tagHeader), SEEK_CUR); if((nowtime=RTMP_GetTime()-begintime)<pretimetamp) { printf("%d - %d\n", pretimetamp, nowtime); usleep(1000 * (pretimetamp-nowtime)); continue; }char* pFileBuf=(char*)malloc(11+FINT24TOINT(tagHeader.datalen)+4); memset(pFileBuf,0,11+FINT24TOINT(tagHeader.datalen)+4); if(fread(pFileBuf,1,11+FINT24TOINT(tagHeader.datalen)+4,fp_push)!=11+FINT24TOINT(tagHeader.datalen)+4) break;if ((res = RTMP_Write(rtmp,pFileBuf,11+FINT24TOINT(tagHeader.datalen)+4)) <= 0) { printf("RTMP_Write end.\n"); break; } pretimetamp = FINT24TOINT(tagHeader.timestamp);free(pFileBuf); pFileBuf=NULL; }return 0; }

然后,我們需要編寫Makefile編譯工程,我們只需要使用librtmp中amf.c log.c parseurl.c rtmp.c hashswf.c這幾個文件就好了:
下面是Makefile,對于需要修改的地方,都注釋好了。根據(jù)自己的系統(tǒng)路徑,做適當(dāng)?shù)男薷摹?/p> CFLAGS= #添加下面的編譯參數(shù),不使用ssl庫 zlib等等 DFLAGS=-DNO_SSL -DNO_CRYPTO LDFLAGS=CC=gccBUILD_DIR=./build OBJ_DIR=$(BUILD_DIR)/objs # 修改為你下載下來的librtmp庫的目錄 SRC_DIR=../../rtmpdump/librtmp# 修改為librtmp庫的頭文件目錄 INC= \ -I../../rtmpdump/librtmp \ -I../../rtmpdumpSRC = \ amf.c \ log.c \ parseurl.c \ rtmp.c \ hashswf.c \ rtmp_push.cvpath %.c $(SRC_DIR) ./OBJS = $(notdir $(patsubst %c,%o,$(SRC)))%.o:%.c | out@true "CC $<"$(CC) $(CFLAGS) $(DFLAGS) $(INC) -o $(addprefix $(OBJ_DIR)/,$@) -c $<rtmp_push: $(OBJS)@true "TARGET rtmp_push"$(CC) -o rtmp_push $(addprefix $(OBJ_DIR)/,$(OBJS)) $(LDFLAGS).PHONY : clean clean:rm -rf $(BUILD_DIR)rm -rf rtmp_pushrm -rf *~ out:mkdir -p $(OBJ_DIR)

Makefile修改完成后,直接make就可以了。這樣,我們的測試代碼連同librtmp庫就編譯完成了。

3.2 測試librtmp庫

首先,用ffmpeg工具把之前的mp4文件,轉(zhuǎn)化為flv文件:

ffmpeg -i source.mp4 -c:v libx264 -crf 19 save.flv ./rtmp_push

然后,打開瀏覽器,輸入 rtmp://127.0.0.1/live/testav 就可以看到我們推的rtmp流了。測試結(jié)束。

最后,附上相關(guān)文件:
Makefile
rtmp_push.c

4. 推h264裸流

一般地,客戶會發(fā)一段h264裸流視頻文件讓云端驗證前端播放器的兼容性問題。這就涉及到如何推h264裸流文件。
我們可以參考雷神的代碼:

git clone https://github.com/leixiaohua1020/simplest_librtmp_example.git cd simplest_librtmp_example/simplest_librtmp_send264/ # 這個是推送264的example代碼

這個代碼是在VS里面編譯的工程,我們移植起來會不方便,所以,選擇在linux下編譯安裝測試。這個代碼主要的功能是解析h264文件,并且按照flv格式用RTMP推送視頻流到服務(wù)器。
下面開始編譯。

4.1 復(fù)制lei神代碼

mkdir push_test && cd push_test/ # 新建一個工程文件夾 我們把需要的源碼從git里面拷貝出來編譯 cp ../simplest_librtmp_example/simplest_librtmp_send264/cuc_ieschool.h264 \../simplest_librtmp_example/simplest_librtmp_send264/librtmp_send264.cpp \../simplest_librtmp_example/simplest_librtmp_send264/librtmp_send264.h \../simplest_librtmp_example/simplest_librtmp_send264/sps_decode.h \../simplest_librtmp_example/simplest_librtmp_send264/simplest_librtmp_send264.cpp .

4.2 編寫Makefile

這里的Makefile和上面的類似,只是增加了兩個cpp文件需要一起集成編譯一下

CFLAGS= #添加下面的編譯參數(shù),不使用ssl庫 zlib等等 DFLAGS=-DNO_SSL -DNO_CRYPTO LDFLAGS=CC=gccBUILD_DIR=./build OBJ_DIR=$(BUILD_DIR)/objs # 修改為你下載下來的librtmp庫的目錄 SRC_DIR=../../../rtmpdump/librtmp# 修改為librtmp庫的頭文件目錄 INC= \ -I../../../rtmpdump/librtmp \ -I../../../rtmpdumpSRC = \ amf.c \ log.c \ parseurl.c \ rtmp.c \ hashswf.cvpath %.c $(SRC_DIR) ./ vpath %.cpp $(SRC_DIR) ./OBJS = $(notdir $(patsubst %c,%o,$(SRC))) simplest_librtmp_send264.o librtmp_send264.o%.o:%.c | out@echo "CC $<"$(CC) $(CFLAGS) $(DFLAGS) $(INC) -o $(addprefix $(OBJ_DIR)/,$@) -c $<rtmp_push: $(OBJS)@echo "TARGET rtmp_push"$(CC) -o rtmp_push $(addprefix $(OBJ_DIR)/,$(OBJS)) $(LDFLAGS)simplest_librtmp_send264.o:simplest_librtmp_send264.cpp | out@echo "CC $<"$(CC) $(CFLAGS) $(DFLAGS) $(INC) -o $(addprefix $(OBJ_DIR)/,$@) -c $<librtmp_send264.o:librtmp_send264.cpp | out@echo "CC $<"$(CC) $(CFLAGS) $(DFLAGS) $(INC) -o $(addprefix $(OBJ_DIR)/,$@) -c $<.PHONY : clean clean:rm -rf $(BUILD_DIR)rm -rf rtmp_pushrm -rf *~ out:mkdir -p $(OBJ_DIR)

直接make一下,報錯:

librtmp_send264.cpp:18:10: fatal error: 'librtmp\rtmp.h' file not found #include "librtmp\rtmp.h"

因為是windows下的程序,路徑中的反斜杠需要改成linux中的斜杠,修改完成,繼續(xù)make,還是報錯

gcc -o rtmp_push ./build/objs/amf.o ./build/objs/log.o ./build/objs/parseurl.o ./build/objs/rtmp.o ./build/objs/hashswf.o ./build/objs/simplest_librtmp_send264.o ./build/objs/librtmp_send264.o Undefined symbols for architecture x86_64:"operator delete[](void*)", referenced from:h264_decode_sps(unsigned char*, unsigned int, int&, int&, int&) in librtmp_send264.o"operator new[](unsigned long)", referenced from:h264_decode_sps(unsigned char*, unsigned int, int&, int&, int&) in librtmp_send264.o ld: symbol(s) not found for architecture x86_64 clang: error: linker command failed with exit code 1 (use -v to see invocation) make: *** [rtmp_push] Error 1

因為是用c編譯器,無法識別c++中的new delete等關(guān)鍵字,所以,我們還得修改代碼。。定位到 sps_decode.h中176行位置,

// 這幾句話看起來沒具體作用,直接注釋掉// int *offset_for_ref_frame=new int[num_ref_frames_in_pic_order_cnt_cycle];// for( int i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; i++ )// offset_for_ref_frame[i]=Se(buf,nLen,StartBit);// delete [] offset_for_ref_frame;

繼續(xù)make,編譯通過。

4.3 測試demo中的h264文件推流

修改 simplest_librtmp_send264.cpp 38行

// 這里,我們使用百度 lss 提供的RTMP推流地址 RTMP264_Connect("rtmp://push.ivc.gz.baidubce.com/xxx/test");

推流,發(fā)現(xiàn)程序在發(fā)完第一個relu之后就卡住了,發(fā)現(xiàn)是msleep的問題,修改 librtmp_send264.cpp 680行位置

tick +=tick_gap; now=RTMP_GetTime(); msleep((int)(tick_gap-now+last_update)); // 這里需要用 int 強制類型轉(zhuǎn)化,不然就會卡住。莫名其妙,不懂,求大佬指點。 //msleep(40);

這樣修改之后,運行 ./rtmp_push 就可以推流了,在客戶端使用ffplay播放:

用rtmp格式播放 ffplay "rtmp://rtmp.play.ivc.gz.baidubce.com/xxx/test?only-video=1" 或者用flv格式播放 ffplay "http://flv.play.ivc.gz.baidubce.com/xxx/test.flv?only-video=1" # 必須加上 only-video=1 參數(shù)因為我們的264文件中只有視頻 沒有音頻,默認(rèn)情況下server回去做音/視頻同步,導(dǎo)致30s左右延遲! # 加上這個參數(shù)直接跳過“同步”的過程,差不多5s內(nèi)開首屏。

4.4 測試客戶h264文件

如果你測試客戶發(fā)過來的h264文件,你會發(fā)現(xiàn)用上面的代碼多半是跑不起來的。
雷神代碼中默認(rèn)是按照第一個幀是sps pps來解析的,這本身應(yīng)該沒有問題,因為客戶手機一般也是在檢測到第一個sps pps之后,才開始推流的。開頭并不會出現(xiàn)“無用的”P幀數(shù)據(jù)。
但是,客戶發(fā)過來的h264文件一般都是在開頭夾雜著“無用的”P幀數(shù)據(jù),所以用上面的代碼肯定是不行的,我們要做的是把客戶h264文件開頭的P幀數(shù)據(jù)去掉,才開始用上面的代碼推。
這就涉及到如何編輯二進(jìn)制h264文件了。首先提供一個工具:
truncate_head_n.c

gcc truncate_head_n.c -o truncate_head_n ./truncate_head_n 1000 # 該命令會去掉當(dāng)前目錄下 命名為 temp的二進(jìn)制文件的開始1000個字節(jié)

有了該工具,我們只需要找到264文件中第一個sps的偏移地址就可以了,可以直接用vim 查看

vim -b h264data.h264 :%!xxd

找到偏移,并且用工具去掉無用P幀之后,就可以用上面的demo推客戶的流了,步驟就不贅述。
但是,我這里遇到一個很奇怪的問題,發(fā)現(xiàn)打開還是很慢,需要30s多。經(jīng)過百度lss同學(xué)指點,說需要修改 librtmp_send264.cpp 中,只需要在開始時推一次sps pps,推流過程中,不再推sps pps,經(jīng)過驗證,在去掉推流中間過程的sps pps時候,首屏開啟5s左右!那為何demo中的264文件在不改代碼時也是沒問題的呢?暫時沒結(jié)果。

總結(jié)

以上是生活随笔為你收集整理的使用librtmp实现本地推流的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 色婷婷av国产精品 | 青青草公开视频 | 人人人妻人人澡人人爽欧美一区 | 中文字幕精品视频在线 | 久久精品视频免费 | 朝桐光在线播放 | 国产精品后入内射日本在线观看 | 三级黄色小视频 | 91一区二区三区在线观看 | 国产特黄aaaaa毛片 | free国产hd露脸性开放 | 六月色| 正在播放av | 久青草视频在线 | 老女人一区 | 色香av| 成人精品在线看 | 日本成人在线播放 | 成为性瘾网黄的yy对象后 | 超碰97久久 | 91性| av在线播放网 | a v视频在线观看 | 欧美做受视频 | 精品国产黄 | а√天堂8资源中文在线 | 欧美一区免费看 | 色哟哟在线播放 | 成年人黄色| 国产情侣自拍小视频 | 国产黄色一区 | 在线观看麻豆视频 | 亚洲福利 | xxxx视频在线| 粗大挺进潘金莲身体在线播放 | 成年在线观看视频 | 蜜桃av免费看 | 在线免费观看一区 | 俄罗斯色片| 国产人妻精品久久久久野外 | 懂色av色吟av夜夜嗨 | 欧美另类69 | 孕妇丨91丨九色 | 99视频在线观看视频 | 99日韩| 青青草97国产精品免费观看 | 伊人欧美在线 | 日本va在线| 91精品视频免费看 | 最新中文字幕免费 | 风间由美一区二区 | 免费国产a级片 | 国产91综合 | 99ri精品 | 欧美精品一二三区 | 欧美不卡视频在线观看 | 超碰蜜臀 | 日韩欧美不卡 | 国产五月| 国内一区二区视频 | 韩日一区二区三区 | 国产亚洲视频在线 | 亚洲色图18p | 亚洲女同视频 | 免费观看黄网站 | 国产欧美一区二区三区在线看蜜臂 | 国产精品毛片一区二区 | 黄色精品 | 成人免费在线播放 | 高潮毛片无遮挡 | 波多av在线 | 一区二区三区在线看 | 樱桃视频污污 | 青春草免费视频 | 在线播放视频高清在线观看 | 美女激情av | 野花国产精品入口 | 亚洲精品一区二区三区不卡 | 日本熟妇一区二区三区 | 黄色片中国 | 国产又爽又黄又嫩又猛又粗 | 麻豆成人91精品二区三区 | 青青草原一区二区 | 国产第20页 | 91久久人澡人人添人人爽欧美 | 欧美精品手机在线 | 国产精品国产三级国产普通话对白 | 在线免费观看中文字幕 | av噜噜| 丝袜视频在线观看 | 成人网页 | 波多野吉衣一区二区 | 潘金莲激情呻吟欲求不满视频 | 1区2区3区在线观看 久久久久久久久久久影院 成人网址在线观看 | 中文字幕乱码在线 | 亚洲无码精品免费 | 欧美日韩一区二区在线观看 | 欧美成人精品一区 | 最新av女优 |