r1 - 22 Jan 2006 - 18:42:55 - RaDYou are here: MLT Wiki >  MLT Web  >  Documentation > RuValerie
Copyright (C) 2004 Ushodaya Enterprised Limited 
Author: Charles Yates <charles.yates@pandora.be> 
Last Revision: 2004-03-20
Translator: Ruslan Popov <radz@yandex.ru>
Last Revision: 2006-01-22

Введение

Данный документ описывает интерфейс для работы приложений с DVCP.

Целевая аудитория

Данный документ описывает DVCP дизайн и предполагает, что читатель обладает основными знаниями о фцнкциональности, которую предоставляет ядро DVCP.

Документ предназначен для разработчиков, которые желают использовать или поддерживать API.

Терминология

API предоставляет клиентским приложениям возможность взаимодействовать с отдельным сервером miracle или полностью встраивать ядро DVCP в экземпляр клиентского приложения.

Различие между этими двумя методиками определено с помощью парсера.

Парсер может использоваться для генерации DVCP команд и для получения результатов их выполнения. Обёртка верхнего уровня для парсера предоставляется в целях упрощения его использования и отделения кода приложения от набора команд DVCP.


Определение парсера

Парсер предоставляет API нижнего уровня, который позволяет выполнять текстовые DVCP команды и получать результаты их выполнения. Команды и ответы предоставляются в виде форматированного ASCII текста.

Предоставляются два парсера - локальный и удалённый.

Локальный парсер - это физическая реализация, которая принимает команды и выполняет их.

Удалённый парсер - это сетевая абстракция, которая передает команды экземпляру miracle, которая содержит в себе локальный парсер.

Создание локального парсера

Для создания локального парсера необходимо подключить к коду заголовочный файл:

#include <miracle/miracle_local.h>
и код для инициализации парсера:
valerie_parser parser = miracle_parser_init_local( );
См. приложение A для подробностей по компиляции и сборке.

Создание удалённого парсера

Для создания удаленного парсера необходимо подключить к коду заголовочный файл:

#include <valerie/valerie_remote.h>
и код для инициализации парсера:
valerie_parser parser = valerie_parser_init_remote( "server", port );
См. приложение A для подробностей по компиляции и сборке.

Использование парсера

Несмотря на то, что парсер может быть использован напрямую для отправки команд и получения результатов их выполнения, такое низкоуровневое использование налагает на разработчика бремя обработки результатов.

Хотя такое использование парсера приложениями явно не запрещено, этому препятствуют как строение команд, так и обработка ответов, что ведёт к ненужной зависимости клиентов от ввода/вывода серверов.

Таким образом, предоставляется API более высокого уровня, этот API обеспечивает создание команд и обработку результатов их выполнения. Во второй главе приводятся подробности по этим режимам доступа.

Закрытие парсера

Разработчик должен обязательно закрывать парсер, перед тем как он выходит из области видимости. Делается это так:

valerie_parser_close( parser );

Обёртка верхнего уровня для парсера

Использование valerie API является рекомендуемым способом доступа к парсеру. Подключите заголовочный файл к вашему коду:

#include <valerie/valerie.h>
и код для создания обёртки:
valerie dv = valerie_init( parser );
Следует отметить, что в здесь может использоваться парсер любого типа (локальный или удалённый), никакой разницы в их использовании нет, хотя некоторые возвращаемые ошибки не подходят для обоих случаев.

Рекомендуется, чтобы приложения обрабатывали ошибки для обоих типов парсеров, что позволит этим приложениям свободно выбирать парсер. Также следует помнить, что valerie не является безопасным для использования в среде с несколькими потоками выполнения, т.е. не стоит использовать одну и ту же структуру в нескольких потоках. Правильным решением будет создать valerie для каждого потока:

/* valerie for the application */
valerie dv = valerie_init( parser );
/* valerie for the status handling thread. */
valerie dv_status = valerie_init( parser );
В целях упрощения, далее в главе подразумевается использование удалённого парсера.

Подключение

Пришло время подключаться:

valerie_error_code error = valerie_connect( dv );
Вызов данной функции инициализирует парсер (в случае удалённого парсера устанавливается соединение с сервером, в случае локального инициализируется состояние модулей и необходимых объектов).

