最簡單的基於librtmp的樣本:發布(FLV通過RTMP發布)

來源:互聯網
上載者:User

=====================================================

最簡單的基於libRTMP的樣本系列文章列表:

最簡單的基於librtmp的樣本:接收(RTMP儲存為FLV)

最簡單的基於librtmp的樣本:發布(FLV通過RTMP發布)

最簡單的基於librtmp的樣本:發布H.264(H.264通過RTMP發布)

=====================================================

本文記錄一個基於libRTMP的發布流媒體的程式:Simplest libRTMP Send FLV。該程式可以將本地FLV檔案發布到RTMP流媒體伺服器。是最簡單的基於libRTMP的流媒體發布樣本。   流程圖
使用librtmp發布RTMP流的可以使用兩種API:RTMP_SendPacket()和RTMP_Write()。使用RTMP_SendPacket()發布流的時候的函數執行流程圖如下圖所示。使用RTMP_Write()發布流的時候的函數執行流程圖相差不大。
 

流程圖中關鍵函數的作用如下所列:InitSockets():初始化Socket
RTMP_Alloc():為結構體“RTMP”分配記憶體。
RTMP_Init():初始化結構體“RTMP”中的成員變數。
RTMP_SetupURL():設定輸入的RTMP串連的URL。
RTMP_EnableWrite():發布流的時候必須要使用。如果不使用則代表接收流。
RTMP_Connect():建立RTMP串連,建立一個RTMP協議規範中的NetConnection。
RTMP_ConnectStream():建立一個RTMP協議規範中的NetStream。
Delay:發布流過程中的延時,保證按正常播放速度發送資料。
RTMP_SendPacket():發送一個RTMP資料RTMPPacket。
RTMP_Close():關閉RTMP串連。
RTMP_Free():釋放結構體“RTMP”。
CleanupSockets():關閉Socket。
 
原始碼原始碼中包含了使用兩種API函數RTMP_SendPacket()和RTMP_Write()發布流媒體的原始碼,如下所示。

