<commit_before>/* mbed Microcontroller Library
 * Copyright (c) 2006-2013 ARM Limited
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "Stream.h"

#include <cstdarg>

namespace mbed {

Stream::Stream(const char *name) : FileLike(name), _file(NULL) {
    /* open ourselves */
    char buf[12]; /* :0x12345678 + null byte */
    std::sprintf(buf, ":%p", this);
    _file = std::fopen(buf, "w+");
    setbuf(_file, NULL);
}

Stream::~Stream() {
    fclose(_file);
}

int Stream::putc(int c) {
    fflush(_file);
    return std::fputc(c, _file);
}
int Stream::puts(const char *s) {
    fflush(_file);
    return std::fputs(s, _file);
}
int Stream::getc() {
    fflush(_file);
    return std::fgetc(_file);
}
char* Stream::gets(char *s, int size) {
    fflush(_file);
    return std::fgets(s,size,_file);
}

int Stream::close() {
    return 0;
}

ssize_t Stream::write(const void* buffer, size_t length) {
    const char* ptr = (const char*)buffer;
    const char* end = ptr + length;
    while (ptr != end) {
        if (_putc(*ptr++) == EOF) {
            break;
        }
    }
    return ptr - (const char*)buffer;
}

ssize_t Stream::read(void* buffer, size_t length) {
    char* ptr = (char*)buffer;
    char* end = ptr + length;
    while (ptr != end) {
        int c = _getc();
        if (c==EOF) break;
        *ptr++ = c;
    }
    return ptr - (const char*)buffer;
}

off_t Stream::lseek(off_t offset, int whence) {
    return 0;
}

int Stream::isatty() {
    return 0;
}

int Stream::fsync() {
    return 0;
}

off_t Stream::flen() {
    return 0;
}

int Stream::printf(const char* format, ...) {
    std::va_list arg;
    va_start(arg, format);
    fflush(_file);
    int r = vfprintf(_file, format, arg);
    va_end(arg);
    return r;
}

int Stream::scanf(const char* format, ...) {
    std::va_list arg;
    va_start(arg, format);
    fflush(_file);
    int r = vfscanf(_file, format, arg);
    va_end(arg);
    return r;
}

} // namespace mbed
<commit_msg>Fixed IAR serial fgets fgetc<commit_after>/* mbed Microcontroller Library
 * Copyright (c) 2006-2013 ARM Limited
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "Stream.h"

#include <cstdarg>

namespace mbed {

Stream::Stream(const char *name) : FileLike(name), _file(NULL) {
    /* open ourselves */
    char buf[12]; /* :0x12345678 + null byte */
    std::sprintf(buf, ":%p", this);
    _file = std::fopen(buf, "w+");
#if defined (__ICCARM__)
    std::setvbuf(_file,buf,_IONBF,NULL);
#else
    setbuf(_file, NULL);
#endif
}

Stream::~Stream() {
    fclose(_file);
}

int Stream::putc(int c) {
    fflush(_file);
    return std::fputc(c, _file);
}
int Stream::puts(const char *s) {
    fflush(_file);
    return std::fputs(s, _file);
}
int Stream::getc() {
    fflush(_file);
#if defined (__ICCARM__)
    int res = std::fgetc(_file);
    if (res>=0){
        _file->_Mode = (unsigned short)(_file->_Mode & ~ 0x1000);/* Unset read mode */
        _file->_Rend = _file->_Wend;
        _file->_Next = _file->_Wend;
    }
    return res;
#else
    return std::fgetc(_file);
#endif
}
char* Stream::gets(char *s, int size) {
    fflush(_file);
#if defined (__ICCARM__)
    char *str = fgets(s,size,_file);
    if (str!=NULL){
        _file->_Mode = (unsigned short)(_file->_Mode & ~ 0x1000);/* Unset read mode */
        _file->_Rend = _file->_Wend;
        _file->_Next = _file->_Wend;
    }
    return str;
#else
    return std::fgets(s,size,_file);
#endif
}

int Stream::close() {
    return 0;
}

ssize_t Stream::write(const void* buffer, size_t length) {
    const char* ptr = (const char*)buffer;
    const char* end = ptr + length;
    while (ptr != end) {
        if (_putc(*ptr++) == EOF) {
            break;
        }
    }
    return ptr - (const char*)buffer;
}

ssize_t Stream::read(void* buffer, size_t length) {
    char* ptr = (char*)buffer;
    char* end = ptr + length;
    while (ptr != end) {
        int c = _getc();
        if (c==EOF) break;
        *ptr++ = c;
    }
    return ptr - (const char*)buffer;
}

off_t Stream::lseek(off_t offset, int whence) {
    return 0;
}

int Stream::isatty() {
    return 0;
}

int Stream::fsync() {
    return 0;
}

off_t Stream::flen() {
    return 0;
}

int Stream::printf(const char* format, ...) {
    std::va_list arg;
    va_start(arg, format);
    fflush(_file);
    int r = vfprintf(_file, format, arg);
    va_end(arg);
    return r;
}

int Stream::scanf(const char* format, ...) {
    std::va_list arg;
    va_start(arg, format);
    fflush(_file);
    int r = vfscanf(_file, format, arg);
    va_end(arg);
    return r;
}

} // namespace mbed
<|endoftext|>


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

Program:   Medical Imaging & Interaction Toolkit
Language:  C++
Date:      $Date: 2009-05-13 14:52:01 +0200 (Mi, 13. Mai 2009) $
Version:   $Revision: 17230 $

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "mitkTrackingDeviceSource.h"
#include "mitkVirtualTrackingDevice.h"

#include "mitkTestingMacros.h"
#include <mitkReferenceCountWatcher.h>
#include "itksys/SystemTools.hxx"

/**Documentation
 *  test for the class "NavigationDataSource".
 */
int mitkTrackingDeviceSourceTest(int /* argc */, char* /*argv*/[])
{
  MITK_TEST_BEGIN("TrackingDeviceSource");

  // let's create an object of our class
  mitk::TrackingDeviceSource::Pointer mySource = mitk::TrackingDeviceSource::New();

  // first test: did this work?
  // using MITK_TEST_CONDITION_REQUIRED makes the test stop after failure, since
  // it makes no sense to continue without an object.
  MITK_TEST_CONDITION_REQUIRED(mySource.IsNotNull(), "Testing instantiation");

  mySource->SetTrackingDevice(NULL);
  MITK_TEST_CONDITION(mySource->GetTrackingDevice() == NULL, "Testing Set/GetTrackingDevice(NULL)");
  MITK_TEST_CONDITION(mySource->GetNumberOfOutputs() == 0, "Testing GetNumberOfOutputs with NULL td");
  MITK_TEST_FOR_EXCEPTION(std::invalid_argument, mySource->Connect());
  MITK_TEST_FOR_EXCEPTION(std::invalid_argument, mySource->StartTracking());

  mitk::VirtualTrackingDevice::Pointer tracker = mitk::VirtualTrackingDevice::New();

  mySource->SetTrackingDevice(tracker);
  MITK_TEST_CONDITION(mySource->GetTrackingDevice() == tracker.GetPointer(), "Testing Set/GetTrackingDevice(tracker)");
  MITK_TEST_CONDITION(mySource->GetNumberOfOutputs() == 0, "Testing GetNumberOfOutputs with no tool tracker");
  tracker = mitk::VirtualTrackingDevice::New();
  mitk::ReferenceCountWatcher::Pointer watch = new mitk::ReferenceCountWatcher(tracker);

  tracker->AddTool("T0");
  tracker->AddTool("T1");
  mySource->SetTrackingDevice(tracker);
  MITK_TEST_CONDITION(mySource->GetTrackingDevice() == tracker.GetPointer(), "Testing Set/GetTrackingDevice(tracker2)");
  MITK_TEST_CONDITION(mySource->GetNumberOfOutputs() == 2, "Testing GetNumberOfOutputs with 2 tools tracker");
  MITK_TEST_CONDITION(mySource->IsConnected() == false, "Testing IsConnected()");
  mySource->Connect();
  MITK_TEST_CONDITION(mySource->IsConnected() == true, "Testing Connect()/IsConnected()");
  MITK_TEST_CONDITION(tracker->GetState() == mitk::TrackingDevice::Ready, "Testing Connect()/IsConnected() 2");
  mySource->Disconnect();
  MITK_TEST_CONDITION(mySource->IsConnected() == false, "Testing Disconnect()/IsConnected()");
  MITK_TEST_CONDITION(tracker->GetState() == mitk::TrackingDevice::Setup, "Testing Disconnect()/IsConnected() 2");

  mySource->Connect();
  mySource->StartTracking();
  MITK_TEST_CONDITION(mySource->IsConnected() == true, "Testing StartTracking()/IsConnected()");
  MITK_TEST_CONDITION(mySource->IsTracking() == true, "Testing StartTracking()/IsTracking()");
  MITK_TEST_CONDITION(tracker->GetState() == mitk::TrackingDevice::Tracking, "Testing StartTracking()/IsTracking() 2");

  unsigned long modTime = mySource->GetMTime();
  mySource->UpdateOutputInformation();
  MITK_TEST_CONDITION(mySource->GetMTime() != modTime, "Testing if UpdateOutputInformation() modifies the object");

  mitk::NavigationData* nd0 = mySource->GetOutput(0);

  nd0->Update();
  mitk::NavigationData::PositionType pos = nd0->GetPosition();
  itksys::SystemTools::Delay(500); // allow the tracking thread to advance the tool position
  nd0->Update();
  MITK_TEST_CONDITION(mitk::Equal(nd0->GetPosition(), pos) == false, "Testing if output changes on each update");
  mitk::NavigationData* nd1 = mySource->GetOutput(1);
  MITK_TEST_CONDITION(nd0 != nd1, "Testing if outputs are different");
  MITK_TEST_CONDITION(mitk::Equal(nd0->GetPosition(), nd1->GetPosition()) == false, "Testing if output contents are different");

  mySource->StopTracking();
  mySource->Disconnect();

  tracker = mitk::VirtualTrackingDevice::New();
  mySource->SetTrackingDevice(tracker);
  MITK_TEST_CONDITION(watch->GetReferenceCount() == 0, "Testing if reference to previous tracker object is released");
  watch = NULL;

  MITK_TEST_FOR_EXCEPTION(std::runtime_error, mySource->StartTracking()); // new tracker, needs Connect() before StartTracking()

  mySource->Connect();
  mySource->StartTracking();
 // itksys::SystemTools::Delay(800); // wait for tracking thread to start properly //DEBUG ONLY  --> race condition. will the thread start before the object is destroyed? --> maybe hold a smartpointer?
  try
  {
    mySource = NULL;  // delete source
    tracker = NULL;   // delete tracker --> both should not result in any exceptions or deadlocks
  }
  catch (...)
  {
    MITK_TEST_FAILED_MSG(<< "exception during destruction of source or tracker!");
  }

  // always end with this!
  MITK_TEST_END();
}
<commit_msg>Added check for modification time of NavigationData to test class.<commit_after>/*=========================================================================

Program:   Medical Imaging & Interaction Toolkit
Language:  C++
Date:      $Date: 2009-05-13 14:52:01 +0200 (Mi, 13. Mai 2009) $
Version:   $Revision: 17230 $

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "mitkTrackingDeviceSource.h"
#include "mitkVirtualTrackingDevice.h"

#include "mitkTestingMacros.h"
#include <mitkReferenceCountWatcher.h>
#include "itksys/SystemTools.hxx"

/**Documentation
 *  test for the class "NavigationDataSource".
 */
