Index: libmpdemux/demux_rtp_internal.h =================================================================== --- libmpdemux/demux_rtp_internal.h (Revision 22213) +++ libmpdemux/demux_rtp_internal.h (Arbeitskopie) @@ -10,6 +10,11 @@ #ifndef __DEMUXER_H #include "demuxer.h" #endif +#ifdef USE_LIBAVCODEC_SO +#include +#elif defined(USE_LIBAVCODEC) +#include "libavcodec/avcodec.h" +#endif } #ifndef _LIVEMEDIA_HH Index: libmpdemux/demux_rtp_codec.cpp =================================================================== --- libmpdemux/demux_rtp_codec.cpp (Revision 22213) +++ libmpdemux/demux_rtp_codec.cpp (Arbeitskopie) @@ -6,8 +6,56 @@ #include #include #include "stheader.h" + +int av_base64_decode(uint8_t * out, const char *in, int out_length); } +#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++] = 0x00; + cfg[configSize++] = 0x01; + configSize += av_base64_decode( (uint8_t*)&cfg[configSize], + psz, + 5 * strlen(dup) - 4 ); + + psz += strlen(psz)+1; + } + if( dup ) free( dup ); + return cfg; +} + static void needVideoFrameRate(demuxer_t* demuxer, MediaSubsession* subsession); // forward static Boolean @@ -47,6 +95,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); + insertRTPData(demuxer, demuxer->video, 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 Index: libmpdemux/demux_rtp.cpp =================================================================== --- libmpdemux/demux_rtp.cpp (Revision 22213) +++ libmpdemux/demux_rtp.cpp (Arbeitskopie) @@ -453,6 +453,9 @@ bufferQueue->blockingFlag = ~0; } +demux_packet_t* nextdp = NULL; +float lastpts; + static demux_packet_t* getBuffer(demuxer_t* demuxer, demux_stream_t* ds, Boolean mustGetNewData, float& ptsBehind) { @@ -461,8 +464,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 +491,67 @@ } // 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: +#ifdef USE_LIBAVCODEC +extern AVCodecParserContext * h264parserctx; + + 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 +#endif //USE_LIBAVCODEC +{ + // Schedule the read operation: bufferQueue->blockingFlag = 0; bufferQueue->readSource()->getNextFrame(dp->buffer, MAX_RTP_FRAME_SIZE, @@ -499,6 +561,7 @@ TaskScheduler& scheduler = bufferQueue->readSource()->envir().taskScheduler(); scheduler.doEventLoop(&bufferQueue->blockingFlag); + } // Set the "ptsBehind" result parameter: if (bufferQueue->prevPacketPTS != 0.0