⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 video.cxx

📁 这是一个OPENH323中的MCU程序
💻 CXX
📖 第 1 页 / 共 3 页
字号:
{
  return ReadSrcFrame(frameStores, buffer, width, height, amount);
}


BOOL MCUSimpleVideoMixer::WriteFrame(ConferenceMemberId id, const void * buffer, int width, int height, PINDEX amount)
{
  PWaitAndSignal m(mutex);

  // special case of one member means we do nothing, and don't bother looking for other user to copy from
  if (rows == 0) 
    return TRUE;

  // special case of two members means we do nothing, and tell caller to look for another frame to write to
  if (rows == 1) 
    return FALSE;

  // write data into sub frame of mixed image
  VideoMixPositionMap::const_iterator r = videoPositions.find(id);
  if (r == videoPositions.end())
    return TRUE;

  r->second->WriteSubFrame(*this, buffer, width, height, amount);

  return TRUE;
}

void MCUSimpleVideoMixer::SetAudioLevel(ConferenceMemberId id, unsigned audioLevel)
{
  PWaitAndSignal m(mutex);

  // write data into sub frame of mixed image
  VideoMixPositionMap::const_iterator r = videoPositions.find(id);
  if (r != videoPositions.end()) {
    r->second->audioLevel = audioLevel;
    SetSubFrameLevel(*r->second, audioLevel);
  }
}


void MCUSimpleVideoMixer::SetSubFrameLevel(VideoMixPosition & /*vmp*/, unsigned /*audioLevel*/)
{
}

void MCUSimpleVideoMixer::CalcVideoSplitSize(unsigned int imageCount, int & subImageWidth, int & subImageHeight, int & cols, int & rows)
{
  if (!forceScreenSplit && imageCount < 2) {
    subImageWidth  = CIF_WIDTH;
    subImageHeight = CIF_HEIGHT;
    cols           = 0;
    rows           = 0;
  }
  else
  if (!forceScreenSplit && imageCount == 2) {
    subImageWidth  = CIF_WIDTH;
    subImageHeight = CIF_HEIGHT;
    cols           = 1;
    rows           = 1;

  }
  else
  if (imageCount <= 4) {
    subImageWidth  = QCIF_WIDTH;
    subImageHeight = QCIF_HEIGHT;
    cols           = 2;
    rows           = 2;
  }
  else
  if (imageCount <= 9) {
    subImageWidth  = Q3CIF_WIDTH;
    subImageHeight = Q3CIF_HEIGHT;
    cols           = 3;
    rows           = 3;
  }
  else if (imageCount <= 16) {
    subImageWidth  = Q4CIF_WIDTH;
    subImageHeight = Q4CIF_HEIGHT;
    cols           = 4;
    rows           = 4;
  }
}

void MCUSimpleVideoMixer::ReallocatePositions()
{
  FillCIFYUVFrame(frameStores.GetFrameStore(CIF_WIDTH, CIF_HEIGHT).data.GetPointer(), 0, 0, 0);
  frameStores.InvalidateExcept(CIF_WIDTH, CIF_HEIGHT);

  VideoMixPositionMap::iterator r;

  if (cols == 0 || cols == 1) {
    r = videoPositions.begin();
    if (r != videoPositions.end()) {
      VideoMixPosition & vmp = *(r->second);
      vmp.xpos   = 0;
      vmp.ypos   = 0;
      vmp.width  = subImageWidth;
      vmp.height = subImageHeight;
    }
    return;
  }

  // reallocate display positions, but always use the top left corner last)
  unsigned int start = 1;
  unsigned int i = 0;
  for (r = videoPositions.begin(); r != videoPositions.end(); ++r) {
    unsigned int x = (i + start) % cols;
    unsigned int y = ((i + start) / cols) % rows;
    VideoMixPosition & vmp = *(r->second);
    vmp.xpos   = x * subImageWidth;
    vmp.ypos   = y * subImageHeight;
    vmp.width  = subImageWidth;
    vmp.height = subImageHeight;
    ++i;
  }
}

