From 97357aed9866e0d24bf4b976d2304c8d9f3b9379 Mon Sep 17 00:00:00 2001
From: Thulinma <jaron@vietors.com>
Date: Mon, 21 Mar 2011 18:23:32 +0100
Subject: [PATCH] New FLV_Pack style, hopefully some fixes for HTTP dynamic

---
 Connector_HTTP/main.cpp  |  64 ++++++++++----------
 Connector_RTMP/Makefile  |   6 +-
 HTTP_Box_Parser/main.cpp |  23 +-------
 util/flv.cpp             |   8 +--
 util/flv_data.cpp        |   8 +--
 util/flv_pack.cpp        | 123 +++++++++++++++++++++++++++++++++++++++
 util/flv_sock.cpp        |   8 +--
 7 files changed, 163 insertions(+), 77 deletions(-)
 create mode 100644 util/flv_pack.cpp

diff --git a/Connector_HTTP/main.cpp b/Connector_HTTP/main.cpp
index 8d0bd18f..a0bf743a 100644
--- a/Connector_HTTP/main.cpp
+++ b/Connector_HTTP/main.cpp
@@ -46,15 +46,6 @@ std::string base64_encode(std::string const input) {
   return ret;
 }//base64_encode
 
-int FlvToFragNum( FLV_Pack * tag ) {
-  int Timestamp = (tag->data[7] << 24 ) + (tag->data[4] << 16 ) + (tag->data[5] << 8 ) + (tag->data[6] );
-  return (Timestamp / 10000) + 1;
-}
-
-int FlvGetTimestamp( FLV_Pack * tag ) {
-  return ( (tag->data[7] << 24 ) + (tag->data[4] << 16 ) + (tag->data[5] << 8 ) + (tag->data[6] ) );
-}
-
 std::string GetMetaData( ) {
   AMFType amfreply("container", (unsigned char)AMF0_DDV_CONTAINER);
   amfreply.addContent(AMFType("onMetaData",(unsigned char)AMF0_STRING));
@@ -128,12 +119,13 @@ int mainHandler(int CONN_fd){
   std::string FlashMeta;
   bool Flash_ManifestSent = false;
   int Flash_RequestPending = 0;
+  unsigned int Flash_StartTime;
   std::queue<std::string> Flash_FragBuffer;
   FLV_Pack * tag = 0;
-  char * Video_Init_Data = 0;
-  int Video_Init_Len = 0;
-  char * Audio_Init_Data = 0;
-  int Audio_Init_Len = 0;
+  FLV_Pack Audio_Init;
+  FLV_Pack Video_Init;
+  bool FlashFirstVideo = false;
+  bool FlashFirstAudio = false;
   HTTPReader HTTP_R, HTTP_S;//HTTP Receiver en HTTP Sender.
 
   int retval;
@@ -253,25 +245,23 @@ int mainHandler(int CONN_fd){
         default:
           if (FLV_GetPacket(tag, ss)){//able to read a full packet?f
             if (handler == HANDLER_FLASH){
-              if(tag->data[0] != 0x12 ) {
-                if ((tag->isKeyframe) && (Video_Init_Data == 0)){
+              if (tag->tagTime() > 0){
+                if (Flash_StartTime == 0){
+                  Flash_StartTime = tag->tagTime();
+                }
+                tag->tagTime(tag->tagTime() - Flash_StartTime);
+              }
+              if (tag->data[0] != 0x12 ) {
+                if ((tag->isKeyframe) && (Video_Init.len == 0)){
                   if (((tag->data[11] & 0x0f) == 7) && (tag->data[12] == 0)){
-                    tag->data[4] = 0;//timestamp to zero
-                    tag->data[5] = 0;//timestamp to zero
-                    tag->data[6] = 0;//timestamp to zero
-                    Video_Init_Data = (char*)malloc(tag->len);
-                    Video_Init_Len = tag->len;
-                    memcpy(Video_Init_Data, tag->data, tag->len);
+                    tag->tagTime(0);//timestamp to zero
+                    Video_Init = *tag;
                   }
                 }
-                if ((tag->data[0] == 0x08) && (Audio_Init_Data == 0)){
+                if ((tag->data[0] == 0x08) && (Audio_Init.len == 0)){
                   if (((tag->data[11] & 0xf0) >> 4) == 10){//aac packet
-                    tag->data[4] = 0;//timestamp to zero
-                    tag->data[5] = 0;//timestamp to zero
-                    tag->data[6] = 0;//timestamp to zero
-                    Audio_Init_Data = (char*)malloc(tag->len);
-                    Audio_Init_Len = tag->len;
-                    memcpy(Audio_Init_Data, tag->data, tag->len);
+                    tag->tagTime(0);//timestamp to zero
+                    Audio_Init = *tag;
                   }
                 }
                 if (tag->isKeyframe){
@@ -282,8 +272,18 @@ int mainHandler(int CONN_fd){
                     #endif
                   }
                   FlashBuf.clear();
-                  if (Video_Init_Len > 0) FlashBuf.append(Video_Init_Data, Video_Init_Len);
-                  if (Audio_Init_Len > 0) FlashBuf.append(Audio_Init_Data, Audio_Init_Len);
+                  FlashFirstVideo = true;
+                  FlashFirstAudio = true;
+                }
+                if (FlashFirstVideo && (tag->data[0] == 0x09) && (Video_Init.len > 0)){
+                  Video_Init.tagTime(tag->tagTime());
+                  FlashBuf.append(Video_Init.data, Video_Init.len);
+                  FlashFirstVideo = false;
+                }
+                if (FlashFirstAudio && (tag->data[0] == 0x08) && (Audio_Init.len > 0)){
+                  Audio_Init.tagTime(tag->tagTime());
+                  FlashBuf.append(Audio_Init.data, Audio_Init.len);
+                  FlashFirstAudio = false;
                 }
                 FlashBuf.append(tag->data,tag->len);
               } else {
@@ -293,7 +293,7 @@ int mainHandler(int CONN_fd){
                   HTTP_S.Clean();
                   HTTP_S.SetHeader("Content-Type","text/xml");
                   HTTP_S.SetHeader("Cache-Control","no-cache");
-                  HTTP_S.SetBody(BuildManifest(FlashMeta, Movie, FlvGetTimestamp(tag)));
+                  HTTP_S.SetBody(BuildManifest(FlashMeta, Movie, tag->tagTime()));
                   HTTP_S.SendResponse(CONN_fd, "200", "OK");
                 }
               }
@@ -318,8 +318,6 @@ int mainHandler(int CONN_fd){
     }
   }
   close(CONN_fd);
-  if (Video_Init_Data){free(Video_Init_Data);}
-  if (Audio_Init_Data){free(Audio_Init_Data);}
   if (inited) close(ss);
   #if DEBUG >= 1
   if (All_Hell_Broke_Loose){fprintf(stderr, "All Hell Broke Loose\n");}
diff --git a/Connector_RTMP/Makefile b/Connector_RTMP/Makefile
index c74dc1aa..71f3ffb0 100644
--- a/Connector_RTMP/Makefile
+++ b/Connector_RTMP/Makefile
@@ -1,7 +1,8 @@
 SRC = main.cpp
 OBJ = $(SRC:.cpp=.o)
 OUT = Connector_RTMP
-INCLUDES = 
+INCLUDES =
+STATIC =
 CCFLAGS = -Wall -Wextra -funsigned-char -g
 CC = $(CROSS)g++
 LD = $(CROSS)ld
@@ -13,7 +14,7 @@ default: $(OUT)
 .cpp.o:
 	$(CC) $(INCLUDES) $(CCFLAGS) -c $< -o $@
 $(OUT): $(OBJ) chunkstream.cpp parsechunks.cpp handshake.cpp crypto.cpp amf.cpp
-	$(CC) $(LIBS) -o $(OUT) $(OBJ)
+	$(CC) -o $(OUT) $(OBJ) $(STATIC) $(LIBS)
 clean:
 	rm -rf $(OBJ) $(OUT) Makefile.bak *~
 install: $(OUT)
@@ -21,3 +22,4 @@ install: $(OUT)
 	cp -f ./$(OUT) /usr/bin/
 	cp -f ./RTMP_Conn /etc/init.d/
 	service RTMP_Conn start
+
diff --git a/HTTP_Box_Parser/main.cpp b/HTTP_Box_Parser/main.cpp
index 1d06741e..1be5951a 100644
--- a/HTTP_Box_Parser/main.cpp
+++ b/HTTP_Box_Parser/main.cpp
@@ -5,24 +5,7 @@
 #include "../util/MP4/box_includes.h"
 #include "../util/flv_data.cpp"
 
-std::string tagType(FLV_Pack * F){
-  switch (F->data[0]){
-    case 0x09:
-      if (F->isKeyframe){
-        return "video keyframe";
-      }else{
-        return "video";
-      }
-      break;
-    case 0x08: return "audio"; break;
-    case 0x12: return "data"; break;
-  }
-  return "unknown";
-}
-
-int main( ) {
-  std::string temp;
-
+int main(){
   HTTPReader H;
   FLV_Pack * F = 0;
   unsigned int P = 0;
@@ -30,11 +13,10 @@ int main( ) {
   while (H.ReadSocket(stdin) || H.CleanForNext()){
     if (H.body.size() > 10000){
       Box * TestBox = new Box((uint8_t*)H.body.c_str(), H.body.size());
-      TestBox->Parse();
       P = 0;
       while (TestBox->PayloadSize > P){
         if (FLV_GetPacket(F, (char*)TestBox->Payload, TestBox->PayloadSize, P)){
-          std::cout << "Got a " << F->len << " bytes " << tagType(F) << " FLV tag." << std::endl;
+          std::cout << "Got a " << F->len << " bytes " << F->tagType() << " FLV tag of time " << F->tagTime() << "." << std::endl;
         }
       }
       delete TestBox;
@@ -42,5 +24,4 @@ int main( ) {
       std::cout << "Skipped too small fragment" << std::endl;
     }
   }
-
 }
diff --git a/util/flv.cpp b/util/flv.cpp
index c04d977a..8780077d 100644
--- a/util/flv.cpp
+++ b/util/flv.cpp
@@ -1,12 +1,6 @@
 #include <unistd.h> //for read()
 #include <fcntl.h>
-
-struct FLV_Pack {
-  int len;
-  int buf;
-  bool isKeyframe;
-  char * data;
-};//FLV_Pack
+#include "flv_pack.cpp"
 
 char FLVHeader[13];
 bool All_Hell_Broke_Loose = false;
diff --git a/util/flv_data.cpp b/util/flv_data.cpp
index 28a18da4..ac176ee5 100644
--- a/util/flv_data.cpp
+++ b/util/flv_data.cpp
@@ -1,12 +1,6 @@
 #include <unistd.h> //for read()
 #include <fcntl.h>
-
-struct FLV_Pack {
-  int len;
-  int buf;
-  bool isKeyframe;
-  char * data;
-};//FLV_Pack
+#include "flv_pack.cpp"
 
 char FLVHeader[13];
 bool All_Hell_Broke_Loose = false;
diff --git a/util/flv_pack.cpp b/util/flv_pack.cpp
new file mode 100644
index 00000000..a60bf6a5
--- /dev/null
+++ b/util/flv_pack.cpp
@@ -0,0 +1,123 @@
+#pragma once
+
+class FLV_Pack {
+  public:
+    int len;
+    int buf;
+    bool isKeyframe;
+    char * data;
+    std::string tagType(){
+      std::string R = "";
+      switch (data[0]){
+        case 0x09:
+          switch (data[11] & 0x0F){
+            case 1: R += "JPEG"; break;
+            case 2: R += "H263"; break;
+            case 3: R += "ScreenVideo1"; break;
+            case 4: R += "VP6"; break;
+            case 5: R += "VP6Alpha"; break;
+            case 6: R += "ScreenVideo2"; break;
+            case 7: R += "AVC"; break;
+            default: R += "unknown"; break;
+          }
+          R += " video ";
+          switch (data[11] & 0xF0){
+            case 0x10: R += "keyframe"; break;
+            case 0x20: R += "iframe"; break;
+            case 0x30: R += "disposableiframe"; break;
+            case 0x40: R += "generatedkeyframe"; break;
+            case 0x50: R += "videoinfo"; break;
+          }
+          if ((data[11] & 0x0F) == 7){
+            switch (data[12]){
+              case 0: R += " header"; break;
+              case 1: R += " NALU"; break;
+              case 2: R += " endofsequence"; break;
+            }
+          }
+          break;
+        case 0x08:
+          switch (data[11] & 0xF0){
+            case 0x00: R += "linear PCM PE"; break;
+            case 0x10: R += "ADPCM"; break;
+            case 0x20: R += "MP3"; break;
+            case 0x30: R += "linear PCM LE"; break;
+            case 0x40: R += "Nelly16kHz"; break;
+            case 0x50: R += "Nelly8kHz"; break;
+            case 0x60: R += "Nelly"; break;
+            case 0x70: R += "G711A-law"; break;
+            case 0x80: R += "G711mu-law"; break;
+            case 0x90: R += "reserved"; break;
+            case 0xA0: R += "AAC"; break;
+            case 0xB0: R += "Speex"; break;
+            case 0xE0: R += "MP38kHz"; break;
+            case 0xF0: R += "DeviceSpecific"; break;
+            default: R += "unknown"; break;
+          }
+          switch (data[11] & 0x0C){
+            case 0x0: R += " 5.5kHz"; break;
+            case 0x4: R += " 11kHz"; break;
+            case 0x8: R += " 22kHz"; break;
+            case 0xC: R += " 44kHz"; break;
+          }
+          switch (data[11] & 0x02){
+            case 0: R += " 8bit"; break;
+            case 2: R += " 16bit"; break;
+          }
+          switch (data[11] & 0x01){
+            case 0: R += " mono"; break;
+            case 1: R += " stereo"; break;
+          }
+          R += " audio";
+          if ((data[12] == 0) && ((data[11] & 0xF0) == 0xA0)){
+            R += " initdata";
+          }
+          break;
+        case 0x12:
+          R += "(meta)data";
+          break;
+        default:
+          R += "unknown";
+          break;
+      }
+      return R;
+    };//tagtype
+    unsigned int tagTime(){
+      return (data[4] << 16) + (data[5] << 8) + data[6] + (data[7] << 24);
+    }//tagTime getter
+    void tagTime(unsigned int T){
+      data[4] = ((T >> 16) & 0xFF);
+      data[5] = ((T >> 8) & 0xFF);
+      data[6] = (T & 0xFF);
+      data[7] = ((T >> 24) & 0xFF);
+    }//tagTime setter
+    FLV_Pack(){
+      len = 0; buf = 0; data = 0; isKeyframe = false;
+    }//empty constructor
+    FLV_Pack(const FLV_Pack& O){
+      buf = O.len;
+      len = buf;
+      if (len > 0){
+        data = (char*)malloc(len);
+        memcpy(data, O.data, len);
+      }else{
+        data = 0;
+      }
+      isKeyframe = O.isKeyframe;
+    }//copy constructor
+    FLV_Pack & operator= (const FLV_Pack& O){
+      if (this != &O){//no self-assignment
+        if (data != 0){free(data);}
+        buf = O.len;
+        len = buf;
+        if (len > 0){
+          data = (char*)malloc(len);
+          memcpy(data, O.data, len);
+        }else{
+          data = 0;
+        }
+        isKeyframe = O.isKeyframe;
+      }
+      return *this;
+    }//assignment operator
+};//FLV_Pack
diff --git a/util/flv_sock.cpp b/util/flv_sock.cpp
index be752d73..8b74c9aa 100644
--- a/util/flv_sock.cpp
+++ b/util/flv_sock.cpp
@@ -1,10 +1,4 @@
-
-struct FLV_Pack {
-  int len;
-  int buf;
-  bool isKeyframe;
-  char * data;
-};//FLV_Pack
+#include "flv_pack.cpp"
 
 char FLVHeader[13];
 bool All_Hell_Broke_Loose = false;