[rtmpdump] r257 - trunk/rtmpsrv.c

hyc subversion at mplayerhq.hu
Sun Feb 21 03:22:13 CET 2010


Author: hyc
Date: Sun Feb 21 03:22:12 2010
New Revision: 257

Log:
Spawn rtmpdump directly, don't just print the cmdline

Modified:
   trunk/rtmpsrv.c

Modified: trunk/rtmpsrv.c
==============================================================================
--- trunk/rtmpsrv.c	Sun Feb 21 03:16:19 2010	(r256)
+++ trunk/rtmpsrv.c	Sun Feb 21 03:22:12 2010	(r257)
@@ -39,6 +39,8 @@
 #include "thread.h"
 
 #ifdef linux
+#include <sys/types.h>
+#include <sys/wait.h>
 #include <linux/netfilter_ipv4.h>
 #endif
 
@@ -75,6 +77,8 @@ typedef struct
   int socket;
   int state;
   int streamID;
+  int arglen;
+  int argc;
   char *connect;
 
 } STREAMING_SERVER;
@@ -241,43 +245,202 @@ SendResultNumber(RTMP *r, double txn, do
   return RTMP_SendPacket(r, &packet, false);
 }
 
+SAVC(onStatus);
+SAVC(status);
+static const AVal av_NetStream_Play_Start = AVC("NetStream.Play.Start");
+static const AVal av_Started_playing = AVC("Started playing");
+static const AVal av_NetStream_Play_Stop = AVC("NetStream.Play.Stop");
+static const AVal av_Stopped_playing = AVC("Stopped playing");
+SAVC(details);
+SAVC(clientid);
+
+static bool
+SendPlayStart(RTMP *r)
+{
+  RTMPPacket packet;
+  char pbuf[384], *pend = pbuf+sizeof(pbuf);
+
+  packet.m_nChannel = 0x03;     // control channel (invoke)
+  packet.m_headerType = 1; /* RTMP_PACKET_SIZE_MEDIUM; */
+  packet.m_packetType = 0x14;   // INVOKE
+  packet.m_nInfoField1 = 0;
+  packet.m_nInfoField2 = 0;
+  packet.m_hasAbsTimestamp = 0;
+  packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
+
+  char *enc = packet.m_body;
+  enc = AMF_EncodeString(enc, pend, &av_onStatus);
+  enc = AMF_EncodeNumber(enc, pend, 0);
+  *enc++ = AMF_OBJECT;
+
+  enc = AMF_EncodeNamedString(enc, pend, &av_level, &av_status);
+  enc = AMF_EncodeNamedString(enc, pend, &av_code, &av_NetStream_Play_Start);
+  enc = AMF_EncodeNamedString(enc, pend, &av_description, &av_Started_playing);
+  enc = AMF_EncodeNamedString(enc, pend, &av_details, &r->Link.playpath);
+  enc = AMF_EncodeNamedString(enc, pend, &av_clientid, &av_clientid);
+  *enc++ = AMF_OBJECT_END;
+
+  packet.m_nBodySize = enc - packet.m_body;
+  return RTMP_SendPacket(r, &packet, false);
+}
+
+static bool
+SendPlayStop(RTMP *r)
+{
+  RTMPPacket packet;
+  char pbuf[384], *pend = pbuf+sizeof(pbuf);
+
+  packet.m_nChannel = 0x03;     // control channel (invoke)
+  packet.m_headerType = 1; /* RTMP_PACKET_SIZE_MEDIUM; */
+  packet.m_packetType = 0x14;   // INVOKE
+  packet.m_nInfoField1 = 0;
+  packet.m_nInfoField2 = 0;
+  packet.m_hasAbsTimestamp = 0;
+  packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
+
+  char *enc = packet.m_body;
+  enc = AMF_EncodeString(enc, pend, &av_onStatus);
+  enc = AMF_EncodeNumber(enc, pend, 0);
+  *enc++ = AMF_OBJECT;
+
+  enc = AMF_EncodeNamedString(enc, pend, &av_level, &av_status);
+  enc = AMF_EncodeNamedString(enc, pend, &av_code, &av_NetStream_Play_Stop);
+  enc = AMF_EncodeNamedString(enc, pend, &av_description, &av_Stopped_playing);
+  enc = AMF_EncodeNamedString(enc, pend, &av_details, &r->Link.playpath);
+  enc = AMF_EncodeNamedString(enc, pend, &av_clientid, &av_clientid);
+  *enc++ = AMF_OBJECT_END;
+
+  packet.m_nBodySize = enc - packet.m_body;
+  return RTMP_SendPacket(r, &packet, false);
+}
+
 static void
