<commit_before>/* This file is part of Zanshin Todo.

   Copyright 2008 Kevin Ottens <ervin@kde.org>

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
   USA.
*/

#include "todotreemodel.h"

#include <akonadi/collection.h>
#include <akonadi/item.h>

#include "todoflatmodel.h"

TodoTreeModel::TodoTreeModel(QObject *parent)
    : QAbstractProxyModel(parent)
{
}

TodoTreeModel::~TodoTreeModel()
{

}

QModelIndex TodoTreeModel::index(int row, int column, const QModelIndex &parent) const
{
    if (row < 0 || column < 0
     || row >= rowCount(parent)
     || column >= columnCount(parent)) {
        return QModelIndex();
    }

    Akonadi::Entity::Id parentId = idForIndex(parent);
    Akonadi::Entity::Id id = m_childrenMap[parentId].at(row);

    return createIndex(row, column, (void*)id);
}

QModelIndex TodoTreeModel::parent(const QModelIndex &index) const
{
    if (!index.isValid()
     || !m_parentMap.contains(index.internalId())) {
        return QModelIndex();
    }

    Akonadi::Entity::Id id = idForIndex(index);
    Akonadi::Entity::Id parentId = m_parentMap[id];

    if (parentId==-1) {
        return QModelIndex();
    }

    return indexForId(parentId);
}

int TodoTreeModel::rowCount(const QModelIndex &parent) const
{
    if (!parent.isValid()) {
        return m_childrenMap[-1].count();
    } else if (parent.column() == 0) { // Only one set of children per row
        Akonadi::Entity::Id id = idForIndex(parent);
        return m_childrenMap[id].count();
    }

    return 0;
}

int TodoTreeModel::columnCount(const QModelIndex &/*parent*/) const
{
    return TodoFlatModel::LastColumn + 1;
}

QVariant TodoTreeModel::headerData(int section, Qt::Orientation orientation, int role) const
{
    return flatModel()->headerData(section, orientation, role);
}

QModelIndex TodoTreeModel::mapToSource(const QModelIndex &proxyIndex) const
{
    return flatModel()->indexForItem(Akonadi::Item(proxyIndex.internalId()),
                                     proxyIndex.column());
}

QModelIndex TodoTreeModel::mapFromSource(const QModelIndex &sourceIndex) const
{
    Akonadi::Item item = flatModel()->itemForIndex(sourceIndex);
    return indexForId(item.id(), sourceIndex.column());
}

void TodoTreeModel::setSourceModel(QAbstractItemModel *sourceModel)
{
    if (flatModel()) {
        disconnect(flatModel());
    }

    Q_ASSERT(sourceModel == 0 || qobject_cast<TodoFlatModel*>(sourceModel) != 0);
    QAbstractProxyModel::setSourceModel(sourceModel);

    onSourceInsertRows(QModelIndex(), 0, flatModel()->rowCount() - 1);

    connect(flatModel(), SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)),
            this, SLOT(onSourceDataChanged(const QModelIndex&, const QModelIndex&)));
    connect(flatModel(), SIGNAL(rowsInserted(const QModelIndex&, int, int)),
            this, SLOT(onSourceInsertRows(const QModelIndex&, int, int)));
    connect(flatModel(), SIGNAL(rowsAboutToBeRemoved(const QModelIndex&, int, int)),
            this, SLOT(onSourceRemoveRows(const QModelIndex&, int, int)));
    connect(flatModel(), SIGNAL(collectionChanged(const Akonadi::Collection&)),
            this, SLOT(onSourceCollectionChanged(const Akonadi::Collection&)));
}

void TodoTreeModel::onSourceInsertRows(const QModelIndex &/*sourceIndex*/, int begin, int end)
{
    QList<Akonadi::Entity::Id> idToEmit;

    // Storing the akonadi id vs remote id mapping
    for (int i = begin; i <= end; i++) {
        // Retrieve the item from the source model
        Akonadi::Item item = flatModel()->itemForIndex(flatModel()->index(i, 0));
        QString remoteId = flatModel()->data(flatModel()->index(i, TodoFlatModel::RemoteId)).toString();
        m_remoteIdMap[item.id()] = remoteId;
        m_remoteIdReverseMap[remoteId] = item.id();
        idToEmit << item.id();
    }

    // Filling the global tree maps, also store a partial one only for this bunch of updates
    QHash<Akonadi::Entity::Id, QList<Akonadi::Entity::Id> > partialChildrenMap;
    QHash<Akonadi::Entity::Id, Akonadi::Entity::Id> partialParentMap;
    QList<Akonadi::Entity::Id> partialRoots;
    for (int i = end; i >= begin; i--) {
        Akonadi::Item item = flatModel()->itemForIndex(flatModel()->index(i, 0));
        QString parentRemoteId = flatModel()->data(flatModel()->index(i, TodoFlatModel::ParentRemoteId)).toString();
        Akonadi::Entity::Id parentId = -1;
        if (!parentRemoteId.isEmpty()) {
            parentId = m_remoteIdReverseMap[parentRemoteId];
        }
        partialChildrenMap[parentId] << item.id();
        partialParentMap[item.id()] = parentId;
        if (parentId==-1 || !idToEmit.contains(parentId)) {
            partialRoots << item.id();
        }
    }

    // Use the partial map and roots list to emit the insertions in the correct order
    idToEmit = partialRoots;
    while (!idToEmit.isEmpty()) {
        Akonadi::Entity::Id id = idToEmit.takeFirst();
        idToEmit+=partialChildrenMap[id];

        Akonadi::Entity::Id parentId = partialParentMap[id];
        int row = m_childrenMap[parentId].count();
        QModelIndex proxyParentIndex;
        if (parentId!=-1) {
            proxyParentIndex = indexForId(parentId);
        }

        beginInsertRows(proxyParentIndex, row, row);
        m_parentMap[id] = parentId;
        m_childrenMap[parentId] << id;
        endInsertRows();
    }
}

void TodoTreeModel::onSourceRemoveRows(const QModelIndex &/*Id*/, int begin, int end)
{
    for (int i = begin; i <= end; ++i) {
        QModelIndex sourceIndex = flatModel()->index(i, 0);
        QModelIndex proxyIndex = mapFromSource(sourceIndex);
        Akonadi::Item item = flatModel()->itemForIndex(sourceIndex);
        QString remoteId = flatModel()->data(flatModel()->index(i, TodoFlatModel::RemoteId)).toString();

        QHash<Akonadi::Entity::Id, QList<Akonadi::Entity::Id> >::iterator it = m_childrenMap.find(item.id());
        if (it != m_childrenMap.end()) {
            Akonadi::Entity::Id idKey = it.key();
            QList<Akonadi::Entity::Id> idList = it.value();
            while (!idList.isEmpty()) {
                beginRemoveRows(proxyIndex.child(0, 0), 0, 0);
                Akonadi::Entity::Id id = idList.takeFirst();
                endRemoveRows();

                beginInsertRows(QModelIndex(), 0, 0);
                QList<Akonadi::Entity::Id> idEmpty;
                m_childrenMap[id] = idEmpty;
                endInsertRows();
            }
            m_childrenMap[idKey] = idList;
        }

        beginRemoveRows(proxyIndex.parent(), proxyIndex.row(), proxyIndex.row());

        m_remoteIdMap.remove(item.id());
        m_remoteIdReverseMap.remove(remoteId);

        Akonadi::Entity::Id parent = m_parentMap[item.id()];
        QList<Akonadi::Entity::Id> idList = m_childrenMap[parent];
        idList.removeOne(item.id());
        m_childrenMap[parent] = idList;

        m_childrenMap.remove(item.id());
        m_parentMap.remove(item.id());

        endRemoveRows();
    }
}

void TodoTreeModel::onSourceDataChanged(const QModelIndex &begin, const QModelIndex &end)
{
    for (int row = begin.row(); row <= end.row(); ++row) {
        QModelIndex sourceIndex = flatModel()->index(row, TodoFlatModel::RemoteId);

        QModelIndex proxyIndex = mapFromSource(sourceIndex);
        emit dataChanged(index(proxyIndex.row(), 0, proxyIndex.parent()),
                         index(proxyIndex.row(), TodoFlatModel::LastColumn, proxyIndex.parent()));

        QModelIndex parentRemoteIdIndex = flatModel()->index(row, TodoFlatModel::ParentRemoteId);
        QString parentRemoteId = flatModel()->data(parentRemoteIdIndex).toString();
        Akonadi::Entity::Id newParentId = -1;
        if (!parentRemoteId.isEmpty()) {
            newParentId = m_remoteIdReverseMap[parentRemoteId];
        }

        QString itemRemoteId = flatModel()->data(sourceIndex).toString();
        Akonadi::Entity::Id itemId = -1;
        if (!itemRemoteId.isEmpty()) {
            itemId = m_remoteIdReverseMap[itemRemoteId];
        }

        Akonadi::Entity::Id oldParentId = -1;
        if (m_parentMap.contains(itemId)) {
            oldParentId = m_parentMap[itemId];
        }

        if (oldParentId != newParentId) {
            int oldRow = m_childrenMap[oldParentId].indexOf(itemId);
            beginRemoveRows(indexForId(oldParentId), oldRow, oldRow);
            m_childrenMap[oldParentId].removeAll(itemId);
            m_parentMap.remove(itemId);
            endRemoveRows();

            int newRow = m_childrenMap[newParentId].size();
            beginInsertRows(indexForId(newParentId), newRow, newRow);
            m_childrenMap[newParentId] << itemId;
            m_parentMap[itemId] = newParentId;
            endInsertRows();
        }
    }
}

void TodoTreeModel::onSourceCollectionChanged(const Akonadi::Collection &collection)
{
    m_childrenMap.clear();
    m_parentMap.clear();
    m_remoteIdMap.clear();
    m_remoteIdReverseMap.clear();

    reset();

    emit collectionChanged(collection);
}

Akonadi::Entity::Id TodoTreeModel::idForIndex(const QModelIndex &index) const
{
    return index.isValid() ? index.internalId() : -1;
}

QModelIndex TodoTreeModel::indexForId(Akonadi::Entity::Id id, int column) const
{
    if (id==-1) {
        return QModelIndex();
    }

    Q_ASSERT(m_parentMap.contains(id));
    Akonadi::Entity::Id parentId = m_parentMap[id];
    int row = m_childrenMap[parentId].indexOf(id);
    Q_ASSERT(row>=0);

    return createIndex(row, column, (void*)id);
}

Akonadi::Item TodoTreeModel::itemForIndex(const QModelIndex &index) const
{
    return flatModel()->itemForIndex(mapToSource(index));
}

QModelIndex TodoTreeModel::indexForItem(const Akonadi::Item &item, const int column) const
{
    return mapFromSource(flatModel()->indexForItem(item, column));
}

