<commit_before>/*
 * Copyright (C) 2013 by Glenn Hickey (hickey@soe.ucsc.edu)
 *
 * Released under the MIT license, see LICENSE.txt
 */

#include <cassert>
#include <limits>
#include <cmath>
#include <algorithm>
#include "halLodGraph.h"

using namespace std;
using namespace hal;

LodGraph::LodGraph() : _extendFraction(1.0)
{

}

LodGraph::~LodGraph()
{
  erase();
}

void LodGraph::erase()
{
  for (SequenceMapIterator smi = _seqMap.begin(); smi != _seqMap.end(); ++smi)
  {
    delete smi->second;
  }
  _seqMap.clear();
  for (BlockIterator bi = _blocks.begin(); bi != _blocks.end(); ++bi)
  {
    delete *bi;
  }
  _blocks.clear();
  _parent = NULL;
  _genomes.clear();
  _telomeres.clear();
}

void LodGraph::build(AlignmentConstPtr alignment, const Genome* parent,
                     const vector<const Genome*>& children,
                     hal_size_t step)
{
  erase();
  _alignment = alignment;
  _parent = parent;
  _step = step;

  assert(_parent != NULL);
  assert(_alignment->openGenome(_parent->getName()) == _parent);

  _genomes.insert(parent);
  for (vector<const Genome*>::const_iterator child = children.begin();
       child != children.end(); ++child)
  {
    _genomes.insert(*child);
  }
  assert(_genomes.size() == children.size() + 1);

  for (set<const Genome*>::iterator gi = _genomes.begin();
       gi != _genomes.end(); ++gi)
  {
    scanGenome(*gi);
  }

  computeAdjacencies();
  printDimensions(cout);
  optimizeByExtension();
  printDimensions(cout);
  optimizeByMerging();
  printDimensions(cout);
  optimizeByInsertion();
  printDimensions(cout);
  assert(checkCoverage() == true);
}

void LodGraph::scanGenome(const Genome* genome)
{
  SequenceIteratorConstPtr seqIt = genome->getSequenceIterator();
  SequenceIteratorConstPtr seqEnd = genome->getSequenceEndIterator();
  for (; seqIt != seqEnd; seqIt->toNext())
  {
    const Sequence* sequence = seqIt->getSequence();
    hal_size_t len = sequence->getSequenceLength();

    addTelomeres(sequence);

    for (hal_index_t pos = 0; pos < (hal_index_t)len; pos += (hal_index_t)_step)
    {
      // clamp to last position
      if (pos > 0 && pos + (hal_index_t)_step >= (hal_index_t)len)
      {
        pos =  (hal_index_t)len - 1;
      }
      // better to move column iterator rather than getting each time?
      // -- probably not because we have to worry about dupe cache
      ColumnIteratorConstPtr colIt =
         sequence->getColumnIterator(&_genomes, 0, pos);
      assert(colIt->getReferenceSequencePosition() == pos);

      // scan up to here trying to find a column we're happy to add
      hal_index_t maxTry = std::min(pos + (hal_index_t)_step / 2,
                               (hal_index_t)len - 1);
      hal_index_t tryPos = NULL_INDEX;
      do
      {
        tryPos = colIt->getReferenceSequencePosition();
        bool canAdd = canAddColumn(colIt);
        if (canAdd)
        {
          createColumn(colIt);
          break;
        }
        colIt->toRight();
      }
      while (colIt->lastColumn() == false && tryPos < maxTry);
    }
  }
}

bool LodGraph::canAddColumn(ColumnIteratorConstPtr colIt)
{
  // check that block has not already been added.
  hal_index_t delta = numeric_limits<hal_index_t>::max();
  const ColumnIterator::ColumnMap* colMap = colIt->getColumnMap();
  ColumnIterator::ColumnMap::const_iterator colMapIt = colMap->begin();
  for (; colMapIt != colMap->end(); ++colMapIt)
  {
    const ColumnIterator::DNASet* dnaSet = colMapIt->second;
    if (dnaSet->size() > 0)
    {
      const Sequence* sequence = colMapIt->first;
      ColumnIterator::DNASet::const_iterator dnaIt = dnaSet->begin();
      hal_index_t pos = (*dnaIt)->getArrayIndex();
      LodSegment segment(NULL, sequence, pos, false);
      SequenceMapIterator smi = _seqMap.find(sequence);
      if (smi != _seqMap.end())
      {
        SegmentSet* segmentSet = smi->second;
        SegmentIterator si = segmentSet->lower_bound(&segment);
        SegmentSet::value_compare segPLess;
        if (si != segmentSet->end() && !segPLess(&segment, *si))
        {
          delta = 0;
        }
        else
        {
          delta = std::abs((*si)->getLeftPos() - segment.getLeftPos());
          if (si != segmentSet->begin())
          {
            --si;
            delta = std::min(delta, (hal_index_t)std::abs((*si)->getLeftPos() -
                                             segment.getLeftPos()));
          }
        }
      }
      break;
    }
  }
  bool canAdd = delta > 0;
  hal_index_t refPos = colIt->getReferenceSequencePosition();
  if (canAdd == true && refPos != 0 && (hal_size_t)refPos !=
      colIt->getReferenceSequence()->getSequenceLength())
  {
    canAdd = delta >= (hal_index_t)_step;

    // other heuristics here?
  }
  return canAdd;
}

void LodGraph::addTelomeres(const Sequence* sequence)
{
  SequenceMapIterator smi = _seqMap.find(sequence);
  SegmentSet* segSet = NULL;
  if (smi == _seqMap.end())
  {
    segSet = new SegmentSet();;
    _seqMap.insert(pair<const Sequence*, SegmentSet*>(sequence, segSet));
  }
  else
  {
    segSet = smi->second;
  }

  LodSegment* segment = new LodSegment(&_telomeres, sequence,
                                       sequence->getStartPosition() - 1,
                                       false);
  _telomeres.addSegment(segment);
  segSet->insert(segment);
  segment = new LodSegment(&_telomeres, sequence,
                           sequence->getEndPosition() + 1, false);
  _telomeres.addSegment(segment);
  segSet->insert(segment);
}

void LodGraph::createColumn(ColumnIteratorConstPtr colIt)
{
  LodBlock* block = new LodBlock();
  const ColumnIterator::ColumnMap* colMap = colIt->getColumnMap();
  ColumnIterator::ColumnMap::const_iterator colMapIt = colMap->begin();
  for (; colMapIt != colMap->end(); ++colMapIt)
  {
    const Sequence* sequence = colMapIt->first;
    SequenceMapIterator smi = _seqMap.find(sequence);
    SegmentSet* segSet = NULL;
    if (smi == _seqMap.end())
    {
      segSet = new SegmentSet();;
      _seqMap.insert(pair<const Sequence*, SegmentSet*>(sequence, segSet));
    }
    else
    {
      segSet = smi->second;
    }

    const ColumnIterator::DNASet* dnaSet = colMapIt->second;
    for (ColumnIterator::DNASet::const_iterator dnaIt = dnaSet->begin();
         dnaIt != dnaSet->end(); ++ dnaIt)
    {
      hal_index_t pos = (*dnaIt)->getArrayIndex();
      bool reversed = (*dnaIt)->getReversed();
      LodSegment* segment = new LodSegment(block, sequence, pos, reversed);
      block->addSegment(segment);
      assert(segSet->find(segment) == segSet->end());
      segSet->insert(segment);
    }
  }
  assert(block->getNumSegments() > 0);
  _blocks.push_back(block);
}

void LodGraph::computeAdjacencies()
{
  for (SequenceMapIterator smi = _seqMap.begin(); smi != _seqMap.end(); ++smi)
  {
    SegmentIterator si = smi->second->begin();
    SegmentIterator siNext;
    for (; si != smi->second->end(); ++si)
    {
      siNext = si;
      ++siNext;
      if (siNext != smi->second->end())
      {
        assert((*si)->overlaps(**siNext) == false);
        (*si)->addEdgeFromRightToLeft(*siNext);
      }
    }
  }
}

void LodGraph::optimizeByExtension()
{
  // Put bigger blocks first because (we hope) they tend to represent
  // more information and we'd rather extend them than, say, a block
  // that represents a little insertion.
  std::sort(_blocks.begin(), _blocks.end(), LodBlockPBigger());

  // Pass 1: Extend all blocks with at least 2 sequences by half
  for (BlockIterator bi = _blocks.begin(); bi != _blocks.end() &&
          (*bi)->getNumSegments() > 1; ++bi)
  {
    (*bi)->extend(0.5);
  }

  // Pass 2: Greedily extend each block to the max
  for (BlockIterator bi = _blocks.begin(); bi != _blocks.end(); ++bi)
  {
    (*bi)->extend();
  }

}

void LodGraph::optimizeByMerging()
{
  BlockList mergeList(_blocks);
  for (BlockIterator bi = mergeList.begin(); bi != mergeList.end(); ++bi)
  {
    LodBlock* adjBlock = (*bi)->getHeadMergePartner();
    if (adjBlock != NULL)
    {
      for (hal_size_t segIdx = 0; segIdx < adjBlock->getNumSegments(); ++segIdx)
      {
        // blah - need to clean interface but this is harmless for now
        LodSegment* seg = const_cast<LodSegment*>(
          adjBlock->getSegment(segIdx));
        SequenceMapIterator mapIt = _seqMap.find(seg->getSequence());
        assert(mapIt != _seqMap.end());
        SegmentIterator setIt = mapIt->second->find(seg);
        assert(setIt != mapIt->second->end());
        assert(*setIt == seg);
        mapIt->second->erase(setIt);
      }
      (*bi)->mergeHead(adjBlock);
    }
  }
  _blocks.clear();
  for (BlockIterator bi = mergeList.begin(); bi != mergeList.end(); ++bi)
  {
    if ((*bi)->getNumSegments() > 0)
    {
      _blocks.push_back(*bi);
    }
  }
}

