Пример #1
0
void
sigIntHandler(int sig)
{
  RTMP_ctrlC = TRUE;
  RTMP_LogPrintf("Caught signal: %d, cleaning up, just a second...\n", sig);
  if (rtmpServer)
    stopStreaming(rtmpServer);
  signal(SIGINT, SIG_DFL);
}
Пример #2
0
static void  rtmp_rvod_stop_notify(void* ctx)
{
    if (!ctx)
    {
        return;
    }
    RTMP_LogPrintf("rtmp stopeed\n");
    t_rtmp_vod_ctx *c = ctx;
    c->stopeed = 1;

}
Пример #3
0
void sigIntHandler(int sig)
{
	RTMP_ctrlC = TRUE;
	RTMP_LogPrintf("Caught signal: %d, cleaning up, just a second...\n", sig);
	// ignore all these signals now and let the connection close
	signal(SIGINT, SIG_IGN);
	signal(SIGTERM, SIG_IGN);
	signal(SIGHUP, SIG_IGN);
	signal(SIGPIPE, SIG_IGN);
	signal(SIGQUIT, SIG_IGN);
}
Пример #4
0
TFTYPE
controlServerThread(void *unused)
{
  char ich;
  while (1)
    {
      ich = getchar();
      switch (ich)
	{
	case 'q':
	  RTMP_LogPrintf("Exiting\n");
	  stopStreaming(rtmpServer);
	  exit(0);
	  break;
	default:
	  RTMP_LogPrintf("Unknown command \'%c\', ignoring\n", ich);
	}
    }
  TFRET();
}
Пример #5
0
void
sigIntHandler(int sig)
{
    //xjzhang, 屏蔽这些signal,设置RTMP_ctrlC为TRUE从而进入正常退出流程;
    RTMP_ctrlC = TRUE;
    RTMP_LogPrintf("Caught signal: %d, cleaning up, just a second...\n", sig);
    // ignore all these signals now and let the connection close
    signal(SIGINT, SIG_IGN);
    signal(SIGTERM, SIG_IGN);
#ifndef WIN32
    signal(SIGHUP, SIG_IGN);
    signal(SIGPIPE, SIG_IGN);
    signal(SIGQUIT, SIG_IGN);
#endif
}
Пример #6
0
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();
    }
}
Пример #7
0
int
main(int argc, char **argv)
{
  int nStatus = RD_SUCCESS;

  // http streaming server
  char DEFAULT_HTTP_STREAMING_DEVICE[] = "0.0.0.0";	// 0.0.0.0 is any device

  char *rtmpStreamingDevice = DEFAULT_HTTP_STREAMING_DEVICE;	// streaming device, default 0.0.0.0
  int nRtmpStreamingPort = 1935;	// port

  RTMP_LogPrintf("RTMP Server %s\n", RTMPDUMP_VERSION);
  RTMP_LogPrintf("(c) 2010 Andrej Stepanchuk, Howard Chu; license: GPL\n\n");

  RTMP_debuglevel = RTMP_LOGINFO;

  if (argc > 1 && !strcmp(argv[1], "-z"))
    RTMP_debuglevel = RTMP_LOGALL;

  // init request
  memset(&defaultRTMPRequest, 0, sizeof(RTMP_REQUEST));

  defaultRTMPRequest.rtmpport = -1;
  defaultRTMPRequest.protocol = RTMP_PROTOCOL_UNDEFINED;
  defaultRTMPRequest.bLiveStream = FALSE;	// is it a live stream? then we can't seek/resume

  defaultRTMPRequest.timeout = 300;	// timeout connection afte 300 seconds
  defaultRTMPRequest.bufferTime = 20 * 1000;


  signal(SIGINT, sigIntHandler);
#ifndef WIN32
  signal(SIGPIPE, SIG_IGN);
#endif

#ifdef _DEBUG
  netstackdump = fopen("netstackdump", "wb");
  netstackdump_read = fopen("netstackdump_read", "wb");
#endif

  InitSockets();

  // start text UI
  ThreadCreate(controlServerThread, 0);

  // start http streaming
  if ((rtmpServer =
       startStreaming(rtmpStreamingDevice, nRtmpStreamingPort)) == 0)
    {
      RTMP_Log(RTMP_LOGERROR, "Failed to start RTMP server, exiting!");
      return RD_FAILED;
    }
  RTMP_LogPrintf("Streaming on rtmp://%s:%d\n", rtmpStreamingDevice,
	    nRtmpStreamingPort);

  while (rtmpServer->state != STREAMING_STOPPED)
    {
      sleep(1);
    }
  RTMP_Log(RTMP_LOGDEBUG, "Done, exiting...");

  CleanupSockets();

#ifdef _DEBUG
  if (netstackdump != 0)
    fclose(netstackdump);
  if (netstackdump_read != 0)
    fclose(netstackdump_read);
#endif
  return nStatus;
}
Пример #8
0
int
main(int argc, char **argv)
{
  int nStatus = RD_SUCCESS;

  // http streaming server
  char DEFAULT_HTTP_STREAMING_DEVICE[] = "0.0.0.0";	// 0.0.0.0 is any device

  char *httpStreamingDevice = DEFAULT_HTTP_STREAMING_DEVICE;	// streaming device, default 0.0.0.0
  int nHttpStreamingPort = 80;	// port
  int opt;
  struct option longopts[] = {
    {"help", 0, NULL, 'h'},
    {"host", 1, NULL, 'n'},
    {"port", 1, NULL, 'c'},
    {"socks", 1, NULL, 'S'},
    {"protocol", 1, NULL, 'l'},
    {"playpath", 1, NULL, 'y'},
    {"rtmp", 1, NULL, 'r'},
    {"swfUrl", 1, NULL, 's'},
    {"tcUrl", 1, NULL, 't'},
    {"pageUrl", 1, NULL, 'p'},
    {"app", 1, NULL, 'a'},
#ifdef CRYPTO
    {"swfhash", 1, NULL, 'w'},
    {"swfsize", 1, NULL, 'x'},
    {"swfVfy", 1, NULL, 'W'},
    {"swfAge", 1, NULL, 'X'},
#endif
    {"auth", 1, NULL, 'u'},
    {"conn", 1, NULL, 'C'},
    {"flashVer", 1, NULL, 'f'},
    {"live", 0, NULL, 'v'},
    //{"flv",     1, NULL, 'o'},
    //{"resume",  0, NULL, 'e'},
    {"timeout", 1, NULL, 'm'},
    {"buffer", 1, NULL, 'b'},
    //{"skip",    1, NULL, 'k'},
    {"device", 1, NULL, 'D'},
    {"sport", 1, NULL, 'g'},
    {"subscribe", 1, NULL, 'd'},
    {"start", 1, NULL, 'A'},
    {"stop", 1, NULL, 'B'},
    {"token", 1, NULL, 'T'},
    {"debug", 0, NULL, 'z'},
    {"quiet", 0, NULL, 'q'},
    {"verbose", 0, NULL, 'V'},
    {0, 0, 0, 0}
  };
  RTMP_LogPrintf("HTTP-RTMP Stream Gateway %s\n", RTMPDUMP_VERSION);
  RTMP_LogPrintf("(c) 2010 Andrej Stepanchuk, Howard Chu; license: GPL\n\n");

  // init request
  memset(&defaultRTMPRequest, 0, sizeof(RTMP_REQUEST));

  defaultRTMPRequest.rtmpport = -1;
  defaultRTMPRequest.protocol = RTMP_PROTOCOL_UNDEFINED;
  defaultRTMPRequest.bLiveStream = FALSE;	// is it a live stream? then we can't seek/resume

  defaultRTMPRequest.timeout = 120;	// timeout connection after 120 seconds
  defaultRTMPRequest.bufferTime = 20 * 1000;

  defaultRTMPRequest.swfAge = 30;



  signal(SIGINT, sigIntHandler);
#ifndef WIN32
  signal(SIGPIPE, SIG_IGN);
#endif

  InitSockets();

  while ((opt =
	  getopt_long(argc, argv,
		      "hvqVzr:s:t:p:a:f:u:n:c:l:y:m:d:D:A:B:T:g:w:x:W:X:S:", longopts,
		      NULL)) != -1)
    {
      switch (opt)
	{
	case 'h':
	  RTMP_LogPrintf
	    ("\nThis program serves media content streamed from RTMP onto HTTP.\n\n");
	  RTMP_LogPrintf("--help|-h               Prints this help screen.\n");
	  RTMP_LogPrintf
	    ("--rtmp|-r url           URL (e.g. rtmp://host[:port]/path)\n");
	  RTMP_LogPrintf
	    ("--host|-n hostname      Overrides the hostname in the rtmp url\n");
	  RTMP_LogPrintf
	    ("--port|-c port          Overrides the port in the rtmp url\n");
	  RTMP_LogPrintf
	    ("--socks|-S host:port    Use the specified SOCKS proxy\n");
	  RTMP_LogPrintf
	    ("--protocol|-l           Overrides the protocol in the rtmp url (0 - RTMP, 2 - RTMPE)\n");
	  RTMP_LogPrintf
	    ("--playpath|-y           Overrides the playpath parsed from rtmp url\n");
	  RTMP_LogPrintf("--swfUrl|-s url         URL to player swf file\n");
	  RTMP_LogPrintf
	    ("--tcUrl|-t url          URL to played stream (default: \"rtmp://host[:port]/app\")\n");
	  RTMP_LogPrintf("--pageUrl|-p url        Web URL of played programme\n");
	  RTMP_LogPrintf("--app|-a app            Name of target app in server\n");
#ifdef CRYPTO
	  RTMP_LogPrintf
	    ("--swfhash|-w hexstring  SHA256 hash of the decompressed SWF file (32 bytes)\n");
	  RTMP_LogPrintf
	    ("--swfsize|-x num        Size of the decompressed SWF file, required for SWFVerification\n");
	  RTMP_LogPrintf
	    ("--swfVfy|-W url         URL to player swf file, compute hash/size automatically\n");
	  RTMP_LogPrintf
	    ("--swfAge|-X days        Number of days to use cached SWF hash before refreshing\n");
#endif
	  RTMP_LogPrintf
	    ("--auth|-u string        Authentication string to be appended to the connect string\n");
	  RTMP_LogPrintf
	    ("--conn|-C type:data     Arbitrary AMF data to be appended to the connect string\n");
	  RTMP_LogPrintf
	    ("                        B:boolean(0|1), S:string, N:number, O:object-flag(0|1),\n");
	  RTMP_LogPrintf
	    ("                        Z:(null), NB:name:boolean, NS:name:string, NN:name:number\n");
	  RTMP_LogPrintf
	    ("--flashVer|-f string    Flash version string (default: \"%s\")\n",
	     RTMP_DefaultFlashVer.av_val);
	  RTMP_LogPrintf
	    ("--live|-v               Get a live stream, no --resume (seeking) of live streams possible\n");
	  RTMP_LogPrintf
	    ("--subscribe|-d string   Stream name to subscribe to (otherwise defaults to playpath if live is specified)\n");
	  RTMP_LogPrintf
	    ("--timeout|-m num        Timeout connection num seconds (default: %lu)\n",
	     defaultRTMPRequest.timeout);
	  RTMP_LogPrintf
	    ("--start|-A num          Start at num seconds into stream (not valid when using --live)\n");
	  RTMP_LogPrintf
	    ("--stop|-B num           Stop at num seconds into stream\n");
	  RTMP_LogPrintf
	    ("--token|-T key          Key for SecureToken response\n");
	  RTMP_LogPrintf
	    ("--buffer|-b             Buffer time in milliseconds (default: %lu)\n\n",
	     defaultRTMPRequest.bufferTime);

	  RTMP_LogPrintf
	    ("--device|-D             Streaming device ip address (default: %s)\n",
	     DEFAULT_HTTP_STREAMING_DEVICE);
	  RTMP_LogPrintf
	    ("--sport|-g              Streaming port (default: %d)\n\n",
	     nHttpStreamingPort);
	  RTMP_LogPrintf
	    ("--quiet|-q              Suppresses all command output.\n");
	  RTMP_LogPrintf("--verbose|-V            Verbose command output.\n");
	  RTMP_LogPrintf("--debug|-z              Debug level command output.\n");
	  RTMP_LogPrintf
	    ("If you don't pass parameters for swfUrl, pageUrl, or auth these properties will not be included in the connect ");
	  RTMP_LogPrintf("packet.\n\n");
	  return RD_SUCCESS;
	  break;
	  // streaming server specific options
	case 'D':
	  if (inet_addr(optarg) == INADDR_NONE)
	    {
	      RTMP_Log(RTMP_LOGERROR,
		  "Invalid binding address (requested address %s), ignoring",
		  optarg);
	    }
	  else
	    {
	      httpStreamingDevice = optarg;
	    }
	  break;
	case 'g':
	  {
	    int port = atoi(optarg);
	    if (port < 0 || port > 65535)
	      {
		RTMP_Log(RTMP_LOGERROR,
		    "Streaming port out of range (requested port %d), ignoring\n",
		    port);
	      }
	    else
	      {
		nHttpStreamingPort = port;
	      }
	    break;
	  }
	default:
	  //RTMP_LogPrintf("unknown option: %c\n", opt);
	  if (!ParseOption(opt, optarg, &defaultRTMPRequest))
	    return RD_FAILED;
	  break;
	}
    }

#ifdef _DEBUG
  netstackdump = fopen("netstackdump", "wb");
  netstackdump_read = fopen("netstackdump_read", "wb");
#endif

  // start text UI
  ThreadCreate(controlServerThread, 0);

  // start http streaming
  if ((httpServer =
       startStreaming(httpStreamingDevice, nHttpStreamingPort)) == 0)
    {
      RTMP_Log(RTMP_LOGERROR, "Failed to start HTTP server, exiting!");
      return RD_FAILED;
    }
  RTMP_LogPrintf("Streaming on http://%s:%d\n", httpStreamingDevice,
	    nHttpStreamingPort);

  while (httpServer->state != STREAMING_STOPPED)
    {
      sleep(1);
    }
  RTMP_Log(RTMP_LOGDEBUG, "Done, exiting...");

  CleanupSockets();

#ifdef _DEBUG
  if (netstackdump != 0)
    fclose(netstackdump);
  if (netstackdump_read != 0)
    fclose(netstackdump_read);
#endif
  return nStatus;
}
Пример #9
0
void usage(char *prog)
{
	RTMP_LogPrintf
		("\n%s: This program dumps the media content streamed over RTMP.\n\n", prog);
	RTMP_LogPrintf("--help|-h               Prints this help screen.\n");
	RTMP_LogPrintf
		("--url|-i url            URL with options included (e.g. rtmp://host[:port]/path swfUrl=url tcUrl=url)\n");
	RTMP_LogPrintf
		("--rtmp|-r url           URL (e.g. rtmp://host[:port]/path)\n");
	RTMP_LogPrintf
		("--live|-v               Save a live stream, no --resume (seeking) of live streams possible\n");
	RTMP_LogPrintf
		("--flv|-o string         FLV output file name, if the file name is - print stream to stdout\n");
	RTMP_LogPrintf
		("--timeout|-m num        Timeout connection num seconds (default: %u)\n", DEF_TIMEOUT);
	RTMP_LogPrintf
		("--quiet|-q              Suppresses all command output.\n");
	RTMP_LogPrintf("--verbose|-V            Verbose command output.\n");
	RTMP_LogPrintf
		("If you don't pass parameters for swfUrl, pageUrl, or auth these properties will not be included in the connect ");
	RTMP_LogPrintf("packet.\n\n");
}
Пример #10
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;
}
Пример #11
0
// Return values: true (option parsing ok)
//                false (option not parsed/invalid)
int
ParseOption(char opt, char *arg, RTMP_REQUEST * req)
{
    	AVal parsedHost, parsedPlaypath, parsedApp;
	unsigned int parsedPort = 0;
	int parsedProtocol = RTMP_PROTOCOL_UNDEFINED;
  switch (opt)
    {
#ifdef CRYPTO
    case 'w':
      {
	int res = hex2bin(arg, &req->swfHash.av_val);
	if (!res || res != RTMP_SWF_HASHLEN)
	  {
	    req->swfHash.av_val = NULL;
	    RTMP_Log(RTMP_LOGWARNING,
		"Couldn't parse swf hash hex string, not hexstring or not %d bytes, ignoring!", RTMP_SWF_HASHLEN);
	  }
	req->swfHash.av_len = RTMP_SWF_HASHLEN;
	break;
      }
    case 'x':
      {
	int size = atoi(arg);
	if (size <= 0)
	  {
	    RTMP_Log(RTMP_LOGERROR, "SWF Size must be at least 1, ignoring\n");
	  }
	else
	  {
	    req->swfSize = size;
	  }
	break;
      }
    case 'W':
      {
        STR2AVAL(req->swfUrl, arg);
        req->swfVfy = 1;
      }
      break;
    case 'X':
      {
	int num = atoi(arg);
	if (num < 0)
	  {
	    RTMP_Log(RTMP_LOGERROR, "SWF Age must be non-negative, ignoring\n");
	  }
	else
	  {
	    req->swfAge = num;
	  }
	break;
      }
#endif
    case 'b':
      {
	int32_t bt = atol(arg);
	if (bt < 0)
	  {
	    RTMP_Log(RTMP_LOGERROR,
		"Buffer time must be greater than zero, ignoring the specified value %d!",
		bt);
	  }
	else
	  {
	    req->bufferTime = bt;
	  }
	break;
      }
    case 'v':
      req->bLiveStream = TRUE;	// no seeking or resuming possible!
      break;
    case 'd':
      STR2AVAL(req->subscribepath, arg);
      break;
    case 'n':
      STR2AVAL(req->hostname, arg);
      break;
    case 'c':
      req->rtmpport = atoi(arg);
      break;
    case 'l':
      {
	int protocol = atoi(arg);
	if (protocol < RTMP_PROTOCOL_RTMP || protocol > RTMP_PROTOCOL_RTMPTS)
	  {
	    RTMP_Log(RTMP_LOGERROR, "Unknown protocol specified: %d, using default",
		protocol);
	    return FALSE;
	  }
	else
	  {
	    req->protocol = protocol;
	  }
	break;
      }
    case 'y':
      STR2AVAL(req->playpath, arg);
      break;
    case 'r':
      {
	req->rtmpurl = arg;



	if (!RTMP_ParseURL
	    (req->rtmpurl, &parsedProtocol, &parsedHost, &parsedPort,
	     &parsedPlaypath, &parsedApp))
	  {
	    RTMP_Log(RTMP_LOGWARNING, "Couldn't parse the specified url (%s)!", arg);
	  }
	else
	  {
	    if (!req->hostname.av_len)
	      req->hostname = parsedHost;
	    if (req->rtmpport == -1)
	      req->rtmpport = parsedPort;
	    if (req->playpath.av_len == 0 && parsedPlaypath.av_len)
	      {
		    req->playpath = parsedPlaypath;
	      }
	    if (req->protocol == RTMP_PROTOCOL_UNDEFINED)
	      req->protocol = parsedProtocol;
	    if (req->app.av_len == 0 && parsedApp.av_len)
	      {
		    req->app = parsedApp;
	      }
	  }
	break;
      }
    case 's':
      STR2AVAL(req->swfUrl, arg);
      break;
    case 't':
      STR2AVAL(req->tcUrl, arg);
      break;
    case 'p':
      STR2AVAL(req->pageUrl, arg);
      break;
    case 'a':
      STR2AVAL(req->app, arg);
      break;
    case 'f':
      STR2AVAL(req->flashVer, arg);
      break;
    case 'u':
      STR2AVAL(req->auth, arg);
      break;
    case 'C':
      parseAMF(&req->extras, optarg, &req->edepth);
      break;
    case 'm':
      req->timeout = atoi(arg);
      break;
    case 'A':
      req->dStartOffset = (int)(atof(arg) * 1000.0);
      //printf("dStartOffset = %d\n", dStartOffset);
      break;
    case 'B':
      req->dStopOffset = (int)(atof(arg) * 1000.0);
      //printf("dStartOffset = %d\n", dStartOffset);
      break;
    case 'T':
      STR2AVAL(req->token, arg);
      break;
    case 'S':
      STR2AVAL(req->sockshost, arg);
    case 'q':
      RTMP_debuglevel = RTMP_LOGCRIT;
      break;
    case 'V':
      RTMP_debuglevel = RTMP_LOGDEBUG;
      break;
    case 'z':
      RTMP_debuglevel = RTMP_LOGALL;
      break;
    default:
      RTMP_LogPrintf("unknown option: %c, arg: %s\n", opt, arg);
      return FALSE;
    }
  return TRUE;
}
Пример #12
0
void usage(char *prog)
{
	RTMP_LogPrintf
	("\n%s: This program dumps the media content streamed over RTMP.\n\n", prog);
	RTMP_LogPrintf("--help|-h               Prints this help screen.\n");
	RTMP_LogPrintf
	("--url|-i url            URL with options included (e.g. rtmp://host[:port]/path swfUrl=url tcUrl=url)\n");
	RTMP_LogPrintf
	("--rtmp|-r url           URL (e.g. rtmp://host[:port]/path)\n");
	RTMP_LogPrintf
	("--host|-n hostname      Overrides the hostname in the rtmp url\n");
	RTMP_LogPrintf
	("--port|-c port          Overrides the port in the rtmp url\n");
	RTMP_LogPrintf
	("--socks|-S host:port    Use the specified SOCKS proxy\n");
	RTMP_LogPrintf
	("--protocol|-l num       Overrides the protocol in the rtmp url (0 - RTMP, 2 - RTMPE)\n");
	RTMP_LogPrintf
	("--playpath|-y path      Overrides the playpath parsed from rtmp url\n");
	RTMP_LogPrintf
	("--playlist|-Y           Set playlist before playing\n");
	RTMP_LogPrintf("--swfUrl|-s url         URL to player swf file\n");
	RTMP_LogPrintf
	("--tcUrl|-t url          URL to played stream (default: \"rtmp://host[:port]/app\")\n");
	RTMP_LogPrintf("--pageUrl|-p url        Web URL of played programme\n");
	RTMP_LogPrintf("--app|-a app            Name of target app on server\n");
#ifdef CRYPTO
	RTMP_LogPrintf
	("--swfhash|-w hexstring  SHA256 hash of the decompressed SWF file (32 bytes)\n");
	RTMP_LogPrintf
	("--swfsize|-x num        Size of the decompressed SWF file, required for SWFVerification\n");
	RTMP_LogPrintf
	("--swfVfy|-W url         URL to player swf file, compute hash/size automatically\n");
	RTMP_LogPrintf
	("--swfAge|-X days        Number of days to use cached SWF hash before refreshing\n");
#endif
	RTMP_LogPrintf
	("--auth|-u string        Authentication string to be appended to the connect string\n");
	RTMP_LogPrintf
	("--conn|-C type:data     Arbitrary AMF data to be appended to the connect string\n");
	RTMP_LogPrintf
	("                        B:boolean(0|1), S:string, N:number, O:object-flag(0|1),\n");
	RTMP_LogPrintf
	("                        Z:(null), NB:name:boolean, NS:name:string, NN:name:number\n");
	RTMP_LogPrintf
	("--flashVer|-f string    Flash version string (default: \"%s\")\n",
	 RTMP_DefaultFlashVer.av_val);
	RTMP_LogPrintf
	("--live|-v               Save a live stream, no --resume (seeking) of live streams possible\n");
	RTMP_LogPrintf
	("--subscribe|-d string   Stream name to subscribe to (otherwise defaults to playpath if live is specifed)\n");
	RTMP_LogPrintf
	("--realtime|-R           Don't attempt to speed up download via the Pause/Unpause BUFX hack\n");
	RTMP_LogPrintf
	("--flv|-o string         FLV output file name, if the file name is - print stream to stdout\n");
	RTMP_LogPrintf
	("--resume|-e             Resume a partial RTMP download\n");
	RTMP_LogPrintf
	("--timeout|-m num        Timeout connection num seconds (default: %u)\n",
	 DEF_TIMEOUT);
	RTMP_LogPrintf
	("--start|-A num          Start at num seconds into stream (not valid when using --live)\n");
	RTMP_LogPrintf
	("--stop|-B num           Stop at num seconds into stream\n");
	RTMP_LogPrintf
	("--token|-T key          Key for SecureToken response\n");
	RTMP_LogPrintf
	("--jtv|-j JSON           Authentication token for Justin.tv legacy servers\n");
	RTMP_LogPrintf
	("--hashes|-#             Display progress with hashes, not with the byte counter\n");
	RTMP_LogPrintf
	("--buffer|-b             Buffer time in milliseconds (default: %u)\n",
	 DEF_BUFTIME);
	RTMP_LogPrintf
	("--skip|-k num           Skip num keyframes when looking for last keyframe to resume from. Useful if resume fails (default: %d)\n\n",
	 DEF_SKIPFRM);
	RTMP_LogPrintf
	("--quiet|-q              Suppresses all command output.\n");
	RTMP_LogPrintf("--verbose|-V            Verbose command output.\n");
	RTMP_LogPrintf("--debug|-z              Debug level command output.\n");
	RTMP_LogPrintf
	("If you don't pass parameters for swfUrl, pageUrl, or auth these properties will not be included in the connect ");
	RTMP_LogPrintf("packet.\n\n");
}
Пример #13
0
void QRtmp::run()
{
    bool first = true;
    int retries = 0;

    if(!m_destFile.fileName().isEmpty())
        if(!m_destFile.open(QIODevice::WriteOnly))
        {
            setError(QString("Can't open %1 for writing").arg(m_destFile.fileName()));
            return;
        }

    while(!m_stop)
    {
        RTMP_Log(RTMP_LOGDEBUG, "Setting buffer time to: %dms", m_bufferTime);
        RTMP_SetBufferMS(m_rtmp, m_bufferTime);

        if(first)
        {
            first = false;
            RTMP_LogPrintf("Connecting ...\n");

            if(!RTMP_Connect(m_rtmp, NULL))
            {
                setError("RTMP_Connect failed");
                break;
            }

            RTMP_Log(RTMP_LOGINFO, "Connected...");

            // User defined seek offset
            if(dStartOffset > 0)
            {
                // Don't need the start offset if resuming an existing file
                if(m_bResume)
                {
                    RTMP_Log(RTMP_LOGWARNING, "Can't seek a resumed stream, ignoring --start option");
                    dStartOffset = 0;
                }
                else
                    dSeek = dStartOffset;
            }

            // Calculate the length of the stream to still play
            if(dStopOffset > 0)
            {
                // Quit if start seek is past required stop offset
                if(dStopOffset <= dSeek)
                {
                    RTMP_LogPrintf("Already Completed\n");
                    break;
                }
            }

            if(!RTMP_ConnectStream(m_rtmp, dSeek))
            {
                setError("RTMP_ConnectStream failed");
                break;
            }
        }
        else
        {
            if(retries)
            {
                RTMP_Log(RTMP_LOGERROR, "Failed to resume the stream\n\n");
                if(!RTMP_IsTimedout(m_rtmp))
                    setError("RTMP_IsTimedout failed");
                else
                    setError("RTMP_IsTimedout RD_INCOMPLETE");
                break;
            }

            RTMP_Log(RTMP_LOGINFO, "Connection timed out, trying to resume.\n\n");

            /* Did we already try pausing, and it still didn't work? */
            if(m_rtmp->m_pausing == 3)
            {
                /* Only one try at reconnecting... */
                retries = 1;
                dSeek = m_rtmp->m_pauseStamp;
                if(dStopOffset > 0)
                {
                    if(dStopOffset <= dSeek)
                    {
                        RTMP_LogPrintf("Already Completed\n");
                        break;
                    }
                }
                if(!RTMP_ReconnectStream(m_rtmp, dSeek))
                {
                    RTMP_Log(RTMP_LOGERROR, "Failed to resume the stream\n\n");
                    if(!RTMP_IsTimedout(m_rtmp))
                        setError("RTMP_IsTimedout failed");
                    else
                        setError("RTMP_IsTimedout RD_INCOMPLETE");
                    break;
                }
            }
            else if(!RTMP_ToggleStream(m_rtmp))
            {
                RTMP_Log(RTMP_LOGERROR, "Failed to resume the stream\n\n");
                if(!RTMP_IsTimedout(m_rtmp))
                    setError("RTMP_IsTimedout failed");
                else
                    setError("RTMP_IsTimedout RD_INCOMPLETE");
                break;
            }
            m_bResume = true;
        }
        int nStatus = download();
        if(nStatus != RD_INCOMPLETE || !RTMP_IsTimedout(m_rtmp) || m_bLiveStream)
            break;
    }
    RTMP_Log(RTMP_LOGDEBUG, "Closing connection.\n");
    RTMP_Close(m_rtmp);
    if(m_destFile.isOpen())
        m_destFile.close();
    setStreamIsRunning(false);
}
Пример #14
0
void doServe(STREAMING_SERVER * server,	// server socket and state (our listening socket)
  int sockfd	// client connection socket
  )
{
  server->state = STREAMING_IN_PROGRESS;

  RTMP rtmp = { 0 };		/* our session with the real client */
  RTMPPacket packet = { 0 };

  // timeout for http requests
  fd_set fds;
  struct timeval tv;

  memset(&tv, 0, sizeof(struct timeval));
  tv.tv_sec = 5;

  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
    {
      RTMP_Init(&rtmp);
      rtmp.m_sb.sb_socket = sockfd;
      if (!RTMP_Serve(&rtmp))
	{
	  RTMP_Log(RTMP_LOGERROR, "Handshake failed");
	  goto cleanup;
	}
    }
  server->arglen = 0;
  while (RTMP_IsConnected(&rtmp) && RTMP_ReadPacket(&rtmp, &packet))
    {
      if (!RTMPPacket_IsReady(&packet))
	continue;
      ServePacket(server, &rtmp, &packet);
      RTMPPacket_Free(&packet);
    }

cleanup:
  RTMP_LogPrintf("Closing connection... ");
  RTMP_Close(&rtmp);
  /* Should probably be done by RTMP_Close() ... */
  rtmp.Link.playpath.av_val = NULL;
  rtmp.Link.tcUrl.av_val = NULL;
  rtmp.Link.swfUrl.av_val = NULL;
  rtmp.Link.pageUrl.av_val = NULL;
  rtmp.Link.app.av_val = NULL;
  rtmp.Link.flashVer.av_val = NULL;
  RTMP_LogPrintf("done!\n\n");

quit:
  if (server->state == STREAMING_IN_PROGRESS)
    server->state = STREAMING_ACCEPTING;

  return;
}
Пример #15
0
int main(int argc, char **argv)
{
	extern char *optarg;

	int nStatus = RD_SUCCESS;
	int bStdoutMode = TRUE;	// if true print the stream directly to stdout, messages go to stderr
	int bLiveStream = TRUE;	// is it a live stream? then we can't seek/resume

	long int timeout = DEF_TIMEOUT;	// timeout connection after 120 seconds
	RTMP rtmp = { 0 };
	AVal fullUrl = { 0, 0 };
	RTMP_debuglevel = RTMP_LOGINFO;
	char *flvFile = 0;

	signal(SIGINT, sigIntHandler);
	signal(SIGTERM, sigIntHandler);
	signal(SIGHUP, sigIntHandler);
	signal(SIGPIPE, sigIntHandler);
	signal(SIGQUIT, sigIntHandler);


	RTMP_LogPrintf("RTMPDump %s\n", RTMPDUMP_VERSION);
	RTMP_LogPrintf("(c) 2010 Andrej Stepanchuk, Howard Chu, The Flvstreamer Team; license: GPL\n");


	int opt;
	struct option longopts[] = {
		{"help", 0, NULL, 'h'},
		{"url", 1, NULL, 'i'},
		{"rtmp", 1, NULL, 'r'},
		{"live", 0, NULL, 'v'},
		{"timeout", 1, NULL, 'm'},
		{"hashes", 0, NULL, '#'},
		{"quiet", 0, NULL, 'q'},
		{"verbose", 0, NULL, 'V'},
		{0, 0, 0, 0}
	};

	while ((opt = getopt_long(argc, argv, "hVvqzRr:s:t:i:p:a:b:f:o:u:C:n:c:l:y:Ym:k:d:A:B:T:w:x:W:X:S:#j:", longopts, NULL)) != -1)
	{
		switch (opt)
		{
			case 'h':
				usage(argv[0]);
				return RD_SUCCESS;

			case 'v':
				bLiveStream = TRUE;	// no seeking or resuming possible!
				break;
			case 'i':
				STR2AVAL(fullUrl, optarg);
				break;
			case 'o':
				flvFile = optarg;
				if (strcmp(flvFile, "-"))
					bStdoutMode = FALSE;

				break;
			case 'm':
					  timeout = atoi(optarg);
					  break;
			case 'q':
					  RTMP_debuglevel = RTMP_LOGCRIT;
					  break;
			case 'V':
					  RTMP_debuglevel = RTMP_LOGDEBUG;
					  break;
			case 'z':
					  RTMP_debuglevel = RTMP_LOGALL;
					  break;
			default:
					  RTMP_LogPrintf("unknown option: %c\n", opt);
					  usage(argv[0]);
					  return RD_FAILED;
					  break;
		}
	}

	if (flvFile == 0) {
		RTMP_Log(RTMP_LOGWARNING, "You haven't specified an output file (-o filename), using stdout");
		bStdoutMode = TRUE;
	}
	if (!file)	{
		if (bStdoutMode) {
			file = stdout;
			SET_BINMODE(file);
		}
		else {
			file = fopen(flvFile, "w+b");
			if (file == 0)	{
				RTMP_LogPrintf("Failed to open file! %s\n", flvFile);
				return RD_FAILED;
			}
		}
	}

	////////////////////////////////////////////////////////////////////////////////////////
	RTMP_Init(&rtmp);//初始化RTMP参数
	//指定了-i 参数,直接设置URL
	if (RTMP_SetupURL(&rtmp, fullUrl.av_val) == FALSE) {
		RTMP_Log(RTMP_LOGERROR, "Couldn't parse URL: %s", fullUrl.av_val);
		return RD_FAILED;
	}

	rtmp.Link.timeout = timeout ;
	/* Try to keep the stream moving if it pauses on us */
	if (!bLiveStream )
		rtmp.Link.lFlags |= RTMP_LF_BUFX;
	else {
		rtmp.Link.lFlags |= RTMP_LF_LIVE ;
	}

	printf("aaaaa:%d\n", rtmp.Link.lFlags ) ;
	while (!RTMP_ctrlC)
	{
		RTMP_Log(RTMP_LOGDEBUG, "Setting buffer time to: %dms", DEF_BUFTIME);
		RTMP_SetBufferMS(&rtmp, 2000);//告诉服务器帮我缓存多久

		RTMP_LogPrintf("Connecting ...\n");
		if (!RTMP_Connect(&rtmp, NULL))	{//建立连接,发送"connect"
			nStatus = RD_NO_CONNECT;
			break;
		}
		RTMP_Log(RTMP_LOGINFO, "Connected...");

		//处理服务端返回的各种控制消息包,比如收到connect的result后就进行createStream,以及发送play(test)消息
		if (!RTMP_ConnectStream(&rtmp, 0)) {//一旦返回,表示服务端开始发送数据了.可以play了
			nStatus = RD_FAILED;
			break;
		}

		nStatus = Download(&rtmp, file, bStdoutMode, bLiveStream );

		if (nStatus != RD_INCOMPLETE || !RTMP_IsTimedout(&rtmp) || bLiveStream)
			break;
	}

	RTMP_LogPrintf("Download complete\n");

//clean:
	RTMP_Log(RTMP_LOGDEBUG, "Closing connection.\n");
	RTMP_Close(&rtmp);

	if (file != 0)
		fclose(file);


	return nStatus;
}
Пример #16
0
int
start_sample_rtmp_server(int argc, char **argv)
{
	int nStatus = RD_SUCCESS;
	int i;

	// http streaming server
	char DEFAULT_HTTP_STREAMING_DEVICE[] = "0.0.0.0";	// 0.0.0.0 is any device

	char *rtmpStreamingDevice = DEFAULT_HTTP_STREAMING_DEVICE;	// streaming device, default 0.0.0.0
	int nRtmpStreamingPort = 1935;	// port
	char *cert = NULL, *key = NULL;

	RTMP_LogPrintf("RTMP Server %s\n", "AVRemoteControl Build 1.0");
	RTMP_LogPrintf("(c) 2010 Andrej Stepanchuk, Howard Chu; license: GPL\n\n");

	RTMP_debuglevel = RTMP_LOGINFO;

	for (i = 1; i < argc; i++)
	{
		if (!strcmp(argv[i], "-z"))
			RTMP_debuglevel = RTMP_LOGALL;
		else if (!strcmp(argv[i], "-c") && i + 1 < argc)
			cert = argv[++i];
		else if (!strcmp(argv[i], "-k") && i + 1 < argc)
			key = argv[++i];
	}

	if (cert && key)
		sslCtx = RTMP_TLS_AllocServerContext(cert, key);

	// init request
	memset(&defaultRTMPRequest, 0, sizeof(RTMP_REQUEST));

	defaultRTMPRequest.rtmpport = -1;
	defaultRTMPRequest.protocol = RTMP_PROTOCOL_UNDEFINED;
	defaultRTMPRequest.bLiveStream = true;	// is it a live stream? then we can't seek/resume

	defaultRTMPRequest.timeout = 500;	// timeout connection after 300 seconds
	defaultRTMPRequest.bufferTime = 20 * 1000;


	signal(SIGINT, sigIntHandler);
#ifndef WIN32
	signal(SIGPIPE, SIG_IGN);
#endif

#ifdef _DEBUG
	netstackdump = fopen("netstackdump", "wb");
	netstackdump_read = fopen("netstackdump_read", "wb");
#endif

	InitSockets();

	// start text UI
	//ThreadCreate(controlServerThread, 0);
	std::thread theThread(controlServerThread);

	// start http streaming
	if ((rtmpServer =
		startStreaming(rtmpStreamingDevice, nRtmpStreamingPort)) == 0)
	{
		RTMP_Log(RTMP_LOGERROR, "Failed to start RTMP server, exiting!");
		return RD_FAILED;
	}
	RTMP_LogPrintf("Streaming on rtmp://%s:%d\n", rtmpStreamingDevice,
		nRtmpStreamingPort);

	while (rtmpServer->state != STREAMING_STOPPED)
	{
		sleep(1);
	}
	RTMP_Log(RTMP_LOGDEBUG, "Done, exiting...");

	if (sslCtx)
		RTMP_TLS_FreeServerContext(sslCtx);

	CleanupSockets();

#ifdef _DEBUG
	if (netstackdump != 0)
		fclose(netstackdump);
	if (netstackdump_read != 0)
		fclose(netstackdump_read);
#endif
	return nStatus;
}
Пример #17
0
int
do_rtmp(int port,int protocol,char* playpath_arg,char* host,char* swfVfy_arg,char* tcUrl_arg,char* app_arg,char* pageUrl_arg,char* flashVer_arg,char* conn,char* outfile)
{
  int nStatus = RD_SUCCESS;
  double percent = 0;
  double duration = 0.0;

  int nSkipKeyFrames = DEF_SKIPFRM;	// skip this number of keyframes when resuming

  int bOverrideBufferTime = FALSE;	// if the user specifies a buffer time override this is true
  int bResume = FALSE;		// true in resume mode
  uint32_t dSeek = 0;		// seek position in resume mode, 0 otherwise
  uint32_t bufferTime = DEF_BUFTIME;


  // meta header and initial frame for the resume mode (they are read from the file and compared with
  // the stream we are trying to continue
  char *metaHeader = 0;
  uint32_t nMetaHeaderSize = 0;

  // video keyframe for matching
  char *initialFrame = 0;
  uint32_t nInitialFrameSize = 0;
  int initialFrameType = 0;	// tye: audio or video

  AVal hostname = { 0, 0 };
  AVal playpath = { 0, 0 };
  AVal subscribepath = { 0, 0 };
  AVal usherToken = { 0, 0 }; //Justin.tv auth token
  int retries = 0;
  int bLiveStream = FALSE;	// is it a live stream? then we can't seek/resume
  int bHashes = FALSE;		// display byte counters not hashes by default

  long int timeout = DEF_TIMEOUT;	// timeout connection after 120 seconds
  uint32_t dStopOffset = 0;
  RTMP rtmp;

  AVal swfUrl = { 0, 0 };
  AVal tcUrl = { 0, 0 };
  AVal pageUrl = { 0, 0 };
  AVal app = { 0, 0 };
  AVal auth = { 0, 0 };
  AVal swfHash = { 0, 0 };
  uint32_t swfSize = 0;
  AVal flashVer = { 0, 0 };
  AVal sockshost = { 0, 0 };

#ifdef CRYPTO
  int swfAge = 30;	/* 30 days for SWF cache by default */
  int swfVfy = 0;
  unsigned char hash[RTMP_SWF_HASHLEN];
#endif

  char *flvFile = 0;

  signal(SIGINT, sigIntHandler);
  signal(SIGTERM, sigIntHandler);
  signal(SIGHUP, sigIntHandler);
  signal(SIGPIPE, sigIntHandler);
  signal(SIGQUIT, sigIntHandler);

  RTMP_debuglevel = RTMP_LOGINFO;

  RTMP_Init(&rtmp);

  STR2AVAL(&swfUrl,swfVfy_arg);
  swfVfy = 1;

  if (host) { STR2AVAL(&hostname, host); }
  if (playpath_arg) { STR2AVAL(&playpath, playpath_arg); }
  if (tcUrl_arg) { STR2AVAL(&tcUrl, tcUrl_arg); }
  if (pageUrl_arg) { STR2AVAL(&pageUrl, pageUrl_arg); }
  if (app_arg) { STR2AVAL(&app, app_arg); }
  if (flashVer_arg) { STR2AVAL(&flashVer, flashVer_arg); }

  if (conn) {
    AVal av;
    STR2AVAL(&av, conn);
    if (!RTMP_SetOpt(&rtmp, &av_conn, &av))
    {
      RTMP_Log(RTMP_LOGERROR, "Invalid AMF parameter: %s", conn);
      return RD_FAILED;
    }
  }

  flvFile = outfile;

  file = fopen(flvFile, "w+b");
  if (file == 0)
    {
      RTMP_LogPrintf("Failed to open file! %s\n", flvFile);
      return RD_FAILED;
    }

  if (port == 0)
    {
      if (protocol & RTMP_FEATURE_SSL)
	port = 443;
      else if (protocol & RTMP_FEATURE_HTTP)
	port = 80;
      else
	port = 1935;
    }

#ifdef CRYPTO
  if (swfVfy)
    {
      if (RTMP_HashSWF(swfUrl.av_val, &swfSize, hash, swfAge) == 0)
        {
          swfHash.av_val = (char *)hash;
          swfHash.av_len = RTMP_SWF_HASHLEN;
        }
    }

  if (swfHash.av_len == 0 && swfSize > 0)
    {
      RTMP_Log(RTMP_LOGWARNING,
	  "Ignoring SWF size, supply also the hash with --swfhash");
      swfSize = 0;
    }

  if (swfHash.av_len != 0 && swfSize == 0)
    {
      RTMP_Log(RTMP_LOGWARNING,
	  "Ignoring SWF hash, supply also the swf size  with --swfsize");
      swfHash.av_len = 0;
      swfHash.av_val = NULL;
    }
#endif

  RTMP_SetupStream(&rtmp, protocol, &hostname, port, &sockshost, &playpath,
		   &tcUrl, &swfUrl, &pageUrl, &app, &auth, &swfHash, swfSize,
		   &flashVer, &subscribepath, &usherToken, dSeek, dStopOffset, bLiveStream, timeout);

  /* Try to keep the stream moving if it pauses on us */
  if (!bLiveStream && !(protocol & RTMP_FEATURE_HTTP))
    rtmp.Link.lFlags |= RTMP_LF_BUFX;

  int first = 1;

  while (!RTMP_ctrlC)
    {
      RTMP_Log(RTMP_LOGDEBUG, "Setting buffer time to: %dms", bufferTime);
      RTMP_SetBufferMS(&rtmp, bufferTime);

      if (first)
	{
	  first = 0;
	  RTMP_LogPrintf("Connecting ...\n");

	  if (!RTMP_Connect(&rtmp, NULL))
	    {
	      nStatus = RD_NO_CONNECT;
	      break;
	    }

	  RTMP_Log(RTMP_LOGINFO, "Connected...");

	  if (!RTMP_ConnectStream(&rtmp, dSeek))
	    {
	      nStatus = RD_FAILED;
	      break;
	    }
	}
      else
	{
	  nInitialFrameSize = 0;

          if (retries)
            {
	      RTMP_Log(RTMP_LOGERROR, "Failed to resume the stream\n\n");
	      if (!RTMP_IsTimedout(&rtmp))
	        nStatus = RD_FAILED;
	      else
	        nStatus = RD_INCOMPLETE;
	      break;
            }
	  RTMP_Log(RTMP_LOGINFO, "Connection timed out, trying to resume.\n\n");
          /* Did we already try pausing, and it still didn't work? */
          if (rtmp.m_pausing == 3)
            {
              /* Only one try at reconnecting... */
              retries = 1;
              dSeek = rtmp.m_pauseStamp;
              if (dStopOffset > 0)
                {
                  if (dStopOffset <= dSeek)
                    {
                      RTMP_LogPrintf("Already Completed\n");
		      nStatus = RD_SUCCESS;
		      break;
                    }
                }
              if (!RTMP_ReconnectStream(&rtmp, dSeek))
                {
	          RTMP_Log(RTMP_LOGERROR, "Failed to resume the stream\n\n");
	          if (!RTMP_IsTimedout(&rtmp))
		    nStatus = RD_FAILED;
	          else
		    nStatus = RD_INCOMPLETE;
	          break;
                }
            }
	  else if (!RTMP_ToggleStream(&rtmp))
	    {
	      RTMP_Log(RTMP_LOGERROR, "Failed to resume the stream\n\n");
	      if (!RTMP_IsTimedout(&rtmp))
		nStatus = RD_FAILED;
	      else
		nStatus = RD_INCOMPLETE;
	      break;
	    }
	  bResume = TRUE;
	}

      nStatus = Download(&rtmp, file, dSeek, dStopOffset, duration, bResume,
			 metaHeader, nMetaHeaderSize, initialFrame,
			 initialFrameType, nInitialFrameSize,
			 nSkipKeyFrames, bLiveStream, bHashes,
			 bOverrideBufferTime, bufferTime, &percent);
      free(initialFrame);
      initialFrame = NULL;

      /* If we succeeded, we're done.
       */
      if (nStatus != RD_INCOMPLETE || !RTMP_IsTimedout(&rtmp) || bLiveStream)
	break;
    }

  if (nStatus == RD_SUCCESS)
    {
      RTMP_LogPrintf("Download complete\n");
    }
  else if (nStatus == RD_INCOMPLETE)
    {
      RTMP_LogPrintf
	("Download may be incomplete (downloaded about %.2f%%), try resuming\n",
	 percent);
    }

  RTMP_Log(RTMP_LOGDEBUG, "Closing connection.\n");
  RTMP_Close(&rtmp);

  if (file != 0)
    fclose(file);

  return nStatus;
}
Пример #18
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;
}
Пример #19
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;
}
Пример #20
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(&timestamp,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;  
}  
Пример #21
0
int
main(int argc, char **argv)
{
	extern char *optarg;

	int nStatus = RD_SUCCESS;
	double percent = 0;
	double duration = 0.0;

	int nSkipKeyFrames = DEF_SKIPFRM; // skip this number of keyframes when resuming

	int bOverrideBufferTime = FALSE;  // if the user specifies a buffer time override this is true
	int bStdoutMode = TRUE;	  // if true print the stream directly to stdout, messages go to stderr
	int bResume = FALSE;	  // true in resume mode
	uint32_t dSeek = 0;		  // seek position in resume mode, 0 otherwise
	uint32_t bufferTime = DEF_BUFTIME;

	// meta header and initial frame for the resume mode (they are read from the file and compared with
	// the stream we are trying to continue
	char *metaHeader = 0;
	uint32_t nMetaHeaderSize = 0;

	// video keyframe for matching
	char *initialFrame = 0;
	uint32_t nInitialFrameSize = 0;
	int initialFrameType = 0; // tye: audio or video

	AVal hostname = { 0, 0 };
	AVal playpath = { 0, 0 };
	AVal subscribepath = { 0, 0 };
	AVal usherToken = { 0, 0 };	//Justin.tv auth token
	int port = -1;
	int protocol = RTMP_PROTOCOL_UNDEFINED;
	int retries = 0;
	int bLiveStream = FALSE;  // is it a live stream? then we can't seek/resume
	int bRealtimeStream = FALSE;  // If true, disable the BUFX hack (be patient)
	int bHashes = FALSE;	  // display byte counters not hashes by default

	long int timeout = DEF_TIMEOUT;	  // timeout connection after 120 seconds
	uint32_t dStartOffset = 0;	  // seek position in non-live mode
	uint32_t dStopOffset = 0;
	RTMP rtmp = { 0 };
	FILE *pLogFile;

	AVal fullUrl = { 0, 0 };
	AVal swfUrl = { 0, 0 };
	AVal tcUrl = { 0, 0 };
	AVal pageUrl = { 0, 0 };
	AVal app = { 0, 0 };
	AVal auth = { 0, 0 };
	AVal swfHash = { 0, 0 };
	uint32_t swfSize = 0;
	AVal flashVer = { 0, 0 };
	AVal sockshost = { 0, 0 };

#ifdef CRYPTO
	int swfAge = 30;  /* 30 days for SWF cache by default */
	int swfVfy = 0;
	unsigned char hash[RTMP_SWF_HASHLEN];
#endif

	char *flvFile = 0;

	signal(SIGINT, sigIntHandler);
	signal(SIGTERM, sigIntHandler);
#ifndef WIN32
	signal(SIGHUP, sigIntHandler);
	signal(SIGPIPE, sigIntHandler);
	signal(SIGQUIT, sigIntHandler);
#endif

	RTMP_debuglevel = RTMP_LOGALL;

	//pLogFile = fopen("log.txt", "w");
	//RTMP_LogSetOutput(pLogFile);

	// Check for --quiet option before printing any output
	int index = 0;
	while (index < argc)
	{
		if (strcmp(argv[index], "--quiet") == 0
			|| strcmp(argv[index], "-q") == 0)
			RTMP_debuglevel = RTMP_LOGCRIT;
		index++;
	}
#define RTMPDUMP_VERSION "2.4"
	RTMP_LogPrintf("RTMPDump %s\n", RTMPDUMP_VERSION);
	RTMP_LogPrintf
	("(c) 2010 Andrej Stepanchuk, Howard Chu, The Flvstreamer Team; license: GPL\n");

	if (!InitSockets())
	{
		RTMP_Log(RTMP_LOGERROR,
				 "Couldn't load sockets support on your platform, exiting!");
		return RD_FAILED;
	}

	/* sleep(30); */

	RTMP_Init(&rtmp);

	int opt;
/*  struct option longopts[] = {
	{"help", 0, NULL, 'h'},
	{"host", 1, NULL, 'n'},
	{"port", 1, NULL, 'c'},
	{"socks", 1, NULL, 'S'},
	{"protocol", 1, NULL, 'l'},
	{"playpath", 1, NULL, 'y'},
	{"playlist", 0, NULL, 'Y'},
	{"rtmp", 1, NULL, 'r'},
	{"swfUrl", 1, NULL, 's'},
	{"tcUrl", 1, NULL, 't'},
	{"pageUrl", 1, NULL, 'p'},
	{"app", 1, NULL, 'a'},
	{"auth", 1, NULL, 'u'},
	{"conn", 1, NULL, 'C'},
#ifdef CRYPTO
	{"swfhash", 1, NULL, 'w'},
	{"swfsize", 1, NULL, 'x'},
	{"swfVfy", 1, NULL, 'W'},
	{"swfAge", 1, NULL, 'X'},
#endif
	{"flashVer", 1, NULL, 'f'},
	{"live", 0, NULL, 'v'},
	{"flv", 1, NULL, 'o'},
	{"resume", 0, NULL, 'e'},
	{"timeout", 1, NULL, 'm'},
	{"buffer", 1, NULL, 'b'},
	{"skip", 1, NULL, 'k'},
	{"subscribe", 1, NULL, 'd'},
	{"start", 1, NULL, 'A'},
	{"stop", 1, NULL, 'B'},
	{"token", 1, NULL, 'T'},
	{"hashes", 0, NULL, '#'},
	{"debug", 0, NULL, 'z'},
	{"quiet", 0, NULL, 'q'},
	{"verbose", 0, NULL, 'V'},
	{0, 0, 0, 0}
  };*/

	while ((opt =
			getopt/*_long*/(argc, argv,
							"hVveqzr:s:t:p:a:b:f:o:u:C:n:c:l:y:Ym:k:d:A:B:T:w:x:W:X:S:#"/*,
							longopts, NULL*/)) != -1)
	{
		switch (opt)
		{
			case 'h':
				usage(argv[0]);
				return RD_SUCCESS;
#ifdef CRYPTO
			case 'w':
				{
					int res = hex2bin(optarg, &swfHash.av_val);
					if (res != RTMP_SWF_HASHLEN)
					{
						swfHash.av_val = NULL;
						RTMP_Log(RTMP_LOGWARNING,
								 "Couldn't parse swf hash hex string, not hexstring or not %d bytes, ignoring!", RTMP_SWF_HASHLEN);
					}
					swfHash.av_len = RTMP_SWF_HASHLEN;
					break;
				}
			case 'x':
				{
					int size = atoi(optarg);
					if (size <= 0)
					{
						RTMP_Log(RTMP_LOGERROR, "SWF Size must be at least 1, ignoring\n");
					}
					else
					{
						swfSize = size;
					}
					break;
				}
			case 'W':
				STR2AVAL(swfUrl, optarg);
				swfVfy = 1;
				break;
			case 'X':
				{
					int num = atoi(optarg);
					if (num < 0)
					{
						RTMP_Log(RTMP_LOGERROR, "SWF Age must be non-negative, ignoring\n");
					}
					else
					{
						swfAge = num;
					}
				}
				break;
#endif
			case 'k':
				nSkipKeyFrames = atoi(optarg);
				if (nSkipKeyFrames < 0)
				{
					RTMP_Log(RTMP_LOGERROR,
							 "Number of keyframes skipped must be greater or equal zero, using zero!");
					nSkipKeyFrames = 0;
				}
				else
				{
					RTMP_Log(RTMP_LOGDEBUG, "Number of skipped key frames for resume: %d",
							 nSkipKeyFrames);
				}
				break;
			case 'b':
				{
					int32_t bt = atol(optarg);
					if (bt < 0)
					{
						RTMP_Log(RTMP_LOGERROR,
								 "Buffer time must be greater than zero, ignoring the specified value %d!",
								 bt);
					}
					else
					{
						bufferTime = bt;
						bOverrideBufferTime = TRUE;
					}
					break;
				}
			case 'v':
				bLiveStream = TRUE;	  // no seeking or resuming possible!
				break;
			case 'R':
				bRealtimeStream = TRUE;	// seeking and resuming is still possible
				break;
			case 'd':
				STR2AVAL(subscribepath, optarg);
				break;
			case 'n':
				STR2AVAL(hostname, optarg);
				break;
			case 'c':
				port = atoi(optarg);
				break;
			case 'l':
				protocol = atoi(optarg);
				if (protocol < RTMP_PROTOCOL_RTMP || protocol > RTMP_PROTOCOL_RTMPTS)
				{
					RTMP_Log(RTMP_LOGERROR, "Unknown protocol specified: %d", protocol);
					return RD_FAILED;
				}
				break;
			case 'y':
				STR2AVAL(playpath, optarg);
				break;
			case 'Y':
				RTMP_SetOpt(&rtmp, &av_playlist, (AVal *)&av_true);
				break;
			case 'r':
				{
					AVal parsedHost, parsedApp, parsedPlaypath;
					unsigned int parsedPort = 0;
					int parsedProtocol = RTMP_PROTOCOL_UNDEFINED;

					if (!RTMP_ParseURL
						(optarg, &parsedProtocol, &parsedHost, &parsedPort,
						 &parsedPlaypath, &parsedApp))
					{
						RTMP_Log(RTMP_LOGWARNING, "Couldn't parse the specified url (%s)!",
								 optarg);
					}
					else
					{
						if (!hostname.av_len)
							hostname = parsedHost;
						if (port == -1)
							port = parsedPort;
						if (playpath.av_len == 0 && parsedPlaypath.av_len)
						{
							playpath = parsedPlaypath;
						}
						if (protocol == RTMP_PROTOCOL_UNDEFINED)
							protocol = parsedProtocol;
						if (app.av_len == 0 && parsedApp.av_len)
						{
							app = parsedApp;
						}
					}
					break;
				}
			case 'i':
				STR2AVAL(fullUrl, optarg);
				break;
			case 's':
				STR2AVAL(swfUrl, optarg);
				break;
			case 't':
				STR2AVAL(tcUrl, optarg);
				break;
			case 'p':
				STR2AVAL(pageUrl, optarg);
				break;
			case 'a':
				STR2AVAL(app, optarg);
				break;
			case 'f':
				STR2AVAL(flashVer, optarg);
				break;
			case 'o':
				flvFile = optarg;
				if (strcmp(flvFile, "-"))
					bStdoutMode = FALSE;

				break;
			case 'e':
				bResume = TRUE;
				break;
			case 'u':
				STR2AVAL(auth, optarg);
				break;
			case 'C': {
					AVal av;
					STR2AVAL(av, optarg);
					if (!RTMP_SetOpt(&rtmp, &av_conn, &av))
					{
						RTMP_Log(RTMP_LOGERROR, "Invalid AMF parameter: %s", optarg);
						return RD_FAILED;
					}
				}
				break;
			case 'm':
				timeout = atoi(optarg);
				break;
			case 'A':
				dStartOffset = (int) (atof(optarg) * 1000.0);
				break;
			case 'B':
				dStopOffset = (int) (atof(optarg) * 1000.0);
				break;
			case 'T': {
					AVal token;
					STR2AVAL(token, optarg);
					RTMP_SetOpt(&rtmp, &av_token, &token);
				}
				break;
			case '#':
				bHashes = TRUE;
				break;
			case 'q':
				RTMP_debuglevel = RTMP_LOGCRIT;
				break;
			case 'V':
				RTMP_debuglevel = RTMP_LOGDEBUG;
				break;
			case 'z':
				RTMP_debuglevel = RTMP_LOGALL;
				break;
			case 'S':
				STR2AVAL(sockshost, optarg);
				break;
			case 'j':
				STR2AVAL(usherToken, optarg);
				break;
			default:
				RTMP_LogPrintf("unknown option: %c\n", opt);
				usage(argv[0]);
				return RD_FAILED;
				break;
		}
	}

	if (!hostname.av_len && !fullUrl.av_len)
	{
		RTMP_Log(RTMP_LOGERROR,
				 "You must specify a hostname (--host) or url (-r \"rtmp://host[:port]/playpath\") containing a hostname");
		return RD_FAILED;
	}
	if (playpath.av_len == 0 && !fullUrl.av_len)
	{
		RTMP_Log(RTMP_LOGERROR,
				 "You must specify a playpath (--playpath) or url (-r \"rtmp://host[:port]/playpath\") containing a playpath");
		return RD_FAILED;
	}

	if (protocol == RTMP_PROTOCOL_UNDEFINED && !fullUrl.av_len)
	{
		RTMP_Log(RTMP_LOGWARNING,
				 "You haven't specified a protocol (--protocol) or rtmp url (-r), using default protocol RTMP");
		protocol = RTMP_PROTOCOL_RTMP;
	}
	if (port == -1 && !fullUrl.av_len)
	{
		RTMP_Log(RTMP_LOGWARNING,
				 "You haven't specified a port (--port) or rtmp url (-r), using default port 1935");
		port = 0;
	}
	if (port == 0 && !fullUrl.av_len)
	{
		if (protocol & RTMP_FEATURE_SSL)
			port = 443;
		else if (protocol & RTMP_FEATURE_HTTP)
			port = 80;
		else
			port = 1935;
	}

	if (flvFile == 0)
	{
		RTMP_Log(RTMP_LOGWARNING,
				 "You haven't specified an output file (-o filename), using stdout");
		bStdoutMode = TRUE;
	}

	if (bStdoutMode && bResume)
	{
		RTMP_Log(RTMP_LOGWARNING,
				 "Can't resume in stdout mode, ignoring --resume option");
		bResume = FALSE;
	}

	if (bLiveStream && bResume)
	{
		RTMP_Log(RTMP_LOGWARNING, "Can't resume live stream, ignoring --resume option");
		bResume = FALSE;
	}

#ifdef CRYPTO
	if (swfVfy)
	{
		if (RTMP_HashSWF(swfUrl.av_val, (unsigned int *)&swfSize, hash, swfAge) == 0)
		{
			swfHash.av_val = (char *)hash;
			swfHash.av_len = RTMP_SWF_HASHLEN;
		}
	}

	if (swfHash.av_len == 0 && swfSize > 0)
	{
		RTMP_Log(RTMP_LOGWARNING,
				 "Ignoring SWF size, supply also the hash with --swfhash");
		swfSize = 0;
	}

	if (swfHash.av_len != 0 && swfSize == 0)
	{
		RTMP_Log(RTMP_LOGWARNING,
				 "Ignoring SWF hash, supply also the swf size  with --swfsize");
		swfHash.av_len = 0;
		swfHash.av_val = NULL;
	}
#endif

	if (tcUrl.av_len == 0)
	{
		tcUrl.av_len = strlen(RTMPProtocolStringsLower[protocol]) +
					   hostname.av_len + app.av_len + sizeof("://:65535/");
		tcUrl.av_val = (char *) malloc(tcUrl.av_len);
		if (!tcUrl.av_val)
			return RD_FAILED;
		tcUrl.av_len = snprintf(tcUrl.av_val, tcUrl.av_len, "%s://%.*s:%d/%.*s",
								RTMPProtocolStringsLower[protocol], hostname.av_len,
								hostname.av_val, port, app.av_len, app.av_val);
	}

	int first = 1;

	// User defined seek offset
	if (dStartOffset > 0)
	{
		// Live stream
		if (bLiveStream)
		{
			RTMP_Log(RTMP_LOGWARNING,
					 "Can't seek in a live stream, ignoring --start option");
			dStartOffset = 0;
		}
	}

	if (!fullUrl.av_len)
	{
		RTMP_SetupStream(&rtmp, protocol, &hostname, port, &sockshost, &playpath,
						 &tcUrl, &swfUrl, &pageUrl, &app, &auth, &swfHash, swfSize,
						 &flashVer, &subscribepath, &usherToken, dSeek, dStopOffset, bLiveStream, timeout);
	}
	else
	{
		if (RTMP_SetupURL(&rtmp, fullUrl.av_val) == FALSE)
		{
			RTMP_Log(RTMP_LOGERROR, "Couldn't parse URL: %s", fullUrl.av_val);
			return RD_FAILED;
		}
	}

	/* Try to keep the stream moving if it pauses on us */
	if (!bLiveStream && !bRealtimeStream && !(protocol & RTMP_FEATURE_HTTP))
		rtmp.Link.lFlags |= RTMP_LF_BUFX;

	off_t size = 0;

	// ok, we have to get the timestamp of the last keyframe (only keyframes are seekable) / last audio frame (audio only streams)
	if (bResume)
	{
		nStatus =
		OpenResumeFile(flvFile, &file, &size, &metaHeader, &nMetaHeaderSize,
					   &duration);
		if (nStatus == RD_FAILED)
			goto clean;

		if (!file)
		{
			// file does not exist, so go back into normal mode
			bResume = FALSE;  // we are back in fresh file mode (otherwise finalizing file won't be done)
		}
		else
		{
			nStatus = GetLastKeyframe(file, nSkipKeyFrames,
									  &dSeek, &initialFrame,
									  &initialFrameType, &nInitialFrameSize);
			if (nStatus == RD_FAILED)
			{
				RTMP_Log(RTMP_LOGDEBUG, "Failed to get last keyframe.");
				goto clean;
			}

			if (dSeek == 0)
			{
				RTMP_Log(RTMP_LOGDEBUG,
						 "Last keyframe is first frame in stream, switching from resume to normal mode!");
				bResume = FALSE;
			}
		}
	}

	if (!file)
	{
		if (bStdoutMode)
		{
			file = stdout;
			SET_BINMODE(file);
		}
		else
		{
			file = fopen(flvFile, "w+b");
			if (file == 0)
			{
				RTMP_LogPrintf("Failed to open file! %s\n", flvFile);
				return RD_FAILED;
			}
		}
	}

#ifdef _DEBUG
	netstackdump = fopen("netstackdump", "wb");
	netstackdump_read = fopen("netstackdump_read", "wb");
#endif

	while (!RTMP_ctrlC)
	{
		RTMP_Log(RTMP_LOGDEBUG, "Setting buffer time to: %dms", bufferTime);
		RTMP_SetBufferMS(&rtmp, bufferTime);

		if (first)
		{
			first = 0;
			RTMP_LogPrintf("Connecting ...\n");

			if (!RTMP_Connect(&rtmp, NULL))
			{
				nStatus = RD_NO_CONNECT;
				break;
			}

			RTMP_Log(RTMP_LOGINFO, "Connected...");

			// User defined seek offset
			if (dStartOffset > 0)
			{
				// Don't need the start offset if resuming an existing file
				if (bResume)
				{
					RTMP_Log(RTMP_LOGWARNING,
							 "Can't seek a resumed stream, ignoring --start option");
					dStartOffset = 0;
				}
				else
				{
					dSeek = dStartOffset;
				}
			}

			// Calculate the length of the stream to still play
			if (dStopOffset > 0)
			{
				// Quit if start seek is past required stop offset
				if (dStopOffset <= dSeek)
				{
					RTMP_LogPrintf("Already Completed\n");
					nStatus = RD_SUCCESS;
					break;
				}
			}

			if (!RTMP_ConnectStream(&rtmp, dSeek))
			{
				nStatus = RD_FAILED;
				break;
			}
		}
		else
		{
			nInitialFrameSize = 0;

			if (retries)
			{
				RTMP_Log(RTMP_LOGERROR, "Failed to resume the stream\n\n");
				if (!RTMP_IsTimedout(&rtmp))
					nStatus = RD_FAILED;
				else
					nStatus	= RD_INCOMPLETE;
				break;
			}
			RTMP_Log(RTMP_LOGINFO, "Connection timed out, trying to resume.\n\n");
			/* Did we already try pausing, and it still didn't work? */
			if (rtmp.m_pausing == 3)
			{
				/* Only one try at reconnecting... */
				retries = 1;
				dSeek = rtmp.m_pauseStamp;
				if (dStopOffset > 0)
				{
					if (dStopOffset <= dSeek)
					{
						RTMP_LogPrintf("Already Completed\n");
						nStatus = RD_SUCCESS;
						break;
					}
				}
				if (!RTMP_ReconnectStream(&rtmp, dSeek))
				{
					RTMP_Log(RTMP_LOGERROR, "Failed to resume the stream\n\n");
					if (!RTMP_IsTimedout(&rtmp))
						nStatus = RD_FAILED;
					else
						nStatus	= RD_INCOMPLETE;
					break;
				}
			}
			else if (!RTMP_ToggleStream(&rtmp))
			{
				RTMP_Log(RTMP_LOGERROR, "Failed to resume the stream\n\n");
				if (!RTMP_IsTimedout(&rtmp))
					nStatus = RD_FAILED;
				else
					nStatus	= RD_INCOMPLETE;
				break;
			}
			bResume = TRUE;
		}

		nStatus = Download(&rtmp, file, dSeek, dStopOffset, duration, bResume,
						   metaHeader, nMetaHeaderSize, initialFrame,
						   initialFrameType, nInitialFrameSize, nSkipKeyFrames,
						   bStdoutMode, bLiveStream, bRealtimeStream, bHashes,
						   bOverrideBufferTime, bufferTime, &percent);
		free(initialFrame);
		initialFrame = NULL;

		/* If we succeeded, we're done.
		 */
		if (nStatus != RD_INCOMPLETE || !RTMP_IsTimedout(&rtmp) || bLiveStream)
			break;
	}

	if (nStatus == RD_SUCCESS)
	{
		RTMP_LogPrintf("Download complete\n");
	}
	else if (nStatus == RD_INCOMPLETE)
	{
		RTMP_LogPrintf
		("Download may be incomplete (downloaded about %.2f%%), try resuming\n",
		 percent);
	}

	clean:
	RTMP_Log(RTMP_LOGDEBUG, "Closing connection.\n");
	RTMP_Close(&rtmp);

	if (file != 0)
		fclose(file);

	CleanupSockets();

#ifdef _DEBUG
	if (netstackdump != 0)
		fclose(netstackdump);
	if (netstackdump_read != 0)
		fclose(netstackdump_read);
#endif

	fclose(pLogFile);
	return nStatus;
}
Пример #22
0
//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(&timestamp,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;  
}  
Пример #23
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;
}
Пример #24
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;
}