<commit_before>// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <util/timer.h>
#include <httpclient/httpclient.h>
#include <util/filereader.h>
#include "client.h"

Client::Client(ClientArguments *args)
    : _args(args),
      _status(new ClientStatus()),
      _reqTimer(new Timer()),
      _cycleTimer(new Timer()),
      _masterTimer(new Timer()),
      _http(new HTTPClient(_args->_hostname, _args->_port,
                           _args->_keepAlive, _args->_headerBenchmarkdataCoverage,
                           _args->_extraHeaders, _args->_authority)),
      _reader(new FileReader()),
      _output(),
      _linebufsize(args->_maxLineSize),
      _linebuf(new char[_linebufsize]),
      _contentbufsize(16 * args->_maxLineSize),
      _contentbuf(NULL),
      _stop(false),
      _done(false),
      _thread()
{
    assert(args != NULL);
    _cycleTimer->SetMax(_args->_cycle);
}

Client::~Client()
{
    delete [] _contentbuf;
    delete [] _linebuf;
}

void Client::runMe(Client * me) {
    me->run();
}

class UrlReader {
    FileReader &_reader;
    const ClientArguments &_args;
    int _restarts;
    char *_leftOvers;
    int _leftOversLen;
public:
    UrlReader(FileReader& reader, const ClientArguments &args)
        : _reader(reader), _args(args), _restarts(args._restartLimit),
         _leftOvers(NULL), _leftOversLen(0)
    {}
    int nextUrl(char *buf, int bufLen);
    int getContent(char *buf, int bufLen);
    ~UrlReader() {}
};

int UrlReader::nextUrl(char *buf, int buflen)
{
    if (_leftOvers) {
        if (_leftOversLen < buflen) {
            strncpy(buf, _leftOvers, _leftOversLen);
            buf[_leftOversLen] = '\0';
        } else {
            strncpy(buf, _leftOvers, buflen);
            buf[buflen-1] = '\0';
        }
        _leftOvers = NULL;
        return _leftOversLen;
    }
    // Read maximum to _queryfileOffsetEnd
    if ( _args._singleQueryFile && _reader.GetFilePos() >= _args._queryfileEndOffset ) {
        _reader.SetFilePos(_args._queryfileOffset);
        if (_restarts == 0) {
            return 0;
        } else if (_restarts > 0) {
            _restarts--;
        }
    }
    int ll = _reader.ReadLine(buf, buflen);
    while (ll > 0 && _args._usePostMode && buf[0] != '/') {
        ll = _reader.ReadLine(buf, buflen);
    }
    if (ll > 0 && (buf[0] == '/' || !_args._usePostMode)) {
        return ll;
    }
    if (_restarts == 0) {
        return 0;
    } else if (_restarts > 0) {
        _restarts--;
    }
    if (ll < 0) {
        _reader.Reset();
        // Start reading from offset
        if (_args._singleQueryFile) {
            _reader.SetFilePos(_args._queryfileOffset);
        }
    }
    ll = _reader.ReadLine(buf, buflen);
    while (ll > 0 && _args._usePostMode && buf[0] != '/') {
        ll = _reader.ReadLine(buf, buflen);
    }
    if (ll > 0 && (buf[0] == '/' || !_args._usePostMode)) {
        return ll;
    }
    return 0;
}

int UrlReader::getContent(char *buf, int bufLen)
{
    int totLen = 0;
    while (totLen < bufLen) {
       int len = _reader.ReadLine(buf, bufLen);
       if (len > 0) {
           if (buf[0] == '/') {
               _leftOvers = buf;
               _leftOversLen = len;
               return totLen;
           }
           buf += len;
           bufLen -= len;
           totLen += len;
       } else {
           return totLen;
       }
    }
    return totLen;
}

void
Client::run()
{
    char inputFilename[1024];
    char outputFilename[1024];
    char timestr[64];
    int  linelen;
    ///   int  reslen;

    if (_args->_usePostMode) {
        _contentbuf = new char[_contentbufsize];
    }

    std::this_thread::sleep_for(std::chrono::milliseconds(_args->_delay));

    // open query file
    snprintf(inputFilename, 1024, _args->_filenamePattern, _args->_myNum);
    if (!_reader->Open(inputFilename)) {
        printf("Client %d: ERROR: could not open file '%s' [read mode]\n",
               _args->_myNum, inputFilename);
        _status->SetError("Could not open query file.");
        return;
    }
    if (_args->_outputPattern != NULL) {
        snprintf(outputFilename, 1024, _args->_outputPattern, _args->_myNum);
        _output = std::make_unique<std::ofstream>(outputFilename, std::ofstream::out | std::ofstream::binary);
        if (_output->fail()) {
            printf("Client %d: ERROR: could not open file '%s' [write mode]\n",
                   _args->_myNum, outputFilename);
            _status->SetError("Could not open output file.");
            return;
        }
    }
    if (_output)
        _output->write(FBENCH_DELIMITER + 1, strlen(FBENCH_DELIMITER) - 1);

    if (_args->_ignoreCount == 0)
        _masterTimer->Start();

    // Start reading from offset
    if ( _args->_singleQueryFile )
        _reader->SetFilePos(_args->_queryfileOffset);

    UrlReader urlSource(*_reader, *_args);
    size_t urlNumber = 0;

    // run queries
    while (!_stop) {

        _cycleTimer->Start();

        linelen = urlSource.nextUrl(_linebuf, _linebufsize);
        if (linelen > 0) {
            ++urlNumber;
        } else {
            if (urlNumber == 0) {
                fprintf(stderr, "Client %d: ERROR: could not read any lines from '%s'\n",
                        _args->_myNum, inputFilename);
                _status->SetError("Could not read any lines from query file.");
            }
            break;
        }
        if (linelen < _linebufsize) {
            if (_output) {
                _output->write("URL: ", strlen("URL: "));
                _output->write(_linebuf, linelen);
                _output->write("\n\n", 2);
            }
            if (linelen + (int)_args->_queryStringToAppend.length() < _linebufsize) {
                strcat(_linebuf, _args->_queryStringToAppend.c_str());
            }
            int cLen = _args->_usePostMode ? urlSource.getContent(_contentbuf, _contentbufsize) : 0;
            _reqTimer->Start();
            auto fetch_status = _http->Fetch(_linebuf, _output.get(), _args->_usePostMode, _contentbuf, cLen);
            _reqTimer->Stop();
            _status->AddRequestStatus(fetch_status.RequestStatus());
            if (fetch_status.Ok() && fetch_status.TotalHitCount() == 0)
                ++_status->_zeroHitQueries;
            if (_output) {
                if (!fetch_status.Ok()) {
                    _output->write("\nFBENCH: URL FETCH FAILED!\n",
                                          strlen("\nFBENCH: URL FETCH FAILED!\n"));
                    _output->write(FBENCH_DELIMITER + 1, strlen(FBENCH_DELIMITER) - 1);
                } else {
                    sprintf(timestr, "\nTIME USED: %0.4f s\n",
                            _reqTimer->GetTimespan() / 1000.0);
                    _output->write(timestr, strlen(timestr));
                    _output->write(FBENCH_DELIMITER + 1, strlen(FBENCH_DELIMITER) - 1);
                }
            }
            if (fetch_status.ResultSize() >= _args->_byteLimit) {
                if (_args->_ignoreCount == 0)
                    _status->ResponseTime(_reqTimer->GetTimespan());
            } else {
                if (_args->_ignoreCount == 0)
                    _status->RequestFailed();
            }
        } else {
            if (_args->_ignoreCount == 0)
                _status->SkippedRequest();
        }
        _cycleTimer->Stop();
        if (_args->_cycle < 0) {
            std::this_thread::sleep_for(std::chrono::milliseconds(int(_reqTimer->GetTimespan())));
        } else {
            if (_cycleTimer->GetRemaining() > 0) {
                std::this_thread::sleep_for(std::chrono::milliseconds(int(_cycleTimer->GetRemaining())));
            } else {
                if (_args->_ignoreCount == 0)
                    _status->OverTime();
            }
        }
        if (_args->_ignoreCount > 0) {
            _args->_ignoreCount--;
            if (_args->_ignoreCount == 0)
                _masterTimer->Start();
        }
        // Update current time span to calculate Q/s
        _status->SetRealTime(_masterTimer->GetCurrent());
    }
    _masterTimer->Stop();
    _status->SetRealTime(_masterTimer->GetTimespan());
    _status->SetReuseCount(_http->GetReuseCount());
    printf(".");
    fflush(stdout);
    _done = true;
}

void Client::stop() {
    _stop = true;
}

bool Client::done() {
    return _done;
}

void Client::start() {
    _thread = std::thread(Client::runMe, this);
}

void Client::join() {
    _thread.join();
}
<commit_msg>make _restarts count upwards<commit_after>// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <util/timer.h>
#include <httpclient/httpclient.h>
#include <util/filereader.h>
#include "client.h"

Client::Client(ClientArguments *args)
    : _args(args),
      _status(new ClientStatus()),
      _reqTimer(new Timer()),
      _cycleTimer(new Timer()),
      _masterTimer(new Timer()),
      _http(new HTTPClient(_args->_hostname, _args->_port,
                           _args->_keepAlive, _args->_headerBenchmarkdataCoverage,
                           _args->_extraHeaders, _args->_authority)),
      _reader(new FileReader()),
      _output(),
      _linebufsize(args->_maxLineSize),
      _linebuf(new char[_linebufsize]),
      _contentbufsize(16 * args->_maxLineSize),
      _contentbuf(NULL),
      _stop(false),
      _done(false),
      _thread()
{
    assert(args != NULL);
    _cycleTimer->SetMax(_args->_cycle);
}

Client::~Client()
{
    delete [] _contentbuf;
    delete [] _linebuf;
}

void Client::runMe(Client * me) {
    me->run();
}

class UrlReader {
    FileReader &_reader;
    const ClientArguments &_args;
    int _restarts;
    char *_leftOvers;
    int _leftOversLen;
public:
    UrlReader(FileReader& reader, const ClientArguments &args)
        : _reader(reader), _args(args), _restarts(0),
         _leftOvers(NULL), _leftOversLen(0)
    {}
    int nextUrl(char *buf, int bufLen);
    int getContent(char *buf, int bufLen);
    ~UrlReader() {}
};

int UrlReader::nextUrl(char *buf, int buflen)
{
    if (_leftOvers) {
        if (_leftOversLen < buflen) {
            strncpy(buf, _leftOvers, _leftOversLen);
            buf[_leftOversLen] = '\0';
        } else {
            strncpy(buf, _leftOvers, buflen);
            buf[buflen-1] = '\0';
        }
        _leftOvers = NULL;
        return _leftOversLen;
    }
    // Read maximum to _queryfileOffsetEnd
    if ( _args._singleQueryFile && _reader.GetFilePos() >= _args._queryfileEndOffset ) {
        _reader.SetFilePos(_args._queryfileOffset);
        if (_restarts == _args._restartLimit) {
            return 0;
        } else if (_args._restartLimit > 0) {
            _restarts++;
        }
    }
    int ll = _reader.ReadLine(buf, buflen);
    while (ll > 0 && _args._usePostMode && buf[0] != '/') {
        ll = _reader.ReadLine(buf, buflen);
    }
    if (ll > 0 && (buf[0] == '/' || !_args._usePostMode)) {
        return ll;
    }
    if (_restarts == _args._restartLimit) {
        return 0;
    } else if (_args._restartLimit > 0) {
        _restarts++;
    }
    if (ll < 0) {
        _reader.Reset();
        // Start reading from offset
        if (_args._singleQueryFile) {
            _reader.SetFilePos(_args._queryfileOffset);
        }
    }
    ll = _reader.ReadLine(buf, buflen);
    while (ll > 0 && _args._usePostMode && buf[0] != '/') {
        ll = _reader.ReadLine(buf, buflen);
    }
    if (ll > 0 && (buf[0] == '/' || !_args._usePostMode)) {
        return ll;
    }
    return 0;
}