int mitkTrackingDeviceSourceTest(int /* argc */, char* /*argv*/[])
{
  MITK_TEST_BEGIN("TrackingDeviceSource");

  // let's create an object of our class
  mitk::TrackingDeviceSource::Pointer mySource = mitk::TrackingDeviceSource::New();

  // first test: did this work?
  // using MITK_TEST_CONDITION_REQUIRED makes the test stop after failure, since
  // it makes no sense to continue without an object.
  MITK_TEST_CONDITION_REQUIRED(mySource.IsNotNull(), "Testing instantiation");

  mySource->SetTrackingDevice(NULL);
  MITK_TEST_CONDITION(mySource->GetTrackingDevice() == NULL, "Testing Set/GetTrackingDevice(NULL)");
  MITK_TEST_CONDITION(mySource->GetNumberOfOutputs() == 0, "Testing GetNumberOfOutputs with NULL td");
  MITK_TEST_FOR_EXCEPTION(std::invalid_argument, mySource->Connect());
  MITK_TEST_FOR_EXCEPTION(std::invalid_argument, mySource->StartTracking());

  mitk::VirtualTrackingDevice::Pointer tracker = mitk::VirtualTrackingDevice::New();

  mySource->SetTrackingDevice(tracker);
  MITK_TEST_CONDITION(mySource->GetTrackingDevice() == tracker.GetPointer(), "Testing Set/GetTrackingDevice(tracker)");
  MITK_TEST_CONDITION(mySource->GetNumberOfOutputs() == 0, "Testing GetNumberOfOutputs with no tool tracker");
  tracker = mitk::VirtualTrackingDevice::New();
  mitk::ReferenceCountWatcher::Pointer watch = new mitk::ReferenceCountWatcher(tracker);

  tracker->AddTool("T0");
  tracker->AddTool("T1");
  mySource->SetTrackingDevice(tracker);
  MITK_TEST_CONDITION(mySource->GetTrackingDevice() == tracker.GetPointer(), "Testing Set/GetTrackingDevice(tracker2)");
  MITK_TEST_CONDITION(mySource->GetNumberOfOutputs() == 2, "Testing GetNumberOfOutputs with 2 tools tracker");
  MITK_TEST_CONDITION(mySource->IsConnected() == false, "Testing IsConnected()");
  mySource->Connect();
  MITK_TEST_CONDITION(mySource->IsConnected() == true, "Testing Connect()/IsConnected()");
  MITK_TEST_CONDITION(tracker->GetState() == mitk::TrackingDevice::Ready, "Testing Connect()/IsConnected() 2");
  mySource->Disconnect();
  MITK_TEST_CONDITION(mySource->IsConnected() == false, "Testing Disconnect()/IsConnected()");
  MITK_TEST_CONDITION(tracker->GetState() == mitk::TrackingDevice::Setup, "Testing Disconnect()/IsConnected() 2");

  mySource->Connect();
  mySource->StartTracking();
  MITK_TEST_CONDITION(mySource->IsConnected() == true, "Testing StartTracking()/IsConnected()");
  MITK_TEST_CONDITION(mySource->IsTracking() == true, "Testing StartTracking()/IsTracking()");
  MITK_TEST_CONDITION(tracker->GetState() == mitk::TrackingDevice::Tracking, "Testing StartTracking()/IsTracking() 2");

  unsigned long modTime = mySource->GetMTime();
  mySource->UpdateOutputInformation();
  MITK_TEST_CONDITION(mySource->GetMTime() != modTime, "Testing if UpdateOutputInformation() modifies the object");

  mitk::NavigationData* nd0 = mySource->GetOutput(0);

  nd0->Update();
  mitk::NavigationData::PositionType pos = nd0->GetPosition();
  unsigned long tmpMTime0 = nd0->GetMTime();
  itksys::SystemTools::Delay(500); // allow the tracking thread to advance the tool position
  nd0->Update();
  if(nd0->GetMTime() == tmpMTime0) //tool not modified yet
  {
    MITK_TEST_CONDITION(mitk::Equal(nd0->GetPosition(), pos) == true, "Testing if output changes on each update");
  }
  else
  {
    MITK_TEST_CONDITION(mitk::Equal(nd0->GetPosition(), pos) == false, "Testing if output changes on each update");
  }

  mySource->StopTracking();
  mySource->Disconnect();

  tracker = mitk::VirtualTrackingDevice::New();
  mySource->SetTrackingDevice(tracker);
  MITK_TEST_CONDITION(watch->GetReferenceCount() == 0, "Testing if reference to previous tracker object is released");
  watch = NULL;

  MITK_TEST_FOR_EXCEPTION(std::runtime_error, mySource->StartTracking()); // new tracker, needs Connect() before StartTracking()

  mySource->Connect();
  mySource->StartTracking();
 // itksys::SystemTools::Delay(800); // wait for tracking thread to start properly //DEBUG ONLY  --> race condition. will the thread start before the object is destroyed? --> maybe hold a smartpointer?
  try
  {
    mySource = NULL;  // delete source
    tracker = NULL;   // delete tracker --> both should not result in any exceptions or deadlocks
  }
  catch (...)
  {
    MITK_TEST_FAILED_MSG(<< "exception during destruction of source or tracker!");
  }

  // always end with this!
  MITK_TEST_END();
}
<|endoftext|>


<commit_before><commit_msg>Adicionada questão dos dicionários de Andy<commit_after><|endoftext|>


<commit_before>#include "tools/generate_profiles.hpp"

#include <algorithm>
#include <experimental/filesystem>
#include <fstream>
#include <map>
#include <set>
#include <string>
#include <vector>

#include "glog/logging.h"
#include "google/protobuf/descriptor.h"
#include "serialization/journal.pb.h"

namespace principia {

using ::google::protobuf::Descriptor;
using ::google::protobuf::FieldDescriptor;
using ::google::protobuf::FieldOptions;
using ::google::protobuf::FileDescriptor;

namespace tools {

namespace {
char const kIn[] = "In";
char const kReturn[] = "Return";
char const kOut[] = "Out";

class Generator {
 public:
  void ProcessMethods();

  std::vector<std::string> GetCppMethodTypes() const;

 private:
  void ProcessRepeatedMessageField(FieldDescriptor const* descriptor);

  void ProcessOptionalInt32Field(FieldDescriptor const* descriptor);

  void ProcessRequiredFixed64Field(FieldDescriptor const* descriptor);
  void ProcessRequiredMessageField(FieldDescriptor const* descriptor);
  void ProcessRequiredBoolField(FieldDescriptor const* descriptor);
  void ProcessRequiredDoubleField(FieldDescriptor const* descriptor);
  void ProcessRequiredInt32Field(FieldDescriptor const* descriptor);

  void ProcessSingleStringField(FieldDescriptor const* descriptor);

  void ProcessOptionalField(FieldDescriptor const* descriptor);
  void ProcessRepeatedField(FieldDescriptor const* descriptor);
  void ProcessRequiredField(FieldDescriptor const* descriptor);

  void ProcessField(FieldDescriptor const* descriptor);

  void ProcessInOut(Descriptor const* descriptor,
                    std::vector<FieldDescriptor const*>* field_descriptors);
  void ProcessReturn(Descriptor const* descriptor);

  void ProcessMethodExtension(Descriptor const* descriptor);

 private:
  std::map<Descriptor const*, std::string> cpp_method_type_;
  std::map<FieldDescriptor const*, std::string> size_field_;
  std::set<FieldDescriptor const*> in_out_field_;
  std::map<Descriptor const*, std::string> cpp_nested_type_;
  std::map<FieldDescriptor const*, std::string> cpp_field_type_;
};

void Generator::ProcessMethods() {
  // Get the file containing |Method|.
  Descriptor const* method_descriptor = serialization::Method::descriptor();
  FileDescriptor const* file_descriptor = method_descriptor->file();

  // Process all the messages in that file.
  for (int i = 0; i < file_descriptor->message_type_count(); ++i) {
    Descriptor const* message_descriptor = file_descriptor->message_type(i);
    switch (message_descriptor->extension_count()) {
      case 0: {
        // An auxiliary message that is not an extension.  Nothing to do.
        break;
      }
      case 1: {
        // An extension.  Check that it extends |Method|.
        FieldDescriptor const* extension = message_descriptor->extension(0);
        CHECK(extension->is_extension());
        Descriptor const* containing_type = extension->containing_type();
        CHECK_EQ(method_descriptor, containing_type)
            << message_descriptor->name() << " extends a message other than "
            << method_descriptor->name() << ": " << containing_type->name();
        ProcessMethodExtension(message_descriptor);
        break;
      }
      default: {
        LOG(FATAL) << message_descriptor->name() << " has "
                   << message_descriptor->extension_count() << " extensions";
      }
    }
  }
}

std::vector<std::string> Generator::GetCppMethodTypes() const {
  std::vector<std::string> result;
  for (auto const& pair : cpp_method_type_) {
    result.push_back(pair.second);
  }
  return result;
}

void Generator::ProcessRepeatedMessageField(FieldDescriptor const* descriptor) {
  cpp_field_type_[descriptor] = descriptor->message_type()->name() +
                                " const*";
}

void Generator::ProcessOptionalInt32Field(FieldDescriptor const* descriptor) {
  cpp_field_type_[descriptor] = "int const*";
}

void Generator::ProcessRequiredFixed64Field(FieldDescriptor const* descriptor) {
  FieldOptions const& options = descriptor->options();
  CHECK(options.HasExtension(serialization::pointer_to))
      << descriptor->full_name() << " is missing a pointer_to option";
  std::string const& pointer_to =
      options.GetExtension(serialization::pointer_to);
  cpp_field_type_[descriptor] = pointer_to + "*";
}

void Generator::ProcessRequiredMessageField(FieldDescriptor const* descriptor) {
  cpp_field_type_[descriptor] = descriptor->message_type()->name();
}

void Generator::ProcessRequiredBoolField(FieldDescriptor const* descriptor) {
  cpp_field_type_[descriptor] = descriptor->cpp_type_name();
}

void Generator::ProcessRequiredDoubleField(FieldDescriptor const* descriptor) {
  cpp_field_type_[descriptor] = descriptor->cpp_type_name();
}

void Generator::ProcessRequiredInt32Field(FieldDescriptor const* descriptor) {
  cpp_field_type_[descriptor] = "int";
}

void Generator::ProcessSingleStringField(FieldDescriptor const* descriptor) {
  cpp_field_type_[descriptor] = "char const*";
}

void Generator::ProcessOptionalField(FieldDescriptor const* descriptor) {
  switch (descriptor->type()) {
    case FieldDescriptor::TYPE_INT32:
      ProcessOptionalInt32Field(descriptor);
      break;
    case FieldDescriptor::TYPE_STRING:
      ProcessSingleStringField(descriptor);
      break;
    default:
      LOG(FATAL) << descriptor->full_name() << " has unexpected type "
                 << descriptor->type_name();
  }
}

void Generator::ProcessRepeatedField(FieldDescriptor const* descriptor) {
  switch (descriptor->type()) {
    case FieldDescriptor::TYPE_MESSAGE:
      ProcessRepeatedMessageField(descriptor);
      break;
    default:
      LOG(FATAL) << descriptor->full_name() << " has unexpected type "
                 << descriptor->type_name();
  }
}

void Generator::ProcessRequiredField(FieldDescriptor const* descriptor) {
  switch (descriptor->type()) {
    case FieldDescriptor::TYPE_BOOL:
      ProcessRequiredBoolField(descriptor);
      break;
    case FieldDescriptor::TYPE_DOUBLE:
      ProcessRequiredDoubleField(descriptor);
      break;
    case FieldDescriptor::TYPE_FIXED64:
      ProcessRequiredFixed64Field(descriptor);
      break;
    case FieldDescriptor::TYPE_INT32:
      ProcessRequiredInt32Field(descriptor);
      break;
    case FieldDescriptor::TYPE_MESSAGE:
      ProcessRequiredMessageField(descriptor);
      break;
    case FieldDescriptor::TYPE_STRING:
      ProcessSingleStringField(descriptor);
      break;
    default:
      LOG(FATAL) << descriptor->full_name() << " has unexpected type "
                 << descriptor->type_name();
  }

  // For in-out fields the data is actually passed with an extra level of
  // indirection.
  if (in_out_field_.find(descriptor) != in_out_field_.end()) {
    cpp_field_type_[descriptor] += "*";
  }
}

void Generator::ProcessField(FieldDescriptor const* descriptor) {
  switch (descriptor->label()) {
    case FieldDescriptor::LABEL_OPTIONAL:
      ProcessOptionalField(descriptor);
      break;
    case FieldDescriptor::LABEL_REPEATED:
      ProcessRepeatedField(descriptor);
      break;
    case FieldDescriptor::LABEL_REQUIRED:
      ProcessRequiredField(descriptor);
      break;
  }
  FieldOptions const& options = descriptor->options();
  if (options.HasExtension(serialization::size)) {
    size_field_[descriptor] = options.GetExtension(serialization::size);
  }
}

void Generator::ProcessInOut(
    Descriptor const* descriptor,
    std::vector<FieldDescriptor const*>* field_descriptors) {
  cpp_nested_type_[descriptor] = "  struct " + descriptor->name() + " {\n";
  for (int i = 0; i < descriptor->field_count(); ++i) {
    FieldDescriptor const* field_descriptor = descriptor->field(i);
    if (field_descriptors != nullptr) {
      field_descriptors->push_back(field_descriptor);
    }
    ProcessField(field_descriptor);
    cpp_nested_type_[descriptor] += "    " +
                                    cpp_field_type_[field_descriptor] +
                                    " const " +
                                    field_descriptor->name() + ";\n";

    // This this field has a size, generate it now.
    if (size_field_.find(field_descriptor) != size_field_.end()) {
      cpp_nested_type_[descriptor] += "    int const " +
                                      size_field_[field_descriptor] + ";\n";
    }
  }
  cpp_nested_type_[descriptor] += "  };\n";
}

void Generator::ProcessReturn(Descriptor const* descriptor) {
  CHECK_EQ(1, descriptor->field_count())
      << descriptor->full_name() << " must have exactly one field";
  FieldDescriptor const* field_descriptor = descriptor->field(0);
  ProcessField(field_descriptor);
  cpp_nested_type_[descriptor] =
      "  using Return = " + cpp_field_type_[field_descriptor] + ";\n";
}

void Generator::ProcessMethodExtension(Descriptor const* descriptor) {
  bool has_in = false;
  bool has_out = false;
  bool has_return = false;

  // Do a first pass to determine which fields are in-out.  The data produced
  // here will be overwritten by the next pass.
  std::vector<FieldDescriptor const*> field_descriptors;
  for (int i = 0; i < descriptor->nested_type_count(); ++i) {
    Descriptor const* nested_descriptor = descriptor->nested_type(i);
    const std::string& nested_name = nested_descriptor->name();
    if (nested_name == kIn) {
      has_in = true;
      ProcessInOut(nested_descriptor, &field_descriptors);
    } else if (nested_name == kOut) {
      has_out = true;
      ProcessInOut(nested_descriptor, &field_descriptors);
    } else if (nested_name == kReturn) {
      has_return = true;
    } else {
      LOG(FATAL) << "Unexpected nested message "
                 << nested_descriptor->full_name();
    }
  }

  // Now mark the fields that have the same name in In and Out as in-out.
  if (has_in && has_out) {
    std::sort(field_descriptors.begin(),
              field_descriptors.end(),
              [](FieldDescriptor const* left,
                 FieldDescriptor const* right) {
                return left->name() < right->name();
              });
    for (int i = 0; i < field_descriptors.size() - 1; ++i) {
      if (field_descriptors[i]->name() == field_descriptors[i + 1]->name()) {
        in_out_field_.insert(field_descriptors[i]);
        in_out_field_.insert(field_descriptors[i + 1]);
      }
    }
  }

  // The second pass that produces the actual output.
  cpp_method_type_[descriptor] = "struct " + descriptor->name() + " {\n";
  for (int i = 0; i < descriptor->nested_type_count(); ++i) {
    Descriptor const* nested_descriptor = descriptor->nested_type(i);
    const std::string& nested_name = nested_descriptor->name();
    if (nested_name == kIn) {
      ProcessInOut(nested_descriptor, /*field_descriptors=*/nullptr);
    } else if (nested_name == kOut) {
      ProcessInOut(nested_descriptor, /*field_descriptors=*/nullptr);
    } else if (nested_name == kReturn) {
      ProcessReturn(nested_descriptor);
    }
    cpp_method_type_[descriptor] += cpp_nested_type_[nested_descriptor];
  }
  if (has_in || has_out || has_return) {
    cpp_method_type_[descriptor] += "\n";
  }
  cpp_method_type_[descriptor] +=
      "  using Message = serialization::" +
      descriptor->name() + ";\n";
  if (has_in) {
    cpp_method_type_[descriptor] += "  static void Fill(In const& in, "
                                    "not_null<Message*> const message);\n";
  }
  if (has_out) {
    cpp_method_type_[descriptor] += "  static void Fill(Out const& out, "
                                    "not_null<Message*> const message);\n";
  }
  if (has_return) {
    cpp_method_type_[descriptor] += "  static void Fill("
                                    "Return const& result, "
                                    "not_null<Message*> const message);\n";
  }
  cpp_method_type_[descriptor] += "  static void Run("
                                  "Message const& message,\n"
                                  "                  not_null<"
                                  "Player::PointerMap*> const pointer_map);"
                                  "\n";
  cpp_method_type_[descriptor] += "};\n\n";
}

}  // namespace

void GenerateProfiles() {
  Generator generator;
  generator.ProcessMethods();

  // Now write the output.
  std::experimental::filesystem::path const directory =
      SOLUTION_DIR / "journal";
  std::ofstream profiles_hpp(directory / "profiles.hpp");
  CHECK(profiles_hpp.good());

  profiles_hpp << "#pragma once\n";
  profiles_hpp << "\n";
  profiles_hpp << "#include \"base/not_null.hpp\"\n";
  profiles_hpp << "#include \"journal/player.hpp\"\n";
  profiles_hpp << "#include \"ksp_plugin/interface.hpp\"\n";
  profiles_hpp << "#include \"serialization/journal.pb.h\"\n";
  profiles_hpp << "\n";
  profiles_hpp << "namespace principia {\n";
  profiles_hpp << "\n";
  profiles_hpp << "using base::not_null;\n";
  profiles_hpp << "using ksp_plugin::KSPPart;\n";
  profiles_hpp << "using ksp_plugin::LineAndIterator;\n";
  profiles_hpp << "using ksp_plugin::NavigationFrame;\n";
  profiles_hpp << "using ksp_plugin::Plugin;\n";
  profiles_hpp << "using ksp_plugin::QP;\n";
  profiles_hpp << "using ksp_plugin::WXYZ;\n";
  profiles_hpp << "using ksp_plugin::XYZ;\n";
  profiles_hpp << "using ksp_plugin::XYZSegment;\n";
  profiles_hpp << "\n";
  profiles_hpp << "namespace journal {\n";
  profiles_hpp << "\n";

  for (auto const& cpp_method_type : generator.GetCppMethodTypes()) {
    profiles_hpp << cpp_method_type;
  }

  profiles_hpp << "}  // namespace journal\n";
  profiles_hpp << "}  // namespace principia\n";
}

}  // namespace tools
}  // namespace principia
<commit_msg>Vague attempts.<commit_after>#include "tools/generate_profiles.hpp"