void TodoTreeModel::setCollection(const Akonadi::Collection &collection)
{
    flatModel()->setCollection(collection);
}

Akonadi::Collection TodoTreeModel::collection() const
{
    return flatModel()->collection();
}

TodoFlatModel *TodoTreeModel::flatModel() const
{
    return qobject_cast<TodoFlatModel*>(sourceModel());
}
<commit_msg>SVN_SILENT CCMAIL: nef@ipsquad.net<commit_after>/* This file is part of Zanshin Todo.

   Copyright 2008 Kevin Ottens <ervin@kde.org>

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
   USA.
*/

#include "todotreemodel.h"

#include <akonadi/collection.h>
#include <akonadi/item.h>

#include "todoflatmodel.h"

TodoTreeModel::TodoTreeModel(QObject *parent)
    : QAbstractProxyModel(parent)
{
}

TodoTreeModel::~TodoTreeModel()
{

}

QModelIndex TodoTreeModel::index(int row, int column, const QModelIndex &parent) const
{
    if (row < 0 || column < 0
     || row >= rowCount(parent)
     || column >= columnCount(parent)) {
        return QModelIndex();
    }

    Akonadi::Entity::Id parentId = idForIndex(parent);
    Akonadi::Entity::Id id = m_childrenMap[parentId].at(row);

    return createIndex(row, column, (void*)id);
}

QModelIndex TodoTreeModel::parent(const QModelIndex &index) const
{
    if (!index.isValid()
     || !m_parentMap.contains(index.internalId())) {
        return QModelIndex();
    }

    Akonadi::Entity::Id id = idForIndex(index);
    Akonadi::Entity::Id parentId = m_parentMap[id];

    if (parentId==-1) {
        return QModelIndex();
    }

    return indexForId(parentId);
}

int TodoTreeModel::rowCount(const QModelIndex &parent) const
{
    if (!parent.isValid()) {
        return m_childrenMap[-1].count();
    } else if (parent.column() == 0) { // Only one set of children per row
        Akonadi::Entity::Id id = idForIndex(parent);
        return m_childrenMap[id].count();
    }

    return 0;
}

int TodoTreeModel::columnCount(const QModelIndex &/*parent*/) const
{
    return TodoFlatModel::LastColumn + 1;
}

QVariant TodoTreeModel::headerData(int section, Qt::Orientation orientation, int role) const
{
    return flatModel()->headerData(section, orientation, role);
}

QModelIndex TodoTreeModel::mapToSource(const QModelIndex &proxyIndex) const
{
    return flatModel()->indexForItem(Akonadi::Item(proxyIndex.internalId()),
                                     proxyIndex.column());
}

QModelIndex TodoTreeModel::mapFromSource(const QModelIndex &sourceIndex) const
{
    Akonadi::Item item = flatModel()->itemForIndex(sourceIndex);
    return indexForId(item.id(), sourceIndex.column());
}

void TodoTreeModel::setSourceModel(QAbstractItemModel *sourceModel)
{
    if (flatModel()) {
        disconnect(flatModel());
    }

    Q_ASSERT(sourceModel == 0 || qobject_cast<TodoFlatModel*>(sourceModel) != 0);
    QAbstractProxyModel::setSourceModel(sourceModel);

    onSourceInsertRows(QModelIndex(), 0, flatModel()->rowCount() - 1);

    connect(flatModel(), SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)),
            this, SLOT(onSourceDataChanged(const QModelIndex&, const QModelIndex&)));
    connect(flatModel(), SIGNAL(rowsInserted(const QModelIndex&, int, int)),
            this, SLOT(onSourceInsertRows(const QModelIndex&, int, int)));
    connect(flatModel(), SIGNAL(rowsAboutToBeRemoved(const QModelIndex&, int, int)),
            this, SLOT(onSourceRemoveRows(const QModelIndex&, int, int)));
    connect(flatModel(), SIGNAL(collectionChanged(const Akonadi::Collection&)),
            this, SLOT(onSourceCollectionChanged(const Akonadi::Collection&)));
}

void TodoTreeModel::onSourceInsertRows(const QModelIndex &/*sourceIndex*/, int begin, int end)
{
    QList<Akonadi::Entity::Id> idToEmit;

    // Storing the akonadi id vs remote id mapping
    for (int i = begin; i <= end; i++) {
        // Retrieve the item from the source model
        Akonadi::Item item = flatModel()->itemForIndex(flatModel()->index(i, 0));
        QString remoteId = flatModel()->data(flatModel()->index(i, TodoFlatModel::RemoteId)).toString();
        m_remoteIdMap[item.id()] = remoteId;
        m_remoteIdReverseMap[remoteId] = item.id();
        idToEmit << item.id();
    }

    // Filling the global tree maps, also store a partial one only for this bunch of updates
    QHash<Akonadi::Entity::Id, QList<Akonadi::Entity::Id> > partialChildrenMap;
    QHash<Akonadi::Entity::Id, Akonadi::Entity::Id> partialParentMap;
    QList<Akonadi::Entity::Id> partialRoots;
    for (int i = end; i >= begin; i--) {
        Akonadi::Item item = flatModel()->itemForIndex(flatModel()->index(i, 0));
        QString parentRemoteId = flatModel()->data(flatModel()->index(i, TodoFlatModel::ParentRemoteId)).toString();
        Akonadi::Entity::Id parentId = -1;
        if (!parentRemoteId.isEmpty()) {
            parentId = m_remoteIdReverseMap[parentRemoteId];
        }
        partialChildrenMap[parentId] << item.id();
        partialParentMap[item.id()] = parentId;
        if (parentId==-1 || !idToEmit.contains(parentId)) {
            partialRoots << item.id();
        }
    }

    // Use the partial map and roots list to emit the insertions in the correct order
    idToEmit = partialRoots;
    while (!idToEmit.isEmpty()) {
        Akonadi::Entity::Id id = idToEmit.takeFirst();
        idToEmit+=partialChildrenMap[id];

        Akonadi::Entity::Id parentId = partialParentMap[id];
        int row = m_childrenMap[parentId].count();
        QModelIndex proxyParentIndex;
        if (parentId!=-1) {
            proxyParentIndex = indexForId(parentId);
        }

        beginInsertRows(proxyParentIndex, row, row);
        m_parentMap[id] = parentId;
        m_childrenMap[parentId] << id;
        endInsertRows();
    }
}

void TodoTreeModel::onSourceRemoveRows(const QModelIndex &/*sourceIndex*/, int begin, int end)
{
    for (int i = begin; i <= end; ++i) {
        QModelIndex sourceIndex = flatModel()->index(i, 0);
        QModelIndex proxyIndex = mapFromSource(sourceIndex);
        Akonadi::Item item = flatModel()->itemForIndex(sourceIndex);
        QString remoteId = flatModel()->data(flatModel()->index(i, TodoFlatModel::RemoteId)).toString();

        QHash<Akonadi::Entity::Id, QList<Akonadi::Entity::Id> >::iterator it = m_childrenMap.find(item.id());
        if (it != m_childrenMap.end()) {
            Akonadi::Entity::Id idKey = it.key();
            QList<Akonadi::Entity::Id> idList = it.value();
            while (!idList.isEmpty()) {
                beginRemoveRows(proxyIndex.child(0, 0), 0, 0);
                Akonadi::Entity::Id id = idList.takeFirst();
                endRemoveRows();

                beginInsertRows(QModelIndex(), 0, 0);
                QList<Akonadi::Entity::Id> idEmpty;
                m_childrenMap[id] = idEmpty;
                endInsertRows();
            }
            m_childrenMap[idKey] = idList;
        }

        beginRemoveRows(proxyIndex.parent(), proxyIndex.row(), proxyIndex.row());

        m_remoteIdMap.remove(item.id());
        m_remoteIdReverseMap.remove(remoteId);

        Akonadi::Entity::Id parent = m_parentMap[item.id()];
        QList<Akonadi::Entity::Id> idList = m_childrenMap[parent];
        idList.removeOne(item.id());
        m_childrenMap[parent] = idList;

        m_childrenMap.remove(item.id());
        m_parentMap.remove(item.id());

        endRemoveRows();
    }
}

void TodoTreeModel::onSourceDataChanged(const QModelIndex &begin, const QModelIndex &end)
{
    for (int row = begin.row(); row <= end.row(); ++row) {
        QModelIndex sourceIndex = flatModel()->index(row, TodoFlatModel::RemoteId);

        QModelIndex proxyIndex = mapFromSource(sourceIndex);
        emit dataChanged(index(proxyIndex.row(), 0, proxyIndex.parent()),
                         index(proxyIndex.row(), TodoFlatModel::LastColumn, proxyIndex.parent()));

        QModelIndex parentRemoteIdIndex = flatModel()->index(row, TodoFlatModel::ParentRemoteId);
        QString parentRemoteId = flatModel()->data(parentRemoteIdIndex).toString();
        Akonadi::Entity::Id newParentId = -1;
        if (!parentRemoteId.isEmpty()) {
            newParentId = m_remoteIdReverseMap[parentRemoteId];
        }

        QString itemRemoteId = flatModel()->data(sourceIndex).toString();
        Akonadi::Entity::Id itemId = -1;
        if (!itemRemoteId.isEmpty()) {
            itemId = m_remoteIdReverseMap[itemRemoteId];
        }

        Akonadi::Entity::Id oldParentId = -1;
        if (m_parentMap.contains(itemId)) {
            oldParentId = m_parentMap[itemId];
        }

        if (oldParentId != newParentId) {
            int oldRow = m_childrenMap[oldParentId].indexOf(itemId);
            beginRemoveRows(indexForId(oldParentId), oldRow, oldRow);
            m_childrenMap[oldParentId].removeAll(itemId);
            m_parentMap.remove(itemId);
            endRemoveRows();

            int newRow = m_childrenMap[newParentId].size();
            beginInsertRows(indexForId(newParentId), newRow, newRow);
            m_childrenMap[newParentId] << itemId;
            m_parentMap[itemId] = newParentId;
            endInsertRows();
        }
    }
}

void TodoTreeModel::onSourceCollectionChanged(const Akonadi::Collection &collection)
{
    m_childrenMap.clear();
    m_parentMap.clear();
    m_remoteIdMap.clear();
    m_remoteIdReverseMap.clear();

    reset();

    emit collectionChanged(collection);
}

Akonadi::Entity::Id TodoTreeModel::idForIndex(const QModelIndex &index) const
{
    return index.isValid() ? index.internalId() : -1;
}