BOOL MCUSimpleVideoMixer::AddVideoSource(ConferenceMemberId id, ConferenceMember & mbr)
{
  PWaitAndSignal m(mutex);

  // make sure this source is not already in the list
  VideoMixPositionMap::const_iterator r = videoPositions.find(id);
  if (r != videoPositions.end()) 
    return TRUE;

  if (videoPositions.size() == MAX_SUBFRAMES)
    return FALSE;

  // calculate the kind of video split we need to include the new source
  int newSubImageWidth, newSubImageHeight, newCols, newRows; 
  CalcVideoSplitSize((unsigned int)(videoPositions.size()+1), newSubImageWidth, newSubImageHeight, newCols, newRows);

  VideoMixPosition * newPosition = NULL;

  // if the subimage size has changed, rearrange everything
  if ((newSubImageWidth != subImageWidth) || (newSubImageHeight != subImageHeight) || (cols != newCols) || (rows != newRows)) {
    rows           = newRows;
    cols           = newCols;
    subImageWidth  = newSubImageWidth;;
    subImageHeight = newSubImageHeight;

    newPosition = CreateVideoMixPosition(id, mbr, 0, 0, subImageWidth, subImageHeight);
    videoPositions.insert(VideoMixPositionMap::value_type(id, newPosition));

    ReallocatePositions();
  }

  // otherwise find an empty position
  else if (rows == 0) {
    newPosition = CreateVideoMixPosition(id, mbr, 0, 0,subImageWidth, subImageHeight);
    videoPositions.insert(VideoMixPositionMap::value_type(id, newPosition));
  }
  else {
    BOOL found = FALSE;
    int i = 0;
    int start = 1;
    VideoMixPositionMap::iterator r = videoPositions.end();
    while (!found && i < (rows*cols)) {
      int x = (i + start) % cols;
      int y = ((i + start) / cols) % rows;
      r = videoPositions.begin(); 
      while (r != videoPositions.end()) {
        VideoMixPosition & vmp = *(r->second);
        if (vmp.xpos == (x * subImageWidth) && vmp.ypos == (y * subImageHeight))
          break;
        ++r;
      }
      if (r == videoPositions.end())
        break;
      ++i;
    }

    PAssert(r == videoPositions.end(), "could not find free video position");
    unsigned int x = (i + start) % cols;
    unsigned int y = ((i + start) / cols) % rows;

    newPosition = CreateVideoMixPosition(id, mbr, x * subImageWidth, y * subImageHeight, subImageWidth, subImageHeight);
    videoPositions.insert(VideoMixPositionMap::value_type(id, newPosition));
  }

  if (newPosition != NULL) {
    PBYTEArray fs(CIF_SIZE);
    int amount = CIF_SIZE;
    if (!OpenMCU::Current().GetEmptyMediaFrame(fs.GetPointer(), CIF_WIDTH, CIF_HEIGHT, amount))
      FillYUVFrame(fs.GetPointer(), 0, 0, 0, CIF_WIDTH, CIF_HEIGHT);
    WriteSubFrame(*newPosition, fs.GetPointer(), CIF_WIDTH, CIF_HEIGHT, amount);
  }

  return TRUE;
}

void MCUSimpleVideoMixer::RemoveVideoSource(ConferenceMemberId id, ConferenceMember & mbr)
{
  PWaitAndSignal m(mutex);

  // make sure this source is in the list
  {
    VideoMixPositionMap::iterator r = videoPositions.find(id);
    if (r == videoPositions.end()) 
      return;

    // clear the position where the frame was
    VideoMixPosition & vmp = *(r->second);
    if (videoPositions.size() == 1)
      FillCIFYUVFrame(frameStores.GetFrameStore(CIF_WIDTH, CIF_HEIGHT).data.GetPointer(), 0, 0, 0);
    else
      FillCIFYUVRect(frameStores.GetFrameStore(CIF_WIDTH, CIF_HEIGHT).data.GetPointer(), 0, 0, 0, vmp.xpos, vmp.ypos, vmp.width, vmp.height);
    frameStores.InvalidateExcept(CIF_WIDTH, CIF_HEIGHT);

    // erase the video position information
    delete r->second;

    // remove the source from the list
    videoPositions.erase(r);
  }

  // calculate the kind of video split we need to include the new source
  int newSubImageWidth, newSubImageHeight, newCols, newRows; 
  CalcVideoSplitSize((unsigned int)videoPositions.size(), newSubImageWidth, newSubImageHeight, newCols, newRows);

  // if the subimage size has changed, rearrange everything
  if (newSubImageWidth != subImageWidth || newSubImageHeight != subImageHeight || newRows != rows || newCols != cols) {
    rows           = newRows;
    cols           = newCols;
    subImageWidth  = newSubImageWidth;
    subImageHeight = newSubImageHeight;

    ReallocatePositions();
  }
}