#include <algorithm>
#include <experimental/filesystem>
#include <fstream>
#include <map>
#include <set>
#include <string>
#include <vector>

#include "glog/logging.h"
#include "google/protobuf/descriptor.h"
#include "serialization/journal.pb.h"

namespace principia {

using ::google::protobuf::Descriptor;
using ::google::protobuf::FieldDescriptor;
using ::google::protobuf::FieldOptions;
using ::google::protobuf::FileDescriptor;

namespace tools {

namespace {
char const kIn[] = "In";
char const kReturn[] = "Return";
char const kOut[] = "Out";

class Generator {
 public:
  void ProcessMethods();

  std::vector<std::string> GetCppMethodTypes() const;

 private:
  void ProcessRepeatedMessageField(FieldDescriptor const* descriptor);

  void ProcessOptionalInt32Field(FieldDescriptor const* descriptor);

  void ProcessRequiredFixed64Field(FieldDescriptor const* descriptor);
  void ProcessRequiredMessageField(FieldDescriptor const* descriptor);
  void ProcessRequiredBoolField(FieldDescriptor const* descriptor);
  void ProcessRequiredDoubleField(FieldDescriptor const* descriptor);
  void ProcessRequiredInt32Field(FieldDescriptor const* descriptor);

  void ProcessSingleStringField(FieldDescriptor const* descriptor);

  void ProcessOptionalField(FieldDescriptor const* descriptor);
  void ProcessRepeatedField(FieldDescriptor const* descriptor);
  void ProcessRequiredField(FieldDescriptor const* descriptor);

  void ProcessField(FieldDescriptor const* descriptor);

  void ProcessInOut(Descriptor const* descriptor,
                    std::vector<FieldDescriptor const*>* field_descriptors);
  void ProcessReturn(Descriptor const* descriptor);

  void ProcessMethodExtension(Descriptor const* descriptor);