QModelIndex TodoTreeModel::indexForId(Akonadi::Entity::Id id, int column) const
{
    if (id==-1) {
        return QModelIndex();
    }

    Q_ASSERT(m_parentMap.contains(id));
    Akonadi::Entity::Id parentId = m_parentMap[id];
    int row = m_childrenMap[parentId].indexOf(id);
    Q_ASSERT(row>=0);

    return createIndex(row, column, (void*)id);
}

Akonadi::Item TodoTreeModel::itemForIndex(const QModelIndex &index) const
{
    return flatModel()->itemForIndex(mapToSource(index));
}

QModelIndex TodoTreeModel::indexForItem(const Akonadi::Item &item, const int column) const
{
    return mapFromSource(flatModel()->indexForItem(item, column));
}

void TodoTreeModel::setCollection(const Akonadi::Collection &collection)
{
    flatModel()->setCollection(collection);
}

Akonadi::Collection TodoTreeModel::collection() const
{
    return flatModel()->collection();
}

TodoFlatModel *TodoTreeModel::flatModel() const
{
    return qobject_cast<TodoFlatModel*>(sourceModel());
}
<|endoftext|>


<commit_before>///////////////////////////////////////////////////////////////////////
// File:        network.cpp
// Description: Base class for neural network implementations.
// Author:      Ray Smith
//
// (C) Copyright 2013, Google Inc.
// 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 automatically generated configuration file if running autoconf.
#ifdef HAVE_CONFIG_H
#include "config_auto.h"
#endif

#include "network.h"

#include <cstdlib>

// This base class needs to know about all its sub-classes because of the
// factory deserializing method: CreateFromFile.
#include "allheaders.h"
#include "convolve.h"
#include "fullyconnected.h"
#include "input.h"
#include "lstm.h"
#include "maxpool.h"
#include "parallel.h"
#include "reconfig.h"
#include "reversed.h"
#include "scrollview.h"
#include "series.h"
#include "statistc.h"
#ifdef INCLUDE_TENSORFLOW
#include "tfnetwork.h"
#endif
#include "tprintf.h"

