RTMPdump(libRTMP) 源代码分析系列文章:
RTMPdump (libRTMP) 源代码分析3: AMF编码
RTMPdump (libRTMP) 源代码分析6: 建立一个流媒体连接 (NetStream部分 1)
RTMPdump (libRTMP) 源代码分析9: 接收消息 (Message) (接收视音频数据)
使用RTMPdump下载一个流媒体的大致流程是这样的:
2.里面有很多提取信息的代码形如:rtmp.dlg->AppendCInfo("开始初始化Socket...");这些代码是我为了获取RTMP信息而自己加的,并不影响程序的执行。
- }
- else
- {
- //获取最后一个关键帧
- nStatus = GetLastKeyframe(file, nSkipKeyFrames,
- &dSeek, &initialFrame,
- &initialFrameType, &nInitialFrameSize);
- if (nStatus == RD_FAILED)
- {
- RTMP_Log(RTMP_LOGDEBUG, "Failed to get last keyframe.");
- goto clean;
- }
- if (dSeek == 0)
- {
- RTMP_Log(RTMP_LOGDEBUG,
- "Last keyframe is first frame in stream, switching from resume to normal mode!");
- bResume = FALSE;
- }
- }
- }
- //如果输出文件不存在
- if (!file)
- {
- if (bStdoutMode)
- {
- //直接输出到stdout
- file = stdout;
- SET_BINMODE(file);
- }
- else
- {
- //打开一个文件
- //w+b 读写打开或建立一个二进制文件,允许读和写。
- //-----------------
- rtmp.dlg->AppendCInfo("创建输出文件...");
- //-----------------------------
- file = fopen(flvFile, "w+b");
- if (file == 0)
- {
- //-----------------
- rtmp.dlg->AppendCInfo("创建输出文件失败!");
- //-----------------------------
- RTMP_LogPrintf("Failed to open file! %s\n", flvFile);
- return RD_FAILED;
- }
- rtmp.dlg->AppendCInfo("成功创建输出文件");
- }
- }
- #ifdef _DEBUG
- netstackdump = fopen("netstackdump", "wb");
- netstackdump_read = fopen("netstackdump_read", "wb");
- #endif
- while (!RTMP_ctrlC)
- {
- RTMP_Log(RTMP_LOGDEBUG, "Setting buffer time to: %dms", bufferTime);
- //设置Buffer时间
- //-----------------
- rtmp.dlg->AppendCInfo("设置缓冲(Buffer)的时间");
- //-----------------------------
- RTMP_SetBufferMS(&rtmp, bufferTime);
- //第一次执行
- if (first)
- {
- first = 0;
- RTMP_LogPrintf("开始建立连接!\n");
- //-----------------
- rtmp.dlg->AppendCInfo("开始建立连接(NetConnection)...");
- //-----------------------------
- //建立连接(Connect)
- if (!RTMP_Connect(&rtmp, NULL))
- {
- //-----------------
- rtmp.dlg->AppendCInfo("建立连接(NetConnection)失败!");
- //-----------------------------
- nStatus = RD_FAILED;
- break;
- }
- //-----------------
- rtmp.dlg->AppendCInfo("成功建立连接(NetConnection)");
- //-----------------------------
- //RTMP_Log(RTMP_LOGINFO, "已链接...");
- // User defined seek offset
- if (dStartOffset > 0)
- {
- // Don't need the start offset if resuming an existing file
- if (bResume)
- {
- RTMP_Log(RTMP_LOGWARNING,
- "Can't seek a resumed stream, ignoring --start option");
- dStartOffset = 0;
- }
- else
- {
- dSeek = dStartOffset;
- }
- }
- // Calculate the length of the stream to still play
- if (dStopOffset > 0)
- {
- // Quit if start seek is past required stop offset
- if (dStopOffset <= dSeek)
- {
- RTMP_LogPrintf("Already Completed\n");
- nStatus = RD_SUCCESS;
- break;
- }
- }
- //创建流(Stream)(发送connect命令消息后处理传来的数据)
- itoa(rtmp.m_inChunkSize,temp,10);
- rtmp.dlg->AppendB_R_Info("输入Chunk大小",temp);
- itoa(rtmp.m_outChunkSize,temp,10);
- rtmp.dlg->AppendB_R_Info("输出Chunk大小",temp);
- itoa(rtmp.m_stream_id,temp,10);
- rtmp.dlg->AppendB_R_Info("Stream ID",temp);
- itoa(rtmp.m_nBufferMS,temp,10);
- rtmp.dlg->AppendB_R_Info("Buffer时长(ms)",temp);
- itoa(rtmp.m_nServerBW,temp,10);
- rtmp.dlg->AppendB_R_Info("ServerBW",temp);
- itoa(rtmp.m_nClientBW,temp,10);
- rtmp.dlg->AppendB_R_Info("ClientBW",temp);
- itoa((int)rtmp.m_fEncoding,temp,10);
- rtmp.dlg->AppendB_R_Info("命令消息编码方法",temp);
- itoa((int)rtmp.m_fDuration,temp,10);
- rtmp.dlg->AppendB_R_Info("时长(s)",temp);
- rtmp.dlg->ShowBInfo();
- free(temp);
- //-----------------
- rtmp.dlg->AppendCInfo("开始建立网络流(NetStream)");
- //-----------------------------
- if (!RTMP_ConnectStream(&rtmp, dSeek))
- {
- //-----------------
- rtmp.dlg->AppendCInfo("建立网络流(NetStream)失败!");
- //-----------------
- nStatus = RD_FAILED;
- break;
- }
- //-----------------
- rtmp.dlg->AppendCInfo("成功建立网络流(NetStream)!");
- //-----------------
- }
- else
- {
- nInitialFrameSize = 0;
- if (retries)
- {
- RTMP_Log(RTMP_LOGERROR, "Failed to resume the stream\n\n");
- if (!RTMP_IsTimedout(&rtmp))
- nStatus = RD_FAILED;
- else
- nStatus = RD_INCOMPLETE;
- break;
- }
- RTMP_Log(RTMP_LOGINFO, "Connection timed out, trying to resume.\n\n");
- /* Did we already try pausing, and it still didn't work? */
- if (rtmp.m_pausing == 3)
- {
- /* Only one try at reconnecting... */
- retries = 1;
- dSeek = rtmp.m_pauseStamp;
- if (dStopOffset > 0)
- {
- if (dStopOffset <= dSeek)
- {
- RTMP_LogPrintf("Already Completed\n");
- nStatus = RD_SUCCESS;
- break;
- }
- }
- if (!RTMP_ReconnectStream(&rtmp, dSeek))
- {
- RTMP_Log(RTMP_LOGERROR, "Failed to resume the stream\n\n");
- if (!RTMP_IsTimedout(&rtmp))
- nStatus = RD_FAILED;
- else
- nStatus = RD_INCOMPLETE;
- break;
- }
- }
- else if (!RTMP_ToggleStream(&rtmp))
- {
- RTMP_Log(RTMP_LOGERROR, "Failed to resume the stream\n\n");
- if (!RTMP_IsTimedout(&rtmp))
- nStatus = RD_FAILED;
- else
- nStatus = RD_INCOMPLETE;
- break;
- }
- bResume = TRUE;
- }
- //-----------------
- //-----------------
- rtmp.dlg->AppendCInfo("开始将媒体数据写入文件");
- //-----------------
- //下载,写入文件
- nStatus = Download(&rtmp, file, dSeek, dStopOffset, duration, bResume,
- metaHeader, nMetaHeaderSize, initialFrame,
- initialFrameType, nInitialFrameSize,
- nSkipKeyFrames, bStdoutMode, bLiveStream, bHashes,
- bOverrideBufferTime, bufferTime, &percent);
- free(initialFrame);
- initialFrame = NULL;
- /* If we succeeded, we're done.
- */
- if (nStatus != RD_INCOMPLETE || !RTMP_IsTimedout(&rtmp) || bLiveStream)
- break;
- }
- //当下载完的时候
- if (nStatus == RD_SUCCESS)
- {
- //-----------------
- rtmp.dlg->AppendCInfo("写入文件完成");
- //-----------------
- RTMP_LogPrintf("Download complete\n");
- }
- //没下载完的时候
- else if (nStatus == RD_INCOMPLETE)
- {
- //-----------------
- rtmp.dlg->AppendCInfo("写入文件可能不完整");
- //-----------------
- RTMP_LogPrintf
- ("Download may be incomplete (downloaded about %.2f%%), try resuming\n",
- percent);
- }
- //后续清理工作
- clean:
- //-----------------
- rtmp.dlg->AppendCInfo("关闭连接");
- //-----------------
- RTMP_Log(RTMP_LOGDEBUG, "Closing connection.\n");
- RTMP_Close(&rtmp);
- rtmp.dlg->AppendCInfo("关闭文件");
- if (file != 0)
- fclose(file);
- rtmp.dlg->AppendCInfo("关闭Socket");
- CleanupSockets();
- #ifdef _DEBUG
- if (netstackdump != 0)
- fclose(netstackdump);
- if (netstackdump_read != 0)
- fclose(netstackdump_read);
- #endif
- return nStatus;
- }