Index: libmpdemux/demux_rtp_codec.cpp =================================================================== --- libmpdemux/demux_rtp_codec.cpp (Revision 22122) +++ libmpdemux/demux_rtp_codec.cpp (Arbeitskopie) @@ -6,8 +6,14 @@ #include #include #include "stheader.h" +#include "avcodec.h" } +AVCodecParserContext * h264parserctx; + +static unsigned char* parseH264ConfigStr( char const* configStr, + unsigned int& configSize ); + static void needVideoFrameRate(demuxer_t* demuxer, MediaSubsession* subsession); // forward static Boolean @@ -45,8 +51,15 @@ = mmioFOURCC('H','2','6','3'); needVideoFrameRate(demuxer, subsession); } else if (strcmp(subsession->codecName(), "H264") == 0) { + av_register_codec_parser(&h264_parser); + h264parserctx = av_parser_init(CODEC_ID_H264); bih->biCompression = sh_video->format = mmioFOURCC('H','2','6','4'); + unsigned int configLen = 0; + unsigned char* configData + = parseH264ConfigStr(subsession->fmtp_spropparametersets(), configLen); + insertRTPData(demuxer, demuxer->video, configData, configLen); + delete[] configData; needVideoFrameRate(demuxer, subsession); } else if (strcmp(subsession->codecName(), "H261") == 0) { bih->biCompression = sh_video->format @@ -300,3 +313,100 @@ numChannels = (word7Ptr[0]<<8)|(word7Ptr[1]); return True; } + +static int b64_decode( char *dest, char *src ) +{ + const char *dest_start = dest; + int i_level; + int last = 0; + int b64[256] = { + 64,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 00-0F */ + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 10-1F */ + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63, /* 20-2F */ + 52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1, /* 30-3F */ + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14, /* 40-4F */ + 15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1, /* 50-5F */ + -1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40, /* 60-6F */ + 41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1, /* 70-7F */ + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 80-8F */ + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 90-9F */ + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* A0-AF */ + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* B0-BF */ + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* C0-CF */ + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* D0-DF */ + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* E0-EF */ + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 /* F0-FF */ + }; + for( i_level = 0; *src != '\0'; src++ ) + { + int c; + + c = b64[(unsigned int)*src]; + if( c == -1 ) + { + continue; + } + switch( i_level ) + { + case 0: + i_level++; + break; + case 1: + *dest++ = ( last << 2 ) | ( ( c >> 4)&0x03 ); + i_level++; + break; + case 2: + *dest++ = ( ( last << 4 )&0xf0 ) | ( ( c >> 2 )&0x0f ); + i_level++; + break; + case 3: + *dest++ = ( ( last &0x03 ) << 6 ) | c; + i_level = 0; + } + last = c; + } + *dest = '\0'; + + return dest - dest_start; +} + +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++] = 0x00; + cfg[configSize++] = 0x01; +// av_base64_decode is not (yet) exported +// configSize += av_base64_decode( (uint8_t*)&cfg[configSize], psz, 5 * strlen(dup) - 4 ); + configSize += b64_decode( (char*)&cfg[configSize], psz ); + + psz += strlen(psz)+1; + } + if( dup ) free( dup ); + return cfg; +} Index: libmpdemux/demux_rtp.cpp =================================================================== --- libmpdemux/demux_rtp.cpp (Revision 22122) +++ libmpdemux/demux_rtp.cpp (Arbeitskopie) @@ -8,6 +8,8 @@ #endif #include "demux_rtp.h" #include "stheader.h" +#include "avcodec.h" +#include "parser.h" } #include "demux_rtp_internal.h" @@ -453,6 +455,10 @@ bufferQueue->blockingFlag = ~0; } +demux_packet_t* nextdp = NULL; +extern AVCodecParserContext * h264parserctx; +float lastpts; + static demux_packet_t* getBuffer(demuxer_t* demuxer, demux_stream_t* ds, Boolean mustGetNewData, float& ptsBehind) { @@ -461,8 +467,10 @@ // the demuxer's 'priv' field) RTPState* rtpState = (RTPState*)(demuxer->priv); ReadBufferQueue* bufferQueue = NULL; + sh_video_t* sh_video = NULL; if (ds == demuxer->video) { bufferQueue = rtpState->videoBufferQueue; + sh_video = (sh_video_t*)ds->sh; } else if (ds == demuxer->audio) { bufferQueue = rtpState->audioBufferQueue; } else { @@ -486,10 +494,62 @@ } // Allocate a new packet buffer, and arrange to read into it: + if (!nextdp || !sh_video) { dp = new_demux_packet(MAX_RTP_FRAME_SIZE); bufferQueue->dp = dp; if (dp == NULL) return NULL; + } + // Handle H264 video: + if (sh_video && h264parserctx) { + + int consumed, poutbuf_size; + uint8_t *poutbuf = NULL; + + TaskScheduler& scheduler + = bufferQueue->readSource()->envir().taskScheduler(); + + do { + if (!nextdp) { + dp->buffer[0]=0x00; + dp->buffer[1]=0x00; + dp->buffer[2]=0x01; + + bufferQueue->blockingFlag = 0; + bufferQueue->readSource()->getNextFrame(&dp->buffer[3], + MAX_RTP_FRAME_SIZE-3, + afterReading, bufferQueue, + onSourceClosure, bufferQueue); + scheduler.doEventLoop(&bufferQueue->blockingFlag); + } else { + bufferQueue->dp = dp = nextdp; + nextdp = NULL; + } + + consumed = h264parserctx->parser->parser_parse(h264parserctx, + (AVCodecContext*)sh_video->context, + &poutbuf, &poutbuf_size, + dp->buffer, dp->len+3); + + 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); + if (dp == NULL) return NULL; + } else { + nextdp = dp; + bufferQueue->dp = dp = new_demux_packet(poutbuf_size); + if (dp == NULL) return NULL; + memcpy(dp->buffer, poutbuf, poutbuf_size); + dp->len=poutbuf_size; + dp->pts=lastpts; + } + } while (!poutbuf_size); + } else { + // Schedule the read operation: bufferQueue->blockingFlag = 0; bufferQueue->readSource()->getNextFrame(dp->buffer, MAX_RTP_FRAME_SIZE, @@ -499,7 +559,8 @@ TaskScheduler& scheduler = bufferQueue->readSource()->envir().taskScheduler(); scheduler.doEventLoop(&bufferQueue->blockingFlag); + } // Set the "ptsBehind" result parameter: if (bufferQueue->prevPacketPTS != 0.0