void LodGraph::optimizeByInsertion()
{
  vector<LodBlock*> newBlocks;
  BlockIterator startPoint = _blocks.begin();
  // seems more convoluted than necessary but I had problems with ?iterators?
  // doing it more simply.
  while (startPoint != _blocks.end())
  {
    newBlocks.clear();
    for (BlockIterator bi = _blocks.begin(); bi != _blocks.end(); ++bi)
    {
      (*bi)->insertNeighbours(newBlocks);
    }
    startPoint = _blocks.end();
    --startPoint;
    _blocks.insert(_blocks.end(), newBlocks.begin(), newBlocks.end());

    // need to get the new segments into the sorted structure too!
    for (BlockIterator bi = newBlocks.begin(); bi != newBlocks.end(); ++bi)
    {
      for (hal_size_t i = 0; i < (*bi)->getNumSegments(); ++i)
      {
        // blah - need to clean interface but this is harmless for now
        LodSegment* seg = const_cast<LodSegment*>((*bi)->getSegment(i));
        _seqMap.find(seg->getSequence())->second->insert(seg);
      }
    }
    ++startPoint;
  }
}

void LodGraph::printDimensions(ostream& os) const
{
  hal_size_t totalSegments = 0;
  hal_size_t maxSegments = 0;
  hal_size_t minSegments = numeric_limits<hal_size_t>::max();

  hal_size_t totalLength = 0;
  hal_size_t maxLength = 0;
  hal_size_t minLength = numeric_limits<hal_size_t>::max();

  hal_size_t totalAdjLength = 0;
  hal_size_t maxAdjLength = 0;
  hal_size_t minAdjLength = numeric_limits<hal_size_t>::max();

  for (BlockConstIterator bi = _blocks.begin(); bi != _blocks.end(); ++bi)
  {
    totalSegments += (*bi)->getNumSegments();
    maxSegments = std::max(maxSegments, (*bi)->getNumSegments());
    minSegments = std::min(minSegments, (*bi)->getNumSegments());

    totalLength += (*bi)->getLength();
    maxLength = std::max(maxLength, (*bi)->getLength());
    minLength = std::min(minLength, (*bi)->getLength());

    totalAdjLength += (*bi)->getTotalAdjLength();
    maxAdjLength = std::max(maxAdjLength, (*bi)->getTotalAdjLength());
    minAdjLength = std::min(minAdjLength, (*bi)->getTotalAdjLength());
  }

  os << "Graph: numBlocks=" << _blocks.size()
     << " numSegs=" << totalSegments << " minSegs=" << minSegments
     << " maxSegs=" << maxSegments
     << " totLen=" << totalLength << " minLen=" << minLength
     << " maxLen=" << maxLength
     << " totAdjLen=" << totalAdjLength << " minAdjLen=" << minAdjLength
     << " maxAdjLen=" << maxAdjLength
     << endl;
}

bool LodGraph::checkCoverage() const
{
  map<const Genome*, vector<bool>* > covMap;
  pair<const Genome*, vector<bool>* > covPair;
  map<const Genome*, vector<bool>* >::iterator covMapIt;
  set<const Genome*>::const_iterator genomeIt;
  bool success = true;

  // create new bit vector for each genome, set all zero
  for (genomeIt = _genomes.begin(); genomeIt != _genomes.end(); ++genomeIt)
  {
    covPair.first = *genomeIt;
    covPair.second = new vector<bool>(covPair.first->getSequenceLength(),
                                      false);
    covMap.insert(covPair);
  }

  // iterate through every segment in every block.
  for (BlockConstIterator bi = _blocks.begin(); bi != _blocks.end() && success;
       ++bi)
  {
    for (hal_size_t segIdx = 0; segIdx < (*bi)->getNumSegments() && success;
         ++ segIdx)
    {
      const LodSegment* segment = (*bi)->getSegment(segIdx);
      const Genome* genome = segment->getSequence()->getGenome();
      covMapIt = covMap.find(genome);
      assert(covMapIt != covMap.end());
      assert(segment->getLeftPos() <= segment->getRightPos());
      for (hal_index_t pos = segment->getLeftPos();
           pos <= segment->getRightPos(); ++pos)
      {
        assert(pos < (hal_index_t)genome->getSequenceLength());
        if (covMapIt->second->at(pos) == true)
        {
          cerr << "dupcliate coverage found at position " << pos << " in"
               << " genome " << genome->getName() << " offending block:\n"
               << **bi << endl;
          success = false;
        }
        covMapIt->second->at(pos) = true;
      }
    }
  }

  // check the coverage and clean up
  for (covMapIt = covMap.begin(); covMapIt != covMap.end(); ++covMapIt)
  {
    for (hal_size_t i = 0; i < covMapIt->second->size() && success; ++i)
    {
      if (covMapIt->second->at(i) != true)
      {
        if (success == true)
        {
          cerr << "coverage gap found at position " << i << " in"
               << " genome " << covMapIt->first->getName() << endl;
        }
        success = false;
      }
    }
    delete covMapIt->second;
  }
  return success;
}
<commit_msg>change canAdd heuristic to use the highest delta in the column instead of the lowest.  also check agains half stepsize.<commit_after>/*
 * Copyright (C) 2013 by Glenn Hickey (hickey@soe.ucsc.edu)
 *
 * Released under the MIT license, see LICENSE.txt
 */

#include <cassert>
#include <limits>
#include <cmath>
#include <algorithm>
#include "halLodGraph.h"

using namespace std;
using namespace hal;

LodGraph::LodGraph() : _extendFraction(1.0)
{

}

LodGraph::~LodGraph()
{
  erase();
}

void LodGraph::erase()
{
  for (SequenceMapIterator smi = _seqMap.begin(); smi != _seqMap.end(); ++smi)
  {
    delete smi->second;
  }
  _seqMap.clear();
  for (BlockIterator bi = _blocks.begin(); bi != _blocks.end(); ++bi)
  {
    delete *bi;
  }
  _blocks.clear();
  _parent = NULL;
  _genomes.clear();
  _telomeres.clear();
}

void LodGraph::build(AlignmentConstPtr alignment, const Genome* parent,
                     const vector<const Genome*>& children,
                     hal_size_t step)
{
  erase();
  _alignment = alignment;
  _parent = parent;
  _step = step;

  assert(_parent != NULL);
  assert(_alignment->openGenome(_parent->getName()) == _parent);

  _genomes.insert(parent);
  for (vector<const Genome*>::const_iterator child = children.begin();
       child != children.end(); ++child)
  {
    _genomes.insert(*child);
  }
  assert(_genomes.size() == children.size() + 1);

  for (set<const Genome*>::iterator gi = _genomes.begin();
       gi != _genomes.end(); ++gi)
  {
    scanGenome(*gi);
  }

  computeAdjacencies();
  printDimensions(cout);
  optimizeByExtension();
  printDimensions(cout);
  optimizeByMerging();
  printDimensions(cout);
  optimizeByInsertion();
  printDimensions(cout);
  assert(checkCoverage() == true);
}

void LodGraph::scanGenome(const Genome* genome)
{
  SequenceIteratorConstPtr seqIt = genome->getSequenceIterator();
  SequenceIteratorConstPtr seqEnd = genome->getSequenceEndIterator();
  for (; seqIt != seqEnd; seqIt->toNext())
  {
    const Sequence* sequence = seqIt->getSequence();
    hal_size_t len = sequence->getSequenceLength();

    addTelomeres(sequence);

    for (hal_index_t pos = 0; pos < (hal_index_t)len; pos += (hal_index_t)_step)
    {
      // clamp to last position
      if (pos > 0 && pos + (hal_index_t)_step >= (hal_index_t)len)
      {
        pos =  (hal_index_t)len - 1;
      }
      // better to move column iterator rather than getting each time?
      // -- probably not because we have to worry about dupe cache
      ColumnIteratorConstPtr colIt =
         sequence->getColumnIterator(&_genomes, 0, pos);
      assert(colIt->getReferenceSequencePosition() == pos);

      // scan up to here trying to find a column we're happy to add
      hal_index_t maxTry = std::min(pos + (hal_index_t)_step / 2,
                               (hal_index_t)len - 1);
      hal_index_t tryPos = NULL_INDEX;
      do
      {
        tryPos = colIt->getReferenceSequencePosition();
        bool canAdd = canAddColumn(colIt);
        if (canAdd)
        {
          createColumn(colIt);
          break;
        }
        colIt->toRight();
      }
      while (colIt->lastColumn() == false && tryPos < maxTry);
    }
  }
}

bool LodGraph::canAddColumn(ColumnIteratorConstPtr colIt)
{
  // check that block has not already been added.
  hal_size_t deltaMax = 0;
  const ColumnIterator::ColumnMap* colMap = colIt->getColumnMap();
  ColumnIterator::ColumnMap::const_iterator colMapIt = colMap->begin();
  bool breakOut = false;
  for (; colMapIt != colMap->end() && !breakOut; ++colMapIt)
  {
    const ColumnIterator::DNASet* dnaSet = colMapIt->second;
    const Sequence* sequence = colMapIt->first;
    ColumnIterator::DNASet::const_iterator dnaIt = dnaSet->begin();
    for (; dnaIt != dnaSet->end() && !breakOut; ++dnaIt)
    {
      hal_index_t pos = (*dnaIt)->getArrayIndex();
      LodSegment segment(NULL, sequence, pos, false);
      SequenceMapIterator smi = _seqMap.find(sequence);
      if (smi != _seqMap.end())
      {
        SegmentSet* segmentSet = smi->second;
        SegmentIterator si = segmentSet->lower_bound(&segment);
        SegmentSet::value_compare segPLess = segmentSet->key_comp();
        if (si == segmentSet->end())
        {
          deltaMax = numeric_limits<hal_size_t>::max();
          breakOut = true;
        }
        else if (!segPLess(&segment, *si))
        {
          assert(deltaMax == 0);
          breakOut = true;
        }
        else
        {
          deltaMax = std::max(deltaMax,
                              (hal_size_t)std::abs((*si)->getLeftPos() -
                                                   segment.getLeftPos()));
          if (si != segmentSet->begin())
          {
            --si;
            deltaMax = std::max(deltaMax,
                                (hal_size_t)std::abs((*si)->getLeftPos() -
                                                     segment.getLeftPos()));
          }
        }
      }
    }
  }
  bool canAdd = deltaMax > 0;
  hal_index_t refPos = colIt->getReferenceSequencePosition();
  if (canAdd == true && refPos != 0 && (hal_size_t)refPos !=
      colIt->getReferenceSequence()->getSequenceLength())
  {
    canAdd = deltaMax  >= _step / 2;

    // other heuristics here?
  }
  if (!canAdd) cout << deltaMax << "\n";
  return canAdd;
}