 private:
  std::map<Descriptor const*, std::string> cpp_method_type_;
  std::map<FieldDescriptor const*, std::string> size_field_;
  std::set<FieldDescriptor const*> in_out_field_;
  std::map<Descriptor const*, std::string> cpp_nested_type_;
  std::map<FieldDescriptor const*, std::string> cpp_field_type_;
};

void Generator::ProcessMethods() {
  // Get the file containing |Method|.
  Descriptor const* method_descriptor = serialization::Method::descriptor();
  FileDescriptor const* file_descriptor = method_descriptor->file();

  // Process all the messages in that file.
  for (int i = 0; i < file_descriptor->message_type_count(); ++i) {
    Descriptor const* message_descriptor = file_descriptor->message_type(i);
    switch (message_descriptor->extension_count()) {
      case 0: {
        // An auxiliary message that is not an extension.  Nothing to do.
        break;
      }
      case 1: {
        // An extension.  Check that it extends |Method|.
        FieldDescriptor const* extension = message_descriptor->extension(0);
        CHECK(extension->is_extension());
        Descriptor const* containing_type = extension->containing_type();
        CHECK_EQ(method_descriptor, containing_type)
            << message_descriptor->name() << " extends a message other than "
            << method_descriptor->name() << ": " << containing_type->name();
        ProcessMethodExtension(message_descriptor);
        break;
      }
      default: {
        LOG(FATAL) << message_descriptor->name() << " has "
                   << message_descriptor->extension_count() << " extensions";
      }
    }
  }
}

std::vector<std::string> Generator::GetCppMethodTypes() const {
  std::vector<std::string> result;
  for (auto const& pair : cpp_method_type_) {
    result.push_back(pair.second);
  }
  return result;
}

void Generator::ProcessRepeatedMessageField(FieldDescriptor const* descriptor) {
  cpp_field_type_[descriptor] = descriptor->message_type()->name() +
                                " const*";
}

void Generator::ProcessOptionalInt32Field(FieldDescriptor const* descriptor) {
  cpp_field_type_[descriptor] = "int const*";
}

void Generator::ProcessRequiredFixed64Field(FieldDescriptor const* descriptor) {
  FieldOptions const& options = descriptor->options();
  CHECK(options.HasExtension(serialization::pointer_to))
      << descriptor->full_name() << " is missing a pointer_to option";
  std::string const& pointer_to =
      options.GetExtension(serialization::pointer_to);
  cpp_field_type_[descriptor] = pointer_to + "*";
  cpp_field_setter_[descriptor] = "set_" + descriptor->name();
}

void Generator::ProcessRequiredMessageField(FieldDescriptor const* descriptor) {
  std::string const& message_type_name = descriptor->message_type()->name();
  cpp_field_type_[descriptor] = message_type_name;
  cpp_member_serializer_[descriptor] = "Serialize" + message_type_name;
  cpp_field_setter_[descriptor] =
      "mutable_" + descriptor->name() + "()->CopyFrom";
}

void Generator::ProcessRequiredBoolField(FieldDescriptor const* descriptor) {
  cpp_field_type_[descriptor] = descriptor->cpp_type_name();
  cpp_field_setter_[descriptor] = "set_" + descriptor->name();
}

void Generator::ProcessRequiredDoubleField(FieldDescriptor const* descriptor) {
  cpp_field_type_[descriptor] = descriptor->cpp_type_name();
  cpp_field_setter_[descriptor] = "set_" + descriptor->name();
}

void Generator::ProcessRequiredInt32Field(FieldDescriptor const* descriptor) {
  cpp_field_type_[descriptor] = "int";
  cpp_field_setter_[descriptor] = "set_" + descriptor->name();
}

void Generator::ProcessSingleStringField(FieldDescriptor const* descriptor) {
  cpp_field_type_[descriptor] = "char const*";
}

void Generator::ProcessOptionalField(FieldDescriptor const* descriptor) {
  switch (descriptor->type()) {
    case FieldDescriptor::TYPE_INT32:
      ProcessOptionalInt32Field(descriptor);
      break;
    case FieldDescriptor::TYPE_STRING:
      ProcessSingleStringField(descriptor);
      break;
    default:
      LOG(FATAL) << descriptor->full_name() << " has unexpected type "
                 << descriptor->type_name();
  }
}

void Generator::ProcessRepeatedField(FieldDescriptor const* descriptor) {
  switch (descriptor->type()) {
    case FieldDescriptor::TYPE_MESSAGE:
      ProcessRepeatedMessageField(descriptor);
      break;
    default:
      LOG(FATAL) << descriptor->full_name() << " has unexpected type "
                 << descriptor->type_name();
  }
}

void Generator::ProcessRequiredField(FieldDescriptor const* descriptor) {
  switch (descriptor->type()) {
    case FieldDescriptor::TYPE_BOOL:
      ProcessRequiredBoolField(descriptor);
      break;
    case FieldDescriptor::TYPE_DOUBLE:
      ProcessRequiredDoubleField(descriptor);
      break;
    case FieldDescriptor::TYPE_FIXED64:
      ProcessRequiredFixed64Field(descriptor);
      break;
    case FieldDescriptor::TYPE_INT32:
      ProcessRequiredInt32Field(descriptor);
      break;
    case FieldDescriptor::TYPE_MESSAGE:
      ProcessRequiredMessageField(descriptor);
      break;
    case FieldDescriptor::TYPE_STRING:
      ProcessSingleStringField(descriptor);
      break;
    default:
      LOG(FATAL) << descriptor->full_name() << " has unexpected type "
                 << descriptor->type_name();
  }

  // For in-out fields the data is actually passed with an extra level of
  // indirection.
  if (in_out_field_.find(descriptor) != in_out_field_.end()) {
    cpp_field_type_[descriptor] += "*";
  }
}

void Generator::ProcessField(FieldDescriptor const* descriptor) {
  switch (descriptor->label()) {
    case FieldDescriptor::LABEL_OPTIONAL:
      ProcessOptionalField(descriptor);
      break;
    case FieldDescriptor::LABEL_REPEATED:
      ProcessRepeatedField(descriptor);
      break;
    case FieldDescriptor::LABEL_REQUIRED:
      ProcessRequiredField(descriptor);
      break;
  }
  FieldOptions const& options = descriptor->options();
  if (options.HasExtension(serialization::size)) {
    size_field_[descriptor] = options.GetExtension(serialization::size);
  }
}

void Generator::ProcessInOut(
    Descriptor const* descriptor,
    std::vector<FieldDescriptor const*>* field_descriptors) {
  cpp_nested_type_[descriptor] = "  struct " + descriptor->name() + " {\n";
  for (int i = 0; i < descriptor->field_count(); ++i) {
    FieldDescriptor const* field_descriptor = descriptor->field(i);
    if (field_descriptors != nullptr) {
      field_descriptors->push_back(field_descriptor);
    }
    ProcessField(field_descriptor);
    cpp_nested_type_[descriptor] += "    " +
                                    cpp_field_type_[field_descriptor] +
                                    " const " +
                                    field_descriptor->name() + ";\n";

    // This this field has a size, generate it now.
    if (size_field_.find(field_descriptor) != size_field_.end()) {
      cpp_nested_type_[descriptor] += "    int const " +
                                      size_field_[field_descriptor] + ";\n";
    }
  }
  cpp_nested_type_[descriptor] += "  };\n";
}

void Generator::ProcessReturn(Descriptor const* descriptor) {
  CHECK_EQ(1, descriptor->field_count())
      << descriptor->full_name() << " must have exactly one field";
  FieldDescriptor const* field_descriptor = descriptor->field(0);
  ProcessField(field_descriptor);
  cpp_nested_type_[descriptor] =
      "  using Return = " + cpp_field_type_[field_descriptor] + ";\n";
}

void Generator::ProcessMethodExtension(Descriptor const* descriptor) {
  bool has_in = false;
  bool has_out = false;
  bool has_return = false;

  // Do a first pass to determine which fields are in-out.  The data produced
  // here will be overwritten by the next pass.
  std::vector<FieldDescriptor const*> field_descriptors;
  for (int i = 0; i < descriptor->nested_type_count(); ++i) {
    Descriptor const* nested_descriptor = descriptor->nested_type(i);
    const std::string& nested_name = nested_descriptor->name();
    if (nested_name == kIn) {
      has_in = true;
      ProcessInOut(nested_descriptor, &field_descriptors);
    } else if (nested_name == kOut) {
      has_out = true;
      ProcessInOut(nested_descriptor, &field_descriptors);
    } else if (nested_name == kReturn) {
      has_return = true;
    } else {
      LOG(FATAL) << "Unexpected nested message "
                 << nested_descriptor->full_name();
    }
  }

  // Now mark the fields that have the same name in In and Out as in-out.
  if (has_in && has_out) {
    std::sort(field_descriptors.begin(),
              field_descriptors.end(),
              [](FieldDescriptor const* left,
                 FieldDescriptor const* right) {
                return left->name() < right->name();
              });
    for (int i = 0; i < field_descriptors.size() - 1; ++i) {
      if (field_descriptors[i]->name() == field_descriptors[i + 1]->name()) {
        in_out_field_.insert(field_descriptors[i]);
        in_out_field_.insert(field_descriptors[i + 1]);
      }
    }
  }

  // The second pass that produces the actual output.
  cpp_method_type_[descriptor] = "struct " + descriptor->name() + " {\n";
  for (int i = 0; i < descriptor->nested_type_count(); ++i) {
    Descriptor const* nested_descriptor = descriptor->nested_type(i);
    const std::string& nested_name = nested_descriptor->name();
    if (nested_name == kIn) {
      ProcessInOut(nested_descriptor, /*field_descriptors=*/nullptr);
    } else if (nested_name == kOut) {
      ProcessInOut(nested_descriptor, /*field_descriptors=*/nullptr);
    } else if (nested_name == kReturn) {
      ProcessReturn(nested_descriptor);
    }
    cpp_method_type_[descriptor] += cpp_nested_type_[nested_descriptor];
  }
  if (has_in || has_out || has_return) {
    cpp_method_type_[descriptor] += "\n";
  }
  cpp_method_type_[descriptor] +=
      "  using Message = serialization::" +
      descriptor->name() + ";\n";
  if (has_in) {
    cpp_method_type_[descriptor] += "  static void Fill(In const& in, "
                                    "not_null<Message*> const message);\n";
  }
  if (has_out) {
    cpp_method_type_[descriptor] += "  static void Fill(Out const& out, "
                                    "not_null<Message*> const message);\n";
  }
  if (has_return) {
    cpp_method_type_[descriptor] += "  static void Fill("
                                    "Return const& result, "
                                    "not_null<Message*> const message);\n";
  }
  cpp_method_type_[descriptor] += "  static void Run("
                                  "Message const& message,\n"
                                  "                  not_null<"
                                  "Player::PointerMap*> const pointer_map);"
                                  "\n";
  cpp_method_type_[descriptor] += "};\n\n";
}

}  // namespace

void GenerateProfiles() {
  Generator generator;
  generator.ProcessMethods();

  // Now write the output.
  std::experimental::filesystem::path const directory =
      SOLUTION_DIR / "journal";
  std::ofstream profiles_hpp(directory / "profiles.hpp");
  CHECK(profiles_hpp.good());

  profiles_hpp << "#pragma once\n";
  profiles_hpp << "\n";
  profiles_hpp << "#include \"base/not_null.hpp\"\n";
  profiles_hpp << "#include \"journal/player.hpp\"\n";
  profiles_hpp << "#include \"ksp_plugin/interface.hpp\"\n";
  profiles_hpp << "#include \"serialization/journal.pb.h\"\n";
  profiles_hpp << "\n";
  profiles_hpp << "namespace principia {\n";
  profiles_hpp << "\n";
  profiles_hpp << "using base::not_null;\n";
  profiles_hpp << "using ksp_plugin::KSPPart;\n";
  profiles_hpp << "using ksp_plugin::LineAndIterator;\n";
  profiles_hpp << "using ksp_plugin::NavigationFrame;\n";
  profiles_hpp << "using ksp_plugin::Plugin;\n";
  profiles_hpp << "using ksp_plugin::QP;\n";
  profiles_hpp << "using ksp_plugin::WXYZ;\n";
  profiles_hpp << "using ksp_plugin::XYZ;\n";
  profiles_hpp << "using ksp_plugin::XYZSegment;\n";
  profiles_hpp << "\n";
  profiles_hpp << "namespace journal {\n";
  profiles_hpp << "\n";

  for (auto const& cpp_method_type : generator.GetCppMethodTypes()) {
    profiles_hpp << cpp_method_type;
  }

  profiles_hpp << "}  // namespace journal\n";
  profiles_hpp << "}  // namespace principia\n";
}

}  // namespace tools
}  // namespace principia
<|endoftext|>


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

  Program:   Insight Segmentation & Registration Toolkit
  Module:    $RCSfile: CheckTopology.cxx,v $
  Language:  C++
$Date: 2008/12/07 03:06:27 $
$Revision: 1.8 $
  Copyright (c) 2002 Insight Consortium. All rights reserved.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "antsUtilities.h"
#include "antsAllocImage.h"
#include <algorithm>
#include <algorithm>
#include <iostream>
#include <fstream>
#include <stdio.h>
#include <time.h>

#include "itkDiscreteGaussianImageFilter.h"
#include "itkImage.h"
#include "itkExceptionObject.h"
#include "ReadWriteData.h"
#include "itkRandomImageSource.h"
#include "itkImageRandomConstIteratorWithIndex.h"
#include "itkImageLinearIteratorWithIndex.h"
#include "itkShapedNeighborhoodIterator.h"
#include "BinaryImageToMeshFilter.h"

#include "vtkCallbackCommand.h"
#include "vtkPointPicker.h"
#include "vtkCellPicker.h"
#include "vtkPolyDataWriter.h"
#include "vtkPolyDataReader.h"
#include "vtkExtractEdges.h"

#include "itkMinimumMaximumImageFilter.h"
#include "itkConnectedComponentImageFilter.h"
#include "itkRelabelComponentImageFilter.h"
#include "itkLabelStatisticsImageFilter.h"

