166 lines
4.3 KiB
C
166 lines
4.3 KiB
C
#include "flv.h"
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <sys/select.h>
|
|
#include <librtmp/log.h>
|
|
#include <librtmp/rtmp.h>
|
|
|
|
|
|
int MyRTMP_Write (RTMP* r, const char* buf, int size)
|
|
{
|
|
RTMPPacket* pkt = &r->m_write;
|
|
char* enc;
|
|
int s2 = size, ret, num;
|
|
|
|
pkt->m_nChannel = 0x04; /* source channel */
|
|
pkt->m_nInfoField2 = r->m_stream_id;
|
|
|
|
while (s2) {
|
|
if (!pkt->m_nBytesRead) {
|
|
if (size < 11) {
|
|
/* FLV pkt too small */
|
|
return 0;
|
|
}
|
|
|
|
if (buf[0] == 'F' && buf[1] == 'L' && buf[2] == 'V') {
|
|
buf += 13;
|
|
s2 -= 13;
|
|
}
|
|
|
|
pkt->m_packetType = *buf++;
|
|
pkt->m_nBodySize = AMF_DecodeInt24 (buf);
|
|
buf += 3;
|
|
pkt->m_nTimeStamp = AMF_DecodeInt24 (buf);
|
|
buf += 3;
|
|
pkt->m_nTimeStamp |= *buf++ << 24;
|
|
buf += 3;
|
|
s2 -= 11;
|
|
|
|
if ( ( (pkt->m_packetType == RTMP_PACKET_TYPE_AUDIO
|
|
|| pkt->m_packetType == RTMP_PACKET_TYPE_VIDEO) &&
|
|
!pkt->m_nTimeStamp) || pkt->m_packetType == RTMP_PACKET_TYPE_INFO) {
|
|
pkt->m_headerType = RTMP_PACKET_SIZE_LARGE;
|
|
} else {
|
|
pkt->m_headerType = RTMP_PACKET_SIZE_MEDIUM;
|
|
}
|
|
|
|
if (!RTMPPacket_Alloc (pkt, pkt->m_nBodySize)) {
|
|
RTMP_Log (RTMP_LOGDEBUG, "%s, failed to allocate packet", __FUNCTION__);
|
|
return FALSE;
|
|
}
|
|
|
|
enc = pkt->m_body;
|
|
} else {
|
|
enc = pkt->m_body + pkt->m_nBytesRead;
|
|
}
|
|
|
|
num = pkt->m_nBodySize - pkt->m_nBytesRead;
|
|
|
|
if (num > s2) {
|
|
num = s2;
|
|
}
|
|
|
|
memcpy (enc, buf, num);
|
|
pkt->m_nBytesRead += num;
|
|
s2 -= num;
|
|
buf += num;
|
|
|
|
if (pkt->m_nBytesRead == pkt->m_nBodySize) {
|
|
ret = RTMP_SendPacket (r, pkt, FALSE);
|
|
RTMPPacket_Free (pkt);
|
|
pkt->m_nBytesRead = 0;
|
|
|
|
if (!ret) {
|
|
return -1;
|
|
}
|
|
|
|
buf += 4;
|
|
s2 -= 4;
|
|
|
|
if (s2 < 0) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return size+s2;
|
|
}
|
|
|
|
int main (int argc, const char** argv)
|
|
{
|
|
FILE* flv;
|
|
RTMP* rtmp;
|
|
RTMPPacket rtmpPacket;
|
|
|
|
flvtag_t tag;
|
|
int32_t timestamp = 0;
|
|
int has_audio, has_video;
|
|
char* url = 0;
|
|
|
|
if (2 >= argc) {
|
|
fprintf (stderr,"Usage %s [input] [url]\n",argv[0]);
|
|
}
|
|
|
|
url = (char*) argv[2];
|
|
flv = flv_open_read (argv[1]);
|
|
|
|
if (! flv) {
|
|
fprintf (stderr,"Could not open %s\n",argv[1]);
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
if (! flv_read_header (flv, &has_audio, &has_video)) {
|
|
fprintf (stderr,"Not an flv file %s\n",argv[1]);
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
flvtag_init (&tag);
|
|
rtmp = RTMP_Alloc();
|
|
RTMP_Init (rtmp);
|
|
fprintf (stderr,"Connecting to %s\n", url);
|
|
RTMP_SetupURL (rtmp, url);
|
|
RTMP_EnableWrite (rtmp);
|
|
|
|
RTMP_Connect (rtmp, NULL);
|
|
RTMP_ConnectStream (rtmp, 0);
|
|
memset (&rtmpPacket, 0, sizeof (RTMPPacket));
|
|
|
|
if (! RTMP_IsConnected (rtmp)) {
|
|
fprintf (stderr,"RTMP_IsConnected() Error\n");
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
while (flv_read_tag (flv,&tag)) {
|
|
if (! RTMP_IsConnected (rtmp) || RTMP_IsTimedout (rtmp)) {
|
|
fprintf (stderr,"RTMP_IsConnected() Error\n");
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
if (flvtag_timestamp (&tag) > timestamp) {
|
|
usleep (1000 * (flvtag_timestamp (&tag) - timestamp));
|
|
timestamp = flvtag_timestamp (&tag);
|
|
}
|
|
|
|
MyRTMP_Write (rtmp, (const char*) flvtag_raw_data (&tag),flvtag_raw_size (&tag));
|
|
|
|
// Handle RTMP ping and such
|
|
fd_set sockset; struct timeval timeout = {0,0};
|
|
FD_ZERO (&sockset); FD_SET (RTMP_Socket (rtmp), &sockset);
|
|
register int result = select (RTMP_Socket (rtmp) + 1, &sockset, NULL, NULL, &timeout);
|
|
|
|
if (result == 1 && FD_ISSET (RTMP_Socket (rtmp), &sockset)) {
|
|
RTMP_ReadPacket (rtmp, &rtmpPacket);
|
|
|
|
if (! RTMPPacket_IsReady (&rtmpPacket)) {
|
|
fprintf (stderr,"Received RTMP packet\n");
|
|
RTMP_ClientPacket (rtmp,&rtmpPacket);
|
|
RTMPPacket_Free (&rtmpPacket);
|
|
}
|
|
}
|
|
}
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|