void LodGraph::addTelomeres(const Sequence* sequence)
{
  SequenceMapIterator smi = _seqMap.find(sequence);
  SegmentSet* segSet = NULL;
  if (smi == _seqMap.end())
  {
    segSet = new SegmentSet();;
    _seqMap.insert(pair<const Sequence*, SegmentSet*>(sequence, segSet));
  }
  else
  {
    segSet = smi->second;
  }

  LodSegment* segment = new LodSegment(&_telomeres, sequence,
                                       sequence->getStartPosition() - 1,
                                       false);
  _telomeres.addSegment(segment);
  segSet->insert(segment);
  segment = new LodSegment(&_telomeres, sequence,
                           sequence->getEndPosition() + 1, false);
  _telomeres.addSegment(segment);
  segSet->insert(segment);
}

void LodGraph::createColumn(ColumnIteratorConstPtr colIt)
{
  LodBlock* block = new LodBlock();
  const ColumnIterator::ColumnMap* colMap = colIt->getColumnMap();
  ColumnIterator::ColumnMap::const_iterator colMapIt = colMap->begin();
  for (; colMapIt != colMap->end(); ++colMapIt)
  {
    const Sequence* sequence = colMapIt->first;
    SequenceMapIterator smi = _seqMap.find(sequence);
    SegmentSet* segSet = NULL;
    if (smi == _seqMap.end())
    {
      segSet = new SegmentSet();;
      _seqMap.insert(pair<const Sequence*, SegmentSet*>(sequence, segSet));
    }
    else
    {
      segSet = smi->second;
    }

    const ColumnIterator::DNASet* dnaSet = colMapIt->second;
    for (ColumnIterator::DNASet::const_iterator dnaIt = dnaSet->begin();
         dnaIt != dnaSet->end(); ++ dnaIt)
    {
      hal_index_t pos = (*dnaIt)->getArrayIndex();
      bool reversed = (*dnaIt)->getReversed();
      LodSegment* segment = new LodSegment(block, sequence, pos, reversed);
      block->addSegment(segment);
      assert(segSet->find(segment) == segSet->end());
      segSet->insert(segment);
    }
  }
  assert(block->getNumSegments() > 0);
  _blocks.push_back(block);
}

void LodGraph::computeAdjacencies()
{
  for (SequenceMapIterator smi = _seqMap.begin(); smi != _seqMap.end(); ++smi)
  {
    SegmentIterator si = smi->second->begin();
    SegmentIterator siNext;
    for (; si != smi->second->end(); ++si)
    {
      siNext = si;
      ++siNext;
      if (siNext != smi->second->end())
      {
        assert((*si)->overlaps(**siNext) == false);
        (*si)->addEdgeFromRightToLeft(*siNext);
      }
    }
  }
}

void LodGraph::optimizeByExtension()
{
  // Put bigger blocks first because (we hope) they tend to represent
  // more information and we'd rather extend them than, say, a block
  // that represents a little insertion.
  std::sort(_blocks.begin(), _blocks.end(), LodBlockPBigger());

  // Pass 1: Extend all blocks with at least 2 sequences by half
  for (BlockIterator bi = _blocks.begin(); bi != _blocks.end() &&
          (*bi)->getNumSegments() > 1; ++bi)
  {
    (*bi)->extend(0.5);
  }

  // Pass 2: Greedily extend each block to the max
  for (BlockIterator bi = _blocks.begin(); bi != _blocks.end(); ++bi)
  {
    (*bi)->extend();
  }

}

void LodGraph::optimizeByMerging()
{
  BlockList mergeList(_blocks);
  for (BlockIterator bi = mergeList.begin(); bi != mergeList.end(); ++bi)
  {
    LodBlock* adjBlock = (*bi)->getHeadMergePartner();
    if (adjBlock != NULL)
    {
      for (hal_size_t segIdx = 0; segIdx < adjBlock->getNumSegments(); ++segIdx)
      {
        // blah - need to clean interface but this is harmless for now
        LodSegment* seg = const_cast<LodSegment*>(
          adjBlock->getSegment(segIdx));
        SequenceMapIterator mapIt = _seqMap.find(seg->getSequence());
        assert(mapIt != _seqMap.end());
        SegmentIterator setIt = mapIt->second->find(seg);
        assert(setIt != mapIt->second->end());
        assert(*setIt == seg);
        mapIt->second->erase(setIt);
      }
      (*bi)->mergeHead(adjBlock);
    }
  }
  _blocks.clear();
  for (BlockIterator bi = mergeList.begin(); bi != mergeList.end(); ++bi)
  {
    if ((*bi)->getNumSegments() > 0)
    {
      _blocks.push_back(*bi);
    }
  }
}

void LodGraph::optimizeByInsertion()
{
  vector<LodBlock*> newBlocks;
  BlockIterator startPoint = _blocks.begin();
  // seems more convoluted than necessary but I had problems with ?iterators?
  // doing it more simply.
  while (startPoint != _blocks.end())
  {
    newBlocks.clear();
    for (BlockIterator bi = _blocks.begin(); bi != _blocks.end(); ++bi)
    {
      (*bi)->insertNeighbours(newBlocks);
    }
    startPoint = _blocks.end();
    --startPoint;
    _blocks.insert(_blocks.end(), newBlocks.begin(), newBlocks.end());

    // need to get the new segments into the sorted structure too!
    for (BlockIterator bi = newBlocks.begin(); bi != newBlocks.end(); ++bi)
    {
      for (hal_size_t i = 0; i < (*bi)->getNumSegments(); ++i)
      {
        // blah - need to clean interface but this is harmless for now
        LodSegment* seg = const_cast<LodSegment*>((*bi)->getSegment(i));
        _seqMap.find(seg->getSequence())->second->insert(seg);
      }
    }
    ++startPoint;
  }
}

void LodGraph::printDimensions(ostream& os) const
{
  hal_size_t totalSegments = 0;
  hal_size_t maxSegments = 0;
  hal_size_t minSegments = numeric_limits<hal_size_t>::max();

  hal_size_t totalLength = 0;
  hal_size_t maxLength = 0;
  hal_size_t minLength = numeric_limits<hal_size_t>::max();

  hal_size_t totalAdjLength = 0;
  hal_size_t maxAdjLength = 0;
  hal_size_t minAdjLength = numeric_limits<hal_size_t>::max();

  for (BlockConstIterator bi = _blocks.begin(); bi != _blocks.end(); ++bi)
  {
    totalSegments += (*bi)->getNumSegments();
    maxSegments = std::max(maxSegments, (*bi)->getNumSegments());
    minSegments = std::min(minSegments, (*bi)->getNumSegments());

    totalLength += (*bi)->getLength();
    maxLength = std::max(maxLength, (*bi)->getLength());
    minLength = std::min(minLength, (*bi)->getLength());

    totalAdjLength += (*bi)->getTotalAdjLength();
    maxAdjLength = std::max(maxAdjLength, (*bi)->getTotalAdjLength());
    minAdjLength = std::min(minAdjLength, (*bi)->getTotalAdjLength());
  }

  os << "Graph: numBlocks=" << _blocks.size()
     << " numSegs=" << totalSegments << " minSegs=" << minSegments
     << " maxSegs=" << maxSegments
     << " totLen=" << totalLength << " minLen=" << minLength
     << " maxLen=" << maxLength
     << " totAdjLen=" << totalAdjLength << " minAdjLen=" << minAdjLength
     << " maxAdjLen=" << maxAdjLength
     << endl;
}

bool LodGraph::checkCoverage() const
{
  map<const Genome*, vector<bool>* > covMap;
  pair<const Genome*, vector<bool>* > covPair;
  map<const Genome*, vector<bool>* >::iterator covMapIt;
  set<const Genome*>::const_iterator genomeIt;
  bool success = true;

  // create new bit vector for each genome, set all zero
  for (genomeIt = _genomes.begin(); genomeIt != _genomes.end(); ++genomeIt)
  {
    covPair.first = *genomeIt;
    covPair.second = new vector<bool>(covPair.first->getSequenceLength(),
                                      false);
    covMap.insert(covPair);
  }

  // iterate through every segment in every block.
  for (BlockConstIterator bi = _blocks.begin(); bi != _blocks.end() && success;
       ++bi)
  {
    for (hal_size_t segIdx = 0; segIdx < (*bi)->getNumSegments() && success;
         ++ segIdx)
    {
      const LodSegment* segment = (*bi)->getSegment(segIdx);
      const Genome* genome = segment->getSequence()->getGenome();
      covMapIt = covMap.find(genome);
      assert(covMapIt != covMap.end());
      assert(segment->getLeftPos() <= segment->getRightPos());
      for (hal_index_t pos = segment->getLeftPos();
           pos <= segment->getRightPos(); ++pos)
      {
        assert(pos < (hal_index_t)genome->getSequenceLength());
        if (covMapIt->second->at(pos) == true)
        {
          cerr << "dupcliate coverage found at position " << pos << " in"
               << " genome " << genome->getName() << " offending block:\n"
               << **bi << endl;
          success = false;
        }
        covMapIt->second->at(pos) = true;
      }
    }
  }

  // check the coverage and clean up
  for (covMapIt = covMap.begin(); covMapIt != covMap.end(); ++covMapIt)
  {
    for (hal_size_t i = 0; i < covMapIt->second->size() && success; ++i)
    {
      if (covMapIt->second->at(i) != true)
      {
        if (success == true)
        {
          cerr << "coverage gap found at position " << i << " in"
               << " genome " << covMapIt->first->getName() << endl;
        }
        success = false;
      }
    }
    delete covMapIt->second;
  }
  return success;
}
<|endoftext|>


