static int rtmp_read(URLContext *s, uint8_t *buf, int size) { RTMP *r = s->priv_data; int nRead = 0; int retries = 20; do { if (url_interrupt_cb()>0) { nRead = 0; break; } nRead = RTMP_Read(r, buf, size); if (nRead > 0) { break; } else { if (r->m_read.status == RTMP_READ_EOF) { nRead = 0; break; } if(nRead == 0){ nRead = AVERROR(EAGAIN); usleep(1000*100); }else{ break; } } } while (retries-- > 0); return nRead; }
static int rtmp_read(URLContext *s, uint8_t *buf, int size) { LibRTMPContext *ctx = s->priv_data; RTMP *r = &ctx->rtmp; return RTMP_Read(r, buf, size); }
// @todo - read() is blocking, we would need to handle handle the socket ourself void RTMPWriter::read() { if(state != RW_STATE_INITIALIZED) { printf("error: cannot read because we're not initialized.\n"); return; } char buf[512]; int r = RTMP_Read(rtmp, buf, sizeof(buf)); printf("read: >> %d << \n", r); }
/* * Class: net_butterflytv_rtmp_client_RtmpClient * Method: read * Signature: ([CI)I */ JNIEXPORT jint JNICALL Java_net_ossrs_sea_RtmpClient_read (JNIEnv * env, jobject thiz, jbyteArray data_, jint offset, jint size) { char* data = malloc(size*sizeof(char)); int readCount = RTMP_Read(rtmp, data, size); if (readCount > 0) { (*env)->SetByteArrayRegion(env, data_, offset, readCount, data); // copy } free(data); return readCount; }
static ssize_t rtmp_recv(struct connectdata *conn, int sockindex, char *buf, size_t len, CURLcode *err) { RTMP *r = conn->proto.generic; ssize_t nread; (void)sockindex; /* unused */ nread = RTMP_Read(r, buf, curlx_uztosi(len)); if(nread < 0) { if(r->m_read.status == RTMP_READ_COMPLETE || r->m_read.status == RTMP_READ_EOF) { conn->data->req.size = conn->data->req.bytecount; nread = 0; } else *err = CURLE_RECV_ERROR; } return nread; }
static int rtmp_read(URLContext *s, uint8_t *buf, int size) { RTMP *r = s->priv_data; return RTMP_Read(r, buf, size); }
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; }
int RTMP_Recv_packet_internal(RTMP_Packet *pkt) { uint8_t hdr; uint8_t *p_hdr_recv; uint8_t fmt_type_map[4] = {11, 7, 3, 0}; uint8_t hdr_recv[18] = {0}; p_hdr_recv = hdr_recv; int read_ret = RTMP_Read((char*)&hdr, 1); if (0 >= read_ret) { printf("error, error no %d\n", WSAGetLastError()); return -1; } //if (197 == hdr) //{ // printf("video data come\n"); //} //根据hdr取得fmt_type uint8_t fmt_type_recv = hdr >> 6; pkt->fmt_type = fmt_type_recv; uint8_t character_code_channel_id = hdr & 0x3F; uint8_t hdr_size_recv = 0; /* 根据协议文档: Chunk Type = 0时,msg_header 有11个字节 Chunk Type = 1时,msg_header 有7个字节 Chunk Type = 2时,msg_header 有3个字节 Chunk Type = 3时,msg_header 有0个字节 */ //printf("fmt type %d\n", fmt_type_recv); hdr_size_recv += fmt_type_map[fmt_type_recv]; if (character_code_channel_id == 0) { hdr_size_recv += 1; } else if (character_code_channel_id == 1) { hdr_size_recv += 2; } else { hdr_size_recv += 0; } if (fmt_type_recv < 3) { read_ret = RTMP_Read((char*)hdr_recv, hdr_size_recv); if (read_ret <= 0) { printf("[RTMP_Recv_packet] line %d, error, errorno %d\n", __LINE__, WSAGetLastError()); return -1; } } if (character_code_channel_id == 0) { pkt->channel_id = (RTMPChannel)(hdr_recv[0] + 64); p_hdr_recv++; } else if (character_code_channel_id == 1) { pkt->channel_id = (RTMPChannel)(hdr_recv[1] * 256 + 64); p_hdr_recv++; p_hdr_recv++; } else { //printf("character_code_channel_id is %d\n", character_code_channel_id); pkt->channel_id = (RTMPChannel)character_code_channel_id; //printf("channel id %d\n", pkt->channel_id); } #if 0 printf("channel_id = %d, fmt_type = %d, data_size = %d, read_data_size %d\n", pkt->channel_id,fmt_type_recv, g_context.prev_packets[pkt->channel_id].data_size, g_context.prev_packets[pkt->channel_id].read_data_size); printf("hdr data: "); for (int i = 0; i < hdr_size_recv; i++) { printf("%d ", hdr_recv[i]); } printf("\n"); #endif //只有Chunk Type为0时,才有time_stamp if (fmt_type_recv == 0) { pkt->time_stamp = ((*p_hdr_recv) << 16) | ((*(p_hdr_recv + 1)) << 8) | ((*(p_hdr_recv + 2))); p_hdr_recv += 3; } //只有Chunk Type为1和2时,才有time delta if (fmt_type_recv == 1 || fmt_type_recv == 2) { pkt->time_delta = ((*p_hdr_recv) << 16) | ((*(p_hdr_recv + 1)) << 8) | ((*(p_hdr_recv + 2))); pkt->time_stamp = g_context.prev_packets[pkt->channel_id].time_stamp + pkt->time_delta; p_hdr_recv += 3; } if (fmt_type_recv >= 2) { pkt->msg_stream_id = g_context.prev_packets[pkt->channel_id].msg_stream_id; pkt->msg_type = g_context.prev_packets[pkt->channel_id].msg_type; pkt->data_size = g_context.prev_packets[pkt->channel_id].data_size; pkt->time_stamp = g_context.prev_packets[pkt->channel_id].time_stamp; } if (fmt_type_recv == 3) { //从以前保留的现场信息中恢复 if (g_context.prev_packets[pkt->channel_id].is_read_complete == 1) { //说明当前包和之前包不属于同一个msg } else { //说明当前包和之前报是属于同一个msg memcpy(pkt, &g_context.prev_packets[pkt->channel_id], sizeof(RTMP_Packet)); } //Sleep(10); } //只有Chunk Type为0、1时,才有msg length if (fmt_type_recv < 2) { pkt->data_size = ((*p_hdr_recv) << 16) | ((*(p_hdr_recv + 1)) << 8) | ((*(p_hdr_recv + 2))); if (pkt->data_size <= 0) { printf("data size %d error, break\n", pkt->data_size); } g_context.prev_packets[pkt->channel_id].data_size = pkt->data_size; p_hdr_recv += 3; } //只有Chunk Type为0、1时,才有msg type //msg type 1个字节 if (fmt_type_recv < 2) { pkt->msg_type = (RTMPPacketType)((*(p_hdr_recv))); g_context.prev_packets[pkt->channel_id].msg_type = pkt->msg_type; ++p_hdr_recv; } //只有Chunk Type 为0时,才有msg stream id //msg stream id为4个字节 if (0 == fmt_type_recv) { //坑爹,这个地方竟然是小端序 pkt->msg_stream_id = *(uint32_t *)(p_hdr_recv); } if (pkt->data_size - pkt->read_data_size < 0) { pkt->read_data_size = 0; } int to_read = RTMP_MIN(g_context.in_chunk_size, pkt->data_size - pkt->read_data_size); int read_data_size1 = 0; while (read_data_size1 < to_read) { int read_ret2 = RTMP_Read((char*)pkt->data + pkt->read_data_size + read_data_size1, to_read - read_data_size1); //for (int i = 0; i < read_ret2; i++) //{ // printf("0x%02x ", *((char*)pkt->data + pkt->read_data_size + read_data_size1 + i)); //} //printf("\n"); if (read_ret2 <= 0) { printf("Functio %s, nline %d error, errorno %d\n", __FUNCTION__, __LINE__, WSAGetLastError()); return -1; } read_data_size1 += read_ret2; } pkt->read_data_size += to_read; if (pkt->read_data_size < pkt->data_size) { pkt->is_read_complete = 0; } else { pkt->is_read_complete = 1; } g_context.prev_packets[pkt->channel_id].channel_id = pkt->channel_id; g_context.prev_packets[pkt->channel_id].is_read_complete = pkt->is_read_complete; g_context.prev_packets[pkt->channel_id].msg_type = pkt->msg_type; g_context.prev_packets[pkt->channel_id].data_size = pkt->data_size; g_context.prev_packets[pkt->channel_id].read_data_size = pkt->read_data_size; g_context.prev_packets[pkt->channel_id].time_stamp = pkt->time_stamp; //if (g_context.prev_packets[pkt->channel_id].time_stamp > 1800000) //{ // printf("break;\n"); //} //printf("read data size %d, total size %d\n", pkt->read_data_size, pkt->data_size); memcpy(g_context.prev_packets[pkt->channel_id].data, pkt->data, pkt->read_data_size); return 0; }
void processTCPrequest(STREAMING_SERVER * server, // server socket and state (our listening socket) int sockfd // client connection socket ) { char buf[512] = { 0 }; // answer buffer char header[2048] = { 0 }; // request header char *filename = NULL; // GET request: file name //512 not enuf char *buffer = NULL; // stream buffer char *ptr = NULL; // header pointer int len; size_t nRead = 0; RTMP rtmp = { 0 }; uint32_t dSeek = 0; // can be used to start from a later point in the stream // reset RTMP options to defaults specified upon invokation of streams RTMP_REQUEST req; char srvhead[] = "\r\nServer: HTTP-RTMP Stream Server " RTMPDUMP_VERSION "\r\n"; // timeout for http requests fd_set fds; struct timeval tv; char *status = "404 Not Found"; server->state = STREAMING_IN_PROGRESS; memcpy(&req, &defaultRTMPRequest, sizeof(RTMP_REQUEST)); memset(&tv, 0, sizeof(struct timeval)); tv.tv_sec = 5; // go through request lines //do { FD_ZERO(&fds); FD_SET(sockfd, &fds); if (select(sockfd + 1, &fds, NULL, NULL, &tv) <= 0) { RTMP_Log(RTMP_LOGERROR, "Request timeout/select failed, ignoring request"); goto quit; } else { nRead = recv(sockfd, header, 2047, 0); header[2047] = '\0'; RTMP_Log(RTMP_LOGDEBUG, "%s: header: %s", __FUNCTION__, header); if (strstr(header, "Range: bytes=") != 0) { // TODO check range starts from 0 and asking till the end. RTMP_LogPrintf("%s, Range request not supported\n", __FUNCTION__); len = sprintf(buf, "HTTP/1.0 416 Requested Range Not Satisfiable%s\r\n", srvhead); send(sockfd, buf, len, 0); goto quit; } if (strncmp(header, "GET", 3) == 0 && nRead > 4) { char *p = filename; filename = header + 4; // filter " HTTP/..." from end of request while (*p != '\0') { if (*p == ' ') { *p = '\0'; break; } p++; } } } //} while(!isHTTPRequestEOF(header, nRead)); // if we got a filename from the GET method if (filename != NULL) { RTMP_Log(RTMP_LOGDEBUG, "%s: Request header: %s", __FUNCTION__, filename); if (filename[0] == '/') { // if its not empty, is it /? ptr = filename + 1; // parse parameters if (*ptr == '?') { int len; ptr++; len = strlen(ptr); while (len >= 2) { // get position of the next '&' char *temp; char ich = *ptr; unsigned int nArgLen; char *arg; ptr++; if (*ptr != '=') goto filenotfound; // long parameters not (yet) supported ptr++; len -= 2; nArgLen = len; if ((temp = strstr(ptr, "&")) != 0) { nArgLen = temp - ptr; } arg = (char *) malloc((nArgLen + 1) * sizeof(char)); memcpy(arg, ptr, nArgLen * sizeof(char)); arg[nArgLen] = '\0'; //RTMP_Log(RTMP_LOGDEBUG, "%s: unescaping parameter: %s", __FUNCTION__, arg); http_unescape(arg); RTMP_Log(RTMP_LOGDEBUG, "%s: parameter: %c, arg: %s", __FUNCTION__, ich, arg); ptr += nArgLen + 1; len -= nArgLen + 1; if (!ParseOption(ich, arg, &req)) { status = "400 unknown option"; goto filenotfound; } } } } else { goto filenotfound; } } else { RTMP_LogPrintf("%s: No request header received/unsupported method\n", __FUNCTION__); } // do necessary checks right here to make sure the combined request of default values and GET parameters is correct if (!req.hostname.av_len) { RTMP_Log(RTMP_LOGERROR, "You must specify a hostname (--host) or url (-r \"rtmp://host[:port]/playpath\") containing a hostname"); status = "400 Missing Hostname"; goto filenotfound; } if (req.playpath.av_len == 0) { RTMP_Log(RTMP_LOGERROR, "You must specify a playpath (--playpath) or url (-r \"rtmp://host[:port]/playpath\") containing a playpath"); status = "400 Missing Playpath"; goto filenotfound;; } if (req.protocol == RTMP_PROTOCOL_UNDEFINED) { RTMP_Log(RTMP_LOGWARNING, "You haven't specified a protocol (--protocol) or rtmp url (-r), using default protocol RTMP"); req.protocol = RTMP_PROTOCOL_RTMP; } if (req.rtmpport == -1) { RTMP_Log(RTMP_LOGWARNING, "You haven't specified a port (--port) or rtmp url (-r), using default port"); req.rtmpport = 0; } if (req.rtmpport == 0) { if (req.protocol & RTMP_FEATURE_SSL) req.rtmpport = 443; else if (req.protocol & RTMP_FEATURE_HTTP) req.rtmpport = 80; else req.rtmpport = 1935; } if (req.tcUrl.av_len == 0) { char str[512] = { 0 }; req.tcUrl.av_len = snprintf(str, 511, "%s://%.*s:%d/%.*s", RTMPProtocolStringsLower[req.protocol], req.hostname.av_len, req.hostname.av_val, req.rtmpport, req.app.av_len, req.app.av_val); req.tcUrl.av_val = (char *) malloc(req.tcUrl.av_len + 1); strcpy(req.tcUrl.av_val, str); } if (req.swfVfy) { #ifdef CRYPTO if (RTMP_HashSWF(req.swfUrl.av_val, &req.swfSize, req.hash, req.swfAge) == 0) { req.swfHash.av_val = (char *)req.hash; req.swfHash.av_len = RTMP_SWF_HASHLEN; } #endif } // after validation of the http request send response header len = sprintf(buf, "HTTP/1.0 200 OK%sContent-Type: video/flv\r\n\r\n", srvhead); send(sockfd, buf, len, 0); // send the packets buffer = (char *) calloc(PACKET_SIZE, 1); // User defined seek offset if (req.dStartOffset > 0) { if (req.bLiveStream) RTMP_Log(RTMP_LOGWARNING, "Can't seek in a live stream, ignoring --seek option"); else dSeek += req.dStartOffset; } if (dSeek != 0) { RTMP_LogPrintf("Starting at TS: %d ms\n", dSeek); } RTMP_Log(RTMP_LOGDEBUG, "Setting buffer time to: %dms", req.bufferTime); RTMP_Init(&rtmp); RTMP_SetBufferMS(&rtmp, req.bufferTime); RTMP_SetupStream(&rtmp, req.protocol, &req.hostname, req.rtmpport, &req.sockshost, &req.playpath, &req.tcUrl, &req.swfUrl, &req.pageUrl, &req.app, &req.auth, &req.swfHash, req.swfSize, &req.flashVer, &req.subscribepath, dSeek, req.dStopOffset, req.bLiveStream, req.timeout); /* backward compatibility, we always sent this as true before */ if (req.auth.av_len) rtmp.Link.lFlags |= RTMP_LF_AUTH; rtmp.Link.extras = req.extras; rtmp.Link.token = req.token; rtmp.m_read.timestamp = dSeek; RTMP_LogPrintf("Connecting ... port: %d, app: %s\n", req.rtmpport, req.app); if (!RTMP_Connect(&rtmp, NULL)) { RTMP_LogPrintf("%s, failed to connect!\n", __FUNCTION__); } else { unsigned long size = 0; double percent = 0; double duration = 0.0; int nWritten = 0; int nRead = 0; do { nRead = RTMP_Read(&rtmp, buffer, PACKET_SIZE); if (nRead > 0) { if ((nWritten = send(sockfd, buffer, nRead, 0)) < 0) { RTMP_Log(RTMP_LOGERROR, "%s, sending failed, error: %d", __FUNCTION__, GetSockError()); goto cleanup; // we are in STREAMING_IN_PROGRESS, so we'll go to STREAMING_ACCEPTING } 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) { percent = ((double) (dSeek + 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); } } #ifdef _DEBUG else { RTMP_Log(RTMP_LOGDEBUG, "zero read!"); } #endif } while (server->state == STREAMING_IN_PROGRESS && nRead > -1 && RTMP_IsConnected(&rtmp) && nWritten >= 0); } cleanup: RTMP_LogPrintf("Closing connection... "); RTMP_Close(&rtmp); RTMP_LogPrintf("done!\n\n"); quit: if (buffer) { free(buffer); buffer = NULL; } if (sockfd) closesocket(sockfd); if (server->state == STREAMING_IN_PROGRESS) server->state = STREAMING_ACCEPTING; return; filenotfound: RTMP_LogPrintf("%s, %s, %s\n", __FUNCTION__, status, filename); len = sprintf(buf, "HTTP/1.0 %s%s\r\n", status, srvhead); send(sockfd, buf, len, 0); goto quit; }
/* * Read a new buffer from src->reqoffset, takes care of events * and seeking and such. */ static GstFlowReturn gst_rtmp_src_create (GstPushSrc * pushsrc, GstBuffer ** buffer) { GstRTMPSrc *src; GstBuffer *buf; GstMapInfo map; guint8 *data; guint todo; gsize bsize; int read; int size; src = GST_RTMP_SRC (pushsrc); g_return_val_if_fail (src->rtmp != NULL, GST_FLOW_ERROR); size = GST_BASE_SRC_CAST (pushsrc)->blocksize; GST_DEBUG ("reading from %" G_GUINT64_FORMAT ", size %u", src->cur_offset, size); buf = gst_buffer_new_allocate (NULL, size, NULL); if (G_UNLIKELY (buf == NULL)) { GST_ERROR_OBJECT (src, "Failed to allocate %u bytes", size); return GST_FLOW_ERROR; } bsize = todo = size; gst_buffer_map (buf, &map, GST_MAP_WRITE); data = map.data; read = bsize = 0; while (todo > 0) { read = RTMP_Read (src->rtmp, (char *) data, todo); if (G_UNLIKELY (read == 0 && todo == size)) { goto eos; } else if (G_UNLIKELY (read == 0)) { todo = 0; break; } if (G_UNLIKELY (read < 0)) goto read_failed; if (read < todo) { data += read; todo -= read; bsize += read; } else { bsize += todo; todo = 0; } GST_LOG (" got size %d", read); } gst_buffer_unmap (buf, &map); gst_buffer_resize (buf, 0, bsize); if (src->discont) { GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT); src->discont = FALSE; } GST_BUFFER_TIMESTAMP (buf) = src->last_timestamp; GST_BUFFER_OFFSET (buf) = src->cur_offset; src->cur_offset += size; if (src->last_timestamp == GST_CLOCK_TIME_NONE) src->last_timestamp = src->rtmp->m_mediaStamp * GST_MSECOND; else src->last_timestamp = MAX (src->last_timestamp, src->rtmp->m_mediaStamp * GST_MSECOND); GST_LOG_OBJECT (src, "Created buffer of size %u at %" G_GINT64_FORMAT " with timestamp %" GST_TIME_FORMAT, size, GST_BUFFER_OFFSET (buf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf))); /* we're done, return the buffer */ *buffer = buf; return GST_FLOW_OK; read_failed: { gst_buffer_unref (buf); GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), ("Failed to read data")); return GST_FLOW_ERROR; } eos: { gst_buffer_unref (buf); GST_DEBUG_OBJECT (src, "Reading data gave EOS"); return GST_FLOW_EOS; } }
int Download(RTMP * rtmp, FILE * file, int bStdoutMode, int bLiveStream) { int32_t now, lastUpdate; int bufferSize = 64 * 1024; char *buffer; int nRead = 0; off_t size = ftello(file); rtmp->m_read.timestamp = 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 { RTMP_LogPrintf("Starting download at: %.3f kB\n", (double) size / 1024.0); } rtmp->m_read.initialFrameType = 0; rtmp->m_read.nResumeTS = 0; rtmp->m_read.metaHeader = 0; rtmp->m_read.initialFrame = 0; rtmp->m_read.nMetaHeaderSize = 0; rtmp->m_read.nInitialFrameSize = 0; buffer = (char *) malloc(bufferSize); unsigned long lasttimestamp = 0 ; unsigned long streamlasttimestamp = 0 ; 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; ///////log struct timeval tnow ; gettimeofday(&tnow, NULL); unsigned long t2_ms = tnow.tv_sec * 1000 + tnow.tv_usec/1000; if( lasttimestamp == 0 ) { streamlasttimestamp = rtmp->m_read.timestamp ;//这个是音频流里面的时间戳。这个算出来的就是音频的码率 lasttimestamp = t2_ms ; //这个是我们收到数据的时间戳,这个算出来的是音频的实际接收码率 continue ; } float tmprate = (double)8*nRead/1024/( (double)(t2_ms-lasttimestamp)/1000) ; float streamtmprate = (double)8*nRead/1024/( (double)(rtmp->m_read.timestamp - streamlasttimestamp)/1000) ; KULV_LOG("RTMP_Read,ms,nread:%d\trecv timediff:%dms,receive rate:%.2fkbps\tstream timediff:%dms,stream rate:%.1fkbps.", nRead, t2_ms-lasttimestamp, tmprate, rtmp->m_read.timestamp - streamlasttimestamp, streamtmprate ); lasttimestamp = t2_ms ; streamlasttimestamp = rtmp->m_read.timestamp ; now = RTMP_GetTime(); if (abs(now - lastUpdate) > 200) { RTMP_LogStatus("\r%.3f kB / %.2f sec. recv speed:%.2f kbps. stream rate:%.2f kbps.", (double) size / 1024.0, (double) (rtmp->m_read.timestamp) / 1000.0, tmprate, streamtmprate); lastUpdate = now; } } else { RTMP_Log(RTMP_LOGDEBUG, "zero read!"); 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; RTMP_Log(RTMP_LOGDEBUG, "RTMP_Read returned: %d", nRead); if (nRead == -3) return RD_SUCCESS; if ( RTMP_ctrlC || nRead < 0 || RTMP_IsTimedout(rtmp)) { return RD_INCOMPLETE; } return RD_SUCCESS; }
static int download(char *osis, int chapter) { struct stat sb; int size, pipe; char pageurl[256]; char playpath[256]; char path[256]; double duration = 0; RTMP_Init(rtmp); rtmp->Link.protocol = RTMP_PROTOCOL_RTMP; rtmp->Link.hostname = (AVal)AVC(HOSTNAME); rtmp->Link.port = 1935; rtmp->Link.app = (AVal)AVC(APP); rtmp->Link.flashVer = (AVal)AVC(FLASHVER); rtmp->Link.swfUrl = (AVal)AVC(SWFURL); rtmp->Link.tcUrl = (AVal)AVC(TCURL); sprintf(pageurl, PAGEURL "%s/%s/%s.%d", author, version, osis, chapter); rtmp->Link.pageUrl = (AVal){pageurl, strlen(pageurl)}; sprintf(playpath, "%s-%s/%s.%d", version, author, osis, chapter); rtmp->Link.playpath = (AVal){playpath, strlen(playpath)}; printf("downloading %s .....", playpath); fflush(stdout); sprintf(path, "%s.mp3", playpath); if (stat(path, &sb) == 0 && sb.st_size == 0) { unlink(path); } pipe = open(path, O_WRONLY | O_CREAT | O_EXCL, 0644); if (pipe < 0) { perror("open"); return errno; } size = RTMP_Connect(rtmp, NULL); if (size == FALSE) { perror("rtmp_conect"); return EINVAL; } do { size = RTMP_Read(rtmp, buffer, BUFSIZ); if (duration <= 0) { duration = RTMP_GetDuration(rtmp); } if (rtmp->m_read.status == RTMP_READ_COMPLETE) { size = 0; break; } if (!RTMP_IsConnected(rtmp)) { size = -1; break; } if (size > 0) { write(pipe, buffer, size); if (duration > 0) { printf("\b\b\b\b\b%04.1f%%", ((double)rtmp->m_read.timestamp) / (duration * 10.0)); fflush(stdout); } } } while (size >= 0); close(pipe); RTMP_Close(rtmp); if (size != 0 && stat(path, &sb) == 0) { if (sb.st_size == 0) { unlink(path); } else { sprintf(buffer, "%s.failed", path); rename(path, buffer); } } printf("\b\b\b\b\b%s\n", size == 0 ? "completed" : "incomplete"); return size; }
int main(int argc, char* argv[]) { InitSockets(); double duration = -1; int nRead; //is live stream ? bool bLiveStream = TRUE; int bufsize = 1024 * 1024 * 10; char *buf = (char*)malloc(bufsize); memset(buf, 0, bufsize); long countbufsize = 0; FILE *fp = fopen("receive.flv", "wb"); if (!fp) { RTMP_LogPrintf("Open File Error.\n"); CleanupSockets(); return -1; } /* set log level */ RTMP_LogLevel loglvl = RTMP_LOGDEBUG; RTMP_LogSetLevel(loglvl); RTMP *rtmp = RTMP_Alloc(); RTMP_Init(rtmp); //set connection timeout,default 30s rtmp->Link.timeout = 10; char* rtmpFilePath = "d:\\rtmp.raw"; rtmp->m_pRTMPFile = fopen(rtmpFilePath,"rb"); if (!rtmp->m_pRTMPFile) { RTMP_LogPrintf("Failed to open File :%s\n", rtmpFilePath); return FALSE; } // HKS's live URL if(!RTMP_SetupURL(rtmp, "rtmp://live.hkstv.hk.lxdns.com/live/hks")) { RTMP_Log(RTMP_LOGERROR, "SetupURL Err\n"); RTMP_Free(rtmp); CleanupSockets(); return -1; } if (bLiveStream) { rtmp->Link.lFlags |= RTMP_LF_LIVE; } //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; } while(nRead = RTMP_Read(rtmp, buf, bufsize)) { fwrite(buf, 1, nRead, fp); countbufsize += nRead; RTMP_LogPrintf("Receive: %5dByte, Total: %5.2fkB\n", nRead, countbufsize * 1.0 / 1024); } if(fp) fclose(fp); if(fpPcap) fclose(fpPcap); if (rtmp->m_pRTMPFile) { fclose(rtmp->m_pRTMPFile); } if(buf) { free(buf); } if(rtmp) { RTMP_Close(rtmp); RTMP_Free(rtmp); CleanupSockets(); rtmp = NULL; } return 0; }
int rtmp_read(LibRTMPContext *ctx , char *buf, int size) { RTMP *r = &ctx->rtmp; return RTMP_Read(r, buf, size); }