Import rtmpdump v1.6.
authordiego <diego@400ebc74-4327-4243-bc38-086b20814532>
Fri, 9 Oct 2009 19:22:42 +0000 (19:22 +0000)
committerdiego <diego@400ebc74-4327-4243-bc38-086b20814532>
Fri, 9 Oct 2009 19:22:42 +0000 (19:22 +0000)
git-svn-id: svn://svn.mplayerhq.hu/rtmpdump@6 400ebc74-4327-4243-bc38-086b20814532

ChangeLog
README
bytes.cpp
rtmp.cpp
rtmp.h
rtmpdump.cpp
rtmppacket.cpp
rtmppacket.h
streams.cpp

index 13f3c24..540d23b 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,16 @@
 RTMPDump
 Copyright 2008-2009 Andrej Stepanchuk; Distributed under the GPL v2
 
+17 May 2009, v1.6
+
+- big endian alignment fix, should fix sparc64 and others
+
+- moved timestamp handling into RTMP protocol innings, all packets have
+absolute timestamps now, when seeking the stream will start with timestamp 0
+even if seeked to a later position!
+
+- fixed a timestamp bug (should fix async audio/video problems)
+
 30 Apr 2009, v1.5a
 
 - fixed host name resolution bug (caused unexpected crashes if DNS resolution
diff --git a/README b/README
index 897fb6d..5bbca81 100644 (file)
--- a/README
+++ b/README
@@ -1,4 +1,4 @@
-RTMP Dumper v1.5a
+RTMP Dump v1.6
 (C) 2009 Andrej Stepanchuk
 License: GPLv2
 
@@ -17,17 +17,16 @@ To download an rtmp stream use
 
   $ ./get_iplayer --raw --force --get 1 --vmode flashhigh --rtmp --rtmpdump "./rtmpdump"
 
-rtmpdump still supports hulu (only the non RTMPE streams for now) if you can invoke it with
-a correct rtmp url.
+rtmpdump still supports hulu if you can invoke it with a correct rtmp url.
 
-SWFVerification
----------------
+SWF Verification
+----------------
 
 Download the swf player you want to use for SWFVerification, unzip it using
 
  $ flasm -x file.swf
 
-It will show the decompressed filesize, use it for --swfsize Filesize.
+It will show the decompressed filesize, use it for --swfsize
 
 Now generate the hash
 
index d5ca3cb..54ca462 100644 (file)
--- a/bytes.cpp
+++ b/bytes.cpp
@@ -58,7 +58,9 @@ double ReadNumber(const char *data)
 {
 #if __FLOAT_WORD_ORDER == __BYTE_ORDER
 #if __BYTE_ORDER == __BIG_ENDIAN
-       return *((double *)data);
+       double dVal;
+       memcpy(&dVal, data, 8);
+       return dVal;
 #elif __BYTE_ORDER == __LITTLE_ENDIAN
        uint64_t in  = *((uint64_t*)data);
        uint64_t res = __bswap_64(in);
index 3071e16..88aa3f2 100644 (file)
--- a/rtmp.cpp
+++ b/rtmp.cpp
@@ -1029,10 +1029,13 @@ bool CRTMP::ReadPacket(RTMPPacket &packet)
 
   int nSize = packetSize[packet.m_headerType];
   
-//  Log(LOGDEBUG, "%s, reading RTMP packet chunk on channel %x, headersz %i", __FUNCTION__, packet.m_nChannel, nSize);
+  if (nSize == RTMP_LARGE_HEADER_SIZE) // if we get a full header the timestamp is absolute
+    packet.m_hasAbsTimestamp = true; 
 
-  if (nSize < RTMP_LARGE_HEADER_SIZE) // using values from the last message of this channel
+  if (nSize < RTMP_LARGE_HEADER_SIZE) { // using values from the last message of this channel
+    packet.FreePacketHeader(); // test whether this avoids memory leak
     packet = m_vecChannelsIn[packet.m_nChannel];
+  }
   
   nSize--;
 
@@ -1046,6 +1049,8 @@ bool CRTMP::ReadPacket(RTMPPacket &packet)
   if (nSize >= 3)
     packet.m_nInfoField1 = ReadInt24(header);
 
+  //Log(LOGDEBUG, "%s, reading RTMP packet chunk on channel %x, headersz %i, timestamp %i, abs timestamp %i", __FUNCTION__, packet.m_nChannel, nSize, packet.m_nInfoField1, packet.m_hasAbsTimestamp); 
+
   if (nSize >= 6)
   {
     packet.m_nBodySize = ReadInt24(header + 3);
@@ -1084,10 +1089,19 @@ bool CRTMP::ReadPacket(RTMPPacket &packet)
 
   if (packet.IsReady())
   {
+    packet.m_nTimeStamp = packet.m_nInfoField1;
+    
+    // make packet's timestamp absolute 
+    if (!packet.m_hasAbsTimestamp) 
+      packet.m_nTimeStamp += m_channelTimestamp[packet.m_nChannel]; // timestamps seem to be always relative!! 
+      
+    m_channelTimestamp[packet.m_nChannel] = packet.m_nTimeStamp; 
     // reset the data from the stored packet. we keep the header since we may use it later if a new packet for this channel
     // arrives and requests to re-use some info (small packet header)
     m_vecChannelsIn[packet.m_nChannel].m_body = NULL;
     m_vecChannelsIn[packet.m_nChannel].m_nBytesRead = 0;
+    m_vecChannelsIn[packet.m_nChannel].m_hasAbsTimestamp = false; // can only be false if we reuse header
   }
   else
     packet.m_body = NULL; // so it wont be erased on "free"
diff --git a/rtmp.h b/rtmp.h
index d3c399b..43aca0b 100644 (file)
--- a/rtmp.h
+++ b/rtmp.h
 #ifdef WIN32
 #include <winsock.h>
 #else
-//#include <sys/types.h>
+#include <sys/types.h>
 #include <sys/socket.h>
 #include <netdb.h>
 #include <arpa/inet.h>
-//#include <unistd.h>
+#include <unistd.h>
 #include <netinet/in.h>
 #include <errno.h>
 #endif
@@ -207,6 +207,7 @@ class CRTMP
       int  m_nBufferSize;   // number of unprocessed bytes in buffer
       RTMPPacket m_vecChannelsIn[64];
       RTMPPacket m_vecChannelsOut[64];
+      int  m_channelTimestamp[64]; // abs timestamp of last packet
 
       double m_fDuration; // duration of stream in seconds
   };
index 4d984ea..edf220e 100644 (file)
@@ -36,7 +36,7 @@
 
 using namespace RTMP_LIB;
 
-#define RTMPDUMP_VERSION       "v1.5a"
+#define RTMPDUMP_VERSION       "v1.6"
 
 #define RD_SUCCESS             0
 #define RD_FAILED              1
@@ -62,7 +62,7 @@ inline void CleanupSockets() {
 #endif
 }
 
-uint32_t nTimeStamp = 0;
+//uint32_t nTimeStamp = 0;
 
 #ifdef _DEBUG
 uint32_t debugTS = 0;
@@ -106,6 +106,7 @@ int WriteStream(
                unsigned int len,               // length of buffer if preallocated
                uint32_t *tsm,                  // pointer to timestamp, will contain timestamp of last video packet returned
                bool bResume,                   // resuming mode, will not write FLV header and compare metaHeader and first kexframe
+               uint32_t nResumeTS,             // resume keyframe timestamp
                char *metaHeader,               // pointer to meta header (if bResume == TRUE)
                uint32_t nMetaHeaderSize,       // length of meta header, if zero meta header check omitted (if bResume == TRUE)
                char *initialFrame,             // pointer to initial keyframe (no FLV header or tagSize, raw data) (if bResume == TRUE)
@@ -142,14 +143,13 @@ int WriteStream(
                        return 0;
                }
 #ifdef _DEBUG
-               debugTS += packet.m_nInfoField1;
-               Log(LOGDEBUG, "type: %02X, size: %d, TS: %d ms, sent TS: %d ms", packet.m_packetType, nPacketLen, debugTS, packet.m_nInfoField1);
+               Log(LOGDEBUG, "type: %02X, size: %d, TS: %d ms, abs TS: %d", packet.m_packetType, nPacketLen, packet.m_nTimeStamp, packet.m_hasAbsTimestamp);
                if(packet.m_packetType == 0x09)
                        Log(LOGDEBUG, "frametype: %02X", (*packetBody & 0xf0));
 #endif
 
                // check the header if we get one
-               if(bResume && packet.m_nInfoField1 == 0) {
+               if(bResume && packet.m_nTimeStamp == 0) {
                        if(nMetaHeaderSize > 0 && packet.m_packetType == 0x12) {
                        
                                RTMP_LIB::AMFObject metaObj;
@@ -187,7 +187,7 @@ int WriteStream(
                                // filter it out !!
                                //
                                if(packet.m_packetType == 0x16) {
-                                       // basically we have to find the keyframe with the correct TS being nTimeStamp
+                                       // basically we have to find the keyframe with the correct TS being nResumeTS
                                        unsigned int pos=0;
                                        uint32_t ts = 0;
 
@@ -202,7 +202,7 @@ int WriteStream(
                                                #endif
                                                // ok, is it a keyframe!!!: well doesn't work for audio!
                                                if(packetBody[pos /*6928, test 0*/] == initialFrameType /* && (packetBody[11]&0xf0) == 0x10*/) {
-                                                       if(ts == nTimeStamp) {
+                                                       if(ts == nResumeTS) {
                                                                Log(LOGDEBUG, "Found keyframe with resume-keyframe timestamp!");
                                                                if(nInitialFrameSize != dataSize || memcmp(initialFrame, packetBody+pos+11, nInitialFrameSize) != 0) {
                                                                        Log(LOGERROR, "FLV Stream: Keyframe doesn't match!");
@@ -221,13 +221,13 @@ int WriteStream(
 
                                                                goto stopKeyframeSearch;
 
-                                                       } else if(nTimeStamp < ts) {
+                                                       } else if(nResumeTS < ts) {
                                                                goto stopKeyframeSearch; // the timestamp ts will only increase with further packets, wait for seek
                                                        }
                                                } 
                                                pos += (11+dataSize+4);
                                        }
-                                       if(ts < nTimeStamp) {
+                                       if(ts < nResumeTS) {
                                                Log(LOGERROR, "First packet does not contain keyframe, all timestamps are smaller than the keyframe timestamp, so probably the resume seek failed?");
                                        }
 stopKeyframeSearch:
@@ -240,7 +240,7 @@ stopKeyframeSearch:
                        }
                }
                
-               if(bResume && packet.m_nInfoField1 > 0 && (bFoundFlvKeyframe || bFoundKeyframe)) {
+               if(bResume && packet.m_nTimeStamp > 0 && (bFoundFlvKeyframe || bFoundKeyframe)) {
                        // another problem is that the server can actually change from 09/08 video/audio packets to an FLV stream
                        // or vice versa and our keyframe check will prevent us from going along with the new stream if we resumed
                        //
@@ -273,7 +273,7 @@ stopKeyframeSearch:
                // so don't mess around with multiple copies sent by the server to us! (if the keyframe is found at a later position
                // there is only one copy and it will be ignored by the preceding if clause)
                if(!bStopIgnoring && bResume && packet.m_packetType != 0x16) { // exclude type 0x16 (FLV) since it can conatin several FLV packets
-                       if(packet.m_nInfoField1 == 0) {
+                       if(packet.m_nTimeStamp == 0) {
                                return 0;
                        } else {
                                bStopIgnoring = true; // stop ignoring packets
@@ -294,6 +294,8 @@ stopKeyframeSearch:
                }
                char *ptr = *buf;
 
+               uint32_t nTimeStamp = 0; // use to return timestamp of last processed packet
+
                // audio (0x08), video (0x09) or metadata (0x12) packets :
                // construct 11 byte header then add rtmp packet's data
                if(packet.m_packetType == 0x08 || packet.m_packetType == 0x09 || packet.m_packetType == 0x12)
@@ -301,11 +303,9 @@ stopKeyframeSearch:
                        // set data type
                        *dataType |= (((packet.m_packetType == 0x08)<<2)|(packet.m_packetType == 0x09));
 
-                       nTimeStamp += packet.m_nInfoField1;
+                       nTimeStamp = nResumeTS + packet.m_nTimeStamp;
                        prevTagSize = 11 + nPacketLen;
-                       //nTimeStamp += packet.m_nInfoField1;
 
-                       //Log(LOGDEBUG, "%02X: Added TS: %d ms, TS: %d", packet.m_packetType, packet.m_nInfoField1, nTimeStamp);
                        *ptr = packet.m_packetType;
                        ptr++;
                        ptr += CRTMP::EncodeInt24(ptr, nPacketLen);
@@ -997,14 +997,13 @@ start:
        LogPrintf("Connected...\n\n");
        //}
        
-       #ifdef _DEBUG
+       /*#ifdef _DEBUG
        debugTS = dSeek;
-       #endif
+       #endif*/
 
        timestamp  = dSeek;
-       nTimeStamp = dSeek; // set offset if we continue        
        if(dSeek != 0) {
-               LogPrintf("Continuing at TS: %d ms\n", nTimeStamp);
+               LogPrintf("Continuing at TS: %d ms\n", timestamp);
        }
 
        // print initial status
@@ -1036,7 +1035,7 @@ start:
 
        do
        {
-               nRead = WriteStream(rtmp, &buffer, bufferSize, &timestamp, bResume, metaHeader, nMetaHeaderSize, initialFrame, initialFrameType, nInitialFrameSize, &dataType);
+               nRead = WriteStream(rtmp, &buffer, bufferSize, &timestamp, bResume, dSeek, metaHeader, nMetaHeaderSize, initialFrame, initialFrameType, nInitialFrameSize, &dataType);
 
                //LogPrintf("nRead: %d\n", nRead);
                if(nRead > 0) {
index b15b793..3b70560 100644 (file)
@@ -44,9 +44,9 @@ void RTMPPacket::Reset()
   m_nChannel = 0;
   m_nInfoField1 = 0; 
   m_nInfoField2 = 0; 
+  m_hasAbsTimestamp = false;
   m_nBodySize = 0;
   m_nBytesRead = 0;
-  m_nInternalTimestamp = 0;
   m_body = NULL;
 }
 
index 49d2d67..7e998b3 100644 (file)
@@ -58,10 +58,11 @@ namespace RTMP_LIB
       BYTE     m_packetType;
       BYTE     m_nChannel;
       int32_t  m_nInfoField1; // 3 first bytes
-      int32_t  m_nInfoField2; // last 4 bytes in a long header
+      int32_t  m_nInfoField2; // last 4 bytes in a long header, absolute timestamp for long headers, relative timestamp for short headers 
+      bool      m_hasAbsTimestamp; // timestamp absolute or relative?
+      uint32_t  m_nTimeStamp; // absolute timestamp
       uint32_t m_nBodySize;
       uint32_t m_nBytesRead;
-      uint32_t m_nInternalTimestamp;
       char     *m_body;
   };
 };
index c0a4878..61ffdc0 100644 (file)
@@ -38,7 +38,7 @@
 
 using namespace RTMP_LIB;
 
-#define RTMPDUMP_STREAMS_VERSION       "v1.1"
+#define RTMPDUMP_STREAMS_VERSION       "v1.2"
 
 #define RD_SUCCESS             0
 #define RD_FAILED              1
@@ -265,8 +265,7 @@ int WriteStream(
                        return 0;
                }
 #ifdef _DEBUG
-               debugTS += packet.m_nInfoField1;
-               Log(LOGDEBUG, "type: %02X, size: %d, TS: %d ms, sent TS: %d ms", packet.m_packetType, nPacketLen, debugTS, packet.m_nInfoField1);
+               Log(LOGDEBUG, "type: %02X, size: %d, TS: %d ms", packet.m_packetType, nPacketLen, packet.m_nTimeStamp);
                if(packet.m_packetType == 0x09)
                        Log(LOGDEBUG, "frametype: %02X", (*packetBody & 0xf0));
 #endif
@@ -292,10 +291,9 @@ int WriteStream(
                        // set data type
                        //*dataType |= (((packet.m_packetType == 0x08)<<2)|(packet.m_packetType == 0x09));
 
-                       (*nTimeStamp) += packet.m_nInfoField1;
+                       (*nTimeStamp) = packet.m_nTimeStamp;
                        prevTagSize = 11 + nPacketLen;
 
-                       //Log(LOGDEBUG, "%02X: Added TS: %d ms, TS: %d", packet.m_packetType, packet.m_nInfoField1, *nTimeStamp);
                        *ptr = packet.m_packetType; ptr++;
                        ptr += CRTMP::EncodeInt24(ptr, nPacketLen);
                        ptr += CRTMP::EncodeInt24(ptr, *nTimeStamp);
@@ -599,12 +597,6 @@ void processTCPrequest
        // send the packets
        buffer = (char *)calloc(PACKET_SIZE,1);
 
-       // set timestamp to correct position
-       #ifdef _DEBUG
-        debugTS = dSeek;
-        #endif
-
-        req.nTimeStamp = dSeek; // set offset if we continue        
         if(dSeek != 0) {
                 LogPrintf("Continuing at TS: %d ms\n", req.nTimeStamp);
         }
@@ -676,7 +668,7 @@ void processTCPrequest
                                        duration = rtmp->GetDuration();
 
                                if(duration > 0) {
-                                       percent = ((double)req.nTimeStamp) / (duration*1000.0)*100.0;
+                                       percent = ((double)(dSeek+req.nTimeStamp)) / (duration*1000.0)*100.0;
                                        percent = round(percent*10.0)/10.0;
                                        LogPrintf("\r%.3f KB (%.1f%%)", (double)size/1024.0, percent);
                                } else {