namespace ants
{
float random_range(float lowest_number, float highest_number)
{
  float range = highest_number - lowest_number;

  return lowest_number + (float)(range * (float)rand() / (float)(RAND_MAX) );
}

float ComputeGenus(vtkPolyData* pd1)
{
  vtkExtractEdges* edgeex = vtkExtractEdges::New();

  edgeex->SetInputData(pd1);
  edgeex->Update();
  vtkPolyData* edg1 = edgeex->GetOutput();
  vtkIdType    nedg = edg1->GetNumberOfCells();
  vtkIdType    vers = pd1->GetNumberOfPoints();
  int          nfac = pd1->GetNumberOfPolys();
  float        g = 0.5 * (2.0 - vers + nedg - nfac);
  std::cout << " Genus " << g << std::endl;
  std::cout << " face " << nfac << " edg " << nedg <<  " vert " << vers << std::endl;

  // edg1->Delete(); //caused malloc err
  edgeex->Delete();   // should be deleted b/c of New() above !!
  return g;
}

float vtkComputeTopology(vtkPolyData* pd)
{
  vtkPolyDataConnectivityFilter* con = vtkPolyDataConnectivityFilter::New();

  con->SetExtractionModeToLargestRegion();
  con->SetInputData(pd);
  float g = ComputeGenus(con->GetOutput() );
  con->Delete();   // should be deleted b/c of New() above !!
  return g;
}

template <class TImage>
float GetImageTopology(typename TImage::Pointer image)
{
  typedef TImage      ImageType;
  typedef vtkPolyData MeshType;
  double aaParm = 0.024;
  typedef BinaryImageToMeshFilter<ImageType> FilterType;
  typename  FilterType::Pointer fltMesh = FilterType::New();
  fltMesh->SetInput(image);
  fltMesh->SetAntiAliasMaxRMSError(aaParm);
  fltMesh->SetAntiAliasMaxRMSError( -1000.0 );   // to do nothing
  fltMesh->SetSmoothingIterations(0);
  fltMesh->Update();
  vtkPolyData* vtkmesh = fltMesh->GetMesh();
  std::cout << " start topo " << std::endl;
  float genus =  vtkComputeTopology(vtkmesh);
  std::cout << " Genus " << genus << std::endl;
  //  vtkmesh->Delete();
  return genus;
}

template <class TImage>
void
NormalizeImage(typename TImage::Pointer image)
{
  typedef itk::ImageRegionIteratorWithIndex<TImage> Iterator;
  float    max = 0;
  Iterator vfIter2( image,  image->GetLargestPossibleRegion() );
  for(  vfIter2.GoToBegin(); !vfIter2.IsAtEnd(); ++vfIter2 )
    {
    if( vfIter2.Get() > max )
      {
      max = vfIter2.Get();
      }
    }
  if( max == 0 )
    {
    max = 1;
    }
  for(  vfIter2.GoToBegin(); !vfIter2.IsAtEnd(); ++vfIter2 )
    {
    vfIter2.Set( vfIter2.Get() / max);
    }
}

template <class TImage>
typename TImage::Pointer SmoothImage( typename TImage::Pointer image, float sig )
{
  typedef float  PixelType;
  typedef TImage ImageType;
  enum { ImageDimension = ImageType::ImageDimension };

  typedef itk::DiscreteGaussianImageFilter<ImageType, ImageType> dgf;
  typename dgf::Pointer filter = dgf::New();
  filter->SetVariance(sig);
  filter->SetUseImageSpacingOff();
  filter->SetMaximumError(.01f);
  filter->SetInput(image);
  filter->Update();
  return filter->GetOutput();
}

template <class TImage>
// std::vector<unsigned int>
typename TImage::Pointer
GetLargestComponent(typename TImage::Pointer image)
{
  enum { ImageDimension = TImage::ImageDimension };

  typedef int                                                                      InternalPixelType;
  typedef itk::Image<InternalPixelType, ImageDimension>                            InternalImageType;
  typedef TImage                                                                   OutputImageType;
  typedef itk::BinaryThresholdImageFilter<TImage, InternalImageType>               ThresholdFilterType;
  typedef itk::ConnectedComponentImageFilter<InternalImageType, InternalImageType> FilterType;
  typedef itk::RelabelComponentImageFilter<InternalImageType, InternalImageType>   RelabelType;

  typename ThresholdFilterType::Pointer threshold = ThresholdFilterType::New();
  typename FilterType::Pointer filter = FilterType::New();
  typename RelabelType::Pointer relabel = RelabelType::New();

  threshold->SetInput(image);
  threshold->SetInsideValue(itk::NumericTraits<InternalPixelType>::One);
  threshold->SetOutsideValue(itk::NumericTraits<InternalPixelType>::Zero);
  threshold->SetLowerThreshold(0.499);
  threshold->SetUpperThreshold(1.001);
  threshold->Update();

  filter->SetInput(threshold->GetOutput() );
  // if (argc > 5)
    {
    int fullyConnected = 1;  // atoi( argv[5] );
    filter->SetFullyConnected( fullyConnected );
    }
  relabel->SetInput( filter->GetOutput() );
  unsigned int minSize = 50;
  std::cout << " min Size " << minSize << std::endl;
  relabel->SetMinimumObjectSize( minSize );
  //    relabel->SetUseHistograms(true);

  try
    {
    relabel->Update();
    }
  catch( itk::ExceptionObject & excep )
    {
    std::cerr << "Relabel: exception caught !" << std::endl;
    std::cerr << excep << std::endl;
    }

  typename TImage::Pointer Clusters = AllocImage<TImage>(image, 0);

  typedef itk::ImageRegionIteratorWithIndex<InternalImageType> Iterator;
  Iterator vfIter( relabel->GetOutput(),  relabel->GetOutput()->GetLargestPossibleRegion() );

  float                     maximum = relabel->GetNumberOfObjects();
  float                     maxtstat = 0;
  std::vector<unsigned int> histogram( (int)maximum + 1);
  std::vector<float>        clustersum( (int)maximum + 1);
  for( int i = 0; i <= maximum; i++ )
    {
    histogram[i] = 0;
    clustersum[i] = 0;
    }
  for(  vfIter.GoToBegin(); !vfIter.IsAtEnd(); ++vfIter )
    {
    if( vfIter.Get() > 0 )
      {
      float vox = image->GetPixel(vfIter.GetIndex() );
      histogram[(unsigned int)vfIter.Get()] = histogram[(unsigned int)vfIter.Get()] + 1;
      clustersum[(unsigned int)vfIter.Get()] += vox;
      if( vox > maxtstat )
        {
        maxtstat = vox;
        }
      }
    }
  for(  vfIter.GoToBegin(); !vfIter.IsAtEnd(); ++vfIter )
    {
    if( vfIter.Get() > 0 )
      {
      Clusters->SetPixel( vfIter.GetIndex(), histogram[(unsigned int)vfIter.Get()]  );
      //  if ( Clusters->GetPixel( vfIter.GetIndex() ) > maximgval )
      //    maximgval=Clusters->GetPixel( vfIter.GetIndex());
      }
    else
      {
      Clusters->SetPixel(vfIter.GetIndex(), 0);
      }
    }

  float maximgval = 0;
  for(  vfIter.GoToBegin(); !vfIter.IsAtEnd(); ++vfIter )
    {
    if( Clusters->GetPixel( vfIter.GetIndex() ) > maximgval )
      {
      maximgval = Clusters->GetPixel( vfIter.GetIndex() );
      }
    }

  std::cout << " max size " << maximgval << std::endl;
  for(  vfIter.GoToBegin(); !vfIter.IsAtEnd(); ++vfIter )
    {
    if( Clusters->GetPixel( vfIter.GetIndex() ) >= maximgval )
      {
      Clusters->SetPixel( vfIter.GetIndex(), 1);
      }
    else
      {
      Clusters->SetPixel( vfIter.GetIndex(), 0);
      }
    }

  //  for (int i=0; i<=maximum; i++)
  //  std::cout << " label " << i << " ct is: " << histogram[i] << std::endl;

  return Clusters;
}

// entry point for the library; parameter 'args' is equivalent to 'argv' in (argc,argv) of commandline parameters to
// 'main()'
int CheckTopology( std::vector<std::string> args, std::ostream* )
{
  // put the arguments coming in as 'args' into standard (argc,argv) format;
  // 'args' doesn't have the command name as first, argument, so add it manually;
  // 'args' may have adjacent arguments concatenated into one argument,
  // which the parser should handle
  args.insert( args.begin(), "CheckTopology" );
  int     argc = args.size();
  char* * argv = new char *[args.size() + 1];
  for( unsigned int i = 0; i < args.size(); ++i )
    {
    // allocate space for the string plus a null character
    argv[i] = new char[args[i].length() + 1];
    std::strncpy( argv[i], args[i].c_str(), args[i].length() );
    // place the null character in the end
    argv[i][args[i].length()] = '\0';
    }
  argv[argc] = 0;
  // class to automatically cleanup argv upon destruction
  class Cleanup_argv
  {
public:
    Cleanup_argv( char* * argv_, int argc_plus_one_ ) : argv( argv_ ), argc_plus_one( argc_plus_one_ )
    {
    }

    ~Cleanup_argv()
    {
      for( unsigned int i = 0; i < argc_plus_one; ++i )
        {
        delete[] argv[i];
        }
      delete[] argv;
    }

private:
    char* *      argv;
    unsigned int argc_plus_one;
  };
  Cleanup_argv cleanup_argv( argv, argc + 1 );

  // antscout->set_stream( out_stream );

  if( argc < 2 )
    {
    std::cerr << "Parameter  missing" << std::endl;
    std::cerr << std::endl;
    std::cerr << "Usage:" << argv[0] << "  image.nii  {g0image.nii}  {threshold}" << std::endl;
    std::cerr
      <<
      " If you put an arg for g0image then image will be smoothed and thresholded \n until it has genus zero or the smoothing kernel gets too large "
      << std::endl;
    return EXIT_FAILURE;
    }

  float thresh = -1; // 0.0001;
  if( argc > 3 )
    {
    thresh = atof(argv[3]);
    }
  typedef float PixelType;
  const unsigned int ImageDimension = 3; // AvantsImageDimension;
  typedef itk::Image<PixelType, ImageDimension> ImageType;
  typedef float                                 FieldValueType;

  ImageType::Pointer image = ImageType::New();
  ReadImage<ImageType>(image, argv[1]);
  image = BinaryThreshold<ImageType>(0.5, 1.e9, 1, image);
  float initG = GetImageTopology<ImageType>(image);

  if( initG < 0 && argc > 2 )
    {
    std::cout <<  "smoothing into a Genus Zero image with thresh " << thresh <<  std::endl;
    float              G = 1;
    float              smooth = 1;
    ImageType::Pointer simage;
    while( G != 0 && smooth < 20 )
      {
      simage = SmoothImage<ImageType>(image, smooth);
      NormalizeImage<ImageType>(simage);
      simage = BinaryThreshold<ImageType>(thresh, 1.e9, 1, simage);
      ImageType::Pointer bigimage = GetLargestComponent<ImageType>(simage);
      G = GetImageTopology<ImageType>(bigimage);
      smooth = smooth + 1;
      simage = bigimage;
      std::cout << " G " <<  G << " at smoothing " << smooth << std::endl;
      }

    std::cout << " Final G " <<  G << " at smoothing " << smooth << std::endl;

    float        G2 = 0;
    unsigned int mct = 0;
    float        err = 1.e9;
    float        lasterr = 1.e10;
    float        derr = lasterr - err;
    while( G2 == 0 && derr > 0 )
      {
      lasterr = err;
      err = 0;
      ImageType::Pointer out = ants::Morphological<ImageType>(simage, 3, 0, 1);
      ImageType::Pointer bigimage = GetLargestComponent<ImageType>(out);
      G2 = GetImageTopology<ImageType>(bigimage);
      typedef itk::ImageRegionIteratorWithIndex<ImageType> ImageIteratorType;
      ImageIteratorType iter( bigimage, bigimage->GetLargestPossibleRegion() );
      iter.GoToBegin();
      while( !iter.IsAtEnd() )
        {
        err += fabs(iter.Get() - image->GetPixel(iter.GetIndex() ) );
        ++iter;
        }

      mct++;
      derr = lasterr - err;
      std::cout << " G2 " <<  G2 << " at morph " << mct << " err " << err << std::endl;
      if( G2 == 0 && derr > 0 )
        {
        simage = GetLargestComponent<ImageType>(out);
        }
      }

    WriteImage<ImageType>(simage, argv[2]);
    }
  else if( argc > 2 )
    {
    WriteImage<ImageType>(image, argv[2]);
    }
  return 0;
}
} // namespace ants
<commit_msg>BUG:  Wasn't finding vtkPolyDataReader/Writer<commit_after>/*=========================================================================

  Program:   Insight Segmentation & Registration Toolkit
  Module:    $RCSfile: CheckTopology.cxx,v $
  Language:  C++
$Date: 2008/12/07 03:06:27 $
$Revision: 1.8 $
  Copyright (c) 2002 Insight Consortium. All rights reserved.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "antsUtilities.h"
#include "antsAllocImage.h"
#include <algorithm>
#include <algorithm>
#include <iostream>
#include <fstream>
#include <stdio.h>
#include <time.h>

#include "itkDiscreteGaussianImageFilter.h"
#include "itkImage.h"
#include "itkExceptionObject.h"
#include "ReadWriteData.h"
#include "itkRandomImageSource.h"
#include "itkImageRandomConstIteratorWithIndex.h"
#include "itkImageLinearIteratorWithIndex.h"
#include "itkShapedNeighborhoodIterator.h"
#include "BinaryImageToMeshFilter.h"

#include "vtkCallbackCommand.h"
#include "vtkPointPicker.h"
#include "vtkCellPicker.h"
#include "vtkExtractEdges.h"

#include "itkMinimumMaximumImageFilter.h"
#include "itkConnectedComponentImageFilter.h"
#include "itkRelabelComponentImageFilter.h"
#include "itkLabelStatisticsImageFilter.h"