Следует отметить, если используется несколько экземпляров valerie на одном парсере, то достаточно подключиться к одному из этих экземпляров.

Коды ошибок valerie

Все функции API, кроме нескольких, возвращают код ошибки.

Коды ошибок:

valerie_ok = 0,
valerie_malloc_failed,
valerie_unknown_error,
valerie_no_response,
valerie_invalid_command,
valerie_server_timeout,
valerie_missing_argument,
valerie_server_unavailable,
valerie_unit_creation_failed,
valerie_unit_unavailable,
valerie_invalid_file,
valerie_invalid_position
В большинстве случаев достаточно проверять, что был позвращён код valerie_ok.

Для получаения текстового описания ошибки можно использовать функцию:

char *valerie_error_description( valerie_error_code );

Использование обёртки верхнего уровня

Следующий пример кода предполагает, что dv проинициализирован и подключен к valerie структуре:

valerie_error_code error = valerie_unit_play( dv, 0 );
if ( error == valerie_ok )
  fprintf( stderr, "Unit 0 is now playing\n" );
else
  fprintf( stderr, "Play on unit 0 failed: %s\n",
           valerie_error_description( error ) );
Полный интерфейс valerie описан в приложении B.

Получение содержимого каталога

Для получения списка файлов или подкаталогов в указанном каталоге относительно параметра ROOT сервера, DVCP предоставляет команду CLS.

Правильное использование CLS:

CLS "/Stuff"
приведёт к результату:
201 OK
"More Stuff/"
"file0001.dv" 15552000
"file0002.dv" 15552000
_empty line_
Первая строка определяет код ошибки, вторая показывает имя каталога, остальные строки отображают два файла, которые находятся в этом каталоге.

valerie позволяет автоматически разобрать ответ сервера с помощью структур valerie_dir и соответствующих функций.

Пример использования:

valerie_dir dir = valerie_dir_init( dv, "/Stuff" );
valerie_error_code error = valerie_dir_get_error_code( dir );
if ( error == valerie_ok )
{
  if ( valerie_dir_count( dir ) > 0 )
  {
    valerie_dir_entry_t entry;
    int index = 0;
    for ( index = 0; index < valerie_dir_count( dir ); index ++ )
    {
      valerie_dir_get( dir, index, &entry );
      if ( entry.dir )
        printf( "<%s>\n", entry.name );
      else
        printf( "%30s %8d", entry.name, entry.size );
    }
  }
  else
  {
    fprintf( stderr, "Directory is empty\n" );
  }
}
else
{
  fprintf( stderr, "Directory listing failed: %s\n",
           valerie_error_description( error ) );
}
valerie_dir_close( dir );
Следует отметить, что entry.name предоставляет имя файла или каталога без префикса в виде родительского каталога. Для удобства, полный путь предоставляет entry.full, так что можно использовать:
error = valerie_unit_load( dv, 0, entry.full );
для загрузки элемента 0.

Получение списка узлов

В настоящее время данное действие не определено в miracle.

Получение списка элементов

Для получения списка определённых элементов DVCP предоставляет команду ULS.

Правильное использование CLS:

ULS
приведёт к результату:
201 OK
U0 00 sdl:360x288 1
_empty line_
Поля каждой записи в результате работы команды описывают элемент, узел, MLT потребителя и статус соответственно.

valerie позволяет автоматически разобрать ответ сервера с помощью структур valerie_units и соответствующих функций.

Пример использования:

valerie_units units = valerie_units_init( dv );
valerie_error_code error = valerie_units_get_error_code( units );
if ( error == valerie_ok )
{
  if ( valerie_units_count( units ) > 0 )
  {
    valerie_unit_entry_t entry;
    int index = 0;
    for ( index = 0; index < valerie_units_count( units ); index ++ )
    {
      valerie_units_get( units, index, &entry );
      printf( "U%d %02d %s %s\n", 
              entry.unit,
              entry.node,
              entry.guid,
              entry.online ? "online" : "offline" );
    }
  }
  else
  {
    fprintf( stderr, "Unit list is empty\n" );
  }
}
else
{
  fprintf( stderr, "Unit listing failed: %s\n",
           valerie_error_description( error ) );
}
valerie_units_close( units );

Информация о статусе элемента