<commit_before>/*
 * This file is part of the statismo library.
 *
 * Author: Marcel Luethi (marcel.luethi@unibas.ch)
 *
 * Copyright (c) 2011 University of Basel
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 *
 * Neither the name of the project's author nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

#ifndef __HDF5_UTILS_CXX
#define __HDF5_UTILS_CXX

#include "HDF5Utils.h"
#include "CommonTypes.h"
#include "Exceptions.h"
#include "H5Cpp.h"
#include <fstream>
#include <iostream>
#include <algorithm>
#include <fstream>
#include <iterator>

namespace statismo {

using namespace H5;

inline
void HDF5Utils::readMatrix(const H5::CommonFG& fg, const char* name, MatrixType& matrix) {
	DataSet ds = fg.openDataSet( name );
	hsize_t dims[2];
	ds.getSpace().getSimpleExtentDims(dims, NULL);

	// simply read the whole dataspace
	matrix.resize(dims[0], dims[1]);
	ds.read(matrix.data(), H5::PredType::NATIVE_FLOAT);
}

inline
void HDF5Utils::readMatrix(const H5::CommonFG& fg, const char* name, unsigned maxNumColumns, MatrixType& matrix) {
	DataSet ds = fg.openDataSet( name );
	hsize_t dims[2];
	ds.getSpace().getSimpleExtentDims(dims, NULL);

	hsize_t nRows = dims[0]; // take the number of rows defined in the hdf5 file
	hsize_t nCols = std::min(dims[1], static_cast<hsize_t>(maxNumColumns)); // take the number of cols provided by the user

	hsize_t offset[2] = {0,0};   // hyperslab offset in the file
	hsize_t count[2];
	count[0] = nRows; count[1] =  nCols;

	DataSpace dataspace = ds.getSpace();
	dataspace.selectHyperslab( H5S_SELECT_SET, count, offset );

	/* Define the memory dataspace. */
	hsize_t     dimsm[2];
	dimsm[0] = nRows; dimsm[1] = nCols;
	DataSpace memspace( 2, dimsm );

	/* Define memory hyperslab. */
	hsize_t      offset_out[2] = {0, 0};       // hyperslab offset in memory
	hsize_t      count_out[2];        // size of the hyperslab in memory

	count_out[0]  = nRows; count_out[1] = nCols;
	memspace.selectHyperslab( H5S_SELECT_SET, count_out, offset_out );

	matrix.resize(nRows, nCols);
	ds.read(matrix.data(), H5::PredType::NATIVE_FLOAT, memspace, dataspace);

}

inline
void HDF5Utils::writeMatrix(const H5::CommonFG& fg, const char* name, const MatrixType& matrix) {
	// HDF5 does not like empty matrices.
	//
	if (matrix.rows() == 0 || matrix.cols() == 0) {
		throw StatisticalModelException("Empty matrix provided to writeMatrix");
	}

	hsize_t dims[2] = {matrix.rows(), matrix.cols()};
	DataSet ds = fg.createDataSet( name, H5::PredType::NATIVE_FLOAT, DataSpace(2, dims));
	ds.write( matrix.data(), H5::PredType::NATIVE_FLOAT );
}

inline
void HDF5Utils::readVector(const H5::CommonFG& fg, const char* name, VectorType& vector) {
	DataSet ds = fg.openDataSet( name );
	hsize_t dims[1];
	ds.getSpace().getSimpleExtentDims(dims, NULL);
	vector.resize(dims[0], 1);
	ds.read(vector.data(), H5::PredType::NATIVE_FLOAT);
}

inline
void HDF5Utils::readVector(const H5::CommonFG& fg, const char* name, unsigned maxNumElements, VectorType& vector) {
	DataSet ds = fg.openDataSet( name );
	hsize_t dims[1];
	ds.getSpace().getSimpleExtentDims(dims, NULL);

	hsize_t nElements = std::min(dims[0], static_cast<hsize_t>(maxNumElements)); // take the number of rows defined in the hdf5 file

	hsize_t offset[1] = {0};   // hyperslab offset in the file
	hsize_t count[1];
	count[0] = nElements;

	DataSpace dataspace = ds.getSpace();
	dataspace.selectHyperslab( H5S_SELECT_SET, count, offset );

	/* Define the memory dataspace. */
	hsize_t     dimsm[1];
	dimsm[0] = nElements;
	DataSpace memspace( 1, dimsm );

	/* Define memory hyperslab. */
	hsize_t      offset_out[1] = {0};       // hyperslab offset in memory
	hsize_t      count_out[1];        // size of the hyperslab in memory

	count_out[0]  = nElements;
	memspace.selectHyperslab( H5S_SELECT_SET, count_out, offset_out );

	vector.resize(nElements);
	ds.read(vector.data(), H5::PredType::NATIVE_FLOAT, memspace, dataspace);
}

inline
void HDF5Utils::writeVector(const H5::CommonFG& fg, const char* name, const VectorType& vector) {
	hsize_t dims[1] = {vector.size()};
	DataSet ds = fg.createDataSet( name, H5::PredType::NATIVE_FLOAT, DataSpace(1, dims));
	ds.write( vector.data(), H5::PredType::NATIVE_FLOAT );

}

inline
void HDF5Utils::writeString(const H5::CommonFG& fg, const char* name, const std::string& s) {
	StrType fls_type(0, s.length()); // 0 is a dummy argument
	DataSet ds = fg.createDataSet(name, fls_type, DataSpace(H5S_SCALAR));
	ds.write(s.data(), fls_type);
}

inline
std::string
HDF5Utils::readString(const H5::CommonFG& fg, const char* name) {
	StrType strdatatype(PredType::C_S1, 256);
	char strreadbuf[256];
	DataSet ds = fg.openDataSet(name);
	ds.read(strreadbuf, strdatatype);
	return std::string(strreadbuf);
}

inline
void HDF5Utils::writeStringAttribute(const H5::Group& fg, const char* name, const std::string& s) {
	StrType strdatatype(PredType::C_S1, 256);
	Attribute att = fg.createAttribute(name, strdatatype, DataSpace(H5S_SCALAR));
	att.write(strdatatype, s.data());
	att.close();
}

inline
std::string
HDF5Utils::readStringAttribute(const H5::Group& fg, const char* name) {
	StrType strdatatype(PredType::C_S1, 256);
	char strreadbuf[256];
	Attribute myatt_out = fg.openAttribute(name);
	myatt_out.read(strdatatype, strreadbuf);
	return std::string(strreadbuf);
}

inline
void HDF5Utils::writeInt(const H5::CommonFG& fg, const char* name, int value) {
	IntType fls_type(PredType::NATIVE_INT32); // 0 is a dummy argument
	DataSet ds = fg.createDataSet(name, fls_type, DataSpace(H5S_SCALAR));
	ds.write(&value, fls_type);
}

inline
int HDF5Utils::readInt(const H5::CommonFG& fg, const char* name) {
	IntType fls_type(PredType::NATIVE_INT32);
	DataSet ds = fg.openDataSet( name );

	int value = 0;
	ds.read(&value, fls_type);
	return value;
}

inline
void HDF5Utils::writeFloat(const H5::CommonFG& fg, const char* name, float value) {
	FloatType fls_type(PredType::NATIVE_FLOAT); // 0 is a dummy argument
	DataSet ds = fg.createDataSet(name, fls_type, DataSpace(H5S_SCALAR));
	ds.write(&value, fls_type);
}

inline
float HDF5Utils::readFloat(const H5::CommonFG& fg, const char* name) {
	FloatType fls_type(PredType::NATIVE_FLOAT);
	DataSet ds = fg.openDataSet( name );

	float value = 0;
	ds.read(&value, fls_type);
	return value;
}

inline
void HDF5Utils::getFileFromHDF5(const H5::CommonFG& fg, const char* name, const char* filename) {
	DataSet ds = fg.openDataSet( name );
	hsize_t dims[1];
	ds.getSpace().getSimpleExtentDims(dims, NULL);
	std::vector<char> buffer(dims[0]);
	if(!buffer.empty()) ds.read(&buffer[0], H5::PredType::NATIVE_CHAR);

	typedef std::ostream_iterator<char> ostream_iterator;
	std::ofstream ofile(filename, std::ios::binary);
	if (!ofile) {
		std::string s= std::string("could not open file ") +filename;
		throw StatisticalModelException(s.c_str());
	}

	std::copy(buffer.begin(), buffer.end(), ostream_iterator(ofile));
	ofile.close();
}

inline
void
HDF5Utils::dumpFileToHDF5( const char* filename, const H5::CommonFG& fg, const char* name) {

	typedef std::istream_iterator<char> istream_iterator;

	std::ifstream ifile(filename, std::ios::binary);
	if (!ifile) {
		std::string s= std::string("could not open file ") +filename;
		throw StatisticalModelException(s.c_str());
	}

	std::vector<char> buffer;
	ifile >> std::noskipws;
	std::copy(istream_iterator(ifile), istream_iterator(), std::back_inserter(buffer));

	ifile.close();

	hsize_t dims[] = {buffer.size()};
	DataSet ds = fg.createDataSet( name,  H5::PredType::NATIVE_CHAR, DataSpace(1, dims));
	ds.write( &buffer[0], H5::PredType::NATIVE_CHAR );

}

} //namespace statismo

#endif
<commit_msg>simplified HDF5Utils::ReadString and HDF5Utils::ReadStringAttributes<commit_after>/*
 * This file is part of the statismo library.
 *
 * Author: Marcel Luethi (marcel.luethi@unibas.ch)
 *
 * Copyright (c) 2011 University of Basel
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 *
 * Neither the name of the project's author nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

#ifndef __HDF5_UTILS_CXX
#define __HDF5_UTILS_CXX

#include "HDF5Utils.h"
#include "CommonTypes.h"
#include "Exceptions.h"
#include "H5Cpp.h"
#include <fstream>
#include <iostream>
#include <algorithm>
#include <fstream>
#include <iterator>

namespace statismo {

using namespace H5;

inline
void HDF5Utils::readMatrix(const H5::CommonFG& fg, const char* name, MatrixType& matrix) {
	DataSet ds = fg.openDataSet( name );
	hsize_t dims[2];
	ds.getSpace().getSimpleExtentDims(dims, NULL);

	// simply read the whole dataspace
	matrix.resize(dims[0], dims[1]);
	ds.read(matrix.data(), H5::PredType::NATIVE_FLOAT);
}

inline
void HDF5Utils::readMatrix(const H5::CommonFG& fg, const char* name, unsigned maxNumColumns, MatrixType& matrix) {
	DataSet ds = fg.openDataSet( name );
	hsize_t dims[2];
	ds.getSpace().getSimpleExtentDims(dims, NULL);

	hsize_t nRows = dims[0]; // take the number of rows defined in the hdf5 file
	hsize_t nCols = std::min(dims[1], static_cast<hsize_t>(maxNumColumns)); // take the number of cols provided by the user

	hsize_t offset[2] = {0,0};   // hyperslab offset in the file
	hsize_t count[2];
	count[0] = nRows; count[1] =  nCols;

	DataSpace dataspace = ds.getSpace();
	dataspace.selectHyperslab( H5S_SELECT_SET, count, offset );

	/* Define the memory dataspace. */
	hsize_t     dimsm[2];
	dimsm[0] = nRows; dimsm[1] = nCols;
	DataSpace memspace( 2, dimsm );

	/* Define memory hyperslab. */
	hsize_t      offset_out[2] = {0, 0};       // hyperslab offset in memory
	hsize_t      count_out[2];        // size of the hyperslab in memory

	count_out[0]  = nRows; count_out[1] = nCols;
	memspace.selectHyperslab( H5S_SELECT_SET, count_out, offset_out );

	matrix.resize(nRows, nCols);
	ds.read(matrix.data(), H5::PredType::NATIVE_FLOAT, memspace, dataspace);

}