namespace tesseract {

// Min and max window sizes.
const int kMinWinSize = 500;
const int kMaxWinSize = 2000;
// Window frame sizes need adding on to make the content fit.
const int kXWinFrameSize = 30;
const int kYWinFrameSize = 80;

// String names corresponding to the NetworkType enum.
// Keep in sync with NetworkType.
// Names used in Serialization to allow re-ordering/addition/deletion of
// layer types in NetworkType without invalidating existing network files.
static char const* const kTypeNames[NT_COUNT] = {
    "Invalid",     "Input",
    "Convolve",    "Maxpool",
    "Parallel",    "Replicated",
    "ParBidiLSTM", "DepParUDLSTM",
    "Par2dLSTM",   "Series",
    "Reconfig",    "RTLReversed",
    "TTBReversed", "XYTranspose",
    "LSTM",        "SummLSTM",
    "Logistic",    "LinLogistic",
    "LinTanh",     "Tanh",
    "Relu",        "Linear",
    "Softmax",     "SoftmaxNoCTC",
    "LSTMSoftmax", "LSTMBinarySoftmax",
    "TensorFlow",
};

Network::Network()
    : type_(NT_NONE),
      training_(TS_ENABLED),
      needs_to_backprop_(true),
      network_flags_(0),
      ni_(0),
      no_(0),
      num_weights_(0),
      forward_win_(nullptr),
      backward_win_(nullptr),
      randomizer_(nullptr) {}
Network::Network(NetworkType type, const std::string& name, int ni, int no)
    : type_(type),
      training_(TS_ENABLED),
      needs_to_backprop_(true),
      network_flags_(0),
      ni_(ni),
      no_(no),
      num_weights_(0),
      name_(name),
      forward_win_(nullptr),
      backward_win_(nullptr),
      randomizer_(nullptr) {}

// Suspends/Enables/Permanently disables training by setting the training_
// flag. Serialize and DeSerialize only operate on the run-time data if state
// is TS_DISABLED or TS_TEMP_DISABLE. Specifying TS_TEMP_DISABLE will
// temporarily disable layers in state TS_ENABLED, allowing a trainer to
// serialize as if it were a recognizer.
// TS_RE_ENABLE will re-enable layers that were previously in any disabled
// state. If in TS_TEMP_DISABLE then the flag is just changed, but if in
// TS_DISABLED, the deltas in the weight matrices are reinitialized so that a
// recognizer can be converted back to a trainer.
void Network::SetEnableTraining(TrainingState state) {
  if (state == TS_RE_ENABLE) {
    // Enable only from temp disabled.
    if (training_ == TS_TEMP_DISABLE) training_ = TS_ENABLED;
  } else if (state == TS_TEMP_DISABLE) {
    // Temp disable only from enabled.
    if (training_ == TS_ENABLED) training_ = state;
  } else {
    training_ = state;
  }
}

// Sets flags that control the action of the network. See NetworkFlags enum
// for bit values.
void Network::SetNetworkFlags(uint32_t flags) {
  network_flags_ = flags;
}

// Sets up the network for training. Initializes weights using weights of
// scale `range` picked according to the random number generator `randomizer`.
int Network::InitWeights(float range, TRand* randomizer) {
  randomizer_ = randomizer;
  return 0;
}

// Provides a pointer to a TRand for any networks that care to use it.
// Note that randomizer is a borrowed pointer that should outlive the network
// and should not be deleted by any of the networks.
void Network::SetRandomizer(TRand* randomizer) {
  randomizer_ = randomizer;
}

// Sets needs_to_backprop_ to needs_backprop and returns true if
// needs_backprop || any weights in this network so the next layer forward
// can be told to produce backprop for this layer if needed.
bool Network::SetupNeedsBackprop(bool needs_backprop) {
  needs_to_backprop_ = needs_backprop;
  return needs_backprop || num_weights_ > 0;
}

// Writes to the given file. Returns false in case of error.
bool Network::Serialize(TFile* fp) const {
  int8_t data = NT_NONE;
  if (!fp->Serialize(&data)) return false;
  STRING type_name = kTypeNames[type_];
  if (!type_name.Serialize(fp)) return false;
  data = training_;
  if (!fp->Serialize(&data)) return false;
  data = needs_to_backprop_;
  if (!fp->Serialize(&data)) return false;
  if (!fp->Serialize(&network_flags_)) return false;
  if (!fp->Serialize(&ni_)) return false;
  if (!fp->Serialize(&no_)) return false;
  if (!fp->Serialize(&num_weights_)) return false;
  if (!fp->Serialize(name_.c_str(), name_.length())) return false;
  return true;
}

static NetworkType getNetworkType(TFile* fp) {
  int8_t data;
  if (!fp->DeSerialize(&data)) return NT_NONE;
  if (data == NT_NONE) {
    STRING type_name;
    if (!type_name.DeSerialize(fp)) return NT_NONE;
    for (data = 0; data < NT_COUNT && type_name != kTypeNames[data]; ++data) {
    }
    if (data == NT_COUNT) {
      tprintf("Invalid network layer type:%s\n", type_name.c_str());
      return NT_NONE;
    }
  }
  return static_cast<NetworkType>(data);
}

// Reads from the given file. Returns nullptr in case of error.
// Determines the type of the serialized class and calls its DeSerialize
// on a new object of the appropriate type, which is returned.
Network* Network::CreateFromFile(TFile* fp) {
  NetworkType type;          // Type of the derived network class.
  TrainingState training;    // Are we currently training?
  bool needs_to_backprop;    // This network needs to output back_deltas.
  int32_t network_flags;     // Behavior control flags in NetworkFlags.
  int32_t ni;                // Number of input values.
  int32_t no;                // Number of output values.
  int32_t num_weights;       // Number of weights in this and sub-network.
  STRING name;               // A unique name for this layer.
  int8_t data;
  Network* network = nullptr;
  type = getNetworkType(fp);
  if (!fp->DeSerialize(&data)) return nullptr;
  training = data == TS_ENABLED ? TS_ENABLED : TS_DISABLED;
  if (!fp->DeSerialize(&data)) return nullptr;
  needs_to_backprop = data != 0;
  if (!fp->DeSerialize(&network_flags)) return nullptr;
  if (!fp->DeSerialize(&ni)) return nullptr;
  if (!fp->DeSerialize(&no)) return nullptr;
  if (!fp->DeSerialize(&num_weights)) return nullptr;
  if (!name.DeSerialize(fp)) return nullptr;

  switch (type) {
    case NT_CONVOLVE:
      network = new Convolve(name.c_str(), ni, 0, 0);
      break;
    case NT_INPUT:
      network = new Input(name.c_str(), ni, no);
      break;
    case NT_LSTM:
    case NT_LSTM_SOFTMAX:
    case NT_LSTM_SOFTMAX_ENCODED:
    case NT_LSTM_SUMMARY:
      network =
          new LSTM(name.c_str(), ni, no, no, false, type);
      break;
    case NT_MAXPOOL:
      network = new Maxpool(name.c_str(), ni, 0, 0);
      break;
    // All variants of Parallel.
    case NT_PARALLEL:
    case NT_REPLICATED:
    case NT_PAR_RL_LSTM:
    case NT_PAR_UD_LSTM:
    case NT_PAR_2D_LSTM:
      network = new Parallel(name.c_str(), type);
      break;
    case NT_RECONFIG:
      network = new Reconfig(name.c_str(), ni, 0, 0);
      break;
    // All variants of reversed.
    case NT_XREVERSED:
    case NT_YREVERSED:
    case NT_XYTRANSPOSE:
      network = new Reversed(name.c_str(), type);
      break;
    case NT_SERIES:
      network = new Series(name.c_str());
      break;
    case NT_TENSORFLOW:
#ifdef INCLUDE_TENSORFLOW
      network = new TFNetwork(name);
#else
      tprintf("TensorFlow not compiled in! -DINCLUDE_TENSORFLOW\n");
#endif
      break;
    // All variants of FullyConnected.
    case NT_SOFTMAX:
    case NT_SOFTMAX_NO_CTC:
    case NT_RELU:
    case NT_TANH:
    case NT_LINEAR:
    case NT_LOGISTIC:
    case NT_POSCLIP:
    case NT_SYMCLIP:
      network = new FullyConnected(name.c_str(), ni, no, type);
      break;
    default:
      break;
  }
  if (network) {
    network->training_ = training;
    network->needs_to_backprop_ = needs_to_backprop;
    network->network_flags_ = network_flags;
    network->num_weights_ = num_weights;
    if (!network->DeSerialize(fp)) {
      delete network;
      network = nullptr;
    }
  }
  return network;
}

// Returns a random number in [-range, range].
double Network::Random(double range) {
  ASSERT_HOST(randomizer_ != nullptr);
  return randomizer_->SignedRand(range);
}

#ifndef GRAPHICS_DISABLED

// === Debug image display methods. ===
// Displays the image of the matrix to the forward window.
void Network::DisplayForward(const NetworkIO& matrix) {
  Pix* image = matrix.ToPix();
  ClearWindow(false, name_.c_str(), pixGetWidth(image),
              pixGetHeight(image), &forward_win_);
  DisplayImage(image, forward_win_);
  forward_win_->Update();
}

// Displays the image of the matrix to the backward window.
void Network::DisplayBackward(const NetworkIO& matrix) {
  Pix* image = matrix.ToPix();
  std::string window_name = name_ + "-back";
  ClearWindow(false, window_name.c_str(), pixGetWidth(image),
              pixGetHeight(image), &backward_win_);
  DisplayImage(image, backward_win_);
  backward_win_->Update();
}

// Creates the window if needed, otherwise clears it.
void Network::ClearWindow(bool tess_coords, const char* window_name,
                          int width, int height, ScrollView** window) {
  if (*window == nullptr) {
    int min_size = std::min(width, height);
    if (min_size < kMinWinSize) {
      if (min_size < 1) min_size = 1;
      width = width * kMinWinSize / min_size;
      height = height * kMinWinSize / min_size;
    }
    width += kXWinFrameSize;
    height += kYWinFrameSize;
    if (width > kMaxWinSize) width = kMaxWinSize;
    if (height > kMaxWinSize) height = kMaxWinSize;
    *window = new ScrollView(window_name, 80, 100, width, height, width, height,
                             tess_coords);
    tprintf("Created window %s of size %d, %d\n", window_name, width, height);
  } else {
    (*window)->Clear();
  }
}

// Displays the pix in the given window. and returns the height of the pix.
// The pix is pixDestroyed.
int Network::DisplayImage(Pix* pix, ScrollView* window) {
  int height = pixGetHeight(pix);
  window->Image(pix, 0, 0);
  pixDestroy(&pix);
  return height;
}
#endif // !GRAPHICS_DISABLED

}  // namespace tesseract.
<commit_msg>Fix regression in Network::Serialize (fix issue #3167)<commit_after>///////////////////////////////////////////////////////////////////////
// File:        network.cpp
// Description: Base class for neural network implementations.
// Author:      Ray Smith
//
// (C) Copyright 2013, Google Inc.
// 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 automatically generated configuration file if running autoconf.
#ifdef HAVE_CONFIG_H
#include "config_auto.h"
#endif

#include "network.h"

#include <cstdlib>

// This base class needs to know about all its sub-classes because of the
// factory deserializing method: CreateFromFile.
#include "allheaders.h"
#include "convolve.h"
#include "fullyconnected.h"
#include "input.h"
#include "lstm.h"
#include "maxpool.h"
#include "parallel.h"
#include "reconfig.h"
#include "reversed.h"
#include "scrollview.h"
#include "series.h"
#include "statistc.h"
#ifdef INCLUDE_TENSORFLOW
#include "tfnetwork.h"
#endif
#include "tprintf.h"

namespace tesseract {

// Min and max window sizes.
const int kMinWinSize = 500;
const int kMaxWinSize = 2000;
// Window frame sizes need adding on to make the content fit.
const int kXWinFrameSize = 30;
const int kYWinFrameSize = 80;

// String names corresponding to the NetworkType enum.
// Keep in sync with NetworkType.
// Names used in Serialization to allow re-ordering/addition/deletion of
// layer types in NetworkType without invalidating existing network files.
static char const* const kTypeNames[NT_COUNT] = {
    "Invalid",     "Input",
    "Convolve",    "Maxpool",
    "Parallel",    "Replicated",
    "ParBidiLSTM", "DepParUDLSTM",
    "Par2dLSTM",   "Series",
    "Reconfig",    "RTLReversed",
    "TTBReversed", "XYTranspose",
    "LSTM",        "SummLSTM",
    "Logistic",    "LinLogistic",
    "LinTanh",     "Tanh",
    "Relu",        "Linear",
    "Softmax",     "SoftmaxNoCTC",
    "LSTMSoftmax", "LSTMBinarySoftmax",
    "TensorFlow",
};

Network::Network()
    : type_(NT_NONE),
      training_(TS_ENABLED),
      needs_to_backprop_(true),
      network_flags_(0),
      ni_(0),
      no_(0),
      num_weights_(0),
      forward_win_(nullptr),
      backward_win_(nullptr),
      randomizer_(nullptr) {}
Network::Network(NetworkType type, const std::string& name, int ni, int no)
    : type_(type),
      training_(TS_ENABLED),
      needs_to_backprop_(true),
      network_flags_(0),
      ni_(ni),
      no_(no),
      num_weights_(0),
      name_(name),
      forward_win_(nullptr),
      backward_win_(nullptr),
      randomizer_(nullptr) {}

// Suspends/Enables/Permanently disables training by setting the training_
// flag. Serialize and DeSerialize only operate on the run-time data if state
// is TS_DISABLED or TS_TEMP_DISABLE. Specifying TS_TEMP_DISABLE will
// temporarily disable layers in state TS_ENABLED, allowing a trainer to
// serialize as if it were a recognizer.
// TS_RE_ENABLE will re-enable layers that were previously in any disabled
// state. If in TS_TEMP_DISABLE then the flag is just changed, but if in
// TS_DISABLED, the deltas in the weight matrices are reinitialized so that a
// recognizer can be converted back to a trainer.
void Network::SetEnableTraining(TrainingState state) {
  if (state == TS_RE_ENABLE) {
    // Enable only from temp disabled.
    if (training_ == TS_TEMP_DISABLE) training_ = TS_ENABLED;
  } else if (state == TS_TEMP_DISABLE) {
    // Temp disable only from enabled.
    if (training_ == TS_ENABLED) training_ = state;
  } else {
    training_ = state;
  }
}

// Sets flags that control the action of the network. See NetworkFlags enum
// for bit values.
void Network::SetNetworkFlags(uint32_t flags) {
  network_flags_ = flags;
}

// Sets up the network for training. Initializes weights using weights of
// scale `range` picked according to the random number generator `randomizer`.
int Network::InitWeights(float range, TRand* randomizer) {
  randomizer_ = randomizer;
  return 0;
}

// Provides a pointer to a TRand for any networks that care to use it.
// Note that randomizer is a borrowed pointer that should outlive the network
// and should not be deleted by any of the networks.
void Network::SetRandomizer(TRand* randomizer) {
  randomizer_ = randomizer;
}

// Sets needs_to_backprop_ to needs_backprop and returns true if
// needs_backprop || any weights in this network so the next layer forward
// can be told to produce backprop for this layer if needed.
bool Network::SetupNeedsBackprop(bool needs_backprop) {
  needs_to_backprop_ = needs_backprop;
  return needs_backprop || num_weights_ > 0;
}

// Writes to the given file. Returns false in case of error.
bool Network::Serialize(TFile* fp) const {
  int8_t data = NT_NONE;
  if (!fp->Serialize(&data)) return false;
  STRING type_name = kTypeNames[type_];
  if (!type_name.Serialize(fp)) return false;
  data = training_;
  if (!fp->Serialize(&data)) return false;
  data = needs_to_backprop_;
  if (!fp->Serialize(&data)) return false;
  if (!fp->Serialize(&network_flags_)) return false;
  if (!fp->Serialize(&ni_)) return false;
  if (!fp->Serialize(&no_)) return false;
  if (!fp->Serialize(&num_weights_)) return false;
  uint32_t length = name_.length();
  if (!fp->Serialize(&length)) return false;
  return fp->Serialize(name_.c_str(), length);
}

static NetworkType getNetworkType(TFile* fp) {
  int8_t data;
  if (!fp->DeSerialize(&data)) return NT_NONE;
  if (data == NT_NONE) {
    STRING type_name;
    if (!type_name.DeSerialize(fp)) return NT_NONE;
    for (data = 0; data < NT_COUNT && type_name != kTypeNames[data]; ++data) {
    }
    if (data == NT_COUNT) {
      tprintf("Invalid network layer type:%s\n", type_name.c_str());
      return NT_NONE;
    }
  }
  return static_cast<NetworkType>(data);
}

// Reads from the given file. Returns nullptr in case of error.
// Determines the type of the serialized class and calls its DeSerialize
// on a new object of the appropriate type, which is returned.
Network* Network::CreateFromFile(TFile* fp) {
  NetworkType type;          // Type of the derived network class.
  TrainingState training;    // Are we currently training?
  bool needs_to_backprop;    // This network needs to output back_deltas.
  int32_t network_flags;     // Behavior control flags in NetworkFlags.
  int32_t ni;                // Number of input values.
  int32_t no;                // Number of output values.
  int32_t num_weights;       // Number of weights in this and sub-network.
  STRING name;               // A unique name for this layer.
  int8_t data;
  Network* network = nullptr;
  type = getNetworkType(fp);
  if (!fp->DeSerialize(&data)) return nullptr;
  training = data == TS_ENABLED ? TS_ENABLED : TS_DISABLED;
  if (!fp->DeSerialize(&data)) return nullptr;
  needs_to_backprop = data != 0;
  if (!fp->DeSerialize(&network_flags)) return nullptr;
  if (!fp->DeSerialize(&ni)) return nullptr;
  if (!fp->DeSerialize(&no)) return nullptr;
  if (!fp->DeSerialize(&num_weights)) return nullptr;
  if (!name.DeSerialize(fp)) return nullptr;

  switch (type) {
    case NT_CONVOLVE:
      network = new Convolve(name.c_str(), ni, 0, 0);
      break;
    case NT_INPUT:
      network = new Input(name.c_str(), ni, no);
      break;
    case NT_LSTM:
    case NT_LSTM_SOFTMAX:
    case NT_LSTM_SOFTMAX_ENCODED:
    case NT_LSTM_SUMMARY:
      network =
          new LSTM(name.c_str(), ni, no, no, false, type);
      break;
    case NT_MAXPOOL:
      network = new Maxpool(name.c_str(), ni, 0, 0);
      break;
    // All variants of Parallel.
    case NT_PARALLEL:
    case NT_REPLICATED:
    case NT_PAR_RL_LSTM:
    case NT_PAR_UD_LSTM:
    case NT_PAR_2D_LSTM:
      network = new Parallel(name.c_str(), type);
      break;
    case NT_RECONFIG:
      network = new Reconfig(name.c_str(), ni, 0, 0);
      break;
    // All variants of reversed.
    case NT_XREVERSED:
    case NT_YREVERSED:
    case NT_XYTRANSPOSE:
      network = new Reversed(name.c_str(), type);
      break;
    case NT_SERIES:
      network = new Series(name.c_str());
      break;
    case NT_TENSORFLOW:
#ifdef INCLUDE_TENSORFLOW
      network = new TFNetwork(name);
#else
      tprintf("TensorFlow not compiled in! -DINCLUDE_TENSORFLOW\n");
#endif
      break;
    // All variants of FullyConnected.
    case NT_SOFTMAX:
    case NT_SOFTMAX_NO_CTC:
    case NT_RELU:
    case NT_TANH:
    case NT_LINEAR:
    case NT_LOGISTIC:
    case NT_POSCLIP:
    case NT_SYMCLIP:
      network = new FullyConnected(name.c_str(), ni, no, type);
      break;
    default:
      break;
  }
  if (network) {
    network->training_ = training;
    network->needs_to_backprop_ = needs_to_backprop;
    network->network_flags_ = network_flags;
    network->num_weights_ = num_weights;
    if (!network->DeSerialize(fp)) {
      delete network;
      network = nullptr;
    }
  }
  return network;
}

// Returns a random number in [-range, range].
double Network::Random(double range) {
  ASSERT_HOST(randomizer_ != nullptr);
  return randomizer_->SignedRand(range);
}

#ifndef GRAPHICS_DISABLED

// === Debug image display methods. ===
// Displays the image of the matrix to the forward window.
void Network::DisplayForward(const NetworkIO& matrix) {
  Pix* image = matrix.ToPix();
  ClearWindow(false, name_.c_str(), pixGetWidth(image),
              pixGetHeight(image), &forward_win_);
  DisplayImage(image, forward_win_);
  forward_win_->Update();
}

// Displays the image of the matrix to the backward window.
void Network::DisplayBackward(const NetworkIO& matrix) {
  Pix* image = matrix.ToPix();
  std::string window_name = name_ + "-back";
  ClearWindow(false, window_name.c_str(), pixGetWidth(image),
              pixGetHeight(image), &backward_win_);
  DisplayImage(image, backward_win_);
  backward_win_->Update();
}

// Creates the window if needed, otherwise clears it.
void Network::ClearWindow(bool tess_coords, const char* window_name,
                          int width, int height, ScrollView** window) {
  if (*window == nullptr) {
    int min_size = std::min(width, height);
    if (min_size < kMinWinSize) {
      if (min_size < 1) min_size = 1;
      width = width * kMinWinSize / min_size;
      height = height * kMinWinSize / min_size;
    }
    width += kXWinFrameSize;
    height += kYWinFrameSize;
    if (width > kMaxWinSize) width = kMaxWinSize;
    if (height > kMaxWinSize) height = kMaxWinSize;
    *window = new ScrollView(window_name, 80, 100, width, height, width, height,
                             tess_coords);
    tprintf("Created window %s of size %d, %d\n", window_name, width, height);
  } else {
    (*window)->Clear();
  }
}

// Displays the pix in the given window. and returns the height of the pix.
// The pix is pixDestroyed.
int Network::DisplayImage(Pix* pix, ScrollView* window) {
  int height = pixGetHeight(pix);
  window->Image(pix, 0, 0);
  pixDestroy(&pix);
  return height;
}
#endif // !GRAPHICS_DISABLED

}  // namespace tesseract.
<|endoftext|>


<commit_before>/*-------------------------------------------------------------------------
 *
 * bridge_test_mix.cpp
 * file description
 *
 * Copyright(c) 2015, CMU
 *
 * /peloton/tests/bridge/bridge_test_mix.cpp
 *
 *-------------------------------------------------------------------------
 */

#include "bridge_test.h"

#include "backend/bridge/ddl/bridge.h"
#include "backend/bridge/ddl/ddl.h"
#include "backend/bridge/ddl/ddl_table.h"
#include "backend/bridge/ddl/ddl_index.h"
#include "backend/catalog/manager.h"
#include "backend/storage/database.h"

namespace peloton {
namespace bridge {

/**
 * @brief Test many DDL functions together
 */
void BridgeTest::DDL_MIX_TEST() {

  DDL_MIX_TEST_1();

  DDL_MIX_TEST_2();

  DDL_MIX_TEST_3();

}

/**
 * @brief Create a table with simple columns that contain
 *        column-level constraints such as single column
 *        primary key, unique, and reference table
 */
void BridgeTest::DDL_MIX_TEST_1() {
  auto& manager = catalog::Manager::GetInstance();
  storage::Database* db =
      manager.GetDatabaseWithOid(Bridge::GetCurrentDatabaseOid());

  // Get the simple columns
  std::vector<catalog::Column> columns = CreateSimpleColumns();

  // Table name and oid
  std::string table_name = "test_table_column_constraint";
  oid_t table_oid = 50001;

  // Create a table
  bool status = DDLTable::CreateTable(table_oid, table_name, columns);
  assert(status);

  // Get the table pointer and schema
  storage::DataTable* table = db->GetTableWithOid(table_oid);
  catalog::Schema* schema = table->GetSchema();

  // Create the constrains
  catalog::Constraint notnull_constraint(CONSTRAINT_TYPE_NOTNULL);

  // Add one constraint to the one column
  schema->AddConstraint("id", notnull_constraint);

  // Create a primary key index and added primary key constraint to the 'name'
  // column
  oid_t primary_key_index_oid = 50002;
  CreateSamplePrimaryKeyIndex(table_name, primary_key_index_oid);

  // Create a unique index and added unique constraint to the 'time' column
  oid_t unique_index_oid = 50003;
  CreateSampleUniqueIndex(table_name, unique_index_oid);

  // Create a reference table and foreign key constraint and added unique
  // constraint to the 'salary' column
  std::string pktable_name = "pktable";
  oid_t pktable_oid = 50004;
  CreateSampleForeignKey(pktable_oid, pktable_name, columns, table_oid);

  // Check the first column's constraint
  catalog::Column column = schema->GetColumn(0);
  CheckColumnWithConstraint(column, CONSTRAINT_TYPE_NOTNULL, "", 1);

  // Check the second column's constraint and index
  column = schema->GetColumn(1);
  CheckColumnWithConstraint(column, CONSTRAINT_TYPE_PRIMARY,
                            table_name + "_pkey", 1);
  index::Index* index = table->GetIndexWithOid(primary_key_index_oid);
  CheckIndex(index, table_name + "_pkey", 1, INDEX_TYPE_BTREE,
             INDEX_CONSTRAINT_TYPE_PRIMARY_KEY, true);

  // Check the third column's constraint and index
  column = schema->GetColumn(2);
  CheckColumnWithConstraint(column, CONSTRAINT_TYPE_UNIQUE, table_name + "_key",
                            1);
  index = table->GetIndexWithOid(unique_index_oid);
  CheckIndex(index, table_name + "_key", 1, INDEX_TYPE_BTREE,
             INDEX_CONSTRAINT_TYPE_UNIQUE, true);

  // Check the fourth column's constraint and foreign key
  column = schema->GetColumn(3);
  CheckColumnWithConstraint(column, CONSTRAINT_TYPE_FOREIGN,
                            "THIS_IS_FOREIGN_CONSTRAINT", 1, 0);
  catalog::ForeignKey* pktable = table->GetForeignKey(0);
  CheckForeignKey(pktable, pktable_oid, "THIS_IS_FOREIGN_CONSTRAINT", 1, 1, 'r',
                  'c');

  // Drop the table
  status = DDLTable::DropTable(table_oid);
  assert(status);

  // Drop the table
  status = DDLTable::DropTable(pktable_oid);
  assert(status);

  std::cout << ":::::: " << __func__ << " DONE\n";
}

/**
 * @brief Test DDL and DML together. Create a table and drop it. Create a table
 *  again and insert tuple into the table.
 */
void BridgeTest::DDL_MIX_TEST_2() {

  auto& manager = catalog::Manager::GetInstance();
  storage::Database* db = manager.GetDatabaseWithOid(Bridge::GetCurrentDatabaseOid());

  // Get the simple columns
  std::vector<catalog::Column> columns = CreateSimpleColumns();

  // Table name and oid
  std::string table_name = "ddl_dml_mix_test_table";
  oid_t table_oid = 60001;

  // Create a table
  bool status = DDLTable::CreateTable(table_oid, table_name, columns);
  assert(status);

  // Drop the table
  status = DDLTable::DropTable(table_oid);
  assert(status);

  // Create a table again
  status = DDLTable::CreateTable(table_oid, table_name, columns);
  assert(status);

  // Get the table pointer and schema
  storage::DataTable* table = db->GetTableWithOid(table_oid);
  catalog::Schema *schema = table->GetSchema();

  // Ensure that the tile group is as expected.
  assert(schema->GetColumnCount() == 4);

  // Insert tuples
  const bool allocate = true;

  for (int col_itr = 0; col_itr < 5; col_itr++) {

    storage::Tuple tuple(schema, allocate);

    // Setting values
    Value integerValue = ValueFactory::GetIntegerValue(243432);
    Value stringValue = ValueFactory::GetStringValue("dude");
    Value timestampValue = ValueFactory::GetTimestampValue(10.22);
    Value doubleValue = ValueFactory::GetDoubleValue(244643.1236);

    tuple.SetValue(0, integerValue);
    tuple.SetValue(1, stringValue);
    tuple.SetValue(2, timestampValue);
    tuple.SetValue(3, doubleValue);

    table->InsertTuple((txn_id_t)col_itr, &tuple, false);

    assert(tuple.GetValue(0) == integerValue);
    assert(tuple.GetValue(1) == stringValue);
    assert(tuple.GetValue(2) == timestampValue);
    assert(tuple.GetValue(3) == doubleValue);
  }

  // Drop the table
  status = DDLTable::DropTable(table_oid);
  assert(status);

  std::cout << ":::::: " << __func__ << " DONE\n";
}

/**
 * @brief UpdateStats Test
 */
void BridgeTest::DDL_MIX_TEST_3() {
  bool status;

  // Get db
  auto& manager = catalog::Manager::GetInstance();
  storage::Database* db = manager.GetDatabaseWithOid(Bridge::GetCurrentDatabaseOid());

  // Get the simple columns
  std::vector<catalog::Column> columns = CreateSimpleColumns();
  std::string table_name = "DDL_MIX_TEST_3";

  // Create a table in Postgres
  oid_t table_oid = CreateTableInPostgres(table_name);
  assert(table_oid);

  // Create a table in Peloton as well
  status = DDLTable::CreateTable(table_oid, table_name, columns);
  assert(status);

  // insert tuple
   // Get the table pointer and schema
  storage::DataTable* table = db->GetTableWithOid(table_oid);
  catalog::Schema *schema = table->GetSchema();

  // Ensure that the tile group is as expected.
  assert(schema->GetColumnCount() == 4);

  // Insert tuples
  const bool allocate = true;

  for (int col_itr = 0; col_itr < 5; col_itr++) {

    storage::Tuple tuple(schema, allocate);

    // Setting values
    Value integerValue = ValueFactory::GetIntegerValue(243432);
    Value stringValue = ValueFactory::GetStringValue("dude");
    Value timestampValue = ValueFactory::GetTimestampValue(10.22);
    Value doubleValue = ValueFactory::GetDoubleValue(244643.1236);

    tuple.SetValue(0, integerValue);
    tuple.SetValue(1, stringValue);
    tuple.SetValue(2, timestampValue);
    tuple.SetValue(3, doubleValue);

    table->InsertTuple((txn_id_t)col_itr, &tuple, false);

    assert(tuple.GetValue(0) == integerValue);
    assert(tuple.GetValue(1) == stringValue);
    assert(tuple.GetValue(2) == timestampValue);
    assert(tuple.GetValue(3) == doubleValue);
  }

  // get the number of tuples
  assert( Bridge::GetNumberOfTuples(table_oid) == 0 );

  // analyze
  db->UpdateStats();

  // get the number of tuples
  assert( Bridge::GetNumberOfTuples(table_oid) == 5 );

  // create table
  // Create a table in Peloton as well
  status = DDLTable::CreateTable(table_oid+1, table_name+"second", columns);
  assert(status);

  // Drop the table in Postgres
  status = DropTableInPostgres(table_name);
  assert(status);

  // Drop the table
  status = DDLTable::DropTable(table_oid);
  assert(status);

  // Drop the table
  status = DDLTable::DropTable(table_oid+1);
  assert(status);

  std::cout << ":::::: " << __func__ << " DONE\n";
}

}  // End bridge namespace
}  // End peloton namespace
<commit_msg>Disabled BRIDGE_TEST_MIX_3 (UpdateStats test)<commit_after>/*-------------------------------------------------------------------------
 *
 * bridge_test_mix.cpp
 * file description
 *
 * Copyright(c) 2015, CMU
 *
 * /peloton/tests/bridge/bridge_test_mix.cpp
 *
 *-------------------------------------------------------------------------
 */

#include "bridge_test.h"

#include "backend/bridge/ddl/bridge.h"
#include "backend/bridge/ddl/ddl.h"
#include "backend/bridge/ddl/ddl_table.h"
#include "backend/bridge/ddl/ddl_index.h"
#include "backend/catalog/manager.h"
#include "backend/storage/database.h"

namespace peloton {
namespace bridge {

/**
 * @brief Test many DDL functions together
 */
void BridgeTest::DDL_MIX_TEST() {

  DDL_MIX_TEST_1();

  DDL_MIX_TEST_2();

  DDL_MIX_TEST_3();

}

/**
 * @brief Create a table with simple columns that contain
 *        column-level constraints such as single column
 *        primary key, unique, and reference table
 */
void BridgeTest::DDL_MIX_TEST_1() {
  auto& manager = catalog::Manager::GetInstance();
  storage::Database* db =
      manager.GetDatabaseWithOid(Bridge::GetCurrentDatabaseOid());

  // Get the simple columns
  std::vector<catalog::Column> columns = CreateSimpleColumns();

  // Table name and oid
  std::string table_name = "test_table_column_constraint";
  oid_t table_oid = 50001;

  // Create a table
  bool status = DDLTable::CreateTable(table_oid, table_name, columns);
  assert(status);

  // Get the table pointer and schema
  storage::DataTable* table = db->GetTableWithOid(table_oid);
  catalog::Schema* schema = table->GetSchema();

  // Create the constrains
  catalog::Constraint notnull_constraint(CONSTRAINT_TYPE_NOTNULL);

  // Add one constraint to the one column
  schema->AddConstraint("id", notnull_constraint);

  // Create a primary key index and added primary key constraint to the 'name'
  // column
  oid_t primary_key_index_oid = 50002;
  CreateSamplePrimaryKeyIndex(table_name, primary_key_index_oid);

  // Create a unique index and added unique constraint to the 'time' column
  oid_t unique_index_oid = 50003;
  CreateSampleUniqueIndex(table_name, unique_index_oid);

  // Create a reference table and foreign key constraint and added unique
  // constraint to the 'salary' column
  std::string pktable_name = "pktable";
  oid_t pktable_oid = 50004;
  CreateSampleForeignKey(pktable_oid, pktable_name, columns, table_oid);

  // Check the first column's constraint
  catalog::Column column = schema->GetColumn(0);
  CheckColumnWithConstraint(column, CONSTRAINT_TYPE_NOTNULL, "", 1);

  // Check the second column's constraint and index
  column = schema->GetColumn(1);
  CheckColumnWithConstraint(column, CONSTRAINT_TYPE_PRIMARY,
                            table_name + "_pkey", 1);
  index::Index* index = table->GetIndexWithOid(primary_key_index_oid);
  CheckIndex(index, table_name + "_pkey", 1, INDEX_TYPE_BTREE,
             INDEX_CONSTRAINT_TYPE_PRIMARY_KEY, true);

  // Check the third column's constraint and index
  column = schema->GetColumn(2);
  CheckColumnWithConstraint(column, CONSTRAINT_TYPE_UNIQUE, table_name + "_key",
                            1);
  index = table->GetIndexWithOid(unique_index_oid);
  CheckIndex(index, table_name + "_key", 1, INDEX_TYPE_BTREE,
             INDEX_CONSTRAINT_TYPE_UNIQUE, true);

  // Check the fourth column's constraint and foreign key
  column = schema->GetColumn(3);
  CheckColumnWithConstraint(column, CONSTRAINT_TYPE_FOREIGN,
                            "THIS_IS_FOREIGN_CONSTRAINT", 1, 0);
  catalog::ForeignKey* pktable = table->GetForeignKey(0);
  CheckForeignKey(pktable, pktable_oid, "THIS_IS_FOREIGN_CONSTRAINT", 1, 1, 'r',
                  'c');

  // Drop the table
  status = DDLTable::DropTable(table_oid);
  assert(status);

  // Drop the table
  status = DDLTable::DropTable(pktable_oid);
  assert(status);

  std::cout << ":::::: " << __func__ << " DONE\n";
}

/**
 * @brief Test DDL and DML together. Create a table and drop it. Create a table
 *  again and insert tuple into the table.
 */
void BridgeTest::DDL_MIX_TEST_2() {

  auto& manager = catalog::Manager::GetInstance();
  storage::Database* db = manager.GetDatabaseWithOid(Bridge::GetCurrentDatabaseOid());

  // Get the simple columns
  std::vector<catalog::Column> columns = CreateSimpleColumns();

  // Table name and oid
  std::string table_name = "ddl_dml_mix_test_table";
  oid_t table_oid = 60001;

  // Create a table
  bool status = DDLTable::CreateTable(table_oid, table_name, columns);
  assert(status);

  // Drop the table
  status = DDLTable::DropTable(table_oid);
  assert(status);

  // Create a table again
  status = DDLTable::CreateTable(table_oid, table_name, columns);
  assert(status);

  // Get the table pointer and schema
  storage::DataTable* table = db->GetTableWithOid(table_oid);
  catalog::Schema *schema = table->GetSchema();

  // Ensure that the tile group is as expected.
  assert(schema->GetColumnCount() == 4);

  // Insert tuples
  const bool allocate = true;

  for (int col_itr = 0; col_itr < 5; col_itr++) {

    storage::Tuple tuple(schema, allocate);

    // Setting values
    Value integerValue = ValueFactory::GetIntegerValue(243432);
    Value stringValue = ValueFactory::GetStringValue("dude");
    Value timestampValue = ValueFactory::GetTimestampValue(10.22);
    Value doubleValue = ValueFactory::GetDoubleValue(244643.1236);

    tuple.SetValue(0, integerValue);
    tuple.SetValue(1, stringValue);
    tuple.SetValue(2, timestampValue);
    tuple.SetValue(3, doubleValue);

    table->InsertTuple((txn_id_t)col_itr, &tuple, false);

    assert(tuple.GetValue(0) == integerValue);
    assert(tuple.GetValue(1) == stringValue);
    assert(tuple.GetValue(2) == timestampValue);
    assert(tuple.GetValue(3) == doubleValue);
  }

  // Drop the table
  status = DDLTable::DropTable(table_oid);
  assert(status);

  std::cout << ":::::: " << __func__ << " DONE\n";
}

/**
 * @brief UpdateStats Test
 */
void BridgeTest::DDL_MIX_TEST_3() {
  bool status;
//
//  // Get db
//  auto& manager = catalog::Manager::GetInstance();
//  storage::Database* db = manager.GetDatabaseWithOid(Bridge::GetCurrentDatabaseOid());
//
//  // Get the simple columns
//  std::vector<catalog::Column> columns = CreateSimpleColumns();
//  std::string table_name = "DDL_MIX_TEST_3";
//
//  // Create a table in Postgres
//  oid_t table_oid = CreateTableInPostgres(table_name);
//  assert(table_oid);
//
//  // Create a table in Peloton as well
//  status = DDLTable::CreateTable(table_oid, table_name, columns);
//  assert(status);
//
//  // insert tuple
//   // Get the table pointer and schema
//  storage::DataTable* table = db->GetTableWithOid(table_oid);
//  catalog::Schema *schema = table->GetSchema();
//
//  // Ensure that the tile group is as expected.
//  assert(schema->GetColumnCount() == 4);
//
//  // Insert tuples
//  const bool allocate = true;
//
//  for (int col_itr = 0; col_itr < 5; col_itr++) {
//
//    storage::Tuple tuple(schema, allocate);
//
//    // Setting values
//    Value integerValue = ValueFactory::GetIntegerValue(243432);
//    Value stringValue = ValueFactory::GetStringValue("dude");
//    Value timestampValue = ValueFactory::GetTimestampValue(10.22);
//    Value doubleValue = ValueFactory::GetDoubleValue(244643.1236);
//
//    tuple.SetValue(0, integerValue);
//    tuple.SetValue(1, stringValue);
//    tuple.SetValue(2, timestampValue);
//    tuple.SetValue(3, doubleValue);
//
//    table->InsertTuple((txn_id_t)col_itr, &tuple, false);
//
//    assert(tuple.GetValue(0) == integerValue);
//    assert(tuple.GetValue(1) == stringValue);
//    assert(tuple.GetValue(2) == timestampValue);
//    assert(tuple.GetValue(3) == doubleValue);
//  }
//
//  // get the number of tuples
//  assert( Bridge::GetNumberOfTuples(table_oid) == 0 );
//
//  // analyze
//  db->UpdateStats();
//
//  // get the number of tuples
//  assert( Bridge::GetNumberOfTuples(table_oid) == 5 );
//
//  // create table
//  // Create a table in Peloton as well
//  status = DDLTable::CreateTable(table_oid+1, table_name+"second", columns);
//  assert(status);
//
//  // Drop the table in Postgres
//  status = DropTableInPostgres(table_name);
//  assert(status);
//
//  // Drop the table
//  status = DDLTable::DropTable(table_oid);
//  assert(status);
//
//  // Drop the table
//  status = DDLTable::DropTable(table_oid+1);
//  assert(status);
//
//  std::cout << ":::::: " << __func__ << " DONE\n";
}

}  // End bridge namespace
}  // End peloton namespace
<|endoftext|>


<commit_before>#include "blackmagicsdk_video_source.h"
#include "deck_link_display_mode_detector.h"
#include <chrono>

namespace gg
{

VideoSourceBlackmagicSDK::VideoSourceBlackmagicSDK()
    : IVideoSource()
    , _frame_rate(0.0)
    , _video_buffer(nullptr)
    , _video_buffer_length(0)
    , _cols(0)
    , _rows(0)
    , _buffer_video_frame(VideoFrame(UYVY))
    , _running(false)
{
    // nop
}

VideoSourceBlackmagicSDK::VideoSourceBlackmagicSDK(size_t deck_link_index,
                                                   ColourSpace colour)
    : IVideoSource(colour)
    , _frame_rate(0.0)
    , _video_buffer(nullptr)
    , _video_buffer_length(0)
    , _cols(0)
    , _rows(0)
    , _buffer_video_frame(VideoFrame(colour, false)) // TODO manage data?
    , _deck_link(nullptr)
    , _deck_link_input(nullptr)
    , _video_input_flags(bmdVideoInputFlagDefault | bmdVideoInputDualStream3D)
    , _running(false)
{
    // Pixel format, i.e. colour space
    BMDPixelFormat pixel_format;
    switch(_colour)
    {
    case UYVY:
        pixel_format = bmdFormat8BitYUV;
        break;
    case BGRA:
    case I420:
    default:
        bail("BlackmagicSDK video source supports only the UYVY colour space");
    }

    // Get an iterator through the available DeckLink ports
    IDeckLinkIterator * deck_link_iterator = CreateDeckLinkIteratorInstance();
    if (deck_link_iterator == nullptr)
        bail("DeckLink drivers do not appear to be installed");

    HRESULT res;

    // Get the desired DeckLink index (port)
    int idx = deck_link_index;
    while ((res = deck_link_iterator->Next(&_deck_link)) == S_OK)
    {
        if (idx == 0)
            break;
        --idx;

        _deck_link->Release();
    }
    if (deck_link_iterator != nullptr)
        deck_link_iterator->Release();
    // No glory: release everything and throw exception
    if (res != S_OK or _deck_link == nullptr)
        bail(
            std::string("Could not get DeckLink device ").append(std::to_string(deck_link_index))
        );

    // Get the input interface of connected DeckLink port
    res = _deck_link->QueryInterface(IID_IDeckLinkInput, reinterpret_cast<void **>(&_deck_link_input));
    // No glory: release everything and throw exception
    if (res != S_OK)
        bail("Could not get the Blackmagic DeckLink input interface");

    // Set the input format (i.e. display mode)
    BMDDisplayMode display_mode;
    std::string error_msg = "";
    if (not detect_input_format(pixel_format, _video_input_flags, display_mode, _frame_rate, error_msg))
    {
        _video_input_flags ^= bmdVideoInputDualStream3D;
        if (not detect_input_format(pixel_format, _video_input_flags, display_mode, _frame_rate, error_msg))
            bail(error_msg);
    }

    // Set this object (IDeckLinkInputCallback instance) as callback
    res = _deck_link_input->SetCallback(this);
    // No glory: release everything and throw exception
    if (res != S_OK)
        bail("Could not set the callback of Blackmagic DeckLink device");

    // Enable video input
    res = _deck_link_input->EnableVideoInput(display_mode,
                                             pixel_format,
                                             _video_input_flags);
    // No glory
    if (res != S_OK)
        bail("Could not enable video input of Blackmagic DeckLink device");

    // Start streaming
    _running = true;
    res = _deck_link_input->StartStreams();
    // No glory: release everything and throw exception
    if (res != S_OK)
    {
        _running = false;
        bail("Could not start streaming from the Blackmagic DeckLink device");
    }
}

VideoSourceBlackmagicSDK::~VideoSourceBlackmagicSDK()
{
    // Make sure streamer thread not trying to access buffer
    std::lock_guard<std::mutex> data_lock_guard(_data_lock);
    _running = false;

    // Stop streaming and disable enabled inputs
    _deck_link_input->StopStreams();
    _deck_link_input->DisableVideoInput();

    // Release DeckLink members
    release_deck_link();
}

bool VideoSourceBlackmagicSDK::get_frame_dimensions(int & width, int & height)
{
    // Make sure only this thread is accessing the cols and rows members now
    std::lock_guard<std::mutex> data_lock_guard(_data_lock);
    if (_cols <= 0 or _rows <= 0)
        return false;

    width = _cols;
    height = _rows;
    return true;
}

bool VideoSourceBlackmagicSDK::get_frame(VideoFrame & frame)
{
    if (frame.colour() != _colour)
        return false;

    // Make sure only this thread is accessing the video frame data now
    std::lock_guard<std::mutex> data_lock_guard(_data_lock);

    if (_video_buffer_length > 0 and _cols > 0 and _rows > 0)
    {
        frame.init_from_specs(_video_buffer, _video_buffer_length, _cols, _rows);
        return true;
    }
    else
        return false;
}

double VideoSourceBlackmagicSDK::get_frame_rate()
{
    return _frame_rate;
}

void VideoSourceBlackmagicSDK::set_sub_frame(int x, int y, int width, int height)
{
    // issue #147
    throw VideoSourceError("Blackmagic does not support cropping yet");
}

void VideoSourceBlackmagicSDK::get_full_frame()
{
    // nop: set_sub_frame currently not implemented
}

HRESULT STDMETHODCALLTYPE VideoSourceBlackmagicSDK::QueryInterface(REFIID iid, LPVOID * ppv)
{
    return E_NOINTERFACE;
}

ULONG STDMETHODCALLTYPE VideoSourceBlackmagicSDK::AddRef(void)
{
    __sync_add_and_fetch(&_n_ref, 1);
    return _n_ref;
}

ULONG STDMETHODCALLTYPE VideoSourceBlackmagicSDK::Release(void)
{
    __sync_sub_and_fetch(&_n_ref, 1);
    return _n_ref;
}

HRESULT STDMETHODCALLTYPE VideoSourceBlackmagicSDK::VideoInputFormatChanged(
    BMDVideoInputFormatChangedEvents events,
    IDeckLinkDisplayMode * display_mode,
    BMDDetectedVideoInputFormatFlags format_flags
)
{
    // not supported yet: see issue #149
    return S_OK;
}

HRESULT STDMETHODCALLTYPE VideoSourceBlackmagicSDK::VideoInputFrameArrived(
    IDeckLinkVideoInputFrame * video_frame,
    IDeckLinkAudioInputPacket * audio_packet
)
{
    if (not _running)
        // nop if not running!
        return S_OK;

    // Not processing the audio packet, but only the video
    // frame for the time being
    if (video_frame == nullptr)
        // nop if no data
        return S_OK;

    // Nr. of bytes of received data
    size_t n_bytes = video_frame->GetRowBytes() * video_frame->GetHeight();

    { // Artificial scope for data lock
        // Make sure only this thread is accessing the buffer now
        std::lock_guard<std::mutex> data_lock_guard(_data_lock);

        // Extend buffer if more memory needed than already allocated
        if (n_bytes > _video_buffer_length)
            _video_buffer = reinterpret_cast<uint8_t *>(
                        realloc(_video_buffer, n_bytes * sizeof(uint8_t))
            );
        if (_video_buffer == nullptr) // something's terribly wrong!
            // nop if something's terribly wrong!
            return S_OK;

        // Get the new data into the buffer
        HRESULT res = video_frame->GetBytes(
            reinterpret_cast<void **>(&_video_buffer)
        );
        // If data could not be read into the buffer, return
        if (FAILED(res))
            return res;
        // Set video frame specs according to new data
        _video_buffer_length = n_bytes;
        _cols = video_frame->GetWidth();
        _rows = video_frame->GetHeight();

        // Propagate new video frame to observers
        _buffer_video_frame.init_from_specs(
            _video_buffer, _video_buffer_length, _cols, _rows
        );
    }

    this->notify(_buffer_video_frame);

    // Everything went fine, return success
    return S_OK;
}

void VideoSourceBlackmagicSDK::release_deck_link() noexcept
{
    if (_deck_link_input != nullptr)
    {
        _deck_link_input->Release();
        _deck_link_input = nullptr;
    }

    if (_deck_link != nullptr)
        _deck_link->Release();
}

bool VideoSourceBlackmagicSDK::detect_input_format(BMDPixelFormat pixel_format,
                                                   BMDVideoInputFlags & video_input_flags,
                                                   BMDDisplayMode & display_mode,
                                                   double & frame_rate,
                                                   std::string & error_msg) noexcept
{
    std::vector<BMDDisplayMode> display_modes =
    {
        bmdModeHD1080p6000, bmdModeHD1080p5994,
        bmdModeHD1080p50,
        bmdModeHD1080p30, bmdModeHD1080p2997,
        bmdModeHD1080p25, bmdModeHD1080p24, bmdModeHD1080p2398,
        bmdModeHD1080i6000, bmdModeHD1080i5994,
        bmdModeHD1080i50,
        bmdModeHD720p60, bmdModeHD720p5994,
        bmdModeHD720p50,
        bmdMode4K2160p60, bmdMode4K2160p5994,
        bmdMode4K2160p50,
        bmdMode4K2160p30, bmdMode4K2160p2997,
        bmdMode4K2160p25, bmdMode4K2160p24, bmdMode4K2160p2398,
        bmdMode2k25, bmdMode2k24, bmdMode2k2398,
    };

    DeckLinkDisplayModeDetector detector(
                _deck_link_input,
                display_modes, pixel_format, video_input_flags
    );
    BMDDisplayMode display_mode_ = detector.get_display_mode();
    if (display_mode_ != bmdModeUnknown)
    {
        frame_rate = detector.get_frame_rate();
        display_mode = display_mode_;
        video_input_flags = detector.get_video_input_flags();
        return true;
    }
    else
    {
        error_msg = detector.get_error_msg();
        return false;
    }
}

}
<commit_msg>Issue #5: hacker-style capturing of stereo frame into an extended buffer<commit_after>#include "blackmagicsdk_video_source.h"
#include "deck_link_display_mode_detector.h"
#include <chrono>

namespace gg
{

VideoSourceBlackmagicSDK::VideoSourceBlackmagicSDK()
    : IVideoSource()
    , _frame_rate(0.0)
    , _video_buffer(nullptr)
    , _video_buffer_length(0)
    , _cols(0)
    , _rows(0)
    , _buffer_video_frame(VideoFrame(UYVY))
    , _running(false)
{
    // nop
}

VideoSourceBlackmagicSDK::VideoSourceBlackmagicSDK(size_t deck_link_index,
                                                   ColourSpace colour)
    : IVideoSource(colour)
    , _frame_rate(0.0)
    , _video_buffer(nullptr)
    , _video_buffer_length(0)
    , _cols(0)
    , _rows(0)
    , _buffer_video_frame(VideoFrame(colour, false)) // TODO manage data?
    , _deck_link(nullptr)
    , _deck_link_input(nullptr)
    , _video_input_flags(bmdVideoInputFlagDefault | bmdVideoInputDualStream3D)
    , _running(false)
{
    // Pixel format, i.e. colour space
    BMDPixelFormat pixel_format;
    switch(_colour)
    {
    case UYVY:
        pixel_format = bmdFormat8BitYUV;
        break;
    case BGRA:
    case I420:
    default:
        bail("BlackmagicSDK video source supports only the UYVY colour space");
    }

    // Get an iterator through the available DeckLink ports
    IDeckLinkIterator * deck_link_iterator = CreateDeckLinkIteratorInstance();
    if (deck_link_iterator == nullptr)
        bail("DeckLink drivers do not appear to be installed");

    HRESULT res;

    // Get the desired DeckLink index (port)
    int idx = deck_link_index;
    while ((res = deck_link_iterator->Next(&_deck_link)) == S_OK)
    {
        if (idx == 0)
            break;
        --idx;

        _deck_link->Release();
    }
    if (deck_link_iterator != nullptr)
        deck_link_iterator->Release();
    // No glory: release everything and throw exception
    if (res != S_OK or _deck_link == nullptr)
        bail(
            std::string("Could not get DeckLink device ").append(std::to_string(deck_link_index))
        );

    // Get the input interface of connected DeckLink port
    res = _deck_link->QueryInterface(IID_IDeckLinkInput, reinterpret_cast<void **>(&_deck_link_input));
    // No glory: release everything and throw exception
    if (res != S_OK)
        bail("Could not get the Blackmagic DeckLink input interface");

    // Set the input format (i.e. display mode)
    BMDDisplayMode display_mode;
    std::string error_msg = "";
    if (not detect_input_format(pixel_format, _video_input_flags, display_mode, _frame_rate, error_msg))
    {
        _video_input_flags ^= bmdVideoInputDualStream3D;
        if (not detect_input_format(pixel_format, _video_input_flags, display_mode, _frame_rate, error_msg))
            bail(error_msg);
    }

    // Set this object (IDeckLinkInputCallback instance) as callback
    res = _deck_link_input->SetCallback(this);
    // No glory: release everything and throw exception
    if (res != S_OK)
        bail("Could not set the callback of Blackmagic DeckLink device");

    // Enable video input
    res = _deck_link_input->EnableVideoInput(display_mode,
                                             pixel_format,
                                             _video_input_flags);
    // No glory
    if (res != S_OK)
        bail("Could not enable video input of Blackmagic DeckLink device");

    // Start streaming
    _running = true;
    res = _deck_link_input->StartStreams();
    // No glory: release everything and throw exception
    if (res != S_OK)
    {
        _running = false;
        bail("Could not start streaming from the Blackmagic DeckLink device");
    }
}

VideoSourceBlackmagicSDK::~VideoSourceBlackmagicSDK()
{
    // Make sure streamer thread not trying to access buffer
    std::lock_guard<std::mutex> data_lock_guard(_data_lock);
    _running = false;

    // Stop streaming and disable enabled inputs
    _deck_link_input->StopStreams();
    _deck_link_input->DisableVideoInput();

    // Release DeckLink members
    release_deck_link();
}

bool VideoSourceBlackmagicSDK::get_frame_dimensions(int & width, int & height)
{
    // Make sure only this thread is accessing the cols and rows members now
    std::lock_guard<std::mutex> data_lock_guard(_data_lock);
    if (_cols <= 0 or _rows <= 0)
        return false;

    width = _cols;
    height = _rows;
    return true;
}

bool VideoSourceBlackmagicSDK::get_frame(VideoFrame & frame)
{
    if (frame.colour() != _colour)
        return false;

    // Make sure only this thread is accessing the video frame data now
    std::lock_guard<std::mutex> data_lock_guard(_data_lock);

    if (_video_buffer_length > 0 and _cols > 0 and _rows > 0)
    {
        frame.init_from_specs(_video_buffer, _video_buffer_length, _cols, _rows);
        return true;
    }
    else
        return false;
}

double VideoSourceBlackmagicSDK::get_frame_rate()
{
    return _frame_rate;
}

void VideoSourceBlackmagicSDK::set_sub_frame(int x, int y, int width, int height)
{
    // issue #147
    throw VideoSourceError("Blackmagic does not support cropping yet");
}

void VideoSourceBlackmagicSDK::get_full_frame()
{
    // nop: set_sub_frame currently not implemented
}

HRESULT STDMETHODCALLTYPE VideoSourceBlackmagicSDK::QueryInterface(REFIID iid, LPVOID * ppv)
{
    return E_NOINTERFACE;
}

ULONG STDMETHODCALLTYPE VideoSourceBlackmagicSDK::AddRef(void)
{
    __sync_add_and_fetch(&_n_ref, 1);
    return _n_ref;
}

ULONG STDMETHODCALLTYPE VideoSourceBlackmagicSDK::Release(void)
{
    __sync_sub_and_fetch(&_n_ref, 1);
    return _n_ref;
}

HRESULT STDMETHODCALLTYPE VideoSourceBlackmagicSDK::VideoInputFormatChanged(
    BMDVideoInputFormatChangedEvents events,
    IDeckLinkDisplayMode * display_mode,
    BMDDetectedVideoInputFormatFlags format_flags
)
{
    // not supported yet: see issue #149
    return S_OK;
}

HRESULT STDMETHODCALLTYPE VideoSourceBlackmagicSDK::VideoInputFrameArrived(
    IDeckLinkVideoInputFrame * video_frame,
    IDeckLinkAudioInputPacket * audio_packet
)
{
    if (not _running)
        // nop if not running!
        return S_OK;

    // Not processing the audio packet, but only the video
    // frame for the time being
    if (video_frame == nullptr)
        // nop if no data
        return S_OK;

    // Nr. of bytes of received data
    size_t n_bytes = video_frame->GetRowBytes() * video_frame->GetHeight();
    if (is_stereo())
        n_bytes *= 2;

    { // Artificial scope for data lock
        // Make sure only this thread is accessing the buffer now
        std::lock_guard<std::mutex> data_lock_guard(_data_lock);

        // Extend buffer if more memory needed than already allocated
        if (n_bytes > _video_buffer_length)
            _video_buffer = reinterpret_cast<uint8_t *>(
                        realloc(_video_buffer, n_bytes * sizeof(uint8_t))
            );
        if (_video_buffer == nullptr) // something's terribly wrong!
            // nop if something's terribly wrong!
            return S_OK;

        // Get the new data into the buffer
        HRESULT res = video_frame->GetBytes(
            reinterpret_cast<void **>(&_video_buffer)
        );
        // If data could not be read into the buffer, return
        if (FAILED(res))
            return res;

        if (is_stereo())
        {
            IDeckLinkVideoFrame *right_eye_frame = nullptr;
            IDeckLinkVideoFrame3DExtensions *three_d_extensions = nullptr;
            if ((video_frame->QueryInterface(
                    IID_IDeckLinkVideoFrame3DExtensions,
                    (void **) &three_d_extensions) != S_OK) ||
                (three_d_extensions->GetFrameForRightEye(
                    &right_eye_frame) != S_OK))
            {
                right_eye_frame = nullptr;
            }

            if (three_d_extensions != nullptr)
                three_d_extensions->Release();

            if (right_eye_frame != nullptr)
            {
                res = right_eye_frame->GetBytes(
                    reinterpret_cast<void **>(&_video_buffer[n_bytes / 2])
                );
                right_eye_frame->Release();
                // If data could not be read into the buffer, return
                if (FAILED(res))
                    return res;
            }
        }

        // Set video frame specs according to new data
        _video_buffer_length = n_bytes;
        _cols = video_frame->GetWidth();
        _rows = video_frame->GetHeight();

        // Propagate new video frame to observers
        _buffer_video_frame.init_from_specs(
            _video_buffer, _video_buffer_length, _cols, _rows
        );
    }

    this->notify(_buffer_video_frame);

    // Everything went fine, return success
    return S_OK;
}

void VideoSourceBlackmagicSDK::release_deck_link() noexcept
{
    if (_deck_link_input != nullptr)
    {
        _deck_link_input->Release();
        _deck_link_input = nullptr;
    }

    if (_deck_link != nullptr)
        _deck_link->Release();
}

bool VideoSourceBlackmagicSDK::detect_input_format(BMDPixelFormat pixel_format,
                                                   BMDVideoInputFlags & video_input_flags,
                                                   BMDDisplayMode & display_mode,
                                                   double & frame_rate,
                                                   std::string & error_msg) noexcept
{
    std::vector<BMDDisplayMode> display_modes =
    {
        bmdModeHD1080p6000, bmdModeHD1080p5994,
        bmdModeHD1080p50,
        bmdModeHD1080p30, bmdModeHD1080p2997,
        bmdModeHD1080p25, bmdModeHD1080p24, bmdModeHD1080p2398,
        bmdModeHD1080i6000, bmdModeHD1080i5994,
        bmdModeHD1080i50,
        bmdModeHD720p60, bmdModeHD720p5994,
        bmdModeHD720p50,
        bmdMode4K2160p60, bmdMode4K2160p5994,
        bmdMode4K2160p50,
        bmdMode4K2160p30, bmdMode4K2160p2997,
        bmdMode4K2160p25, bmdMode4K2160p24, bmdMode4K2160p2398,
        bmdMode2k25, bmdMode2k24, bmdMode2k2398,
    };

    DeckLinkDisplayModeDetector detector(
                _deck_link_input,
                display_modes, pixel_format, video_input_flags
    );
    BMDDisplayMode display_mode_ = detector.get_display_mode();
    if (display_mode_ != bmdModeUnknown)
    {
        frame_rate = detector.get_frame_rate();
        display_mode = display_mode_;
        video_input_flags = detector.get_video_input_flags();
        return true;
    }
    else
    {
        error_msg = detector.get_error_msg();
        return false;
    }
}

}
<|endoftext|>