rtmpdump 实现flv视频数据的rtmp推流功能


rtmpdump 是一个可以通过RTMP协议上推和下载流媒体的工具.

1、rtmpdump的编译

下载rtmpdump
http://download.csdn.net/detail/ternence_hsu/9766021 
(请不要再使用v2.3的版本,建议使用rtmpdump2.4的版本,v2.3版本中有几个bug在里面)
编译
解压后直接make
(编译之前需要先安装openssl,apt-get install openssl;apt-get install libssl-dev)
应用
如:./rtmpdump -r rtmp://172.16.1.65:1935/vod/mp4:sample.mp4 -v -o test.flv
    ./rtmpdump -r "rtmp://live.hkstv.hk.lxdns.com/live/hks" -o test1.flv -q
   
      -r url参数
      -v 是否为直播 
      -o 保存的文件

2、rtmpdump 实现 flv视频数据的rtmp推流功能

Makefle

#!/bin/sh
INCLUDE = /ternence/test/rtmpdump/
LIB_DIR = /ternence/test/rtmpdump/librtmp/
LDFLAGS = -lrtmp

SRC=rtmp_send.c

all:$(SRC)
	gcc -g -Wall $(SRC) -o target -I $(INCLUDE) -L $(LIB_DIR)  $(LDFLAGS)

rtmp_send.c

#include 
#include 
#include 
#include 
#ifndef WIN32
#include 
#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))

#define RTMP_SERVER_URL     "rtmp://172.16.1.65:1935/test1/myStream"
#define LOCAL_FILE          "test.flv"

/*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);
         */
        return 1;
}
 
void CleanupSockets()
{
        // WSACleanup();
        return;
}
 
//Publish using RTMP_SendPacket()
int publish_using_packet(){
         RTMP *rtmp=NULL;                           
         RTMPPacket *packet=NULL;
         uint32_t start_time=0;
         uint32_t now_time=0;
         uint32_t add_time_times=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(LOCAL_FILE,"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_SERVER_URL))
         {
                   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*1500);
         RTMPPacket_Reset(packet);
 
         packet->m_hasAbsTimestamp = 0;        
         packet->m_nChannel = 0x04;
         packet->m_nInfoField2 = rtmp->m_stream_id;
        
        while(1) {
 
         RTMP_LogPrintf("Start to send data ...\n");
         
         fp=fopen(LOCAL_FILE,"rb");
         if (!fp){
                   RTMP_LogPrintf("Open File Error.\n");
                   CleanupSockets();
                   return -1;
         }
        
         //jump over FLV Header
         fseek(fp,9,SEEK_SET);
         //jump over previousTagSizen
         fseek(fp,4,SEEK_CUR);   
         
         start_time=RTMP_GetTime();
         lasttime = 0;
         pre_frame_time = 0;
         RTMP_LogPrintf("add_time_times:%8u ms\n",add_time_times);

         while(1)
         {
                   //if((((now_time=RTMP_GetTime())-start_time) < (pre_frame_time)) && bNextIsKey){        
                   if(((now_time=RTMP_GetTime())-start_time) < (pre_frame_time)){        
                            //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;
                            }
                            usleep(10000); // 10ms
                            continue;
                   }
                  
                   //not quite the same as FLV spec
                   if(!ReadU8(&type,fp))
                   {
                        break;
                        printf("line:%d\n",__LINE__);
                   }                       

                   if(!ReadU24(&datalength,fp))
                   {
                        break;
                        printf("line:%d\n",__LINE__);
                   }    
                   if(!ReadTime(×tamp,fp))
                   {
                        break;
                        printf("line:%d\n",__LINE__);
                   }    
                   if(!ReadU24(&streamid,fp))
                   {
                        break;
                        printf("line:%d\n",__LINE__);
                   }    
 
                   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;
                        printf("line:%d\n",__LINE__);
                   }    

                   packet->m_headerType = RTMP_PACKET_SIZE_LARGE;
                   packet->m_nTimeStamp = timestamp + add_time_times;
                   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");
                            printf("line:%d\n",__LINE__);
                            break;
                   }
                   if (!RTMP_SendPacket(rtmp,packet,0)){
                            RTMP_Log(RTMP_LOGERROR,"Send Error\n");
                            printf("line:%d\n",__LINE__);
                            break;
                   }
 
                   if(!ReadU32(&preTagsize,fp))
                   {
                        break;
                        printf("line:%d\n",__LINE__);
                   }    
                           
                   if(!PeekU8(&type,fp))
                   {
                        break;
                        printf("line:%d\n",__LINE__);
                   }    
                   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");
         
         add_time_times += 237080;
        
         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(LOCAL_FILE,"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_SERVER_URL))
         {
                   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:%8u ms\n",pre_frame_time);
                                     lasttime=pre_frame_time;
                            }
                            sleep(1);
                            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;
}

源码的下载地址:

http://download.csdn.net/detail/ternence_hsu/9766189


你可能感兴趣的:(流媒体)