BOOL MCUSimpleVideoMixer::WriteSubFrame(VideoMixPosition & vmp, const void * buffer, int width, int height, PINDEX amount)
{
  PWaitAndSignal m(mutex);

  VideoFrameStoreList::FrameStore & cifFs = frameStores.GetFrameStore(CIF_WIDTH, CIF_HEIGHT);

  if (width == vmp.width && height == vmp.height) {
    CopyRectIntoCIF(buffer, cifFs.data.GetPointer(), vmp.xpos, vmp.ypos, vmp.width, vmp.height);
    frameStores.InvalidateExcept(CIF_WIDTH, CIF_HEIGHT);
  }

  else {
    converter->SetSrcFrameSize(width, height);
    PINDEX bytesReturned = (vmp.width * vmp.height * 3) / 2;
    converter->SetDstFrameSize(vmp.width, vmp.height, TRUE);
    converter->Convert((const BYTE *)buffer, imageStore.GetPointer((vmp.width * vmp.height * 3) / 2), amount, &bytesReturned);
    CopyRectIntoCIF(imageStore.GetPointer(), cifFs.data.GetPointer(), vmp.xpos, vmp.ypos, vmp.width, vmp.height);
    frameStores.InvalidateExcept(CIF_WIDTH, CIF_HEIGHT);
  }
  return TRUE;
};

///////////////////////////////////////////////////////////////////////////////////////

#if ENABLE_TEST_ROOMS

TestVideoMixer::TestVideoMixer(unsigned _frames)
  : frames(_frames), allocated(FALSE)
{
}

BOOL TestVideoMixer::AddVideoSource(ConferenceMemberId id, ConferenceMember & mbr)
{
  PWaitAndSignal m(mutex);

  if (allocated)
    return FALSE;

  allocated = TRUE;

  unsigned i;
  for (i = 0; i < frames; ++i) {

    // calculate the kind of video split we need to include the new source
    CalcVideoSplitSize(i+1, subImageWidth, subImageHeight, cols, rows);

    VideoMixPosition * newPosition = CreateVideoMixPosition(id, mbr, 0, 0, subImageWidth, subImageHeight);
    videoPositions.insert(VideoMixPositionMap::value_type((ConferenceMemberId)(i+(BYTE *)id), newPosition));

    ReallocatePositions();
  }

  return TRUE;
}

BOOL TestVideoMixer::ReadFrame(ConferenceMember &, void * buffer, int width, int height, PINDEX & amount)
{
  PWaitAndSignal m(mutex);

  // not allocated means fill with black
  if (!allocated) {
    VideoFrameStoreList::FrameStore & fs = frameStores.GetFrameStore(width, height);
    if (!fs.valid) {
      if (!OpenMCU::Current().GetEmptyMediaFrame(fs.data.GetPointer(), width, height, amount))
        FillYUVFrame(fs.data.GetPointer(), 0, 0, 0, width, height);
      fs.valid = TRUE;
    }
    memcpy(buffer, fs.data.GetPointer(), amount);
    return TRUE;
  }

  return ReadMixedFrame(buffer, width, height, amount);
}


BOOL TestVideoMixer::WriteFrame(ConferenceMemberId id, const void * buffer, int width, int height, PINDEX amount)
{
  PWaitAndSignal m(mutex);

  unsigned i;
  for (i = 0; i < frames; ++i) {

    // write data into sub frame of mixed image
    VideoMixPositionMap::const_iterator r;
    for (r = videoPositions.begin(); r != videoPositions.end(); ++r) {
      r->second->WriteSubFrame(*this, buffer, width, height, amount);
    }
  }

  return TRUE;
}

#endif // ENABLE_TEST_ROOMS


#if ENABLE_ECHO_MIXER

EchoVideoMixer::EchoVideoMixer()
  : MCUSimpleVideoMixer()
{
}

BOOL EchoVideoMixer::AddVideoSource(ConferenceMemberId id, ConferenceMember & mbr)
{
  PWaitAndSignal m(mutex);

  CalcVideoSplitSize(1, subImageWidth, subImageHeight, cols, rows);
  VideoMixPosition * newPosition = CreateVideoMixPosition(id, mbr, 0, 0, subImageWidth, subImageHeight);
  videoPositions.insert(VideoMixPositionMap::value_type(id, newPosition));
  ReallocatePositions();

  return TRUE;
}

BOOL EchoVideoMixer::WriteFrame(ConferenceMemberId id, const void * buffer, int width, int height, PINDEX amount)
{
  PWaitAndSignal m(mutex);

  // write data into sub frame of mixed image
  VideoMixPositionMap::const_iterator r = videoPositions.begin();
  if (r != videoPositions.end())
    r->second->WriteSubFrame(*this, buffer, width, height, amount);

  return TRUE;
}

BOOL EchoVideoMixer::ReadFrame(ConferenceMember &, void * buffer, int width, int height, PINDEX & amount)
{
  return ReadMixedFrame(buffer, width, height, amount);
}


#endif // ENABLE_ECHO_MIXER

#endif // OPENMCU_VIDEO

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -