/**************************************** * RecAudio * Obtiene los packetes y los muestra *****************************************/ int MediaBridgeSession::RecAudio() { DWORD firstAudio = 0; DWORD timeStamp=0; DWORD firstTS = 0; SWORD raw[512]; DWORD rawSize = 512; DWORD rawLen; //Create new audio frame RTMPAudioFrame *audio = new RTMPAudioFrame(0,RTPPAYLOADSIZE); Log(">RecAudio\n"); //Mientras tengamos que capturar while(receivingAudio) { //Obtenemos el paquete RTPPacket *packet = rtpAudio.GetPacket(); //Check if (!packet) //Next continue; //Get type AudioCodec::Type codec = (AudioCodec::Type)packet->GetCodec(); //Check rtp type if (codec==AudioCodec::SPEEX16) { //TODO!!!! } //Check if we have a decoder if (!rtpAudioDecoder || rtpAudioDecoder->type!=codec) { //Check if (rtpAudioDecoder) //Delete old one delete(rtpAudioDecoder); //Create new one rtpAudioDecoder = AudioCodecFactory::CreateDecoder(codec); } //Decode it rawLen = rtpAudioDecoder->Decode(packet->GetMediaData(),packet->GetMediaLength(),raw,rawSize); //Delete packet delete(packet); //Rencode it DWORD len; while((len=rtmpAudioEncoder->Encode(raw,rawLen,audio->GetMediaData(),audio->GetMaxMediaSize()))>0) { //REset rawLen = 0; //Set length audio->SetMediaSize(len); switch(rtmpAudioEncoder->type) { case AudioCodec::SPEEX16: //Set RTMP data audio->SetAudioCodec(RTMPAudioFrame::SPEEX); audio->SetSoundRate(RTMPAudioFrame::RATE11khz); audio->SetSamples16Bits(1); audio->SetStereo(0); break; case AudioCodec::NELLY8: //Set RTMP data audio->SetAudioCodec(RTMPAudioFrame::NELLY8khz); audio->SetSoundRate(RTMPAudioFrame::RATE11khz); audio->SetSamples16Bits(1); audio->SetStereo(0); break; case AudioCodec::NELLY11: //Set RTMP data audio->SetAudioCodec(RTMPAudioFrame::NELLY); audio->SetSoundRate(RTMPAudioFrame::RATE11khz); audio->SetSamples16Bits(1); audio->SetStereo(0); break; } //If it is first if (!firstTS) { //Get first audio time firstAudio = getDifTime(&first)/1000; //It is first firstTS = timeStamp; } DWORD ts = firstAudio +(timeStamp-firstTS)/8; //Set timestamp audio->SetTimestamp(ts); //Send packet SendMediaFrame(audio); } } //Check if (audio) //Delete it delete(audio); Log("<RecAudio\n"); }
int FLVEncoder::EncodeVideo() { timeval prev; //Start Log(">FLVEncoder encode video\n"); //Allocate media frame RTMPVideoFrame frame(0,262143); //Check codec switch(videoCodec) { case VideoCodec::SORENSON: //Ser Video codec frame.SetVideoCodec(RTMPVideoFrame::FLV1); break; case VideoCodec::H264: //Ser Video codec frame.SetVideoCodec(RTMPVideoFrame::AVC); //Set NAL type frame.SetAVCType(RTMPVideoFrame::AVCNALU); //No delay frame.SetAVCTS(0); break; default: return Error("-Wrong codec type %d\n",videoCodec); } //Create the encoder VideoEncoder *encoder = VideoCodecFactory::CreateEncoder(videoCodec,videoProperties); ///Set frame rate encoder->SetFrameRate(fps,bitrate,intra); //Set dimensions encoder->SetSize(width,height); //Start capturing videoInput->StartVideoCapture(width,height,fps); //The time of the first one gettimeofday(&prev,NULL); //No wait for first DWORD frameTime = 0; Log(">FLVEncoder encode vide\n"); //Mientras tengamos que capturar while(encodingVideo) { //Nos quedamos con el puntero antes de que lo cambien BYTE* pic=videoInput->GrabFrame(frameTime); //Ensure we are still encoding if (!encodingVideo) break; //Check pic if (!pic) continue; //Check if we need to send intra if (sendFPU) { //Set it encoder->FastPictureUpdate(); //Do not send anymore sendFPU = false; } //Encode next frame VideoFrame *encoded = encoder->EncodeFrame(pic,videoInput->GetBufferSize()); //Check if (!encoded) break; //Check size if (frame.GetMaxMediaSize()<encoded->GetLength()) { //Not enougth space Error("Not enought space to copy FLV encodec frame [frame:%d,encoded:%d",frame.GetMaxMediaSize(),encoded->GetLength()); //NExt continue; } //Check if (frameTime) { timespec ts; //Lock pthread_mutex_lock(&mutex); //Calculate timeout calcAbsTimeout(&ts,&prev,frameTime); //Wait next or stopped int canceled = !pthread_cond_timedwait(&cond,&mutex,&ts); //Unlock pthread_mutex_unlock(&mutex); //Check if we have been canceled if (canceled) //Exit break; } //Set sending time of previous frame getUpdDifTime(&prev); //Set timestamp encoded->SetTimestamp(getDifTime(&first)/1000); //Set next one frameTime = 1000/fps; //Set duration encoded->SetDuration(frameTime); //Get full frame frame.SetVideoFrame(encoded->GetData(),encoded->GetLength()); //Set buffer size frame.SetMediaSize(encoded->GetLength()); //Check type if (encoded->IsIntra()) //Set type frame.SetFrameType(RTMPVideoFrame::INTRA); else //Set type frame.SetFrameType(RTMPVideoFrame::INTER); //If we need desc but yet not have it if (!frameDesc && encoded->IsIntra() && videoCodec==VideoCodec::H264) { //Create new description AVCDescriptor desc; //Set values desc.SetConfigurationVersion(1); desc.SetAVCProfileIndication(0x42); desc.SetProfileCompatibility(0x80); desc.SetAVCLevelIndication(0x0C); desc.SetNALUnitLength(3); //Get encoded data BYTE *data = encoded->GetData(); //Get size DWORD size = encoded->GetLength(); //get from frame desc.AddParametersFromFrame(data,size); //Crete desc frame frameDesc = new RTMPVideoFrame(getDifTime(&first)/1000,desc); //Lock pthread_mutex_lock(&mutex); //Send it SendMediaFrame(frameDesc); //unlock pthread_mutex_unlock(&mutex); } //Lock pthread_mutex_lock(&mutex); //Set timestamp frame.SetTimestamp(encoded->GetTimeStamp()); //Publish it SendMediaFrame(&frame); //For each listener for(MediaFrameListeners::iterator it = mediaListeners.begin(); it!=mediaListeners.end(); ++it) //Send it (*it)->onMediaFrame(RTMPMediaStream::id,*encoded); //unlock pthread_mutex_unlock(&mutex); } Log("-FLVEncoder encode video end of loop\n"); //Stop the capture videoInput->StopVideoCapture(); //Check if (encoder) //Exit delete(encoder); Log("<FLVEncoder encode vide\n"); //Exit return 1; }
/**************************************** * RecVideo * Obtiene los packetes y los muestra *****************************************/ int MediaBridgeSession::RecVideo() { //Coders VideoDecoder* decoder = NULL; VideoEncoder* encoder = VideoCodecFactory::CreateEncoder(VideoCodec::SORENSON); //Create new video frame RTMPVideoFrame frame(0,262143); //Set codec frame.SetVideoCodec(RTMPVideoFrame::FLV1); int width=0; int height=0; DWORD numpixels=0; Log(">RecVideo\n"); //Mientras tengamos que capturar while(receivingVideo) { ///Obtenemos el paquete RTPPacket* packet = rtpVideo.GetPacket(); //Check if (!packet) //Next continue; //Get type VideoCodec::Type type = (VideoCodec::Type)packet->GetCodec(); if ((decoder==NULL) || (type!=decoder->type)) { //Si habia uno nos lo cargamos if (decoder!=NULL) delete decoder; //Creamos uno dependiendo del tipo decoder = VideoCodecFactory::CreateDecoder(type); //Check if (!decoder) { delete(packet); continue; } } //Lo decodificamos if(!decoder->DecodePacket(packet->GetMediaData(),packet->GetMediaLength(),0,packet->GetMark())) { delete(packet); continue; } //Get mark bool mark = packet->GetMark(); //Delete packet delete(packet); //Check if it is last one if(!mark) continue; //Check size if (decoder->GetWidth()!=width || decoder->GetHeight()!=height) { //Get dimension width = decoder->GetWidth(); height = decoder->GetHeight(); //Set size numpixels = width*height*3/2; //Set also frame rate and bps encoder->SetFrameRate(25,300,500); //Set them in the encoder encoder->SetSize(width,height); } //Encode next frame VideoFrame *encoded = encoder->EncodeFrame(decoder->GetFrame(),numpixels); //Check if (!encoded) break; //Check size if (frame.GetMaxMediaSize()<encoded->GetLength()) //Not enougth space return Error("Not enought space to copy FLV encodec frame [frame:%d,encoded:%d",frame.GetMaxMediaSize(),encoded->GetLength()); //Get full frame frame.SetVideoFrame(encoded->GetData(),encoded->GetLength()); //Set buffer size frame.SetMediaSize(encoded->GetLength()); //Check type if (encoded->IsIntra()) //Set type frame.SetFrameType(RTMPVideoFrame::INTRA); else //Set type frame.SetFrameType(RTMPVideoFrame::INTER); //Let the connection set the timestamp frame.SetTimestamp(getDifTime(&first)/1000); //Send it SendMediaFrame(&frame); } //Check if (decoder) //Delete delete(decoder); //Check if (encoder) //Delete delete(encoder); Log("<RecVideo\n"); }
/******************************************* * Encode * Capturamos el audio y lo mandamos *******************************************/ int FLVEncoder::EncodeAudio() { RTMPAudioFrame audio(0,4096); //Start Log(">Encode Audio\n"); //Fill frame preperties switch(audioCodec) { case AudioCodec::SPEEX16: //Set RTMP data audio.SetAudioCodec(RTMPAudioFrame::SPEEX); audio.SetSoundRate(RTMPAudioFrame::RATE11khz); audio.SetSamples16Bits(1); audio.SetStereo(0); break; case AudioCodec::NELLY8: //Set RTMP data audio.SetAudioCodec(RTMPAudioFrame::NELLY8khz); audio.SetSoundRate(RTMPAudioFrame::RATE11khz); audio.SetSamples16Bits(1); audio.SetStereo(0); break; case AudioCodec::NELLY11: //Set RTMP data audio.SetAudioCodec(RTMPAudioFrame::NELLY); audio.SetSoundRate(RTMPAudioFrame::RATE11khz); audio.SetSamples16Bits(1); audio.SetStereo(0); break; case AudioCodec::AAC: //Set RTMP data // If the SoundFormat indicates AAC, the SoundType should be 1 (stereo) and the SoundRate should be 3 (44 kHz). // However, this does not mean that AAC audio in FLV is always stereo, 44 kHz data. // Instead, the Flash Player ignores these values and extracts the channel and sample rate data is encoded in the AAC bit stream. audio.SetAudioCodec(RTMPAudioFrame::AAC); audio.SetSoundRate(RTMPAudioFrame::RATE44khz); audio.SetSamples16Bits(1); audio.SetStereo(1); audio.SetAACPacketType(RTMPAudioFrame::AACRaw); break; default: return Error("-Codec %s not supported\n",AudioCodec::GetNameFor(audioCodec)); } //Create encoder AudioEncoder *encoder = AudioCodecFactory::CreateEncoder(audioCodec,audioProperties); //Check if (!encoder) //Error return Error("Error opening encoder"); //Try to set native rate DWORD rate = encoder->TrySetRate(audioInput->GetNativeRate()); //Create audio frame AudioFrame frame(audioCodec,rate); //Start recording audioInput->StartRecording(rate); //Get first QWORD ini = 0; //Num of samples since ini QWORD samples = 0; //Allocate samlpes SWORD* recBuffer = (SWORD*) malloc(encoder->numFrameSamples*sizeof(SWORD)); //Check codec if (audioCodec==AudioCodec::AAC) { //Create AAC config frame aacSpecificConfig = new RTMPAudioFrame(0,AACSpecificConfig(rate,1)); //Lock pthread_mutex_lock(&mutex); //Send audio desc SendMediaFrame(aacSpecificConfig); //unlock pthread_mutex_unlock(&mutex); } //Mientras tengamos que capturar while(encodingAudio) { //Check clock drift, do not allow to exceed 4 frames if (ini+(samples+encoder->numFrameSamples*4)*1000/encoder->GetClockRate()<getDifTime(&first)/1000) { Log("-RTMPParticipant clock drift, dropping audio and reseting init time\n"); //Clear buffer audioInput->ClearBuffer(); //Reser timestam ini = getDifTime(&first)/1000; //And samples samples = 0; } //Capturamos DWORD recLen = audioInput->RecBuffer(recBuffer,encoder->numFrameSamples); //Check len if (!recLen) { //Log Debug("-cont\n"); //Reser timestam ini = getDifTime(&first)/1000; //And samples samples = 0; //Skip continue; } //Rencode it DWORD len; while((len=encoder->Encode(recBuffer,recLen,audio.GetMediaData(),audio.GetMaxMediaSize()))>0) { //REset recLen = 0; //Set length audio.SetMediaSize(len); //Check if it is first frame if (!ini) //Get initial timestamp ini = getDifTime(&first)/1000; //Set timestamp audio.SetTimestamp(ini+samples*1000/encoder->GetClockRate()); //Increase samples samples += encoder->numFrameSamples; //Copy to rtp frame frame.SetMedia(audio.GetMediaData(),audio.GetMediaSize()); //Set frame time frame.SetTimestamp(audio.GetTimestamp()); //Set frame duration frame.SetDuration(encoder->numFrameSamples); //Clear rtp frame.ClearRTPPacketizationInfo(); //Add rtp packet frame.AddRtpPacket(0,len,NULL,0); //Lock pthread_mutex_lock(&mutex); //Send audio SendMediaFrame(&audio); //For each listener for(MediaFrameListeners::iterator it = mediaListeners.begin(); it!=mediaListeners.end(); ++it) //Send it (*it)->onMediaFrame(RTMPMediaStream::id,frame); //unlock pthread_mutex_unlock(&mutex); } } //Stop recording audioInput->StopRecording(); //Delete buffer if (recBuffer) //Delete free(recBuffer); //Check codec if (encoder) //Borramos el codec delete(encoder); //Salimos Log("<Encode Audio\n"); }