X-Git-Url: http://research.m1stereo.tv/gitweb?a=blobdiff_plain;f=docs%2Flibmvcp.txt;fp=docs%2Flibmvcp.txt;h=9a90c867f2eeccaec5b27618f93fc0a8f7c63ad1;hb=27f0329aa8f434794f1f18e018fc3221e58b77a4;hp=0000000000000000000000000000000000000000;hpb=f5a43889f0ea29962f2d32b5dab0fcd25bebb945;p=melted diff --git a/docs/libmvcp.txt b/docs/libmvcp.txt new file mode 100644 index 0000000..9a90c86 --- /dev/null +++ b/docs/libmvcp.txt @@ -0,0 +1,861 @@ +Valerie API Documentation + +Copyright (C) 2004 Ushodaya Enterprised Limited +Author: Charles Yates +Last Revision: 2004-03-20 + + +TABLE OF CONTENTS +----------------- + + 0. Overview + 0.1. Intended Audience + 0.2. Terminology + 1. Definition of a Parser + 1.1. Construction of a Local Parser + 1.2. Construction of a Remote Parser + 1.3. Using the Parser + 1.4. Closing the Parser + 2. The High Level Parser Wrapper + 2.1. Connecting + 2.2. valerie_error_code + 2.3. Using the High Level Wrapper + 2.4. Obtaining Directory Contents + 2.5. Obtaining the Node List + 2.6. Obtaining the Unit List + 2.7. Unit Status Information + 2.8. Server Side Queuing APIs + 2.9. Accessing the Low Level Parser Directly + 2.10. Cleaning up + 2.11. Examples + 3. The Low Level Parser API + 3.1. Executing a Command + 3.2. Interpreting valerie_response + 3.3. Accessing Unit Status + APPENDIX A - COMPILATION AND LINKING + APPENDIX B - COMPLETE HIGH LEVEL PARSER WRAPPER API LISTING + APPENDIX C - COMPLETE LOW LEVEL PARSER API LISTING + APPENDIX D - REFERENCES + + +0. Overview +----------- + + This document details how applications interface to DVCP functionality. + + +0.1. Intended Audience +---------------------- + + This document draws heavily upon the DVCP design (1) and assumes a basic + knowledge of the functionality provided by the DVCP core. + + It is aimed at developers who wish to use or maintain the API. + + +0.2. Terminology +---------------- + + The API is designed to allow client applications the ability to communicate + to a standalone miracle server or entirely embed the DVCP core in an + instance of a client application. + + The distinction between the two is defined by the construction of the + 'parser'. + + This 'parser' can be used to issue DVCP commands and receive responses and + a 'high level parser wrapper' is provided to simplify the usage and + decouple the application from the DVCP command set. + + +1. Definition of a Parser +------------------------- + + The parser provides a low level API which allows text DVCP commands to be + executed with responses being returned to the caller. Commands and + responses are ASCII formatted text. + + Two parsers are provided - local and remote. + + The local parser is the physical implementation which takes commands and + executes them. + + The remote parser is a network abstraction that forwards commands to a + miracle instance that hosts a local parser. + + +1.1. Construction of a Local Parser +----------------------------------- + + To construct a local parser you must have: + + #include + + and code to initialise the parser is as follows: + + valerie_parser parser = miracle_parser_init_local( ); + + See Appendix A for compilation and linking details. + + +1.2. Construction of a Remote Parser +------------------------------------ + + To construct a remote parser you must have: + + #include + + and code to initialise the parser is as follows: + + valerie_parser parser = valerie_parser_init_remote( "server", port ); + + See Appendix A for compilation and linking details. + + +1.3. Using the Parser +--------------------- + + Although the parser can be used directly to send commands and receive + responses, this low level usage puts the onus on the developer to parse the + responses in a meaningful way. + + Although this usage is not strictly forbidden by applications, it is + discouraged as construction of commands and meaningful parsing of responses + leads to the clients being unnecessarily dependent on the servers input and + output. + + As a result, a higher level Parser Wrapper API is provided - this API + encapsulates the command construction and response parsing. + + The following 2 sections provide details on these modes of access. + + +1.4. Closing the Parser +----------------------- + + Regardless of use, it is the constructors responsibility to close the + parser before it goes out of scope. This is done via: + + valerie_parser_close( parser ); + + +2. The High Level Parser Wrapper +-------------------------------- + + The recommended way to access the parser, is via the valerie API. To use + this API, you must have: + + #include + + and code to construct the wrapper is: + + valerie dv = valerie_init( parser ); + + Note that either remote or local parsers can be used here and there is no + difference in usage, though some error returns will not be applicable to + both. + + It is recommended that applications honour and deal with the error returns + of both as this allows applications to interchange parsers. + + Also note that valerie is not threadsafe, so you should not use the same + structure in multiple threads. The correct solution to this is to create a + valerie per thread - you may safely use the same parser for each thread ie: + + /* valerie for the application */ + valerie dv = valerie_init( parser ); + /* valerie for the status handling thread. */ + valerie dv_status = valerie_init( parser ); + + For the purposes of simplification, the remainder of this section assumes + that a remote parser is in use. + + +2.1. Connecting +--------------- + + Once constructed, the next thing to do is 'connect': + + valerie_error_code error = valerie_connect( dv ); + + This function call initialises the parser (ie: if it's remote, it + establishes a connection to the server, or if it's local, it initialises + the state of the units and supporting objects). + + Note that if you have multiple valerie instances on the same parser you + should only connect one of the instances. + + +2.2. valerie_error_code +---------------------- + + All but a couple of the functions that make up the valerie API return a + valerie_error_code. + + These are defined as follows: + + 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 + + In most cases, it is sufficient to check on a return of valerie_ok. + + To obtain a textual description of a particular error, you can use: + + char *valerie_error_description( valerie_error_code ); + + +2.3. Using the High Level Wrapper +--------------------------------- + + The following code snippet assumes that dv is an initialised and connected + valerie structure: + + 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 ) ); + + The complete interface to valerie is listed in Appendix B of this document. + + +2.4. Obtaining Directory Contents +-------------------------------- + + To obtain a list of files and subdirectories in a given directory relative + to the ROOT property of the server, DVCP provides the CLS command. + + A valid execution of CLS would be something like: + + CLS "/Stuff" + + would provide a response formatted as follows: + + 201 OK + "More Stuff/" + "file0001.dv" 15552000 + "file0002.dv" 15552000 + + with a trailing empty line. + + The first line indicates the error value, the second line shows an example + of a subdirectory and the 3rd and 4th line lists two files that happen to + exist in the directory. + + valerie provides a high level view on this which automatically parses the + response from the server correctly via the valerie_dir structures and + related functions. + + An example of use is as follows: + + 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 ); + + Note that entry.name provides the name of the file or directory without the + directory prefix. As a convenience, entry.full provides the prefixed name, + so you could subsequently use: + + error = valerie_unit_load( dv, 0, entry.full ); + + to load unit 0 with an entry. + + +2.5. Obtaining the Node List +---------------------------- + + Currently not defined by miracle. + +2.6. Obtaining the Unit List +---------------------------- + + To obtain a list of defined units, DVCP provides the ULS command. + + A valid execution of ULS would be: + + ULS + + and would provide a response formatted as follows: + + 201 OK + U0 00 sdl:360x288 1 + + with a trailing empty line. + + The fields of each record in the response dictate unit, node, mlt consumer and + online status respectively. + + valerie provides a high level view on this which automatically parses the + response from the server correctly via the valerie_units structures and + related functions. + + An example of use is as follows: + + 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 ); + + +2.7. Unit Status Information +---------------------------- + + There are two methods for a client to obtain unit status information. + + The first is via the DVCP USTA command, which would normally be accessed + via: + + USTA U0 + + and would provide a response formated as follows: + + 202 OK + 0 playing "a.dv" 58 1000 25.00 0 6999 7000 "a.dv" 157 0 6999 7000 1 4 0 + + with no trailing empty line. + + The entries in the record are: + + * Unit + * State (undefined, offline, not_loaded, stopped, playing, + paused, disconnected [when server dies]) + * Name of Clip + * Position in clip + * Speed * 1000 + * Frames per second + * Start of clip (in point) + * End of clip (out point) + * Length of clip + * Read ahead clip + * Read ahead position + * Read ahead clip in + * Read ahead clip out + * Read ahead clip length + * Seekable flag + * Playlist generation + * Clip index + + Again, valerie provides a high level means for obtaining this via the + valerie_unit_status function and valerie_status structures: + + 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 ) ); + } + + The second approach for obtaining a units status is via automatic + notification. + + This is done via the valerie_notifier API. To obtain the notifier from the + high level API, you can use: + + valerie_notifier notifier = valerie_get_notifier( dv ); + + To obtain the last status associated to a unit, you can use: + + int unit = 1; + valerie_status_t status; + valerie_notifier_get( notifier, &status, unit ); + + To wait for the next status from any unit, you can use: + + valerie_notifier_wait( notifier, &status ); + + If you wish to trigger the action associated to your applications wait + handling of a particular unit, you can use: + + valerie_notifier_get( notifier, &status, unit ); + valerie_notifier_put( notifier, &status ); + + See Examples below for details on this. + + The complete list of fields in the status structure are: + + 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; + + You will always receive a status record for every frame output. + + The read ahead information is provided for client side queuing. Client side + queuing assumes that uset eof=pause is applied to the unit. A client can + detect when the previously scheduled clip is played out by using the read + ahead information and schedule the next clip. While this mode of operation + is still supported, it is recommended that new clients use the server side + queuing mechanism which is described in the following section. + + +2.8. Server Side Queueing APIs +------------------------------ + + This section describes the APIs available to provide server side queueing. + + The concept is that each unit maintains its own playlist, containing multiple + clips. Associated to the playlist is a generation number which is incremented + on each modification to the playlist. The current playlist generation is + provided in the status record in order for a client to know when to refresh + its presentation of the list. The status record also indicates which clip is + currently active. + + Actions that can be carried out on the playlist are summarised as: + + * list - list all the clips and associated in/out points and size + * loading a clip - a load will wipe the current list and replace it with the + specified clip + * appending a clip - append will always place the specified clip at the end + of the playlist + * inserting a clip - insert will place a new clip at the specified position + in the playlist + * moving a clip - move will allow clips can be moved in the playlist + * removing a clip - remove will remove the specified clip from the playlist + * clean - clean will remove all but the playing clip from the playlist + + Additionally, the following existing actions are clip aware: + + * goto allows you to move the current play position to a specific clip position + * set in/out points allows you to modify clip in and out points + + Backward compatability has been maintained by the addition of a clip-aware + family of APIs which have the naming convention of valerie_unit_clip_*. + + These are listed in Appendix B. + + The following shows an example of obtaining the clips queued on unit 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 ); + + To load a clip on unit 0: + + valerie_unit_load( dv, 0, "/path/clip.dv" ); + + To append a clip on unit 0: + + valerie_unit_append( dv, 0, "/path/clip.dv", -1, -1 ); + + Note that the last two arguments specify the in and out points of the clip + with -1 denoting dfaults of the entirety of the file. + + To insert a clip at position 0 on unit 0, we can use the following: + + valerie_unit_clip_insert( dv, 0, clip_absolute, 0, "/path/clip.dv", -1, -1 ); + + The 3rd and 4th arguments here are common to all the valerie_unit_clip functions. + They take the form of either [clip_absolute, n] to indicate an absolute clip + index, or [clip_relative, n] to indicate a clip index relative to the + currently playing clip. + + So, to insert a clip immediately before the currently playing clip, we can + use: + + valerie_unit_clip_insert( dv, 0, clip_relative, -1, "/path/clip.dv", -1, -1 ); + + To move the current clip to the next position in the list: + + valerie_unit_clip_move( dv, 0, clip_relative, 0, clip_relative, 1 ); + + To remove a specific clip: + + valerie_unit_clip_remove( dv, 0, clip_absolute, index ); + + To remove all but the currently playing clip: + + valerie_unit_clean( dv, 0 ); + + To goto the first frame in the first clip, you can use: + + valerie_unit_clip_goto( dv, 0, clip_absolute, 0, 0 ); + + To set the in and out points on the current clip: + + valerie_unit_clip_set_in( dv, 0, clip_relative, 0, 0 ); + valerie_unit_clip_set_out( dv, 0, clip_relative, 0, 1000 ); + + A more complete example of use of the server side can queuing can be found + at: + + http://users.pandora.be/acp/rugen + + The demo client provided with valerie is used for retaining backward + compatability with the client side queuing API. + + +2.9. Accessing the Low Level Parser Directly +-------------------------------------------- + + The low level parser and its associated structures can be accessed directly + from the high level API, but is very occasionally actually needed. + + The methods are provided via a pair of high level methods: + + 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 ) ); + + More details on the valerie_response structure can be found in section 3 of this + document. + + +2.10. Cleaning up +----------------- + + Before the valerie and parser go out of scope, you need to run: + + valerie_close( dv ); + valerie_parser_close( parser ); + + Note that you should close all valerie instances before closing the parser. + + +2.11. Examples +-------------- + + Please refer to albino and humperdink source for examples provided with + the project. Additional examples can be found via google with gdv1394 and + poldo. + + +3. The Low Level Parser API +--------------------------- + + The low level parser API provides a very simple mechanism for constructing + commands and receiving responses. + + As described in section 2, a parser is constructed as local or remote and + this is sufficient for constructing the low level parser. + + +3.1. Executing a Command +------------------------ + + All commands can be executed via the single variable argument function + valerie_parser_executef and this function returns a valerie_response, ie: + + valerie_response response = valerie_parser_executef( parser, "CLS \"%s\"", dir ); + + Note that no carriage return/line feed is required (adding this is + erroneous). + + It is the receiver of the response who is responsible for closing it. + + valerie_response_close( response ); + + +3.2. Interpreting valerie_response +----------------------------- + + The response received can be NULL, but it is safe to call: + + int error = valerie_response_get_error_code( response ); + + which will return: + + * -1 if response is NULL, + * -2 if there is no content to the response, + * 0 if the responses first line does not correspond to a valid DVCP response + * or the DVCP protocol error code returned on the first line of the response + + A simple use of a valerie_response structure is as follows: + + 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 ); + + Note that it is safe to call valerie_response_close regardless of the error + condition indicated. + + +3.3. Accessing Unit Status +-------------------------- + + As with the high level parser, there are two alternatives to obtain unit + status information - either via the USTA DVCP command or via the + valerie1394_notifier. + + The latter is the recommended way for any applications which wish to extract + meaningful information from the status while avoiding the requirement to + duplicate the parsing process in a specific client. + + The notifier can be obtained by: + + valerie_notifier notifier = valerie_parser_get_notifier( parser ); + + The use of the notifier with the low level parser is identical to that + dictated in Section 2 - to obtain the last status associated to a unit, + you can use: + + int unit = 1; + valerie_status_t status; + valerie_notifier_get( notifier, &status, unit ); + + To wait for the next status from any unit, you can use: + + valerie_notifier_wait( notifier, &status ); + + +APPENDIX A - COMPILATION AND LINKING +------------------------------------ + + Compilation flags are: + + -I /include + + where prefix defaults to /usr/local. + + Linking flags for a client are: + + -L /lib/ -lvalerie + + Or for a local parser: + + -L /lib/ -lmiracle + + Note that you never need both libs. + + +APPENDIX B - COMPLETE HIGH LEVEL PARSER WRAPPER API LISTING +----------------------------------------------------------- + + 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 ); + + Notifier Functions + ------------------ + + 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 ); + + Server Side Queuing + ------------------- + + 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 ) + + + +APPENDIX C - COMPLETE LOW LEVEL PARSER API LISTING +-------------------------------------------------- + + 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 ); + + +APPENDIX D - REFERENCES +----------------------- + + (1) doc/dvcp.txt - DVCP protocol + (2) doc/testing.txt - Test procedures