首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 网络技术 > 网络基础 >

RTMPdump 源代码分析 一: main()函数

2013-10-23 
RTMPdump 源代码分析 1: main()函数rtmpdump 是一个用来处理 RTMP 流媒体的工具包,支持 rtmp://, rtmpt://

RTMPdump 源代码分析 1: main()函数

rtmpdump 是一个用来处理 RTMP 流媒体的工具包,支持 rtmp://, rtmpt://, rtmpe://, rtmpte://, and rtmps:// 等。之前在学习RTMP协议的时候,发现没有讲它源代码的,只好自己分析,现在打算把自己学习的成果写出来,可能结果不一定都对,先暂且记录一下。


使用RTMPdump下载一个流媒体的大致流程是这样的:

intDownload(RTMP * rtmp,// connected RTMP object FILE * file, uint32_t dSeek, uint32_t dStopOffset, double duration, int bResume, char *metaHeader, uint32_t nMetaHeaderSize, char *initialFrame, int initialFrameType, uint32_t nInitialFrameSize, int nSkipKeyFrames, int bStdoutMode, int bLiveStream, int bHashes, int bOverrideBufferTime, uint32_t bufferTime, double *percent)// percentage downloaded [out]{  int32_t now, lastUpdate;  int bufferSize = 64 * 1024;  char *buffer = (char *) malloc(bufferSize);  int nRead = 0;  //long ftell(FILE *stream);  //返回当前文件指针  RTMP_LogPrintf("开始下载!\n");  off_t size = ftello(file);  unsigned long lastPercent = 0;  //时间戳  rtmp->m_read.timestamp = dSeek;  *percent = 0.0;  if (rtmp->m_read.timestamp)    {      RTMP_Log(RTMP_LOGDEBUG, "Continuing at TS: %d ms\n", rtmp->m_read.timestamp);    }  //是直播  if (bLiveStream)    {      RTMP_LogPrintf("直播流\n");    }  else    {      // print initial status      // Workaround to exit with 0 if the file is fully (> 99.9%) downloaded      if (duration > 0){  if ((double) rtmp->m_read.timestamp >= (double) duration * 999.0)    {      RTMP_LogPrintf("Already Completed at: %.3f sec Duration=%.3f sec\n",(double) rtmp->m_read.timestamp / 1000.0,(double) duration / 1000.0);      return RD_SUCCESS;    }  else    {      *percent = ((double) rtmp->m_read.timestamp) / (duration * 1000.0) * 100.0;      *percent = ((double) (int) (*percent * 10.0)) / 10.0;      RTMP_LogPrintf("%s download at: %.3f kB / %.3f sec (%.1f%%)\n",bResume ? "Resuming" : "Starting",(double) size / 1024.0, (double) rtmp->m_read.timestamp / 1000.0,*percent);    }}      else{  RTMP_LogPrintf("%s download at: %.3f kB\n",    bResume ? "Resuming" : "Starting",    (double) size / 1024.0);}    }  if (dStopOffset > 0)    RTMP_LogPrintf("For duration: %.3f sec\n", (double) (dStopOffset - dSeek) / 1000.0);  //各种设置参数到rtmp连接  if (bResume && nInitialFrameSize > 0)  rtmp->m_read.flags |= RTMP_READ_RESUME;  rtmp->m_read.initialFrameType = initialFrameType;  rtmp->m_read.nResumeTS = dSeek;  rtmp->m_read.metaHeader = metaHeader;  rtmp->m_read.initialFrame = initialFrame;  rtmp->m_read.nMetaHeaderSize = nMetaHeaderSize;  rtmp->m_read.nInitialFrameSize = nInitialFrameSize;  now = RTMP_GetTime();  lastUpdate = now - 1000;  do    {//从rtmp中把bufferSize(64k)个数据读入buffer      nRead = RTMP_Read(rtmp, buffer, bufferSize);      //RTMP_LogPrintf("nRead: %d\n", nRead);      if (nRead > 0){//函数:size_t fwrite(const void* buffer,size_t size,size_t count,FILE* stream);//向文件读入写入一个数据块。返回值:返回实际写入的数据块数目//(1)buffer:是一个指针,对fwrite来说,是要输出数据的地址。//(2)size:要写入内容的单字节数;   //(3)count:要进行写入size字节的数据项的个数;   //(4)stream:目标文件指针。   //(5)返回实际写入的数据项个数count。//关键。把buffer里面的数据写成文件if (fwrite(buffer, sizeof(unsigned char), nRead, file) !=      (size_t) nRead)    {      RTMP_Log(RTMP_LOGERROR, "%s: Failed writing, exiting!", __FUNCTION__);      free(buffer);      return RD_FAILED;    }//记录已经写入的字节数  size += nRead;  //RTMP_LogPrintf("write %dbytes (%.1f kB)\n", nRead, nRead/1024.0);  if (duration <= 0)// if duration unknown try to get it from the stream (onMetaData)    duration = RTMP_GetDuration(rtmp);  if (duration > 0)    {      // make sure we claim to have enough buffer time!      if (!bOverrideBufferTime && bufferTime < (duration * 1000.0)){  bufferTime = (uint32_t) (duration * 1000.0) + 5000;// 再加5s以确保buffertime足够长  RTMP_Log(RTMP_LOGDEBUG,      "Detected that buffer time is less than duration, resetting to: %dms",      bufferTime);  //重设Buffer长度  RTMP_SetBufferMS(rtmp, bufferTime);  //给服务器发送UserControl消息通知Buffer改变  RTMP_UpdateBufferMS(rtmp);}  //计算百分比      *percent = ((double) rtmp->m_read.timestamp) / (duration * 1000.0) * 100.0;      *percent = ((double) (int) (*percent * 10.0)) / 10.0;      if (bHashes){  if (lastPercent + 1 <= *percent)    {      RTMP_LogStatus("#");      lastPercent = (unsigned long) *percent;    }}      else{//设置显示数据的更新间隔200ms  now = RTMP_GetTime();  if (abs(now - lastUpdate) > 200)    {      RTMP_LogStatus("\r%.3f kB / %.2f sec (%.1f%%)",(double) size / 1024.0,(double) (rtmp->m_read.timestamp) / 1000.0, *percent);      lastUpdate = now;    }}    }  else    {//现在距离开机的毫秒数      now = RTMP_GetTime();  //每间隔200ms刷新一次数据      if (abs(now - lastUpdate) > 200){  if (bHashes)    RTMP_LogStatus("#");  else//size为已写入文件的字节数    RTMP_LogStatus("\r%.3f kB / %.2f sec", (double) size / 1024.0,      (double) (rtmp->m_read.timestamp) / 1000.0);  lastUpdate = now;}    }}#ifdef _DEBUG      else{  RTMP_Log(RTMP_LOGDEBUG, "zero read!");}#endif    }  while (!RTMP_ctrlC && nRead > -1 && RTMP_IsConnected(rtmp) && !RTMP_IsTimedout(rtmp));  free(buffer);  if (nRead < 0)//nRead是读取情况    nRead = rtmp->m_read.status;  /* Final status update */  if (!bHashes)    {      if (duration > 0){  *percent = ((double) rtmp->m_read.timestamp) / (duration * 1000.0) * 100.0;  *percent = ((double) (int) (*percent * 10.0)) / 10.0;  //输出  RTMP_LogStatus("\r%.3f kB / %.2f sec (%.1f%%)",    (double) size / 1024.0,    (double) (rtmp->m_read.timestamp) / 1000.0, *percent);}      else{  RTMP_LogStatus("\r%.3f kB / %.2f sec", (double) size / 1024.0,    (double) (rtmp->m_read.timestamp) / 1000.0);}    }  RTMP_Log(RTMP_LOGDEBUG, "RTMP_Read returned: %d", nRead);  //读取错误  if (bResume && nRead == -2)    {      RTMP_LogPrintf("Couldn't resume FLV file, try --skip %d\n\n",nSkipKeyFrames + 1);      return RD_FAILED;    }  //读取正确  if (nRead == -3)    return RD_SUCCESS;  //没读完...  if ((duration > 0 && *percent < 99.9) || RTMP_ctrlC || nRead < 0      || RTMP_IsTimedout(rtmp))    {      return RD_INCOMPLETE;    }  return RD_SUCCESS;}

以上内容是我能理解到的rtmpdump.c里面的内容。

热点排行