From bluesky-commits-return-148-apmail-incubator-bluesky-commits-archive=incubator.apache.org@incubator.apache.org Tue Sep 29 12:17:46 2009 Return-Path: Delivered-To: apmail-incubator-bluesky-commits-archive@minotaur.apache.org Received: (qmail 43604 invoked from network); 29 Sep 2009 12:17:46 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.3) by minotaur.apache.org with SMTP; 29 Sep 2009 12:17:46 -0000 Received: (qmail 52408 invoked by uid 500); 29 Sep 2009 12:17:46 -0000 Delivered-To: apmail-incubator-bluesky-commits-archive@incubator.apache.org Received: (qmail 52389 invoked by uid 500); 29 Sep 2009 12:17:46 -0000 Mailing-List: contact bluesky-commits-help@incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: bluesky-dev@incubator.apache.org Delivered-To: mailing list bluesky-commits@incubator.apache.org Received: (qmail 52380 invoked by uid 99); 29 Sep 2009 12:17:46 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 29 Sep 2009 12:17:46 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=10.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 29 Sep 2009 12:17:40 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id 3E10523888DB; Tue, 29 Sep 2009 12:17:20 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Subject: svn commit: r819898 [2/5] - in /incubator/bluesky/trunk/RealClass/Student-1.0: ./ src/ src/pic/ Date: Tue, 29 Sep 2009 12:17:19 -0000 To: bluesky-commits@incubator.apache.org From: ping@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20090929121720.3E10523888DB@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Added: incubator/bluesky/trunk/RealClass/Student-1.0/src/en_de_audio.cpp URL: http://svn.apache.org/viewvc/incubator/bluesky/trunk/RealClass/Student-1.0/src/en_de_audio.cpp?rev=819898&view=auto ============================================================================== --- incubator/bluesky/trunk/RealClass/Student-1.0/src/en_de_audio.cpp (added) +++ incubator/bluesky/trunk/RealClass/Student-1.0/src/en_de_audio.cpp Tue Sep 29 12:17:17 2009 @@ -0,0 +1,1098 @@ +#include "en_de_audio.h" + +#define ENCODE_ID CODEC_ID_MP2//CODEC_ID_PCM_S16LE +#define DECODE_ID CODEC_ID_MP3 + +#define STATIC_AUDIO_FRAMES 10 +#define MAX_PACKET_SIZE 10*1024 +extern void PErrorText(const char* error); + +// For CAEncoder class. + +CAEncoder::CAEncoder() : + m_soundcard("/dev/dsp") +{ + m_pCodec = 0; + m_pCodecCtx = 0; + m_bInit = false; + + m_audio_buf = 0; + m_fifo = 0; + m_data = 0; + m_datasize = 0; + +} + +CAEncoder::~CAEncoder() +{ + /*CAEncoder can't close audio device in ~CAEncoder(), + and close audio device in main()*/ + + m_bInit = false; + CloseAudio(); + + if (m_data) + { + free( m_data); + m_data = 0; + m_datasize = 0; + } + if (m_pCodecCtx) + { + avcodec_close( m_pCodecCtx); + m_pCodecCtx = 0; + } + + if (m_audio_buf) + free( m_audio_buf); + + if (m_fifo) + { + fifo_free( m_fifo); + free(m_fifo); + } + +} + +void CAEncoder::CloseAudio() +{ +} + +bool CAEncoder::OpenAudio() +{ + if (m_soundcard.start_record() < 0) + { + printf("\nopen audio error.\n"); + return false; + } + + SOUNDPARAMS sp; + sp.format = 2; + + sp.channels = 1; + + sp.rate = AUDIO_ENCODE_sample_rate; + + m_soundcard.setparams(&sp); + + printf("\nopen audio success.\n"); + return true; + +} + +#define MAX_AUDIO_PACKET_SIZE (128 * 1024) +bool CAEncoder::Init(enum CodecID nCodecID /*=CODEC_ID_MPEG4*/) +{ + m_bInit = false; + + avienc_init(); + av_register_all(); + + if (!OpenAudio()) + return false; + + /* find the mpeg4 video encoder */ + m_pCodec = avcodec_find_encoder(nCodecID); + if (!m_pCodec) + { + PErrorText("codec not found"); + return false; + } + + if (m_pCodecCtx) + { + avcodec_close( m_pCodecCtx); + m_pCodecCtx = 0; + } + + m_pCodecCtx = avcodec_alloc_context(); + /* put sample parameters */ + m_pCodecCtx->codec_id = nCodecID; + m_pCodecCtx->codec_type = CODEC_TYPE_AUDIO; + m_pCodecCtx->bit_rate = AUDIO_ENCODE_bit_rate; + m_pCodecCtx->sample_rate = AUDIO_ENCODE_sample_rate; + m_pCodecCtx->channels = 1; + + /* open it */ + if (avcodec_open(m_pCodecCtx, m_pCodec) < 0) + { + PErrorText("could not open codec"); + return false; + } + + if (0 == m_audio_buf) + m_audio_buf = (uint8_t*) av_malloc(2 * MAX_AUDIO_PACKET_SIZE); + + if (m_fifo == 0) + { + m_fifo = (FifoBuffer*) malloc(sizeof(FifoBuffer)); + fifo_init(m_fifo, 10000); + } + + m_bInit = true; + return true; +} + +int CAEncoder::EncodeProcess(uint8_t* data, uint8_t *pOutBuf[2], int nOutsize) +{ + int size_out = nOutsize; + int loop_times = 0; + + if (!m_bInit) + return -1; + + /* now encode as many frames as possible */ + if (m_pCodecCtx->frame_size > 1) + { + fifo_write(m_fifo, data, nOutsize, &m_fifo->wptr); + int frame_bytes = m_pCodecCtx->frame_size * 2 * m_pCodecCtx->channels; + while (fifo_read(m_fifo, m_audio_buf, frame_bytes, &m_fifo->rptr) == 0) + { + m_encode_length[loop_times] = avcodec_encode_audio(m_pCodecCtx, + pOutBuf[loop_times], 4 * MAX_AUDIO_PACKET_SIZE, + (short *) m_audio_buf); + ++loop_times; + if (loop_times >= 2) + break; + + } + } + else + { + switch (m_pCodecCtx->codec->id) + { + case CODEC_ID_PCM_S16LE: + case CODEC_ID_PCM_S16BE: + case CODEC_ID_PCM_U16LE: + case CODEC_ID_PCM_U16BE: + break; + default: + size_out = size_out >> 1; + break; + } + m_encode_length[0] = avcodec_encode_audio(m_pCodecCtx, pOutBuf[0], + size_out, (short *) data); + loop_times = 1; + printf("now encode here!\n"); + } + + return loop_times; + +} + +int CAEncoder::Capture(uint8_t** pOutBuf, int &size) +{ + int ret; + static uint8_t buf[10000]; + if (!m_bInit) + return -1; + m_soundcard.sounddata(buf, ret); + + if (ret > 0) + { + *pOutBuf = buf; + size = ret; + return ret; + } + + return -1; +} + +// For CADecoder class. +CADecoder::CADecoder() +{ + m_pCodec = 0; + m_pCodecCtx = 0; + m_pSDLBuf = 0; + m_bInit = false; + +} + +CADecoder::~CADecoder() +{ + + m_bInit = false; + CloseAudio(); + if (m_pSDLBuf) + { + free( m_pSDLBuf); + m_pSDLBuf = 0; + } + + if (m_pCodecCtx) + { + avcodec_close( m_pCodecCtx); + m_pCodecCtx = 0; + } + +} + +void CADecoder::CloseAudio() +{ + +} + +bool CADecoder::OpenAudio() +{ + + return true; +} + +bool CADecoder::Init(enum CodecID nCodecID/* = CODEC_ID_MP3*/, int nOutBufSize /*= SDLBufSize*/) +{ + m_bInit = false; + + avcodec_init(); + avcodec_register_all(); + + if (!OpenAudio()) + { + printf("\n Open audio device faild!"); + return false; + } + //malloc SDLBuf. + if (m_pSDLBuf) + { + free( m_pSDLBuf); + m_pSDLBuf = 0; + } + + m_pSDLBuf = (uint8_t*) malloc(nOutBufSize * sizeof(uint8_t)); + if (m_pSDLBuf == 0) + { + PErrorText("OutBuf malloc failed!"); + return false; + } + // find the video decoder + m_pCodec = avcodec_find_decoder(nCodecID); + if (!m_pCodec) + { + PErrorText("Codec not found"); + return false; + } + + if (m_pCodecCtx) + { + avcodec_close( m_pCodecCtx); + m_pCodecCtx = 0; + } + m_pCodecCtx = avcodec_alloc_context(); + + // frames per second + m_pCodecCtx->frame_rate = A_DECODE_framerate; + m_pCodecCtx->frame_rate_base = A_DECODE_frame_rate_base; + // emit one intra frame every ten frames + m_pCodecCtx->gop_size = A_DECODE_gop_size; + + m_pCodecCtx->bit_rate = AUDIO_DECODE_bit_rate; + m_pCodecCtx->sample_rate = AUDIO_DECODE_sample_rate; + m_pCodecCtx->channels = 1; + + m_pCodecCtx->codec_type = CODEC_TYPE_AUDIO; + + // we dont send complete frames + if (m_pCodec->capabilities & CODEC_CAP_TRUNCATED) + m_pCodecCtx->flags |= CODEC_FLAG_TRUNCATED; + + // open it + if (avcodec_open(m_pCodecCtx, m_pCodec) < 0) + { + PErrorText("could not open codec"); + return false; + } + m_bInit = true; + return true; +} + +int SetFormat(unsigned int fd, unsigned int bits, unsigned int chn, + unsigned int hz) +{ + int ioctl_val; + + /* set bit format */ + ioctl_val = bits; + if (ioctl(fd, SNDCTL_DSP_SETFMT, &ioctl_val) == -1) + { + fprintf(stderr, "Set fmt to bit failed:\n"); + return (-1); + } + if (ioctl_val != bits) + { + fprintf(stderr, "do not support bit supported \n"); + return (-1); + } + + /*set channel */ + ioctl_val = chn; + if ((ioctl(fd, SNDCTL_DSP_CHANNELS, &ioctl_val)) == -1) + { + fprintf(stderr, "Set Audio Channels %d failed:\n", chn); + return (-1); + } + if (ioctl_val != chn) + { + fprintf(stderr, "do not support channel %d,supported\n", chn); + return (-1); + } + + /*set speed */ + ioctl_val = hz; + if (ioctl(fd, SNDCTL_DSP_SPEED, &ioctl_val) == -1) + { + fprintf(stderr, "Set speed to %d failed:\n", hz); + return (-1); + } + if (ioctl_val != hz) + { + fprintf(stderr, "do not support speed %d,supported is\n", hz); + return (-1); + } + + return (0); +} + +int CADecoder::DecodeProcess(uint8_t *encodeddata_a, + const int encodeddatasize_a) +{ + + static JMutex writemutex; + int len; + int encodedAudioSize; + int outAudioBufSize; + int kkk; + + if (!m_bInit) + { + return -1; + } + + if (!writemutex.IsInitialized()) + { + if (!writemutex.Init()) + { + PErrorText("\nDecodeProcess: writemutex Init error\n"); + return -1; + + } + } + + encodedAudioSize = encodeddatasize_a; + len = 0; + kkk = 0; + while (encodedAudioSize > 0) + { + len = avcodec_decode_audio(m_pCodecCtx, (short *) m_pSDLBuf, + &outAudioBufSize, encodeddata_a + kkk, encodedAudioSize); + if (len < 0) + { + PErrorText("Error While Decoding Audio"); + return -2; + } + + encodedAudioSize -= len; + kkk += len; + } + static int s_iloops = 0; + static char s_chAudioBuf[STATIC_AUDIO_FRAMES * 2 * 4096]; + static int s_AudioBuflength = 0; + memcpy(s_chAudioBuf + s_AudioBuflength, m_pSDLBuf, outAudioBufSize); + s_AudioBuflength += outAudioBufSize; + s_iloops++; + + if (outAudioBufSize > 0) + if (s_iloops >= STATIC_AUDIO_FRAMES) + { + writemutex.Lock(); + static int64_t pre, cur, inteval; + pre = av_gettime(); + //write + int fd2; + fd2 = open("/dev/dsp", O_WRONLY); + if (SetFormat(fd2, AFMT_S16_LE, 1, 44100) < 0) + { + fprintf(stderr, "cannot set............\n"); + return (-1); + } + printf("here test 2 %d , %d ........\n", m_pCodecCtx->sample_rate, + fd2); + write(fd2, s_chAudioBuf, s_AudioBuflength); + close(fd2); + + s_iloops = 0; + s_AudioBuflength = 0; + cur = av_gettime(); + inteval = (cur - pre); + + writemutex.Unlock(); + } + + return 0; +} + +//CStuAudioSender class. + +CStuAudioSender::CStuAudioSender() +{ + stop = false; + m_bInit = 0; + m_sendpause = false; + + m_pOutBuf[0] = 0; + m_pOutBuf[1] = 0; +} + +CStuAudioSender::~CStuAudioSender() +{ + //first stop thread, because m_pOutBuf is being used by Thread(); + Stop(); + + //free buffer. + if (m_pOutBuf[0] != 0) + free( m_pOutBuf[0]); + if (m_pOutBuf[1] != 0) + free( m_pOutBuf[1]); +} + +bool CStuAudioSender::Init(int nPort) +{ + if (m_bInit) + return true; + + //init rtpsession. + RTPSessionParams sessParams1; + sessParams1.SetOwnTimestampUnit(1.0 / 30.0); //30 video frames per second + sessParams1.SetUsePollThread(0); //background thread to call virtual callbacks - set by default, but just to be sure + sessParams1.SetMaximumPacketSize(MAX_PACKET_SIZE); + //setup transmission parameters + RTPUDPv4TransmissionParams transParams1; + transParams1.SetPortbase(nPort); + //CREATE THE SESSION + int status1 = m_fecrtpsession.Create(sessParams1, &transParams1); + if (status1) + { + // ReportError(status1); + return false; //unable to create the session + } + //must set for fec SendFECPacket. + m_fecrtpsession.SetDefaultMark(true); + m_fecrtpsession.SetDefaultPayloadType(1); + m_fecrtpsession.SetDefaultTimestampIncrement(0); + + for (int i = 0; i <= 1; i++) + { + if (m_pOutBuf[i] == 0) + { + m_pOutBuf[i] = (uint8_t*) malloc(CAEncoder::A_OutBufSize); + if (m_pOutBuf[i] == 0) + { + return false; + } + + } + } + //Init vencoder. + if (!m_aencoder.Init(ENCODE_ID)) + { + return false; + } + + m_bInit = true; + return m_bInit; +} + +int CStuAudioSender::Start(char* szFile /* =0 */, bool bIsRecord /* =false */) +{ + if (!m_bInit) + return -1; + + if (JThread::IsRunning()) + return 0; + + if (!stopmutex.IsInitialized()) + { + if (stopmutex.Init() < 0) + return -2; + } + + stop = false; + + if (!m_sendpausemutex.IsInitialized()) + { + if (m_sendpausemutex.Init() < 0) + return -2; + } + + m_sendpause = false; + + if (JThread::Start() < 0) + { + return -6; + } + + return 0; +} + +void CStuAudioSender::Stop() +{ + if (!IsRunning()) + return; + + stopmutex.Lock(); + stop = true; + stopmutex.Unlock(); + + //wait for two minute; + sleep(1); + if (JThread::IsRunning()) + { + JThread::Kill(); + } + stop = false; + +} + +void CStuAudioSender::Pause() +{ + if (!m_bInit) + return; + m_sendpausemutex.Lock(); + m_sendpause = true; + m_sendpausemutex.Unlock(); + +} + +void CStuAudioSender::Resume() +{ + if (!m_bInit) + return; + + m_sendpausemutex.Lock(); + m_sendpause = false; + m_sendpausemutex.Unlock(); + +} + +void *CStuAudioSender::Thread() +{ + uint8_t * data; + int datasize; + int OutBufSzie; + int status; + + JThread::ThreadStarted(); + + bool stopthread; + + stopmutex.Lock(); + stopthread = stop; + stopmutex.Unlock(); + + bool sendpause; + + m_sendpausemutex.Lock(); + sendpause = m_sendpause; + m_sendpausemutex.Unlock(); + + int64_t pre_time, cur_time; + useconds_t delay; + pre_time = av_gettime(); + while (!stopthread) + { + + cur_time = av_gettime(); + delay = cur_time - pre_time; + if (delay < 20000 * 2) + { + usleep(20000 * 2 - delay); + pre_time = av_gettime(); + } + + if ((status = m_aencoder.Capture(&data, datasize)) < 0) + { + printf("\naudio capture failed"); + stopthread = true; + } + else + { + if (datasize <= 0) + continue; + OutBufSzie = datasize; + if ((status = m_aencoder.EncodeProcess(data, m_pOutBuf, OutBufSzie)) + < 0) + { + printf("\naudio EncodeProcess failed"); + stopthread = true; + } + else + { + if (status > 0) + { + if (!sendpause) + { + static int s_iTemp1 = 0; + s_iTemp1++; + for (int i = 0; i < status; i++) + { + static char temp_buf[1000]; + int *temp_p = (int *) temp_buf; + static int s_iTemp1 = 0; + s_iTemp1++; + + // printf("now send sequen is %d\n",s_iTemp1); + *temp_p = s_iTemp1; + memcpy(temp_buf + sizeof(int), m_pOutBuf[i], + m_aencoder.encodelength(i)); + m_fecrtpsession.SendPacket(temp_buf, + m_aencoder.encodelength(i) + sizeof(int)); + } + //usleep(20000); + } + } + + m_sendpausemutex.Lock(); + sendpause = m_sendpause; + m_sendpausemutex.Unlock(); + + stopmutex.Lock(); + stopthread = stop; + stopmutex.Unlock(); + } + } + + } + printf("\nAudio capture thread stoped.\n"); + return 0; +} + +bool CStuAudioSender::AddDestination(const RTPIPv4Address &des) +{ + if (!m_bInit) + return false; + if (m_fecrtpsession.AddDestination(des) < 0) + return false; + + return true; +} + +void CStuAudioSender::ClearDestinations() +{ + if (!m_bInit) + return; + m_fecrtpsession.ClearDestinations(); +} + +//CAudioReceiver class. + +CAudioReceiver::CAudioReceiver() +{ + m_bInit = false; +} + +CAudioReceiver::~CAudioReceiver() +{ + +} + +bool CAudioReceiver::Init() +{ + if (m_bInit) + return m_bInit; + + //init video decoder. + if (!m_adecoder.Init(DECODE_ID)) + { + return false; + } + + m_bInit = true; + return m_bInit; + +} + +int CAudioReceiver::Start(int nPort) +{ + if (!m_bInit) + return -1; + + if (IsActive()) + return 0; + + //init rtpsession. + RTPSessionParams sessParams1; + sessParams1.SetOwnTimestampUnit(1.0 / 30.0); //30 video frames per second + sessParams1.SetUsePollThread(1); //background thread to call virtual callbacks - set by default, but just to be sure + sessParams1.SetMaximumPacketSize(MAX_PACKET_SIZE); + //setup transmission parameters + RTPUDPv4TransmissionParams transParams1; + transParams1.SetPortbase(nPort); + //CREATE THE SESSION + int status1 = Create(sessParams1, &transParams1); + if (status1) + return -2; //unable to create the session + + return 0; +} + +void CAudioReceiver::Stop() +{ + Destroy(); +} + +void CAudioReceiver::OnRTPPacket(RTPPacket *pack, const RTPTime &receivetime, + const RTPAddress *senderaddress) +{ + int *iTemp = 0; + iTemp = (int *) pack->GetPayloadData(); + printf("now receive audio sequen is %d\n", *iTemp); + + m_adecoder.DecodeProcess(pack->GetPayloadData() + sizeof(int), + pack->GetPayloadLength() - sizeof(int)); + +} + +/* ---------------------------------------------------------------------- */ + +Soundcard::Soundcard(const char *dev) +{ + if (dev) + strcpy(devname, dev); + else + strcpy(devname, "/dev/dsp"); + + driver_name[0] = '\0'; + + stat = STATUS_CLOSED; + get_capabilities(); + channels = 1; + rate = 22050; + fd = -1; +} + +Soundcard::~Soundcard() +{ + /* nothing */ + close_dev(); +} + +int Soundcard::start_record() +{ + switch (stat) + { + case STATUS_CLOSED: + if (!init_done) + get_capabilities(); + if (!init_done) + return -1; + return open_dev(TRUE); + case STATUS_RECORD: + return 0; + case STATUS_PLAYBACK: + close_dev(); + return open_dev(TRUE); + } + return -1; +} + +int Soundcard::start_playback() +{ + switch (stat) + { + case STATUS_CLOSED: + if (!init_done) + get_capabilities(); + if (!init_done) + return -1; + return open_dev(FALSE); + case STATUS_RECORD: + close_dev(); + return open_dev(FALSE); + case STATUS_PLAYBACK: + return 0; + } + return -1; +} + +int Soundcard::kill_buffer() +{ + ioctl(fd, SNDCTL_DSP_RESET, 0); + return 0; +} + +int Soundcard::stop() +{ + if (stat != STATUS_CLOSED) + close_dev(); + return 0; +} + +/* ---------------------------------------------------------------------- */ + +void Soundcard::get_capabilities() +{ + int i, dsp; + int try_afmt; + int try_channels; + + afmt = 0; + if (-1 != (dsp = open(devname, O_RDONLY))) + { + + ioctl(dsp, SNDCTL_DSP_SETFMT, &afmt); /* current */ + ioctl(dsp, SNDCTL_DSP_GETFMTS, &afmt_hw); /* hardware cap */ + afmt_sw = 0; + + for (i = 0; i < 16; i++) + { + try_afmt = (1 << i); + if (-1 == ioctl(dsp, SNDCTL_DSP_SETFMT, &try_afmt)) + continue; + if (try_afmt != (1 << i)) + continue; + afmt_sw |= try_afmt; + } + + try_channels = 2; + if (-1 != ioctl(dsp, SNDCTL_DSP_CHANNELS, &try_channels) && 2 + == try_channels) + channels_hw = 2; + else + channels_hw = 1; + + close(dsp); + init_done = 1; + + } + else + { + init_done = 0; + } +} + +int Soundcard::has_channels() +{ + if (!init_done) + return -1; + return channels_hw; +} + +int Soundcard::has_format(int f) +{ + if (!init_done) + return -1; + switch (f) + { + case FMT_8BIT: + return (afmt_hw & AFMT_U8) ? 1 : 0; + break; + case FMT_16BIT: + return (afmt_hw & AFMT_S16_LE) ? 1 : 0; + break; + case FMT_MULAW: + case FMT_ALAW: + default: + return 0; + } +} + +char* +Soundcard::driver() +{ + return driver_name; +} + +int Soundcard::open_dev(int record) +{ + struct SOUNDPARAMS p; + int frag, rrate; + + if (-1 == (fd = open(devname, record ? O_RDONLY : O_WRONLY))) + goto err; + fcntl(fd, F_SETFD, FD_CLOEXEC); + + /* try to get ~50 ms latency */ + blocksize = 50 * channels * rate / 1000; + if (afmt == AFMT_U16_BE || afmt == AFMT_S16_BE || afmt == AFMT_U16_LE + || afmt == AFMT_S16_LE) + blocksize *= 2; + for (frag = 0; blocksize != 1; frag++) + blocksize >>= 1; +#if 0 + fprintf(stderr,"asking for %d byte blocksize\n",1 << frag); +#endif + frag |= 0x7fff0000; + if (-1 == ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &frag)) + perror("ioctl SNDCTL_DSP_SETFRAGMENT"); + + rrate = rate; + if (-1 == ioctl(fd, SNDCTL_DSP_SETFMT, &afmt)) + { + perror("ioctl SNDCTL_DSP_SETFMT"); + goto err; + } + if (-1 == ioctl(fd, SNDCTL_DSP_CHANNELS, &channels)) + { + perror("ioctl SNDCTL_DSP_SETFMT"); + goto err; + } + if (-1 == ioctl(fd, SNDCTL_DSP_SPEED, &rrate)) + { + perror("ioctl SNDCTL_DSP_SETFMT"); + goto err; + } + if (-1 == ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &blocksize)) + { + perror("ioctl SNDCTL_DSP_SETFMT"); + goto err; + } + if (0 == blocksize) + blocksize = 4096; + if (rrate != rate) + { + fprintf(stderr, "sample rate: asked for %d, hardware uses %d. ", rate, + rrate); + if (abs(rate - rrate) * 100 < rate) + { + fprintf(stderr, "that's fine (diff <1%%).\n"); + } + else + { + fprintf(stderr, "way off, using hardware rate.\n"); + rate = rrate; + } + } + + latency = blocksize * 1000 / channels / rate; + if (afmt == AFMT_U16_BE || afmt == AFMT_S16_BE || afmt == AFMT_U16_LE + || afmt == AFMT_S16_LE) + latency = latency / 2; + + stat = record ? STATUS_RECORD : STATUS_PLAYBACK; +#if 0 + fprintf(stderr,"%s (format=%d, %s, rate=%d, blocksize=%d, latency=%d ms)\n", + record ? "recording" : "playback", + afmt, + (channels == 2) ? "stereo" : "mono", + rate, blocksize, latency); +#endif + p.channels = channels; + p.rate = rate; + p.blocksize = blocksize; + p.latency = latency; + switch (afmt) + { + case AFMT_U8: + p.format = FMT_8BIT; + break; + case AFMT_S16_LE: + p.format = FMT_16BIT; + break; + default: + fprintf(stderr, "oops(open): unsupported sound format\n"); + exit(1); + } + + if (record) + { + trigger = ~PCM_ENABLE_INPUT; + ioctl(fd, SNDCTL_DSP_SETTRIGGER, &trigger); + trigger = PCM_ENABLE_INPUT; + ioctl(fd, SNDCTL_DSP_SETTRIGGER, &trigger); + } + return 0; + + err: if (-1 != fd) + close( fd); + stat = STATUS_CLOSED; + fd = -1; + return -1; +} + +void Soundcard::close_dev() +{ + close( fd); + fd = -1; + stat = STATUS_CLOSED; + + return; +} + +void Soundcard::setparams(struct SOUNDPARAMS *p) +{ + rate = p->rate; + channels = p->channels; + switch (p->format) + { + case FMT_8BIT: + afmt = AFMT_U8; + break; + case FMT_16BIT: + afmt = AFMT_S16_LE; + break; + default: + fprintf(stderr, "oops(set): unsupported sound format\n"); + exit(1); + } + + switch (stat) + { + case STATUS_RECORD: + close_dev(); + open_dev( TRUE); + break; + case STATUS_PLAYBACK: + close_dev(); + open_dev( FALSE); + break; + case STATUS_CLOSED: + if (!init_done) + get_capabilities(); + if (!init_done) + return; + if (0 == open_dev(TRUE)) + close_dev(); + break; + } + printf("\nchannels=%d\n", channels); + printf("\nrate=%d\n", rate); + printf("\nblocksize=%d\n", blocksize); + printf("\nlatency=%d\n", latency); + +} + +void +//Soundcard::sounddata(int s) +Soundcard::sounddata(uint8_t* buf, int &size) +{ + int rc, have; + + switch (stat) + { + case STATUS_RECORD: + /* read */ + for (have = 0; have < blocksize;) + { + rc = read(fd, buf + have, blocksize - have); + switch (rc) + { + case -1: + { + printf("\naudio capture failed\n"); + size = -1; + return; + } + break; + case 0: + fprintf(stderr, "Huh? got 0 bytes from sound device?\n"); + exit(1); + default: + have += rc; + } + } + size = have; + break; + case STATUS_PLAYBACK: + if (-1 != fd) + write(fd, buffer, blocksize); + break; + } +} Added: incubator/bluesky/trunk/RealClass/Student-1.0/src/en_de_audio.h URL: http://svn.apache.org/viewvc/incubator/bluesky/trunk/RealClass/Student-1.0/src/en_de_audio.h?rev=819898&view=auto ============================================================================== --- incubator/bluesky/trunk/RealClass/Student-1.0/src/en_de_audio.h (added) +++ incubator/bluesky/trunk/RealClass/Student-1.0/src/en_de_audio.h Tue Sep 29 12:17:17 2009 @@ -0,0 +1,236 @@ +#include "fecrtpsession.h" + +// Linux sys. +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +// FFmpeg +#include +#include + +// X11 +#include +#include + +// Jthread and JMutex +#include +#include + +// Audio +#include + +#define STATUS_CLOSED 0 +#define STATUS_RECORD 1 +#define STATUS_PLAYBACK 2 + +#define FMT_UNDEFINED 0 +#define FMT_8BIT 1 /* unsigned */ +#define FMT_16BIT 2 /* signed - native byte order */ +#define FMT_MULAW 4 /* NOT SUPPORTED (yet) */ +#define FMT_ALAW 8 /* NOT SUPPORTED (yet) */ + +#define FMT_MAX 2 + +struct SOUNDPARAMS +{ + int format; + int channels; + int rate; + int blocksize; + int latency; +}; + +class Soundcard +{ + +public: + /* sound card capabilities */ + char devname[32]; + int init_done; + int afmt_hw; + int afmt_sw; + int channels_hw; + + int trigger; + char driver_name[64]; + + /* current settings */ + int afmt; + int channels; + int rate; + int blocksize; + int latency; + + /* file handle, reference count */ + int fd, stat; + char buffer[65536]; + + /* internal functions */ + void get_capabilities(); + int open_dev(int record); + void close_dev(); + +public: + Soundcard(const char *dev); + ~Soundcard(); + char *driver(); + void setparams(struct SOUNDPARAMS *params); + int start_record(); + int start_playback(); + int kill_buffer(); + int stop(); + + int has_channels(); /* # of channels (1=mono,2=stereo) */ + int has_format(int f); /* check format availibity */ + +public: + void sounddata(uint8_t* buf, int &size); + +}; + +#if !defined(_EN_DE_AUDIO_H__INCLUDED_) +#define _EN_DE_AUDIO_H__INCLUDED_ + +// Audio decoder. +class CADecoder +{ +public: +private: + enum ADECODERBUFSIZE + { + A_SDLBufSize = AVCODEC_MAX_AUDIO_FRAME_SIZE + }; + enum AUDIO_DECODEC_PARA + { + AUDIO_DECODE_bit_rate = 64000, + AUDIO_DECODE_sample_rate = 44100, + A_DECODE_framerate = 25, + A_DECODE_frame_rate_base = 1, + A_DECODE_gop_size = 12 + }; + +public: + CADecoder(); + virtual ~CADecoder(); +public: + int DecodeProcess(uint8_t *encodeddata_a, const int encodeddatasize_a); + bool Init(enum CodecID nCodecID = CODEC_ID_MP3, int nOutBufSize = + A_SDLBufSize); +private: + bool OpenAudio(); + void CloseAudio(); +private: + bool m_bInit; + AVCodec *m_pCodec; + AVCodecContext *m_pCodecCtx; + uint8_t *m_pSDLBuf; + +}; + +class CAEncoder +{ + friend class CAudioSender; + friend class CStuAudioSender; +private: + enum AUDIO_ENCODEC_PARA + { + AUDIO_ENCODE_bit_rate = 64000, + AUDIO_ENCODE_sample_rate = 44100, + A_ENCODE_framerate = 25, + A_ENCODE_frame_rate_base = 1, + A_ENCODE_gop_size = 12 + }; +private: + bool OpenAudio(); + void CloseAudio(); + +private: + + enum AENCODERBUFSIZE + { + A_OutBufSize = 4 * 128 * 1024 + };//128000 +public: + int Capture(uint8_t** pOutBuf, int &size); + int EncodeProcess(uint8_t* data, uint8_t *pOutBuf[2], int nOutsize); + bool Init(enum CodecID nCodecID = CODEC_ID_MP2); + CAEncoder(); + virtual ~CAEncoder(); + inline int encodelength(int i) + { + return m_encode_length[i]; + } +private: + + // for audio. +private: + uint8_t* m_data; + int m_datasize; + // for encode. +private: + bool m_bInit; + AVCodec *m_pCodec; + AVCodecContext *m_pCodecCtx; + int m_encode_length[2]; +public: + Soundcard m_soundcard; + uint8_t* m_audio_buf; + FifoBuffer *m_fifo; +}; + +class CStuAudioSender: private JThread +{ +public: + CStuAudioSender(); + ~CStuAudioSender(); + bool Init(int nPort); + bool AddDestination(const RTPIPv4Address &des); + void ClearDestinations(); + int Start(char* szFile = 0, bool bIsRecord = false); + void Pause(); + void Resume(); +private: + void Stop(); + void *Thread(); + bool stop; + JMutex stopmutex; +private: + CAEncoder m_aencoder; + + uint8_t *m_pOutBuf[2]; //only record endcode data 2 times + RTPSession m_fecrtpsession; + int m_bInit; + bool m_sendpause; + JMutex m_sendpausemutex; +}; + +//audio receiver + +class CAudioReceiver: public RTPSession +{ +public: + CAudioReceiver(); + virtual ~CAudioReceiver(); + + bool Init(); + int Start(int nPort); + void Stop(); + +private: + virtual void OnRTPPacket(RTPPacket *pack, const RTPTime &receivetime, + const RTPAddress *senderaddress); + +private: + bool m_bInit; + CADecoder m_adecoder; +}; + +#endif // !defined(_EN_DE_AUDIO_H__INCLUDED_) Added: incubator/bluesky/trunk/RealClass/Student-1.0/src/en_de_common.cpp URL: http://svn.apache.org/viewvc/incubator/bluesky/trunk/RealClass/Student-1.0/src/en_de_common.cpp?rev=819898&view=auto ============================================================================== --- incubator/bluesky/trunk/RealClass/Student-1.0/src/en_de_common.cpp (added) +++ incubator/bluesky/trunk/RealClass/Student-1.0/src/en_de_common.cpp Tue Sep 29 12:17:17 2009 @@ -0,0 +1,17 @@ +#include "en_de_common.h" + +static char g_error_txt[550]; + +char* GetLastErrText() +{ + return g_error_txt; +} + +void PErrorText(const char* error) +{ + if (strlen(error) <= 500) + { + sprintf(g_error_txt, "\nEn_De Error:%s", error); + } +} + Added: incubator/bluesky/trunk/RealClass/Student-1.0/src/en_de_common.h URL: http://svn.apache.org/viewvc/incubator/bluesky/trunk/RealClass/Student-1.0/src/en_de_common.h?rev=819898&view=auto ============================================================================== --- incubator/bluesky/trunk/RealClass/Student-1.0/src/en_de_common.h (added) +++ incubator/bluesky/trunk/RealClass/Student-1.0/src/en_de_common.h Tue Sep 29 12:17:17 2009 @@ -0,0 +1,12 @@ + +#if !defined(_EN_DE_COMMON_INCLUDED_) +#define _EN_DE_COMMON_INCLUDED_ + +extern char* GetLastErrText(); + +#include "en_de_audio.h" +#include "en_de_video.h" +#include "en_de_screen.h" + + +#endif // !defined(_EN_DE_COMMON_INCLUDED_) Added: incubator/bluesky/trunk/RealClass/Student-1.0/src/en_de_screen.cpp URL: http://svn.apache.org/viewvc/incubator/bluesky/trunk/RealClass/Student-1.0/src/en_de_screen.cpp?rev=819898&view=auto ============================================================================== --- incubator/bluesky/trunk/RealClass/Student-1.0/src/en_de_screen.cpp (added) +++ incubator/bluesky/trunk/RealClass/Student-1.0/src/en_de_screen.cpp Tue Sep 29 12:17:17 2009 @@ -0,0 +1,1481 @@ +#include "en_de_screen.h" + +extern int delay_time; + +extern void PErrorText(const char* error); +//CSEncoder class. +CSEncoder::CSEncoder() +{ + m_pFrameBuf = 0; + m_pFrame = 0; + m_pCodec = 0; + m_pCodecCtx = 0; + m_bInit = false; + m_bInitScreen = false; + + m_image = 0; + m_display = 0; + m_d = 0; + m_width = 0; + m_height = 0; + m_screen_num = 0; + +} + +CSEncoder::~CSEncoder() +{ + m_bInitScreen = false; + m_bInit = false; + + if (m_pFrameBuf) + { + free( m_pFrameBuf); + m_pFrameBuf = 0; + } + + if (m_pFrame) + { + free( m_pFrame); + m_pFrame = 0; + } + if (m_pCodecCtx) + { + avcodec_close( m_pCodecCtx); + m_pCodecCtx = 0; + } + + // free for image + if (m_image) + { + XDestroyImage( m_image); + m_image = 0; + } + + if (m_display) + { + if (m_d) + { + XClearWindow(m_display, m_d); + m_d = 0; + } + + XCloseDisplay( m_display); + m_display = 0; + } + +} + +bool CSEncoder::Init(enum CodecID nCodecID /*=CODEC_ID_MPEG4*/) +{ + m_bInit = false; + /*Init for encode*/ + avcodec_init(); + avcodec_register_all(); + + if (!InitScreen(S_CODEC_width, S_CODEC_height)) + return false; + + //new a frame object. + if (m_pFrame) + { + free( m_pFrame); + m_pFrame = 0; + } + m_pFrame = avcodec_alloc_frame(); + + /* find the mpeg4 video encoder */ + m_pCodec = avcodec_find_encoder(nCodecID); + if (!m_pCodec) + { + PErrorText("codec not found\n"); + // fprintf(stderr, ); + return false; + } + + if (m_pCodecCtx) + { + avcodec_close( m_pCodecCtx); + m_pCodecCtx = 0; + } + + m_pCodecCtx = avcodec_alloc_context(); + /* resolution must be a multiple of two */ + m_pCodecCtx->width = m_width; + m_pCodecCtx->height = m_height; + /* frames per second */ + m_pCodecCtx->frame_rate = S_CODEC_framerate; + m_pCodecCtx->frame_rate_base = S_CODEC_frame_rate_base; + m_pCodecCtx->gop_size = S_CODEC_gop_size; /* emit one intra frame every ten frames */ + + m_pCodecCtx->bit_rate = 512 * 1024; + m_pCodecCtx->pix_fmt = PIX_FMT_YUV420P; + m_pCodecCtx->codec_type = CODEC_TYPE_VIDEO; + + /* open it */ + if (avcodec_open(m_pCodecCtx, m_pCodec) < 0) + { + fprintf(stderr, "could not open codec\n"); + return false; + } + + if (m_pFrameBuf) + { + free( m_pFrameBuf); + m_pFrameBuf = 0; + } + + int image_size = avpicture_get_size(PIX_FMT_YUV420P, m_pCodecCtx->width, + m_pCodecCtx->height); + + m_pFrameBuf = (uint8_t*) malloc(image_size); + if (m_pFrameBuf == 0) + { + PErrorText("FrameBuf malloc failed!"); + return false; + } + /*Init for encode*/ + + avpicture_fill((AVPicture*) m_pFrame, m_pFrameBuf, PIX_FMT_YUV420P, + m_pCodecCtx->width, m_pCodecCtx->height); + m_pFrame->type = FF_BUFFER_TYPE_SHARED; + + m_bInit = true; + return true; +} + +int CSEncoder::EncodeProcess(XImage *image, uint8_t *pOutBuf, int nOutsize) +{ + + if (!m_bInit) + return -1; + + if (nOutsize < S_En_OutBufSize) + { + return -2; + } + + //colorconvert + int k, j; + unsigned long r32, g32, b32, color32; + + for (k = 0; k < m_pCodecCtx->height; k++) + { + for (j = 0; j < m_pCodecCtx->width; j++) + { + color32 = *((unsigned long*) (image->data + k * m_pCodecCtx->width + * 4 + j * 4)); + r32 = color32 & (image->red_mask); + g32 = color32 & (image->green_mask); + b32 = color32 & (image->blue_mask); + r32 = ((r32 >> 16) & 255) << 16; + g32 = ((g32 >> 8) & 255) << 8; + b32 = ((b32) & 255); + color32 = r32 | g32 | b32; + color32 = color32 & 16777215; + *((unsigned long*) (image->data + k * m_pCodecCtx->width * 4 + j + * 4)) = color32; + } + } + GetColorInfo(image, &c_info); + switch (image->bits_per_pixel) + { + case 8: + input_pixfmt = PIX_FMT_PAL8; + break; + case 16: + if (image->red_mask == 0xF800 && image->green_mask == 0x07E0 + && image->blue_mask == 0x1F) + { + input_pixfmt = PIX_FMT_RGB565; + } + else if (image->red_mask == 0x7C00 && image->green_mask == 0x03E0 + && image->blue_mask == 0x1F) + { + input_pixfmt = PIX_FMT_RGB555; + } + else + { + fprintf( + stderr, + "xtoffmpeg.XImageToFFMPEG(): rgb ordering at image depth %i not supported ... aborting\n", + image->bits_per_pixel); + fprintf( + stderr, + "xtoffmpeg.XImageToFFMPEG(): color masks: r 0x%.6lX g 0x%.6lX b 0x%.6lX\n", + image->red_mask, image->green_mask, image->blue_mask); + } + break; + case 24: + if (image->red_mask == 0xFF0000 && image->green_mask == 0xFF00 + && image->blue_mask == 0xFF) + { + input_pixfmt = PIX_FMT_BGR24; + } + else if (image->red_mask == 0xFF && image->green_mask == 0xFF00 + && image->blue_mask == 0xFF0000) + { + input_pixfmt = PIX_FMT_RGB24; + } + else + { + PErrorText( + "xtoffmpeg.XImageToFFMPEG(): rgb ordering at image depth not supported ... aborting\n"); + PErrorText("xtoffmpeg.XImageToFFMPEG()"); + return false; + } + break; + case 32: + if (c_info.alpha_mask == 0xFF000000 && image->green_mask == 0xFF00) + { + // byte order is relevant here, not endianness + // endianness is handled by avcodec, but atm no such thing + // as having ABGR, instead of ARGB in a word. Since we + // need this for Solaris/SPARC, but need to do the conversion + // for every frame we do it outside of this loop, cf. below + // this matches both ARGB32 and ABGR32 + input_pixfmt = PIX_FMT_RGBA32; + } + else + { + PErrorText( + "xtoffmpeg.XImageToFFMPEG(): image depth not supported ... aborting"); + return false; + } + break; + default: + PErrorText( + "xtoffmpeg.XImageToFFMPEG(): image depth not supported ... aborting"); + return false; + } + + avpicture_fill(&m_pic_rgb, (uint8_t *) image->data, input_pixfmt, + m_pCodecCtx->width, m_pCodecCtx->height); + avpicture_fill((AVPicture*) m_pFrame, m_pFrameBuf, PIX_FMT_YUV420P, + m_pCodecCtx->width, m_pCodecCtx->height); + + if (img_convert((AVPicture*) m_pFrame, PIX_FMT_YUV420P, &m_pic_rgb, + input_pixfmt, m_pCodecCtx->width, m_pCodecCtx->height) < 0) + { + PErrorText( + "xtoffmpeg.XImageToFFMPEG(): pixel format conversion not handled ... aborting"); + return -2; + } + + m_ScreenHeader.width = m_width; + m_ScreenHeader.height = m_height; + memcpy((char *) pOutBuf, &m_ScreenHeader, sizeof(ScreenHeader)); + + int ret; + ret = avcodec_encode_video(m_pCodecCtx, pOutBuf + sizeof(ScreenHeader), + nOutsize, m_pFrame); + + if (ret <= 0) + return ret; + + return ret + sizeof(ScreenHeader); + +} + +bool CSEncoder::InitScreen(int width, int height) +{ + if (m_bInitScreen) + return true; + m_display = XOpenDisplay(NULL); + + m_width = width; + m_height = height; + m_screen_num = DefaultScreen(m_display); + + m_d = RootWindow(m_display, m_screen_num); + + XWindowAttributes win_attr; + + if (!XGetWindowAttributes(m_display, m_d, &win_attr))//获取屏幕窗口属性 + + perror("Can't get window attributes!\n"); + + m_image = 0; + m_bInitScreen = true; + return true; +} + +bool CSEncoder::GetScreenSize(int &width, int &height) +{ + if (!m_bInit) + return false; + + width = m_pCodecCtx->width; + height = m_pCodecCtx->height; + + return true; +} + +//Mouse capture. +uint16_t mousePointerBlack[] = +{ 0, 49152, 40960, 36864, 34816, 33792, 33280, 33024, 32896, 32832, 33728, + 37376, 43264, 51456, 1152, 1152, 576, 576, 448, 0 }; +uint16_t mousePointerWhite[] = +{ 0, 0, 16384, 24576, 28672, 30720, 31744, 32256, 32512, 32640, 31744, 27648, + 17920, 1536, 768, 768, 384, 384, 0, 0 }; +/* + * the following function finds out where the mouse pointer is + */ +void CSEncoder::getCurrentPointer(int *x, int *y) +{ + Window mrootwindow, childwindow; + int dummy; + + if (!m_bInit) + return; + + mrootwindow = DefaultRootWindow(m_display); + + if (XQueryPointer(m_display, mrootwindow, &mrootwindow, &childwindow, x, y, + &dummy, &dummy, (unsigned int *) &dummy)) + { + // empty + // if the XQueryPointer was successfull, we have everything we need in the variables + // passed as result pointers + } + else + { + *x = -1; + *y = -1; + } + + XClearWindow(m_display, mrootwindow); +} + +/* + * paint the dummy mouse pointer into a given frame + */ +void CSEncoder::paintMousePointer(int *x, int *y, XImage *image) +{ + // only paint a mouse pointer into the dummy frame if the position of the mouse + // is within the rectangle defined by the capture frame + + if (*x >= 0 && *x < S_CODEC_width - 25 && //25 is width and height of cursor . + *y >= 0 && *y < S_CODEC_height - 25) + { + int line; + uint8_t *im_data = (uint8_t *) image->data; + + // move the cursor to the right starting position + im_data += (image->bytes_per_line * (*y)); // shift to right line + im_data += (image->bits_per_pixel / 8 * (*x)); // shift to right pixel + + uint32_t *cursor; + int width; + uint16_t bm_b, bm_w, mask; + + // the dummy mouse pointer is 20 pixels high ... + for (line = 0; line < 20; line++) + { + bm_b = mousePointerBlack[line]; + bm_w = mousePointerWhite[line]; + + mask = (0x0001 << 15); + + // ... and 16 pixels wide + for (cursor = (uint32_t*) im_data, width = 0; ((width + *x) + < S_CODEC_width && width < 16); cursor++, width++) + { + if ((bm_b & mask) > 0) + { + *cursor &= ((~image->red_mask) & (~image->green_mask) + & (~image->blue_mask)); + } + else if ((bm_w & mask) > 0) + { + *cursor |= (image->red_mask | image->green_mask + | image->blue_mask); + } + mask >>= 1; + } + im_data += image->bytes_per_line; + } + + } +} + +//Mouse capture. + +bool CSEncoder::Capture(XImage **image) +{ + int x, y; + if (!m_bInitScreen) + return false; + + if (m_image) + { + m_image->f.destroy_image(m_image); + m_image = 0; + } + getCurrentPointer(&x, &y); + m_image = XGetImage(m_display, m_d, 0, 0, m_width, m_height, AllPlanes, + ZPixmap); + + if (m_image == 0) + { + PErrorText("GetImage error"); + return false; + } + paintMousePointer(&x, &y, m_image); + + *image = m_image; + return true; +} + +void CSEncoder::GetColorInfo(XImage *image, ColorInfo *ci /* return struct */) +{ + unsigned long red_mask, green_mask, blue_mask, alpha_mask; + // the shifts are unsigned longs as well + + if (!ci) + return; + + // setting shifts and bit_depths to zero + ci->red_shift = ci->green_shift = ci->blue_shift = ci->alpha_shift = 0; + ci->red_bit_depth = ci->green_bit_depth = ci->blue_bit_depth + = ci->alpha_bit_depth = 0; + + red_mask = image->red_mask; + if (red_mask > 0) + { + // shift red_mask to the right till all empty bits have been + // shifted out and count how many they were + while ((red_mask & 0x01) == 0) + { + red_mask >>= 1; + ci->red_shift++; + } + // count how many bits are set in the mask = depth + while ((red_mask & 0x01) == 1) + { + red_mask >>= 1; + ci->red_bit_depth++; + } + } + + ci->red_max_val = (1 << ci->red_bit_depth) - 1; + + green_mask = image->green_mask; + if (green_mask > 0) + { + while ((green_mask & 0x01) == 0) + { + green_mask >>= 1; + ci->green_shift++; + } + while ((green_mask & 0x01) == 1) + { + green_mask >>= 1; + ci->green_bit_depth++; + } + } + ci->green_max_val = (1 << ci->green_bit_depth) - 1; + + blue_mask = image->blue_mask; + if (blue_mask > 0) + { + while ((blue_mask & 0x01) == 0) + { + blue_mask >>= 1; + ci->blue_shift++; + } + while ((blue_mask & 0x01) == 1) + { + blue_mask >>= 1; + ci->blue_bit_depth++; + } + } + ci->blue_max_val = (1 << ci->blue_bit_depth) - 1; + + /* over all max values */ + // whatever they are good for + ci->max_val = max(ci->red_max_val, ci->green_max_val); + ci->max_val = max(ci->blue_max_val, ci->max_val); + ci->bit_depth = max(ci->red_bit_depth, ci->green_bit_depth); + ci->bit_depth = max(ci->blue_bit_depth, ci->bit_depth); + if (image->bits_per_pixel > image->depth) + { + + ci->alpha_mask = ~(image->red_mask | image->blue_mask + | image->green_mask); + alpha_mask = ci->alpha_mask; + if (alpha_mask > 0) + { + while ((alpha_mask & 0x01) == 0) + { + alpha_mask >>= 1; + ci->alpha_shift++; + } + while ((alpha_mask & 0x01) == 1) + { + alpha_mask >>= 1; + ci->alpha_bit_depth++; + } + } + ci->alpha_max_val = (1 << ci->alpha_bit_depth) - 1; + } +} +//CSDecoder class. +CSDecoder::CSDecoder() +{ + m_pCodec = 0; + m_pCodecCtx = 0; + m_pOutFrame = 0; + m_bInit = false; + + m_display = 0; + m_win = 0; + m_d = 0; + m_image = 0; + m_parent = 0; + + m_width = 0; + m_height = 0; + +} + +CSDecoder::~CSDecoder() +{ + m_bInit = false; + + if (m_image) + { + XDestroyImage( m_image); + m_image = 0; + } + + if (m_display) + { + if (m_win) + { + XClearWindow(m_display, m_win); + m_win = 0; + } + if (m_d) + { + XClearWindow(m_display, m_d); + m_d = 0; + } + + XCloseDisplay( m_display); + m_display = 0; + } + + if (m_pOutFrame) + { + free( m_pOutFrame); + m_pOutFrame = 0; + } + if (m_pCodecCtx) + { + if (m_pCodecCtx->extradata) + { + free(m_pCodecCtx->extradata); + m_pCodecCtx->extradata = 0; + m_pCodecCtx->extradata_size = 0; + } + avcodec_close( m_pCodecCtx); + m_pCodecCtx = 0; + } + +} + +bool CSDecoder::CreateXImage(Drawable parent, int x, int y, int width, + int height) +{ + int screen_num; + + GdkPixbuf *original_pixbuf; + + gint original_width, original_height; + GdkColorspace original_color; + gboolean original_alpha; + gboolean pixbuf_has_alpha; + XSetWindowAttributes win_attr; + XImage *p_image = NULL; + if (!m_bInit) + return false; + + CloseXImage(); + + m_imagemutex.Lock(); + + m_display = XOpenDisplay(NULL); + screen_num = DefaultScreen(m_display); + m_gc = DefaultGC(m_display, screen_num); + m_d = RootWindow(m_display, screen_num); + + m_win = XCreateWindow(m_display, parent, x, y, width, height, 1, + XDefaultDepth(m_display, screen_num), InputOutput, CopyFromParent, + 0, &win_attr); + + if (gdk_pixbuf_new_from_file("pic/screen.bmp", NULL) == NULL) + { + XSetWindowBackgroundPixmap(m_display, m_win, ParentRelative); + XMapWindow(m_display, m_win); + } + else + { + original_pixbuf = gdk_pixbuf_new_from_file("pic/screen.bmp", NULL); + pixbuf_has_alpha = gdk_pixbuf_get_has_alpha(original_pixbuf); + original_color = gdk_pixbuf_get_colorspace(original_pixbuf); + original_alpha = gdk_pixbuf_get_has_alpha(original_pixbuf); + original_width = gdk_pixbuf_get_width(original_pixbuf); + original_height = gdk_pixbuf_get_height(original_pixbuf); + printf("original_alpha = %d\n", original_alpha); + printf("original_color = %d\n", original_color); + printf("original_width = %d\n", original_width); + printf("original_height = %d\n", original_height); + printf("n_channles = %d\n", gdk_pixbuf_get_n_channels(original_pixbuf)); + + Pixmap pixmap = XCreatePixmap(m_display, m_win, original_width, + original_height, XDefaultDepth(m_display, screen_num)); + XSetWindowBackgroundPixmap(m_display, m_win, pixmap); + + p_image = XGetImage(m_display, m_d, 0, 0, original_width, + original_height, AllPlanes, ZPixmap); + if (!p_image) + { + printf("error\n"); + exit(10); + } + + AVPicture pic_rgb24, pic_rgb32; + if (m_display && p_image && pixmap) + { + avpicture_fill(&pic_rgb32, (uint8_t*) p_image->data, + PIX_FMT_RGBA32, original_width, original_height); + avpicture_fill(&pic_rgb24, gdk_pixbuf_get_pixels(original_pixbuf), + PIX_FMT_RGB24, original_width, original_height); + + if (img_convert(&pic_rgb32, PIX_FMT_RGBA32, &pic_rgb24, + PIX_FMT_RGB24, original_width, original_height) < 0) + { + printf("Error pixel format conversion"); + return -1; + } + + XPutImage(m_display, pixmap, m_gc, p_image, 0, 0, 0, 0, + original_width, original_height); + + } + + XMapWindow(m_display, m_win); + XFreePixmap(m_display, pixmap); + gdk_pixbuf_unref(original_pixbuf); + XDestroyImage(p_image); + } + + m_image = XGetImage(m_display, m_d, 0, 0, m_width, m_height, AllPlanes, + ZPixmap); + if (!m_image) + { + printf("error\n"); + m_imagemutex.Unlock(); + return false; + } + + m_imagemutex.Unlock(); + m_parent = parent; + return true; +} + +void CSDecoder::CloseXImage() +{ + if (!m_bInit) + return; + + m_imagemutex.Lock(); + if (m_image) + { + XDestroyImage( m_image); + // m_image->f.destroy_image(m_image); + m_image = 0; + } + + if (m_display) + { + if (m_win) + { + XUnmapWindow(m_display, m_win); + XClearWindow(m_display, m_win); + m_win = 0; + } + + if (m_d) + { + XClearWindow(m_display, m_d); + m_d = 0; + } + + XCloseDisplay( m_display); + m_display = 0; + + } + + m_imagemutex.Unlock(); + +} + +void CSDecoder::CloseCodec() +{ + m_bInit = false; + + if (m_pOutFrame) + { + free( m_pOutFrame); + m_pOutFrame = 0; + } + if (m_pCodecCtx) + { + if (m_pCodecCtx->extradata) + { + free(m_pCodecCtx->extradata); + m_pCodecCtx->extradata = 0; + m_pCodecCtx->extradata_size = 0; + } + avcodec_close( m_pCodecCtx); + m_pCodecCtx = 0; + } + +} +bool CSDecoder::ResetCodec(const int width, const int height) +{ + CodecID nCodecID = m_pCodecCtx->codec_id; + CloseCodec(); + m_bInit = false; + + m_width = width; + m_height = height; + + // find the video decoder + m_pCodec = avcodec_find_decoder(nCodecID); + if (!m_pCodec) + { + PErrorText("Codec not found"); + return false; + } + + if (m_pOutFrame) + { + free( m_pOutFrame); + m_pOutFrame = 0; + } + m_pOutFrame = avcodec_alloc_frame(); + + if (m_pCodecCtx) + { + if (m_pCodecCtx->extradata) + { + free(m_pCodecCtx->extradata); + m_pCodecCtx->extradata = 0; + m_pCodecCtx->extradata_size = 0; + } + avcodec_close( m_pCodecCtx); + m_pCodecCtx = 0; + } + m_pCodecCtx = avcodec_alloc_context(); + m_pCodecCtx->extradata = 0; + m_pCodecCtx->extradata_size = 0; + + m_pCodecCtx->width = m_width; + m_pCodecCtx->height = m_height; + /* frames per second */ + m_pCodecCtx->frame_rate = CSEncoder::S_CODEC_framerate; + m_pCodecCtx->frame_rate_base = CSEncoder::S_CODEC_frame_rate_base; + m_pCodecCtx->gop_size = CSEncoder::S_CODEC_gop_size; /* emit one intra frame every ten frames */ + + m_pCodecCtx->bit_rate = 512 * 1024; + m_pCodecCtx->pix_fmt = PIX_FMT_YUV420P; + m_pCodecCtx->codec_type = CODEC_TYPE_VIDEO; + + m_pCodecCtx->flags |= CODEC_FLAG_GLOBAL_HEADER; + m_pCodecCtx->extradata = malloc(S_De_ExtraHeaderSize); + if (m_pCodecCtx->extradata == 0) + { + return false; + } + m_pCodecCtx->extradata_size = S_De_ExtraHeaderSize / 8; + + // we dont send complete frames + if (m_pCodec->capabilities & CODEC_CAP_TRUNCATED) + m_pCodecCtx->flags |= CODEC_FLAG_TRUNCATED; + + // open it + if (avcodec_open(m_pCodecCtx, m_pCodec) < 0) + { + PErrorText("could not open codec"); + return false; + } + + if (m_image) + { + XDestroyImage( m_image); + m_image = 0; + } + + m_image = XGetImage(m_display, m_parent, 0, 0, m_width, m_height, + AllPlanes, ZPixmap); + if (!m_image) + { + PErrorText("GetImage error"); + m_imagemutex.Unlock(); + return false; + } + + m_bInit = true; + return true; + +} + +bool CSDecoder::Init(int width, int height, enum CodecID nCodecID) +{ + + if (m_bInit) + return true; + + avcodec_init(); + avcodec_register_all(); + + if (!m_imagemutex.IsInitialized()) + { + if (m_imagemutex.Init() < 0) + return false; + } + + m_width = width; + m_height = height; + + // find the video decoder + m_pCodec = avcodec_find_decoder(nCodecID); + if (!m_pCodec) + { + PErrorText("Codec not found"); + return false; + } + + if (m_pOutFrame) + { + free( m_pOutFrame); + m_pOutFrame = 0; + } + m_pOutFrame = avcodec_alloc_frame(); + + if (m_pCodecCtx) + { + if (m_pCodecCtx->extradata) + { + free(m_pCodecCtx->extradata); + m_pCodecCtx->extradata = 0; + m_pCodecCtx->extradata_size = 0; + } + avcodec_close( m_pCodecCtx); + m_pCodecCtx = 0; + } + m_pCodecCtx = avcodec_alloc_context(); + m_pCodecCtx->extradata = 0; + m_pCodecCtx->extradata_size = 0; + + // put sample parameters + /* resolution must be a multiple of two */ + m_pCodecCtx->width = m_width; + m_pCodecCtx->height = m_height; + /* frames per second */ + m_pCodecCtx->frame_rate = CSEncoder::S_CODEC_framerate; + m_pCodecCtx->frame_rate_base = CSEncoder::S_CODEC_frame_rate_base; + m_pCodecCtx->gop_size = CSEncoder::S_CODEC_gop_size; /* emit one intra frame every ten frames */ + + m_pCodecCtx->bit_rate = 512 * 1024; + m_pCodecCtx->pix_fmt = PIX_FMT_YUV420P; + m_pCodecCtx->codec_type = CODEC_TYPE_VIDEO; + + m_pCodecCtx->flags |= CODEC_FLAG_GLOBAL_HEADER; + m_pCodecCtx->extradata = malloc(S_De_ExtraHeaderSize); + if (m_pCodecCtx->extradata == 0) + { + return false; + } + m_pCodecCtx->extradata_size = S_De_ExtraHeaderSize / 8; + + // we dont send complete frames + if (m_pCodec->capabilities & CODEC_CAP_TRUNCATED) + m_pCodecCtx->flags |= CODEC_FLAG_TRUNCATED; + + // open it + if (avcodec_open(m_pCodecCtx, m_pCodec) < 0) + { + PErrorText("could not open codec"); + return false; + } + + m_bInit = true; + return true; +} + +int CSDecoder::DecodeProcess(uint8_t *encodeddata_v, + const int encodeddatasize_v) +{ + bool isPaintPic; + int realsize, i; + int got_picture; + if (!m_bInit) + { + return -1; + } + + int left = 0; + int len; + m_imagemutex.Lock(); + for (i = 0;; i++) + { + if (encodeddatasize_v - i * S_De_INBUF_SIZE >= S_De_INBUF_SIZE) + realsize = S_De_INBUF_SIZE; + else + realsize = encodeddatasize_v - i * S_De_INBUF_SIZE; + + if (realsize <= 0) + break; + + left = 0; + isPaintPic = false; + while (realsize > 0) + { + m_pCodecCtx->width = m_width; + m_pCodecCtx->height = m_height; + len = avcodec_decode_video(m_pCodecCtx, m_pOutFrame, &got_picture, + (encodeddata_v + i * S_De_INBUF_SIZE + left), realsize); + + if (len < 0) + { + PErrorText("Error while decoding"); + m_imagemutex.Unlock(); + return -2; + } + + if (m_image != 0) + { + + m_encoder.GetColorInfo(m_image, &c_info); + switch (m_image->bits_per_pixel) + { + case 8: + input_pixfmt = PIX_FMT_PAL8; + break; + case 16: + if (m_image->red_mask == 0xF800 && m_image->green_mask + == 0x07E0 && m_image->blue_mask == 0x1F) + { + input_pixfmt = PIX_FMT_RGB565; + } + else if (m_image->red_mask == 0x7C00 && m_image->green_mask + == 0x03E0 && m_image->blue_mask == 0x1F) + { + input_pixfmt = PIX_FMT_RGB555; + } + else + { + fprintf( + stderr, + "xtoffmpeg.XImageToFFMPEG(): rgb ordering at image depth %i not supported ... aborting\n", + m_image->bits_per_pixel); + fprintf( + stderr, + "xtoffmpeg.XImageToFFMPEG(): color masks: r 0x%.6lX g 0x%.6lX b 0x%.6lX\n", + m_image->red_mask, m_image->green_mask, + m_image->blue_mask); + } + break; + case 24: + if (m_image->red_mask == 0xFF0000 && m_image->green_mask + == 0xFF00 && m_image->blue_mask == 0xFF) + { + input_pixfmt = PIX_FMT_BGR24; + } + else if (m_image->red_mask == 0xFF && m_image->green_mask + == 0xFF00 && m_image->blue_mask == 0xFF0000) + { + input_pixfmt = PIX_FMT_RGB24; + } + else + { + PErrorText( + "xtoffmpeg.XImageToFFMPEG(): rgb ordering at image depth not supported ... aborting"); + PErrorText("xtoffmpeg.XImageToFFMPEG(): color masks"); + return false; + } + break; + case 32: + if (c_info.alpha_mask == 0xFF000000 && m_image->green_mask + == 0xFF00) + { + // byte order is relevant here, not endianness + // endianness is handled by avcodec, but atm no such thing + // as having ABGR, instead of ARGB in a word. Since we + // need this for Solaris/SPARC, but need to do the conversion + // for every frame we do it outside of this loop, cf. below + // this matches both ARGB32 and ABGR32 + input_pixfmt = PIX_FMT_RGBA32; + } + else + { + PErrorText( + "xtoffmpeg.XImageToFFMPEG(): image depth not supported ... aborting\n"); + return false; + } + break; + default: + PErrorText( + "xtoffmpeg.XImageToFFMPEG(): image depth not supported ... aborting\n"); + return false; + } + } + + if (got_picture) + { + + if (!isPaintPic) + { + if (m_display && m_image && m_win) + { + avpicture_fill(&pic_rgb, (uint8_t*) m_image->data, + input_pixfmt, m_width, m_height); + + if (img_convert(&pic_rgb, input_pixfmt, + (AVPicture*) m_pOutFrame, PIX_FMT_YUV420P, + m_width, m_height) < 0) + { + PErrorText("Error pixel format conversion"); + m_imagemutex.Unlock(); + return -3; + } + + XPutImage(m_display, m_win, m_gc, m_image, 0, 0, 0, 0, + m_width, m_height); + } + } + isPaintPic = true; + + } + realsize -= len; + left += len; + } + } + + m_imagemutex.Unlock(); + return 0; +} + +//CScreenSender class. + +CScreenSender::CScreenSender() : + m_sendthread(SendBufSize) +{ + stop = false; + m_bIsRecord = false; + m_bInit = 0; + + m_hFile = 0; + +} + +CScreenSender::~CScreenSender() +{ + //first stop thread, because m_pOutBuf is being used by Thread(); + Stop(); + + //close file. + if (m_hFile) + { + fclose( m_hFile); + m_hFile = 0; + } + + //free buffer. + if (m_pOutBuf != 0) + free( m_pOutBuf); +} + +bool CScreenSender::Init(int nPort) +{ + if (m_bInit) + return true; + + //init sendthread. + if (!m_sendthread.Init(nPort)) + return false; + + if (m_pOutBuf == 0) + { + m_pOutBuf = (uint8_t*) malloc(CSEncoder::S_En_OutBufSize); + if (m_pOutBuf == 0) + { + return false; + } + + } + + //Init sencoder. + if (!m_sencoder.Init(CODEC_ID_MPEG4)) + { + return false; + } + + m_bInit = true; + return m_bInit; +} + +int CScreenSender::Start(char* szFile /* =0 */, bool bIsRecord /* =false */) +{ + if (!m_bInit) + return -1; + + if (JThread::IsRunning()) + return 0; + + if (!stopmutex.IsInitialized()) + { + if (stopmutex.Init() < 0) + return -2; + } + + stop = false; + + if (!m_recordmutex.IsInitialized()) + { + if (m_recordmutex.Init() < 0) + return -2; + } + + m_bIsRecord = bIsRecord; + + if (bIsRecord && szFile != 0) + { + if (m_hFile) + { + fclose( m_hFile); + m_hFile = 0; + } + + m_hFile = fopen(szFile, "wb"); + if (m_hFile == 0) + { + return -3; + } + + } + + if (m_sendthread.Start() < 0) + { + return -6; + } + + if (JThread::Start() < 0) + { + return -6; + } + + return 0; +} + +void CScreenSender::Stop() +{ + if (!IsRunning()) + return; + + stopmutex.Lock(); + stop = true; + stopmutex.Unlock(); + + int count = 0; + while (1) + { + if (count >= 100) + { + if (JThread::IsRunning()) + { + JThread::Kill(); + } + break; + } + + if (JThread::IsRunning()) + { + count++; + usleep(10000); + continue; + } + + break; + } + + stop = false; + + //close file. + if (m_hFile) + { + fclose( m_hFile); + m_hFile = 0; + } + + m_bIsRecord = false; + + m_sendthread.Stop(); + +} + +void CScreenSender::Record(bool bInRecord /* =true */) +{ + if (!m_bInit) + return; + + m_recordmutex.Lock(); + m_bIsRecord = bInRecord; + m_recordmutex.Unlock(); + +} + +void *CScreenSender::Thread() +{ + XImage * pImage; + int OutBufSzie; + + JThread::ThreadStarted(); + + bool stopthread; + + stopmutex.Lock(); + stopthread = stop; + stopmutex.Unlock(); + + bool isrecord; + m_recordmutex.Lock(); + isrecord = m_bIsRecord; + m_recordmutex.Unlock(); + + int status; + + int64_t pre_time, cur_time; + useconds_t delay, delay1; + + if (m_sencoder.m_pCodecCtx->frame_rate != 0) + { + if (m_sencoder.m_pCodecCtx->frame_rate_base != 0) + delay1 = 1000000 * m_sencoder.m_pCodecCtx->frame_rate_base + / m_sencoder.m_pCodecCtx->frame_rate; + else + delay1 = 1000000 / m_sencoder.m_pCodecCtx->frame_rate; + } + else + { + delay1 = 1000000; + } + + // sleep for sync + if (delay_time > 0) + { + sleep( delay_time); + } + + // for Utiltiy rate of CPU + cur_time = av_gettime(); + pre_time = cur_time - delay1; + + // for compensate. + int64_t nFrame = 0; + int64_t rec_time = 0; + int64_t rec_start; + rec_start = av_gettime(); + + while (!stopthread) + { + delay = cur_time - pre_time; + if (delay < delay1) + { + usleep(delay1 - delay); + } + pre_time = av_gettime(); + + if ((status = m_sencoder.Capture(&pImage)) < 0) + { + stopthread = true; + continue; + } + else + { + OutBufSzie = CSEncoder::S_En_OutBufSize; + if ((status = m_sencoder.EncodeProcess(pImage, m_pOutBuf, + OutBufSzie)) < 0) + { + stopthread = true; + continue; + } + else + { + if (status > 0) + { + //static int iiii=0; + m_sendthread.SendData(m_pOutBuf, status); + //iiii ++; + //printf("\nscreen send(%d): %d bytes\n", iiii, status); + + if (m_hFile != 0 && isrecord) + { + fwrite(m_pOutBuf + sizeof(ScreenHeader), status + - sizeof(ScreenHeader), 1, m_hFile); + nFrame++; + + //add up rec_time; + rec_time = av_gettime() - rec_start; + int i; + for (i = 0; rec_time > nFrame * delay1; nFrame++, i++) + { + printf("\nScreen Frame=%d\n", nFrame); + if ((status = m_sencoder.EncodeProcess(pImage, + m_pOutBuf, OutBufSzie)) < 0) + { + printf("\nscreen: encode vital error."); + stopthread = true; + printf( + "\nscreen capture thread stoped by EncodeProcess error!\n"); + return 0; + } + if (status > 0) + fwrite(m_pOutBuf + sizeof(ScreenHeader), status + - sizeof(ScreenHeader), 1, m_hFile); + } + + } + else + { + rec_start = av_gettime(); + nFrame = 0; + } + + } + + m_recordmutex.Lock(); + isrecord = m_bIsRecord; + m_recordmutex.Unlock(); + + stopmutex.Lock(); + stopthread = stop; + stopmutex.Unlock(); + } + } + + cur_time = av_gettime(); + // printf("\ncur-pre=%d\n", cur-pre); + } + + printf("\nscreen capture thread stoped!\n"); + return 0; +} + +bool CScreenSender::AddDestination(const RTPIPv4Address &des) +{ + if (!m_bInit) + return false; + if (m_sendthread.AddDestination(des) < 0) + return false; + + return true; +} +void CScreenSender::ClearDestinations() +{ + if (!m_bInit) + return; + m_sendthread.ClearDestinations(); +} + +//CScreenReceiver class. + +CScreenReceiver::CScreenReceiver() +{ + m_bInit = false; + m_ScreenInit = false; + // m_playback = 0; +} + +CScreenReceiver::~CScreenReceiver() +{ + +} +bool CScreenReceiver::Init() +{ + if (m_bInit) + return m_bInit; + + //init video decoder. + if (!m_sdecoder.Init(800, 600, CODEC_ID_MPEG4)) + { + return false; + } + + m_bInit = true; + return m_bInit; + +} +bool CScreenReceiver::CreateXImage(Drawable parent, int x, int y, int width, + int height) +{ + bool ret; + //init screen decoder. + + ret = m_sdecoder.CreateXImage(parent, x, y, width, height); + + return ret; +} + +void CScreenReceiver::CloseXImage() +{ + m_sdecoder.CloseXImage(); +} + +#define MAX_PACKET_SIZE 10240 + +int CScreenReceiver::Start(int nPort) +{ + if (IsActive()) + return 0; + + //init rtpsession. + RTPSessionParams sessParams1; + sessParams1.SetOwnTimestampUnit(1.0 / 30.0); //30 video frames per second + sessParams1.SetUsePollThread(1); //background thread to call virtual callbacks - set by default, but just to be sure + sessParams1.SetMaximumPacketSize(MAX_PACKET_SIZE); + //setup transmission parameters + RTPUDPv4TransmissionParams transParams1; + transParams1.SetPortbase(nPort); + //CREATE THE SESSION + int status1 = Create(sessParams1, &transParams1); + if (status1) + { + // ReportError(status1); + return -2; //unable to create the session + } + + return 0; +} + +void CScreenReceiver::Stop() +{ + Destroy(); +} + +void CScreenReceiver::ProcessFrame(unsigned char* framedata, int framelen) +{ + pScreen = (ScreenHeader*) framedata; + + if (pScreen->width != m_sdecoder.m_width || pScreen->height + != m_sdecoder.m_height) + { + m_sdecoder.ResetCodec(pScreen->width, pScreen->height); + } + m_sdecoder.DecodeProcess(framedata + sizeof(ScreenHeader), framelen + - sizeof(ScreenHeader)); + +} Added: incubator/bluesky/trunk/RealClass/Student-1.0/src/en_de_screen.h URL: http://svn.apache.org/viewvc/incubator/bluesky/trunk/RealClass/Student-1.0/src/en_de_screen.h?rev=819898&view=auto ============================================================================== --- incubator/bluesky/trunk/RealClass/Student-1.0/src/en_de_screen.h (added) +++ incubator/bluesky/trunk/RealClass/Student-1.0/src/en_de_screen.h Tue Sep 29 12:17:17 2009 @@ -0,0 +1,222 @@ +//en_de_srceen.h + +#include "fecrtpsession.h" +#include "en_de_sendthread.h" + +// Linux sys. +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +// FFmpeg +#include +#include +//Time +#include +// X11 +#include +#include +// Jthread and JMutex +#include +#include +#include + +#define max(x,y) (x > y ? x : y) + +#if !defined(_EN_DE_SCREEN_H__INCLUDED_) +#define _EN_DE_SCREEN_H__INCLUDED_ + +typedef void (*ScreenPlayback)(uint8_t* screendata, int width, int height); +typedef struct ScreenHeader +{ + int width; + int height; +} ScreenHeader; + +typedef struct +{ + unsigned long red_shift; + unsigned long green_shift; + unsigned long blue_shift; + unsigned long alpha_shift; + unsigned long max_val; + unsigned long bit_depth; + unsigned long red_max_val; + unsigned long green_max_val; + unsigned long blue_max_val; + unsigned long alpha_max_val; + unsigned long red_bit_depth; + unsigned long green_bit_depth; + unsigned long blue_bit_depth; + unsigned long alpha_bit_depth; + u_int32_t alpha_mask; +} ColorInfo; + +//Screen encoder. +class CSEncoder +{ + friend class CSDecoder; + friend class CScreenSender; + friend class CWScreenRecorder; +private: + enum SENCODERBUFSIZE + { + S_En_OutBufSize = 400 * 1024 + }; + enum SCREEN_CODEC_PARA + { + S_CODEC_width = 800, + S_CODEC_height = 600, + S_CODEC_framerate = 1, + S_CODEC_frame_rate_base = 1, + S_CODEC_gop_size = 4, + S_CODEC_max_b_frames + }; +public: + bool GetScreenSize(int &width, int &height); + bool Capture(XImage **image); + int EncodeProcess(XImage *image, uint8_t *pOutBuf, int nOutsize); + bool Init(enum CodecID nCodecID = CODEC_ID_MPEG4); + CSEncoder(); + virtual ~CSEncoder(); + void GetColorInfo(XImage *image, ColorInfo *ci /* return struct */); + +private: + void paintMousePointer(int *x, int *y, XImage *image); + void getCurrentPointer(int *x, int *y); + bool InitScreen(int width, int height); + + // for screen . +private: + XImage *m_image; + Display *m_display; + int m_screen_num; + Drawable m_d; + unsigned int m_width, m_height; + bool m_bInitScreen; + ColorInfo c_info; + int input_pixfmt; + ScreenHeader m_ScreenHeader; + +private: + bool m_bInit; + AVPicture m_pic_rgb; + uint8_t *m_pFrameBuf; + AVFrame *m_pFrame; + AVCodec *m_pCodec; + AVCodecContext *m_pCodecCtx; +}; + +//Screen decoder. +class CSDecoder +{ + friend class CScreenReceiver; +private: + enum VDECODERBUFSIZE + { + S_De_ExtraHeaderSize = 10000, S_De_INBUF_SIZE = 1024 + }; +public: + CSDecoder(); + virtual ~CSDecoder(); +public: + int DecodeProcess(uint8_t *encodeddata_v, const int encodeddatasize_v); + bool Init(int width, int height, enum CodecID nCodecID); + +public: + bool CreateXImage(Drawable parent, int x, int y, int width, int height); + void CloseXImage(); + +private: + void CloseCodec(); + bool ResetCodec(const int width, const int height); + //for ximage. + Drawable m_parent; + Display *m_display; + GC m_gc; + Window m_d; + + Window m_win; + XImage *m_image; + JMutex m_imagemutex; + CSEncoder m_encoder; + ColorInfo c_info; + int input_pixfmt; + +private: + bool m_bInit; + AVCodec *m_pCodec; + AVCodecContext *m_pCodecCtx; + AVFrame *m_pOutFrame; + AVPicture pic_rgb; + int m_width; + int m_height; + +}; + +//screen sender. +class CScreenSender: private JThread +{ +private: + enum SCREENSENDBUFSIZE + { + SendBufSize = 2 + }; +public: + CScreenSender(); + ~CScreenSender(); + bool Init(int nPort); + bool AddDestination(const RTPIPv4Address &des); + void ClearDestinations(); + int Start(char* szFile = 0, bool bIsRecord = false); + void Stop(); + void Record(bool bInRecord = true); +private: + void *Thread(); + bool stop; + JMutex stopmutex; +private: + bool m_bIsRecord; + JMutex m_recordmutex; + + CSEncoder m_sencoder; + uint8_t *m_pOutBuf; + FILE* m_hFile; + CSendThread m_sendthread; + int m_bInit; +}; + +//screen receiver + +class CScreenReceiver: public CFECRtpSession +{ +public: + CScreenReceiver(); + virtual ~CScreenReceiver(); + + bool Init(); + int Start(int nPort); + void Stop(); + +public: + bool CreateXImage(Drawable parent, int x, int y, int width, int height); + void CloseXImage(); + +private: + virtual void ProcessFrame(unsigned char* framedata, int framelen); + +private: + bool m_ScreenInit; + bool m_bInit; + CSDecoder m_sdecoder; +public: + ScreenHeader* pScreen; +}; + +#endif // !defined(_EN_DE_SCREEN_H__INCLUDED_) Added: incubator/bluesky/trunk/RealClass/Student-1.0/src/en_de_sendthread.cpp URL: http://svn.apache.org/viewvc/incubator/bluesky/trunk/RealClass/Student-1.0/src/en_de_sendthread.cpp?rev=819898&view=auto ============================================================================== --- incubator/bluesky/trunk/RealClass/Student-1.0/src/en_de_sendthread.cpp (added) +++ incubator/bluesky/trunk/RealClass/Student-1.0/src/en_de_sendthread.cpp Tue Sep 29 12:17:17 2009 @@ -0,0 +1,231 @@ +#include "en_de_sendthread.h" + +extern void PErrorText(const char* error); +//CSendThread class. + +CSendThread::CSendThread(int nSendBufSize) +{ + stop = false; + m_bInit = 0; + + if (nSendBufSize <= 2) + { + m_nSendBufSize = 2; + } + else if (nSendBufSize >= 25) + { + m_nSendBufSize = 25; + } + else + m_nSendBufSize = nSendBufSize; + +} + +CSendThread::~CSendThread() +{ + Stop(); + +} + +#define MAX_PACKET_SIZE 10*1024 +bool CSendThread::Init(int nPort) +{ + if (m_bInit) + return true; + + //init rtpsession. + RTPSessionParams sessParams1; + sessParams1.SetOwnTimestampUnit(1.0 / 30.0); //30 video frames per second + sessParams1.SetUsePollThread(0); //background thread to call virtual callbacks - set by default, but just to be sure + sessParams1.SetMaximumPacketSize(MAX_PACKET_SIZE); + //setup transmission parameters + RTPUDPv4TransmissionParams transParams1; + transParams1.SetPortbase(nPort); + //CREATE THE SESSION + int status1 = m_fecrtpsession.Create(sessParams1, &transParams1); + if (status1) + { + return false; //unable to create the session + } + + //must set for fec SendFECPacket. + m_fecrtpsession.SetDefaultMark(true); + m_fecrtpsession.SetDefaultPayloadType(1); + m_fecrtpsession.SetDefaultTimestampIncrement(0); + + m_bInit = true; + return m_bInit; +} + +int CSendThread::Start() +{ + if (!m_bInit) + return -1; + + if (JThread::IsRunning()) + return 0; + + if (!stopmutex.IsInitialized()) + { + if (stopmutex.Init() < 0) + return -2; + } + + stop = false; + + if (!m_senddatamutex.IsInitialized()) + { + if (m_senddatamutex.Init() < 0) + return -2; + } + + if (JThread::Start() < 0) + { + return -6; + } + + return 0; +} + +void CSendThread::Stop() +{ + if (!IsRunning()) + return; + + stopmutex.Lock(); + stop = true; + stopmutex.Unlock(); + + //wait for two minute; + sleep(1); + if (JThread::IsRunning()) + { + JThread::Kill(); + } + stop = false; + +} + +int CSendThread::SendData(uint8_t *data, int datalen) +{ + SENDBUFDATA *pData; + if (!m_bInit) + return -1; + + pData = new SENDBUFDATA; + if (pData == 0) + { + PErrorText("Error: CSendThread::SendData new SENDBUFDATA"); + return -2; + } + + pData->data = new uint8_t[datalen]; + if (pData->data == 0) + { + delete pData; + PErrorText("Error: CSendThread::SendData new uint8_t"); + return -3; + } + + memcpy(pData->data, data, datalen); + pData->datalen = datalen; + + m_senddatamutex.Lock(); + m_senddata.insert(m_senddata.end(), pData); + m_senddatamutex.Unlock(); + + return 0; +} + +void *CSendThread::Thread() +{ + JThread::ThreadStarted(); + + SENDBUFDATA *senddata = new SENDBUFDATA[m_nSendBufSize]; + bool stopthread; + + stopmutex.Lock(); + stopthread = stop; + stopmutex.Unlock(); + + int size; + SENDBUFDATA* p; + SendDatalist::iterator itera; + int index; + while (!stopthread) + { + + m_senddatamutex.Lock(); + size = m_senddata.size(); + if (size == 0) + { + m_senddatamutex.Unlock(); + + usleep(50000); + + stopmutex.Lock(); + stopthread = stop; + stopmutex.Unlock(); + continue; + } + if (size > m_nSendBufSize) + { + for (itera = m_senddata.begin(); itera != m_senddata.end(); itera++) + { + p = *itera; + delete p->data; + delete p; + p = 0; + } + m_senddata.clear(); + size = 0; + } + else + { + for (itera = m_senddata.begin(), index = 0; itera + != m_senddata.end(); itera++, index++) + { + p = *itera; + senddata[index].data = p->data; + senddata[index].datalen = p->datalen; + delete p; + p = 0; + } + m_senddata.clear(); + size = index; + } + + m_senddatamutex.Unlock(); + + for (index = 0; index < size; index++) + { + m_fecrtpsession.SendFECPacket(senddata[index].data, + senddata[index].datalen, 5000); + delete senddata[index].data; + } + + stopmutex.Lock(); + stopthread = stop; + stopmutex.Unlock(); + + } + printf("\nSendthread stoped.\n"); + return 0; +} + +bool CSendThread::AddDestination(const RTPIPv4Address &des) +{ + if (!m_bInit) + return false; + if (m_fecrtpsession.AddDestination(des) < 0) + return false; + + return true; +} + +void CSendThread::ClearDestinations() +{ + if (!m_bInit) + return; + m_fecrtpsession.ClearDestinations(); +} Added: incubator/bluesky/trunk/RealClass/Student-1.0/src/en_de_sendthread.h URL: http://svn.apache.org/viewvc/incubator/bluesky/trunk/RealClass/Student-1.0/src/en_de_sendthread.h?rev=819898&view=auto ============================================================================== --- incubator/bluesky/trunk/RealClass/Student-1.0/src/en_de_sendthread.h (added) +++ incubator/bluesky/trunk/RealClass/Student-1.0/src/en_de_sendthread.h Tue Sep 29 12:17:17 2009 @@ -0,0 +1,63 @@ + +// rtp +#include "fecrtpsession.h" +// Linux sys. +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +// FFmpeg +#include +#include + +#include + +// X11 +#include +#include +// Jthread and JMutex +#include +#include + +#if !defined(_EN_DE_SENDTHREAD_H__INCLUDED_) +#define _EN_DE_SENDTHREAD_H__INCLUDED_ + +struct SENDBUFDATA +{ + uint8_t* data; + int datalen; +}; +typedef std::list SendDatalist; + +//CSendThread class. +class CSendThread: private JThread +{ +public: + CSendThread(int nSendBufSize); + ~CSendThread(); + bool Init(int nPort); + bool AddDestination(const RTPIPv4Address &des); + void ClearDestinations(); + int SendData(uint8_t *data, int datalen); + int Start(); + void Stop(); +private: + void *Thread(); + bool stop; + JMutex stopmutex; +private: + CFECRtpSession m_fecrtpsession; + int m_bInit; + + int m_nSendBufSize; + SendDatalist m_senddata; + JMutex m_senddatamutex; +}; + +#endif // !defined(_EN_DE_SENDTHREAD_H__INCLUDED_)