Существует два метода с помощью которых клиент может получить информацию о статусе элемента.

В первом случаем можно использовать DVCP команду USTA:

USTA U0
приведёт к результату:
202 OK
0 playing "a.dv" 58 1000 25.00 0 6999 7000 "a.dv" 157 0 6999 7000 1 4 0
Перечислим поля записи:
  • Номер элемента;
  • Состояние:
    • offline - отключен;
    • not_loaded - не загружен;
    • stopped - остановлен;
    • playing - воспроизведение;
    • paused - пауза;
    • disconnected - отсоединен (когда сервер упал);
  • Имя клипа;
  • Позиция в клипе;
  • Скорость * 1000;
  • Количество кадров в секунду;
  • Начало клипа (в point);
  • Конец клипа (в point);
  • Длительность клипа (в point);
  • Упреждающее чтение (УЧ) клипа;
  • Позиция УЧ;
  • Начало УЧ;
  • Конец УЧ;
  • Длительность УЧ клипа;
  • Флаг свободного перемещения по контенту;
  • Playlist generation
  • Индекс клипа.

И снова, valerie позволяет автоматически разобрать ответ сервера с помощью структур valerie_unit_status и функции valerie_unit_status.

Пример использования:

valerie_status_t status;
valerie_error_code error = valerie_unit_status( dv, 0, &status );
if ( error == valerie_ok )
{
  switch( status.status )
  {
    case unit_offline:
      printf( "offline   " );
      break;
    case unit_undefined:
      printf( "undefined " );
      break;
    case unit_not_loaded:
      printf( "unloaded  " );
      break;
    case unit_stopped:
      printf( "stopped   " );
      break;
    case unit_playing:
      printf( "playing   " );
      break;
    default:
      printf( "unknown   " );
      break;
  }
  printf( "%06lld %06lld %06lld %s\n", status.in,
                                       status.position,
                                       status.out,
                                       status.clip );
}
else
{
  fprintf( stderr, "Unit status failed: %s\n",
           valerie_error_description( error ) );
}

Во втором случае получение статуса элементов происходит с помощью автоматического уведомления.

Для этого существует valerie_notifier API. Для получения объекта, который будет генерировать уведомления, надо использовать:

valerie_notifier notifier = valerie_get_notifier( dv );
Для получения последнего статуса элемента надо делать так:
int unit = 1;
valerie_status_t status;
valerie_notifier_get( notifier, &status, unit );
Для ожидания следующего состояния от любого элемента надо делать так:
valerie_notifier_wait( notifier, &status );
Если требуется изменить действие, которое будет выполнено при обработке статуса определённого элемент, можно использовать:
valerie_notifier_get( notifier, &status, unit );
valerie_notifier_put( notifier, &status );
Далее в примерах будут рассмотрены подробности.

Ниже приведён полный список полей в структуре статуса:

int unit;
unit_status status;
char clip[ 2048 ];
int64_t position;
int speed;
double fps;
int64_t in;
int64_t out;
int64_t length;
char tail_clip[ 2048 ];
int64_t tail_position;
int64_t tail_in;
int64_t tail_out;
int64_t tail_length;
int seekable;
int generation;
int clip_index;
Вы всегда получите запись о статусе для каждого выводимого кадра.

Информация, получаемая с помощью упреждаемого чтения, предоставляется для организации очереди на стороне клиента, которая предполагает that uset eof=pause применяется к элементу. Клиент может определить, что проигрывается подкачанный клип с помощью информации УЧ и закэшировать следующий клип. До тех пор, пока поддерживается такой режим работы, рекомендуется для новых клиентов использовать механизм организации очереди на стороне сервера, который описан в следующей главе.

API для организации очереди на стороне сервера

Эта глава описывает API, доступные для организации очереди на стороне сервера.

Смысл в том, что каждый элемент организовывает свой собственный список проигрывания, содержащий некоторое количество клипов. Со списком проигрывания связан номер поколения, который увеличивается по факту изменения списка проигрывания. Поколение текущего списка проигрывания предоставляется в записи статуса для того, чтобы клиент знал когда надо обновлять информацию о списке. Запись о статусе также определяет текущий активный клип.