int UrlReader::getContent(char *buf, int bufLen)
{
    int totLen = 0;
    while (totLen < bufLen) {
       int len = _reader.ReadLine(buf, bufLen);
       if (len > 0) {
           if (buf[0] == '/') {
               _leftOvers = buf;
               _leftOversLen = len;
               return totLen;
           }
           buf += len;
           bufLen -= len;
           totLen += len;
       } else {
           return totLen;
       }
    }
    return totLen;
}

void
Client::run()
{
    char inputFilename[1024];
    char outputFilename[1024];
    char timestr[64];
    int  linelen;
    ///   int  reslen;

    if (_args->_usePostMode) {
        _contentbuf = new char[_contentbufsize];
    }

    std::this_thread::sleep_for(std::chrono::milliseconds(_args->_delay));

    // open query file
    snprintf(inputFilename, 1024, _args->_filenamePattern, _args->_myNum);
    if (!_reader->Open(inputFilename)) {
        printf("Client %d: ERROR: could not open file '%s' [read mode]\n",
               _args->_myNum, inputFilename);
        _status->SetError("Could not open query file.");
        return;
    }
    if (_args->_outputPattern != NULL) {
        snprintf(outputFilename, 1024, _args->_outputPattern, _args->_myNum);
        _output = std::make_unique<std::ofstream>(outputFilename, std::ofstream::out | std::ofstream::binary);
        if (_output->fail()) {
            printf("Client %d: ERROR: could not open file '%s' [write mode]\n",
                   _args->_myNum, outputFilename);
            _status->SetError("Could not open output file.");
            return;
        }
    }
    if (_output)
        _output->write(FBENCH_DELIMITER + 1, strlen(FBENCH_DELIMITER) - 1);

    if (_args->_ignoreCount == 0)
        _masterTimer->Start();

    // Start reading from offset
    if ( _args->_singleQueryFile )
        _reader->SetFilePos(_args->_queryfileOffset);

    UrlReader urlSource(*_reader, *_args);
    size_t urlNumber = 0;

    // run queries
    while (!_stop) {

        _cycleTimer->Start();

        linelen = urlSource.nextUrl(_linebuf, _linebufsize);
        if (linelen > 0) {
            ++urlNumber;
        } else {
            if (urlNumber == 0) {
                fprintf(stderr, "Client %d: ERROR: could not read any lines from '%s'\n",
                        _args->_myNum, inputFilename);
                _status->SetError("Could not read any lines from query file.");
            }
            break;
        }
        if (linelen < _linebufsize) {
            if (_output) {
                _output->write("URL: ", strlen("URL: "));
                _output->write(_linebuf, linelen);
                _output->write("\n\n", 2);
            }
            if (linelen + (int)_args->_queryStringToAppend.length() < _linebufsize) {
                strcat(_linebuf, _args->_queryStringToAppend.c_str());
            }
            int cLen = _args->_usePostMode ? urlSource.getContent(_contentbuf, _contentbufsize) : 0;
            _reqTimer->Start();
            auto fetch_status = _http->Fetch(_linebuf, _output.get(), _args->_usePostMode, _contentbuf, cLen);
            _reqTimer->Stop();
            _status->AddRequestStatus(fetch_status.RequestStatus());
            if (fetch_status.Ok() && fetch_status.TotalHitCount() == 0)
                ++_status->_zeroHitQueries;
            if (_output) {
                if (!fetch_status.Ok()) {
                    _output->write("\nFBENCH: URL FETCH FAILED!\n",
                                          strlen("\nFBENCH: URL FETCH FAILED!\n"));
                    _output->write(FBENCH_DELIMITER + 1, strlen(FBENCH_DELIMITER) - 1);
                } else {
                    sprintf(timestr, "\nTIME USED: %0.4f s\n",
                            _reqTimer->GetTimespan() / 1000.0);
                    _output->write(timestr, strlen(timestr));
                    _output->write(FBENCH_DELIMITER + 1, strlen(FBENCH_DELIMITER) - 1);
                }
            }
            if (fetch_status.ResultSize() >= _args->_byteLimit) {
                if (_args->_ignoreCount == 0)
                    _status->ResponseTime(_reqTimer->GetTimespan());
            } else {
                if (_args->_ignoreCount == 0)
                    _status->RequestFailed();
            }
        } else {
            if (_args->_ignoreCount == 0)
                _status->SkippedRequest();
        }
        _cycleTimer->Stop();
        if (_args->_cycle < 0) {
            std::this_thread::sleep_for(std::chrono::milliseconds(int(_reqTimer->GetTimespan())));
        } else {
            if (_cycleTimer->GetRemaining() > 0) {
                std::this_thread::sleep_for(std::chrono::milliseconds(int(_cycleTimer->GetRemaining())));
            } else {
                if (_args->_ignoreCount == 0)
                    _status->OverTime();
            }
        }
        if (_args->_ignoreCount > 0) {
            _args->_ignoreCount--;
            if (_args->_ignoreCount == 0)
                _masterTimer->Start();
        }
        // Update current time span to calculate Q/s
        _status->SetRealTime(_masterTimer->GetCurrent());
    }
    _masterTimer->Stop();
    _status->SetRealTime(_masterTimer->GetTimespan());
    _status->SetReuseCount(_http->GetReuseCount());
    printf(".");
    fflush(stdout);
    _done = true;
}

void Client::stop() {
    _stop = true;
}

bool Client::done() {
    return _done;
}

void Client::start() {
    _thread = std::thread(Client::runMe, this);
}

void Client::join() {
    _thread.join();
}
<|endoftext|>


<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "media/filters/pipeline_integration_test_base.h"

#include "base/bind.h"
#include "media/base/test_data_util.h"
#include "media/filters/chunk_demuxer_client.h"

namespace media {

// Helper class that emulates calls made on the ChunkDemuxer by the
// Media Source API.
class MockMediaSource : public ChunkDemuxerClient {
 public:
  MockMediaSource(const std::string& filename, int initial_append_size)
      : url_(GetTestDataURL(filename)),
        current_position_(0),
        initial_append_size_(initial_append_size) {
    ReadTestDataFile(filename, &file_data_, &file_data_size_);

    DCHECK_GT(initial_append_size_, 0);
    DCHECK_LE(initial_append_size_, file_data_size_);
  }

  virtual ~MockMediaSource() {}

  const std::string& url() { return url_; }

  void Seek(int new_position, int seek_append_size) {
    chunk_demuxer_->FlushData();

    DCHECK_GE(new_position, 0);
    DCHECK_LT(new_position, file_data_size_);
    current_position_ = new_position;

    AppendData(seek_append_size);
  }

  void AppendData(int size) {
    DCHECK(chunk_demuxer_.get());
    DCHECK_LT(current_position_, file_data_size_);
    DCHECK_LE(current_position_ + size, file_data_size_);
    chunk_demuxer_->AppendData(file_data_.get() + current_position_, size);
    current_position_ += size;
  }

  void EndOfStream() {
    chunk_demuxer_->EndOfStream(PIPELINE_OK);
  }

  void Abort() {
    if (!chunk_demuxer_.get())
      return;
    chunk_demuxer_->Shutdown();
  }

  // ChunkDemuxerClient methods.
  virtual void DemuxerOpened(ChunkDemuxer* demuxer) {
    chunk_demuxer_ = demuxer;
    AppendData(initial_append_size_);
  }

  virtual void DemuxerClosed() {
    chunk_demuxer_ = NULL;
  }

 private:
  std::string url_;
  scoped_array<uint8> file_data_;
  int file_data_size_;
  int current_position_;
  int initial_append_size_;
  scoped_refptr<ChunkDemuxer> chunk_demuxer_;
};

class PipelineIntegrationTest
    : public testing::Test,
      public PipelineIntegrationTestBase {
 public:
  void StartPipelineWithMediaSource(MockMediaSource& source) {
    pipeline_->Start(
        CreateFilterCollection(&source), source.url(),
        base::Bind(&PipelineIntegrationTest::OnEnded, base::Unretained(this)),
        base::Bind(&PipelineIntegrationTest::OnError, base::Unretained(this)),
        NetworkEventCB(), QuitOnStatusCB(PIPELINE_OK));

    message_loop_.Run();
  }

  // Verifies that seeking works properly for ChunkDemuxer when the
  // seek happens while there is a pending read on the ChunkDemuxer
  // and no data is available.
  bool TestSeekDuringRead(const std::string& filename,
                          int initial_append_size,
                          base::TimeDelta start_seek_time,
                          base::TimeDelta seek_time,
                          int seek_file_position,
                          int seek_append_size) {
    MockMediaSource source(filename, initial_append_size);
    StartPipelineWithMediaSource(source);

    if (pipeline_status_ != PIPELINE_OK)
      return false;

    Play();
    if (!WaitUntilCurrentTimeIsAfter(start_seek_time))
      return false;

    source.Seek(seek_file_position, seek_append_size);
    if (!Seek(seek_time))
      return false;

    source.EndOfStream();

    source.Abort();
    Stop();
    return true;
  }
};

TEST_F(PipelineIntegrationTest, BasicPlayback) {
  ASSERT_TRUE(Start(GetTestDataURL("bear-320x240.webm"), PIPELINE_OK));

  Play();

  ASSERT_TRUE(WaitUntilOnEnded());

  // TODO(dalecurtis): Due to threading issues in FFmpeg, frames are not always
  // decoded exactly, see http://crbug.com/93932 and http://crbug.com/109875.
  // ASSERT_EQ(GetVideoHash(), "f0be120a90a811506777c99a2cdf7cc1");
}

// TODO(xhwang): Enable this test when AddKey is integrated into pipeline.
TEST_F(PipelineIntegrationTest, DISABLED_EncryptedPlayback) {
  MockMediaSource source("bear-320x240-encrypted.webm", 219726);
  StartPipelineWithMediaSource(source);

  source.EndOfStream();
  ASSERT_EQ(PIPELINE_OK, pipeline_status_);

  Play();

  ASSERT_TRUE(WaitUntilOnEnded());
  source.Abort();
  Stop();
}

// TODO(acolwell): Fix flakiness http://crbug.com/117921
TEST_F(PipelineIntegrationTest, DISABLED_SeekWhilePaused) {
  ASSERT_TRUE(Start(GetTestDataURL("bear-320x240.webm"), PIPELINE_OK));

  base::TimeDelta duration(pipeline_->GetMediaDuration());
  base::TimeDelta start_seek_time(duration / 4);
  base::TimeDelta seek_time(duration * 3 / 4);

  Play();
  ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(start_seek_time));
  Pause();
  ASSERT_TRUE(Seek(seek_time));
  EXPECT_EQ(pipeline_->GetCurrentTime(), seek_time);
  Play();
  ASSERT_TRUE(WaitUntilOnEnded());

  // Make sure seeking after reaching the end works as expected.
  Pause();
  ASSERT_TRUE(Seek(seek_time));
  EXPECT_EQ(pipeline_->GetCurrentTime(), seek_time);
  Play();
  ASSERT_TRUE(WaitUntilOnEnded());
}

