void rtpCodecInitialize_audio(demuxer_t* demuxer, MediaSubsession* subsession, unsigned& flags) { flags = 0; // Create a dummy audio stream header // to make the main MPlayer code happy: sh_audio_t* sh_audio = new_sh_audio(demuxer,0); WAVEFORMATEX* wf = (WAVEFORMATEX*)calloc(1,sizeof(WAVEFORMATEX)); sh_audio->wf = wf; demux_stream_t* d_audio = demuxer->audio; d_audio->sh = sh_audio; sh_audio->ds = d_audio; d_audio->id = sh_audio->aid; wf->nChannels = subsession->numChannels(); // Map known audio MIME types to the WAVEFORMATEX parameters // that this program uses. (Note that not all types need all // of the parameters to be set.) wf->nSamplesPerSec = subsession->rtpSource()->timestampFrequency(); // by default if (strcmp(subsession->codecName(), "MPA") == 0 || strcmp(subsession->codecName(), "MPA-ROBUST") == 0 || strcmp(subsession->codecName(), "X-MP3-DRAFT-00") == 0) { wf->wFormatTag = sh_audio->format = 0x55; // Note: 0x55 is for layer III, but should work for I,II also wf->nSamplesPerSec = 0; // sample rate is deduced from the data } else if (strcmp(subsession->codecName(), "AC3") == 0) { wf->wFormatTag = sh_audio->format = 0x2000; wf->nSamplesPerSec = 0; // sample rate is deduced from the data } else if (strcmp(subsession->codecName(), "X-ASF-PF") == 0) { ; } else if (strcmp(subsession->codecName(), "L16") == 0) { wf->wFormatTag = sh_audio->format = 0x736f7774; // "twos" wf->nBlockAlign = 1; wf->wBitsPerSample = 16; wf->cbSize = 0; } else if (strcmp(subsession->codecName(), "L8") == 0) { wf->wFormatTag = sh_audio->format = 0x20776172; // "raw " wf->nBlockAlign = 1; wf->wBitsPerSample = 8; wf->cbSize = 0; } else if (strcmp(subsession->codecName(), "PCMU") == 0) { wf->wFormatTag = sh_audio->format = 0x7; wf->nAvgBytesPerSec = 8000; wf->nBlockAlign = 1; wf->wBitsPerSample = 8; wf->cbSize = 0; } else if (strcmp(subsession->codecName(), "PCMA") == 0) { wf->wFormatTag = sh_audio->format = 0x6; wf->nAvgBytesPerSec = 8000; 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(), "GSM") == 0) { wf->wFormatTag = sh_audio->format = mmioFOURCC('a','g','s','m'); wf->nAvgBytesPerSec = 1650; wf->nBlockAlign = 33; wf->wBitsPerSample = 16; wf->cbSize = 0; } else if (strcmp(subsession->codecName(), "QCELP") == 0) { wf->wFormatTag = sh_audio->format = mmioFOURCC('Q','c','l','p'); wf->nAvgBytesPerSec = 1750; wf->nBlockAlign = 35; wf->wBitsPerSample = 16; wf->cbSize = 0; } else if (strcmp(subsession->codecName(), "MP4A-LATM") == 0) { wf->wFormatTag = sh_audio->format = mmioFOURCC('m','p','4','a'); // For the codec to work correctly, it needs "AudioSpecificConfig" // data, which is parsed from the "StreamMuxConfig" string that // was present (hopefully) in the SDP description: unsigned codecdata_len; sh_audio->codecdata = parseStreamMuxConfigStr(subsession->fmtp_config(), codecdata_len); sh_audio->codecdata_len = codecdata_len; //faad doesn't understand LATM's data length field, so omit it ((MPEG4LATMAudioRTPSource*)subsession->rtpSource())->omitLATMDataLengthField(); } else if (strcmp(subsession->codecName(), "MPEG4-GENERIC") == 0) { wf->wFormatTag = sh_audio->format = mmioFOURCC('m','p','4','a'); // For the codec to work correctly, it needs "AudioSpecificConfig" // data, which was present (hopefully) in the SDP description: unsigned codecdata_len; sh_audio->codecdata = parseGeneralConfigStr(subsession->fmtp_config(), codecdata_len); sh_audio->codecdata_len = codecdata_len; } else if (strcmp(subsession->codecName(), "X-QT") == 0 || strcmp(subsession->codecName(), "X-QUICKTIME") == 0) { // QuickTime generic RTP format, as described in // http://developer.apple.com/quicktime/icefloe/dispatch026.html // We can't initialize this stream until we've received the first packet // that has QuickTime "sdAtom" information in the header. So, keep // reading packets until we get one: unsigned char* packetData; unsigned packetDataLen; float pts; QuickTimeGenericRTPSource* qtRTPSource = (QuickTimeGenericRTPSource*)(subsession->rtpSource()); unsigned fourcc, numChannels; do { if (!awaitRTPPacket(demuxer, demuxer->audio, packetData, packetDataLen, pts)) { return; } } while (!parseQTState_audio(qtRTPSource->qtState, fourcc, numChannels)); wf->wFormatTag = sh_audio->format = fourcc; wf->nChannels = numChannels; if (qtRTPSource->qtState.sdAtomSize > 33) { wf->wBitsPerSample = qtRTPSource->qtState.sdAtom[27]; wf->nSamplesPerSec = qtRTPSource->qtState.sdAtom[32]<<8|qtRTPSource->qtState.sdAtom[33]; } 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()); } }
int CLvRtspClient::InitAudio( MediaSubsession *pss ) {_STT(); if ( !m_pRtspClient ) { setLastError( -200, oexT( "Invalid rtsp client object" ) ); return 0; } // end if if ( !pss ) { setLastError( -201, oexT( "Invalid video object" ) ); return 0; } // end if // Create receiver for stream if ( !pss->initiate() ) { setLastError( -203, sqbind::oex2std( oexMks( oexT( "initiate() video stream failed : " ), oexT( " : " ), m_pEnv->getResultMsg() ) ) ); return 0; } // end if if ( !pss->rtpSource() ) { setLastError( -204, sqbind::oex2std( oexMks( oexT( "RTP source is null : " ), oexT( " : " ), m_pEnv->getResultMsg() ) ) ); return 0; } // end if if ( oex::CStr8( "MP4A-LATM" ) == pss->codecName() ) { ((MPEG4LATMAudioRTPSource*)pss->rtpSource())->omitLATMDataLengthField(); const char *pCfg = pss->fmtp_config(); if ( pCfg ) { unsigned elen = 0; unsigned char *pExtra = parseStreamMuxConfigStr( pCfg, elen ); if ( pExtra && elen ) m_extraAudio.AppendBuffer( (const char*)pExtra, elen ); } // end if } // end if else if ( oex::CStr8( "MPEG4-GENERIC" ) == pss->codecName() ) { const char *pCfg = pss->fmtp_config(); if ( pCfg ) { unsigned elen = 0; unsigned char *pExtra = parseGeneralConfigStr( pCfg, elen ); if ( pExtra && elen ) m_extraAudio.AppendBuffer( (const char*)pExtra, elen ); } // end if } // end if // Read extradata const char *props = pss->fmtp_spropparametersets(); if ( props ) { oex::TList< oex::CStr8 > lst = oex::CParser::Explode( props, oexT( "," ) ); for ( oex::TList< oex::CStr8 >::iterator it; lst.Next( it ); ) { m_extraAudio.AppendBuffer( "\x00\x00\x01", 3 ); m_extraAudio.Mem().appendString( oex::CBase64::Decode( *it ) ); } // end for } // end if // Set minimum rx buffer size if ( 2000000 > m_nRxBufferSize ) m_nRxBufferSize = 2000000; // Set rx buffer size int sn = pss->rtpSource()->RTPgs()->socketNum(); increaseReceiveBufferTo( *m_pEnv, sn, m_nRxBufferSize ); pss->rtpSource()->setPacketReorderingThresholdTime( 2000000 ); if ( pss->codecName() ) m_sAudioCodec = oexMbToStrPtr( pss->codecName() ); if ( !m_pRtspClient->setupMediaSubsession( *pss, False, False ) ) { setLastError( -205, sqbind::oex2std( oexMks( oexT( "setupMediaSubsession() failed : " ), oexT( " : " ), m_pEnv->getResultMsg() ) ) ); return 0; } // end if // Save away important audio parameters m_nAudioNumChannels = pss->numChannels(); m_nAudioRate = pss->rtpTimestampFrequency(); m_nAudioBps = 0; m_pAs = new CAudioSink( *m_pEnv ); if ( !m_pAs ) { setLastError( -206, sqbind::oex2std( oexMks( oexT( "CAudioSink::createNew() failed : " ), oexT( " : " ), m_pEnv->getResultMsg() ) ) ); return 0; } // end if m_pAs->setDataEvent( &m_evtData ); m_pAsPss = pss; return 1; }