Ниже приведены действия, которые можно выполнять над списком проигрывания:

  • list - список всех клипов с указанием их размеров, точек начала и завершения;
  • loading a clip - указанный клип будет загружен вместо текущего списка;
  • appending a clip - указанный клип будет добавлен в конец списка проигрывания;
  • inserting a clip - новый клип будет размещён в указанной позиции списка проигрывания;
  • moving a clip - клипы могут быть перемещены по списку проигрывания;
  • removing a clip - указанный клип удаляется из списка проигрывания;
  • clean - удаляются все клипы из списка проигрывания кроме проигрываемого в настоящее время.
Дополнительно, следующие действия предназначены только для клипов:
  • действие goto позволяет переместить текущую позицию проигрывания в позицию указанного клипа;
  • установка точек начала и завершения позволяет изменять эти точки у клипов.
Обратная совместимость обеспечивается дополнительными семействами API для клипов, которые начинаются с valerie_unit_clip_.

Они приведены в приложении B.

Ниже приведён пример получения клипов закэшированных в элементе 0:

valerie_list list = valerie_list_init( dv, 0 );
valerie_list_entry_t entry;
int index;

printf( "Generation = %d\n", list->generation );
for ( index = 0; index < valerie_list_count( list ); index ++ )
{
  valerie_list_get( list, index, &entry );
  printf( "%d %s %d %d %d %d\n", 
          entry.clip, 
          entry.full,
          entry.in,
          entry.out,
          entry.max,
          entry.size );
}
valerie_list_close( list );
Для загрузки клипа в элемент 0 надо выполнить:
valerie_unit_load( dv, 0, "/path/clip.dv" );
Для добавления клипа в элемент 0 надо выполнить:
valerie_unit_append( dv, 0, "/path/clip.dv", -1, -1 );
Следует отметить, что последние два аргумента указывают точки начала и завершения клипа, причём значение -1 определяет весь файл.

Для вставки клипа в позицию 0 в элементе 0 можно использовать следующий код:

valerie_unit_clip_insert( dv, 0, clip_absolute, 0, "/path/clip.dv", -1, -1 );
В данном вызове функции третий и четвёртый аргументы подобны для всех функций valerie_unit_clip. Они принимают форму либо [clip_absolute, n], указывая абсолютное индексирование клипа, либо [clip_relative, n], указывая индекс клипа относительно клипа, проигрываемого в настоящее время.

Таким образом, для вставки клипа сразу после клипа, проигрываемого в настоящее время, можно использовать следующий код:

valerie_unit_clip_insert( dv, 0, clip_relative, -1, "/path/clip.dv", -1, -1 );
Перемещение текущего клипа в следующую позицию в списке:
valerie_unit_clip_move( dv, 0, clip_relative, 0, clip_relative, 1 );
Удаление указанного клипа:
valerie_unit_clip_remove( dv, 0, clip_absolute, index );
Удаление всех клипов, кроме текущего:
valerie_unit_clean( dv, 0 );
Переход на первый кадр первого клипа:
valerie_unit_clip_goto( dv, 0, clip_absolute, 0, 0 );
Установка точек начала и завершения для текущего клипа:
valerie_unit_clip_set_in( dv, 0, clip_relative, 0, 0 );
valerie_unit_clip_set_out( dv, 0, clip_relative, 0, 1000 );
Более полный пример использования очереди на стороне сервера можно найти по адресу http://users.pandora.be/acp/rugen

Демонстрационный клиент поставляемый вместе с valerie используется для сохранения обратной совместимости с API для организации очереди на стороне клиента.

Прямой доступ к парсеру нижнего уровня

Парсер нижнего уровня и ассоциированные с ним структуры можно использовать напрямую из API верхнего уровня, но такое требуется очень редко.

Методы предоставляются через пару методов верхнего уровня:

valerie_error_code error = valerie_execute( dv, 1024, "USTA U%d", unit );
valerie_response response = valerie_get_last_response( dv );
int index = 0;
for ( index = 0; index < valerie_response_count( response ); index ++ )
  printf( "%d: %s\n", index, valerie_response_get_line( response,index ) );
Подробности о структуре valerie_response могут быть найдены в главе 3 данного документа.

Очистка

Перед выходом valerie и парсера из области видимости, следует выполнить:

valerie_close( dv );
valerie_parser_close( parser );
Следует отметить, что требуется закрыть все экземпляры valerie перед закрытием парсера.