inline
void HDF5Utils::writeMatrix(const H5::CommonFG& fg, const char* name, const MatrixType& matrix) {
	// HDF5 does not like empty matrices.
	//
	if (matrix.rows() == 0 || matrix.cols() == 0) {
		throw StatisticalModelException("Empty matrix provided to writeMatrix");
	}

	hsize_t dims[2] = {matrix.rows(), matrix.cols()};
	DataSet ds = fg.createDataSet( name, H5::PredType::NATIVE_FLOAT, DataSpace(2, dims));
	ds.write( matrix.data(), H5::PredType::NATIVE_FLOAT );
}

inline
void HDF5Utils::readVector(const H5::CommonFG& fg, const char* name, VectorType& vector) {
	DataSet ds = fg.openDataSet( name );
	hsize_t dims[1];
	ds.getSpace().getSimpleExtentDims(dims, NULL);
	vector.resize(dims[0], 1);
	ds.read(vector.data(), H5::PredType::NATIVE_FLOAT);
}

inline
void HDF5Utils::readVector(const H5::CommonFG& fg, const char* name, unsigned maxNumElements, VectorType& vector) {
	DataSet ds = fg.openDataSet( name );
	hsize_t dims[1];
	ds.getSpace().getSimpleExtentDims(dims, NULL);

	hsize_t nElements = std::min(dims[0], static_cast<hsize_t>(maxNumElements)); // take the number of rows defined in the hdf5 file

	hsize_t offset[1] = {0};   // hyperslab offset in the file
	hsize_t count[1];
	count[0] = nElements;

	DataSpace dataspace = ds.getSpace();
	dataspace.selectHyperslab( H5S_SELECT_SET, count, offset );

	/* Define the memory dataspace. */
	hsize_t     dimsm[1];
	dimsm[0] = nElements;
	DataSpace memspace( 1, dimsm );

	/* Define memory hyperslab. */
	hsize_t      offset_out[1] = {0};       // hyperslab offset in memory
	hsize_t      count_out[1];        // size of the hyperslab in memory

	count_out[0]  = nElements;
	memspace.selectHyperslab( H5S_SELECT_SET, count_out, offset_out );

	vector.resize(nElements);
	ds.read(vector.data(), H5::PredType::NATIVE_FLOAT, memspace, dataspace);
}

inline
void HDF5Utils::writeVector(const H5::CommonFG& fg, const char* name, const VectorType& vector) {
	hsize_t dims[1] = {vector.size()};
	DataSet ds = fg.createDataSet( name, H5::PredType::NATIVE_FLOAT, DataSpace(1, dims));
	ds.write( vector.data(), H5::PredType::NATIVE_FLOAT );

}

inline
void HDF5Utils::writeString(const H5::CommonFG& fg, const char* name, const std::string& s) {
	StrType fls_type(0, s.length()); // 0 is a dummy argument
	DataSet ds = fg.createDataSet(name, fls_type, DataSpace(H5S_SCALAR));
	ds.write(s, fls_type);
}

inline
std::string
HDF5Utils::readString(const H5::CommonFG& fg, const char* name) {
    H5std_string outputString;
    DataSet ds = fg.openDataSet(name);
    ds.read(outputString, ds.getStrType());
    return outputString;
}

inline
void HDF5Utils::writeStringAttribute(const H5::Group& fg, const char* name, const std::string& s) {
	StrType strdatatype(0, s.length());
	Attribute att = fg.createAttribute(name, strdatatype, DataSpace(H5S_SCALAR));
	att.write(strdatatype, s);
	att.close();
}

inline
std::string
HDF5Utils::readStringAttribute(const H5::Group& fg, const char* name) {
	H5std_string outputString;

	Attribute myatt_out = fg.openAttribute(name);
	myatt_out.read(myatt_out.getStrType(), outputString);
	return outputString;
}

inline
void HDF5Utils::writeInt(const H5::CommonFG& fg, const char* name, int value) {
	IntType fls_type(PredType::NATIVE_INT32); // 0 is a dummy argument
	DataSet ds = fg.createDataSet(name, fls_type, DataSpace(H5S_SCALAR));
	ds.write(&value, fls_type);
}

inline
int HDF5Utils::readInt(const H5::CommonFG& fg, const char* name) {
	IntType fls_type(PredType::NATIVE_INT32);
	DataSet ds = fg.openDataSet( name );

	int value = 0;
	ds.read(&value, fls_type);
	return value;
}

inline
void HDF5Utils::writeFloat(const H5::CommonFG& fg, const char* name, float value) {
	FloatType fls_type(PredType::NATIVE_FLOAT); // 0 is a dummy argument
	DataSet ds = fg.createDataSet(name, fls_type, DataSpace(H5S_SCALAR));
	ds.write(&value, fls_type);
}

inline
float HDF5Utils::readFloat(const H5::CommonFG& fg, const char* name) {
	FloatType fls_type(PredType::NATIVE_FLOAT);
	DataSet ds = fg.openDataSet( name );

	float value = 0;
	ds.read(&value, fls_type);
	return value;
}

inline
void HDF5Utils::getFileFromHDF5(const H5::CommonFG& fg, const char* name, const char* filename) {
	DataSet ds = fg.openDataSet( name );
	hsize_t dims[1];
	ds.getSpace().getSimpleExtentDims(dims, NULL);
	std::vector<char> buffer(dims[0]);
	if(!buffer.empty()) ds.read(&buffer[0], H5::PredType::NATIVE_CHAR);

	typedef std::ostream_iterator<char> ostream_iterator;
	std::ofstream ofile(filename, std::ios::binary);
	if (!ofile) {
		std::string s= std::string("could not open file ") +filename;
		throw StatisticalModelException(s.c_str());
	}

	std::copy(buffer.begin(), buffer.end(), ostream_iterator(ofile));
	ofile.close();
}

inline
void
HDF5Utils::dumpFileToHDF5( const char* filename, const H5::CommonFG& fg, const char* name) {

	typedef std::istream_iterator<char> istream_iterator;

	std::ifstream ifile(filename, std::ios::binary);
	if (!ifile) {
		std::string s= std::string("could not open file ") +filename;
		throw StatisticalModelException(s.c_str());
	}

	std::vector<char> buffer;
	ifile >> std::noskipws;
	std::copy(istream_iterator(ifile), istream_iterator(), std::back_inserter(buffer));

	ifile.close();

	hsize_t dims[] = {buffer.size()};
	DataSet ds = fg.createDataSet( name,  H5::PredType::NATIVE_CHAR, DataSpace(1, dims));
	ds.write( &buffer[0], H5::PredType::NATIVE_CHAR );

}

} //namespace statismo

#endif
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "rtp_sender_video.h"

#include "critical_section_wrapper.h"
#include "trace.h"

#include "rtp_utility.h"

#include <string.h> // memcpy
#include <cassert>  // assert
#include <cstdlib>  // srand

#include "producer_fec.h"
#include "rtp_format_vp8.h"

namespace webrtc {
enum { REDForFECHeaderLength = 1 };

struct RtpPacket {
  WebRtc_UWord16 rtpHeaderLength;
  ForwardErrorCorrection::Packet* pkt;
};

RTPSenderVideo::RTPSenderVideo(const WebRtc_Word32 id,
                               RtpRtcpClock* clock,
                               RTPSenderInterface* rtpSender) :
    _id(id),
    _rtpSender(*rtpSender),
    _sendVideoCritsect(CriticalSectionWrapper::CreateCriticalSection()),

    _videoType(kRtpNoVideo),
    _videoCodecInformation(NULL),
    _maxBitrate(0),
    _retransmissionSettings(kRetransmitBaseLayer),

