最近作直播系統的朋友不少,正好前端時間也在作這一塊,寫片文章分享下開發心得,覺得後用。前端
直播系統我將它分爲前堆推流,後臺服務,客戶端播放三大部分。前端推流基於ffmpeg,後臺服務linux
使用crtmp服務,播放端可使用JWPlayer(網頁端播放),也能夠是CGplayer。windows
一.前端推流服務器
推流能夠採用命令: ffmpeg -i input -vcodec copy -acodec copy -f flv rtmp://127.0.0.1/live/cgstream0網絡
input 能夠是實時流,也能夠是文件,若是是文件 須要加上-re。運用中須要將127.0.0.1換成rtmp所在機器的ip地址。併發
用命令推流時間戳信息不能任意修改,想要達到一個滿意的結果仍是要用代碼實現。rtmp推流前面有文章介紹過,負載均衡
這裏將主要的幾個方法介紹下,文章後面會給出完成的工程包。less
ffmpeg推流 若是不須要重寫編碼(視頻源已是編碼好的數據),推流的過程比較簡單就是一個demux和remux過程。高併發
主要方法代碼以下:工具
1.打開視頻流,filename能夠文件名稱也能夠是實時流url.
int OpenInput(char *fileName) { AVDictionary* options = nullptr; context = avformat_alloc_context(); cout << "Begin Open file Input " << endl; lastTime = av_gettime(); context->interrupt_callback.callback = interrupt_cb; int ret = avformat_open_input(&context, fileName, nullptr,&options); if(ret < 0) { return ret; } ret = avformat_find_stream_info(context,nullptr); return ret; }
2.建立輸出上下文以及輸出流,輸出流的格式須要設置成flv
int OpenOutput(char *fileName) { int ret = 0; ret = avformat_alloc_output_context2(&outputContext, nullptr, "flv", fileName); if(ret < 0) { goto Error; } ret = avio_open2(&outputContext->pb, fileName, AVIO_FLAG_READ_WRITE,nullptr, nullptr); if(ret < 0) { goto Error; } for(int i = 0; i < context->nb_streams; i++) { AVStream * stream = avformat_new_stream(outputContext, context->streams[i]->codec->codec); ret = avcodec_copy_context(stream->codec, context->streams[i]->codec); if(ret < 0) { goto Error; } } ret = avformat_write_header(outputContext, nullptr); if(ret < 0) { goto Error; } return ret ; Error: if(outputContext) { for(int i = 0; i < outputContext->nb_streams; i++) { avcodec_close(outputContext->streams[i]->codec); } avformat_close_input(&outputContext); } return ret ; }
3. 從輸入流中讀取音視頻包
shared_ptr<AVPacket> ReadPacketFormSource() { shared_ptr<AVPacket> packet(static_cast<AVPacket*>(av_malloc(sizeof(AVPacket))),
[&](AVPacket *p) { av_free_packet(p); av_freep(&p);}); av_init_packet(packet.get()); lastTime = av_gettime(); int ret = av_read_frame(context, packet.get()); if(ret >= 0) { return packet; } return nullptr; }
4. 簡單示例
int main(int argc,char *argv[])
{
if(argc != 3) { std::cout <<" more or less parameters "<<endl; this_thread::sleep_for(chrono::seconds(1000)); return 0; } string fileInput= argv[1]; string fileOutput = argv[2]; thread task; bool streamEof = false; std::cout <<"input file is:"<< fileInput<< endl; std::cout <<"output file is:"<< fileOutput << endl; Init(); if(OpenInput((char *)fileInput.c_str()) < 0) { std::cout << "Open file Input failed!" << endl; this_thread::sleep_for(chrono::seconds(1000)); return 0; } std::cout <<"OpenInput successful"<<endl; if(OpenOutput((char *)fileOutput.c_str()) < 0) { std::cout << "Open file Output failed!" << endl; this_thread::sleep_for(chrono::seconds(1000)); return 0; } std::cout <<"OpenOutput successful"<<endl; int count = 0; auto timebase = av_q2d(context->streams[0]->time_base); int ret = 0; while(true) { auto packet = ReadPacketFormSource(); if(packet) { ret = av_write_frame(outputContext,packet.get()); } if(ret < 0 ) { break; } }
}
fileOutput 能夠賦值爲rtmp://127.0.0.1/live/cgstream0,表示視頻流將要推送到本地的rtmp服務,默認端口是1935.
二. 服務端
服務端能夠選擇crtmpserver,crtmpserver開源,在windows平臺以及linux平臺下均可以運行,不少朋友總會問crtmpserver效率
如何,有人質疑:crtmpserver是一個單線程的select模型,可否知足高併發的性能要求。質疑是有理的,有段時間我打算將crtmpserver改爲
並行結構,後來我仍是放棄了,由於不少狀況下用不到,仍是等需求來了再改。大部分狀況下,瓶頸並不在crtmpserver能併發多少路,而在網絡
帶寬能支持多少路音視頻流。隨着人們對視頻質量要求的提升,基本上視頻的分辨率都是高清(1080p),碼率基本會在4M以上。試想若是服務器
網卡選擇千兆網卡,單個網卡最多也就支持兩百多路。通常來說,服務器的cpu配置會比普通電腦高不少,支持幾百路併發是不會出現性能問題。固然,
若是追求最低的配置實現最高的併發也許crtmpserver不是最好的選擇,但項目講究實用,不少場合下足以知足需求。說到這裏,確定有人會問,若是並
發訪問的命令上千上萬怎麼辦?答案是負載均衡。
三. 播放端
若是在網頁上播放(IE),能夠選擇JwPlayer,若是用插件的也是能夠。Android端播放器若是底層基於ffmpeg,也能夠播放CrtmpServer
轉發的音視頻流(ffmpeg須要引入librtmp庫),IOS系統 同理。播放的url是rtmp://127.0.0.1/live/cgstream0。
若是須要技術交流可加QQ 350197870,或加羣流媒體/Ffmpeg/音視頻 127903734討論,CrtmpServer以及JwPlayer能夠在羣裏
直接下載,推流部分的源碼過兩天,也會上傳上來。
四. 如何搭建
說了半天,有些新手朋友可能還不知道如何動手搭建一個簡單的直播系統,怎麼推流,又如何播放,下面我一步步介紹.
1.首先 下載CrtmpServer服務(能夠直接從羣裏下載),運行雙擊文件夾下的crtmpserver.exe,若是沒有閃退,說明運行成功.
2.下載ffmpeg.exe (能夠從羣裏直接下載),在命令行執行 ffmpeg -i input -vcodec copy -acodec copy -f flv rtmp://127.0.0.1/live/cgstream0
127.0.0.1改爲crtmpserver.exe所在服務器的地址.若是你在linux下推流,須要linux版本的ffmpeg。cgstream0能夠根據須要任意修改。在 windows平臺下若是推流成功ffmpeg會一直打印信息,出錯也會有相應的提示。
3.播放:播放能夠用ffplayer.exe(能夠從羣裏下載,這個工具對rtmp流支持不是很好 ,播放的地址是rtmp://127.0.0.1/live/cgstream0 live=1),JwPlayer(用法前面有文章介紹), 還能夠用CGPlayer播放器
(這是本人寫的不檢查時間戳的rtmp播放器 播放的地址是rtmp://127.0.0.1/live/cgstream0 live=1)。過兩天會將下載地址粘貼上來。
如需交流,能夠加QQ羣1038388075,766718184,或者QQ:350197870
視頻教程 播放地址: http://www.iqiyi.com/u/1426749687
視頻下載地址:http://www.chungen90.com/?news_3/
Demo下載地址: http://www.chungen90.com/?news_2