int QRtmp::download() { qint32 now, lastUpdate; int bufferSize = 64 * 1024; char *buffer = (char *) malloc(bufferSize); int nRead = 0; off_t size = 0; m_rtmp->m_read.timestamp = dSeek; m_percent = 0.0; if(m_rtmp->m_read.timestamp) RTMP_Log(RTMP_LOGDEBUG, "Continuing at TS: %d ms\n", m_rtmp->m_read.timestamp); if(m_bLiveStream) RTMP_LogPrintf("Starting Live Stream\n"); else { // print initial status // Workaround to exit with 0 if the file is fully (> 99.9%) downloaded if(m_duration > 0) { if((double) m_rtmp->m_read.timestamp >= (double) m_duration * 999.0) { RTMP_LogPrintf("Already Completed at: %.3f sec Duration=%.3f sec\n", (double) m_rtmp->m_read.timestamp / 1000.0, (double) m_duration / 1000.0); return RD_SUCCESS; } else { m_percent = ((double) m_rtmp->m_read.timestamp) / (m_duration * 1000.0) * 100.0; m_percent = ((double) (int) (m_percent * 10.0)) / 10.0; RTMP_LogPrintf("%s download at: %.3f kB / %.3f sec (%.1f%%)\n", m_bResume ? "Resuming" : "Starting", (double) size / 1024.0, (double) m_rtmp->m_read.timestamp / 1000.0, m_percent); } } else { RTMP_LogPrintf("%s download at: %.3f kB\n", m_bResume ? "Resuming" : "Starting", (double) size / 1024.0); } } if(dStopOffset > 0) RTMP_LogPrintf("For duration: %.3f sec\n", (double) (dStopOffset - dSeek) / 1000.0); m_rtmp->m_read.nResumeTS = dSeek; now = RTMP_GetTime(); lastUpdate = now - 1000; do { nRead = RTMP_Read(m_rtmp, buffer, bufferSize); //RTMP_LogPrintf("nRead: %d\n", nRead); if(nRead > 0) { if(m_destFile.isOpen()) { if(m_destFile.write(buffer, nRead) != nRead) { setError(QString("Can't write to %1 - %2").arg(m_destFile.fileName()).arg(m_destFile.errorString())); m_stop = true; } } else emit readData(QByteArray(buffer, nRead)); m_destFile.flush(); size += nRead; setStreamIsRunning(true); //RTMP_LogPrintf("write %dbytes (%.1f kB)\n", nRead, nRead/1024.0); if(m_duration <= 0) // if duration unknown try to get it from the stream (onMetaData) m_duration = RTMP_GetDuration(m_rtmp); if(m_duration > 0) { // make sure we claim to have enough buffer time! if(!m_bOverrideBufferTime && m_bufferTime < (m_duration * 1000.0)) { m_bufferTime = (quint32) (m_duration * 1000.0) + 5000; // extra 5sec to make sure we've got enough RTMP_Log(RTMP_LOGDEBUG, "Detected that buffer time is less than duration, resetting to: %dms", m_bufferTime); RTMP_SetBufferMS(m_rtmp, m_bufferTime); RTMP_UpdateBufferMS(m_rtmp); } m_percent = ((double) m_rtmp->m_read.timestamp) / (m_duration * 1000.0) * 100.0; m_percent = ((double) (int) (m_percent * 10.0)) / 10.0; now = RTMP_GetTime(); if(abs(now - lastUpdate) > 200) { RTMP_LogStatus("\r%.3f kB / %.2f sec (%.1f%%)", (double) size / 1024.0, (double) (m_rtmp->m_read.timestamp) / 1000.0, m_percent); lastUpdate = now; } } else { now = RTMP_GetTime(); if(abs(now - lastUpdate) > 200) { RTMP_LogStatus("\r%.3f kB / %.2f sec", (double) size / 1024.0, (double) (m_rtmp->m_read.timestamp) / 1000.0); lastUpdate = now; } } } }while (!m_stop && nRead > -1 && RTMP_IsConnected(m_rtmp) && !RTMP_IsTimedout(m_rtmp)); free(buffer); if (nRead < 0) nRead = m_rtmp->m_read.status; /* Final status update */ if(m_duration > 0) { m_percent = ((double) m_rtmp->m_read.timestamp) / (m_duration * 1000.0) * 100.0; m_percent = ((double) (int) (m_percent * 10.0)) / 10.0; RTMP_LogStatus("\r%.3f kB / %.2f sec (%.1f%%)", (double) size / 1024.0, (double) (m_rtmp->m_read.timestamp) / 1000.0, m_percent); } else { RTMP_LogStatus("\r%.3f kB / %.2f sec", (double) size / 1024.0, (double) (m_rtmp->m_read.timestamp) / 1000.0); } RTMP_Log(RTMP_LOGDEBUG, "RTMP_Read returned: %d", nRead); if(m_bResume && nRead == -2) { RTMP_LogPrintf("Couldn't resume FLV file, try --skip %d\n\n", m_nSkipKeyFrames + 1); return RD_FAILED; } if(nRead == -3) return RD_SUCCESS; if((m_duration > 0 && m_percent < 99.9) || m_stop || nRead < 0 || RTMP_IsTimedout(m_rtmp)) { return RD_INCOMPLETE; } return RD_SUCCESS; }
int Download(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 bRealtimeStream, 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; 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("Starting Live Stream\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 (bRealtimeStream) RTMP_LogPrintf(" in approximately realtime (disabled BUFX speedup hack)\n"); } if (dStopOffset > 0) RTMP_LogPrintf("For duration: %.3f sec\n", (double) (dStopOffset - dSeek) / 1000.0); 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; buffer = (char *) malloc(bufferSize); now = RTMP_GetTime(); lastUpdate = now - 1000; do { nRead = RTMP_Read(rtmp, buffer, bufferSize); //RTMP_LogPrintf("nRead: %d\n", nRead); if (nRead > 0) { 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; // extra 5sec to make sure we've got enough RTMP_Log(RTMP_LOGDEBUG, "Detected that buffer time is less than duration, resetting to: %dms", bufferTime); RTMP_SetBufferMS(rtmp, bufferTime); 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 { 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(); if (abs(now - lastUpdate) > 200) { if (bHashes) RTMP_LogStatus("#"); else RTMP_LogStatus("\r%.3f kB / %.2f sec", (double) size / 1024.0, (double) (rtmp->m_read.timestamp) / 1000.0); lastUpdate = now; } } } else { #ifdef _DEBUG RTMP_Log(RTMP_LOGDEBUG, "zero read!"); #endif if (rtmp->m_read.status == RTMP_READ_EOF) break; } } while (!RTMP_ctrlC && nRead > -1 && RTMP_IsConnected(rtmp) && !RTMP_IsTimedout(rtmp)); free(buffer); if (nRead < 0) 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; }