基於RTMP推送即時AAC+H264流(三)__rtmp

來源:互聯網
上載者:User
推送

流程:初始化、串連伺服器、發送資料
這一部分主要用的是librtmp,由於是使用別人封裝好的庫,總的來說比較簡單 初始化

簡單地調用一下函數

rtmp = RTMP_Alloc();RTMP_Init(rtmp);
串連伺服器

四個函數分別代表:設定URL、使自己成為發送端、建立NetConnection,建立NetStream

RTMP_SetupURL(rtmp, url);RTMP_EnableWrite(rtmp);RTMP_Connect(rtmp, NULL);RTMP_ConnectStream(mRTMP, 0);
發送資料

不斷從隊列中取出RTMP包,加上時間戳記和流ID,然後往伺服器發送,幀率的控制位於編碼線程,所以這裡不用計算時間,直接加上時間戳記發送即可,而且由於這裡也不好計算時間,還有就是這裡的隊列是阻塞隊列

while (true) {    RTMPPacket& packet = queue.front();    packet.m_nInfoField2 = rtmp->m_stream_id;    packet.m_nTimeStamp = RTMP_GetTime();    RTMP_SendPacket(rtmp, &packet, 1);    queue.pop();}
主程式

主要分為:視頻編碼線程、音頻編碼線程、主線程(發送線程) 視頻編碼線程

根據幀率算出間隔時間,然後把視頻中繼資料的rtmp包存下來以便多次發送,從視頻源擷取幀,判斷是否是主要畫面格,如果是則先發送中繼資料,經過編碼封裝後發送資料,最後比較花費時間與間隔時間決定是否需要等待

const int interval = 1000 / fps;int bytes;char *buf, *frame;RTMPPacket packet, meta;H264RTMPPackager packager;std::chrono::milliseconds duration;std::pair<int, char*> result;meta = encoder.getMetadata();buf = pool.get(1024);packet = packager.metadata(buf, result.second, result.first);auto last = std::chrono::system_clock::now();while ((frame = source.getNextFrame()) != NULL) {    result = source.encode(frame);    if (H264RTMPPackager::isKeyFrame(result.second)) {        queue.push(meta, true);    }    bytes = packager.getBodyLength(result.first);    buf = pool.get(bytes);    packet = packager.pack(buf, result.second, result.first)    queue.push(packet);    duration = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - last);    if (duration < interval) {        msleep((interval - duration).count());    }    last = std::chrono::system_clock::now();}
音頻編碼線程

步驟與視頻編碼線程相似,只是這裡無需等待,因為音頻源是根據採樣率來輸出幀的,這裡由於中繼資料只需要發送一次,所以可以不用儲存下來

int bytes;char *buf;RTMPPacket packet;AACRTMPPackager packager;std::pair<int, char*> frame, result;result = encoder.getMetadata();buf = pool.get(128);packet = packager.metadata(buf, result.second, result.first);queue.push(packet, true);while ((frame = source.getNextFrames()).second != NULL) {    result = encoder.encode(frame.first, frame.second);    if (result.first != 0) {        bytes = packager.getBodyLength(result.first);        buf = pool.get(bytes);        packet = packager.pack(buf, result.second, result.first);        queue.push(packet);    }}
主線程

建立H264流以及AAC流,然後開啟視頻編碼線程和音頻編碼線程

PacketQueue queue;MemoryPool pool;V4L2Source v4l2(width, height);PCMSource pcm;YUY2Converter converter(YUY2_CVT_RGB24);MotionDetector detector;FilteredVideoSource videoSource(v4l2);videoSource.addFilter(&converter);videoSource.addFilter(&detector);RTMPPublisher publisher(queue, pool);publisher.connect(url);H264Stream videoStream(videoSource, queue, pool, fps, bitrate);AACStream audioStream(pcm, queue, pool);std::thread videoEncodeThread(&H264Stream::run, &videoStream);std::thread audioEncodeThread(&AACStream::run, &audioStream);publisher.run();
後記

至此,簡單的推送程式就完成了,項目整體比較簡單,基本上也就是在調用第三方庫,但是總的來說學到的東西不少,對於以前不懂的視音頻編碼,也有了一些瞭解,而且也是第一次遇到生產者-消費者的情景,雖然這裡的情景比較簡單,只有一位消費者
自己的測試環境是電腦Ubuntu和樹莓派Raspbian,關於使用到的庫,opencv3應該是需要編譯安裝,樹莓派上libfaac可能也需要編譯安裝
rtmp伺服器用的是SRS,配置方法再網上可以很簡單地搜尋到

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.