namespace ants
{
float random_range(float lowest_number, float highest_number)
{
  float range = highest_number - lowest_number;

  return lowest_number + (float)(range * (float)rand() / (float)(RAND_MAX) );
}

float ComputeGenus(vtkPolyData* pd1)
{
  vtkExtractEdges* edgeex = vtkExtractEdges::New();

  edgeex->SetInputData(pd1);
  edgeex->Update();
  vtkPolyData* edg1 = edgeex->GetOutput();
  vtkIdType    nedg = edg1->GetNumberOfCells();
  vtkIdType    vers = pd1->GetNumberOfPoints();
  int          nfac = pd1->GetNumberOfPolys();
  float        g = 0.5 * (2.0 - vers + nedg - nfac);
  std::cout << " Genus " << g << std::endl;
  std::cout << " face " << nfac << " edg " << nedg <<  " vert " << vers << std::endl;

  // edg1->Delete(); //caused malloc err
  edgeex->Delete();   // should be deleted b/c of New() above !!
  return g;
}

float vtkComputeTopology(vtkPolyData* pd)
{
  vtkPolyDataConnectivityFilter* con = vtkPolyDataConnectivityFilter::New();

  con->SetExtractionModeToLargestRegion();
  con->SetInputData(pd);
  float g = ComputeGenus(con->GetOutput() );
  con->Delete();   // should be deleted b/c of New() above !!
  return g;
}

template <class TImage>
float GetImageTopology(typename TImage::Pointer image)
{
  typedef TImage      ImageType;
  typedef vtkPolyData MeshType;
  double aaParm = 0.024;
  typedef BinaryImageToMeshFilter<ImageType> FilterType;
  typename  FilterType::Pointer fltMesh = FilterType::New();
  fltMesh->SetInput(image);
  fltMesh->SetAntiAliasMaxRMSError(aaParm);
  fltMesh->SetAntiAliasMaxRMSError( -1000.0 );   // to do nothing
  fltMesh->SetSmoothingIterations(0);
  fltMesh->Update();
  vtkPolyData* vtkmesh = fltMesh->GetMesh();
  std::cout << " start topo " << std::endl;
  float genus =  vtkComputeTopology(vtkmesh);
  std::cout << " Genus " << genus << std::endl;
  //  vtkmesh->Delete();
  return genus;
}

template <class TImage>
void
NormalizeImage(typename TImage::Pointer image)
{
  typedef itk::ImageRegionIteratorWithIndex<TImage> Iterator;
  float    max = 0;
  Iterator vfIter2( image,  image->GetLargestPossibleRegion() );
  for(  vfIter2.GoToBegin(); !vfIter2.IsAtEnd(); ++vfIter2 )
    {
    if( vfIter2.Get() > max )
      {
      max = vfIter2.Get();
      }
    }
  if( max == 0 )
    {
    max = 1;
    }
  for(  vfIter2.GoToBegin(); !vfIter2.IsAtEnd(); ++vfIter2 )
    {
    vfIter2.Set( vfIter2.Get() / max);
    }
}

template <class TImage>
typename TImage::Pointer SmoothImage( typename TImage::Pointer image, float sig )
{
  typedef float  PixelType;
  typedef TImage ImageType;
  enum { ImageDimension = ImageType::ImageDimension };

  typedef itk::DiscreteGaussianImageFilter<ImageType, ImageType> dgf;
  typename dgf::Pointer filter = dgf::New();
  filter->SetVariance(sig);
  filter->SetUseImageSpacingOff();
  filter->SetMaximumError(.01f);
  filter->SetInput(image);
  filter->Update();
  return filter->GetOutput();
}

template <class TImage>
// std::vector<unsigned int>
typename TImage::Pointer
GetLargestComponent(typename TImage::Pointer image)
{
  enum { ImageDimension = TImage::ImageDimension };

  typedef int                                                                      InternalPixelType;
  typedef itk::Image<InternalPixelType, ImageDimension>                            InternalImageType;
  typedef TImage                                                                   OutputImageType;
  typedef itk::BinaryThresholdImageFilter<TImage, InternalImageType>               ThresholdFilterType;
  typedef itk::ConnectedComponentImageFilter<InternalImageType, InternalImageType> FilterType;
  typedef itk::RelabelComponentImageFilter<InternalImageType, InternalImageType>   RelabelType;

  typename ThresholdFilterType::Pointer threshold = ThresholdFilterType::New();
  typename FilterType::Pointer filter = FilterType::New();
  typename RelabelType::Pointer relabel = RelabelType::New();

  threshold->SetInput(image);
  threshold->SetInsideValue(itk::NumericTraits<InternalPixelType>::One);
  threshold->SetOutsideValue(itk::NumericTraits<InternalPixelType>::Zero);
  threshold->SetLowerThreshold(0.499);
  threshold->SetUpperThreshold(1.001);
  threshold->Update();

  filter->SetInput(threshold->GetOutput() );
  // if (argc > 5)
    {
    int fullyConnected = 1;  // atoi( argv[5] );
    filter->SetFullyConnected( fullyConnected );
    }
  relabel->SetInput( filter->GetOutput() );
  unsigned int minSize = 50;
  std::cout << " min Size " << minSize << std::endl;
  relabel->SetMinimumObjectSize( minSize );
  //    relabel->SetUseHistograms(true);

  try
    {
    relabel->Update();
    }
  catch( itk::ExceptionObject & excep )
    {
    std::cerr << "Relabel: exception caught !" << std::endl;
    std::cerr << excep << std::endl;
    }

  typename TImage::Pointer Clusters = AllocImage<TImage>(image, 0);

  typedef itk::ImageRegionIteratorWithIndex<InternalImageType> Iterator;
  Iterator vfIter( relabel->GetOutput(),  relabel->GetOutput()->GetLargestPossibleRegion() );

  float                     maximum = relabel->GetNumberOfObjects();
  float                     maxtstat = 0;
  std::vector<unsigned int> histogram( (int)maximum + 1);
  std::vector<float>        clustersum( (int)maximum + 1);
  for( int i = 0; i <= maximum; i++ )
    {
    histogram[i] = 0;
    clustersum[i] = 0;
    }
  for(  vfIter.GoToBegin(); !vfIter.IsAtEnd(); ++vfIter )
    {
    if( vfIter.Get() > 0 )
      {
      float vox = image->GetPixel(vfIter.GetIndex() );
      histogram[(unsigned int)vfIter.Get()] = histogram[(unsigned int)vfIter.Get()] + 1;
      clustersum[(unsigned int)vfIter.Get()] += vox;
      if( vox > maxtstat )
        {
        maxtstat = vox;
        }
      }
    }
  for(  vfIter.GoToBegin(); !vfIter.IsAtEnd(); ++vfIter )
    {
    if( vfIter.Get() > 0 )
      {
      Clusters->SetPixel( vfIter.GetIndex(), histogram[(unsigned int)vfIter.Get()]  );
      //  if ( Clusters->GetPixel( vfIter.GetIndex() ) > maximgval )
      //    maximgval=Clusters->GetPixel( vfIter.GetIndex());
      }
    else
      {
      Clusters->SetPixel(vfIter.GetIndex(), 0);
      }
    }

  float maximgval = 0;
  for(  vfIter.GoToBegin(); !vfIter.IsAtEnd(); ++vfIter )
    {
    if( Clusters->GetPixel( vfIter.GetIndex() ) > maximgval )
      {
      maximgval = Clusters->GetPixel( vfIter.GetIndex() );
      }
    }

  std::cout << " max size " << maximgval << std::endl;
  for(  vfIter.GoToBegin(); !vfIter.IsAtEnd(); ++vfIter )
    {
    if( Clusters->GetPixel( vfIter.GetIndex() ) >= maximgval )
      {
      Clusters->SetPixel( vfIter.GetIndex(), 1);
      }
    else
      {
      Clusters->SetPixel( vfIter.GetIndex(), 0);
      }
    }

  //  for (int i=0; i<=maximum; i++)
  //  std::cout << " label " << i << " ct is: " << histogram[i] << std::endl;

  return Clusters;
}

// entry point for the library; parameter 'args' is equivalent to 'argv' in (argc,argv) of commandline parameters to
// 'main()'
int CheckTopology( std::vector<std::string> args, std::ostream* )
{
  // put the arguments coming in as 'args' into standard (argc,argv) format;
  // 'args' doesn't have the command name as first, argument, so add it manually;
  // 'args' may have adjacent arguments concatenated into one argument,
  // which the parser should handle
  args.insert( args.begin(), "CheckTopology" );
  int     argc = args.size();
  char* * argv = new char *[args.size() + 1];
  for( unsigned int i = 0; i < args.size(); ++i )
    {
    // allocate space for the string plus a null character
    argv[i] = new char[args[i].length() + 1];
    std::strncpy( argv[i], args[i].c_str(), args[i].length() );
    // place the null character in the end
    argv[i][args[i].length()] = '\0';
    }
  argv[argc] = 0;
  // class to automatically cleanup argv upon destruction
  class Cleanup_argv
  {
public:
    Cleanup_argv( char* * argv_, int argc_plus_one_ ) : argv( argv_ ), argc_plus_one( argc_plus_one_ )
    {
    }

    ~Cleanup_argv()
    {
      for( unsigned int i = 0; i < argc_plus_one; ++i )
        {
        delete[] argv[i];
        }
      delete[] argv;
    }

private:
    char* *      argv;
    unsigned int argc_plus_one;
  };
  Cleanup_argv cleanup_argv( argv, argc + 1 );

  // antscout->set_stream( out_stream );

  if( argc < 2 )
    {
    std::cerr << "Parameter  missing" << std::endl;
    std::cerr << std::endl;
    std::cerr << "Usage:" << argv[0] << "  image.nii  {g0image.nii}  {threshold}" << std::endl;
    std::cerr
      <<
      " If you put an arg for g0image then image will be smoothed and thresholded \n until it has genus zero or the smoothing kernel gets too large "
      << std::endl;
    return EXIT_FAILURE;
    }

  float thresh = -1; // 0.0001;
  if( argc > 3 )
    {
    thresh = atof(argv[3]);
    }
  typedef float PixelType;
  const unsigned int ImageDimension = 3; // AvantsImageDimension;
  typedef itk::Image<PixelType, ImageDimension> ImageType;
  typedef float                                 FieldValueType;

  ImageType::Pointer image = ImageType::New();
  ReadImage<ImageType>(image, argv[1]);
  image = BinaryThreshold<ImageType>(0.5, 1.e9, 1, image);
  float initG = GetImageTopology<ImageType>(image);

  if( initG < 0 && argc > 2 )
    {
    std::cout <<  "smoothing into a Genus Zero image with thresh " << thresh <<  std::endl;
    float              G = 1;
    float              smooth = 1;
    ImageType::Pointer simage;
    while( G != 0 && smooth < 20 )
      {
      simage = SmoothImage<ImageType>(image, smooth);
      NormalizeImage<ImageType>(simage);
      simage = BinaryThreshold<ImageType>(thresh, 1.e9, 1, simage);
      ImageType::Pointer bigimage = GetLargestComponent<ImageType>(simage);
      G = GetImageTopology<ImageType>(bigimage);
      smooth = smooth + 1;
      simage = bigimage;
      std::cout << " G " <<  G << " at smoothing " << smooth << std::endl;
      }

    std::cout << " Final G " <<  G << " at smoothing " << smooth << std::endl;

    float        G2 = 0;
    unsigned int mct = 0;
    float        err = 1.e9;
    float        lasterr = 1.e10;
    float        derr = lasterr - err;
    while( G2 == 0 && derr > 0 )
      {
      lasterr = err;
      err = 0;
      ImageType::Pointer out = ants::Morphological<ImageType>(simage, 3, 0, 1);
      ImageType::Pointer bigimage = GetLargestComponent<ImageType>(out);
      G2 = GetImageTopology<ImageType>(bigimage);
      typedef itk::ImageRegionIteratorWithIndex<ImageType> ImageIteratorType;
      ImageIteratorType iter( bigimage, bigimage->GetLargestPossibleRegion() );
      iter.GoToBegin();
      while( !iter.IsAtEnd() )
        {
        err += fabs(iter.Get() - image->GetPixel(iter.GetIndex() ) );
        ++iter;
        }

      mct++;
      derr = lasterr - err;
      std::cout << " G2 " <<  G2 << " at morph " << mct << " err " << err << std::endl;
      if( G2 == 0 && derr > 0 )
        {
        simage = GetLargestComponent<ImageType>(out);
        }
      }

    WriteImage<ImageType>(simage, argv[2]);
    }
  else if( argc > 2 )
    {
    WriteImage<ImageType>(image, argv[2]);
    }
  return 0;
}
} // namespace ants
<|endoftext|>


<commit_before>#define LOG_TAG "silk-h264-enc"
#include "SimpleH264Encoder.h"

#include <queue>

#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MetaData.h>
// This is an ugly hack. We forked this from libstagefright
// so we can trigger key frames and adjust bitrate
#include "MediaCodecSource.h"
#include <media/openmax/OMX_IVCommon.h>
#include <media/stagefright/OMXCodec.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
#include <utils/Thread.h>
#include <utils/SystemClock.h>
#include <utils/Log.h>

using namespace android;

static const char* kMimeTypeAvc = "video/avc";
static const uint32_t kColorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
static const int32_t kIFrameInterval = 3;

class SingleBufferMediaSource: public MediaSource {
 public:
  SingleBufferMediaSource(int width, int height)
      : mBuffer(0), mHaveNextBuffer(false) {
    mMetaData = new MetaData();
    mMetaData->setInt32(kKeyWidth, width);
    mMetaData->setInt32(kKeyHeight, height);
    mMetaData->setInt32(kKeyStride, width);
    mMetaData->setInt32(kKeySliceHeight, height);
    mMetaData->setInt32(kKeyColorFormat, kColorFormat);
    mMetaData->setCString(kKeyMIMEType, "video/raw");
  }

  status_t start(MetaData *params = NULL) override {
    (void) params;
    return 0;
  }

  status_t stop() override {
    nextFrame(nullptr); // Unclog read
    return 0;
  }

  sp<MetaData> getFormat() override {
    return mMetaData;
  }

  status_t read(MediaBuffer **buffer, const ReadOptions *options = NULL) override {
    Mutex::Autolock autolock(mBufferLock);

    if (options != NULL) {
      ALOGW("ReadOptions not supported");
      return ERROR_END_OF_STREAM;
    }

    while (!mHaveNextBuffer) {
      mBufferCondition.wait(mBufferLock);
    }
    mHaveNextBuffer = false;

    if (!mBuffer) {
      ALOGI("End of stream");
      return ERROR_END_OF_STREAM;
    }

    *buffer = mBuffer;
    mBuffer = nullptr;
    return ::OK;
  }

  void nextFrame(android::MediaBuffer *yuv420SemiPlanarFrame) {
    Mutex::Autolock autolock(mBufferLock);
    if (mBuffer) {
      mBuffer->release();
    }
    mBuffer = yuv420SemiPlanarFrame;
    mHaveNextBuffer = true;
    mBufferCondition.signal();
  }

 private:
  MediaBuffer *mBuffer;
  bool mHaveNextBuffer;
  Mutex mBufferLock;
  Condition mBufferCondition;

  sp<MetaData> mMetaData;
};

class SimpleH264EncoderImpl: public SimpleH264Encoder {
 public:
  static SimpleH264Encoder *Create(int width,
                                   int height,
                                   int maxBitrateK,
                                   int targetFps,
                                   FrameOutCallback frameOutCallback,
                                   void *frameOutUserData);
  virtual ~SimpleH264EncoderImpl() {
    stop();
  }
  virtual void setBitRate(int bitrateK);
  virtual void requestKeyFrame();
  virtual void nextFrame(void *yuv420SemiPlanarFrame,
                         void (*deallocator)(void *),
                         InputFrameInfo& inputFrameInfo);
  virtual void stop();

 private:
  class FramePuller: public android::Thread {
   public:
    FramePuller(SimpleH264EncoderImpl *encoder): encoder(encoder) {};
   private:
    bool threadLoop() override {
      return encoder->threadLoop();
    }
    SimpleH264EncoderImpl *encoder;
  };
  friend class FramePuller;

  SimpleH264EncoderImpl(int width,
                        int height,
                        int maxBitrateK,
                        FrameOutCallback frameOutCallback,
                        void *frameOutUserData);