// TODO(acolwell): Fix flakiness http://crbug.com/117921
TEST_F(PipelineIntegrationTest, DISABLED_SeekWhilePlaying) {
  ASSERT_TRUE(Start(GetTestDataURL("bear-320x240.webm"), PIPELINE_OK));

  base::TimeDelta duration(pipeline_->GetMediaDuration());
  base::TimeDelta start_seek_time(duration / 4);
  base::TimeDelta seek_time(duration * 3 / 4);

  Play();
  ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(start_seek_time));
  ASSERT_TRUE(Seek(seek_time));
  EXPECT_GE(pipeline_->GetCurrentTime(), seek_time);
  ASSERT_TRUE(WaitUntilOnEnded());

  // Make sure seeking after reaching the end works as expected.
  ASSERT_TRUE(Seek(seek_time));
  EXPECT_GE(pipeline_->GetCurrentTime(), seek_time);
  ASSERT_TRUE(WaitUntilOnEnded());
}

// Verify audio decoder & renderer can handle aborted demuxer reads.
TEST_F(PipelineIntegrationTest, ChunkDemuxerAbortRead_AudioOnly) {
  ASSERT_TRUE(TestSeekDuringRead("bear-320x240-audio-only.webm", 8192,
                                 base::TimeDelta::FromMilliseconds(477),
                                 base::TimeDelta::FromMilliseconds(617),
                                 0x10CA, 19730));
}

// Verify video decoder & renderer can handle aborted demuxer reads.
TEST_F(PipelineIntegrationTest, ChunkDemuxerAbortRead_VideoOnly) {
  ASSERT_TRUE(TestSeekDuringRead("bear-320x240-video-only.webm", 32768,
                                 base::TimeDelta::FromMilliseconds(200),
                                 base::TimeDelta::FromMilliseconds(1668),
                                 0x1C896, 65536));
}

}  // namespace media
<commit_msg>Renable hashing for the basic playback test.<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "media/filters/pipeline_integration_test_base.h"

#include "base/bind.h"
#include "media/base/test_data_util.h"
#include "media/filters/chunk_demuxer_client.h"

namespace media {

// Helper class that emulates calls made on the ChunkDemuxer by the
// Media Source API.
class MockMediaSource : public ChunkDemuxerClient {
 public:
  MockMediaSource(const std::string& filename, int initial_append_size)
      : url_(GetTestDataURL(filename)),
        current_position_(0),
        initial_append_size_(initial_append_size) {
    ReadTestDataFile(filename, &file_data_, &file_data_size_);

    DCHECK_GT(initial_append_size_, 0);
    DCHECK_LE(initial_append_size_, file_data_size_);
  }

  virtual ~MockMediaSource() {}

  const std::string& url() { return url_; }

  void Seek(int new_position, int seek_append_size) {
    chunk_demuxer_->FlushData();

    DCHECK_GE(new_position, 0);
    DCHECK_LT(new_position, file_data_size_);
    current_position_ = new_position;

    AppendData(seek_append_size);
  }

  void AppendData(int size) {
    DCHECK(chunk_demuxer_.get());
    DCHECK_LT(current_position_, file_data_size_);
    DCHECK_LE(current_position_ + size, file_data_size_);
    chunk_demuxer_->AppendData(file_data_.get() + current_position_, size);
    current_position_ += size;
  }

  void EndOfStream() {
    chunk_demuxer_->EndOfStream(PIPELINE_OK);
  }

  void Abort() {
    if (!chunk_demuxer_.get())
      return;
    chunk_demuxer_->Shutdown();
  }

  // ChunkDemuxerClient methods.
  virtual void DemuxerOpened(ChunkDemuxer* demuxer) {
    chunk_demuxer_ = demuxer;
    AppendData(initial_append_size_);
  }

  virtual void DemuxerClosed() {
    chunk_demuxer_ = NULL;
  }

 private:
  std::string url_;
  scoped_array<uint8> file_data_;
  int file_data_size_;
  int current_position_;
  int initial_append_size_;
  scoped_refptr<ChunkDemuxer> chunk_demuxer_;
};

class PipelineIntegrationTest
    : public testing::Test,
      public PipelineIntegrationTestBase {
 public:
  void StartPipelineWithMediaSource(MockMediaSource& source) {
    pipeline_->Start(
        CreateFilterCollection(&source), source.url(),
        base::Bind(&PipelineIntegrationTest::OnEnded, base::Unretained(this)),
        base::Bind(&PipelineIntegrationTest::OnError, base::Unretained(this)),
        NetworkEventCB(), QuitOnStatusCB(PIPELINE_OK));

    message_loop_.Run();
  }

  // Verifies that seeking works properly for ChunkDemuxer when the
  // seek happens while there is a pending read on the ChunkDemuxer
  // and no data is available.
  bool TestSeekDuringRead(const std::string& filename,
                          int initial_append_size,
                          base::TimeDelta start_seek_time,
                          base::TimeDelta seek_time,
                          int seek_file_position,
                          int seek_append_size) {
    MockMediaSource source(filename, initial_append_size);
    StartPipelineWithMediaSource(source);

    if (pipeline_status_ != PIPELINE_OK)
      return false;

    Play();
    if (!WaitUntilCurrentTimeIsAfter(start_seek_time))
      return false;

    source.Seek(seek_file_position, seek_append_size);
    if (!Seek(seek_time))
      return false;

    source.EndOfStream();

    source.Abort();
    Stop();
    return true;
  }
};

TEST_F(PipelineIntegrationTest, BasicPlayback) {
  ASSERT_TRUE(Start(GetTestDataURL("bear-320x240.webm"), PIPELINE_OK));

  Play();

  ASSERT_TRUE(WaitUntilOnEnded());

  ASSERT_EQ(GetVideoHash(), "f0be120a90a811506777c99a2cdf7cc1");
}

// TODO(xhwang): Enable this test when AddKey is integrated into pipeline.
TEST_F(PipelineIntegrationTest, DISABLED_EncryptedPlayback) {
  MockMediaSource source("bear-320x240-encrypted.webm", 219726);
  StartPipelineWithMediaSource(source);

  source.EndOfStream();
  ASSERT_EQ(PIPELINE_OK, pipeline_status_);

  Play();

  ASSERT_TRUE(WaitUntilOnEnded());
  source.Abort();
  Stop();
}

// TODO(acolwell): Fix flakiness http://crbug.com/117921
TEST_F(PipelineIntegrationTest, DISABLED_SeekWhilePaused) {
  ASSERT_TRUE(Start(GetTestDataURL("bear-320x240.webm"), PIPELINE_OK));

  base::TimeDelta duration(pipeline_->GetMediaDuration());
  base::TimeDelta start_seek_time(duration / 4);
  base::TimeDelta seek_time(duration * 3 / 4);

  Play();
  ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(start_seek_time));
  Pause();
  ASSERT_TRUE(Seek(seek_time));
  EXPECT_EQ(pipeline_->GetCurrentTime(), seek_time);
  Play();
  ASSERT_TRUE(WaitUntilOnEnded());

  // Make sure seeking after reaching the end works as expected.
  Pause();
  ASSERT_TRUE(Seek(seek_time));
  EXPECT_EQ(pipeline_->GetCurrentTime(), seek_time);
  Play();
  ASSERT_TRUE(WaitUntilOnEnded());
}

// TODO(acolwell): Fix flakiness http://crbug.com/117921
TEST_F(PipelineIntegrationTest, DISABLED_SeekWhilePlaying) {
  ASSERT_TRUE(Start(GetTestDataURL("bear-320x240.webm"), PIPELINE_OK));

  base::TimeDelta duration(pipeline_->GetMediaDuration());
  base::TimeDelta start_seek_time(duration / 4);
  base::TimeDelta seek_time(duration * 3 / 4);

  Play();
  ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(start_seek_time));
  ASSERT_TRUE(Seek(seek_time));
  EXPECT_GE(pipeline_->GetCurrentTime(), seek_time);
  ASSERT_TRUE(WaitUntilOnEnded());

  // Make sure seeking after reaching the end works as expected.
  ASSERT_TRUE(Seek(seek_time));
  EXPECT_GE(pipeline_->GetCurrentTime(), seek_time);
  ASSERT_TRUE(WaitUntilOnEnded());
}

// Verify audio decoder & renderer can handle aborted demuxer reads.
TEST_F(PipelineIntegrationTest, ChunkDemuxerAbortRead_AudioOnly) {
  ASSERT_TRUE(TestSeekDuringRead("bear-320x240-audio-only.webm", 8192,
                                 base::TimeDelta::FromMilliseconds(477),
                                 base::TimeDelta::FromMilliseconds(617),
                                 0x10CA, 19730));
}

// Verify video decoder & renderer can handle aborted demuxer reads.
TEST_F(PipelineIntegrationTest, ChunkDemuxerAbortRead_VideoOnly) {
  ASSERT_TRUE(TestSeekDuringRead("bear-320x240-video-only.webm", 32768,
                                 base::TimeDelta::FromMilliseconds(200),
                                 base::TimeDelta::FromMilliseconds(1668),
                                 0x1C896, 65536));
}

}  // namespace media
<|endoftext|>


<commit_before>#include "cinder/app/App.h"
#include "cinder/app/RendererGl.h"
#include "cinder/ImageIo.h"
#include "cinder/gl/gl.h"

using namespace ci;
using namespace ci::app;
using namespace std;

struct Satellite {
	vec3		mPos;
	Colorf		mColor;
};

class DynamicCubeMappingApp : public App {
  public:
	void setup() override;
	void resize() override;
	void update() override;
	void keyDown( KeyEvent event ) override;

	void drawSatellites();
	void drawSkyBox();
	void draw();

	gl::TextureCubeMapRef	mSkyBoxCubeMap;
	gl::BatchRef			mTeapotBatch, mSkyBoxBatch;
	mat4					mObjectRotation;
	CameraPersp				mCam;

	gl::FboCubeMapRef		mDynamicCubeMapFbo;
	bool					mDrawCubeMap;

	std::vector<Satellite>	mSatellites;
	gl::BatchRef			mSatelliteBatch;
};

const int SKY_BOX_SIZE = 500;

void DynamicCubeMappingApp::setup()
{
	mSkyBoxCubeMap = gl::TextureCubeMap::create( loadImage( loadAsset( "env_map.jpg" ) ), gl::TextureCubeMap::Format().mipmap() );

#if defined( CINDER_GL_ES )
	auto envMapGlsl = gl::GlslProg::create( loadAsset( "env_map_es2.vert" ), loadAsset( "env_map_es2.frag" ) );
	auto skyBoxGlsl = gl::GlslProg::create( loadAsset( "sky_box_es2.vert" ), loadAsset( "sky_box_es2.frag" ) );
#else
	auto envMapGlsl = gl::GlslProg::create( loadAsset( "env_map.vert" ), loadAsset( "env_map.frag" ) );
	auto skyBoxGlsl = gl::GlslProg::create( loadAsset( "sky_box.vert" ), loadAsset( "sky_box.frag" ) );
#endif

	mTeapotBatch = gl::Batch::create( geom::Teapot().subdivisions( 7 ), envMapGlsl );
	mTeapotBatch->getGlslProg()->uniform( "uCubeMapTex", 0 );

	mSkyBoxBatch = gl::Batch::create( geom::Cube(), skyBoxGlsl );
	mSkyBoxBatch->getGlslProg()->uniform( "uCubeMapTex", 0 );

	// build our dynamic CubeMap
	mDynamicCubeMapFbo = gl::FboCubeMap::create( 1024, 1024 );

	// setup satellites (orbiting spheres )
	for( int i = 0; i < 33; ++i ) {
		mSatellites.push_back( Satellite() );
		float angle = i / 33.0f;
		mSatellites.back().mColor = Colorf( CM_HSV, angle, 1.0f, 1.0f );
		mSatellites.back().mPos = vec3( cos( angle * 2 * M_PI ) * 7, 0, sin( angle * 2 * M_PI ) * 7 );
	}
	mSatelliteBatch = gl::Batch::create( geom::Sphere(), getStockShader( gl::ShaderDef().color() ) );

	mDrawCubeMap = false;

	gl::enableDepthRead();
	gl::enableDepthWrite();
}