    // Generic FEC
    _fec(id),
    _fecEnabled(false),
    _payloadTypeRED(-1),
    _payloadTypeFEC(-1),
    _numberFirstPartition(0),
    delta_fec_params_(),
    key_fec_params_(),
    producer_fec_(&_fec),
    _fecOverheadRate(clock),
    _videoBitrate(clock) {
  memset(&delta_fec_params_, 0, sizeof(delta_fec_params_));
  memset(&key_fec_params_, 0, sizeof(key_fec_params_));
  delta_fec_params_.max_fec_frames = key_fec_params_.max_fec_frames = 1;
}

RTPSenderVideo::~RTPSenderVideo()
{
    if(_videoCodecInformation)
    {
        delete _videoCodecInformation;
    }
    delete _sendVideoCritsect;
}

void
RTPSenderVideo::SetVideoCodecType(RtpVideoCodecTypes videoType)
{
    CriticalSectionScoped cs(_sendVideoCritsect);
    _videoType = videoType;
}

RtpVideoCodecTypes
RTPSenderVideo::VideoCodecType() const
{
    return _videoType;
}

WebRtc_Word32 RTPSenderVideo::RegisterVideoPayload(
    const char payloadName[RTP_PAYLOAD_NAME_SIZE],
    const WebRtc_Word8 payloadType,
    const WebRtc_UWord32 maxBitRate,
    ModuleRTPUtility::Payload*& payload) {
  CriticalSectionScoped cs(_sendVideoCritsect);

  RtpVideoCodecTypes videoType = kRtpNoVideo;
  if (ModuleRTPUtility::StringCompare(payloadName, "VP8",3)) {
    videoType = kRtpVp8Video;
  } else if (ModuleRTPUtility::StringCompare(payloadName, "I420", 4)) {
    videoType = kRtpNoVideo;
  } else {
    return -1;
  }
  payload = new ModuleRTPUtility::Payload;
  payload->name[RTP_PAYLOAD_NAME_SIZE - 1] = 0;
  strncpy(payload->name, payloadName, RTP_PAYLOAD_NAME_SIZE - 1);
  payload->typeSpecific.Video.videoCodecType = videoType;
  payload->typeSpecific.Video.maxRate = maxBitRate;
  payload->audio = false;
  return 0;
}

WebRtc_Word32
RTPSenderVideo::SendVideoPacket(const WebRtc_UWord8* data_buffer,
                                const WebRtc_UWord16 payload_length,
                                const WebRtc_UWord16 rtp_header_length,
                                StorageType storage,
                                bool protect) {
  if(_fecEnabled) {
    int ret = 0;
    int fec_overhead_sent = 0;
    int video_sent = 0;

    RedPacket* red_packet = producer_fec_.BuildRedPacket(data_buffer,
                                                         payload_length,
                                                         rtp_header_length,
                                                         _payloadTypeRED);
    // Sending the media packet with RED header.
    int packet_success = _rtpSender.SendToNetwork(
        red_packet->data(),
        red_packet->length() - rtp_header_length,
        rtp_header_length,
        storage);

    ret |= packet_success;

    if (packet_success == 0) {
      video_sent += red_packet->length();
    }
    delete red_packet;
    red_packet = NULL;

    if (protect) {
      ret = producer_fec_.AddRtpPacketAndGenerateFec(data_buffer,
                                                     payload_length,
                                                     rtp_header_length);
      if (ret != 0)
        return ret;
    }

    while (producer_fec_.FecAvailable()) {
      red_packet = producer_fec_.GetFecPacket(
          _payloadTypeRED,
          _payloadTypeFEC,
          _rtpSender.IncrementSequenceNumber());
      StorageType storage = kDontRetransmit;
      if (_retransmissionSettings & kRetransmitFECPackets) {
        storage = kAllowRetransmission;
      }
      // Sending FEC packet with RED header.
      int packet_success = _rtpSender.SendToNetwork(
          red_packet->data(),
          red_packet->length() - rtp_header_length,
          rtp_header_length,
          storage);

      ret |= packet_success;

      if (packet_success == 0) {
        fec_overhead_sent += red_packet->length();
      }
      delete red_packet;
      red_packet = NULL;
    }
    _videoBitrate.Update(video_sent);
    _fecOverheadRate.Update(fec_overhead_sent);
    return ret;
  }
  int ret = _rtpSender.SendToNetwork(data_buffer,
                                     payload_length,
                                     rtp_header_length,
                                     storage);
  if (ret == 0) {
    _videoBitrate.Update(payload_length + rtp_header_length);
  }
  return ret;
}

WebRtc_Word32
RTPSenderVideo::SendRTPIntraRequest()
{
    // RFC 2032
    // 5.2.1.  Full intra-frame Request (FIR) packet

    WebRtc_UWord16 length = 8;
    WebRtc_UWord8 data[8];
    data[0] = 0x80;
    data[1] = 192;
    data[2] = 0;
    data[3] = 1; // length

    ModuleRTPUtility::AssignUWord32ToBuffer(data+4, _rtpSender.SSRC());

    return _rtpSender.SendToNetwork(data, 0, length, kAllowRetransmission);
}

WebRtc_Word32
RTPSenderVideo::SetGenericFECStatus(const bool enable,
                                    const WebRtc_UWord8 payloadTypeRED,
                                    const WebRtc_UWord8 payloadTypeFEC)
{
    _fecEnabled = enable;
    _payloadTypeRED = payloadTypeRED;
    _payloadTypeFEC = payloadTypeFEC;
    memset(&delta_fec_params_, 0, sizeof(delta_fec_params_));
    memset(&key_fec_params_, 0, sizeof(key_fec_params_));
    delta_fec_params_.max_fec_frames = key_fec_params_.max_fec_frames = 1;
    return 0;
}

WebRtc_Word32
RTPSenderVideo::GenericFECStatus(bool& enable,
                                 WebRtc_UWord8& payloadTypeRED,
                                 WebRtc_UWord8& payloadTypeFEC) const
{
    enable = _fecEnabled;
    payloadTypeRED = _payloadTypeRED;
    payloadTypeFEC = _payloadTypeFEC;
    return 0;
}

WebRtc_UWord16
RTPSenderVideo::FECPacketOverhead() const
{
    if (_fecEnabled)
    {
        return ForwardErrorCorrection::PacketOverhead() +
            REDForFECHeaderLength;
    }
    return 0;
}

WebRtc_Word32 RTPSenderVideo::SetFecParameters(
    const FecProtectionParams* delta_params,
    const FecProtectionParams* key_params) {
  assert(delta_params);
  assert(key_params);
  delta_fec_params_ = *delta_params;
  key_fec_params_ = *key_params;
  return 0;
}

WebRtc_Word32
RTPSenderVideo::SendVideo(const RtpVideoCodecTypes videoType,
                          const FrameType frameType,
                          const WebRtc_Word8 payloadType,
                          const WebRtc_UWord32 captureTimeStamp,
                          const WebRtc_UWord8* payloadData,
                          const WebRtc_UWord32 payloadSize,
                          const RTPFragmentationHeader* fragmentation,
                          VideoCodecInformation* codecInfo,
                          const RTPVideoTypeHeader* rtpTypeHdr)
{
    if( payloadSize == 0)
    {
        return -1;
    }

    if (frameType == kVideoFrameKey) {
      producer_fec_.SetFecParameters(&key_fec_params_,
                                     _numberFirstPartition);
    } else {
      producer_fec_.SetFecParameters(&delta_fec_params_,
                                     _numberFirstPartition);
    }

    // Default setting for number of first partition packets:
    // Will be extracted in SendVP8 for VP8 codec; other codecs use 0
    _numberFirstPartition = 0;

    WebRtc_Word32 retVal = -1;
    switch(videoType)
    {
    case kRtpNoVideo:
        retVal = SendGeneric(payloadType,captureTimeStamp, payloadData,
                             payloadSize);
        break;
    case kRtpVp8Video:
        retVal = SendVP8(frameType, payloadType, captureTimeStamp,
                payloadData, payloadSize, fragmentation, rtpTypeHdr);
        break;
    default:
        assert(false);
        break;
    }
    if(retVal <= 0)
    {
        return retVal;
    }
    WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, _id, "%s(timestamp:%u)",
                 __FUNCTION__, captureTimeStamp);
    return 0;
}

WebRtc_Word32
RTPSenderVideo::SendGeneric(const WebRtc_Word8 payloadType,
                            const WebRtc_UWord32 captureTimeStamp,
                            const WebRtc_UWord8* payloadData,
                            const WebRtc_UWord32 payloadSize)
{
    WebRtc_UWord16 payloadBytesInPacket = 0;
    WebRtc_UWord32 bytesSent = 0;
    WebRtc_Word32 payloadBytesToSend = payloadSize;

    const WebRtc_UWord8* data = payloadData;
    WebRtc_UWord16 rtpHeaderLength = _rtpSender.RTPHeaderLength();
    WebRtc_UWord16 maxLength = _rtpSender.MaxPayloadLength() -
        FECPacketOverhead() - rtpHeaderLength;
    WebRtc_UWord8 dataBuffer[IP_PACKET_SIZE];

    // Fragment packet into packets of max MaxPayloadLength bytes payload.
    while (payloadBytesToSend > 0)
    {
        if (payloadBytesToSend > maxLength)
        {
            payloadBytesInPacket = maxLength;
            payloadBytesToSend -= payloadBytesInPacket;
            // MarkerBit is 0
            if(_rtpSender.BuildRTPheader(dataBuffer,
                                         payloadType,
                                         false,
                                         captureTimeStamp) != rtpHeaderLength)
            {
                return -1;
           }
        }
        else
        {
            payloadBytesInPacket = (WebRtc_UWord16)payloadBytesToSend;
            payloadBytesToSend = 0;
            // MarkerBit is 1
            if(_rtpSender.BuildRTPheader(dataBuffer, payloadType, true,
                                         captureTimeStamp) != rtpHeaderLength)
            {
                return -1;
            }
        }

        // Put payload in packet
        memcpy(&dataBuffer[rtpHeaderLength], &data[bytesSent],
               payloadBytesInPacket);
        bytesSent += payloadBytesInPacket;

        if(-1 == SendVideoPacket(dataBuffer,
                                 payloadBytesInPacket,
                                 rtpHeaderLength,
                                 kAllowRetransmission,
                                 true))
        {
            return -1;
        }
    }
    return 0;
}

VideoCodecInformation*
RTPSenderVideo::CodecInformationVideo()
{
    return _videoCodecInformation;
}

void
RTPSenderVideo::SetMaxConfiguredBitrateVideo(const WebRtc_UWord32 maxBitrate)
{
    _maxBitrate = maxBitrate;
}

WebRtc_UWord32
RTPSenderVideo::MaxConfiguredBitrateVideo() const
{
    return _maxBitrate;
}

WebRtc_Word32
RTPSenderVideo::SendVP8(const FrameType frameType,
                        const WebRtc_Word8 payloadType,
                        const WebRtc_UWord32 captureTimeStamp,
                        const WebRtc_UWord8* payloadData,
                        const WebRtc_UWord32 payloadSize,
                        const RTPFragmentationHeader* fragmentation,
                        const RTPVideoTypeHeader* rtpTypeHdr)
{
    const WebRtc_UWord16 rtpHeaderLength = _rtpSender.RTPHeaderLength();

    WebRtc_Word32 payloadBytesToSend = payloadSize;
    const WebRtc_UWord8* data = payloadData;

    WebRtc_UWord16 maxPayloadLengthVP8 = _rtpSender.MaxDataPayloadLength();

    assert(rtpTypeHdr);
    // Initialize disregarding partition boundaries: this will use kEqualSize
    // packetization mode, which produces ~equal size packets for each frame.
    RtpFormatVp8 packetizer(data, payloadBytesToSend, rtpTypeHdr->VP8,
                            maxPayloadLengthVP8);

    StorageType storage = kAllowRetransmission;
    if (rtpTypeHdr->VP8.temporalIdx == 0 &&
        !(_retransmissionSettings & kRetransmitBaseLayer)) {
      storage = kDontRetransmit;
    }
    if (rtpTypeHdr->VP8.temporalIdx > 0 &&
        !(_retransmissionSettings & kRetransmitHigherLayers)) {
      storage = kDontRetransmit;
    }

    bool last = false;
    _numberFirstPartition = 0;
    // |rtpTypeHdr->VP8.temporalIdx| is zero for base layers, or -1 if the field
    // isn't used. We currently only protect base layers.
    bool protect = (rtpTypeHdr->VP8.temporalIdx < 1);
    while (!last)
    {
        // Write VP8 Payload Descriptor and VP8 payload.
        WebRtc_UWord8 dataBuffer[IP_PACKET_SIZE] = {0};
        int payloadBytesInPacket = 0;
        int packetStartPartition =
            packetizer.NextPacket(&dataBuffer[rtpHeaderLength],
                                  &payloadBytesInPacket, &last);
        if (packetStartPartition == 0)
        {
            ++_numberFirstPartition;
        }
        else if (packetStartPartition < 0)
        {
            return -1;
        }

        // Write RTP header.
        // Set marker bit true if this is the last packet in frame.
        _rtpSender.BuildRTPheader(dataBuffer, payloadType, last,
            captureTimeStamp);
        if (-1 == SendVideoPacket(dataBuffer, payloadBytesInPacket,
            rtpHeaderLength, storage, protect))
        {
          WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
                       "RTPSenderVideo::SendVP8 failed to send packet number"
                       " %d", _rtpSender.SequenceNumber());
        }
    }
    return 0;
}