Примеры

Обратитесь к исходному коду albino и humperdink. Дополнительные примеры могут быть найдены через http://www.google.ru через запросы gdv1394 и poldo.


API парсера нижнего уровня

API парсера нижнего уровня предоставляет очень простой механизм для создания команд и получения результатов их выполнения.

Как описано в главе 2, парсер создаётся как локальный, либо удалённый, и этого достаточно для создания парсера нижнего уровня.

Выполнение команды

Все команды могут выполняться так:

valerie_response response = valerie_parser_executef( parser, "CLS \"%s\"", dir );
Следует отметить, не следует использовать символы CR и LF.

Тот кто получает результат выполнения команды должен сделать следующее:

valerie_response_close( response );

Интерпретация valerie_response

Результат выполнения команды может быть получен в виде NULL, следовательно стоит выполнять:

int error = valerie_response_get_error_code( response );
В переменной error может появиться:
  • -1 - если результатом был NULL;
  • -2 - если результат ничего не содержал;
  • 0 - если первая строка результата не соответствует формату отклика DVCP;
  • код ошибки протокола DVCP из первой строки результата.

Простое использование структуры valerie_response:

valerie_response response = valerie_parser_executef( parser, "CLS \"%s\"", dir );
int error = valerie_response_get_error_code( response );
if ( error >= 0 )
{
  int index = 0;
  for ( index = 0; index < valerie_response_count( response ); index ++ )
    printf( "%3d: %s\n", index, valerie_response_get_line( response, index ) );
}
else
{
  /* interpret error */
}
valerie_response_close( response );
Следует отметить, что надо вызывать функцию valerie_response_close независимо от кода ошибки.

Статус доступа к элементу

Как и в случае с парсером верхнего уровня, существует два способа получения информации о статусе элемента - через DVCP команду USTA или через valerie1394_notifier.

Последний способ рекомендуется для приложений, которым требуется получить информацию о статусе без дупликации процесса обработки в указанном клиенте.

Делается это так:

valerie_notifier notifier = valerie_parser_get_notifier( parser );
Использование механизма уведомлений с парсером нижнего уровня аналогично описанному во главе 2. Для получения последнего состояния элемента, следует делать так:
int unit = 1;
valerie_status_t status;
valerie_notifier_get( notifier, &status, unit );
Для ожидания следующего состояния любого элемента можно использовать следующий код:
valerie_notifier_wait( notifier, &status );

Приложение А - Компиляция и сборка

Флаги компиляции:

-I <prefix>/include
где prefix по умолчанию равен /usr/local.

Флаги сборки для клиента:

-L <prefix>/lib/ -lvalerie
Флаги сборки для локального парсера:
-L <prefix>/lib/ -lmiracle
Запомните, вам никогда не понадобятся обе библиотеки.

Приложение B - Полный список функций API парсера верхнего уровня

valerie valerie_init( valerie_parser );

valerie_error_code valerie_connect( valerie );

valerie_error_code valerie_set( valerie, char *, char * );
valerie_error_code valerie_get( valerie, char *, char *, int );

valerie_error_code valerie_unit_add( valerie, char * );
valerie_error_code valerie_unit_load( valerie, int, char * );
valerie_error_code valerie_unit_load_clipped( valerie,int,char *,long,long );
valerie_error_code valerie_unit_load_back( valerie, int, char * );
valerie_error_code valerie_unit_load_back_clipped(valerie,int,char *,long,long)
valerie_error_code valerie_unit_play( valerie, int );
valerie_error_code valerie_unit_play_at_speed( valerie, int, int );
valerie_error_code valerie_unit_stop( valerie, int );
valerie_error_code valerie_unit_pause( valerie, int );
valerie_error_code valerie_unit_rewind( valerie, int );
valerie_error_code valerie_unit_fast_forward( valerie, int );
valerie_error_code valerie_unit_step( valerie, int, int );
valerie_error_code valerie_unit_goto( valerie, int, int );
valerie_error_code valerie_unit_set_in( valerie, int, int );
valerie_error_code valerie_unit_set_out( valerie, int, int );
valerie_error_code valerie_unit_clear_in( valerie, int );
valerie_error_code valerie_unit_clear_out( valerie, int );
valerie_error_code valerie_unit_clear_in_out( valerie, int );
valerie_error_code valerie_unit_set( valerie, int, char *, char * );
valerie_error_code valerie_unit_get( valerie, int, char * );