void DynamicCubeMappingApp::resize()
{
	mCam.setPerspective( 60, getWindowAspectRatio(), 1, 1000 );
}

void DynamicCubeMappingApp::update()
{
	// move the camera semi-randomly around based on time
	mCam.lookAt( vec3( 8 * sin( getElapsedSeconds() / 1 + 10 ), 7 * sin( getElapsedSeconds() / 2 ), 8 * cos( getElapsedSeconds() / 4 + 11 ) ), vec3( 0 ) );

	// rotate the object (teapot) a bit each frame
	mObjectRotation *= rotate( 0.04f, normalize( vec3( 0.1f, 1, 0.1f ) ) );

	// move the satellites
	for( int i = 0; i < 33; ++i ) {
		float angle = i / 33.0f;
		mSatellites[i].mPos = vec3( cos( angle * 2 * M_PI ) * 7, 6 * sin( getElapsedSeconds() * 2 + angle * 4 * M_PI ), sin( angle * 2 * M_PI ) * 7 );
	}
}

void DynamicCubeMappingApp::keyDown( KeyEvent event )
{
	if( event.getChar() == 'd' )
		mDrawCubeMap = ! mDrawCubeMap;
}

void DynamicCubeMappingApp::drawSatellites()
{
	for( const auto &satellite : mSatellites ) {
		gl::pushModelMatrix();
		gl::translate( satellite.mPos );
		gl::color( satellite.mColor );
		mSatelliteBatch->draw();
		gl::popModelMatrix();
	}
}

void DynamicCubeMappingApp::drawSkyBox()
{
	mSkyBoxCubeMap->bind();
	gl::pushMatrices();
		gl::scale( SKY_BOX_SIZE, SKY_BOX_SIZE, SKY_BOX_SIZE );
		mSkyBoxBatch->draw();
	gl::popMatrices();
}

void DynamicCubeMappingApp::draw()
{
	gl::clear( Color( 1, 0, 0 ) );

	gl::pushViewport( ivec2( 0, 0 ), mDynamicCubeMapFbo->getSize() );
	// we need to save the current FBO because we'll be calling bindFramebufferFace() below
	gl::context()->pushFramebuffer();
	for( uint8_t dir = 0; dir < 6; ++dir ) {
		gl::setProjectionMatrix( ci::CameraPersp( mDynamicCubeMapFbo->getWidth(), mDynamicCubeMapFbo->getHeight(), 90.0f, 1, 1000 ).getProjectionMatrix() );
		gl::setViewMatrix( mDynamicCubeMapFbo->calcViewMatrix( GL_TEXTURE_CUBE_MAP_POSITIVE_X + dir, vec3( 0 ) ) );
		mDynamicCubeMapFbo->bindFramebufferFace( GL_TEXTURE_CUBE_MAP_POSITIVE_X + dir );

		gl::clear();
		drawSatellites();
		drawSkyBox();
	}
	// restore the FBO before we bound the various faces of the CubeMapFbo
	gl::context()->popFramebuffer();
	gl::popViewport();

	gl::setMatrices( mCam );
	// now draw the full scene
	drawSatellites();
	drawSkyBox();

	mDynamicCubeMapFbo->bindTexture( 0 );
	gl::pushMatrices();
		gl::multModelMatrix( mObjectRotation );
		gl::scale( vec3( 4 ) );
		mTeapotBatch->draw();
	gl::popMatrices();

	if( mDrawCubeMap ) {
		gl::setMatricesWindow( getWindowSize() );
		gl::ScopedDepth d( false );
		//gl::drawHorizontalCross( mDynamicCubeMapFbo->getTextureCubeMap(), Rectf( 0, 0, 400, 200 ) );
		gl::drawEquirectangular( mDynamicCubeMapFbo->getTextureCubeMap(), Rectf( 0, getWindowHeight() - 200, 400, getWindowHeight() ) ); // try this alternative
	}
}

CINDER_APP( DynamicCubeMappingApp, RendererGl( RendererGl::Options().msaa( 16 ) ) )<commit_msg>Minor tweak to DynamicCubeMapping; drawing horizontal cross by default<commit_after>#include "cinder/app/App.h"
#include "cinder/app/RendererGl.h"
#include "cinder/ImageIo.h"
#include "cinder/gl/gl.h"

using namespace ci;
using namespace ci::app;
using namespace std;

struct Satellite {
	vec3		mPos;
	Colorf		mColor;
};

class DynamicCubeMappingApp : public App {
  public:
	void setup() override;
	void resize() override;
	void update() override;
	void keyDown( KeyEvent event ) override;

	void drawSatellites();
	void drawSkyBox();
	void draw();

	gl::TextureCubeMapRef	mSkyBoxCubeMap;
	gl::BatchRef			mTeapotBatch, mSkyBoxBatch;
	mat4					mObjectRotation;
	CameraPersp				mCam;

	gl::FboCubeMapRef		mDynamicCubeMapFbo;
	bool					mDrawCubeMap;

	std::vector<Satellite>	mSatellites;
	gl::BatchRef			mSatelliteBatch;
};

const int SKY_BOX_SIZE = 500;

void DynamicCubeMappingApp::setup()
{
	mSkyBoxCubeMap = gl::TextureCubeMap::create( loadImage( loadAsset( "env_map.jpg" ) ), gl::TextureCubeMap::Format().mipmap() );

#if defined( CINDER_GL_ES )
	auto envMapGlsl = gl::GlslProg::create( loadAsset( "env_map_es2.vert" ), loadAsset( "env_map_es2.frag" ) );
	auto skyBoxGlsl = gl::GlslProg::create( loadAsset( "sky_box_es2.vert" ), loadAsset( "sky_box_es2.frag" ) );
#else
	auto envMapGlsl = gl::GlslProg::create( loadAsset( "env_map.vert" ), loadAsset( "env_map.frag" ) );
	auto skyBoxGlsl = gl::GlslProg::create( loadAsset( "sky_box.vert" ), loadAsset( "sky_box.frag" ) );
#endif

	mTeapotBatch = gl::Batch::create( geom::Teapot().subdivisions( 7 ), envMapGlsl );
	mTeapotBatch->getGlslProg()->uniform( "uCubeMapTex", 0 );

	mSkyBoxBatch = gl::Batch::create( geom::Cube(), skyBoxGlsl );
	mSkyBoxBatch->getGlslProg()->uniform( "uCubeMapTex", 0 );

	// build our dynamic CubeMap
	mDynamicCubeMapFbo = gl::FboCubeMap::create( 1024, 1024 );

	// setup satellites (orbiting spheres )
	for( int i = 0; i < 33; ++i ) {
		mSatellites.push_back( Satellite() );
		float angle = i / 33.0f;
		mSatellites.back().mColor = Colorf( CM_HSV, angle, 1.0f, 1.0f );
		mSatellites.back().mPos = vec3( cos( angle * 2 * M_PI ) * 7, 0, sin( angle * 2 * M_PI ) * 7 );
	}
	mSatelliteBatch = gl::Batch::create( geom::Sphere(), getStockShader( gl::ShaderDef().color() ) );

	mDrawCubeMap = true;

	gl::enableDepthRead();
	gl::enableDepthWrite();
}

void DynamicCubeMappingApp::resize()
{
	mCam.setPerspective( 60, getWindowAspectRatio(), 1, 1000 );
}

void DynamicCubeMappingApp::update()
{
	// move the camera semi-randomly around based on time
	mCam.lookAt( vec3( 8 * sin( getElapsedSeconds() / 1 + 10 ), 7 * sin( getElapsedSeconds() / 2 ), 8 * cos( getElapsedSeconds() / 4 + 11 ) ), vec3( 0 ) );

	// rotate the object (teapot) a bit each frame
	mObjectRotation *= rotate( 0.04f, normalize( vec3( 0.1f, 1, 0.1f ) ) );

	// move the satellites
	for( int i = 0; i < 33; ++i ) {
		float angle = i / 33.0f;
		mSatellites[i].mPos = vec3( cos( angle * 2 * M_PI ) * 7, 6 * sin( getElapsedSeconds() * 2 + angle * 4 * M_PI ), sin( angle * 2 * M_PI ) * 7 );
	}
}

void DynamicCubeMappingApp::keyDown( KeyEvent event )
{
	if( event.getChar() == 'd' )
		mDrawCubeMap = ! mDrawCubeMap;
}

void DynamicCubeMappingApp::drawSatellites()
{
	for( const auto &satellite : mSatellites ) {
		gl::pushModelMatrix();
		gl::translate( satellite.mPos );
		gl::color( satellite.mColor );
		mSatelliteBatch->draw();
		gl::popModelMatrix();
	}
}

void DynamicCubeMappingApp::drawSkyBox()
{
	mSkyBoxCubeMap->bind();
	gl::pushMatrices();
		gl::scale( SKY_BOX_SIZE, SKY_BOX_SIZE, SKY_BOX_SIZE );
		mSkyBoxBatch->draw();
	gl::popMatrices();
}

void DynamicCubeMappingApp::draw()
{
	gl::clear( Color( 1, 0, 0 ) );

	gl::pushViewport( ivec2( 0, 0 ), mDynamicCubeMapFbo->getSize() );
	// we need to save the current FBO because we'll be calling bindFramebufferFace() below
	gl::context()->pushFramebuffer();
	for( uint8_t dir = 0; dir < 6; ++dir ) {
		gl::setProjectionMatrix( ci::CameraPersp( mDynamicCubeMapFbo->getWidth(), mDynamicCubeMapFbo->getHeight(), 90.0f, 1, 1000 ).getProjectionMatrix() );
		gl::setViewMatrix( mDynamicCubeMapFbo->calcViewMatrix( GL_TEXTURE_CUBE_MAP_POSITIVE_X + dir, vec3( 0 ) ) );
		mDynamicCubeMapFbo->bindFramebufferFace( GL_TEXTURE_CUBE_MAP_POSITIVE_X + dir );

		gl::clear();
		drawSatellites();
		drawSkyBox();
	}
	// restore the FBO before we bound the various faces of the CubeMapFbo
	gl::context()->popFramebuffer();
	gl::popViewport();

	gl::setMatrices( mCam );
	// now draw the full scene
	drawSatellites();
	drawSkyBox();

	mDynamicCubeMapFbo->bindTexture( 0 );
	gl::pushMatrices();
		gl::multModelMatrix( mObjectRotation );
		gl::scale( vec3( 4 ) );
		mTeapotBatch->draw();
	gl::popMatrices();

	if( mDrawCubeMap ) {
		gl::setMatricesWindow( getWindowSize() );
		gl::ScopedDepth d( false );
		gl::drawHorizontalCross( mDynamicCubeMapFbo->getTextureCubeMap(), Rectf( 0, 0, 300, 150 ) );
		//gl::drawEquirectangular( mDynamicCubeMapFbo->getTextureCubeMap(), Rectf( 0, getWindowHeight() - 200, 400, getWindowHeight() ) ); // try this alternative
	}
}

CINDER_APP( DynamicCubeMappingApp, RendererGl( RendererGl::Options().msaa( 16 ) ) )<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Insight Segmentation & Registration Toolkit
  Module:    itkImageToParametricSpaceFilterTest.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 2001 Insight Consortium
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.

 * The name of the Insight Consortium, nor the names of any consortium members,
   nor of any contributors, may be used to endorse or promote products derived
   from this software without specific prior written permission.

  * Modified source versions must be plainly marked as such, and must not be
    misrepresented as being the original software.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER 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 AUTHORS 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.