void RTPSenderVideo::ProcessBitrate() {
  _videoBitrate.Process();
  _fecOverheadRate.Process();
}

WebRtc_UWord32 RTPSenderVideo::VideoBitrateSent() const {
  return _videoBitrate.BitrateLast();
}

WebRtc_UWord32 RTPSenderVideo::FecOverheadRate() const {
  return _fecOverheadRate.BitrateLast();
}

int RTPSenderVideo::SelectiveRetransmissions() const {
  return _retransmissionSettings;
}

int RTPSenderVideo::SetSelectiveRetransmissions(uint8_t settings) {
  _retransmissionSettings = settings;
  return 0;
}

} // namespace webrtc
<commit_msg>Temporarily disable first partition packet counting to avoid a bug in ProducerFec which doesn't properly handle important packets.<commit_after>/*
 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "rtp_sender_video.h"

#include "critical_section_wrapper.h"
#include "trace.h"

#include "rtp_utility.h"

#include <string.h> // memcpy
#include <cassert>  // assert
#include <cstdlib>  // srand

#include "producer_fec.h"
#include "rtp_format_vp8.h"

namespace webrtc {
enum { REDForFECHeaderLength = 1 };

struct RtpPacket {
  WebRtc_UWord16 rtpHeaderLength;
  ForwardErrorCorrection::Packet* pkt;
};

RTPSenderVideo::RTPSenderVideo(const WebRtc_Word32 id,
                               RtpRtcpClock* clock,
                               RTPSenderInterface* rtpSender) :
    _id(id),
    _rtpSender(*rtpSender),
    _sendVideoCritsect(CriticalSectionWrapper::CreateCriticalSection()),

    _videoType(kRtpNoVideo),
    _videoCodecInformation(NULL),
    _maxBitrate(0),
    _retransmissionSettings(kRetransmitBaseLayer),

    // Generic FEC
    _fec(id),
    _fecEnabled(false),
    _payloadTypeRED(-1),
    _payloadTypeFEC(-1),
    _numberFirstPartition(0),
    delta_fec_params_(),
    key_fec_params_(),
    producer_fec_(&_fec),
    _fecOverheadRate(clock),
    _videoBitrate(clock) {
  memset(&delta_fec_params_, 0, sizeof(delta_fec_params_));
  memset(&key_fec_params_, 0, sizeof(key_fec_params_));
  delta_fec_params_.max_fec_frames = key_fec_params_.max_fec_frames = 1;
}

RTPSenderVideo::~RTPSenderVideo()
{
    if(_videoCodecInformation)
    {
        delete _videoCodecInformation;
    }
    delete _sendVideoCritsect;
}

void
RTPSenderVideo::SetVideoCodecType(RtpVideoCodecTypes videoType)
{
    CriticalSectionScoped cs(_sendVideoCritsect);
    _videoType = videoType;
}

RtpVideoCodecTypes
RTPSenderVideo::VideoCodecType() const
{
    return _videoType;
}

WebRtc_Word32 RTPSenderVideo::RegisterVideoPayload(
    const char payloadName[RTP_PAYLOAD_NAME_SIZE],
    const WebRtc_Word8 payloadType,
    const WebRtc_UWord32 maxBitRate,
    ModuleRTPUtility::Payload*& payload) {
  CriticalSectionScoped cs(_sendVideoCritsect);

  RtpVideoCodecTypes videoType = kRtpNoVideo;
  if (ModuleRTPUtility::StringCompare(payloadName, "VP8",3)) {
    videoType = kRtpVp8Video;
  } else if (ModuleRTPUtility::StringCompare(payloadName, "I420", 4)) {
    videoType = kRtpNoVideo;
  } else {
    return -1;
  }
  payload = new ModuleRTPUtility::Payload;
  payload->name[RTP_PAYLOAD_NAME_SIZE - 1] = 0;
  strncpy(payload->name, payloadName, RTP_PAYLOAD_NAME_SIZE - 1);
  payload->typeSpecific.Video.videoCodecType = videoType;
  payload->typeSpecific.Video.maxRate = maxBitRate;
  payload->audio = false;
  return 0;
}

WebRtc_Word32
RTPSenderVideo::SendVideoPacket(const WebRtc_UWord8* data_buffer,
                                const WebRtc_UWord16 payload_length,
                                const WebRtc_UWord16 rtp_header_length,
                                StorageType storage,
                                bool protect) {
  if(_fecEnabled) {
    int ret = 0;
    int fec_overhead_sent = 0;
    int video_sent = 0;

    RedPacket* red_packet = producer_fec_.BuildRedPacket(data_buffer,
                                                         payload_length,
                                                         rtp_header_length,
                                                         _payloadTypeRED);
    // Sending the media packet with RED header.
    int packet_success = _rtpSender.SendToNetwork(
        red_packet->data(),
        red_packet->length() - rtp_header_length,
        rtp_header_length,
        storage);

    ret |= packet_success;

    if (packet_success == 0) {
      video_sent += red_packet->length();
    }
    delete red_packet;
    red_packet = NULL;

    if (protect) {
      ret = producer_fec_.AddRtpPacketAndGenerateFec(data_buffer,
                                                     payload_length,
                                                     rtp_header_length);
      if (ret != 0)
        return ret;
    }

    while (producer_fec_.FecAvailable()) {
      red_packet = producer_fec_.GetFecPacket(
          _payloadTypeRED,
          _payloadTypeFEC,
          _rtpSender.IncrementSequenceNumber());
      StorageType storage = kDontRetransmit;
      if (_retransmissionSettings & kRetransmitFECPackets) {
        storage = kAllowRetransmission;
      }
      // Sending FEC packet with RED header.
      int packet_success = _rtpSender.SendToNetwork(
          red_packet->data(),
          red_packet->length() - rtp_header_length,
          rtp_header_length,
          storage);

      ret |= packet_success;

      if (packet_success == 0) {
        fec_overhead_sent += red_packet->length();
      }
      delete red_packet;
      red_packet = NULL;
    }
    _videoBitrate.Update(video_sent);
    _fecOverheadRate.Update(fec_overhead_sent);
    return ret;
  }
  int ret = _rtpSender.SendToNetwork(data_buffer,
                                     payload_length,
                                     rtp_header_length,
                                     storage);
  if (ret == 0) {
    _videoBitrate.Update(payload_length + rtp_header_length);
  }
  return ret;
}

WebRtc_Word32
RTPSenderVideo::SendRTPIntraRequest()
{
    // RFC 2032
    // 5.2.1.  Full intra-frame Request (FIR) packet

    WebRtc_UWord16 length = 8;
    WebRtc_UWord8 data[8];
    data[0] = 0x80;
    data[1] = 192;
    data[2] = 0;
    data[3] = 1; // length

    ModuleRTPUtility::AssignUWord32ToBuffer(data+4, _rtpSender.SSRC());

    return _rtpSender.SendToNetwork(data, 0, length, kAllowRetransmission);
}

WebRtc_Word32
RTPSenderVideo::SetGenericFECStatus(const bool enable,
                                    const WebRtc_UWord8 payloadTypeRED,
                                    const WebRtc_UWord8 payloadTypeFEC)
{
    _fecEnabled = enable;
    _payloadTypeRED = payloadTypeRED;
    _payloadTypeFEC = payloadTypeFEC;
    memset(&delta_fec_params_, 0, sizeof(delta_fec_params_));
    memset(&key_fec_params_, 0, sizeof(key_fec_params_));
    delta_fec_params_.max_fec_frames = key_fec_params_.max_fec_frames = 1;
    return 0;
}

WebRtc_Word32
RTPSenderVideo::GenericFECStatus(bool& enable,
                                 WebRtc_UWord8& payloadTypeRED,
                                 WebRtc_UWord8& payloadTypeFEC) const
{
    enable = _fecEnabled;
    payloadTypeRED = _payloadTypeRED;
    payloadTypeFEC = _payloadTypeFEC;
    return 0;
}

WebRtc_UWord16
RTPSenderVideo::FECPacketOverhead() const
{
    if (_fecEnabled)
    {
        return ForwardErrorCorrection::PacketOverhead() +
            REDForFECHeaderLength;
    }
    return 0;
}

WebRtc_Word32 RTPSenderVideo::SetFecParameters(
    const FecProtectionParams* delta_params,
    const FecProtectionParams* key_params) {
  assert(delta_params);
  assert(key_params);
  delta_fec_params_ = *delta_params;
  key_fec_params_ = *key_params;
  return 0;
}

WebRtc_Word32
RTPSenderVideo::SendVideo(const RtpVideoCodecTypes videoType,
                          const FrameType frameType,
                          const WebRtc_Word8 payloadType,
                          const WebRtc_UWord32 captureTimeStamp,
                          const WebRtc_UWord8* payloadData,
                          const WebRtc_UWord32 payloadSize,
                          const RTPFragmentationHeader* fragmentation,
                          VideoCodecInformation* codecInfo,
                          const RTPVideoTypeHeader* rtpTypeHdr)
{
    if( payloadSize == 0)
    {
        return -1;
    }

    if (frameType == kVideoFrameKey) {
      producer_fec_.SetFecParameters(&key_fec_params_,
                                     _numberFirstPartition);
    } else {
      producer_fec_.SetFecParameters(&delta_fec_params_,
                                     _numberFirstPartition);
    }

    // Default setting for number of first partition packets:
    // Will be extracted in SendVP8 for VP8 codec; other codecs use 0
    _numberFirstPartition = 0;

    WebRtc_Word32 retVal = -1;
    switch(videoType)
    {
    case kRtpNoVideo:
        retVal = SendGeneric(payloadType,captureTimeStamp, payloadData,
                             payloadSize);
        break;
    case kRtpVp8Video:
        retVal = SendVP8(frameType, payloadType, captureTimeStamp,
                payloadData, payloadSize, fragmentation, rtpTypeHdr);
        break;
    default:
        assert(false);
        break;
    }
    if(retVal <= 0)
    {
        return retVal;
    }
    WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, _id, "%s(timestamp:%u)",
                 __FUNCTION__, captureTimeStamp);
    return 0;
}