/** * Simplest Librtmp Send FLV * * 雷霄驊,張暉 * leixiaohua1020@126.com * zhanghuicuc@gmail.com * 中國傳媒大學/數字電視技術 * Communication University of China / Digital TV Technology * http://blog.csdn.net/leixiaohua1020 * * 本程式用於將FLV格式的視音頻檔案使用RTMP推送至RTMP流媒體伺服器。 * This program can send local flv file to net server as a rtmp live stream. */ #include <stdio.h>#include <stdlib.h>#include <string.h>#include <stdint.h>#ifndef WIN32#include <unistd.h>#endif  #include "librtmp/rtmp_sys.h"#include "librtmp/log.h" #define HTON16(x)  ((x>>8&0xff)|(x<<8&0xff00))#define HTON24(x)  ((x>>16&0xff)|(x<<16&0xff0000)|(x&0xff00))#define HTON32(x)  ((x>>24&0xff)|(x>>8&0xff00)|\         (x<<8&0xff0000)|(x<<24&0xff000000))#define HTONTIME(x) ((x>>16&0xff)|(x<<16&0xff0000)|(x&0xff00)|(x&0xff000000)) /*read 1 byte*/int ReadU8(uint32_t *u8,FILE*fp){         if(fread(u8,1,1,fp)!=1)                   return 0;         return 1;}/*read 2 byte*/int ReadU16(uint32_t *u16,FILE*fp){         if(fread(u16,2,1,fp)!=1)                   return 0;         *u16=HTON16(*u16);         return 1;}/*read 3 byte*/int ReadU24(uint32_t *u24,FILE*fp){         if(fread(u24,3,1,fp)!=1)                   return 0;         *u24=HTON24(*u24);         return 1;}/*read 4 byte*/int ReadU32(uint32_t *u32,FILE*fp){         if(fread(u32,4,1,fp)!=1)                   return 0;         *u32=HTON32(*u32);         return 1;}/*read 1 byte,and loopback 1 byte at once*/int PeekU8(uint32_t *u8,FILE*fp){         if(fread(u8,1,1,fp)!=1)                   return 0;         fseek(fp,-1,SEEK_CUR);         return 1;}/*read 4 byte and convert to time format*/int ReadTime(uint32_t *utime,FILE*fp){         if(fread(utime,4,1,fp)!=1)                   return 0;         *utime=HTONTIME(*utime);         return 1;} int InitSockets(){         WORD version;         WSADATA wsaData;         version=MAKEWORD(2,2);         return (WSAStartup(version, &wsaData) == 0);} void CleanupSockets(){         WSACleanup();} //Publish using RTMP_SendPacket()int publish_using_packet(){         RTMP *rtmp=NULL;                                    RTMPPacket *packet=NULL;         uint32_t start_time=0;         uint32_t now_time=0;         //the timestamp of the previous frame         long pre_frame_time=0;         long lasttime=0;         int bNextIsKey=1;         uint32_t preTagsize=0;                 //packet attributes         uint32_t type=0;                                 uint32_t datalength=0;                    uint32_t timestamp=0;                    uint32_t streamid=0;                                  FILE*fp=NULL;         fp=fopen("cuc_ieschool.flv","rb");         if (!fp){                   RTMP_LogPrintf("Open File Error.\n");                   CleanupSockets();                   return -1;         }          /* set log level */         //RTMP_LogLevel loglvl=RTMP_LOGDEBUG;         //RTMP_LogSetLevel(loglvl);                           if (!InitSockets()){                   RTMP_LogPrintf("Init Socket Err\n");                   return -1;         }          rtmp=RTMP_Alloc();         RTMP_Init(rtmp);         //set connection timeout,default 30s         rtmp->Link.timeout=5;                               if(!RTMP_SetupURL(rtmp,"rtmp://localhost/publishlive/livestream"))         {                   RTMP_Log(RTMP_LOGERROR,"SetupURL Err\n");                   RTMP_Free(rtmp);                   CleanupSockets();                   return -1;         }                 //if unable,the AMF command would be 'play' instead of 'publish'         RTMP_EnableWrite(rtmp);                      if (!RTMP_Connect(rtmp,NULL)){                   RTMP_Log(RTMP_LOGERROR,"Connect Err\n");                   RTMP_Free(rtmp);                   CleanupSockets();                   return -1;         }                 if (!RTMP_ConnectStream(rtmp,0)){                   RTMP_Log(RTMP_LOGERROR,"ConnectStream Err\n");                   RTMP_Close(rtmp);                   RTMP_Free(rtmp);                   CleanupSockets();                   return -1;         }          packet=(RTMPPacket*)malloc(sizeof(RTMPPacket));         RTMPPacket_Alloc(packet,1024*64);         RTMPPacket_Reset(packet);          packet->m_hasAbsTimestamp = 0;                 packet->m_nChannel = 0x04;         packet->m_nInfoField2 = rtmp->m_stream_id;          RTMP_LogPrintf("Start to send data ...\n");                 //jump over FLV Header         fseek(fp,9,SEEK_SET);              //jump over previousTagSizen         fseek(fp,4,SEEK_CUR);            start_time=RTMP_GetTime();         while(1)         {                   if((((now_time=RTMP_GetTime())-start_time)                              <(pre_frame_time)) && bNextIsKey){                                    //wait for 1 sec if the send process is too fast                            //this mechanism is not very good,need some improvement                            if(pre_frame_time>lasttime){                                     RTMP_LogPrintf("TimeStamp:%8lu ms\n",pre_frame_time);                                     lasttime=pre_frame_time;                            }                            Sleep(1000);                            continue;                   }                                     //not quite the same as FLV spec                   if(!ReadU8(&type,fp))                                 break;                   if(!ReadU24(&datalength,fp))                            break;                   if(!ReadTime(×tamp,fp))                            break;                   if(!ReadU24(&streamid,fp))                            break;                    if (type!=0x08&&type!=0x09){                            //jump over non_audio and non_video frame,                            //jump over next previousTagSizen at the same time                            fseek(fp,datalength+4,SEEK_CUR);                            continue;                   }                                     if(fread(packet->m_body,1,datalength,fp)!=datalength)                            break;                    packet->m_headerType = RTMP_PACKET_SIZE_LARGE;                   packet->m_nTimeStamp = timestamp;                   packet->m_packetType = type;                   packet->m_nBodySize  = datalength;                   pre_frame_time=timestamp;                    if (!RTMP_IsConnected(rtmp)){                            RTMP_Log(RTMP_LOGERROR,"rtmp is not connect\n");                            break;                   }                   if (!RTMP_SendPacket(rtmp,packet,0)){                            RTMP_Log(RTMP_LOGERROR,"Send Error\n");                            break;                   }                    if(!ReadU32(&preTagsize,fp))                            break;                                              if(!PeekU8(&type,fp))                            break;                   if(type==0x09){                            if(fseek(fp,11,SEEK_CUR)!=0)                                     break;                            if(!PeekU8(&type,fp)){                                     break;                            }                            if(type==0x17)                                     bNextIsKey=1;                            else                                     bNextIsKey=0;                             fseek(fp,-11,SEEK_CUR);                   }         }                         RTMP_LogPrintf("\nSend Data Over\n");                 if(fp)                   fclose(fp);          if (rtmp!=NULL){                   RTMP_Close(rtmp);                           RTMP_Free(rtmp);                    rtmp=NULL;         }         if (packet!=NULL){                   RTMPPacket_Free(packet);                       free(packet);                   packet=NULL;         }          CleanupSockets();         return 0;} //Publish using RTMP_Write()int publish_using_write(){         uint32_t start_time=0;         uint32_t now_time=0;         uint32_t pre_frame_time=0;         uint32_t lasttime=0;         int bNextIsKey=0;         char* pFileBuf=NULL;          //read from tag header         uint32_t type=0;         uint32_t datalength=0;         uint32_t timestamp=0;          RTMP *rtmp=NULL;                                            FILE*fp=NULL;         fp=fopen("cuc_ieschool.flv","rb");         if (!fp){                   RTMP_LogPrintf("Open File Error.\n");                   CleanupSockets();                   return -1;         }          /* set log level */         //RTMP_LogLevel loglvl=RTMP_LOGDEBUG;         //RTMP_LogSetLevel(loglvl);                           if (!InitSockets()){                  RTMP_LogPrintf("Init Socket Err\n");                   return -1;         }          rtmp=RTMP_Alloc();         RTMP_Init(rtmp);         //set connection timeout,default 30s         rtmp->Link.timeout=5;                               if(!RTMP_SetupURL(rtmp,"rtmp://localhost/publishlive/livestream"))         {                   RTMP_Log(RTMP_LOGERROR,"SetupURL Err\n");                   RTMP_Free(rtmp);                   CleanupSockets();                   return -1;         }          RTMP_EnableWrite(rtmp);         //1hour         RTMP_SetBufferMS(rtmp, 3600*1000);                  if (!RTMP_Connect(rtmp,NULL)){                   RTMP_Log(RTMP_LOGERROR,"Connect Err\n");                   RTMP_Free(rtmp);                   CleanupSockets();                   return -1;         }                 if (!RTMP_ConnectStream(rtmp,0)){                   RTMP_Log(RTMP_LOGERROR,"ConnectStream Err\n");                   RTMP_Close(rtmp);                   RTMP_Free(rtmp);                   CleanupSockets();                   return -1;         }          printf("Start to send data ...\n");                 //jump over FLV Header         fseek(fp,9,SEEK_SET);              //jump over previousTagSizen         fseek(fp,4,SEEK_CUR);            start_time=RTMP_GetTime();         while(1)         {                   if((((now_time=RTMP_GetTime())-start_time)                              <(pre_frame_time)) && bNextIsKey){                                    //wait for 1 sec if the send process is too fast                            //this mechanism is not very good,need some improvement                            if(pre_frame_time>lasttime){                                     RTMP_LogPrintf("TimeStamp:%8lu ms\n",pre_frame_time);                                     lasttime=pre_frame_time;                            }                            Sleep(1000);                            continue;                   }                                     //jump over type                   fseek(fp,1,SEEK_CUR);                      if(!ReadU24(&datalength,fp))                            break;                   if(!ReadTime(×tamp,fp))                            break;                   //jump back                   fseek(fp,-8,SEEK_CUR);                                       pFileBuf=(char*)malloc(11+datalength+4);                   memset(pFileBuf,0,11+datalength+4);                   if(fread(pFileBuf,1,11+datalength+4,fp)!=(11+datalength+4))                            break;                                     pre_frame_time=timestamp;                                     if (!RTMP_IsConnected(rtmp)){                            RTMP_Log(RTMP_LOGERROR,"rtmp is not connect\n");                            break;                   }                   if (!RTMP_Write(rtmp,pFileBuf,11+datalength+4)){                            RTMP_Log(RTMP_LOGERROR,"Rtmp Write Error\n");                            break;                   }                                     free(pFileBuf);                   pFileBuf=NULL;                    if(!PeekU8(&type,fp))                            break;                   if(type==0x09){                            if(fseek(fp,11,SEEK_CUR)!=0)                                     break;                            if(!PeekU8(&type,fp)){                                     break;                            }                            if(type==0x17)                                     bNextIsKey=1;                            else                                     bNextIsKey=0;                            fseek(fp,-11,SEEK_CUR);                   }         }          RTMP_LogPrintf("\nSend Data Over\n");                 if(fp)                   fclose(fp);          if (rtmp!=NULL){                   RTMP_Close(rtmp);                           RTMP_Free(rtmp);                   rtmp=NULL;         }          if(pFileBuf){                   free(pFileBuf);                   pFileBuf=NULL;         }          CleanupSockets();         return 0;} int main(int argc, char* argv[]){         //2 Methods:         publish_using_packet();         //publish_using_write();         return 0;}


運行結果

程式運行後,會將“cuc_ieschool.flv”檔案以直播流的形式發布到“rtmp://localhost/publishlive/livestream”的URL。修改檔案名稱和RTMP的URL可以實現將任意flv檔案發布到任意RTMP的URL。


下載  Simplest LibRTMP Example
 

項目首頁

SourceForge:https://sourceforge.net/projects/simplestlibrtmpexample/

Github:https://github.com/leixiaohua1020/simplest_librtmp_example

開源中國:http://git.oschina.net/leixiaohua1020/simplest_librtmp_example


CSDN下載: http://download.csdn.net/detail/leixiaohua1020/8291757
 
本工程包含了LibRTMP的使用樣本,包含如下子工程:
simplest_librtmp_receive: 接收RTMP流媒體並在本地儲存成FLV格式的檔案。
simplest_librtmp_send_flv: 將FLV格式的視音頻檔案使用RTMP推送至RTMP流媒體伺服器。
simplest_librtmp_send264: 將記憶體中的H.264資料推送至RTMP流媒體伺服器。
 
 
 
 
 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.