Я пишу интерфейс между Python и нашей библиотекой C ++ для обработки видео, используя SWIG. В Python я использую класс Fraction для представления частоты кадров (например, NTFS24 = 24000/1001 FPS). Рассматриваемая функциональность - это транскодирование видео, то есть ввод видео (или потока кадров) и создание аналогичного вывода. Для этого нам нужно указать выходную (а иногда и входную) частоту кадров.

Есть ли способ, которым я могу взаимодействовать с классом Fraction на стороне C ++ (SWIG)? Из того, что я нашел в Интернете, я должен быть в состоянии передать tuple параметру std::pair<int,int>, так что это мой запасной план, но есть ли лучший способ? Благодарность!

0
BIOStheZerg 29 Окт 2019 в 14:39

1 ответ

Лучший ответ

Я собрал следующий файл интерфейса, чтобы проиллюстрировать, как может работать упаковка Fraction. В конце концов я решил создать свою собственную структуру фракций для хранения фракций на стороне C ++, прежде всего потому, что она менее двусмысленна, чем использование std::pair<int, int>. (Я полагал, что пара целых чисел также может быть двухмерной координатой, или разрешением экрана, или многими другими типами, и более строгая типизация лучше для разрешения перегрузки и т. Д.)

%module test

%{
#include <iostream> // Just for testing....

static PyObject *fractions_module = NULL;
%}

%init %{
  // Import the module we want
  fractions_module = PyImport_ImportModule("fractions");
  assert(fractions_module);
  // TODO: we should call Py_DECREF(fractions_module) when our module gets unloaded
%}

%typemap(in) const Fraction& (Fraction tmp) {
  // Input typemap for fraction: duck-type on attrs numerator, denominator
  PyObject *numerator = PyObject_GetAttrString($input, "numerator");
  PyObject *denominator = PyObject_GetAttrString($input, "denominator");

  int err = SWIG_AsVal_int(numerator, &tmp.numerator);
  assert(SWIG_IsOK(err)); // TODO: proper error handling
  err = SWIG_AsVal_int(denominator, &tmp.denominator);
  assert(SWIG_IsOK(err)); // TODO: errors...

  Py_DECREF(numerator);
  Py_DECREF(denominator);

  $1 = &tmp;  
}

%typemap(out) Fraction {
  // Output typemap: pass two ints into fractions.Fraction() ctor
  $result = PyObject_CallMethod(fractions_module, "Fraction", "ii", $1.numerator, $1.denominator);
}

%inline %{
  struct Fraction {
    int numerator, denominator;
  };

  void fraction_in(const Fraction& fraction) {
    std::cout << fraction.numerator << "/" << fraction.denominator << "\n";
  }

  Fraction fraction_out() {
    Fraction f = {100, 1};
    return f;
  }
%}

В основном это всего два набора типов - одна для входов в функции C ++ и одна для выходов. Они создают временную фракцию C ++ из атрибутов числителя и знаменателя входного объекта и создают объект Python fractions.Fraction из нашего объекта C ++ соответственно. Адаптировать их для других подобных дробных типов должно быть довольно просто.

1
Flexo 29 Окт 2019 в 20:00