static void send_cb(EV_P_ ev_async *w, int revents) { jack_ringbuffer_read(ringbuf, framebuf, (buffer_samples * sizeof(jack_default_audio_sample_t)) ); int rtmp_size = RTMP_MAX_HEADER_SIZE + 1 + buffer_samples * 5 / 4 + 7200; unsigned char *rtmp_buffer = malloc(rtmp_size); int mp3size = lame_encode_buffer_ieee_float(mp3, (const float *) framebuf, NULL, buffer_samples, rtmp_buffer + RTMP_MAX_HEADER_SIZE + 1, rtmp_size - RTMP_MAX_HEADER_SIZE - 1); if ( mp3size < 0 ) { fprintf(stderr, "mp3 encoding error %d . buffer_samples %d\n", mp3size, buffer_samples); } else { if (!start_time) { rtmp_w.m_headerType = RTMP_PACKET_SIZE_LARGE; rtmp_w.m_nInfoField2 = rtmp_o->m_stream_id; rtmp_w.m_nTimeStamp = 0; start_time = RTMP_GetTime(); } else { rtmp_w.m_headerType = RTMP_PACKET_SIZE_MEDIUM; rtmp_w.m_nTimeStamp = RTMP_GetTime()-start_time; } rtmp_w.m_nChannel = 0x04; // source channel rtmp_w.m_body = (char *) rtmp_buffer + RTMP_MAX_HEADER_SIZE; rtmp_w.m_nBodySize = mp3size + 1; rtmp_w.m_packetType = RTMP_PACKET_TYPE_AUDIO; rtmp_buffer[RTMP_MAX_HEADER_SIZE] = FLV_CODECID_MP3 | FLV_SAMPLERATE_44100HZ | FLV_SAMPLESSIZE_16BIT | FLV_MONO; if ( !RTMP_SendPacket(rtmp_o, &rtmp_w, FALSE) ) { // queue учитывается только для INVOKE fprintf(stderr, "RTMP_SendPacket error\n"); } //fprintf(stderr, "sent %d bytes of data. time: %d\n", (buffer_samples * (int)sizeof(jack_default_audio_sample_t)), rtmp_w.m_nTimeStamp ); } free(rtmp_buffer); }
int ExecuteAuthenticationDetails(RTMP *r, AMFObject *proplist, YLENGStream *yle) { long authResult = -1; int i; for (i=0; i<AMF_CountProp(proplist); i++) { AVal name; AMFObjectProperty *prop = AMF_GetProp(proplist, NULL, i); AMFProp_GetName(prop, &name); if (AVMATCH(&name, &av_locatedInBroadcastTerritory)) { yle->locatedInBroadcastTerritory = AMFProp_GetBoolean(prop); } else if (AVMATCH(&name, &av_randomAuth)) { authResult = ((long)AMFProp_GetNumber(prop) + 447537687) % 6834253; } else if (AVMATCH(&name, &av_tvFeeActivated)) { yle->tvFeeActivated = AMFProp_GetBoolean(prop); } } if (authResult != -1) { RTMPPacket packet; char pbuf[128], *pend = pbuf+sizeof(pbuf); packet.m_nChannel = 0x03; // control channel packet.m_headerType = RTMP_PACKET_SIZE_LARGE; packet.m_packetType = 0x11; // FLEX MESSAGE packet.m_nTimeStamp = RTMP_GetTime(); packet.m_nInfoField2 = 0; packet.m_hasAbsTimestamp = 0; packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE; char *enc = packet.m_body; *enc++ = 0x00; // Unknown enc = AMF_EncodeString(enc, pend, &av_authenticateRandomNumber); enc = AMF_EncodeNumber(enc, pend, 0); *enc++ = AMF_NULL; enc = AMF_EncodeNumber(enc, pend, (double)authResult); packet.m_nBodySize = enc-packet.m_body; RTMP_Log(RTMP_LOGDEBUG, "sending authenticateRandomNumber"); return RTMP_SendPacket(r, &packet, FALSE); } return FALSE; }
int RequestData(RTMP *r, YLENGStream *yle) { RTMPPacket packet; char pbuf[128], *pend = pbuf+sizeof(pbuf); AVal clipID; packet.m_nChannel = 0x03; // control channel packet.m_headerType = RTMP_PACKET_SIZE_LARGE; packet.m_packetType = 0x11; // FLEX MESSAGE packet.m_nTimeStamp = RTMP_GetTime(); packet.m_nInfoField2 = 0; packet.m_hasAbsTimestamp = 0; packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE; char *enc = packet.m_body; *enc++ = 0x00; // Unknown enc = AMF_EncodeString(enc, pend, &av_requestData); enc = AMF_EncodeNumber(enc, pend, 0); *enc++ = AMF_NULL; enc = AMF_EncodeString(enc, pend, &av_e0); if ((r->Link.lFlags & RTMP_LF_LIVE) != 0) { char *tmp = malloc(yle->clipID.av_len+12); strcpy(tmp, "streams/fi/"); strncat(tmp, yle->clipID.av_val, yle->clipID.av_len); STR2AVAL(clipID, tmp); enc = AMF_EncodeString(enc, pend, &clipID); free(tmp); } else { char *tmp = malloc(yle->clipID.av_len+2); strcpy(tmp, "/"); strncat(tmp, yle->clipID.av_val, yle->clipID.av_len); STR2AVAL(clipID, tmp); enc = AMF_EncodeString(enc, pend, &clipID); free(tmp); } if (!enc) { RTMP_Log(RTMP_LOGERROR, "Buffer too short in RequestData"); return FALSE; } packet.m_nBodySize = enc-packet.m_body; return RTMP_SendPacket(r, &packet, FALSE); }
static void rtmp_rvod_pause_notify(void* ctx, int paused, double ts) { RTMP_LogPrintf("rtmp pause %d ts %lf\n", paused, ts); if (!ctx) { return; } t_rtmp_vod_ctx *c = ctx; c->paused = paused; if (paused) { c->start_timestamp = ts; } else { c->start_timestamp = ts; c->epoch = RTMP_GetTime(); } }
int rtmp_rvod_start(t_rtmp_vod_ctx* ctx, const char *publishurl, const char*deviceid) { RTMP *rtmp; if (!ctx) { return -1; } if (ctx->rtmp) { return -1; } rtmp = rtmp_create_publishstream(publishurl, 30, deviceid); ctx->rtmp = rtmp; if (!rtmp) { /*create connection error*/ return -1; } /*set the notificaiton function*/ rtmp->pause_notify = rtmp_rvod_pause_notify; rtmp->seek_notify = rtmp_rvod_seek_notify; rtmp->stop_notify = rtmp_rvod_stop_notify; rtmp->rvodCtx = ctx; ctx->epoch = RTMP_GetTime(); ctx->start_timestamp = 0; ont_platform_sleep(300);/* for rvod, need sleep a while to avoid server drop frame*/ rtmp_send_metadata(rtmp, &ctx->meta); ctx->next_videosampleid = 1; /*start from 1*/ ctx->next_audiosampleid = 1; return 0; }
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; }
// Returns 0 for OK/Failed/error, 1 for 'Stop or Complete' int ServeInvoke(STREAMING_SERVER *server, RTMP * r, RTMPPacket *packet, unsigned int offset) { const char *body; unsigned int nBodySize; int ret = 0, nRes; body = packet->m_body + offset; nBodySize = packet->m_nBodySize - offset; if (body[0] != 0x02) // make sure it is a string method name we start with { RTMP_Log(RTMP_LOGWARNING, "%s, Sanity failed. no string method in invoke packet", __FUNCTION__); return 0; } AMFObject obj; nRes = AMF_Decode(&obj, body, nBodySize, FALSE); if (nRes < 0) { RTMP_Log(RTMP_LOGERROR, "%s, error decoding invoke packet", __FUNCTION__); return 0; } AMF_Dump(&obj); AVal method; AMFProp_GetString(AMF_GetProp(&obj, NULL, 0), &method); double txn = AMFProp_GetNumber(AMF_GetProp(&obj, NULL, 1)); RTMP_Log(RTMP_LOGDEBUG, "%s, client invoking <%s>", __FUNCTION__, method.av_val); if (AVMATCH(&method, &av_connect)) { AMFObject cobj; AVal pname, pval; int i; server->connect = packet->m_body; packet->m_body = NULL; AMFProp_GetObject(AMF_GetProp(&obj, NULL, 2), &cobj); for (i=0; i<cobj.o_num; i++) { pname = cobj.o_props[i].p_name; pval.av_val = NULL; pval.av_len = 0; if (cobj.o_props[i].p_type == AMF_STRING) pval = cobj.o_props[i].p_vu.p_aval; if (AVMATCH(&pname, &av_app)) { r->Link.app = pval; pval.av_val = NULL; if (!r->Link.app.av_val) r->Link.app.av_val = ""; server->arglen += 6 + pval.av_len; server->argc += 2; } else if (AVMATCH(&pname, &av_flashVer)) { r->Link.flashVer = pval; pval.av_val = NULL; server->arglen += 6 + pval.av_len; server->argc += 2; } else if (AVMATCH(&pname, &av_swfUrl)) { r->Link.swfUrl = pval; pval.av_val = NULL; server->arglen += 6 + pval.av_len; server->argc += 2; } else if (AVMATCH(&pname, &av_tcUrl)) { r->Link.tcUrl = pval; pval.av_val = NULL; server->arglen += 6 + pval.av_len; server->argc += 2; } else if (AVMATCH(&pname, &av_pageUrl)) { r->Link.pageUrl = pval; pval.av_val = NULL; server->arglen += 6 + pval.av_len; server->argc += 2; } else if (AVMATCH(&pname, &av_audioCodecs)) { r->m_fAudioCodecs = cobj.o_props[i].p_vu.p_number; } else if (AVMATCH(&pname, &av_videoCodecs)) { r->m_fVideoCodecs = cobj.o_props[i].p_vu.p_number; } else if (AVMATCH(&pname, &av_objectEncoding)) { r->m_fEncoding = cobj.o_props[i].p_vu.p_number; } } /* Still have more parameters? Copy them */ if (obj.o_num > 3) { int i = obj.o_num - 3; r->Link.extras.o_num = i; r->Link.extras.o_props = malloc(i*sizeof(AMFObjectProperty)); memcpy(r->Link.extras.o_props, obj.o_props+3, i*sizeof(AMFObjectProperty)); obj.o_num = 3; server->arglen += countAMF(&r->Link.extras, &server->argc); } SendConnectResult(r, txn); } else if (AVMATCH(&method, &av_createStream)) { SendResultNumber(r, txn, ++server->streamID); } else if (AVMATCH(&method, &av_getStreamLength)) { SendResultNumber(r, txn, 10.0); } else if (AVMATCH(&method, &av_play)) { char *file, *p, *q, *cmd, *ptr; AVal *argv, av; int len, argc; uint32_t now; RTMPPacket pc = {0}; AMFProp_GetString(AMF_GetProp(&obj, NULL, 3), &r->Link.playpath); /* r->Link.seekTime = AMFProp_GetNumber(AMF_GetProp(&obj, NULL, 4)); if (obj.o_num > 5) r->Link.length = AMFProp_GetNumber(AMF_GetProp(&obj, NULL, 5)); */ if (r->Link.tcUrl.av_len) { len = server->arglen + r->Link.playpath.av_len + 4 + sizeof("rtmpdump") + r->Link.playpath.av_len + 12; server->argc += 5; cmd = malloc(len + server->argc * sizeof(AVal)); ptr = cmd; argv = (AVal *)(cmd + len); argv[0].av_val = cmd; argv[0].av_len = sizeof("rtmpdump")-1; ptr += sprintf(ptr, "rtmpdump"); argc = 1; argv[argc].av_val = ptr + 1; argv[argc++].av_len = 2; argv[argc].av_val = ptr + 5; ptr += sprintf(ptr," -r \"%s\"", r->Link.tcUrl.av_val); argv[argc++].av_len = r->Link.tcUrl.av_len; if (r->Link.app.av_val) { argv[argc].av_val = ptr + 1; argv[argc++].av_len = 2; argv[argc].av_val = ptr + 5; ptr += sprintf(ptr, " -a \"%s\"", r->Link.app.av_val); argv[argc++].av_len = r->Link.app.av_len; } if (r->Link.flashVer.av_val) { argv[argc].av_val = ptr + 1; argv[argc++].av_len = 2; argv[argc].av_val = ptr + 5; ptr += sprintf(ptr, " -f \"%s\"", r->Link.flashVer.av_val); argv[argc++].av_len = r->Link.flashVer.av_len; } if (r->Link.swfUrl.av_val) { argv[argc].av_val = ptr + 1; argv[argc++].av_len = 2; argv[argc].av_val = ptr + 5; ptr += sprintf(ptr, " -W \"%s\"", r->Link.swfUrl.av_val); argv[argc++].av_len = r->Link.swfUrl.av_len; } if (r->Link.pageUrl.av_val) { argv[argc].av_val = ptr + 1; argv[argc++].av_len = 2; argv[argc].av_val = ptr + 5; ptr += sprintf(ptr, " -p \"%s\"", r->Link.pageUrl.av_val); argv[argc++].av_len = r->Link.pageUrl.av_len; } if (r->Link.extras.o_num) { ptr = dumpAMF(&r->Link.extras, ptr, argv, &argc); AMF_Reset(&r->Link.extras); } argv[argc].av_val = ptr + 1; argv[argc++].av_len = 2; argv[argc].av_val = ptr + 5; ptr += sprintf(ptr, " -y \"%.*s\"", r->Link.playpath.av_len, r->Link.playpath.av_val); argv[argc++].av_len = r->Link.playpath.av_len; av = r->Link.playpath; /* strip trailing URL parameters */ q = memchr(av.av_val, '?', av.av_len); if (q) { if (q == av.av_val) { av.av_val++; av.av_len--; } else { av.av_len = q - av.av_val; } } /* strip leading slash components */ for (p=av.av_val+av.av_len-1; p>=av.av_val; p--) if (*p == '/') { p++; av.av_len -= p - av.av_val; av.av_val = p; break; } /* skip leading dot */ if (av.av_val[0] == '.') { av.av_val++; av.av_len--; } file = malloc(av.av_len+5); memcpy(file, av.av_val, av.av_len); file[av.av_len] = '\0'; for (p=file; *p; p++) if (*p == ':') *p = '_'; /* Add extension if none present */ if (file[av.av_len - 4] != '.') { av.av_len += 4; } /* Always use flv extension, regardless of original */ if (strcmp(file+av.av_len-4, ".flv")) { strcpy(file+av.av_len-4, ".flv"); } argv[argc].av_val = ptr + 1; argv[argc++].av_len = 2; argv[argc].av_val = file; argv[argc].av_len = av.av_len; ptr += sprintf(ptr, " -o %s", file); now = RTMP_GetTime(); if (now - server->filetime < DUPTIME && AVMATCH(&argv[argc], &server->filename)) { printf("Duplicate request, skipping.\n"); free(file); } else { printf("\n%s\n\n", cmd); fflush(stdout); server->filetime = now; free(server->filename.av_val); server->filename = argv[argc++]; spawn_dumper(argc, argv, cmd); } free(cmd); } pc.m_body = server->connect; server->connect = NULL; RTMPPacket_Free(&pc); ret = 1; RTMP_SendCtrl(r, 0, 1, 0); SendPlayStart(r); RTMP_SendCtrl(r, 1, 1, 0); SendPlayStop(r); } AMF_Reset(&obj); return ret; }
//Publish using RTMP_SendPacket() int publish_using_packet(){ RTMP *rtmp=NULL; RTMPPacket *packet=NULL; uint32_t start_time=0; uint32_t now_time=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("../live.flv","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://101.251.251.93:1935/myapp/mystream")) { 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*64); RTMPPacket_Reset(packet); packet->m_hasAbsTimestamp = 0; packet->m_nChannel = 0x04; packet->m_nInfoField2 = rtmp->m_stream_id; RTMP_LogPrintf("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:%8lu ms\n",pre_frame_time); lasttime=pre_frame_time; } sleep(1); continue; } //not quite the same as FLV spec if(!ReadU8(&type,fp)) break; if(!ReadU24(&datalength,fp)) break; if(!ReadTime(×tamp,fp)) break; if(!ReadU24(&streamid,fp)) break; 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; packet->m_headerType = RTMP_PACKET_SIZE_LARGE; packet->m_nTimeStamp = timestamp; 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"); break; } if (!RTMP_SendPacket(rtmp,packet,0)){ RTMP_Log(RTMP_LOGERROR,"Send Error\n"); break; } if(!ReadU32(&preTagsize,fp)) break; 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 (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("cuc_ieschool.flv","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://localhost/publishlive/livestream")) { 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:%8lu 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 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; }