=========================================================================*/
#include "itkImageToParametricSpaceFilter.h"
#include "itkMesh.h"
#include "itkImage.h"
#include "itkImageRegionIteratorWithIndex.h"

int main()
{

  // Declare the mesh pixel type.
  // Those are the values associated
  // with each mesh point. (not used on this filter test)
  typedef int    MeshPixelType;
  typedef float  ImagePixelType;

  // Declare the types of the Mesh
  typedef itk::Mesh<MeshPixelType>  MeshType;

  // Declare the type for PointsContainer
  typedef MeshType::PointsContainer     PointsContainerType;

  // Declare the type for PointsContainerPointer
  typedef MeshType::PointsContainerPointer
                                        PointsContainerPointer;
  // Declare the type for Points
  typedef MeshType::PointType           PointType;

  // Create an input Mesh
  MeshType::Pointer inputMesh  = MeshType::New();

  // Insert data on the Mesh
  PointsContainerPointer  points = inputMesh->GetPoints();

  // Declare the type for the images
  typedef itk::Image<ImagePixelType,2>         ImageType;
  typedef ImageType::Pointer              ImagePointer;
  typedef ImageType::IndexType            IndexType;

  // Declare the type for the images
  typedef itk::ImageRegionIteratorWithIndex<ImageType> ImageIteratorType;

  // Declare the type for the filter
  typedef itk::ImageToParametricSpaceFilter<
                                       ImageType,
                                       MeshType   > FilterType;

  typedef FilterType::Pointer                     FilterPointer;

  ImagePointer imageX = ImageType::New();
  ImagePointer imageY = ImageType::New();
  ImagePointer imageZ = ImageType::New();

  ImageType::SizeType  size;
  ImageType::IndexType start;

  start = IndexType::ZeroIndex;
  size[0] = 10;
  size[1] = 10;

  ImageType::RegionType region;
  region.SetSize( size );
  region.SetIndex( start );

  imageX->SetLargestPossibleRegion( region );
  imageY->SetLargestPossibleRegion( region );
  imageZ->SetLargestPossibleRegion( region );

  imageX->SetBufferedRegion( region );
  imageY->SetBufferedRegion( region );
  imageZ->SetBufferedRegion( region );

  imageX->SetRequestedRegion( region );
  imageY->SetRequestedRegion( region );
  imageZ->SetRequestedRegion( region );

  imageX->Allocate();
  imageY->Allocate();
  imageZ->Allocate();

  ImageIteratorType   ix( imageX, region );
  ImageIteratorType   iy( imageY, region );
  ImageIteratorType   iz( imageZ, region );

  ix.GoToBegin();
  iy.GoToBegin();
  iz.GoToBegin();

  while( ! ix.IsAtEnd() )
    {
      ix.Set( rand() );
      ++ix;
    }

  while( ! iy.IsAtEnd() )
    {
      iy.Set( rand() );
      ++iy;
    }

  while( ! iz.IsAtEnd() )
    {
      iz.Set( rand() );
      ++iz;
    }

  FilterPointer filter = FilterType::New();

  // Connect the inputs
  filter->SetInput( 0, imageX );
  filter->SetInput( 1, imageY );
  filter->SetInput( 2, imageZ );

  // Execute the filter
  filter->Update();

  // Get the Smart Pointer to the Filter Output
  MeshType::Pointer outputMesh = filter->GetOutput();

  // Get the the point container
  MeshType::PointsContainer::Iterator beginPoint =
                           outputMesh->GetPoints()->Begin();

  MeshType::PointsContainer::Iterator endPoint =
                           outputMesh->GetPoints()->End();

  MeshType::PointsContainer::Iterator pointIt = beginPoint;

  bool ok = true;

  ix.GoToBegin();
  iy.GoToBegin();
  iz.GoToBegin();

  while( pointIt != endPoint )
    {
    PointType point = pointIt.Value();
    if( point[0] != ix.Value() )
      {
      ok = false;
      break;
      }
    if( point[1] != iy.Value() )
      {
      ok = false;
      break;
      }
    if( point[2] != iz.Value() )
      {
      ok = false;
      break;
      }

    ++pointIt;
    ++ix;
    ++iy;
    ++iz;
    }

  // All objects should be automatically destroyed at this point

  if( !ok )
    {
    return EXIT_FAILURE;
    }
  return EXIT_SUCCESS;

}

<commit_msg>FIX: Mesh pixels have to be Image::IndexType<commit_after>/*=========================================================================

  Program:   Insight Segmentation & Registration Toolkit
  Module:    itkImageToParametricSpaceFilterTest.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 2001 Insight Consortium
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.

 * The name of the Insight Consortium, nor the names of any consortium members,
   nor of any contributors, may be used to endorse or promote products derived
   from this software without specific prior written permission.

  * Modified source versions must be plainly marked as such, and must not be
    misrepresented as being the original software.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER 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 AUTHORS 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.

=========================================================================*/
#include "itkImageToParametricSpaceFilter.h"
#include "itkMesh.h"
#include "itkImage.h"
#include "itkImageRegionIteratorWithIndex.h"

int main()
{

  typedef float  ImagePixelType;

  // Declare the type for the images
  typedef itk::Image<ImagePixelType,2>        ImageType;
  typedef ImageType::Pointer                  ImagePointer;
  typedef ImageType::IndexType                IndexType;

  // Make the Mesh PointData type be an Image Index.
  typedef IndexType                         MeshPixelType;

  // Declare the types of the Mesh
  typedef itk::Mesh<MeshPixelType>  MeshType;

  // Declare the type for PointsContainer
  typedef MeshType::PointsContainer     PointsContainerType;

  // Declare the type for PointsContainerPointer
  typedef MeshType::PointsContainerPointer
                                        PointsContainerPointer;
  // Declare the type for Points
  typedef MeshType::PointType           PointType;

  // Create an input Mesh
  MeshType::Pointer inputMesh  = MeshType::New();

  // Insert data on the Mesh
  PointsContainerPointer  points = inputMesh->GetPoints();

  // Declare the type for the images
  typedef itk::ImageRegionIteratorWithIndex<ImageType> ImageIteratorType;

  // Declare the type for the filter
  typedef itk::ImageToParametricSpaceFilter<
                                       ImageType,
                                       MeshType   > FilterType;

  typedef FilterType::Pointer                     FilterPointer;

  ImagePointer imageX = ImageType::New();
  ImagePointer imageY = ImageType::New();
  ImagePointer imageZ = ImageType::New();

  ImageType::SizeType  size;
  ImageType::IndexType start;

  start = IndexType::ZeroIndex;
  size[0] = 10;
  size[1] = 10;

  ImageType::RegionType region;
  region.SetSize( size );
  region.SetIndex( start );

  imageX->SetLargestPossibleRegion( region );
  imageY->SetLargestPossibleRegion( region );
  imageZ->SetLargestPossibleRegion( region );

  imageX->SetBufferedRegion( region );
  imageY->SetBufferedRegion( region );
  imageZ->SetBufferedRegion( region );

  imageX->SetRequestedRegion( region );
  imageY->SetRequestedRegion( region );
  imageZ->SetRequestedRegion( region );

  imageX->Allocate();
  imageY->Allocate();
  imageZ->Allocate();

  ImageIteratorType   ix( imageX, region );
  ImageIteratorType   iy( imageY, region );
  ImageIteratorType   iz( imageZ, region );

  ix.GoToBegin();
  iy.GoToBegin();
  iz.GoToBegin();

  while( ! ix.IsAtEnd() )
    {
      ix.Set( rand() );
      ++ix;
    }

  while( ! iy.IsAtEnd() )
    {
      iy.Set( rand() );
      ++iy;
    }

  while( ! iz.IsAtEnd() )
    {
      iz.Set( rand() );
      ++iz;
    }

  FilterPointer filter = FilterType::New();

  // Connect the inputs
  filter->SetInput( 0, imageX );
  filter->SetInput( 1, imageY );
  filter->SetInput( 2, imageZ );

  // Execute the filter
  filter->Update();

  // Get the Smart Pointer to the Filter Output
  MeshType::Pointer outputMesh = filter->GetOutput();

  // Get the the point container
  MeshType::PointsContainer::Iterator beginPoint =
                           outputMesh->GetPoints()->Begin();

  MeshType::PointsContainer::Iterator endPoint =
                           outputMesh->GetPoints()->End();

  MeshType::PointsContainer::Iterator pointIt = beginPoint;

  bool ok = true;

  ix.GoToBegin();
  iy.GoToBegin();
  iz.GoToBegin();

  while( pointIt != endPoint )
    {
    PointType point = pointIt.Value();
    if( point[0] != ix.Value() )
      {
      ok = false;
      break;
      }
    if( point[1] != iy.Value() )
      {
      ok = false;
      break;
      }
    if( point[2] != iz.Value() )
      {
      ok = false;
      break;
      }

    ++pointIt;
    ++ix;
    ++iy;
    ++iz;
    }

  // All objects should be automatically destroyed at this point

  if( !ok )
    {
    return EXIT_FAILURE;
    }
  return EXIT_SUCCESS;

}

<|endoftext|>


<commit_before>/***********************************************************************************************************************
**
** Copyright (c) 2011, 2013 ETH Zurich
** 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 ETH Zurich 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.
**
***********************************************************************************************************************/

#include "CShapeSetProperty.h"
#include "items/VCommentDiagramShape.h"

#include "VisualizationBase/src/VisualizationManager.h"

namespace Comments {

bool CShapeSetProperty::canInterpret(Visualization::Item*, Visualization::Item*, const QStringList& commandTokens)
{
	return commandTokens.size() == 2 &&
			(commandTokens.first() == "fgcolor"
					|| commandTokens.first() == "bgcolor"
					|| commandTokens.first() == "bordercolor");
}

Interaction::CommandResult* CShapeSetProperty::execute(Visualization::Item*, Visualization::Item* target, const QStringList& commandTokens)
{
	auto shape = dynamic_cast<VCommentDiagramShape*>(target);
	shape->node()->model()->beginModification(shape->node(), "Setting color");

	if(commandTokens.first() == "fgcolor")
		shape->node()->setTextColor(commandTokens.last());
	else if(commandTokens.first() == "bgcolor")
		shape->node()->setBackgroundColor(commandTokens.last());
	else if(commandTokens.first() == "bordercolor")
		shape->node()->setShapeColor(commandTokens.last());

	shape->node()->model()->endModification();
	shape->setUpdateNeeded(Visualization::Item::StandardUpdate);
	return new Interaction::CommandResult();
}

QList<Interaction::CommandSuggestion*> CShapeSetProperty::suggest(Visualization::Item*, Visualization::Item*, const QString& textSoFar)
{
	QList<Interaction::CommandSuggestion*> s;
	if(QString("fgcolor").startsWith(textSoFar.trimmed(), Qt::CaseInsensitive))
		s.append(new Interaction::CommandSuggestion("fgcolor", "Set shape's foreground color"));
	if(QString("bgcolor").startsWith(textSoFar.trimmed(), Qt::CaseInsensitive))
		s.append(new Interaction::CommandSuggestion("bgcolor", "Set shape's background color"));
	if(QString("bordercolor").startsWith(textSoFar.trimmed(), Qt::CaseInsensitive))
			s.append(new Interaction::CommandSuggestion("bordercolor", "Set shape's border color"));
	return s;
}

QStringList CShapeSetProperty::commandForms(Visualization::Item*, Visualization::Item*, const QString& textSoFar)
{
	QStringList forms;
	if (textSoFar.isEmpty() || QString("exit").startsWith(textSoFar.trimmed(), Qt::CaseInsensitive) )
		forms.append("exit");
	return forms;
}

}
<commit_msg>Rename command fgcolor to textcolor<commit_after>/***********************************************************************************************************************
**
** Copyright (c) 2011, 2013 ETH Zurich
** 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 ETH Zurich 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.
**
***********************************************************************************************************************/

