Index: libmpdemux/demux_rtp_internal.h =================================================================== --- libmpdemux/demux_rtp_internal.h (Revision 22306) +++ 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 @@ -36,8 +41,4 @@ // "streamType": 0 => video; 1 => audio // This routine returns False if the input stream has closed -// A routine for adding our own data to an incoming RTP data stream: -Boolean insertRTPData(demuxer_t* demuxer, demux_stream_t* ds, - unsigned char* data, unsigned dataLen); - #endif Index: libmpdemux/demux_rtp_codec.cpp =================================================================== --- libmpdemux/demux_rtp_codec.cpp (Revision 22306) +++ 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++] = 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 needVideoFrameRate(demuxer_t* demuxer, MediaSubsession* subsession); // forward static Boolean @@ -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 @@ -172,6 +229,10 @@ wf->nBlockAlign = 1; wf->wBitsPerSample = 8; wf->cbSize = 0; + } else if (strcmp(subsession->codecName(), "AMR") == 0) { + wf->wFormatTag = sh_audio->format = mmioFOURCC('s','a','m','r'); + } else if (strcmp(subsession->codecName(), "AMR-WB") == 0) { + wf->wFormatTag = sh_audio->format = mmioFOURCC('s','a','w','b'); } else if (strcmp(subsession->codecName(), "PCMU") == 0) { wf->wFormatTag = sh_audio->format = 0x7; wf->nAvgBytesPerSec = 8000; @@ -238,11 +299,36 @@ wf->wFormatTag = sh_audio->format = fourcc; wf->nChannels = numChannels; + + uint8_t *pos = (uint8_t*)qtRTPSource->qtState.sdAtom + 52; + uint8_t *endpos = (uint8_t*)qtRTPSource->qtState.sdAtom + + qtRTPSource->qtState.sdAtomSize; + while (pos+8 < endpos) { + unsigned atomLength = pos[0]<<24 | pos[1]<<16 | pos[2]<<8 | pos[3]; + if (atomLength == 0 || atomLength > endpos-pos) break; + if (!memcmp(pos+4, "wave", 4) && fourcc==mmioFOURCC('Q','D','M','2') && + atomLength > 8 && + atomLength <= INT_MAX) { + sh_audio->codecdata = (unsigned char*) malloc(atomLength-8); + if (sh_audio->codecdata) { + memcpy(sh_audio->codecdata, pos+8, atomLength-8); + sh_audio->codecdata_len = atomLength-8; + } + break; + } + pos += atomLength; + } } else { fprintf(stderr, "Unknown MPlayer format code for MIME type \"audio/%s\"\n", subsession->codecName()); } +unsigned char* packetData; unsigned packetDataLen;float curPTS; +for (int i=0;i<00;printf("%i ",i++)) +if (!awaitRTPPacket(demuxer, demuxer->video, packetData, packetDataLen, curPTS) +|| !awaitRTPPacket(demuxer, demuxer->audio, packetData, packetDataLen, curPTS)) +printf("Nicht gelungen\n"); +printf("\n"); } static void needVideoFrameRate(demuxer_t* demuxer, @@ -260,6 +346,7 @@ int fps = (int)(subsession->videoFPS()); if (fps != 0) { sh_video->fps = fps; + sh_video->frametime=1.0f/fps; return; } @@ -313,10 +400,11 @@ // contain the number of channels ("numChannels") that we want: char const* sdAtom = qtState.sdAtom; if (sdAtom == NULL || qtState.sdAtomSize < 7*4) return False; - +printf("Sound Atom: ");for (int i=0;ipriv); - ReadBufferQueue* bufferQueue = NULL; - if (ds == demuxer->video) { - bufferQueue = rtpState->videoBufferQueue; - } else if (ds == demuxer->audio) { - bufferQueue = rtpState->audioBufferQueue; - } else { - fprintf(stderr, "(demux_rtp)insertRTPData: internal error: unknown stream\n"); - return False; - } - - if (data == NULL || dataLen == 0) return False; - - demux_packet_t* dp = new_demux_packet(dataLen); - if (dp == NULL) return False; - - // Copy our data into the buffer, and save it: - memmove(dp->buffer, data, dataLen); - dp->len = dataLen; - dp->pts = 0; - bufferQueue->savePendingBuffer(dp); - return True; -} - static void teardownRTSPorSIPSession(RTPState* rtpState); // forward extern "C" void demux_close_rtp(demuxer_t* demuxer) { @@ -453,6 +425,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,10 +436,15 @@ // the demuxer's 'priv' field) RTPState* rtpState = (RTPState*)(demuxer->priv); ReadBufferQueue* bufferQueue = NULL; + sh_video_t* sh_video = NULL; + int amr=0; if (ds == demuxer->video) { bufferQueue = rtpState->videoBufferQueue; + sh_video = (sh_video_t*)ds->sh; } else if (ds == demuxer->audio) { bufferQueue = rtpState->audioBufferQueue; + if (((sh_audio_t*)ds->sh)->format== mmioFOURCC('s','a','m','r')) + amr=1; } else { fprintf(stderr, "(demux_rtp)getBuffer: internal error: unknown stream\n"); return NULL; @@ -486,13 +466,75 @@ } // 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 + { + + if (amr) + dp->buffer[0] = + ((AMRAudioSource*)bufferQueue->readSource())->lastFrameHeader(); + // Schedule the read operation: bufferQueue->blockingFlag = 0; - bufferQueue->readSource()->getNextFrame(dp->buffer, MAX_RTP_FRAME_SIZE, + bufferQueue->readSource()->getNextFrame(&dp->buffer[amr], + MAX_RTP_FRAME_SIZE, afterReading, bufferQueue, onSourceClosure, bufferQueue); // Block ourselves until data becomes available: @@ -500,6 +542,23 @@ = bufferQueue->readSource()->envir().taskScheduler(); scheduler.doEventLoop(&bufferQueue->blockingFlag); + dp->len+=amr; + } + +if (sh_video){ +rtpState->last_pts=dp->pts; +mp_msg(MSGT_DEMUX, MSGL_V, "PTS: %f, len. %d; %#x %#x %#x %#x %#x %#x %#x %#x %#x %#x\n",dp->pts,dp->len,dp->buffer[0],dp->buffer[1],dp->buffer[2],dp->buffer[3],dp->buffer[4],dp->buffer[5],dp->buffer[6],dp->buffer[7],dp->buffer[10],dp->buffer[11]); +//if (dp->len>biggest){biggest=dp->len;mp_msg(MSGT_DEMUX, MSGL_INFO,"Biggest: %d \n",biggest);} +} +/* + if (amr) + dp->buffer[0] = + ((AMRAudioSource*)bufferQueue->readSource())->lastFrameHeader(); +...&dp->buffer[amr] +... + dp->len+=amr; + +*/ // Set the "ptsBehind" result parameter: if (bufferQueue->prevPacketPTS != 0.0 && bufferQueue->prevPacketWasSynchronized @@ -513,6 +572,7 @@ } if (mustGetNewData) { + resize_demux_packet(dp, dp->len); // Save this buffer for future reads: bufferQueue->savePendingBuffer(dp); } @@ -582,7 +642,31 @@ return dp; } +static void demux_rtp_seek(demuxer_t *demuxer,float rel_seek_secs,float audio_delay,int flags) { +((RTPState*)demuxer->priv)->rtspClient->playMediaSession(*((RTPState*)demuxer->priv)->mediaSession, ((RTPState*)demuxer->priv)->last_pts+rel_seek_secs); +} +static int demux_rtp_control(struct demuxer_st *demuxer, int cmd, void *arg) { + double endpos = ((RTPState*)demuxer->priv)->mediaSession->playEndTime(); + + switch(cmd) { + case DEMUXER_CTRL_GET_TIME_LENGTH: + if (endpos <= 0) + return DEMUXER_CTRL_DONTKNOW; + *((double *)arg) = endpos; + return DEMUXER_CTRL_OK; + + case DEMUXER_CTRL_GET_PERCENT_POS: + if (endpos <= 0) + return DEMUXER_CTRL_DONTKNOW; + *((int *)arg) = (int)(((RTPState*)demuxer->priv)->last_pts*100/endpos); + return DEMUXER_CTRL_OK; + + default: + return DEMUXER_CTRL_NOTIMPL; + } +} + demuxer_desc_t demuxer_desc_rtp = { "LIVE555 RTP demuxer", "rtp", @@ -595,6 +679,6 @@ demux_rtp_fill_buffer, demux_open_rtp, demux_close_rtp, - NULL, - NULL + demux_rtp_seek, + demux_rtp_control };