valerie_error_code valerie_unit_status( valerie, int, valerie_status );
valerie_notifier valerie_get_notifier( valerie );

valerie_dir valerie_dir_init( valerie, char * );
valerie_error_code valerie_dir_get( valerie_dir, int, valerie_dir_entry );
int valerie_dir_count( valerie_dir );
void valerie_dir_close( valerie_dir );

valerie_nodes valerie_nodes_init( valerie );
valerie_error_code valerie_nodes_get(valerie_nodes,int,valerie_node_entry);
int valerie_nodes_count( valerie_nodes );
void valerie_nodes_close( valerie_nodes );

valerie_units valerie_units_init( valerie );
valerie_error_code valerie_units_get(valerie_units,int,valerie_unit_entry);
int valerie_units_count( valerie_units );
void valerie_units_close( valerie_units );

valerie_response valerie_get_last_response( valerie );

valerie_error_code valerie_execute( valerie, size_t, char *, ... );

void valerie_close( valerie );

Функции механизма уведомлений

void valerie_notifier_get( valerie_notifier, valerie_status, int );
void valerie_notifier_put( valerie_notifier, valerie_status );
int valerie_notifier_wait( valerie_notifier, valerie_status );
void valerie_notifier_close( valerie_notifier );

Функции очереди на стороне сервера

valerie_list valerie_list_init( valerie, int )
valerie_error_code valerie_list_get_error_code( valerie_list )
valerie_error_code valerie_list_get( valerie_list, int, valerie_list_entry )
int valerie_list_count( valerie_list )
void valerie_list_close( valerie_list )

valerie_error_code valerie_unit_clean( valerie dv, int unit )
valerie_error_code valerie_unit_append( valerie dv, int unit, char *file, int in, int out )
valerie_error_code valerie_unit_remove_current_clip( valerie dv, int unit )

valerie_error_code valerie_unit_clip_goto( valerie dv, int unit, valerie_clip_offset offset, int clip, int position )
valerie_error_code valerie_unit_clip_set_in( valerie dv, int unit, valerie_clip_offset offset, int clip, int in )
valerie_error_code valerie_unit_clip_set_out( valerie dv, int unit, valerie_clip_offset offset, int clip, int in )
valerie_error_code valerie_unit_clip_move( valerie dv, int unit, valerie_clip_offset offset, int src, valerie_clip_offset offset, int dest )
valerie_error_code valerie_unit_clip_remove( valerie dv, int unit, valerie_clip_offset offset, int clip )
valerie_error_code valerie_unit_clip_insert( valerie dv, int unit, valerie_clip_offset offset, int clip, char *file, int in, int out )

Приложение C - Полный список функций API парсера нижнего уровня

valerie_response valerie_parser_connect( valerie_parser );
valerie_response valerie_parser_execute( valerie_parser, char * );
valerie_response valerie_parser_executef( valerie_parser, char *, ... );
valerie_response valerie_parser_run( valerie_parser, char * );
valerie_notifier valerie_parser_get_notifier( valerie_parser );
void valerie_parser_close( valerie_parser );

valerie_response valerie_response_init( );
valerie_response valerie_response_clone( valerie_response );
int valerie_response_get_error_code( valerie_response );
char *valerie_response_get_error_string( valerie_response );
char *valerie_response_get_line( valerie_response, int );
int valerie_response_count( valerie_response );
void valerie_response_set_error( valerie_response, int, char * );
int valerie_response_printf( valerie_response, size_t, char *, ... );
int valerie_response_write( valerie_response, char *, int );
void valerie_response_close( valerie_response );

Приложение D - Ссылки

(1) doc/dvcp.txt - Протокол =DVCP. (2) doc/testing.txt - Тестовые процедуры.

-- RaD - 22 Jan 2006

Edit | WYSIWYG | Attach | Printable | Raw View | Backlinks: Web, All Webs | History: r1 | More topic actions
 
MLT Wiki
This site is powered by the TWiki collaboration platformCopyright © by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding MLT Wiki? Send feedback