#include "CShapeSetProperty.h"
#include "items/VCommentDiagramShape.h"

#include "VisualizationBase/src/VisualizationManager.h"

namespace Comments {

bool CShapeSetProperty::canInterpret(Visualization::Item*, Visualization::Item*, const QStringList& commandTokens)
{
	return commandTokens.size() == 2 &&
			(commandTokens.first() == "textcolor"
					|| commandTokens.first() == "bgcolor"
					|| commandTokens.first() == "bordercolor");
}

Interaction::CommandResult* CShapeSetProperty::execute(Visualization::Item*, Visualization::Item* target, const QStringList& commandTokens)
{
	auto shape = dynamic_cast<VCommentDiagramShape*>(target);
	shape->node()->model()->beginModification(shape->node(), "Setting color");

	if(commandTokens.first() == "textcolor")
		shape->node()->setTextColor(commandTokens.last());
	else if(commandTokens.first() == "bgcolor")
		shape->node()->setBackgroundColor(commandTokens.last());
	else if(commandTokens.first() == "bordercolor")
		shape->node()->setShapeColor(commandTokens.last());

	shape->node()->model()->endModification();
	shape->setUpdateNeeded(Visualization::Item::StandardUpdate);
	return new Interaction::CommandResult();
}

QList<Interaction::CommandSuggestion*> CShapeSetProperty::suggest(Visualization::Item*, Visualization::Item*, const QString& textSoFar)
{
	QList<Interaction::CommandSuggestion*> s;
	if(QString("fgcolor").startsWith(textSoFar.trimmed(), Qt::CaseInsensitive))
		s.append(new Interaction::CommandSuggestion("textcolor", "Set shape's foreground color"));
	if(QString("bgcolor").startsWith(textSoFar.trimmed(), Qt::CaseInsensitive))
		s.append(new Interaction::CommandSuggestion("bgcolor", "Set shape's background color"));
	if(QString("bordercolor").startsWith(textSoFar.trimmed(), Qt::CaseInsensitive))
			s.append(new Interaction::CommandSuggestion("bordercolor", "Set shape's border color"));
	return s;
}

QStringList CShapeSetProperty::commandForms(Visualization::Item*, Visualization::Item*, const QString&)
{
	QStringList forms;
	return forms;
}

}
<|endoftext|>


<commit_before>
#include "ksp_plugin/planetarium.hpp"

#include <algorithm>
#include <vector>

#include "geometry/point.hpp"
#include "quantities/elementary_functions.hpp"

namespace principia {
namespace ksp_plugin {
namespace internal_planetarium {

using geometry::Position;
using geometry::RP2Line;
using geometry::Sign;
using geometry::Velocity;
using quantities::Pow;
using quantities::Sin;
using quantities::Sqrt;
using quantities::Tan;
using quantities::Time;

Planetarium::Parameters::Parameters(double const sphere_radius_multiplier,
                                    Angle const& angular_resolution,
                                    Angle const& field_of_view)
    : sphere_radius_multiplier_(sphere_radius_multiplier),
      sin²_angular_resolution_(Pow<2>(Sin(angular_resolution))),
      tan_angular_resolution_(Tan(angular_resolution)),
      tan_field_of_view_(Tan(field_of_view)) {}

Planetarium::Planetarium(
    Parameters const& parameters,
    Perspective<Navigation, Camera> const& perspective,
    not_null<Ephemeris<Barycentric> const*> const ephemeris,
    not_null<NavigationFrame const*> const plotting_frame)
    : parameters_(parameters),
      perspective_(perspective),
      ephemeris_(ephemeris),
      plotting_frame_(plotting_frame) {}

RP2Lines<Length, Camera> Planetarium::PlotMethod0(
    DiscreteTrajectory<Barycentric>::Iterator const& begin,
    DiscreteTrajectory<Barycentric>::Iterator const& end,
    Instant const& now,
    bool const reverse) const {
  auto const plottable_begin =
      begin.trajectory()->LowerBound(plotting_frame_->t_min());
  auto const plottable_end =
      begin.trajectory()->LowerBound(plotting_frame_->t_max());
  auto const plottable_spheres = ComputePlottableSpheres(now);
  auto const plottable_segments = ComputePlottableSegments(plottable_spheres,
                                                           plottable_begin,
                                                           plottable_end);

  auto const field_of_view_radius² =
      perspective_.focal() * perspective_.focal() *
      parameters_.tan_field_of_view_ * parameters_.tan_field_of_view_;
  std::experimental::optional<Position<Navigation>> previous_position;
  RP2Lines<Length, Camera> rp2_lines;
  for (auto const& plottable_segment : plottable_segments) {
    // Apply the projection to the current plottable segment.
    auto const rp2_first = perspective_(plottable_segment.first);
    auto const rp2_second = perspective_(plottable_segment.second);

    // If the segment is entirely outside the field of view, ignore it.
    Length const x1 = rp2_first.x();
    Length const y1 = rp2_first.y();
    Length const x2 = rp2_second.x();
    Length const y2 = rp2_second.y();
    if (x1 * x1 + y1 * y1 > field_of_view_radius² &&
        x2 * x2 + y2 * y2 > field_of_view_radius²) {
      continue;
    }

    // Create a new ℝP² line when two segments are not consecutive.  Don't
    // compare ℝP² points for equality, that's expensive.
    bool const are_consecutive =
        previous_position == plottable_segment.first;
    previous_position = plottable_segment.second;

    if (are_consecutive) {
      rp2_lines.back().push_back(rp2_second);
    } else {
      RP2Line<Length, Camera> const rp2_line = {rp2_first, rp2_second};
      rp2_lines.push_back(rp2_line);
    }
  }
  return rp2_lines;
}

RP2Lines<Length, Camera> Planetarium::PlotMethod1(
    DiscreteTrajectory<Barycentric>::Iterator const& begin,
    DiscreteTrajectory<Barycentric>::Iterator const& end,
    Instant const& now,
    bool const reverse) const {
  Length const focal_plane_tolerance =
      perspective_.focal() * parameters_.tan_angular_resolution_;
  auto const focal_plane_tolerance² =
      focal_plane_tolerance * focal_plane_tolerance;

  auto const rp2_lines = PlotMethod0(begin, end, now, reverse);

  int skipped = 0;
  int total = 0;
  RP2Lines<Length, Camera> new_rp2_lines;
  for (auto const& rp2_line : rp2_lines) {
    RP2Line<Length, Camera> new_rp2_line;
    std::experimental::optional<RP2Point<Length, Camera>> start_rp2_point;
    for (int i = 0; i < rp2_line.size(); ++i) {
      RP2Point<Length, Camera> const& rp2_point = rp2_line[i];
      if (i == 0) {
        new_rp2_line.push_back(rp2_point);
        start_rp2_point = rp2_point;
      } else if (Pow<2>(rp2_point.x() - start_rp2_point->x()) +
                 Pow<2>(rp2_point.y() - start_rp2_point->y()) >
                     focal_plane_tolerance²) {
        // TODO(phl): This creates a segment if the tolerance is exceeded.  It
        // should probably create a segment that stays just below the tolerance.
        new_rp2_line.push_back(rp2_point);
        start_rp2_point = rp2_point;
      } else if (i == rp2_line.size() - 1) {
        new_rp2_line.push_back(rp2_point);
      } else {
        ++skipped;
      }
      ++total;
    }
    new_rp2_lines.push_back(std::move(new_rp2_line));
  }
  LOG(INFO) << "PlotMethod1 skipped " << skipped << " points out of " << total
            << ", emitting " << total - skipped << " points";
  return new_rp2_lines;
}

RP2Lines<Length, Camera> Planetarium::PlotMethod2(
    DiscreteTrajectory<Barycentric>::Iterator const& begin,
    DiscreteTrajectory<Barycentric>::Iterator const& end,
    Instant const& now,
    bool const reverse) const {
  RP2Lines<Length, Camera> lines;
  if (begin == end) {
    return lines;
  }
  auto last = end;
  --last;

  double const tan²_angular_resolution =
      Pow<2>(parameters_.tan_angular_resolution_);
  auto const plottable_spheres = ComputePlottableSpheres(now);
  auto const& trajectory = *begin.trajectory();
  auto const begin_time = std::max(begin.time(), plotting_frame_->t_min());
  auto const last_time = std::min(last.time(), plotting_frame_->t_max());
  auto const final_time = reverse ? begin_time : last_time;
  auto previous_time = reverse ? last_time : begin_time;
  Sign const direction = reverse ? Sign(-1) : Sign(1);
  if (direction * (final_time - previous_time) <= Time{}) {
    return lines;
  }
  RigidMotion<Barycentric, Navigation> to_plotting_frame_at_t =
      plotting_frame_->ToThisFrameAtTime(previous_time);
  DegreesOfFreedom<Navigation> const initial_degrees_of_freedom =
      to_plotting_frame_at_t(
          trajectory.EvaluateDegreesOfFreedom(previous_time));
  Position<Navigation> previous_position =
      initial_degrees_of_freedom.position();
  Velocity<Navigation> previous_velocity =
      initial_degrees_of_freedom.velocity();
  Time Δt = final_time - previous_time;

  Instant t;
  double estimated_tan²_error;
  std::experimental::optional<DegreesOfFreedom<Barycentric>>
      degrees_of_freedom_in_barycentric;
  Position<Navigation> position;

  std::experimental::optional<Position<Navigation>> last_endpoint;

  int steps_accepted = 0;
  int steps_attempted = 0;

  goto estimate_tan²_error;

  while (direction * (previous_time - final_time) < Time{} &&
         steps_accepted < 10'000) {
    do {
      // One square root because we have squared errors, another one because the
      // errors are quadratic in time (in other words, two square roots because
      // the squared errors are quartic in time).
      // A safety factor prevents catastrophic retries.
      Δt *= 0.9 * Sqrt(Sqrt(tan²_angular_resolution / estimated_tan²_error));
    estimate_tan²_error:
      t = previous_time + Δt;
      if (direction * (t - final_time) > Time{}) {
        t = final_time;
        Δt = t - previous_time;
      }
      Position<Navigation> const extrapolated_position =
          previous_position + previous_velocity * Δt;
      to_plotting_frame_at_t = plotting_frame_->ToThisFrameAtTime(t);
      degrees_of_freedom_in_barycentric =
          trajectory.EvaluateDegreesOfFreedom(t);
      position = to_plotting_frame_at_t.rigid_transformation()(
                     degrees_of_freedom_in_barycentric->position());

      // The quadratic term of the error between the linear interpolation and
      // the actual function is maximized halfway through the segment, so it is
      // 1/2 (Δt/2)² f″(t-Δt) = (1/2 Δt² f″(t-Δt)) / 4; the squared error is
      // thus (1/2 Δt² f″(t-Δt))² / 16.
      estimated_tan²_error =
          perspective_.Tan²AngularDistance(extrapolated_position, position) /
          16;
      ++steps_attempted;
    } while (estimated_tan²_error > tan²_angular_resolution);
    ++steps_accepted;

    // TODO(egg): also limit to field of view.
    auto const segment_behind_focal_plane =
        perspective_.SegmentBehindFocalPlane(
            Segment<Navigation>(previous_position, position));

    previous_time = t;
    previous_position = position;
    previous_velocity =
        to_plotting_frame_at_t(*degrees_of_freedom_in_barycentric).velocity();

    if (!segment_behind_focal_plane) {
      continue;
    }

    auto const visible_segments = perspective_.VisibleSegments(
                                      *segment_behind_focal_plane,
                                      plottable_spheres);
    for (auto const& segment : visible_segments) {
      if (last_endpoint != segment.first) {
        lines.emplace_back();
        lines.back().push_back(perspective_(segment.first));
      }
      lines.back().push_back(perspective_(segment.second));
      last_endpoint = segment.second;
    }
  }
  LOG(INFO) << "PlotMethod2 took " << steps_accepted << " steps, attempted "
            << steps_attempted << " steps";
  return lines;
}

std::vector<Sphere<Navigation>> Planetarium::ComputePlottableSpheres(
    Instant const& now) const {
  RigidMotion<Barycentric, Navigation> const rigid_motion_at_now =
      plotting_frame_->ToThisFrameAtTime(now);
  std::vector<Sphere<Navigation>> plottable_spheres;

  auto const& bodies = ephemeris_->bodies();
  for (auto const body : bodies) {
    auto const trajectory = ephemeris_->trajectory(body);
    Length const mean_radius = body->mean_radius();
    Position<Barycentric> const centre_in_barycentric =
        trajectory->EvaluatePosition(now);
    Sphere<Navigation> plottable_sphere(
        rigid_motion_at_now.rigid_transformation()(centre_in_barycentric),
        parameters_.sphere_radius_multiplier_ * mean_radius);
    // If the sphere is seen under an angle that is very small it doesn't
    // participate in hiding.
    if (perspective_.SphereSin²HalfAngle(plottable_sphere) >
        parameters_.sin²_angular_resolution_) {
      plottable_spheres.emplace_back(std::move(plottable_sphere));
    }
  }
  return plottable_spheres;
}

Segments<Navigation> Planetarium::ComputePlottableSegments(
    const std::vector<Sphere<Navigation>>& plottable_spheres,
    DiscreteTrajectory<Barycentric>::Iterator const& begin,
    DiscreteTrajectory<Barycentric>::Iterator const& end) const {
  Segments<Navigation> all_segments;
  if (begin == end) {
    return all_segments;
  }
  auto it1 = begin;
  Instant t1 = it1.time();
  RigidMotion<Barycentric, Navigation> rigid_motion_at_t1 =
      plotting_frame_->ToThisFrameAtTime(t1);
  Position<Navigation> p1 =
      rigid_motion_at_t1(it1.degrees_of_freedom()).position();

  auto it2 = it1;
  while (++it2 != end) {
    // Processing one segment of the trajectory.
    Instant const t2 = it2.time();

    // Transform the degrees of freedom to the plotting frame.
    RigidMotion<Barycentric, Navigation> const rigid_motion_at_t2 =
        plotting_frame_->ToThisFrameAtTime(t2);
    Position<Navigation> const p2 =
        rigid_motion_at_t2(it2.degrees_of_freedom()).position();

    // Find the part of the segment that is behind the focal plane.  We don't
    // care about things that are in front of the focal plane.
    const Segment<Navigation> segment = {p1, p2};
    auto const segment_behind_focal_plane =
        perspective_.SegmentBehindFocalPlane(segment);
    if (segment_behind_focal_plane) {
      // Find the part(s) of the segment that are not hidden by spheres.  These
      // are the ones we want to plot.
      auto segments = perspective_.VisibleSegments(*segment_behind_focal_plane,
                                                   plottable_spheres);
      std::move(segments.begin(),
                segments.end(),
                std::back_inserter(all_segments));
    }

    it1 = it2;
    t1 = t2;
    rigid_motion_at_t1 = rigid_motion_at_t2;
    p1 = p2;
  }

  return all_segments;
}

}  // namespace internal_planetarium
}  // namespace ksp_plugin
}  // namespace principia
<commit_msg>the linter is stupid<commit_after>
#include "ksp_plugin/planetarium.hpp"