  bool init(int targetFps);
  bool threadLoop();

  int width;
  int height;
  int maxBitrateK;
  FrameOutCallback frameOutCallback;
  void *frameOutUserData;
  uint8_t *codecConfig;
  int codecConfigLength;

  uint8_t *encodedFrame;
  int encodedFrameMaxLength;

  android::sp<android::ALooper> looper;
  android::sp<android::MediaCodecSource> mediaCodecSource;
  android::sp<SingleBufferMediaSource> frameQueue;
  android::sp<android::Thread> framePuller;
  std::queue<InputFrameInfo> frameInfo;
  android::Mutex mutex;
};

SimpleH264Encoder *SimpleH264EncoderImpl::Create(int width,
                                                 int height,
                                                 int maxBitrateK,
                                                 int targetFps,
                                                 FrameOutCallback frameOutCallback,
                                                 void *frameOutUserData) {
  SimpleH264EncoderImpl *enc = new SimpleH264EncoderImpl(
    width,
    height,
    maxBitrateK,
    frameOutCallback,
    frameOutUserData
  );

  if (!enc->init(targetFps)) {
    delete enc;
    enc = nullptr;
  };

  return enc;

bail:
  delete enc;
  return nullptr;
}

SimpleH264EncoderImpl::SimpleH264EncoderImpl(int width,
                                             int height,
                                             int maxBitrateK,
                                             FrameOutCallback frameOutCallback,
                                             void *frameOutUserData)
    : width(width),
      height(height),
      maxBitrateK(maxBitrateK),
      frameOutCallback(frameOutCallback),
      frameOutUserData(frameOutUserData),
      codecConfig(nullptr),
      codecConfigLength(0),
      encodedFrame(nullptr),
      encodedFrameMaxLength(0) {

  frameQueue = new SingleBufferMediaSource(width, height);
  looper = new ALooper;
  looper->setName("SimpleH264Encoder");
  framePuller = new SimpleH264EncoderImpl::FramePuller(this);
};

bool SimpleH264EncoderImpl::init(int targetFps) {
  sp<MetaData> meta = frameQueue->getFormat();
  int32_t width, height, stride, sliceHeight, colorFormat;
  CHECK(meta->findInt32(kKeyWidth, &width));
  CHECK(meta->findInt32(kKeyHeight, &height));
  CHECK(meta->findInt32(kKeyStride, &stride));
  CHECK(meta->findInt32(kKeySliceHeight, &sliceHeight));
  CHECK(meta->findInt32(kKeyColorFormat, &colorFormat));

  sp<AMessage> format = new AMessage();
  format->setInt32("width", width);
  format->setInt32("height", height);
  format->setInt32("stride", stride);
  format->setInt32("slice-height", sliceHeight);
  format->setInt32("color-format", colorFormat);

  format->setString("mime", kMimeTypeAvc);
  format->setInt32("bitrate", maxBitrateK * 1024);
  format->setInt32("bitrate-mode", OMX_Video_ControlRateConstant);
  format->setFloat("frame-rate", targetFps);
  format->setInt32("i-frame-interval", kIFrameInterval);

  looper->start();
  mediaCodecSource = MediaCodecSource::Create(
    looper,
    format,
    frameQueue,
#ifdef TARGET_GE_MARSHMALLOW
    NULL,
#endif
    0
  );
  if (mediaCodecSource == nullptr) {
    ALOGE("Unable to create encoder");
    return false;
  }

  status_t err;
  err = mediaCodecSource->start();
  if (err != 0) {
    ALOGE("Unable to start encoder");
    return false;
  }
  err = framePuller->run();
  if (err != 0) {
    ALOGE("Unable to start puller thread");
    return false;
  }
  return true;
}

void SimpleH264EncoderImpl::setBitRate(int bitrateK) {
  Mutex::Autolock autolock(mutex);
  if (mediaCodecSource != nullptr) {
    mediaCodecSource->videoBitRate(
      (bitrateK < maxBitrateK ? bitrateK : maxBitrateK) * 1024
    );
  }
}

void SimpleH264EncoderImpl::requestKeyFrame() {
  Mutex::Autolock autolock(mutex);
  if (mediaCodecSource != nullptr) {
    mediaCodecSource->requestIDRFrame();
  }
}

class UserMediaBuffer: public android::MediaBuffer {
 public:
  UserMediaBuffer(void *data, size_t size, void (*deallocator)(void *))
    : MediaBuffer(data, size),
      deallocator(deallocator) {}

 protected:
  ~UserMediaBuffer() {
    deallocator(data());
  }
 private:
  void (*deallocator)(void *);
};

void SimpleH264EncoderImpl::nextFrame(void *yuv420SemiPlanarFrame,
                                      void (*deallocator)(void *),
                                      InputFrameInfo& inputFrameInfo) {
  Mutex::Autolock autolock(mutex);
  if (frameQueue == nullptr) {
    ALOGI("Stopped, ignoring frame");
    return;
  }

  auto buffer = new UserMediaBuffer(
    yuv420SemiPlanarFrame,
    height * width * 3 / 2,
    deallocator
  );
  buffer->meta_data()->setInt64(kKeyTime, inputFrameInfo.captureTimeMs * 1000);
  frameInfo.push(inputFrameInfo);
  frameQueue->nextFrame(buffer);
}

void SimpleH264EncoderImpl::stop() {
  Mutex::Autolock autolock(mutex);
  framePuller->requestExit();

  if (mediaCodecSource != nullptr) {
    mediaCodecSource->stop();
  }

  if (frameQueue != nullptr) {
    frameQueue->stop();
  }

  if (looper != nullptr) {
    looper->stop();
  }

  if (framePuller->isRunning()) {
    framePuller->join();
    CHECK(!framePuller->isRunning());
  }

  frameQueue = nullptr;
  mediaCodecSource = nullptr;
  looper = nullptr;

  delete [] codecConfig;
  codecConfig = nullptr;
  codecConfigLength = 0;

  delete [] encodedFrame;
  encodedFrame = nullptr;
  encodedFrameMaxLength = 0;
}

bool SimpleH264EncoderImpl::threadLoop() {
  MediaBuffer *buffer;

  status_t err = mediaCodecSource->read(&buffer);
  if (err != ::OK) {
    ALOGE("Error reading from source: %d", err);
    return false;
  }

  if (buffer == NULL) {
    ALOGE("Failed to get buffer from source");
    return false;
  }

  int32_t isCodecConfig = 0;
  int32_t isIFrame = 0;
  int64_t timestamp = 0;

  if (buffer->meta_data() == NULL) {
    ALOGE("Failed to get buffer meta_data()");
    return false;
  }

  buffer->meta_data()->findInt32(kKeyIsCodecConfig, &isCodecConfig);
  buffer->meta_data()->findInt32(kKeyIsSyncFrame, &isIFrame);

  if (isCodecConfig) {
    if (codecConfig) {
      delete [] codecConfig;
    }
    codecConfigLength = buffer->range_length();
    codecConfig = new uint8_t[codecConfigLength];
    memcpy(codecConfig,
      static_cast<uint8_t*>(buffer->data()) + buffer->range_offset(),
      codecConfigLength
    );

  } else {
    EncodedFrameInfo info;
    bool drop = false;
    info.userData = frameOutUserData;
    info.keyFrame = isIFrame;
    int64_t timeMicro = 0;
    buffer->meta_data()->findInt64(kKeyTime, &timeMicro);
    info.input.captureTimeMs = timeMicro / 1000;

    {
      Mutex::Autolock autolock(mutex);
      for (;;) {
        if (frameInfo.empty()) {
          ALOGE("frameInfo exhausted. Encoder broken?");
          drop = true;
          break;
        }
        InputFrameInfo& ifi = frameInfo.front();
        if (ifi.captureTimeMs != info.input.captureTimeMs) {
          ALOGE("Unknown frame. Encoder broken?");
          frameInfo.pop();
          continue;
        }
        info.input = ifi;
        frameInfo.pop();
        break;
      }
    }

    if (!drop) {
      if (isIFrame) {
        int encodedFrameLength = codecConfigLength + buffer->range_length();

        if (encodedFrame == nullptr ||
            encodedFrameMaxLength < encodedFrameLength) {
          encodedFrameMaxLength = encodedFrameLength + encodedFrameLength / 2;
          delete [] encodedFrame;
          encodedFrame = new uint8_t[encodedFrameMaxLength];
        }

        // Always send codecConfig with an i-frame to make the stream more
        // resilient
        if (codecConfig) {
          memcpy(encodedFrame, codecConfig, codecConfigLength);
        }
        memcpy(
          encodedFrame + codecConfigLength,
          static_cast<uint8_t*>(buffer->data()) + buffer->range_offset(),
          buffer->range_length()
        );
        info.encodedFrame = encodedFrame;
        info.encodedFrameLength = encodedFrameLength;
      } else {
        info.encodedFrame = static_cast<uint8_t*>(buffer->data()) + buffer->range_offset();
        info.encodedFrameLength = buffer->range_length();
      }
      frameOutCallback(info);
    }
  }

  buffer->release();
  return true;
}

SimpleH264Encoder *SimpleH264Encoder::Create(int width,
                                             int height,
                                             int maxBitrateK,
                                             int targetFps,
                                             FrameOutCallback frameOutCallback,
                                             void *frameOutUserData) {
  return SimpleH264EncoderImpl::Create(
    width,
    height,
    maxBitrateK,
    targetFps,
    frameOutCallback,
    frameOutUserData
  );
}

<commit_msg>Slow down iframe interval<commit_after>#define LOG_TAG "silk-h264-enc"
#include "SimpleH264Encoder.h"

#include <queue>

#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MetaData.h>
// This is an ugly hack. We forked this from libstagefright
// so we can trigger key frames and adjust bitrate
#include "MediaCodecSource.h"
#include <media/openmax/OMX_IVCommon.h>
#include <media/stagefright/OMXCodec.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
#include <utils/Thread.h>
#include <utils/SystemClock.h>
#include <utils/Log.h>

using namespace android;

static const char* kMimeTypeAvc = "video/avc";
static const uint32_t kColorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
static const int32_t kIFrameInterval = 60;

class SingleBufferMediaSource: public MediaSource {
 public:
  SingleBufferMediaSource(int width, int height)
      : mBuffer(0), mHaveNextBuffer(false) {
    mMetaData = new MetaData();
    mMetaData->setInt32(kKeyWidth, width);
    mMetaData->setInt32(kKeyHeight, height);
    mMetaData->setInt32(kKeyStride, width);
    mMetaData->setInt32(kKeySliceHeight, height);
    mMetaData->setInt32(kKeyColorFormat, kColorFormat);
    mMetaData->setCString(kKeyMIMEType, "video/raw");
  }

  status_t start(MetaData *params = NULL) override {
    (void) params;
    return 0;
  }

  status_t stop() override {
    nextFrame(nullptr); // Unclog read
    return 0;
  }

  sp<MetaData> getFormat() override {
    return mMetaData;
  }

  status_t read(MediaBuffer **buffer, const ReadOptions *options = NULL) override {
    Mutex::Autolock autolock(mBufferLock);

    if (options != NULL) {
      ALOGW("ReadOptions not supported");
      return ERROR_END_OF_STREAM;
    }

    while (!mHaveNextBuffer) {
      mBufferCondition.wait(mBufferLock);
    }
    mHaveNextBuffer = false;

    if (!mBuffer) {
      ALOGI("End of stream");
      return ERROR_END_OF_STREAM;
    }

    *buffer = mBuffer;
    mBuffer = nullptr;
    return ::OK;
  }

  void nextFrame(android::MediaBuffer *yuv420SemiPlanarFrame) {
    Mutex::Autolock autolock(mBufferLock);
    if (mBuffer) {
      mBuffer->release();
    }
    mBuffer = yuv420SemiPlanarFrame;
    mHaveNextBuffer = true;
    mBufferCondition.signal();
  }

 private:
  MediaBuffer *mBuffer;
  bool mHaveNextBuffer;
  Mutex mBufferLock;
  Condition mBufferCondition;

  sp<MetaData> mMetaData;
};

class SimpleH264EncoderImpl: public SimpleH264Encoder {
 public:
  static SimpleH264Encoder *Create(int width,
                                   int height,
                                   int maxBitrateK,
                                   int targetFps,
                                   FrameOutCallback frameOutCallback,
                                   void *frameOutUserData);
  virtual ~SimpleH264EncoderImpl() {
    stop();
  }
  virtual void setBitRate(int bitrateK);
  virtual void requestKeyFrame();
  virtual void nextFrame(void *yuv420SemiPlanarFrame,
                         void (*deallocator)(void *),
                         InputFrameInfo& inputFrameInfo);
  virtual void stop();

