changeset 22852:d7f4da5e9ee4

Support h264 over rtsp
author cehoyos
date Sun, 01 Apr 2007 03:03:05 +0000
parents e878a71cb27f
children aaaedf34d589
files libmpdemux/demux_rtp.cpp libmpdemux/demux_rtp_codec.cpp libmpdemux/demux_rtp_internal.h
diffstat 3 files changed, 113 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/libmpdemux/demux_rtp.cpp	Sun Apr 01 03:00:47 2007 +0000
+++ b/libmpdemux/demux_rtp.cpp	Sun Apr 01 03:03:05 2007 +0000
@@ -44,6 +44,9 @@
   void savePendingBuffer(demux_packet_t* dp);
   demux_packet_t* getPendingBuffer();
 
+  // For H264 over rtsp using AVParser, the next packet has to be saved
+  demux_packet_t* nextpacket;
+
 private:
   demux_packet_t* pendingDPHead;
   demux_packet_t* pendingDPTail;
@@ -377,6 +380,13 @@
 
   if (bufferQueue->readSource()->isAMRAudioSource())
     headersize = 1;
+  else if (bufferQueue == rtpState->videoBufferQueue &&
+      ((sh_video_t*)demuxer->video->sh)->format == mmioFOURCC('H','2','6','4')) {
+    dp->buffer[0]=0x00;
+    dp->buffer[1]=0x00;
+    dp->buffer[2]=0x01;
+    headersize = 3;
+  }
 
   resize_demux_packet(dp, frameSize + headersize);
 
@@ -440,6 +450,8 @@
   int headersize = 0;
   if (ds == demuxer->video) {
     bufferQueue = rtpState->videoBufferQueue;
+    if (((sh_video_t*)ds->sh)->format == mmioFOURCC('H','2','6','4'))
+      headersize = 3;
   } else if (ds == demuxer->audio) {
     bufferQueue = rtpState->audioBufferQueue;
     if (bufferQueue->readSource()->isAMRAudioSource())
@@ -465,10 +477,21 @@
   }
 
   // Allocate a new packet buffer, and arrange to read into it:
+    if (!bufferQueue->nextpacket) {
   dp = new_demux_packet(MAX_RTP_FRAME_SIZE);
   bufferQueue->dp = dp;
   if (dp == NULL) return NULL;
+    }
 
