You are viewing a plain text version of this content. The canonical link for it is here.
Posted to bluesky-commits@incubator.apache.org by pi...@apache.org on 2009/11/30 12:01:26 UTC
svn commit: r885392 [23/25] - in /incubator/bluesky/trunk/RealClass:
Student/src/ Teacher/ Teacher/autom4te.cache/ Teacher/src/
Teacher/src/.deps/ Teacher/src/pic/
Added: incubator/bluesky/trunk/RealClass/Teacher/src/en_de_video.cpp
URL: http://svn.apache.org/viewvc/incubator/bluesky/trunk/RealClass/Teacher/src/en_de_video.cpp?rev=885392&view=auto
==============================================================================
--- incubator/bluesky/trunk/RealClass/Teacher/src/en_de_video.cpp (added)
+++ incubator/bluesky/trunk/RealClass/Teacher/src/en_de_video.cpp Mon Nov 30 12:01:23 2009
@@ -0,0 +1,1904 @@
+/** \file en_de_video.cpp Implementation for video operation:capture,encoder,decoder,sender,receiver
+*
+*
+*Licensed to the Apache Software Foundation (ASF) under one
+*or more contributor license agreements. See the NOTICE file
+*distributed with this work for additional information
+*regarding copyright ownership. The ASF licenses this file
+*to you under the Apache License, Version 2.0 (the
+*"License"); you may not use this file except in compliance
+*with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+*Unless required by applicable law or agreed to in writing,
+*software distributed under the License is distributed on an
+*"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+*KIND, either express or implied. See the License for the
+*specific language governing permissions and limitations
+*under the License.
+*/
+
+//V4l classes.
+#include <deque>
+#include <unistd.h>
+#include <string>
+#include <sstream>
+#include <iostream>
+#include <iomanip>
+
+#include <pthread.h>
+
+#include <gtk/gtk.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include "en_de_video.h"
+static char g_error_txt[550];
+void PErrorText(const char* error)
+{
+ if (strlen(error) <= 500)
+ {
+ sprintf(g_error_txt, "\nEn_De Error:%s", error);
+ }
+}
+//extern int v4l_dev_num = 0;
+//extern int delay_time = 0;
+
+extern "C"
+{
+#include <sys/types.h>
+#include <sys/soundcard.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+}
+
+V4L::V4L()
+{
+
+}
+
+V4L::~V4L()
+{
+ if (fd != -1)
+ {
+ close( fd);
+
+ delete this->capability;
+ }
+}
+void V4L::setInfo(char *device, char *input, int sample)
+{
+ this->device = device;
+ this->input = input;
+ this->sample = sample;
+}
+
+bool V4L::openDevice()
+{
+ bool ret = true;
+
+ if (!strcmp(this->input, "PAL"))
+ {
+ this->width = VideoWidth;
+ this->height = VideoHeight;
+ this->fps = 25;
+ }
+ else if (!strcmp(this->input, "NTSC"))
+ {
+ this->width = 720;
+ this->height = 480;
+ this->fps = 30;
+ }
+
+ this->fd = open(device, O_RDWR);
+ if (fd == -1)
+ {
+ perror("Unable to open video device");
+ return false;
+ }
+
+ {
+ video_capability capability;
+ if (ioctl(fd, VIDIOCGCAP, &capability) != -1)
+ {
+ printf(" query was successful\n");
+ }
+ else
+ {
+ perror("query");
+ }
+
+ if ((capability.type & VID_TYPE_CAPTURE) != 0)
+ {
+ printf("this device can capture video to memory\n");
+ }
+ else
+ {
+ perror("can't capture video to memtory");
+ }
+
+ struct video_channel queryChannel;
+ int i = 0;
+ while (i < capability.channels)
+ {
+ queryChannel.channel = i;
+ if (ioctl(fd, VIDIOCGCHAN, &queryChannel) != -1)
+ { // ioctl success, queryChannel contains information about this channel
+ printf(" information about this channel:%d, %s\n",
+ queryChannel.channel, queryChannel.name);
+ }
+
+ ++i;
+ }
+
+ struct video_channel selectedChannel;
+ selectedChannel.channel = 0;
+ selectedChannel.norm = VIDEO_MODE_PAL;
+ if (ioctl(fd, VIDIOCSCHAN, &selectedChannel) == -1)
+ {
+ return false;
+ }
+
+ struct video_window captureWindow;
+ memset(&captureWindow, 0, sizeof(captureWindow));
+ captureWindow.width = VideoWidth;
+ captureWindow.height = VideoHeight;
+
+ memset(&captureWindow, 0, sizeof(captureWindow));
+ if (ioctl(fd, VIDIOCGWIN, &captureWindow) == -1)
+ {
+ return false;
+ }
+
+ width = captureWindow.width;
+ height = captureWindow.height;
+ printf("width=%d,height=%d\n", width, height);
+
+ }
+
+ int depth;
+ int palette;
+ struct video_picture imageProperties;
+
+ if (ioctl(fd, VIDIOCGPICT, &imageProperties) == -1)
+ { // failed to retrieve default image properties
+ return false;
+ }
+ depth = imageProperties.depth;
+ palette = imageProperties.palette;
+ printf("\nVideo:depth=%d,palette=%d\n", depth, palette);
+ if (ioctl(fd, VIDIOCSPICT, &imageProperties) == -1)
+ { // failed to retrieve default image properties
+ return false;
+ }
+
+ return ret;
+}
+
+
+int V4L::getWidth()
+{
+ return width;
+}
+
+int V4L::getHeight()
+{
+ return height;
+}
+
+int V4L::mappedMemorySize(bool init)
+{
+ static video_mbuf buf;
+ if (init == true)
+ {
+ init = 1;
+ ioctl(fd, VIDIOCGMBUF, &buf);
+ frame_maps = buf.frames;
+ }
+ return buf.size;
+}
+
+bool V4L::initialiseCapture(int format)
+{
+ map = mmap(0, mappedMemorySize(true), PROT_READ | PROT_WRITE, MAP_SHARED,
+ fd, 0);
+
+ if (map != NULL)
+ {
+ for (int i = 0; i < frame_maps; i++)
+ {
+ frame[i].frame = i;
+ frame[i].width = getWidth();
+ frame[i].height = getHeight();
+ frame[i].format = format;
+ }
+ frames = 0;
+ frame_next = 0;
+
+ int retry = 0;
+ while (ioctl(fd, VIDIOCMCAPTURE, &frame[0]) == -1 && retry++
+ < frame_maps + 1)
+ ;
+
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+void *V4L::getNextFrame()
+{
+ unsigned char * ret = NULL;
+
+ int current = frame_next;
+ frame_next = (frame_next + 1) % frame_maps;
+
+ if (ioctl(fd, VIDIOCMCAPTURE, &frame[frame_next]) == -1)
+ ; //cout << "Frame 1 Failed to initialise" << endl;
+ if (ioctl(fd, VIDIOCSYNC, &frame[current].frame) == -1)
+ ; //cout << "Frame 0 Failed to sync" << endl;
+ ret = (unsigned char *) map + current * (mappedMemorySize() / frame_maps);
+
+ frames++;
+
+ return (void *) ret;
+}
+
+
+int CVDecoder::input_pixfmt = PIX_FMT_RGBA32;
+
+#define STARTTIME { static int MaxTime=0; \
+ static int MinTime=1000; \
+ static int largecount=0; \
+ int IntervalTime=0; \
+ int64_t start_time=av_gettime();
+
+#define ENDTIME IntervalTime = av_gettime()-start_time; \
+ if(IntervalTime>40000) \
+ largecount++; \
+ if(MaxTime<IntervalTime) \
+ MaxTime=IntervalTime; \
+ if(MinTime>IntervalTime) \
+ MinTime=IntervalTime; \
+ printf("\nMaxTime=%d, MinTime=%d, largecount=%d, IntervalTime=%d\n", MaxTime, MinTime, largecount, IntervalTime);}
+
+//CVDecoder class.
+
+CVDecoder::CVDecoder()
+{
+ m_pCodec = 0;
+ m_pCodecCtx = 0;
+ m_pOutFrame = 0;
+ m_bInit = false;
+
+ m_display = 0;
+ m_win = 0;
+ m_image = 0;
+
+}
+
+CVDecoder::~CVDecoder()
+{
+ 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;
+ }
+
+ 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;
+ }
+
+}
+void CVDecoder::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;
+
+ 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;
+ }
+}
+
+bool CVDecoder::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;
+ Pixmap pixmap;
+ 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/student.bmp", NULL) == NULL)
+ {
+ XSetWindowBackgroundPixmap(m_display, m_win, ParentRelative);
+ XMapWindow(m_display, m_win);
+ }
+ else
+ {
+ original_pixbuf = gdk_pixbuf_new_from_file("pic/student.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 = 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("XGetImage error\n");
+ m_imagemutex.Unlock();
+ return false;
+ }
+
+ m_imagemutex.Unlock();
+ return true;
+}
+
+void CVDecoder::CloseXImage()
+{
+ if (!m_bInit)
+ return;
+
+ m_imagemutex.Lock();
+
+ if (m_image)
+ {
+ XDestroyImage( 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();
+ return;
+}
+
+bool CVDecoder::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;
+
+ m_pCodec = avcodec_find_decoder(CODEC_ID_MPEG4);
+ if (!m_pCodec)
+ {
+ PErrorText("Codec not found\n");
+ 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
+ m_pCodecCtx->bit_rate = 512 * 1024;
+ // resolution must be a multiple of two
+ m_pCodecCtx->width = m_width;
+ m_pCodecCtx->height = m_height;
+ // frames per second
+ m_pCodecCtx->frame_rate = V_CODEC_framerate;
+ m_pCodecCtx->frame_rate_base = V_CODEC_frame_rate_base;
+ // emit one intra frame every ten frames
+ m_pCodecCtx->gop_size = V_CODEC_gop_size;
+
+ m_pCodecCtx->flags |= CODEC_FLAG_GLOBAL_HEADER;
+ m_pCodecCtx->extradata = malloc(V_De_ExtraHeaderSize);
+ if (m_pCodecCtx->extradata == 0)
+ {
+ return false;
+ }
+ m_pCodecCtx->extradata_size = V_De_ExtraHeaderSize;
+
+ 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 CVDecoder::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 * V_De_INBUF_SIZE >= V_De_INBUF_SIZE)
+ realsize = V_De_INBUF_SIZE;
+ else
+ realsize = encodeddatasize_v - i * V_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 * V_De_INBUF_SIZE + left), realsize);
+ if (len < 0)
+ {
+ PErrorText("Error while decoding");
+ m_imagemutex.Unlock();
+ return -2;
+ }
+
+ if (m_image != 0)
+ {
+
+ 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\n");
+ PErrorText("xtoffmpeg.XImageToFFMPEG(): color masks");
+ return false;
+ }
+ break;
+ case 32:
+ if (c_info.alpha_mask == 0xFF000000 && m_image->green_mask
+ == 0xFF00)
+ {
+
+ 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;
+ }
+ }
+
+ 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;
+}
+
+void CVDecoder::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 CVDecoder::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;
+
+ // put sample parameters
+ m_pCodecCtx->bit_rate = 512 * 1024;
+ // resolution must be a multiple of two
+ m_pCodecCtx->width = m_width;
+ m_pCodecCtx->height = m_height;
+ // frames per second
+ m_pCodecCtx->frame_rate = V_CODEC_framerate;
+ m_pCodecCtx->frame_rate_base = V_CODEC_frame_rate_base;
+ // emit one intra frame every ten frames
+ m_pCodecCtx->gop_size = V_CODEC_gop_size;
+
+ m_pCodecCtx->flags |= CODEC_FLAG_GLOBAL_HEADER;
+ m_pCodecCtx->extradata = malloc(V_De_ExtraHeaderSize);
+ if (m_pCodecCtx->extradata == 0)
+ {
+ return false;
+ }
+ m_pCodecCtx->extradata_size = V_De_ExtraHeaderSize;
+
+ 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;
+
+}
+
+#define MAX_PACKET_SIZE 10*1024
+//CVideoReceiver class.
+
+CVideoReceiver::CVideoReceiver()
+{
+ m_bInit = false;
+}
+
+CVideoReceiver::~CVideoReceiver()
+{
+
+}
+
+bool CVideoReceiver::Init()
+{
+ if (m_bInit)
+ return m_bInit;
+
+ if (!m_vdecoder.Init(320, 240, CODEC_ID_MPEG4))
+ {
+ return false;
+ }
+
+ m_bInit = true;
+ return m_bInit;
+
+}
+
+bool CVideoReceiver::CreateXImage(Drawable parent, int x, int y, int width,
+ int height)
+{
+ bool ret;
+ ret = m_vdecoder.CreateXImage(parent, x, y, width, height);
+
+ return ret;
+}
+
+void CVideoReceiver::CloseXImage()
+{
+ m_vdecoder.CloseXImage();
+}
+
+int CVideoReceiver::Start(int nHostPort)
+{
+ 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(nHostPort);
+ //CREATE THE SESSION
+ int status1 = Create(sessParams1, &transParams1);
+ if (status1)
+ {
+ // ReportError(status1);
+ return -2; //unable to create the session
+ }
+
+ return 0;
+}
+
+void CVideoReceiver::Stop()
+{
+ Destroy();
+}
+
+void CVideoReceiver::ProcessFrame(unsigned char* framedata, int framelen)
+{
+ pVideo = (VideoHeader*) framedata;
+ if (pVideo->width != m_vdecoder.m_width || pVideo->height
+ != m_vdecoder.m_height)
+ {
+ m_vdecoder.ResetCodec(pVideo->width, pVideo->height);
+ }
+ m_vdecoder.DecodeProcess(framedata + sizeof(VideoHeader), framelen
+ - sizeof(VideoHeader));
+}
+
+//CV4LVEncoder class.
+
+CV4LVEncoder::CV4LVEncoder()
+{
+ m_pFrameBuf = 0;
+ m_pFrame = 0;
+ m_pCodec = 0;
+ m_pCodecCtx = 0;
+ m_bInit = false;
+}
+
+CV4LVEncoder::~CV4LVEncoder()
+{
+
+ 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;
+ }
+ m_bInit = false;
+
+}
+
+bool CV4LVEncoder::Init(int width, int height, enum CodecID nCodecID /*=CODEC_ID_MPEG4*/)
+{
+ m_bInit = false;
+ /*Init for encode*/
+ avcodec_init();
+ avcodec_register_all();
+
+ //new a frame object.
+ if (m_pFrame)
+ {
+ free( m_pFrame);
+ m_pFrame = 0;
+ }
+ m_pFrame = avcodec_alloc_frame();
+ if (m_pFrame == 0)
+ {
+ return false;
+ }
+
+ /* find the video encoder */
+ m_pCodec = avcodec_find_encoder(nCodecID);
+ if (!m_pCodec)
+ {
+ PErrorText("codec not found");
+
+ printf("\ncodec not found\n");
+ 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 = width;
+ m_pCodecCtx->height = height;
+ /* frames per second */
+ m_pCodecCtx->frame_rate = V_CODEC_framerate;
+ m_pCodecCtx->frame_rate_base = V_CODEC_frame_rate_base;
+
+ m_pCodecCtx->bit_rate = 512 * 1024; //1128kbps->512kbps
+ m_pCodecCtx->gop_size = V_CODEC_gop_size; /* emit one intra frame every ten frames */
+ m_pCodecCtx->codec_type = CODEC_TYPE_VIDEO;
+ m_pCodecCtx->pix_fmt = PIX_FMT_YUV420P;
+
+ /* open it */
+ if (avcodec_open(m_pCodecCtx, m_pCodec) < 0)
+ {
+ PErrorText("could not open codec");
+ return false;
+ }
+
+ //malloc outbuf.
+ 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 CV4LVEncoder::EncodeProcess(char *frameaddress, uint8_t *pOutBuf,
+ int nOutsize)
+{
+
+ if (!m_bInit)
+ return -1;
+
+ if (nOutsize < V_En_OutBufSize)
+ {
+ return -2;
+ }
+
+ avpicture_fill(&m_pic_rgb, (uint8_t *) frameaddress, PIX_FMT_BGR24,
+ 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,
+ PIX_FMT_BGR24, m_pCodecCtx->width, m_pCodecCtx->height) < 0)
+ {
+ fprintf(
+ stderr,
+ "xtoffmpeg.XImageToFFMPEG(): pixel format conversion not handled ... aborting\n");
+ return -3;
+ }
+
+ m_VideoHeader.width = m_pCodecCtx->width;
+ m_VideoHeader.height = m_pCodecCtx->height;
+ memcpy((char *) pOutBuf, &m_VideoHeader, sizeof(VideoHeader));
+
+ int iii = avcodec_encode_video(m_pCodecCtx, pOutBuf + sizeof(VideoHeader),
+ nOutsize, m_pFrame);
+
+ if (iii <= 0)
+ return -4;
+
+ return iii + sizeof(VideoHeader);
+}
+
+bool CV4LVEncoder::GetCapSize(int &width, int &height)
+{
+ if (!m_bInit)
+ return false;
+
+ width = m_pCodecCtx->width;
+ height = m_pCodecCtx->height;
+
+ return true;
+}
+
+void CV4LVEncoder::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;
+
+ 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;
+ }
+}
+
+//CV4LVideoSender class.
+
+CV4LVideoSender::CV4LVideoSender() :
+ m_sendthread(SendBufSize)
+{
+ stop = false;
+ m_bIsRecord = false;
+ m_bInit = 0;
+
+ m_pOutBuf = 0;
+ m_hFile = 0;
+ m_mode = ModeNone;
+ m_pV4Ldev = 0;
+
+ if (!m_initmutex.IsInitialized())
+ {
+ m_initmutex.Init();
+ }
+
+ m_display = 0;
+ m_win = 0;
+ m_d = 0;
+ m_image = 0;
+
+}
+
+CV4LVideoSender::~CV4LVideoSender()
+{
+ //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);
+ m_pOutBuf = 0;
+ }
+
+ // for image
+ if (m_image)
+ {
+ XDestroyImage( 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;
+ }
+
+ CloseVideo();
+}
+
+bool CV4LVideoSender::Init(int nHostPort)
+{
+ m_initmutex.Lock();
+ m_bInit = false;
+
+ if (!m_imagemutex.IsInitialized())
+ {
+ if (m_imagemutex.Init() < 0)
+ {
+ m_initmutex.Unlock();
+ return false;
+ }
+ }
+
+ if (!OpenVideo())
+ {
+ m_initmutex.Unlock();
+ return false;
+ }
+
+ if (!m_sendthread.Init(nHostPort))
+ {
+
+ m_initmutex.Unlock();
+ return false;
+ }
+
+ if (m_pOutBuf == 0)
+ {
+ m_pOutBuf = (uint8_t*) malloc(CV4LVEncoder::V_En_OutBufSize);
+ if (m_pOutBuf == 0)
+ {
+ m_initmutex.Unlock();
+ return false;
+ }
+
+ }
+
+ //Init sencoder.
+ if (!m_vencoder.Init(VideoWidth, VideoHeight, CODEC_ID_MPEG4))
+ {
+ m_initmutex.Unlock();
+ return false;
+ }
+
+ if (!m_modemutex.IsInitialized())
+ {
+ if (m_modemutex.Init() < 0)
+ {
+ m_initmutex.Unlock();
+ return false;
+ }
+
+ }
+
+ m_bIsRecord = false;
+
+ m_bInit = true;
+ m_initmutex.Unlock();
+ return true;
+}
+
+bool CV4LVideoSender::OpenVideo()
+{
+ CloseVideo();
+
+ m_pV4Ldev = new V4L();
+
+ if (m_pV4Ldev == 0)
+ return false;
+
+ char dev_name[20] = "/dev/video";
+ char temp_count[3] = "\0";
+
+ strcpy(dev_name, "/dev/video");
+// sprintf(temp_count, "%d", v4l_dev_num);
+// strcat(dev_name, temp_count);
+
+ m_pV4Ldev->setInfo(dev_name, "PAL", 0); //dev/video
+
+ printf("CV4LVideoSender::OpenVideo(): dev_name = %s\n", dev_name);
+
+ if (!m_pV4Ldev->openDevice())
+ {
+ return false;
+ }
+
+ if (!m_pV4Ldev->initialiseCapture(VIDEO_PALETTE_RGB24))
+ {
+ return false;
+ }
+
+ return true;
+}
+
+void CV4LVideoSender::CloseVideo()
+{
+ if (m_pV4Ldev != 0)
+ {
+ delete m_pV4Ldev;
+ m_pV4Ldev = 0;
+ }
+}
+
+bool CV4LVideoSender::IsInitialized()
+{
+ bool b;
+
+ m_initmutex.Lock();
+ b = m_bInit;
+ m_initmutex.Unlock();
+
+ return b;
+}
+
+bool CV4LVideoSender::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/teacher.bmp", NULL) == NULL)
+ {
+ XSetWindowBackgroundPixmap(m_display, m_win, ParentRelative);
+ XMapWindow(m_display, m_win);
+ }
+ else
+ {
+ original_pixbuf = gdk_pixbuf_new_from_file("pic/teacher.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);
+ }
+ int imagewidth, imageheight;
+ m_vencoder.GetCapSize(imagewidth, imageheight);
+
+ m_image = XGetImage(m_display, m_d, 0, 0, imagewidth, imageheight,
+ AllPlanes, ZPixmap);
+ if (!m_image)
+ {
+ PErrorText("GetImage error");
+ m_imagemutex.Unlock();
+ return false;
+ }
+
+ m_imagemutex.Unlock();
+ return true;
+}
+
+void CV4LVideoSender::CloseXImage()
+{
+
+ if (!IsInitialized())
+ return;
+
+ m_imagemutex.Lock();
+
+ if (m_image)
+ {
+ XDestroyImage( 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 CV4LVideoSender::Playback(uint8_t* videodata)
+{
+ AVPicture pic_rgb24, pic_rgb32;
+ int width, height;
+
+ if (!IsInitialized())
+ return;
+
+ m_vencoder.GetCapSize(width, height);
+
+ m_imagemutex.Lock();
+ if (m_display && m_image && m_win)
+ {
+
+ avpicture_fill(&pic_rgb32, (uint8_t*) m_image->data,
+ CVDecoder::input_pixfmt, width, height);
+ avpicture_fill(&pic_rgb24, videodata, PIX_FMT_BGR24, width, height);
+
+ if (img_convert(&pic_rgb32, CVDecoder::input_pixfmt, &pic_rgb24,
+ PIX_FMT_BGR24, width, height) < 0)
+ {
+ PErrorText("Error pixel format conversion");
+ m_imagemutex.Unlock();
+ return;
+ }
+
+ XPutImage(m_display, m_win, m_gc, m_image, 0, 0, 0, 0, width, height);
+ }
+
+ m_imagemutex.Unlock();
+ return;
+}
+
+int CV4LVideoSender::Start(char* szFile /* =0 */, bool bIsRecord /* =false */)
+{
+
+ if (!IsInitialized())
+ 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 (szFile != 0)
+ {
+ if (m_hFile)
+ {
+ fclose( m_hFile);
+ m_hFile = 0;
+ }
+
+ m_hFile = fopen(szFile, "wb");
+ if (m_hFile == 0)
+ {
+ m_bIsRecord = false;
+ return -3;
+ }
+
+ }
+
+ if (m_sendthread.Start() < 0)
+ {
+ return -6;
+ }
+
+ if (JThread::Start() < 0)
+ {
+ m_bIsRecord = false;
+ return -6;
+ }
+
+ return 0;
+}
+
+void CV4LVideoSender::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_sendthread.Stop();
+
+ m_bIsRecord = false;
+}
+
+void CV4LVideoSender::SetMode(V4LVIDEO_SEND_MODE mode)
+{
+
+ if (!IsInitialized())
+ return;
+
+ if (mode == ModeCapture || mode == ModeTransmit || mode == ModeNone)
+ {
+
+ m_modemutex.Lock();
+ m_mode = mode;
+ m_modemutex.Unlock();
+ }
+
+}
+
+void CV4LVideoSender::Record(bool bInRecord /* =true */)
+{
+
+ if (!IsInitialized())
+ return;
+
+ m_recordmutex.Lock();
+ m_bIsRecord = bInRecord;
+ m_recordmutex.Unlock();
+
+}
+
+void *CV4LVideoSender::Thread()
+{
+ char * data;
+ int OutBufSzie;
+ int status;
+
+ JThread::ThreadStarted();
+
+ bool stopthread;
+ V4LVIDEO_SEND_MODE mode;
+
+ stopmutex.Lock();
+ stopthread = stop;
+ stopmutex.Unlock();
+
+ bool isrecord;
+ m_recordmutex.Lock();
+ isrecord = m_bIsRecord;
+ m_recordmutex.Unlock();
+
+ int64_t pre_time, cur_time;
+ useconds_t delay, delay1;
+ pre_time = av_gettime();
+ if (m_vencoder.m_pCodecCtx->frame_rate != 0)
+ {
+ if (m_vencoder.m_pCodecCtx->frame_rate_base != 0)
+ delay1 = 1000000 * m_vencoder.m_pCodecCtx->frame_rate_base
+ / m_vencoder.m_pCodecCtx->frame_rate;
+ else
+ delay1 = 1000000 / m_vencoder.m_pCodecCtx->frame_rate;
+ }
+ else
+ {
+ delay1 = 62500;
+ }
+
+/* if (delay_time > 0)
+ {
+ sleep( delay_time);
+ }
+*/
+ // for utility rate of CPU
+ cur_time = pre_time = av_gettime();
+ pre_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();
+
+ m_modemutex.Lock();
+ mode = m_mode;
+ m_modemutex.Unlock();
+
+ if (mode == ModeNone)
+ {
+ stopmutex.Lock();
+ stopthread = stop;
+ stopmutex.Unlock();
+
+ rec_start = cur_time = av_gettime();
+ nFrame = 0;
+ cur_time = av_gettime();
+ continue;
+ }
+
+ if ((status = Capture((uint8_t**) &data)) < 0)
+ {
+ printf("\nvideo: capture vital error.");
+ stopthread = true;
+ continue;
+ }
+ else
+ {
+ if (mode == ModeCapture || mode == ModeTransmit)
+ {
+ Playback((uint8_t*) data);
+ if (mode == ModeCapture)
+ {
+ stopmutex.Lock();
+ stopthread = stop;
+ stopmutex.Unlock();
+
+ rec_start = cur_time = av_gettime();
+ nFrame = 0;
+ cur_time = av_gettime();
+ continue;
+ }
+ }
+
+ OutBufSzie = CV4LVEncoder::V_En_OutBufSize;
+ if ((status = m_vencoder.EncodeProcess(data, m_pOutBuf, OutBufSzie))
+ < 0)
+ {
+ printf("\nvideo: encode vital error.");
+ stopthread = true;
+ continue;
+ }
+ else
+ {
+ if (status > 0 && mode == ModeTransmit)
+ {
+ m_sendthread.SendData(m_pOutBuf, status);
+
+ if (m_hFile != 0 && isrecord)
+ {
+ nFrame++;
+ fwrite(m_pOutBuf + sizeof(VideoHeader), status
+ - sizeof(VideoHeader), 1, m_hFile);
+
+ rec_time = av_gettime() - rec_start;
+ int i;
+ for (i = 0; rec_time > nFrame * delay1; nFrame++, i++)
+ {
+ if ((status = m_vencoder.EncodeProcess(data,
+ m_pOutBuf, OutBufSzie)) < 0)
+ {
+ printf("\nvideo: encode vital error.");
+ stopthread = true;
+ printf(
+ "\nvideo capture thread stoped by EncodeProcess error!\n");
+ return 0;
+ }
+ if (status > 0)
+ {
+ fwrite(m_pOutBuf + sizeof(VideoHeader), status
+ - sizeof(VideoHeader), 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("\nvideo capture thread stoped.\n");
+ return 0;
+}
+
+bool CV4LVideoSender::AddDestination(const RTPIPv4Address &des)
+{
+
+ if (!IsInitialized())
+ return false;
+
+ if (m_sendthread.AddDestination(des) < 0)
+ return false;
+
+ return true;
+}
+
+void CV4LVideoSender::ClearDestinations()
+{
+
+ if (!IsInitialized())
+ return;
+
+ m_sendthread.ClearDestinations();
+}
+
+int CV4LVideoSender::Capture(uint8_t** data)
+{
+ *data = (uint8_t*) m_pV4Ldev->getNextFrame();
+ return 0;
+}
+
Added: incubator/bluesky/trunk/RealClass/Teacher/src/en_de_video.h
URL: http://svn.apache.org/viewvc/incubator/bluesky/trunk/RealClass/Teacher/src/en_de_video.h?rev=885392&view=auto
==============================================================================
--- incubator/bluesky/trunk/RealClass/Teacher/src/en_de_video.h (added)
+++ incubator/bluesky/trunk/RealClass/Teacher/src/en_de_video.h Mon Nov 30 12:01:23 2009
@@ -0,0 +1,331 @@
+
+/** \file en_de_video.h Classes for video operation:capture,encoder,decoder,sender,receiver
+*
+*
+*Licensed to the Apache Software Foundation (ASF) under one
+*or more contributor license agreements. See the NOTICE file
+*distributed with this work for additional information
+*regarding copyright ownership. The ASF licenses this file
+*to you under the Apache License, Version 2.0 (the
+*"License"); you may not use this file except in compliance
+*with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+*Unless required by applicable law or agreed to in writing,
+*software distributed under the License is distributed on an
+*"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+*KIND, either express or implied. See the License for the
+*specific language governing permissions and limitations
+*under the License.
+*/
+
+#include "fecrtpsession.h"
+
+#include <vector>
+#include <deque>
+using std::vector;
+using std::deque;
+
+#include <string>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <time.h>
+#include <sys/time.h>
+#include <iostream>
+#include <stdlib.h>
+
+#define _DEVICE_H_
+#define _LINUX_TIME_H
+
+#include <linux/videodev.h>
+#include <linux/types.h>
+
+// FFmpeg
+#include <ffmpeg/avcodec.h>
+#include <ffmpeg/avformat.h>
+
+// X11
+#include <X11/Intrinsic.h>
+#include <X11/XWDFile.h>
+// Jthread and JMutex
+#include <jthread.h>
+#include <jmutex.h>
+
+#include "en_de_sendthread.h"
+#include "en_de_screen.h"
+
+#if !defined(_EN_DE_VIDEO_H__INCLUDED_)
+#define _EN_DE_VIDEO_H__INCLUDED_
+
+
+//!Video capture
+class V4L
+{
+
+private:
+ //!V4L params
+ enum V4LPARA
+ {
+ VideoWidth = 320, VideoHeight = 240
+ };
+
+private:
+ //!file descriptor
+ int fd;
+ //!Video width
+ int width;
+ //!Video height
+ int height;
+ //!map memory
+ void *map;
+ //!video_mmap struct
+ struct video_mmap frame[32];
+ //!frame stored in maps memory
+ int frame_maps;
+ //!next frame
+ int frame_next;
+ //!number of frames
+ int frames;
+ //!/dev/video0
+ char *device;
+ //!PAL
+ char *input;
+ //!samples per second
+ int sample;
+ //!frames per second
+ int fps;
+public:
+ //!V4LCapability Instance
+ struct video_capability *capability;
+ //!Constuctor
+ V4L();
+ //!Destructor
+ virtual ~V4L();
+ //!Set capture information
+ /*!
+ \param device video device name
+ \param input NTSC or PAL
+ \param sample sample rate for capture
+ */
+ void setInfo(char *device, char *input, int sample);
+ //!Open audio device
+ bool openDevice();
+ //!get Video Width
+ int getWidth();
+ //!get Video Height
+ int getHeight();
+ //!initialise Capture
+ bool initialiseCapture(int format);
+ //!get Next Frame
+ void *getNextFrame();
+ //!get mapped Memory Size
+ int mappedMemorySize(bool init = false);
+};
+//!Video Header Information
+/*!
+\param width video width
+\param height video height
+*/
+typedef struct VideoHeader
+{
+ int width;
+ int height;
+} VideoHeader;
+
+
+
+//Video decoder.
+class CVDecoder
+{
+ friend class CVideoReceiver;
+private:
+ enum VDECODERBUFSIZE
+ {
+ V_De_ExtraHeaderSize = 10000,
+ V_De_SDLBufSize = 512 * 1024,
+ V_De_INBUF_SIZE = 1024
+ };
+ enum VIDEO_CODEC_PARA
+ {
+ V_CODEC_width = 320,
+ V_CODEC_height = 240,
+ V_CODEC_framerate = 16,
+ V_CODEC_frame_rate_base = 1,
+ V_CODEC_gop_size = 12,
+ V_CODEC_max_b_frames = 1
+ };
+public:
+ CVDecoder();
+ virtual ~CVDecoder();
+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();
+ void GetColorInfo(XImage *image, ColorInfo *ci /* return struct */);
+
+private:
+
+ void CloseCodec();
+ bool ResetCodec(const int width, const int height);
+ bool m_bInit;
+ AVCodec *m_pCodec;
+ AVCodecContext *m_pCodecCtx;
+ AVFrame *m_pOutFrame;
+ AVPicture pic_rgb;
+ int m_width;
+ int m_height;
+ Display *m_display;
+ GC m_gc;
+ Window m_d;
+ XSetWindowAttributes win_attr;
+ Window m_win;
+ XImage *m_image;
+ JMutex m_imagemutex;
+ ColorInfo c_info;
+public:
+ static int input_pixfmt;
+
+};
+
+//video receiver
+
+class CVideoReceiver: public CFECRtpSession
+{
+public:
+ VideoHeader* pVideo;
+ CVideoReceiver();
+ virtual ~CVideoReceiver();
+
+ bool Init();
+ int Start(int nHostPort);
+ 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_bInit;
+ CVDecoder m_vdecoder;
+};
+
+// V4L Video encoder.
+class CV4LVEncoder
+{
+
+ friend class CV4LVideoSender;
+ friend class CV4LStuVideoSender;
+
+private:
+ enum V4L_VENCODE_BUFSIZE
+ {
+ V_En_OutBufSize = 400 * 1024
+ };
+ enum V4L_VIDEO_CODEC_PARA
+ {
+ V_CODEC_framerate = 16,
+ V_CODEC_frame_rate_base = 1,
+ V_CODEC_gop_size = 12,
+ V_CODEC_max_b_frames = 1
+ };
+public:
+ bool GetCapSize(int &width, int &height);
+ int EncodeProcess(char * frameaddress, uint8_t * pOutBuf, int nOutsize);
+ bool Init(int width, int height, enum CodecID nCodecID = CODEC_ID_MPEG4);
+ CV4LVEncoder();
+ virtual ~CV4LVEncoder();
+ void GetColorInfo(XImage *image, ColorInfo *ci);
+
+private:
+ bool m_bInit;
+
+ //for avcodec
+ AVPicture m_pic_rgb;
+ uint8_t *m_pFrameBuf;
+ AVFrame *m_pFrame;
+ AVCodec *m_pCodec;
+ AVCodecContext *m_pCodecCtx;
+ VideoHeader m_VideoHeader;
+};
+
+// V4L video sender.
+class CV4LVideoSender: private JThread
+{
+public:
+ enum V4LVIDEO_SEND_MODE
+ {
+ ModeNone = 0, ModeCapture = 1, ModeTransmit = 2
+ };
+private:
+ enum V4LVIDEO_SEND_BUFSIZE
+ {
+ SendBufSize = 16
+ };
+private:
+ enum V4LVIDEO_SEND_PARA
+ {
+ VideoWidth = 320, VideoHeight = 240
+ };
+public:
+ CV4LVideoSender();
+ ~CV4LVideoSender();
+ bool Init(int nHostPort);
+ bool AddDestination(const RTPIPv4Address &des);
+ void ClearDestinations();
+ int Start(char* szFile = 0, bool bIsRecord = false);
+ void Stop();
+ void SetMode(V4LVIDEO_SEND_MODE mode);
+ bool CreateXImage(Drawable parent, int x, int y, int width, int height);
+ void CloseXImage();
+ void Record(bool bInRecord = true);
+ void GetColorInfo(XImage *image, ColorInfo *ci);
+ bool IsInitialized();
+
+private:
+ bool OpenVideo();
+ void CloseVideo();
+ int Capture(uint8_t** data);
+ bool IsHavedV4LVideo();
+
+ void Playback(uint8_t* videodata);
+ void *Thread();
+ bool stop;
+ JMutex stopmutex;
+private:
+ bool m_bIsRecord;
+ JMutex m_recordmutex;
+
+ CV4LVEncoder m_vencoder;
+ uint8_t *m_pOutBuf;
+ FILE* m_hFile;
+ CSendThread m_sendthread;
+ bool m_bInit;
+ JMutex m_initmutex;
+ V4LVIDEO_SEND_MODE m_mode;
+ JMutex m_modemutex;
+
+ //for ximage
+ Window m_d;
+ Display *m_display;
+ GC m_gc;
+ Window m_win;
+ XImage *m_image;
+
+ JMutex m_imagemutex;
+ ColorInfo c_info;
+ V4L *m_pV4Ldev;
+
+};
+
+#endif // !defined(_EN_DE_VIDEO_H__INCLUDED_)
Added: incubator/bluesky/trunk/RealClass/Teacher/src/errorinfo.h
URL: http://svn.apache.org/viewvc/incubator/bluesky/trunk/RealClass/Teacher/src/errorinfo.h?rev=885392&view=auto
==============================================================================
--- incubator/bluesky/trunk/RealClass/Teacher/src/errorinfo.h (added)
+++ incubator/bluesky/trunk/RealClass/Teacher/src/errorinfo.h Mon Nov 30 12:01:23 2009
@@ -0,0 +1,97 @@
+/** \file error.h define various errors
+*
+*
+*Licensed to the Apache Software Foundation (ASF) under one
+*or more contributor license agreements. See the NOTICE file
+*distributed with this work for additional information
+*regarding copyright ownership. The ASF licenses this file
+*to you under the Apache License, Version 2.0 (the
+*"License"); you may not use this file except in compliance
+*with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+*Unless required by applicable law or agreed to in writing,
+*software distributed under the License is distributed on an
+*"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+*KIND, either express or implied. See the License for the
+*specific language governing permissions and limitations
+*under the License.
+*/
+
+#ifndef _ERRORINFO_H
+#define _ERRORINFO_H
+
+#define ERROR001 "Error 001:The establishment of server and classroom socket connection failure!\n\n"
+#define ERROR_S001 "Information 001: Please check server's IP is correct and confirm the server has been activated!"
+
+#define ERROR002 "Error 002:The establishment of service centers and classroom socket connection failure!\n\n"
+#define ERROR_S002 "Information 002:Please check the server's status."
+
+#define ERROR003 "Error 003:Medium-Login failed!\n\n"
+#define ERROR_S003 "Information 003:Please check server's status, inspection user's name and password."
+
+#define ERROR004 "Error 004:Send message to create class failure!\n\n"
+#define ERROR_S004 "Information 004:Please check server's status."
+
+#define ERROR005 "Error 005:The creation of classroom failure!\n\n"
+#define ERROR_S005 "Information 005:Please check server's status, and make sure that the DTU has been activated."
+
+#define ERROR006 "Error 006:Send message to cancele creating class error!\n\n"
+#define ERROR_S006 "Information 006:Please check server's status."
+
+#define ERROR007 "Error 007:Send message to get Students List error!\n\n"
+#define ERROR_S007 "Information 007:Please check server's status."
+
+#define ERROR008 "Error 008:Send message to get Students List error!\n\n"
+#define ERROR_S008 "Information 008:Please check server's status."
+
+#define ERROR009 "Error 009:Send message to student error!\n\n"
+#define ERROR_S009 "Information 009:Please check server's status."
+
+#define ERROR010 "Error 010:Designated focus of students fail!\n\n"
+#define ERROR_S010 "Information 010:Please check server's status and make sure that the user is still online."
+
+#define ERROR011 "Error 011:Send message to cancel the focus of the student error!\n\n"
+#define ERROR_S011 "Information 011:Please check server's status."
+
+#define ERROR012 "Error 012: Cancel the student's focus error!\n\n"
+#define ERROR_S012 "Information 012:Please check server's status, and make sure that the user do not logout."
+
+#define ERROR013 "Error 013:Send message to chat failure!\n\n"
+#define ERROR_S013 "Information 013:Please check server's status."
+
+#define ERROR014 "Error 014:Data reception port write error!\n\n"
+#define ERROR_S014 "Information 014:Focus of students receiving audio data ports please fill in even-numbered."
+
+#define ERROR015 "Error 015:Data reception port write error!\n\n"
+#define ERROR_S015 "Information 015:Focus of students receiving audio data ports please fill in even-numbered."
+
+#define ERROR016 "Error 016:Data reception port write error!\n\n"
+#define ERROR_S016 "Information 016:Focus of students receiving audio data ports please fill in even-numbered."
+
+#define ERROR017 "Error 017:The class's name filling in is error!\n\n"
+#define ERROR_S017 "Information 017:Please check whether you fill in the class's name, and whether the name is too long."
+
+#define ERROR018 "Error 018:Username filled is error!\n\n"
+#define ERROR_S018 "Information 018:Please check whether you fill in username, and whether the name is too long."
+
+#define ERROR019 "Error 019:Prohibiting chatting failure!\n\n"
+#define ERROR_S019 "Information 019:Please check server's status."
+
+#define ERROR020 "Error 020:Failure to allow chatting!\n\n"
+#define ERROR_S020 "Information 020:Please check server's status."
+
+#define ERROR021 "Error 021:No audio equipment found!\n\n"
+#define ERROR_S021 "Information 021:Please check sound card."
+
+#define ERROR022 "Error 022:No video equipment found!\n\n"
+#define ERROR_S022 "Information 022:Please check whether video equipment ready."
+
+#define ERROR023 "Error 023:Display's resolution too large, and cann't show correctly!\n\n"
+#define ERROR_S023 "Information 023:Please set the resolution to 800 * 600."
+
+#define ERROR024 "Error 024:Display's resolution is too small, and cann't show correctly!\n\n"
+#define ERROR_S024 "Information 024:Please set the resolution to 800 * 600."
+
+#endif
Added: incubator/bluesky/trunk/RealClass/Teacher/src/fecrtpsession.cpp
URL: http://svn.apache.org/viewvc/incubator/bluesky/trunk/RealClass/Teacher/src/fecrtpsession.cpp?rev=885392&view=auto
==============================================================================
--- incubator/bluesky/trunk/RealClass/Teacher/src/fecrtpsession.cpp (added)
+++ incubator/bluesky/trunk/RealClass/Teacher/src/fecrtpsession.cpp Mon Nov 30 12:01:23 2009
@@ -0,0 +1,1448 @@
+/** \file fecrtpsession.cpp implementation of the CFECRtpSession class
+*
+*
+*Licensed to the Apache Software Foundation (ASF) under one
+*or more contributor license agreements. See the NOTICE file
+*distributed with this work for additional information
+*regarding copyright ownership. The ASF licenses this file
+*to you under the Apache License, Version 2.0 (the
+*"License"); you may not use this file except in compliance
+*with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+*Unless required by applicable law or agreed to in writing,
+*software distributed under the License is distributed on an
+*"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+*KIND, either express or implied. See the License for the
+*specific language governing permissions and limitations
+*under the License.
+*/
+
+#include <unistd.h>
+#include "fecrtpsession.h"
+
+#ifndef GF_BITS
+#define GF_BITS 8
+#endif
+
+#define u_char unsigned char
+#define u_short unsigned short
+#define u_long unsigned long
+
+#define bcmp(a,b,n) memcmp(a,b,n)
+#define bcopy(s, d, siz) memcpy((d), (s), (siz))
+#define bzero(d, siz) memset((d), '\0', (siz))
+
+#define DEB(x)
+#define DDB(x) x
+
+#if (GF_BITS < 2 && GF_BITS >16)
+#error "GF_BITS must be 2 .. 16"
+#endif
+
+#if (GF_BITS <= 8)
+typedef unsigned char gf;
+#else
+typedef unsigned short gf;
+#endif
+
+#define GF_SIZE ((1 << GF_BITS) - 1) /* powers of \alpha */
+
+static char *allPp[] =
+{ /* GF_BITS polynomial */
+0, /* 0 no code */
+0, /* 1 no code */
+"111", /* 2 1+x+x^2 */
+"1101", /* 3 1+x+x^3 */
+"11001", /* 4 1+x+x^4 */
+"101001", /* 5 1+x^2+x^5 */
+"1100001", /* 6 1+x+x^6 */
+"10010001", /* 7 1 + x^3 + x^7 */
+"101110001", /* 8 1+x^2+x^3+x^4+x^8 */
+"1000100001", /* 9 1+x^4+x^9 */
+"10010000001", /* 10 1+x^3+x^10 */
+"101000000001", /* 11 1+x^2+x^11 */
+"1100101000001", /* 12 1+x+x^4+x^6+x^12 */
+"11011000000001", /* 13 1+x+x^3+x^4+x^13 */
+"110000100010001", /* 14 1+x+x^6+x^10+x^14 */
+"1100000000000001", /* 15 1+x+x^15 */
+"11010000000010001" /* 16 1+x+x^3+x^12+x^16 */
+};
+
+static gf gf_exp[2 * GF_SIZE]; /* index->poly form conversion table */
+static int gf_log[GF_SIZE + 1]; /* Poly->index form conversion table */
+static gf inverse[GF_SIZE + 1]; /* inverse of field elem. */
+
+int modnn(int x)
+{
+ while (x >= GF_SIZE)
+ {
+ x -= GF_SIZE;
+ x = (x >> GF_BITS) + (x & GF_SIZE);
+ }
+ return x;
+}
+
+#define SWAP(a,b,t) {t tmp; tmp=a; a=b; b=tmp;}
+
+#if (GF_BITS <= 8)
+static gf gf_mul_table[GF_SIZE + 1][GF_SIZE + 1];
+
+#define gf_mul(x,y) gf_mul_table[x][y]
+
+#define USE_GF_MULC register gf * __gf_mulc_
+#define GF_MULC0(c) __gf_mulc_ = gf_mul_table[c]
+#define GF_ADDMULC(dst, x) dst ^= __gf_mulc_[x]
+
+static void init_mul_table()
+{
+ int i, j;
+ for (i = 0; i < GF_SIZE + 1; i++)
+ for (j = 0; j < GF_SIZE + 1; j++)
+ gf_mul_table[i][j] = gf_exp[modnn(gf_log[i] + gf_log[j])];
+
+ for (j = 0; j < GF_SIZE + 1; j++)
+ gf_mul_table[0][j] = gf_mul_table[j][0] = 0;
+}
+#else
+static inline gf gf_mul(gf x,gf y)
+{
+ if ( (x) == 0 || (y)==0 ) return 0;
+
+ return gf_exp[gf_log[x] + gf_log[y] ];
+}
+#define init_mul_table()
+
+#define USE_GF_MULC register gf * __gf_mulc_
+#define GF_MULC0(c) __gf_mulc_ = &gf_exp[ gf_log[c] ]
+#define GF_ADDMULC(dst, x) { if (x) dst ^= __gf_mulc_[ gf_log[x] ] ; }
+#endif
+
+static void* my_malloc(int sz, char *err_string)
+{
+ void *p = malloc(sz);
+ if (p == 0)
+ {
+ }
+ return p;
+}
+
+#define NEW_GF_MATRIX(rows, cols) (gf *)my_malloc(rows * cols * sizeof(gf), " ## __LINE__ ## " )
+
+static void generate_gf(void)
+{
+ int i;
+ gf mask;
+ char *Pp = allPp[GF_BITS];
+
+ mask = 1; /* x ** 0 = 1 */
+ gf_exp[GF_BITS] = 0; /* will be updated at the end of the 1st loop */
+
+ for (i = 0; i < GF_BITS; i++, mask <<= 1)
+ {
+ gf_exp[i] = mask;
+ gf_log[gf_exp[i]] = i;
+ if (Pp[i] == '1')
+ gf_exp[GF_BITS] ^= mask;
+ }
+ gf_log[gf_exp[GF_BITS]] = GF_BITS;
+
+ mask = 1 << (GF_BITS - 1);
+ for (i = GF_BITS + 1; i < GF_SIZE; i++)
+ {
+ if (gf_exp[i - 1] >= mask)
+ gf_exp[i] = gf_exp[GF_BITS] ^ ((gf_exp[i - 1] ^ mask) << 1);
+ else
+ gf_exp[i] = gf_exp[i - 1] << 1;
+ gf_log[gf_exp[i]] = i;
+ }
+
+ gf_log[0] = GF_SIZE;
+
+ for (i = 0; i < GF_SIZE; i++)
+ gf_exp[i + GF_SIZE] = gf_exp[i];
+
+ inverse[0] = 0;
+ inverse[1] = 1;
+ for (i = 2; i <= GF_SIZE; i++)
+ inverse[i] = gf_exp[GF_SIZE - gf_log[i]];
+}
+
+#define addmul(dst, src, c, sz) \
+ if (c != 0) addmul1(dst, src, c, sz)
+
+#define UNROLL 16 /* 1, 4, 8, 16 */
+static void addmul1(gf *dst1, gf *src1, gf c, int sz)
+{
+ USE_GF_MULC ;
+ register gf *dst = dst1, *src = src1;
+ gf *lim = &dst[sz - UNROLL + 1];
+
+ GF_MULC0(c);
+
+#if (UNROLL > 1) /* unrolling by 8/16 is quite effective on the pentium */
+ for (; dst < lim; dst += UNROLL, src += UNROLL)
+ {
+ GF_ADDMULC( dst[0] , src[0] );
+ GF_ADDMULC( dst[1] , src[1] );
+ GF_ADDMULC( dst[2] , src[2] );
+ GF_ADDMULC( dst[3] , src[3] );
+#if (UNROLL > 4)
+ GF_ADDMULC( dst[4] , src[4] );
+ GF_ADDMULC( dst[5] , src[5] );
+ GF_ADDMULC( dst[6] , src[6] );
+ GF_ADDMULC( dst[7] , src[7] );
+#endif
+#if (UNROLL > 8)
+ GF_ADDMULC( dst[8] , src[8] );
+ GF_ADDMULC( dst[9] , src[9] );
+ GF_ADDMULC( dst[10] , src[10] );
+ GF_ADDMULC( dst[11] , src[11] );
+ GF_ADDMULC( dst[12] , src[12] );
+ GF_ADDMULC( dst[13] , src[13] );
+ GF_ADDMULC( dst[14] , src[14] );
+ GF_ADDMULC( dst[15] , src[15] );
+#endif
+ }
+#endif
+ lim += UNROLL - 1;
+ for (; dst < lim; dst++, src++) /* final components */
+ GF_ADDMULC( *dst , *src );
+}
+
+static void matmul(gf *a, gf *b, gf *c, int n, int k, int m)
+{
+ int row, col, i;
+
+ for (row = 0; row < n; row++)
+ {
+ for (col = 0; col < m; col++)
+ {
+ gf *pa = &a[row * k];
+ gf *pb = &b[col];
+ gf acc = 0;
+ for (i = 0; i < k; i++, pa++, pb += m)
+ acc ^= gf_mul( *pa, *pb );
+ c[row * m + col] = acc;
+ }
+ }
+}
+
+#ifdef DEBUG
+static int is_identity(gf *m, int k)
+{
+ int row, col;
+ for (row=0; row<k; row++)
+ for (col=0; col<k; col++)
+ if ( (row==col && *m != 1) || (row!=col && *m != 0) )
+ return 0;
+ else
+ m++;
+ return 1;
+}
+#endif /* debug */
+
+DEB( int pivloops=0; int pivswaps=0; /* diagnostic */)
+static int invert_mat(gf *src, int k)
+{
+ gf c, *p;
+ int irow, icol, row, col, i, ix;
+
+ int error = 1;
+ int *indxc = (int *) my_malloc(k * sizeof(int), "indxc");
+
+ int *indxr = (int *) my_malloc(k * sizeof(int), "indxr");
+ int *ipiv = (int *) my_malloc(k * sizeof(int), "ipiv");
+ gf *id_row = NEW_GF_MATRIX(1, k);
+ gf *temp_row = NEW_GF_MATRIX(1, k);
+
+ if ((indxc == 0) || (indxr == 0) || (id_row == 0) || (temp_row == 0)
+ || (ipiv == 0))
+ {
+ goto fail;
+ }
+
+ bzero(id_row, k*sizeof(gf));
+ DEB( pivloops=0; pivswaps=0; /* diagnostic */)
+
+ for (i = 0; i < k; i++)
+ ipiv[i] = 0;
+
+ for (col = 0; col < k; col++)
+ {
+ gf *pivot_row;
+
+ irow = icol = -1;
+ if (ipiv[col] != 1 && src[col * k + col] != 0)
+ {
+ irow = col;
+ icol = col;
+ goto found_piv;
+ }
+ for (row = 0; row < k; row++)
+ {
+ if (ipiv[row] != 1)
+ {
+ for (ix = 0; ix < k; ix++)
+ {
+ DEB( pivloops++; )
+ if (ipiv[ix] == 0)
+ {
+ if (src[row * k + ix] != 0)
+ {
+ irow = row;
+ icol = ix;
+ goto found_piv;
+ }
+ }
+ else if (ipiv[ix] > 1)
+ {
+ //fprintf(stderr, "singular matrix\n");
+ goto fail;
+ }
+ }
+ }
+ }
+ if (icol == -1)
+ {
+ goto fail;
+ }
+ found_piv: ++(ipiv[icol]);
+
+ if (irow != icol)
+ {
+ for (ix = 0; ix < k; ix++)
+ {
+ SWAP( src[irow*k + ix], src[icol*k + ix], gf);
+ }
+ }
+ indxr[col] = irow;
+ indxc[col] = icol;
+ pivot_row = &src[icol * k];
+ c = pivot_row[icol];
+ if (c == 0)
+ {
+ goto fail;
+ }
+ if (c != 1)
+ {
+ DEB( pivswaps++; )
+ c = inverse[c];
+ pivot_row[icol] = 1;
+ for (ix = 0; ix < k; ix++)
+ pivot_row[ix] = gf_mul(c, pivot_row[ix] );
+ }
+ id_row[icol] = 1;
+ if (bcmp(pivot_row, id_row, k*sizeof(gf)) != 0)
+ {
+ for (p = src, ix = 0; ix < k; ix++, p += k)
+ {
+ if (ix != icol)
+ {
+ c = p[icol];
+ p[icol] = 0;
+ addmul(p, pivot_row, c, k );
+ }
+ }
+ }
+ id_row[icol] = 0;
+ } /* done all columns */
+ for (col = k - 1; col >= 0; col--)
+ {
+ if (indxr[col] < 0 || indxr[col] >= k)
+ {
+ goto fail;
+ }
+ else if (indxc[col] < 0 || indxc[col] >= k)
+ {
+ goto fail;
+ }
+ else if (indxr[col] != indxc[col])
+ {
+ for (row = 0; row < k; row++)
+ {
+ SWAP( src[row*k + indxr[col]], src[row*k + indxc[col]], gf);
+ }
+ }
+ }
+
+ error = 0;
+ fail: if (indxc != 0)
+ free(indxc);
+ if (indxr != 0)
+ free(indxr);
+ if (ipiv != 0)
+ free(ipiv);
+ if (id_row != 0)
+ free(id_row);
+ if (temp_row != 0)
+ free(temp_row);
+ return error;
+}
+
+int invert_vdm(gf *src, int k)
+{
+ int i, j, row, col;
+ gf *b, *c, *p;
+ gf t, xx;
+
+ if (k == 1) /* degenerate case, matrix must be p^0 = 1 */
+ return 0;
+
+ c = NEW_GF_MATRIX(1, k);
+
+ b = NEW_GF_MATRIX(1, k);
+
+ p = NEW_GF_MATRIX(1, k);
+ if ((c == 0) || (b == 0) || (p == 0))
+ {
+ if (b == 0)
+ free(b);
+ if (c == 0)
+ free(c);
+ if (p == 0)
+ free(p);
+ return 1;
+ }
+
+ for (j = 1, i = 0; i < k; i++, j += k)
+ {
+ c[i] = 0;
+ p[i] = src[j]; /* p[i] */
+ }
+ c[k - 1] = p[0]; /* really -p(0), but x = -x in GF(2^m) */
+ for (i = 1; i < k; i++)
+ {
+ gf p_i = p[i]; /* see above comment */
+ for (j = k - 1 - (i - 1); j < k - 1; j++)
+ c[j] ^= gf_mul( p_i, c[j+1] );
+ c[k - 1] ^= p_i;
+ }
+
+ for (row = 0; row < k; row++)
+ {
+
+ xx = p[row];
+ t = 1;
+ b[k - 1] = 1; /* this is in fact c[k] */
+ for (i = k - 2; i >= 0; i--)
+ {
+ b[i] = c[i + 1] ^ gf_mul(xx, b[i+1]);
+ t = gf_mul(xx, t) ^ b[i];
+ }
+ for (col = 0; col < k; col++)
+ src[col * k + row] = gf_mul(inverse[t], b[col] );
+ }
+ free(c);
+ free(b);
+ free(p);
+ return 0;
+}
+
+static int fec_initialized = 0;
+static void init_fec()
+{
+
+ generate_gf();
+
+ init_mul_table();
+
+ fec_initialized = 1;
+}
+
+#define FEC_MAGIC 0xFECC0DEC
+
+struct fec_parms
+{
+ u_long magic;
+ int k, n; /* parameters of the code */
+ gf *enc_matrix;
+};
+
+void fec_free(struct fec_parms *p)
+{
+ if (p == 0 || p->magic != (((FEC_MAGIC ^ p->k) ^ p->n)
+ ^ (int) (p->enc_matrix)))
+ {
+ return;
+ }
+ free(p->enc_matrix);
+ free(p);
+}
+
+struct fec_parms * fec_new(int k, int n)
+{
+ int row, col;
+ gf *p, *tmp_m;
+
+ struct fec_parms *retval;
+
+ if (fec_initialized == 0)
+ init_fec();
+
+ if (k > GF_SIZE + 1 || n > GF_SIZE + 1 || k > n)
+ {
+ return 0;
+ }
+
+ retval
+ = (struct fec_parms*) my_malloc(sizeof(struct fec_parms),
+ "new_code");
+ if (retval == 0)
+ return 0;
+
+ retval->k = k;
+ retval->n = n;
+ retval->enc_matrix = NEW_GF_MATRIX(n, k);
+ if (retval->enc_matrix == 0)
+ {
+ free(retval);
+ return 0;
+ }
+
+ retval->magic = ((FEC_MAGIC ^ k) ^ n) ^ (int) (retval->enc_matrix);
+ tmp_m = NEW_GF_MATRIX(n, k);
+ if (tmp_m == 0)
+ {
+ free(retval->enc_matrix);
+ free(retval);
+ return 0;
+ }
+
+ tmp_m[0] = 1;
+ for (col = 1; col < k; col++)
+ tmp_m[col] = 0;
+ for (p = tmp_m + k, row = 0; row < n - 1; row++, p += k)
+ {
+ for (col = 0; col < k; col++)
+ p[col] = gf_exp[modnn(row * col)];
+ }
+
+ if (invert_vdm(tmp_m, k)) /* much faster than invert_mat */
+ {
+ free(retval->enc_matrix);
+ free(retval);
+ free(tmp_m);
+ return 0;
+ }
+ matmul(tmp_m + k * k, tmp_m, retval->enc_matrix + k * k, n - k, k, k);
+
+ bzero(retval->enc_matrix, k*k*sizeof(gf) );
+ for (p = retval->enc_matrix, col = 0; col < k; col++, p += k + 1)
+ *p = 1;
+ free(tmp_m);
+
+ DEB(pr_matrix(retval->enc_matrix, n, k, "encoding_matrix");)
+ return retval;
+}
+
+void fec_encode(struct fec_parms *code, gf *src[], gf *fec, int index, int sz)
+{
+ int i, k = code->k;
+ gf *p;
+
+ if (GF_BITS > 8)
+ sz /= 2;
+
+ if (index < k)
+ bcopy(src[index], fec, sz*sizeof(gf) );
+ else if (index < code->n)
+ {
+ p = &(code->enc_matrix[index * k]);
+ bzero(fec, sz*sizeof(gf));
+ for (i = 0; i < k; i++)
+ addmul(fec, src[i], p[i], sz );
+ }
+ else
+ ;
+
+}
+
+static int shuffle(gf *pkt[], int index[], int k)
+{
+ int i;
+
+ for (i = 0; i < k;)
+ {
+ if (index[i] >= k || index[i] == i)
+ i++;
+ else
+ {
+ int c = index[i];
+
+ if (index[c] == c)
+ {
+ return 1;
+ }
+ SWAP(index[i], index[c], int);
+ SWAP(pkt[i], pkt[c], gf *);
+ }
+ }
+ DEB(
+ for ( i = 0; i < k; i++ )
+ {
+ if (index[i] < k && index[i] != i)
+ {
+ return 1;
+ }
+ }
+ )
+ return 0;
+}
+
+static gf* build_decode_matrix(struct fec_parms *code, gf *pkt[], int index[])
+{
+ int i, k = code->k;
+ gf *p, *matrix = NEW_GF_MATRIX(k, k);
+
+ if (matrix == 0)
+ {
+ return 0;
+ }
+ for (i = 0, p = matrix; i < k; i++, p += k)
+ {
+ if (index[i] < k)
+ {
+ bzero(p, k*sizeof(gf) );
+ p[i] = 1;
+ }
+ else if (index[i] < code->n)
+ bcopy( &(code->enc_matrix[index[i]*k]), p, k*sizeof(gf) );
+ else
+ {
+ free(matrix);
+ return 0;
+ }
+ }
+
+ if (invert_mat(matrix, k))
+ {
+ free(matrix);
+ matrix = 0;
+ }
+ return matrix;
+}
+
+int fec_decode(struct fec_parms *code, gf *pkt[], int index[], int sz)
+{
+ gf *m_dec;
+ gf **new_pkt;
+ int i, row, col, k = code->k;
+
+ if (GF_BITS > 8)
+ sz /= 2;
+
+ if (shuffle(pkt, index, k)) /* error if true */
+ return 1;
+ m_dec = build_decode_matrix(code, pkt, index);
+
+ if (m_dec == 0)
+ return 1; /* error */
+
+ new_pkt = (gf **) my_malloc(k * sizeof(gf *), "new pkt pointers");
+ if (new_pkt == 0)
+ {
+ free(m_dec);
+ return 1;
+ }
+ for (row = 0; row < k; row++)
+ {
+ if (index[row] >= k)
+ {
+ new_pkt[row] = (gf *) my_malloc(sz * sizeof(gf), "new pkt buffer");
+ if (new_pkt[row] == 0)
+ {
+ free(m_dec);
+ for (i = 0; i < row; i++)
+ {
+ free(new_pkt[row]);
+ }
+ free(new_pkt);
+ return 1;
+ }
+ bzero(new_pkt[row], sz * sizeof(gf) );
+ for (col = 0; col < k; col++)
+ addmul(new_pkt[row], pkt[col], m_dec[row*k + col], sz);
+ }
+ }
+
+ for (row = 0; row < k; row++)
+ {
+ if (index[row] >= k)
+ {
+ bcopy(new_pkt[row], pkt[row], sz*sizeof(gf));
+ free(new_pkt[row]);
+ }
+ }
+ free(new_pkt);
+ free(m_dec);
+ return 0;
+}
+
+CFECRtpSession::CFECRtpSession()
+{
+
+ //init for send.
+ m_nRedundentRate = 1;
+ m_nFrameNo = 0;
+
+ m_oldVideotimestamp = 0;
+ m_usLatestVideoSeq = 0;
+
+ int i;
+ for (i = 0; i < FECLISTSIZE; i++)
+ {
+ m_FECListInfo[i].b_isEmpty = true;
+ m_FECListInfo[i].ul_HaveArriveNum = 0;
+ m_FECListInfo[i].ul_timestamp = 0;
+ m_FECListInfo[i].ul_TotalNeedNum = 0;
+ }
+
+}
+
+CFECRtpSession::~CFECRtpSession()
+{
+
+}
+
+void CFECRtpSession::OnRTPPacket(RTPPacket *pack, const RTPTime &receivetime,
+ const RTPAddress *senderaddress)
+{
+ FECHEADER* fec_header;
+ unsigned char *RecvData;
+ RecvData = pack->GetPayloadData();
+ fec_header = (FECHEADER*) RecvData;
+ int Datalen = pack->GetPayloadLength();
+
+ int rtptimestamp = pack->GetTimestamp();
+ int rtpFramNo = pack->GetExtensionID();
+
+ if (m_oldVideotimestamp != 0 || m_usLatestVideoSeq != 0)
+ {
+ if (rtptimestamp <= m_oldVideotimestamp && rtpFramNo
+ <= m_usLatestVideoSeq)
+ {
+ if (m_usLatestVideoSeq - rtpFramNo <= 10 && m_oldVideotimestamp
+ - rtptimestamp <= 10)
+ return;
+
+ }
+ m_usLatestVideoSeq = 0;
+ m_oldVideotimestamp = 0;
+ }
+
+ if (fec_header->FecCoded == 0)
+ {
+
+ int nVideoframeNum;
+ bool bIsSameVideoUDP = false;
+ nVideoframeNum = m_PreSendFrameList.size();
+
+ if (bIsSameVideoUDP == false)
+ {
+ unsigned char* pPacket;
+ pPacket = new unsigned char[Datalen];
+ if (pPacket == NULL)
+ {
+ return;
+ }
+
+ memcpy(pPacket, RecvData, Datalen);
+
+ FRAMEINFO* pFrameInfo = NULL;
+ pFrameInfo = new FRAMEINFO;
+
+ if (pFrameInfo == NULL)
+ {
+ delete pPacket;
+ return;
+ }
+
+ pFrameInfo->FECCoded = false;
+ pFrameInfo->ul_timestamp = rtptimestamp;
+ pFrameInfo->us_latestseq = rtpFramNo;
+ pFrameInfo->l_datalen = Datalen - sizeof(FECHEADER);
+ pFrameInfo->pData = pPacket + sizeof(FECHEADER);
+
+ m_PreSendFrameList.insert(m_PreSendFrameList.end(), pFrameInfo);
+ UpdateFrames();
+
+ }
+ }
+ else
+ {
+ if (fec_header->FecCoded == 1)
+ {//7
+
+ FRAMEINFO* pFrameInfo;
+ FRAMEINFOLIST::iterator itera;
+ for (itera = m_PreSendFrameList.begin(); itera
+ != m_PreSendFrameList.end(); ++itera)
+ {
+ pFrameInfo = *itera;
+ if (rtptimestamp == pFrameInfo->ul_timestamp)
+ return;
+ }
+
+ int i;
+ bool b_isNotAdd = true;
+
+ for (i = 0; i < FECLISTSIZE; i++)
+ {//6
+ if (m_VideoDataList[i].size() != 0)
+ {//5
+ if (rtptimestamp == m_FECListInfo[i].ul_timestamp)
+ {
+ b_isNotAdd = false;
+
+ bool bIsSameFECVideoData = false;
+
+ if (bIsSameFECVideoData == false)
+ {
+ unsigned char *pPack = new unsigned char[Datalen];
+ if (pPack == NULL)
+ {
+ return;
+ }
+ memcpy(pPack, RecvData, Datalen);
+
+ m_VideoDataList[i].insert(m_VideoDataList[i].end(),
+ (char*) pPack);
+
+ m_FECListInfo[i].ul_HaveArriveNum++;
+
+ if (m_FECListInfo[i].ul_HaveArriveNum
+ == m_FECListInfo[i].ul_TotalNeedNum)
+ {
+ if (FECDecode(&(m_FECListInfo[i]),
+ &m_VideoDataList[i], pack) == 0)
+ {
+
+ UpdateFrames();
+ }
+ else
+ {
+ printf("\nFEC decode failed.");
+
+ }
+ }
+ }//4
+ }//5
+ }//6
+ }
+ if (b_isNotAdd)
+ {
+ for (i = 0; i < FECLISTSIZE; i++)
+ {
+
+ if (m_FECListInfo[i].b_isEmpty)
+ {
+ unsigned char *pPack = new unsigned char[Datalen];
+ if (pPack == NULL)
+ {
+ return;
+ }
+ memcpy(pPack, RecvData, Datalen);
+
+ m_VideoDataList[i].insert(m_VideoDataList[i].end(),
+ (char*) pPack);
+
+ m_FECListInfo[i].b_isEmpty = false;
+ m_FECListInfo[i].ul_HaveArriveNum = 1;
+ m_FECListInfo[i].ul_timestamp = rtptimestamp;
+
+ m_FECListInfo[i].ul_TotalNeedNum
+ = fec_header->OriginalK;
+ b_isNotAdd = false;
+ return;
+ }
+ }
+ }
+ if (b_isNotAdd)
+ {
+ ulong time = m_FECListInfo[0].ul_timestamp;
+ int j = 0;
+
+ for (i = 1; i < FECLISTSIZE; i++)
+ {
+ if (m_FECListInfo[i].ul_timestamp < time)
+ {
+ time = m_FECListInfo[i].ul_timestamp;
+ j = i;
+ }
+ }
+
+ char* p;
+ FECDATALIST::iterator itera;
+ for (itera = m_VideoDataList[j].begin(); itera
+ != m_VideoDataList[j].end(); ++itera)
+ {
+ p = *itera;
+ delete p;
+ p = 0;
+ }
+ m_VideoDataList[j].clear();
+
+ unsigned char *pPack = new unsigned char[Datalen];
+ if (pPack == NULL)
+ {
+ return;
+ }
+ memcpy(pPack, RecvData, Datalen);
+
+ m_VideoDataList[j].insert(m_VideoDataList[j].end(),
+ (char*) pPack);
+
+ m_FECListInfo[j].b_isEmpty = false;
+ m_FECListInfo[j].ul_HaveArriveNum = 1;
+ m_FECListInfo[j].ul_timestamp = rtptimestamp;
+ m_FECListInfo[j].ul_TotalNeedNum = fec_header->OriginalK;
+ return;
+ }
+ }
+ }
+ return;
+
+}
+
+int CFECRtpSession::FECDecode(FECLISTINFO* pFecListInfo,
+ FECDATALIST *pFecDataList, RTPPacket *pack)
+{
+ int PSize;
+ int *ixs;
+ void *code;
+ unsigned char* *d_src;
+
+ unsigned char * pDataBuf;
+ ulong ul_timestamp;
+ unsigned int kCount;
+ kCount = pFecListInfo->ul_TotalNeedNum;
+
+ FECHEADER* fec_header;
+ unsigned char *RecvData;
+ RecvData = pack->GetPayloadData();
+ fec_header = (FECHEADER*) RecvData;
+ int rtptimestamp = pack->GetTimestamp();
+ int rtpFramNo = pack->GetExtensionID();
+
+ ul_timestamp = rtptimestamp;
+ PSize = fec_header->PacketSize;
+
+ code = (*fec_new)(fec_header->OriginalK, fec_header->RedunN);
+ if (code == NULL)
+ {
+ return 1;
+ }
+ ixs = new int[kCount];
+ if (ixs == NULL)
+ {
+ fec_free((struct fec_parms *) code);
+ return 1;
+ }
+ d_src = new PUCHAR[kCount];
+ if (d_src == NULL)
+ {
+ delete ixs;
+ fec_free((struct fec_parms *) code);
+ return 1;
+ }
+ long OriginalDataLen;
+ unsigned int j;
+ for (j = 0; j < kCount; j++)
+ {
+ d_src[j] = new unsigned char[PSize];
+ if (d_src[j] == NULL)
+ {
+ delete ixs;
+ fec_free((struct fec_parms *) code);
+ for (unsigned int ii = 0; ii < j; ii++)
+ {
+ delete d_src[ii];
+ }
+ delete d_src;
+ return 1;
+ }
+ }
+ char* p;
+ FECDATALIST::iterator itera;
+ for (j = 0, itera = pFecDataList->begin(); j < kCount && itera
+ != pFecDataList->end(); j++, itera++)
+ {
+ FECHEADER* fec_header1;
+ p = *itera;
+ fec_header1 = (FECHEADER*) (p);
+
+ ixs[j] = fec_header1->OrigiCol;
+ memcpy(d_src[j], (char*) (p + sizeof(FECHEADER)),
+ fec_header1->PacketSize);
+ delete p;
+ }
+
+ pFecDataList->clear();
+
+ pFecListInfo->b_isEmpty = true;
+ pFecListInfo->ul_HaveArriveNum = 0;
+ pFecListInfo->ul_timestamp = 0;
+ pFecListInfo->ul_TotalNeedNum = 0;
+
+ int CodeResult = 0;
+ try
+ {
+ CodeResult = fec_decode((struct fec_parms *) code,
+ (unsigned char **) d_src, ixs, PSize);
+ } catch (...)
+ {
+ CodeResult = 1;
+ }
+
+ if (CodeResult == 0)
+ {
+
+ OriginalDataLen = GetDataLen(d_src, PSize, kCount);
+ pDataBuf = new unsigned char[OriginalDataLen];
+ if (pDataBuf != NULL)
+ {
+ GetData(pDataBuf, d_src, PSize, kCount);
+
+ FRAMEINFO *pFrameInfo;
+ pFrameInfo = new FRAMEINFO;
+ if (pFrameInfo != NULL)
+ {
+ pFrameInfo->FECCoded = true;
+ pFrameInfo->ul_timestamp = ul_timestamp;
+ pFrameInfo->us_latestseq = rtpFramNo;
+ pFrameInfo->l_datalen = OriginalDataLen;
+ pFrameInfo->pData = pDataBuf;
+
+ m_PreSendFrameList.insert(m_PreSendFrameList.end(), pFrameInfo);
+ }
+ }
+
+ }
+
+ delete ixs;
+ for (unsigned int i = 0; i < kCount; i++)
+ {
+ delete d_src[i];
+ }
+ delete d_src;
+ fec_free((struct fec_parms *) code);
+
+ return CodeResult;
+
+}
+
+long CFECRtpSession::GetDataLen(PUCHAR* d_src, long lPacketSize,
+ unsigned int kCount)
+{
+ PADHEADER* pad_header;
+ long OriginalDataLen = 0;
+
+ for (unsigned int i = 0; i < kCount; i++)
+ {
+ pad_header = (PADHEADER*) (d_src[i]);
+ if (pad_header->paddled == 0)
+ {
+ OriginalDataLen = OriginalDataLen + lPacketSize - sizeof(PADHEADER);
+ }
+ else if (pad_header->paddled == 1)
+ {
+ OriginalDataLen = OriginalDataLen + lPacketSize - sizeof(PADHEADER)
+ - pad_header->padlen;
+ }
+ }
+ return OriginalDataLen;
+}
+
+void CFECRtpSession::GetData(unsigned char* pData, PUCHAR* d_src,
+ long lPacketSize, unsigned int kCount)
+{
+ unsigned char* midbuf;
+ midbuf = pData;
+ PADHEADER* pad_header;
+ for (unsigned int i = 0; i < kCount; i++)
+ {
+ pad_header = (PADHEADER*) (d_src[i]);
+ if (pad_header->paddled == 0)
+ {
+ memcpy(midbuf, d_src[i] + sizeof(PADHEADER), lPacketSize
+ - sizeof(PADHEADER));
+ midbuf = midbuf + lPacketSize - sizeof(PADHEADER);
+ }
+ else if (pad_header->paddled == 1)
+ {
+ memcpy(midbuf, d_src[i] + sizeof(PADHEADER), lPacketSize
+ - sizeof(PADHEADER) - pad_header->padlen);
+ midbuf = midbuf + lPacketSize - sizeof(PADHEADER)
+ - pad_header->padlen;
+ }
+ }
+
+}
+
+int CFECRtpSession::GetRtpMaxLen()
+{
+
+ return RtpMaxLen;
+}
+
+int CFECRtpSession::SendFECPacket(void *lpData, int datalen, int ndelay /* = 5000*/)
+{
+ int nRtpMaxLen;
+ char *pFECPacket;
+ FECHEADER* fec_header;
+
+ pFECPacket = 0;
+ nRtpMaxLen = GetRtpMaxLen();
+
+ IncrementTimestamp(1);
+ SetDefaultTimestampIncrement(0);
+ m_nFrameNo++;
+ if (datalen + sizeof(FECHEADER) <= nRtpMaxLen)
+ { //Send a FEC packet directly.
+ pFECPacket = new char[datalen + sizeof(FECHEADER)];
+ if (pFECPacket == 0)
+ {
+ return -1;
+ }
+ fec_header = (FECHEADER*) pFECPacket;
+ fec_header->FecCoded = 0;
+ memcpy(pFECPacket + sizeof(FECHEADER), lpData, datalen);
+
+ SendPacketEx(pFECPacket, datalen + sizeof(FECHEADER), m_nFrameNo, 0, 0);
+ delete[] pFECPacket;
+ usleep(ndelay);
+ return 0;
+ }
+
+ FECEncodeSend(lpData, datalen, m_nFrameNo, ndelay);
+ return 0;
+}
+
+int CFECRtpSession::FECEncodeSend(void *pData, long datalen,
+ unsigned int FrameNo, int ndelay)
+{
+ int SZ;
+ void *code = 0;
+ int kk;
+ uchar* SendData = 0;
+ FECHEADER* fec_header;
+ PADHEADER* pad_header;
+ int lim = GF_SIZE + 1;
+ int *ixs = 0;
+ int redudant, i;
+ int lastpacketlen;
+ uchar **d_original, **d_src;
+
+ bool CodeResult = true;
+
+ SZ = GetRtpMaxLen();
+ try
+ {
+ kk = datalen / (SZ - sizeof(PADHEADER));
+ } catch (...)
+ {
+ return -1;
+ }
+ if (kk < 0)
+ return -1;
+ lastpacketlen = datalen % (SZ - sizeof(PADHEADER));
+ if (lastpacketlen != 0)
+ kk++;
+ d_original = (uchar**) malloc(kk * sizeof(void *));
+ if (d_original == 0)
+ return -2;
+
+ d_src = (uchar**) malloc(kk * sizeof(void *));
+ if ((d_original == 0) || (d_src == 0))
+ {
+ free(d_original);
+ return -3;
+ }
+ for (i = 0; i < kk; i++)
+ {
+ d_original[i] = 0;
+ d_src[i] = 0;
+ }
+
+ for (i = 0; i < kk; i++)
+ {
+ d_original[i] = (uchar*) malloc(SZ);
+ if (d_original[i] == 0)
+ goto fail;
+ d_src[i] = (uchar*) malloc(SZ);
+ if (d_src[i] == 0)
+ goto fail;
+ }
+ code = (*fec_new)(kk, lim);
+ if (code == 0)
+ {
+ goto fail;
+ }
+
+ ixs = (int*) malloc(kk * sizeof(int));
+ if (ixs == 0)
+ goto fail;
+
+ SendData = (uchar*) malloc(SZ + sizeof(FECHEADER));
+ if (SendData == 0)
+ goto fail;
+
+ for (i = 0; i < kk; i++)
+ ixs[i] = kk + i;
+
+ for (i = 0; i < kk; i++)
+ {
+ pad_header = (PADHEADER*) d_original[i];
+ if ((i != (kk - 1)) || (lastpacketlen == 0))
+ {
+ pad_header->paddled = UNPAD;
+ pad_header->padlen = 0;
+
+ memcpy(d_original[i] + sizeof(PADHEADER), (uchar*) pData + i * (SZ
+ - sizeof(PADHEADER)), SZ - sizeof(PADHEADER));
+ }
+ else
+ {
+ pad_header->paddled = ISPAD;
+ pad_header->padlen = SZ - sizeof(PADHEADER) - lastpacketlen;
+ memcpy(d_original[i] + sizeof(PADHEADER), (uchar*) pData + i * (SZ
+ - sizeof(PADHEADER)), lastpacketlen);
+ memset(d_original[i] + sizeof(PADHEADER) + lastpacketlen, 'A', SZ
+ - sizeof(PADHEADER) - lastpacketlen);
+ }
+ }
+
+ int maxpacket;
+
+ if (m_nRedundentRate <= 0)
+ {
+ maxpacket = 0;
+ }
+ else if (m_nRedundentRate > 200)
+ {
+
+ maxpacket = 0;
+ }
+ else if (m_nRedundentRate > 100)
+ {
+ maxpacket = (int) ((m_nRedundentRate - 100) * kk / 100) + 1;
+ if (maxpacket > kk)
+ {
+ maxpacket = kk;
+ }
+
+ if (maxpacket > MAXFECPACKET - kk)
+ {
+ maxpacket = MAXFECPACKET - kk;
+ }
+ }
+ else
+ {
+ if (kk < 5)
+ {
+ maxpacket = kk;
+
+ if (maxpacket > MAXFECPACKET - kk)
+ {
+ maxpacket = MAXFECPACKET - kk;
+ }
+ }
+ else
+ {
+ maxpacket = (int) (m_nRedundentRate * kk / 100) + 5;
+
+ if (maxpacket > kk)
+ {
+ maxpacket = kk;
+ }
+ if (maxpacket > MAXFECPACKET - kk)
+ {
+ maxpacket = MAXFECPACKET - kk;
+ }
+ }
+ }
+
+ for (i = 0; i < maxpacket; i++)
+ {
+ try
+ {
+ fec_encode((fec_parms *) code, (unsigned char**) d_original,
+ (unsigned char*) (d_src[i]), ixs[i], SZ);
+ } catch (...)
+ {
+ CodeResult = false;
+ }
+ }
+
+ if (CodeResult == false)
+ goto fail;
+ redudant = 0;
+
+ if ((redudant != -1))
+ {
+ for (i = 0; i < kk; i++)
+ {
+ memset(SendData, 0, SZ + sizeof(FECHEADER));
+ fec_header = (FECHEADER*) SendData;
+ fec_header->FecCoded = FECCODED;
+ fec_header->OriginalK = kk;
+ fec_header->OrigiCol = i;
+ fec_header->PacketSize = SZ;
+ fec_header->RedunN = lim;
+ memcpy(SendData + sizeof(FECHEADER), d_original[i], SZ);
+
+ SendPacketEx(SendData, SZ + sizeof(FECHEADER), FrameNo, 0, 0);
+ usleep(ndelay);
+ }
+ }
+
+ if (kk > 20)
+ {
+ if (redudant == -1)
+ {
+ redudant = 1;
+ }
+ else if (kk > 20)
+ {
+ redudant = +5;
+ }
+ }
+
+ if (redudant >= kk)
+ {
+ redudant = kk;
+ }
+
+ if (kk + redudant >= MAXFECPACKET)
+ redudant = MAXFECPACKET - kk;
+
+ for (i = 0; i < maxpacket; i++)
+ {
+ memset(SendData, 0, SZ + sizeof(FECHEADER));
+ fec_header = (FECHEADER*) SendData;
+ fec_header->FecCoded = FECCODED;
+ fec_header->OriginalK = kk;
+ fec_header->OrigiCol = kk + i;
+ fec_header->PacketSize = SZ;
+ fec_header->RedunN = lim;
+ memcpy(SendData + sizeof(FECHEADER), d_src[i], SZ);
+
+ SendPacketEx(SendData, SZ + sizeof(FECHEADER), FrameNo, 0, 0);
+ usleep(ndelay);
+ }
+
+ if (SendData != 0)
+ free(SendData);
+ if (code != 0)
+ fec_free((fec_parms *) code);
+ for (i = 0; i < kk; i++)
+ {
+ free(d_original[i]);
+ free(d_src[i]);
+ }
+ free(d_original);
+ free(d_src);
+ free(ixs);
+ return 0;
+ fail: if (SendData != 0)
+ free(SendData);
+ if (code != 0)
+ fec_free((fec_parms *) code);
+ for (i = 0; i < kk; i++)
+ {
+ if (d_original[i] != 0)
+ free(d_original[i]);
+ if (d_src[i] != 0)
+ free(d_src[i]);
+ }
+ if (d_original != 0)
+ free(d_original);
+ if (d_src != 0)
+ free(d_src);
+ if (ixs != 0)
+ free(ixs);
+ return -5;
+}
+
+void CFECRtpSession::UpdateFrames()
+{
+ int framecount;
+ FRAMEINFO * p;
+ FRAMEINFOLIST::iterator itera;
+
+ framecount = m_PreSendFrameList.size();
+ if (framecount == 0)
+ return;
+
+ for (itera = m_PreSendFrameList.begin(); itera != m_PreSendFrameList.end(); ++itera)
+ {
+ p = *itera;
+ m_usLatestVideoSeq = p->us_latestseq;
+ m_oldVideotimestamp = p->ul_timestamp;
+ ProcessFrame(p->pData, p->l_datalen);
+ RemoveFrame(p);
+ p = 0;
+ }
+ m_PreSendFrameList.clear();
+ return;
+
+ for (itera = m_PreSendFrameList.begin(); itera != m_PreSendFrameList.end(); ++itera)
+ {
+ p = *itera;
+ if (p->us_latestseq == uint16_t(m_usLatestVideoSeq + 1))
+ {
+ m_usLatestVideoSeq = p->us_latestseq;
+ m_oldVideotimestamp = p->ul_timestamp;
+ ProcessFrame(p->pData, p->l_datalen);
+ RemoveFrame(p);
+ p = 0;
+ m_PreSendFrameList.erase(itera);
+ UpdateFrames();
+ return;
+ }
+ }
+
+ if (framecount < 3)
+ return;
+
+ FRAMEINFO *fff;
+ FRAMEINFOLIST::iterator kkk;
+ kkk = m_PreSendFrameList.begin();
+ fff = *kkk;
+ for (itera = kkk; itera != m_PreSendFrameList.end(); ++itera)
+ {
+ p = *itera;
+ if (fff->ul_timestamp > p->ul_timestamp)
+ {
+ kkk = itera;
+ fff = p;
+ }
+ }
+
+ m_usLatestVideoSeq = fff->us_latestseq;
+ m_oldVideotimestamp = fff->ul_timestamp;
+ ProcessFrame(fff->pData, fff->l_datalen);
+ RemoveFrame(fff);
+ fff = 0;
+ m_PreSendFrameList.erase(kkk);
+
+ return;
+
+}
+
+void CFECRtpSession::ProcessFrame(unsigned char *recvdata, int recvlen)
+{
+ return;
+
+}
+
+void CFECRtpSession::RemoveFrame(FRAMEINFO *p)
+{
+ if (p->FECCoded)
+ delete p->pData;
+ else if (!p->FECCoded)
+ delete (p->pData - sizeof(FECHEADER));
+ delete p;
+}
Added: incubator/bluesky/trunk/RealClass/Teacher/src/fecrtpsession.h
URL: http://svn.apache.org/viewvc/incubator/bluesky/trunk/RealClass/Teacher/src/fecrtpsession.h?rev=885392&view=auto
==============================================================================
--- incubator/bluesky/trunk/RealClass/Teacher/src/fecrtpsession.h (added)
+++ incubator/bluesky/trunk/RealClass/Teacher/src/fecrtpsession.h Mon Nov 30 12:01:23 2009
@@ -0,0 +1,136 @@
+/** \file fecrtpsession.h interface for the CFECRtpSession class
+*
+*
+*Licensed to the Apache Software Foundation (ASF) under one
+*or more contributor license agreements. See the NOTICE file
+*distributed with this work for additional information
+*regarding copyright ownership. The ASF licenses this file
+*to you under the Apache License, Version 2.0 (the
+*"License"); you may not use this file except in compliance
+*with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+*Unless required by applicable law or agreed to in writing,
+*software distributed under the License is distributed on an
+*"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+*KIND, either express or implied. See the License for the
+*specific language governing permissions and limitations
+*under the License.
+*/
+
+#include <rtpsession.h>
+#include <rtppacket.h>
+#include <rtpipv4address.h>
+#include <rtpsessionparams.h>
+#include <rtpudpv4transmitter.h>
+
+#if !defined(_FECRTPSESSION_H__INCLUDED_)
+#define _FECRTPSESSION_H__INCLUDED_
+
+#define uchar char
+#define ushort unsigned short
+#define ulong unsigned long
+
+#define ISPAD 1
+#define UNPAD 0
+#define FECCODED 1
+#define SENDFREQUENCY 1
+#define MAXSENDBUFFER 10000
+#define MAXFECPACKET 255
+
+#define FRAMENUM 2
+typedef struct _PADHEADER
+{
+ ushort paddled;
+ ushort padlen;
+} PADHEADER;
+
+typedef struct _FECHEADER
+{
+ ulong FecCoded :1;
+ ulong OriginalK :10;
+ ulong RedunN :11;
+ ulong OrigiCol :10;
+ ulong PacketSize;
+} FECHEADER;
+
+typedef struct _FECLISTINFO
+{
+ ulong ul_timestamp;
+ ulong ul_TotalNeedNum;
+ ulong ul_HaveArriveNum;
+ bool b_isEmpty;
+} FECLISTINFO;
+
+typedef struct _FRAMEINFO
+{
+ bool FECCoded;
+ ulong ul_timestamp;
+ uint16_t us_latestseq;
+ long l_datalen;
+ unsigned char *pData;
+} FRAMEINFO;
+
+typedef std::list<char*> FECDATALIST;
+typedef std::list<FRAMEINFO*> FRAMEINFOLIST;
+
+typedef unsigned char * PUCHAR;
+
+#define FECLISTSIZE 3
+
+class CFECRtpSession: public RTPSession
+{
+public:
+ int ScreenWidth;
+ int ScreenHeight;
+private:
+ enum FECRTP
+ {
+ RtpMaxLen = 4096
+ };
+
+private:
+ long GetDataLen(PUCHAR* d_src, long lPacketSize, unsigned int kCount);
+ void GetData(unsigned char* pData, PUCHAR* d_src, long lPacketSize,
+ unsigned int kCount);
+ virtual void OnRTPPacket(RTPPacket *pack, const RTPTime &receivetime,
+ const RTPAddress *senderaddress);
+ int FECDecode(FECLISTINFO* pFecListInfo, FECDATALIST *pFecDataList,
+ RTPPacket *pack);
+public:
+
+ inline uint16_t GetFrameNo()
+ {
+ return m_nFrameNo;
+ }
+ ;
+ int SendFECPacket(void *lpData, int datalen, int delay = 5000);
+public:
+ CFECRtpSession();
+ virtual ~CFECRtpSession();
+private:
+ int FECEncodeSend(void* pData, long datalen, unsigned int FrameNo,
+ int delay);
+ int GetRtpMaxLen();
+
+private:
+ void RemoveFrame(FRAMEINFO* p);
+ virtual void ProcessFrame(unsigned char* framedata, int framelen);
+ void UpdateFrames();
+ //for FECEncode send.
+ uint16_t m_nFrameNo;
+ int m_nRedundentRate;
+
+protected:
+ uint16_t m_usLatestVideoSeq;
+ int m_oldVideotimestamp;
+
+private:
+ FRAMEINFOLIST m_PreSendFrameList; //
+ FECLISTINFO m_FECListInfo[FECLISTSIZE]; //
+ FECDATALIST m_VideoDataList[FECLISTSIZE]; //
+
+};
+
+#endif // !defined(_FECRTPSESSION_H__INCLUDED_)