#include <algorithm>
#include <vector>

#include "geometry/point.hpp"
#include "quantities/elementary_functions.hpp"

namespace principia {
namespace ksp_plugin {
namespace internal_planetarium {

using geometry::Position;
using geometry::RP2Line;
using geometry::Sign;
using geometry::Velocity;
using quantities::Pow;
using quantities::Sin;
using quantities::Sqrt;
using quantities::Tan;
using quantities::Time;

Planetarium::Parameters::Parameters(double const sphere_radius_multiplier,
                                    Angle const& angular_resolution,
                                    Angle const& field_of_view)
    : sphere_radius_multiplier_(sphere_radius_multiplier),
      sin²_angular_resolution_(Pow<2>(Sin(angular_resolution))),
      tan_angular_resolution_(Tan(angular_resolution)),
      tan_field_of_view_(Tan(field_of_view)) {}

Planetarium::Planetarium(
    Parameters const& parameters,
    Perspective<Navigation, Camera> const& perspective,
    not_null<Ephemeris<Barycentric> const*> const ephemeris,
    not_null<NavigationFrame const*> const plotting_frame)
    : parameters_(parameters),
      perspective_(perspective),
      ephemeris_(ephemeris),
      plotting_frame_(plotting_frame) {}

RP2Lines<Length, Camera> Planetarium::PlotMethod0(
    DiscreteTrajectory<Barycentric>::Iterator const& begin,
    DiscreteTrajectory<Barycentric>::Iterator const& end,
    Instant const& now,
    bool const reverse) const {
  auto const plottable_begin =
      begin.trajectory()->LowerBound(plotting_frame_->t_min());
  auto const plottable_end =
      begin.trajectory()->LowerBound(plotting_frame_->t_max());
  auto const plottable_spheres = ComputePlottableSpheres(now);
  auto const plottable_segments = ComputePlottableSegments(plottable_spheres,
                                                           plottable_begin,
                                                           plottable_end);

  auto const field_of_view_radius² =
      perspective_.focal() * perspective_.focal() *
      parameters_.tan_field_of_view_ * parameters_.tan_field_of_view_;
  std::experimental::optional<Position<Navigation>> previous_position;
  RP2Lines<Length, Camera> rp2_lines;
  for (auto const& plottable_segment : plottable_segments) {
    // Apply the projection to the current plottable segment.
    auto const rp2_first = perspective_(plottable_segment.first);
    auto const rp2_second = perspective_(plottable_segment.second);

    // If the segment is entirely outside the field of view, ignore it.
    Length const x1 = rp2_first.x();
    Length const y1 = rp2_first.y();
    Length const x2 = rp2_second.x();
    Length const y2 = rp2_second.y();
    if (x1 * x1 + y1 * y1 > field_of_view_radius² &&
        x2 * x2 + y2 * y2 > field_of_view_radius²) {
      continue;
    }

    // Create a new ℝP² line when two segments are not consecutive.  Don't
    // compare ℝP² points for equality, that's expensive.
    bool const are_consecutive =
        previous_position == plottable_segment.first;
    previous_position = plottable_segment.second;

    if (are_consecutive) {
      rp2_lines.back().push_back(rp2_second);
    } else {
      RP2Line<Length, Camera> const rp2_line = {rp2_first, rp2_second};
      rp2_lines.push_back(rp2_line);
    }
  }
  return rp2_lines;
}

RP2Lines<Length, Camera> Planetarium::PlotMethod1(
    DiscreteTrajectory<Barycentric>::Iterator const& begin,
    DiscreteTrajectory<Barycentric>::Iterator const& end,
    Instant const& now,
    bool const reverse) const {
  Length const focal_plane_tolerance =
      perspective_.focal() * parameters_.tan_angular_resolution_;
  auto const focal_plane_tolerance² =
      focal_plane_tolerance * focal_plane_tolerance;

  auto const rp2_lines = PlotMethod0(begin, end, now, reverse);

  int skipped = 0;
  int total = 0;
  RP2Lines<Length, Camera> new_rp2_lines;
  for (auto const& rp2_line : rp2_lines) {
    RP2Line<Length, Camera> new_rp2_line;
    std::experimental::optional<RP2Point<Length, Camera>> start_rp2_point;
    for (int i = 0; i < rp2_line.size(); ++i) {
      RP2Point<Length, Camera> const& rp2_point = rp2_line[i];
      if (i == 0) {
        new_rp2_line.push_back(rp2_point);
        start_rp2_point = rp2_point;
      } else if (Pow<2>(rp2_point.x() - start_rp2_point->x()) +
                 Pow<2>(rp2_point.y() - start_rp2_point->y()) >
                     focal_plane_tolerance²) {
        // TODO(phl): This creates a segment if the tolerance is exceeded.  It
        // should probably create a segment that stays just below the tolerance.
        new_rp2_line.push_back(rp2_point);
        start_rp2_point = rp2_point;
      } else if (i == rp2_line.size() - 1) {
        new_rp2_line.push_back(rp2_point);
      } else {
        ++skipped;
      }
      ++total;
    }
    new_rp2_lines.push_back(std::move(new_rp2_line));
  }
  LOG(INFO) << "PlotMethod1 skipped " << skipped << " points out of " << total
            << ", emitting " << total - skipped << " points";
  return new_rp2_lines;
}

RP2Lines<Length, Camera> Planetarium::PlotMethod2(
    DiscreteTrajectory<Barycentric>::Iterator const& begin,
    DiscreteTrajectory<Barycentric>::Iterator const& end,
    Instant const& now,
    bool const reverse) const {
  RP2Lines<Length, Camera> lines;
  if (begin == end) {
    return lines;
  }
  auto last = end;
  --last;

  double const tan²_angular_resolution =
      Pow<2>(parameters_.tan_angular_resolution_);
  auto const plottable_spheres = ComputePlottableSpheres(now);
  auto const& trajectory = *begin.trajectory();
  auto const begin_time = std::max(begin.time(), plotting_frame_->t_min());
  auto const last_time = std::min(last.time(), plotting_frame_->t_max());
  auto const final_time = reverse ? begin_time : last_time;
  auto previous_time = reverse ? last_time : begin_time;
  Sign const direction = reverse ? Sign(-1) : Sign(1);
  if (direction * (final_time - previous_time) <= Time{}) {
    return lines;
  }
  RigidMotion<Barycentric, Navigation> to_plotting_frame_at_t =
      plotting_frame_->ToThisFrameAtTime(previous_time);
  DegreesOfFreedom<Navigation> const initial_degrees_of_freedom =
      to_plotting_frame_at_t(
          trajectory.EvaluateDegreesOfFreedom(previous_time));
  Position<Navigation> previous_position =
      initial_degrees_of_freedom.position();
  Velocity<Navigation> previous_velocity =
      initial_degrees_of_freedom.velocity();
  Time Δt = final_time - previous_time;

  Instant t;
  double estimated_tan²_error;
  std::experimental::optional<DegreesOfFreedom<Barycentric>>
      degrees_of_freedom_in_barycentric;
  Position<Navigation> position;

  std::experimental::optional<Position<Navigation>> last_endpoint;

  int steps_accepted = 0;
  int steps_attempted = 0;

  goto estimate_tan²_error;

  while (steps_accepted < 10'000 &&
         direction * (previous_time - final_time) < Time{}) {
    do {
      // One square root because we have squared errors, another one because the
      // errors are quadratic in time (in other words, two square roots because
      // the squared errors are quartic in time).
      // A safety factor prevents catastrophic retries.
      Δt *= 0.9 * Sqrt(Sqrt(tan²_angular_resolution / estimated_tan²_error));
    estimate_tan²_error:
      t = previous_time + Δt;
      if (direction * (t - final_time) > Time{}) {
        t = final_time;
        Δt = t - previous_time;
      }
      Position<Navigation> const extrapolated_position =
          previous_position + previous_velocity * Δt;
      to_plotting_frame_at_t = plotting_frame_->ToThisFrameAtTime(t);
      degrees_of_freedom_in_barycentric =
          trajectory.EvaluateDegreesOfFreedom(t);
      position = to_plotting_frame_at_t.rigid_transformation()(
                     degrees_of_freedom_in_barycentric->position());

      // The quadratic term of the error between the linear interpolation and
      // the actual function is maximized halfway through the segment, so it is
      // 1/2 (Δt/2)² f″(t-Δt) = (1/2 Δt² f″(t-Δt)) / 4; the squared error is
      // thus (1/2 Δt² f″(t-Δt))² / 16.
      estimated_tan²_error =
          perspective_.Tan²AngularDistance(extrapolated_position, position) /
          16;
      ++steps_attempted;
    } while (estimated_tan²_error > tan²_angular_resolution);
    ++steps_accepted;

    // TODO(egg): also limit to field of view.
    auto const segment_behind_focal_plane =
        perspective_.SegmentBehindFocalPlane(
            Segment<Navigation>(previous_position, position));

    previous_time = t;
    previous_position = position;
    previous_velocity =
        to_plotting_frame_at_t(*degrees_of_freedom_in_barycentric).velocity();

    if (!segment_behind_focal_plane) {
      continue;
    }

    auto const visible_segments = perspective_.VisibleSegments(
                                      *segment_behind_focal_plane,
                                      plottable_spheres);
    for (auto const& segment : visible_segments) {
      if (last_endpoint != segment.first) {
        lines.emplace_back();
        lines.back().push_back(perspective_(segment.first));
      }
      lines.back().push_back(perspective_(segment.second));
      last_endpoint = segment.second;
    }
  }
  LOG(INFO) << "PlotMethod2 took " << steps_accepted << " steps, attempted "
            << steps_attempted << " steps";
  return lines;
}

std::vector<Sphere<Navigation>> Planetarium::ComputePlottableSpheres(
    Instant const& now) const {
  RigidMotion<Barycentric, Navigation> const rigid_motion_at_now =
      plotting_frame_->ToThisFrameAtTime(now);
  std::vector<Sphere<Navigation>> plottable_spheres;

  auto const& bodies = ephemeris_->bodies();
  for (auto const body : bodies) {
    auto const trajectory = ephemeris_->trajectory(body);
    Length const mean_radius = body->mean_radius();
    Position<Barycentric> const centre_in_barycentric =
        trajectory->EvaluatePosition(now);
    Sphere<Navigation> plottable_sphere(
        rigid_motion_at_now.rigid_transformation()(centre_in_barycentric),
        parameters_.sphere_radius_multiplier_ * mean_radius);
    // If the sphere is seen under an angle that is very small it doesn't
    // participate in hiding.
    if (perspective_.SphereSin²HalfAngle(plottable_sphere) >
        parameters_.sin²_angular_resolution_) {
      plottable_spheres.emplace_back(std::move(plottable_sphere));
    }
  }
  return plottable_spheres;
}

Segments<Navigation> Planetarium::ComputePlottableSegments(
    const std::vector<Sphere<Navigation>>& plottable_spheres,
    DiscreteTrajectory<Barycentric>::Iterator const& begin,
    DiscreteTrajectory<Barycentric>::Iterator const& end) const {
  Segments<Navigation> all_segments;
  if (begin == end) {
    return all_segments;
  }
  auto it1 = begin;
  Instant t1 = it1.time();
  RigidMotion<Barycentric, Navigation> rigid_motion_at_t1 =
      plotting_frame_->ToThisFrameAtTime(t1);
  Position<Navigation> p1 =
      rigid_motion_at_t1(it1.degrees_of_freedom()).position();

  auto it2 = it1;
  while (++it2 != end) {
    // Processing one segment of the trajectory.
    Instant const t2 = it2.time();

    // Transform the degrees of freedom to the plotting frame.
    RigidMotion<Barycentric, Navigation> const rigid_motion_at_t2 =
        plotting_frame_->ToThisFrameAtTime(t2);
    Position<Navigation> const p2 =
        rigid_motion_at_t2(it2.degrees_of_freedom()).position();

    // Find the part of the segment that is behind the focal plane.  We don't
    // care about things that are in front of the focal plane.
    const Segment<Navigation> segment = {p1, p2};
    auto const segment_behind_focal_plane =
        perspective_.SegmentBehindFocalPlane(segment);
    if (segment_behind_focal_plane) {
      // Find the part(s) of the segment that are not hidden by spheres.  These
      // are the ones we want to plot.
      auto segments = perspective_.VisibleSegments(*segment_behind_focal_plane,
                                                   plottable_spheres);
      std::move(segments.begin(),
                segments.end(),
                std::back_inserter(all_segments));
    }

    it1 = it2;
    t1 = t2;
    rigid_motion_at_t1 = rigid_motion_at_t2;
    p1 = p2;
  }

  return all_segments;
}

}  // namespace internal_planetarium
}  // namespace ksp_plugin
}  // namespace principia
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2011 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 "webrtc/voice_engine/channel_manager.h"