+#ifdef USE_LIBAVCODEC
+  extern AVCodecParserContext * h264parserctx;
+  int consumed, poutbuf_size = 1;
+  uint8_t *poutbuf = NULL;
+  float lastpts;
+
+  do {
+    if (!bufferQueue->nextpacket) {
+#endif
   // Schedule the read operation:
   bufferQueue->blockingFlag = 0;
   bufferQueue->readSource()->getNextFrame(&dp->buffer[headersize], MAX_RTP_FRAME_SIZE - headersize,
@@ -482,6 +505,33 @@
   if (headersize == 1) // amr
     dp->buffer[0] =
         ((AMRAudioSource*)bufferQueue->readSource())->lastFrameHeader();
+#ifdef USE_LIBAVCODEC
+    } else {
+      bufferQueue->dp = dp = bufferQueue->nextpacket;
+      bufferQueue->nextpacket = NULL;
+    }
+    if (headersize == 3 && h264parserctx) { // h264
+      consumed = h264parserctx->parser->parser_parse(h264parserctx,
+                               NULL,
+                               &poutbuf, &poutbuf_size,
+                               dp->buffer, dp->len);
+
+      if (!consumed && !poutbuf_size)
+        return NULL;
+
+      if (!poutbuf_size) {
+        lastpts=dp->pts;
+        free_demux_packet(dp);
+        bufferQueue->dp = dp = new_demux_packet(MAX_RTP_FRAME_SIZE);
+      } else {
+        bufferQueue->nextpacket = dp;
+        bufferQueue->dp = dp = new_demux_packet(poutbuf_size);
+        memcpy(dp->buffer, poutbuf, poutbuf_size);
+        dp->pts=lastpts;
+      }
+    }
+  } while (!poutbuf_size);
+#endif
 
   // Set the "ptsBehind" result parameter:
   if (bufferQueue->prevPacketPTS != 0.0
@@ -523,6 +573,7 @@
 ReadBufferQueue::ReadBufferQueue(MediaSubsession* subsession,
 				 demuxer_t* demuxer, char const* tag)
   : prevPacketWasSynchronized(False), prevPacketPTS(0.0), otherQueue(NULL),
+    nextpacket(NULL),
     dp(NULL), pendingDPHead(NULL), pendingDPTail(NULL),
     fReadSource(subsession == NULL ? NULL : subsession->readSource()),
     fRTPSource(subsession == NULL ? NULL : subsession->rtpSource()),
--- a/libmpdemux/demux_rtp_codec.cpp	Sun Apr 01 03:00:47 2007 +0000
+++ b/libmpdemux/demux_rtp_codec.cpp	Sun Apr 01 03:03:05 2007 +0000
@@ -6,6 +6,54 @@
 #include <limits.h>
 #include <math.h>
 #include "stheader.h"
+#include "base64.h"
+}
+
+#ifdef USE_LIBAVCODEC
+AVCodecParserContext * h264parserctx;
+#endif
+
+// Copied from vlc
+static unsigned char* parseH264ConfigStr( char const* configStr,
+                                          unsigned int& configSize )
+{
+
+    char *dup, *psz;
+    int i, i_records = 1;
+
+    if( configSize )
+    configSize = 0;
+    if( configStr == NULL || *configStr == '\0' )
+        return NULL;
+    psz = dup = strdup( configStr );
+
+ /* Count the number of comma's */
+    for( psz = dup; *psz != '\0'; ++psz )
+    {
+        if( *psz == ',')
+        {
+            ++i_records;
+            *psz = '\0';
+        }
+    }
+
+    unsigned char *cfg = new unsigned char[5 * strlen(dup)];
+    psz = dup;
+    for( i = 0; i < i_records; i++ )
+    {
+
+        cfg[configSize++] = 0x00;
+        cfg[configSize++] = 0x00;
+        cfg[configSize++] = 0x01;
+        configSize += av_base64_decode( (uint8_t*)&cfg[configSize],
+                                        psz,
+                                        5 * strlen(dup) - 3 );
+
+    psz += strlen(psz)+1;
+    }
+    if( dup ) free( dup );
+
+    return cfg;
 }
 
 static void
@@ -63,6 +111,15 @@
   } else if (strcmp(subsession->codecName(), "H264") == 0) {
     bih->biCompression = sh_video->format
       = mmioFOURCC('H','2','6','4');
+    unsigned int configLen = 0;
+    unsigned char* configData
+      = parseH264ConfigStr(subsession->fmtp_spropparametersets(), configLen);
+    sh_video->bih = bih = insertVideoExtradata(bih, configData, configLen);
+    delete[] configData;
+#ifdef USE_LIBAVCODEC
+    av_register_codec_parser(&h264_parser);
+    h264parserctx = av_parser_init(CODEC_ID_H264);
+#endif
     needVideoFrameRate(demuxer, subsession);
   } else if (strcmp(subsession->codecName(), "H261") == 0) {
     bih->biCompression = sh_video->format
--- a/libmpdemux/demux_rtp_internal.h	Sun Apr 01 03:00:47 2007 +0000
+++ b/libmpdemux/demux_rtp_internal.h	Sun Apr 01 03:03:05 2007 +0000
@@ -10,6 +10,11 @@
 #ifndef __DEMUXER_H
 #include "demuxer.h"
 #endif
+#ifdef USE_LIBAVCODEC_SO
+#include <ffmpeg/avcodec.h>
+#elif defined(USE_LIBAVCODEC)
+#include "libavcodec/avcodec.h"
+#endif
 }
 
 #ifndef _LIVEMEDIA_HH