-dumpAMF(AMFObject *obj)
+spawn_dumper(int argc, AVal *av, char *cmd)
 {
-   int i;
-   const char opt[] = "NBSO Z";
+#ifdef WIN32
+  STARTUPINFO si = {0};
+  PROCESS_INFORMATION pi = {0};
 
-   for (i=0; i < obj->o_num; i++)
-     {
-       AMFObjectProperty *p = &obj->o_props[i];
-       printf(" -C ");
-       if (p->p_name.av_val)
-         printf("N");
-       printf("%c:", opt[p->p_type]);
-       if (p->p_name.av_val)
-         printf("%.*s:", p->p_name.av_len, p->p_name.av_val);
-       switch(p->p_type)
-         {
-         case AMF_BOOLEAN:
-           printf("%d", p->p_vu.p_number != 0);
-           break;
-         case AMF_STRING:
-           printf("%.*s", p->p_vu.p_aval.av_len, p->p_vu.p_aval.av_val);
-           break;
-         case AMF_NUMBER:
-           printf("%f", p->p_vu.p_number);
-           break;
-         case AMF_OBJECT:
-           printf("1");
-           dumpAMF(&p->p_vu.p_object);
-           printf(" -C O:0");
-           break;
-         case AMF_NULL:
-           break;
-         default:
-           printf("<type %d>", p->p_type);
-         }
+  si.cb = sizeof(si);
+  if (CreateProcess(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL,
+    &si, &pi))
+    {
+      CloseHandle(pi.hThread);
+      closeHandle(pi.hProcess);
+    }
+#else
+  /* reap any dead children */
+  while (waitpid(-1, NULL, WNOHANG) > 0);
+
+  if (fork() == 0) {
+    char **argv = malloc((argc+1) * sizeof(char *));
+    int i;
+
+    for (i=0; i<argc; i++) {
+      argv[i] = av[i].av_val;
+      argv[i][av[i].av_len] = '\0';
     }
+    argv[i] = NULL;
+    execvp(argv[0], argv);
+  }
+#endif
+}
+
+static int
+countAMF(AMFObject *obj, int *argc)
+{
+  int i, len;
+
+  for (i=0, len=0; i < obj->o_num; i++)
+    {
+      AMFObjectProperty *p = &obj->o_props[i];
+      len += 4;
+      (*argc)+= 2;
+      if (p->p_name.av_val)
+        len += 1;
+      len += 2;
+      if (p->p_name.av_val)
+        len += p->p_name.av_len + 1;
+      switch(p->p_type)
+        {
+        case AMF_BOOLEAN:
+          len += 1;
+          break;
+        case AMF_STRING:
+          len += p->p_vu.p_aval.av_len;
+          break;
+        case AMF_NUMBER:
+          len += 40;
+          break;
+        case AMF_OBJECT:
+          len += 9;
+          len += countAMF(&p->p_vu.p_object, argc);
+          (*argc) += 2;
+          break;
+        case AMF_NULL:
+        default:
+          break;
+        }
+    }
+  return len;
+}
+
+static char *
+dumpAMF(AMFObject *obj, char *ptr, AVal *argv, int *argc)
+{
+  int i, len, ac = *argc;
+  const char opt[] = "NBSO Z";
+
+  for (i=0, len=0; i < obj->o_num; i++)
+    {
+      AMFObjectProperty *p = &obj->o_props[i];
+      argv[ac].av_val = ptr+1;
+      argv[ac++].av_len = 2;
+      ptr += sprintf(ptr, " -C ");
+      argv[ac].av_val = ptr;
+      if (p->p_name.av_val)
+        *ptr++ = 'N';
+      *ptr++ = opt[p->p_type];
+      *ptr++ = ':';
+      if (p->p_name.av_val)
+        ptr += sprintf(ptr, "%.*s:", p->p_name.av_len, p->p_name.av_val);
+      switch(p->p_type)
+        {
+        case AMF_BOOLEAN:
+          *ptr++ = p->p_vu.p_number != 0 ? '1' : '0';
+          argv[ac].av_len = ptr - argv[ac].av_val;
+          break;
+        case AMF_STRING:
+          memcpy(ptr, p->p_vu.p_aval.av_val, p->p_vu.p_aval.av_len);
+          ptr += p->p_vu.p_aval.av_len;
+          argv[ac].av_len = ptr - argv[ac].av_val;
+          break;
+        case AMF_NUMBER:
+          ptr += sprintf(ptr, "%f", p->p_vu.p_number);
+          argv[ac].av_len = ptr - argv[ac].av_val;
+          break;
+        case AMF_OBJECT:
+          *ptr++ = '1';
+          argv[ac].av_len = ptr - argv[ac].av_val;
+          ac++;
+          *argc = ac;
+          ptr = dumpAMF(&p->p_vu.p_object, ptr, argv, argc);
+          ac = *argc;
+          argv[ac].av_val = ptr+1;
+          argv[ac++].av_len = 2;
+          argv[ac].av_val = ptr+4;
+          argv[ac].av_len = 3;
+          ptr += sprintf(ptr, " -C O:0");
+          break;
+        case AMF_NULL:
+        default:
+          argv[ac].av_len = ptr - argv[ac].av_val;
+          break;
+        }
+      ac++;
+    }
+  *argc = ac;
+  return ptr;
 }
 
 // Returns 0 for OK/Failed/error, 1 for 'Stop or Complete'
@@ -333,26 +496,36 @@ ServeInvoke(STREAMING_SERVER *server, RT
             {
               r->Link.app = pval;
               pval.av_val = NULL;
+	      server->arglen += 6 + pval.av_len;
+	      server->argc += 2;
             }
           else if (AVMATCH(&pname, &av_flashVer))
             {
               r->Link.flashVer = pval;
               pval.av_val = NULL;
+	      server->arglen += 6 + pval.av_len;
+	      server->argc += 2;
             }
           else if (AVMATCH(&pname, &av_swfUrl))
             {
               r->Link.swfUrl = pval;
               pval.av_val = NULL;
+	      server->arglen += 6 + pval.av_len;
+	      server->argc += 2;
             }
           else if (AVMATCH(&pname, &av_tcUrl))
             {
               r->Link.tcUrl = pval;
               pval.av_val = NULL;
+	      server->arglen += 6 + pval.av_len;
+	      server->argc += 2;
             }
           else if (AVMATCH(&pname, &av_pageUrl))
             {
               r->Link.pageUrl = pval;
               pval.av_val = NULL;
+	      server->arglen += 6 + pval.av_len;
+	      server->argc += 2;
             }
           else if (AVMATCH(&pname, &av_audioCodecs))
             {
@@ -375,6 +548,7 @@ ServeInvoke(STREAMING_SERVER *server, RT
           r->Link.extras.o_props = malloc(i*sizeof(AMFObjectProperty));
           memcpy(r->Link.extras.o_props, obj.o_props+3, i*sizeof(AMFObjectProperty));
           obj.o_num = 3;
+          server->arglen += countAMF(&r->Link.extras, &server->argc);
         }
       SendConnectResult(r, txn);
     }
@@ -388,75 +562,133 @@ ServeInvoke(STREAMING_SERVER *server, RT
     }
   else if (AVMATCH(&method, &av_play))
     {
-      char *file, *p, *q;
+      char *file, *p, *q, *cmd, *ptr;
+      AVal *argv, av;
+      int len, argc;
       RTMPPacket pc = {0};
       AMFProp_GetString(AMF_GetProp(&obj, NULL, 3), &r->Link.playpath);
+      /*
       r->Link.seekTime = AMFProp_GetNumber(AMF_GetProp(&obj, NULL, 4));
       if (obj.o_num > 5)
         r->Link.length = AMFProp_GetNumber(AMF_GetProp(&obj, NULL, 5));
+      */
       if (r->Link.tcUrl.av_len)
         {
-          printf("\nrtmpdump -r \"%s\"", r->Link.tcUrl.av_val);
+          len = server->arglen + r->Link.playpath.av_len + 4 +
+            sizeof("rtmpdump") + r->Link.playpath.av_len + 8;
+          server->argc += 5;
+
+          cmd = malloc(len + server->argc * sizeof(AVal));
+          ptr = cmd;
+          argv = (AVal *)(cmd + len);
+          argv[0].av_val = cmd;
+          argv[0].av_len = sizeof("rtmpdump")-1;
+          ptr += sprintf(ptr, "rtmpdump");
+          argc = 1;
+
+          argv[argc].av_val = ptr + 1;
+          argv[argc++].av_len = 2;
+          argv[argc].av_val = ptr + 5;
+          ptr += sprintf(ptr," -r \"%s\"", r->Link.tcUrl.av_val);
+          argv[argc++].av_len = r->Link.tcUrl.av_len;
+
           if (r->Link.app.av_val)
-            printf(" -a \"%s\"", r->Link.app.av_val);
+            {
+              argv[argc].av_val = ptr + 1;
+              argv[argc++].av_len = 2;
+              argv[argc].av_val = ptr + 5;
+              ptr += sprintf(ptr, " -a \"%s\"", r->Link.app.av_val);
+              argv[argc++].av_len = r->Link.app.av_len;
+            }
           if (r->Link.flashVer.av_val)
-            printf(" -f \"%s\"", r->Link.flashVer.av_val);
+            {
+              argv[argc].av_val = ptr + 1;
+              argv[argc++].av_len = 2;
+              argv[argc].av_val = ptr + 5;
+              ptr += sprintf(ptr, " -f \"%s\"", r->Link.flashVer.av_val);
+              argv[argc++].av_len = r->Link.flashVer.av_len;
+            }
           if (r->Link.swfUrl.av_val)
-            printf(" -W \"%s\"", r->Link.swfUrl.av_val);
-          printf(" -t \"%s\"", r->Link.tcUrl.av_val);
+            {
+              argv[argc].av_val = ptr + 1;
+              argv[argc++].av_len = 2;
+              argv[argc].av_val = ptr + 5;
+              ptr += sprintf(ptr, " -W \"%s\"", r->Link.swfUrl.av_val);
+              argv[argc++].av_len = r->Link.swfUrl.av_len;
+            }
           if (r->Link.pageUrl.av_val)
-            printf(" -p \"%s\"", r->Link.pageUrl.av_val);
-          if (r->Link.auth.av_val)
-            printf(" -u \"%s\"", r->Link.auth.av_val);
-          if (r->Link.extras.o_num)
             {
-              dumpAMF(&r->Link.extras);
-              AMF_Reset(&r->Link.extras);
+              argv[argc].av_val = ptr + 1;
+              argv[argc++].av_len = 2;
+              argv[argc].av_val = ptr + 5;
+              ptr += sprintf(ptr, " -p \"%s\"", r->Link.pageUrl.av_val);
+              argv[argc++].av_len = r->Link.pageUrl.av_len;
             }
-          if (r->Link.playpath.av_val)
+          if (r->Link.extras.o_num) {
+            ptr = dumpAMF(&r->Link.extras, ptr, argv, &argc);
+            AMF_Reset(&r->Link.extras);
+          }
+          argv[argc].av_val = ptr + 1;
+          argv[argc++].av_len = 2;
+          argv[argc].av_val = ptr + 5;
+          ptr += sprintf(ptr, " -y \"%.*s\"",
+            r->Link.playpath.av_len, r->Link.playpath.av_val);
+          argv[argc++].av_len = r->Link.playpath.av_len;
+
+          av = r->Link.playpath;
+          /* strip trailing URL parameters */
+          q = memchr(av.av_val, '?', av.av_len);
+          if (q)
+            av.av_len = q - av.av_val;
+          /* strip leading slash components */
+          for (p=av.av_val+av.av_len-1; p>=av.av_val; p--)
+            if (*p == '/')
+              {
+                p++;
+                av.av_len -= p - av.av_val;
+                av.av_val = p;
+                break;
+              }
+          /* skip leading dot */
+          if (av.av_val[0] == '.')
             {
-              AVal av = r->Link.playpath;
-              /* strip trailing URL parameters */
-              q = memchr(av.av_val, '?', av.av_len);
-              if (q)
-                av.av_len = q - av.av_val;
-              /* strip leading slash components */
-              for (p=av.av_val+av.av_len-1; p>=av.av_val; p--)
-                if (*p == '/')
-                  {
-                    p++;
-                    av.av_len -= p - av.av_val;
-                    av.av_val = p;
-                    break;
-                  }
-              /* skip leading dot */
-              if (av.av_val[0] == '.')
-                {
-                  av.av_val++;
-                  av.av_len--;
-                }
-              file = malloc(av.av_len+1);
+              av.av_val++;
+              av.av_len--;
+            }
+          file = malloc(av.av_len+5);
 
-              memcpy(file, av.av_val, av.av_len);
-              file[av.av_len] = '\0';
-              for (p=file; *p; p++)
-                if (*p == ':')
-                  *p = '_';
-	    }
-	  else
+          memcpy(file, av.av_val, av.av_len);
+          file[av.av_len] = '\0';
+          for (p=file; *p; p++)
+            if (*p == ':')
+              *p = '_';
+
+	  /* Add extension if none present */
+	  if (file[av.av_len - 4] != '.')
 	    {
-	      file="output.flv";
+	      strcpy(file+av.av_len, ".flv");
+	      av.av_len += 4;
 	    }
-          printf(" -y \"%.*s\" -o %s\n\n",
-            r->Link.playpath.av_len, r->Link.playpath.av_val, file);
+          argv[argc].av_val = ptr + 1;
+          argv[argc++].av_len = 2;
+          argv[argc].av_val = file;
+          argv[argc++].av_len = av.av_len;
+          ptr += sprintf(ptr, " -o %s", file);
+
+          printf("\n%s\n\n", cmd);
           fflush(stdout);
-	  if (r->Link.playpath.av_val)
-	    free(file);
+          spawn_dumper(argc, argv, cmd);
+          free(file);
+          free(cmd);
         }
       pc.m_body = server->connect;
       server->connect = NULL;
       RTMPPacket_Free(&pc);
       ret = 1;
+	  RTMP_SendCtrl(r, 0, 1, 0);
+	  SendPlayStart(r);
+	  RTMP_SendCtrl(r, 1, 1, 0);
+	  SendPlayStop(r);
     }
   AMF_Reset(&obj);
   return ret;
@@ -528,7 +760,8 @@ ServePacket(STREAMING_SERVER *server, RT
 
 	   obj.Dump(); */
 
-	ServeInvoke(server, r, packet, 1);
+	if (ServeInvoke(server, r, packet, 1))
+	  RTMP_Close(r);
 	break;
       }
     case 0x12:
@@ -618,6 +851,7 @@ void doServe(STREAMING_SERVER * server,	
           goto cleanup;
         }
     }
+  server->arglen = 0;
   while (RTMP_IsConnected(&rtmp) && RTMP_ReadPacket(&rtmp, &packet))
     {
       if (!RTMPPacket_IsReady(&packet))
@@ -635,7 +869,6 @@ cleanup:
   rtmp.Link.swfUrl.av_val = NULL;
   rtmp.Link.pageUrl.av_val = NULL;
   rtmp.Link.app.av_val = NULL;
-  rtmp.Link.auth.av_val = NULL;
   rtmp.Link.flashVer.av_val = NULL;
   LogPrintf("done!\n\n");
 


More information about the rtmpdump mailing list