#include "webrtc/voice_engine/channel.h"

namespace webrtc {
namespace voe {

ChannelOwner::ChannelOwner(class Channel* channel)
    : channel_ref_(new ChannelRef(channel)) {}

ChannelOwner::ChannelOwner(const ChannelOwner& channel_owner)
    : channel_ref_(channel_owner.channel_ref_) {
  ++channel_ref_->ref_count;
}

ChannelOwner::~ChannelOwner() {
  if (--channel_ref_->ref_count == 0)
    delete channel_ref_;
}

ChannelOwner& ChannelOwner::operator=(const ChannelOwner& other) {
  if (other.channel_ref_ == channel_ref_)
    return *this;

  if (--channel_ref_->ref_count == 0)
    delete channel_ref_;

  channel_ref_ = other.channel_ref_;
  ++channel_ref_->ref_count;

  return *this;
}

ChannelOwner::ChannelRef::ChannelRef(class Channel* channel)
    : channel(channel), ref_count(1) {}

ChannelManager::ChannelManager(uint32_t instance_id)
    : instance_id_(instance_id),
      last_channel_id_(-1),
      lock_(CriticalSectionWrapper::CreateCriticalSection()) {}

ChannelOwner ChannelManager::CreateChannel() {
  Channel* channel;
  Channel::CreateChannel(channel, ++last_channel_id_, instance_id_);
  ChannelOwner channel_owner(channel);

  CriticalSectionScoped crit(lock_.get());

  channels_.push_back(channel_owner);

  return channel_owner;
}

ChannelOwner ChannelManager::GetChannel(int32_t channel_id) {
  CriticalSectionScoped crit(lock_.get());

  for (size_t i = 0; i < channels_.size(); ++i) {
    if (channels_[i].channel()->ChannelId() == channel_id)
      return channels_[i];
  }
  return ChannelOwner(NULL);
}

void ChannelManager::GetAllChannels(std::vector<ChannelOwner>* channels) {
  CriticalSectionScoped crit(lock_.get());

  *channels = channels_;
}

void ChannelManager::DestroyChannel(int32_t channel_id) {
  CriticalSectionScoped crit(lock_.get());
  assert(channel_id >= 0);

  for (std::vector<ChannelOwner>::iterator it = channels_.begin();
       it != channels_.end();
       ++it) {
    if (it->channel()->ChannelId() == channel_id) {
      channels_.erase(it);
      break;
    }
  }
}

void ChannelManager::DestroyAllChannels() {
  CriticalSectionScoped crit(lock_.get());
  channels_.clear();
}

size_t ChannelManager::NumOfChannels() const {
  CriticalSectionScoped crit(lock_.get());
  return channels_.size();
}

ChannelManager::Iterator::Iterator(ChannelManager* channel_manager)
    : iterator_pos_(0) {
  channel_manager->GetAllChannels(&channels_);
}

Channel* ChannelManager::Iterator::GetChannel() {
  if (iterator_pos_ < channels_.size())
    return channels_[iterator_pos_].channel();
  return NULL;
}

bool ChannelManager::Iterator::IsValid() {
  return iterator_pos_ < channels_.size();
}

void ChannelManager::Iterator::Increment() {
  ++iterator_pos_;
}

}  // namespace voe
}  // namespace webrtc
<commit_msg>Delete Channels without ChannelManager lock.<commit_after>/*
 *  Copyright (c) 2011 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 "webrtc/voice_engine/channel_manager.h"

#include "webrtc/voice_engine/channel.h"

namespace webrtc {
namespace voe {

ChannelOwner::ChannelOwner(class Channel* channel)
    : channel_ref_(new ChannelRef(channel)) {}

ChannelOwner::ChannelOwner(const ChannelOwner& channel_owner)
    : channel_ref_(channel_owner.channel_ref_) {
  ++channel_ref_->ref_count;
}

ChannelOwner::~ChannelOwner() {
  if (--channel_ref_->ref_count == 0)
    delete channel_ref_;
}

ChannelOwner& ChannelOwner::operator=(const ChannelOwner& other) {
  if (other.channel_ref_ == channel_ref_)
    return *this;

  if (--channel_ref_->ref_count == 0)
    delete channel_ref_;

  channel_ref_ = other.channel_ref_;
  ++channel_ref_->ref_count;

  return *this;
}

ChannelOwner::ChannelRef::ChannelRef(class Channel* channel)
    : channel(channel), ref_count(1) {}

ChannelManager::ChannelManager(uint32_t instance_id)
    : instance_id_(instance_id),
      last_channel_id_(-1),
      lock_(CriticalSectionWrapper::CreateCriticalSection()) {}

ChannelOwner ChannelManager::CreateChannel() {
  Channel* channel;
  Channel::CreateChannel(channel, ++last_channel_id_, instance_id_);
  ChannelOwner channel_owner(channel);

  CriticalSectionScoped crit(lock_.get());

  channels_.push_back(channel_owner);

  return channel_owner;
}

ChannelOwner ChannelManager::GetChannel(int32_t channel_id) {
  CriticalSectionScoped crit(lock_.get());

  for (size_t i = 0; i < channels_.size(); ++i) {
    if (channels_[i].channel()->ChannelId() == channel_id)
      return channels_[i];
  }
  return ChannelOwner(NULL);
}

void ChannelManager::GetAllChannels(std::vector<ChannelOwner>* channels) {
  CriticalSectionScoped crit(lock_.get());

  *channels = channels_;
}

void ChannelManager::DestroyChannel(int32_t channel_id) {
  assert(channel_id >= 0);
  // Holds a reference to a channel, this is used so that we never delete
  // Channels while holding a lock, but rather when the method returns.
  ChannelOwner reference(NULL);
  {
    CriticalSectionScoped crit(lock_.get());

    for (std::vector<ChannelOwner>::iterator it = channels_.begin();
         it != channels_.end();
         ++it) {
      if (it->channel()->ChannelId() == channel_id) {
        reference = *it;
        channels_.erase(it);
        break;
      }
    }
  }
}

void ChannelManager::DestroyAllChannels() {
  // Holds references so that Channels are not destroyed while holding this
  // lock, but rather when the method returns.
  std::vector<ChannelOwner> references;
  {
    CriticalSectionScoped crit(lock_.get());
    references = channels_;
    channels_.clear();
  }
}

size_t ChannelManager::NumOfChannels() const {
  CriticalSectionScoped crit(lock_.get());
  return channels_.size();
}

ChannelManager::Iterator::Iterator(ChannelManager* channel_manager)
    : iterator_pos_(0) {
  channel_manager->GetAllChannels(&channels_);
}

Channel* ChannelManager::Iterator::GetChannel() {
  if (iterator_pos_ < channels_.size())
    return channels_[iterator_pos_].channel();
  return NULL;
}

bool ChannelManager::Iterator::IsValid() {
  return iterator_pos_ < channels_.size();
}

void ChannelManager::Iterator::Increment() {
  ++iterator_pos_;
}

}  // namespace voe
}  // namespace webrtc
<|endoftext|>