 private:
  class FramePuller: public android::Thread {
   public:
    FramePuller(SimpleH264EncoderImpl *encoder): encoder(encoder) {};
   private:
    bool threadLoop() override {
      return encoder->threadLoop();
    }
    SimpleH264EncoderImpl *encoder;
  };
  friend class FramePuller;

  SimpleH264EncoderImpl(int width,
                        int height,
                        int maxBitrateK,
                        FrameOutCallback frameOutCallback,
                        void *frameOutUserData);

  bool init(int targetFps);
  bool threadLoop();

  int width;
  int height;
  int maxBitrateK;
  FrameOutCallback frameOutCallback;
  void *frameOutUserData;
  uint8_t *codecConfig;
  int codecConfigLength;

  uint8_t *encodedFrame;
  int encodedFrameMaxLength;

  android::sp<android::ALooper> looper;
  android::sp<android::MediaCodecSource> mediaCodecSource;
  android::sp<SingleBufferMediaSource> frameQueue;
  android::sp<android::Thread> framePuller;
  std::queue<InputFrameInfo> frameInfo;
  android::Mutex mutex;
};

SimpleH264Encoder *SimpleH264EncoderImpl::Create(int width,
                                                 int height,
                                                 int maxBitrateK,
                                                 int targetFps,
                                                 FrameOutCallback frameOutCallback,
                                                 void *frameOutUserData) {
  SimpleH264EncoderImpl *enc = new SimpleH264EncoderImpl(
    width,
    height,
    maxBitrateK,
    frameOutCallback,
    frameOutUserData
  );

  if (!enc->init(targetFps)) {
    delete enc;
    enc = nullptr;
  };

  return enc;

bail:
  delete enc;
  return nullptr;
}

SimpleH264EncoderImpl::SimpleH264EncoderImpl(int width,
                                             int height,
                                             int maxBitrateK,
                                             FrameOutCallback frameOutCallback,
                                             void *frameOutUserData)
    : width(width),
      height(height),
      maxBitrateK(maxBitrateK),
      frameOutCallback(frameOutCallback),
      frameOutUserData(frameOutUserData),
      codecConfig(nullptr),
      codecConfigLength(0),
      encodedFrame(nullptr),
      encodedFrameMaxLength(0) {

  frameQueue = new SingleBufferMediaSource(width, height);
  looper = new ALooper;
  looper->setName("SimpleH264Encoder");
  framePuller = new SimpleH264EncoderImpl::FramePuller(this);
};

bool SimpleH264EncoderImpl::init(int targetFps) {
  sp<MetaData> meta = frameQueue->getFormat();
  int32_t width, height, stride, sliceHeight, colorFormat;
  CHECK(meta->findInt32(kKeyWidth, &width));
  CHECK(meta->findInt32(kKeyHeight, &height));
  CHECK(meta->findInt32(kKeyStride, &stride));
  CHECK(meta->findInt32(kKeySliceHeight, &sliceHeight));
  CHECK(meta->findInt32(kKeyColorFormat, &colorFormat));

  sp<AMessage> format = new AMessage();
  format->setInt32("width", width);
  format->setInt32("height", height);
  format->setInt32("stride", stride);
  format->setInt32("slice-height", sliceHeight);
  format->setInt32("color-format", colorFormat);

  format->setString("mime", kMimeTypeAvc);
  format->setInt32("bitrate", maxBitrateK * 1024);
  format->setInt32("bitrate-mode", OMX_Video_ControlRateConstant);
  format->setFloat("frame-rate", targetFps);
  format->setInt32("i-frame-interval", kIFrameInterval);

  looper->start();
  mediaCodecSource = MediaCodecSource::Create(
    looper,
    format,
    frameQueue,
#ifdef TARGET_GE_MARSHMALLOW
    NULL,
#endif
    0
  );
  if (mediaCodecSource == nullptr) {
    ALOGE("Unable to create encoder");
    return false;
  }

  status_t err;
  err = mediaCodecSource->start();
  if (err != 0) {
    ALOGE("Unable to start encoder");
    return false;
  }
  err = framePuller->run();
  if (err != 0) {
    ALOGE("Unable to start puller thread");
    return false;
  }
  return true;
}

void SimpleH264EncoderImpl::setBitRate(int bitrateK) {
  Mutex::Autolock autolock(mutex);
  if (mediaCodecSource != nullptr) {
    mediaCodecSource->videoBitRate(
      (bitrateK < maxBitrateK ? bitrateK : maxBitrateK) * 1024
    );
  }
}

void SimpleH264EncoderImpl::requestKeyFrame() {
  Mutex::Autolock autolock(mutex);
  if (mediaCodecSource != nullptr) {
    mediaCodecSource->requestIDRFrame();
  }
}

class UserMediaBuffer: public android::MediaBuffer {
 public:
  UserMediaBuffer(void *data, size_t size, void (*deallocator)(void *))
    : MediaBuffer(data, size),
      deallocator(deallocator) {}

 protected:
  ~UserMediaBuffer() {
    deallocator(data());
  }
 private:
  void (*deallocator)(void *);
};

void SimpleH264EncoderImpl::nextFrame(void *yuv420SemiPlanarFrame,
                                      void (*deallocator)(void *),
                                      InputFrameInfo& inputFrameInfo) {
  Mutex::Autolock autolock(mutex);
  if (frameQueue == nullptr) {
    ALOGI("Stopped, ignoring frame");
    return;
  }

  auto buffer = new UserMediaBuffer(
    yuv420SemiPlanarFrame,
    height * width * 3 / 2,
    deallocator
  );
  buffer->meta_data()->setInt64(kKeyTime, inputFrameInfo.captureTimeMs * 1000);
  frameInfo.push(inputFrameInfo);
  frameQueue->nextFrame(buffer);
}

void SimpleH264EncoderImpl::stop() {
  Mutex::Autolock autolock(mutex);
  framePuller->requestExit();

  if (mediaCodecSource != nullptr) {
    mediaCodecSource->stop();
  }

  if (frameQueue != nullptr) {
    frameQueue->stop();
  }

  if (looper != nullptr) {
    looper->stop();
  }

  if (framePuller->isRunning()) {
    framePuller->join();
    CHECK(!framePuller->isRunning());
  }

  frameQueue = nullptr;
  mediaCodecSource = nullptr;
  looper = nullptr;

  delete [] codecConfig;
  codecConfig = nullptr;
  codecConfigLength = 0;

  delete [] encodedFrame;
  encodedFrame = nullptr;
  encodedFrameMaxLength = 0;
}

bool SimpleH264EncoderImpl::threadLoop() {
  MediaBuffer *buffer;

  status_t err = mediaCodecSource->read(&buffer);
  if (err != ::OK) {
    ALOGE("Error reading from source: %d", err);
    return false;
  }

  if (buffer == NULL) {
    ALOGE("Failed to get buffer from source");
    return false;
  }

  int32_t isCodecConfig = 0;
  int32_t isIFrame = 0;
  int64_t timestamp = 0;

  if (buffer->meta_data() == NULL) {
    ALOGE("Failed to get buffer meta_data()");
    return false;
  }

  buffer->meta_data()->findInt32(kKeyIsCodecConfig, &isCodecConfig);
  buffer->meta_data()->findInt32(kKeyIsSyncFrame, &isIFrame);

  if (isCodecConfig) {
    if (codecConfig) {
      delete [] codecConfig;
    }
    codecConfigLength = buffer->range_length();
    codecConfig = new uint8_t[codecConfigLength];
    memcpy(codecConfig,
      static_cast<uint8_t*>(buffer->data()) + buffer->range_offset(),
      codecConfigLength
    );

  } else {
    EncodedFrameInfo info;
    bool drop = false;
    info.userData = frameOutUserData;
    info.keyFrame = isIFrame;
    int64_t timeMicro = 0;
    buffer->meta_data()->findInt64(kKeyTime, &timeMicro);
    info.input.captureTimeMs = timeMicro / 1000;

    {
      Mutex::Autolock autolock(mutex);
      for (;;) {
        if (frameInfo.empty()) {
          ALOGE("frameInfo exhausted. Encoder broken?");
          drop = true;
          break;
        }
        InputFrameInfo& ifi = frameInfo.front();
        if (ifi.captureTimeMs != info.input.captureTimeMs) {
          ALOGE("Unknown frame. Encoder broken?");
          frameInfo.pop();
          continue;
        }
        info.input = ifi;
        frameInfo.pop();
        break;
      }
    }

    if (!drop) {
      if (isIFrame) {
        int encodedFrameLength = codecConfigLength + buffer->range_length();

        if (encodedFrame == nullptr ||
            encodedFrameMaxLength < encodedFrameLength) {
          encodedFrameMaxLength = encodedFrameLength + encodedFrameLength / 2;
          delete [] encodedFrame;
          encodedFrame = new uint8_t[encodedFrameMaxLength];
        }

        // Always send codecConfig with an i-frame to make the stream more
        // resilient
        if (codecConfig) {
          memcpy(encodedFrame, codecConfig, codecConfigLength);
        }
        memcpy(
          encodedFrame + codecConfigLength,
          static_cast<uint8_t*>(buffer->data()) + buffer->range_offset(),
          buffer->range_length()
        );
        info.encodedFrame = encodedFrame;
        info.encodedFrameLength = encodedFrameLength;
      } else {
        info.encodedFrame = static_cast<uint8_t*>(buffer->data()) + buffer->range_offset();
        info.encodedFrameLength = buffer->range_length();
      }
      frameOutCallback(info);
    }
  }

  buffer->release();
  return true;
}

SimpleH264Encoder *SimpleH264Encoder::Create(int width,
                                             int height,
                                             int maxBitrateK,
                                             int targetFps,
                                             FrameOutCallback frameOutCallback,
                                             void *frameOutUserData) {
  return SimpleH264EncoderImpl::Create(
    width,
    height,
    maxBitrateK,
    targetFps,
    frameOutCallback,
    frameOutUserData
  );
}

<|endoftext|>


<commit_before>/* @(#)main.cpp ---
 *
 * Author: Nicolas Niclausse
 * Copyright (C) 2014 - Nicolas Niclausse, Inria.
 * Created: 2014/04/25 16:28:19
 */

/* Commentary:
 *
 */

/* Change log:
 *
 */

#include <dtkCore/dtkCore.h>
#include <dtkDistributed/dtkDistributedServerDaemon.h>
#include <dtkLog/dtkLogger.h>

#include <QCoreApplication>

int main(int argc, char **argv)
{
    QCoreApplication application(argc, argv);

    if(!dtkApplicationArgumentsContain(&application, "-type")) {
        qDebug() << "Usage:" << argv[0] << " [-p port] -type <Oar | Torque | Local |...>";
        return 1;
    }
    int port;
    if(dtkApplicationArgumentsContain(&application, "-p"))
        port = dtkApplicationArgumentsValue(&application, "-p").toInt();
    else
        port = 9999;

    application.setApplicationName("dtkDistributedServer");
    application.setApplicationVersion("0.0.1");
    application.setOrganizationName("inria");
    application.setOrganizationDomain("fr");

    qDebug() << "Starting dtkDistributedServer"; // DO NOT REMOVE THIS
    qInstallMessageHandler(dtkMessageOutput);

    QSettings settings("inria", "dtk");
    settings.beginGroup("server");

    dtkDistributedServerDaemon server(port);

    server.setManager( dtkApplicationArgumentsValue(&application, "-type"));
    qDebug() << "server started";

    int status = application.exec();

    return status;
}

<commit_msg>disable messageHandler stuff<commit_after>/* @(#)main.cpp ---
 *
 * Author: Nicolas Niclausse
 * Copyright (C) 2014 - Nicolas Niclausse, Inria.
 * Created: 2014/04/25 16:28:19
 */

/* Commentary:
 *
 */

/* Change log:
 *
 */

#include <dtkCore/dtkCore.h>
#include <dtkDistributed/dtkDistributedServerDaemon.h>
#include <dtkLog/dtkLogger.h>

#include <QCoreApplication>

int main(int argc, char **argv)
{
    QCoreApplication application(argc, argv);

    if(!dtkApplicationArgumentsContain(&application, "-type")) {
        qDebug() << "Usage:" << argv[0] << " [-p port] -type <Oar | Torque | Local |...>";
        return 1;
    }
    int port;
    if(dtkApplicationArgumentsContain(&application, "-p"))
        port = dtkApplicationArgumentsValue(&application, "-p").toInt();
    else
        port = 9999;

    application.setApplicationName("dtkDistributedServer");
    application.setApplicationVersion("0.0.1");
    application.setOrganizationName("inria");
    application.setOrganizationDomain("fr");

    qDebug() << "Starting dtkDistributedServer"; // DO NOT REMOVE THIS
//    qInstallMessageHandler(dtkMessageOutput);

    QSettings settings("inria", "dtk");
    settings.beginGroup("server");

    dtkDistributedServerDaemon server(port);

    server.setManager( dtkApplicationArgumentsValue(&application, "-type"));
    qDebug() << "server started";

    int status = application.exec();

    return status;
}

<|endoftext|>