Exemplo n.º 1
0
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;
}
Exemplo n.º 2
0
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;
}
Exemplo n.º 5
0
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;
}
Exemplo n.º 6
0
static int rtmp_read(URLContext *s, uint8_t *buf, int size)
{
    RTMP *r = s->priv_data;

    return RTMP_Read(r, buf, size);
}
Exemplo n.º 7
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;
}
Exemplo n.º 8
0
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;
}
Exemplo n.º 9
0
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;

}
Exemplo n.º 10
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;
}
Exemplo n.º 11
0
/*
 * 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;
  }
}
Exemplo n.º 12
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;
}
Exemplo n.º 13
0
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;
}
Exemplo n.º 14
0
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;
}
Exemplo n.º 15
0
int rtmp_read(LibRTMPContext *ctx , char *buf, int size)
{
    RTMP *r = &ctx->rtmp;
    return RTMP_Read(r, buf, size);
}