WebRtc_Word32
RTPSenderVideo::SendGeneric(const WebRtc_Word8 payloadType,
                            const WebRtc_UWord32 captureTimeStamp,
                            const WebRtc_UWord8* payloadData,
                            const WebRtc_UWord32 payloadSize)
{
    WebRtc_UWord16 payloadBytesInPacket = 0;
    WebRtc_UWord32 bytesSent = 0;
    WebRtc_Word32 payloadBytesToSend = payloadSize;

    const WebRtc_UWord8* data = payloadData;
    WebRtc_UWord16 rtpHeaderLength = _rtpSender.RTPHeaderLength();
    WebRtc_UWord16 maxLength = _rtpSender.MaxPayloadLength() -
        FECPacketOverhead() - rtpHeaderLength;
    WebRtc_UWord8 dataBuffer[IP_PACKET_SIZE];

    // Fragment packet into packets of max MaxPayloadLength bytes payload.
    while (payloadBytesToSend > 0)
    {
        if (payloadBytesToSend > maxLength)
        {
            payloadBytesInPacket = maxLength;
            payloadBytesToSend -= payloadBytesInPacket;
            // MarkerBit is 0
            if(_rtpSender.BuildRTPheader(dataBuffer,
                                         payloadType,
                                         false,
                                         captureTimeStamp) != rtpHeaderLength)
            {
                return -1;
           }
        }
        else
        {
            payloadBytesInPacket = (WebRtc_UWord16)payloadBytesToSend;
            payloadBytesToSend = 0;
            // MarkerBit is 1
            if(_rtpSender.BuildRTPheader(dataBuffer, payloadType, true,
                                         captureTimeStamp) != rtpHeaderLength)
            {
                return -1;
            }
        }

        // Put payload in packet
        memcpy(&dataBuffer[rtpHeaderLength], &data[bytesSent],
               payloadBytesInPacket);
        bytesSent += payloadBytesInPacket;

        if(-1 == SendVideoPacket(dataBuffer,
                                 payloadBytesInPacket,
                                 rtpHeaderLength,
                                 kAllowRetransmission,
                                 true))
        {
            return -1;
        }
    }
    return 0;
}

VideoCodecInformation*
RTPSenderVideo::CodecInformationVideo()
{
    return _videoCodecInformation;
}

void
RTPSenderVideo::SetMaxConfiguredBitrateVideo(const WebRtc_UWord32 maxBitrate)
{
    _maxBitrate = maxBitrate;
}

WebRtc_UWord32
RTPSenderVideo::MaxConfiguredBitrateVideo() const
{
    return _maxBitrate;
}

WebRtc_Word32
RTPSenderVideo::SendVP8(const FrameType frameType,
                        const WebRtc_Word8 payloadType,
                        const WebRtc_UWord32 captureTimeStamp,
                        const WebRtc_UWord8* payloadData,
                        const WebRtc_UWord32 payloadSize,
                        const RTPFragmentationHeader* fragmentation,
                        const RTPVideoTypeHeader* rtpTypeHdr)
{
    const WebRtc_UWord16 rtpHeaderLength = _rtpSender.RTPHeaderLength();

    WebRtc_Word32 payloadBytesToSend = payloadSize;
    const WebRtc_UWord8* data = payloadData;

    WebRtc_UWord16 maxPayloadLengthVP8 = _rtpSender.MaxDataPayloadLength();

    assert(rtpTypeHdr);
    // Initialize disregarding partition boundaries: this will use kEqualSize
    // packetization mode, which produces ~equal size packets for each frame.
    RtpFormatVp8 packetizer(data, payloadBytesToSend, rtpTypeHdr->VP8,
                            maxPayloadLengthVP8);

    StorageType storage = kAllowRetransmission;
    if (rtpTypeHdr->VP8.temporalIdx == 0 &&
        !(_retransmissionSettings & kRetransmitBaseLayer)) {
      storage = kDontRetransmit;
    }
    if (rtpTypeHdr->VP8.temporalIdx > 0 &&
        !(_retransmissionSettings & kRetransmitHigherLayers)) {
      storage = kDontRetransmit;
    }

    bool last = false;
    _numberFirstPartition = 0;
    // |rtpTypeHdr->VP8.temporalIdx| is zero for base layers, or -1 if the field
    // isn't used. We currently only protect base layers.
    bool protect = (rtpTypeHdr->VP8.temporalIdx < 1);
    while (!last)
    {
        // Write VP8 Payload Descriptor and VP8 payload.
        WebRtc_UWord8 dataBuffer[IP_PACKET_SIZE] = {0};
        int payloadBytesInPacket = 0;
        int packetStartPartition =
            packetizer.NextPacket(&dataBuffer[rtpHeaderLength],
                                  &payloadBytesInPacket, &last);
        // TODO(holmer): Temporarily disable first partition packet counting
        // to avoid a bug in ProducerFec which doesn't properly handle
        // important packets.
        // if (packetStartPartition == 0)
        // {
        //     ++_numberFirstPartition;
        // }
        // else
        if (packetStartPartition < 0)
        {
            return -1;
        }

        // Write RTP header.
        // Set marker bit true if this is the last packet in frame.
        _rtpSender.BuildRTPheader(dataBuffer, payloadType, last,
            captureTimeStamp);
        if (-1 == SendVideoPacket(dataBuffer, payloadBytesInPacket,
            rtpHeaderLength, storage, protect))
        {
          WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
                       "RTPSenderVideo::SendVP8 failed to send packet number"
                       " %d", _rtpSender.SequenceNumber());
        }
    }
    return 0;
}

void RTPSenderVideo::ProcessBitrate() {
  _videoBitrate.Process();
  _fecOverheadRate.Process();
}

WebRtc_UWord32 RTPSenderVideo::VideoBitrateSent() const {
  return _videoBitrate.BitrateLast();
}

WebRtc_UWord32 RTPSenderVideo::FecOverheadRate() const {
  return _fecOverheadRate.BitrateLast();
}

int RTPSenderVideo::SelectiveRetransmissions() const {
  return _retransmissionSettings;
}

int RTPSenderVideo::SetSelectiveRetransmissions(uint8_t settings) {
  _retransmissionSettings = settings;
  return 0;
}

} // namespace webrtc
<|endoftext|>


<commit_before>#include "FrameContainer.hpp"

#include "../../util/util.hpp"

using namespace morda;

FrameContainer::FrameContainer(const stob::Node* chain) :
		Widget(chain),
		Container(chain)
{}

void FrameContainer::OnResize() {
	for(auto i = this->Children().begin(); i != this->Children().end(); ++i){
		auto& lp = this->GetLayoutParamsAs<Container::LayoutParams>(**i);

		Vec2r d;
		for(unsigned j = 0; j != 2; ++j){
			if(lp.dim[j] == LayoutParams::D_Max){
				d[j] = this->Rect().d[j];
			}else if(lp.dim[j] == LayoutParams::D_Min || lp.dim[j] < 0){
				d[j] = -1;
			}else{
				d[j] = lp.dim[j];
			}
		}

		(*i)->Resize((*i)->measure(d));

		(*i)->MoveTo(((this->Rect().d - (*i)->Rect().d) / 2).Round());
	}
}

morda::Vec2r FrameContainer::onMeasure(const morda::Vec2r& quotum)const{
	Vec2r ret(quotum);
	for(unsigned i = 0; i != ret.size(); ++i){
		ting::util::ClampBottom(ret[i], real(0));
	}

	for(auto i = this->Children().begin(); i != this->Children().end(); ++i){
		auto& lp = this->GetLayoutParamsAs<Container::LayoutParams>(**i);

		morda::Vec2r d;

		for(unsigned j = 0; j != d.size(); ++j){
			if(lp.dim[j] == LayoutParams::D_Max){
				if(quotum[j] >= 0){
					d[j] = quotum[j];
				}else{
					d[j] = -1;
				}
			}else if(lp.dim[j] == LayoutParams::D_Min || lp.dim[j] < 0){
				d[j] = -1;
			}else{
				d[j] = lp.dim[j];
			}
		}

		d = (*i)->measure(d);

		for(unsigned j = 0; j != d.size(); ++j){
			if(quotum[j] < 0){
				ting::util::ClampBottom(ret[j], d[j]);
			}
		}
	}

	return ret;
}

<commit_msg>refactoring<commit_after>#include "FrameContainer.hpp"

#include "../../util/util.hpp"

using namespace morda;

FrameContainer::FrameContainer(const stob::Node* chain) :
		Widget(chain),
		Container(chain)
{}

void FrameContainer::OnResize() {
	for(auto i = this->Children().begin(); i != this->Children().end(); ++i){
		auto& lp = this->GetLayoutParamsAs<Container::LayoutParams>(**i);

		(*i)->Resize(this->dimForWidget(**i, lp));

		(*i)->MoveTo(((this->Rect().d - (*i)->Rect().d) / 2).Round());
	}
}

morda::Vec2r FrameContainer::onMeasure(const morda::Vec2r& quotum)const{
	Vec2r ret(quotum);
	for(unsigned i = 0; i != ret.size(); ++i){
		ting::util::ClampBottom(ret[i], real(0));
	}

	for(auto i = this->Children().begin(); i != this->Children().end(); ++i){
		auto& lp = this->GetLayoutParamsAs<Container::LayoutParams>(**i);

		morda::Vec2r d;

		for(unsigned j = 0; j != d.size(); ++j){
			if(lp.dim[j] == LayoutParams::D_Max){
				if(quotum[j] >= 0){
					d[j] = quotum[j];
				}else{
					d[j] = -1;
				}
			}else if(lp.dim[j] == LayoutParams::D_Min || lp.dim[j] < 0){
				d[j] = -1;
			}else{
				d[j] = lp.dim[j];
			}
		}

		d = (*i)->measure(d);

		for(unsigned j = 0; j != d.size(); ++j){
			if(quotum[j] < 0){
				ting::util::ClampBottom(ret[j], d[j]);
			}
		}
	}

	return ret;
}

<|endoftext|>