1 MLT libmvcp API Documentation
3 Copyright (C) 2004-2009 Ushodaya Enterprised Limited
4 Author: Charles Yates <charles.yates@pandora.be>
5 Last Revision: 2009-05-15
12 0.1. Intended Audience
14 1. Definition of a Parser
15 1.1. Construction of a Local Parser
16 1.2. Construction of a Remote Parser
18 1.4. Closing the Parser
19 2. The High Level Parser Wrapper
22 2.3. Using the High Level Wrapper
23 2.4. Obtaining Directory Contents
24 2.5. Obtaining the Node List
25 2.6. Obtaining the Unit List
26 2.7. Unit Status Information
27 2.8. Server Side Queuing APIs
28 2.9. Accessing the Low Level Parser Directly
31 3. The Low Level Parser API
32 3.1. Executing a Command
33 3.2. Interpreting mvcp_response
34 3.3. Accessing Unit Status
35 APPENDIX A - COMPILATION AND LINKING
36 APPENDIX B - COMPLETE HIGH LEVEL PARSER WRAPPER API LISTING
37 APPENDIX C - COMPLETE LOW LEVEL PARSER API LISTING
38 APPENDIX D - REFERENCES
44 This document details how applications interface to MVCP functionality.
47 0.1. Intended Audience
48 ----------------------
50 This document draws heavily upon the MVCP design (1) and assumes a basic
51 knowledge of the functionality provided by the MVCP core.
53 It is aimed at developers who wish to use or maintain the API.
59 The API is designed to allow client applications the ability to communicate
60 to a standalone melted server or entirely embed the MVCP core in an
61 instance of a client application.
63 The distinction between the two is defined by the construction of the
66 This 'parser' can be used to issue MVCP commands and receive responses and
67 a 'high level parser wrapper' is provided to simplify the usage and
68 decouple the application from the MVCP command set.
71 1. Definition of a Parser
72 -------------------------
74 The parser provides a low level API which allows text MVCP commands to be
75 executed with responses being returned to the caller. Commands and
76 responses are ASCII formatted text.
78 Two parsers are provided - local and remote.
80 The local parser is the physical implementation which takes commands and
83 The remote parser is a network abstraction that forwards commands to a
84 melted instance that hosts a local parser.
87 1.1. Construction of a Local Parser
88 -----------------------------------
90 To construct a local parser you must have:
92 #include <melted/melted_local.h>
94 and code to initialise the parser is as follows:
96 mvcp_parser parser = melted_parser_init_local( );
98 See Appendix A for compilation and linking details.
101 1.2. Construction of a Remote Parser
102 ------------------------------------
104 To construct a remote parser you must have:
106 #include <mvcp/mvcp_remote.h>
108 and code to initialise the parser is as follows:
110 mvcp_parser parser = mvcp_parser_init_remote( "server", port );
112 See Appendix A for compilation and linking details.
115 1.3. Using the Parser
116 ---------------------
118 Although the parser can be used directly to send commands and receive
119 responses, this low level usage puts the onus on the developer to parse the
120 responses in a meaningful way.
122 Although this usage is not strictly forbidden by applications, it is
123 discouraged as construction of commands and meaningful parsing of responses
124 leads to the clients being unnecessarily dependent on the servers input and
127 As a result, a higher level Parser Wrapper API is provided - this API
128 encapsulates the command construction and response parsing.
130 The following 2 sections provide details on these modes of access.
133 1.4. Closing the Parser
134 -----------------------
136 Regardless of use, it is the constructors responsibility to close the
137 parser before it goes out of scope. This is done via:
139 mvcp_parser_close( parser );
142 2. The High Level Parser Wrapper
143 --------------------------------
145 The recommended way to access the parser, is via the mvcp API. To use
146 this API, you must have:
148 #include <mvcp/mvcp.h>
150 and code to construct the wrapper is:
152 mvcp client = mvcp_init( parser );
154 Note that either remote or local parsers can be used here and there is no
155 difference in usage, though some error returns will not be applicable to
158 It is recommended that applications honour and deal with the error returns
159 of both as this allows applications to interchange parsers.
161 Also note that mvcp is not threadsafe, so you should not use the same
162 structure in multiple threads. The correct solution to this is to create a
163 mvcp per thread - you may safely use the same parser for each thread ie:
165 /* mvcp for the application */
166 mvcp client = mvcp_init( parser );
167 /* mvcp for the status handling thread. */
168 mvcp client_status = mvcp_init( parser );
170 For the purposes of simplification, the remainder of this section assumes
171 that a remote parser is in use.
177 Once constructed, the next thing to do is 'connect':
179 mvcp_error_code error = mvcp_connect( client );
181 This function call initialises the parser (ie: if it's remote, it
182 establishes a connection to the server, or if it's local, it initialises
183 the state of the units and supporting objects).
185 Note that if you have multiple mvcp instances on the same parser you
186 should only connect one of the instances.
190 ----------------------
192 All but a couple of the functions that make up the mvcp API return a
195 These are defined as follows:
201 mvcp_invalid_command,
203 mvcp_missing_argument,
204 mvcp_server_unavailable,
205 mvcp_unit_creation_failed,
206 mvcp_unit_unavailable,
208 mvcp_invalid_position
210 In most cases, it is sufficient to check on a return of mvcp_ok.
212 To obtain a textual description of a particular error, you can use:
214 char *mvcp_error_description( mvcp_error_code );
217 2.3. Using the High Level Wrapper
218 ---------------------------------
220 The following code snippet assumes that client is an initialised and connected
223 mvcp_error_code error = mvcp_unit_play( client, 0 );
224 if ( error == mvcp_ok )
225 fprintf( stderr, "Unit 0 is now playing\n" );
227 fprintf( stderr, "Play on unit 0 failed: %s\n",
228 mvcp_error_description( error ) );
230 The complete interface to mvcp is listed in Appendix B of this document.
233 2.4. Obtaining Directory Contents
234 --------------------------------
236 To obtain a list of files and subdirectories in a given directory relative
237 to the ROOT property of the server, MVCP provides the CLS command.
239 A valid execution of CLS would be something like:
243 would provide a response formatted as follows:
247 "file0001.dv" 15552000
248 "file0002.dv" 15552000
250 with a trailing empty line.
252 The first line indicates the error value, the second line shows an example
253 of a subdirectory and the 3rd and 4th line lists two files that happen to
254 exist in the directory.
256 mvcp provides a high level view on this which automatically parses the
257 response from the server correctly via the mvcp_dir structures and
260 An example of use is as follows:
262 mvcp_dir dir = mvcp_dir_init( client, "/Stuff" );
263 mvcp_error_code error = mvcp_dir_get_error_code( dir );
264 if ( error == mvcp_ok )
266 if ( mvcp_dir_count( dir ) > 0 )
268 mvcp_dir_entry_t entry;
270 for ( index = 0; index < mvcp_dir_count( dir ); index ++ )
272 mvcp_dir_get( dir, index, &entry );
274 printf( "<%s>\n", entry.name );
276 printf( "%30s %8d", entry.name, entry.size );
281 fprintf( stderr, "Directory is empty\n" );
286 fprintf( stderr, "Directory listing failed: %s\n",
287 mvcp_error_description( error ) );
289 mvcp_dir_close( dir );
291 Note that entry.name provides the name of the file or directory without the
292 directory prefix. As a convenience, entry.full provides the prefixed name,
293 so you could subsequently use:
295 error = mvcp_unit_load( client, 0, entry.full );
297 to load unit 0 with an entry.
300 2.5. Obtaining the Node List
301 ----------------------------
303 Currently not defined by melted.
305 2.6. Obtaining the Unit List
306 ----------------------------
308 To obtain a list of defined units, MVCP provides the ULS command.
310 A valid execution of ULS would be:
314 and would provide a response formatted as follows:
319 with a trailing empty line.
321 The fields of each record in the response dictate unit, node, mlt consumer and
322 online status respectively.
324 mvcp provides a high level view on this which automatically parses the
325 response from the server correctly via the mvcp_units structures and
328 An example of use is as follows:
330 mvcp_units units = mvcp_units_init( client );
331 mvcp_error_code error = mvcp_units_get_error_code( units );
332 if ( error == mvcp_ok )
334 if ( mvcp_units_count( units ) > 0 )
336 mvcp_unit_entry_t entry;
338 for ( index = 0; index < mvcp_units_count( units ); index ++ )
340 mvcp_units_get( units, index, &entry );
341 printf( "U%d %02d %s %s\n",
345 entry.online ? "online" : "offline" );
350 fprintf( stderr, "Unit list is empty\n" );
355 fprintf( stderr, "Unit listing failed: %s\n",
356 mvcp_error_description( error ) );
358 mvcp_units_close( units );
361 2.7. Unit Status Information
362 ----------------------------
364 There are two methods for a client to obtain unit status information.
366 The first is via the MVCP USTA command, which would normally be accessed
371 and would provide a response formated as follows:
374 0 playing "a.dv" 58 1000 25.00 0 6999 7000 "a.dv" 157 0 6999 7000 1 4 0
376 with no trailing empty line.
378 The entries in the record are:
381 * State (undefined, offline, not_loaded, stopped, playing,
382 paused, disconnected [when server dies])
387 * Start of clip (in point)
388 * End of clip (out point)
391 * Read ahead position
393 * Read ahead clip out
394 * Read ahead clip length
396 * Playlist generation
399 Again, mvcp provides a high level means for obtaining this via the
400 mvcp_unit_status function and mvcp_status structures:
402 mvcp_status_t status;
403 mvcp_error_code error = mvcp_unit_status( client, 0, &status );
404 if ( error == mvcp_ok )
406 switch( status.status )
409 printf( "offline " );
412 printf( "undefined " );
414 case unit_not_loaded:
415 printf( "unloaded " );
418 printf( "stopped " );
421 printf( "playing " );
424 printf( "unknown " );
428 printf( "%06lld %06lld %06lld %s\n", status.in,
435 fprintf( stderr, "Unit status failed: %s\n",
436 mvcp_error_description( error ) );
439 The second approach for obtaining a units status is via automatic
442 This is done via the mvcp_notifier API. To obtain the notifier from the
443 high level API, you can use:
445 mvcp_notifier notifier = mvcp_get_notifier( client );
447 To obtain the last status associated to a unit, you can use:
450 mvcp_status_t status;
451 mvcp_notifier_get( notifier, &status, unit );
453 To wait for the next status from any unit, you can use:
455 mvcp_notifier_wait( notifier, &status );
457 If you wish to trigger the action associated to your applications wait
458 handling of a particular unit, you can use:
460 mvcp_notifier_get( notifier, &status, unit );
461 mvcp_notifier_put( notifier, &status );
463 See Examples below for details on this.
465 The complete list of fields in the status structure are:
476 char tail_clip[ 2048 ];
477 int64_t tail_position;
485 You will always receive a status record for every frame output.
487 The read ahead information is provided for client side queuing. Client side
488 queuing assumes that uset eof=pause is applied to the unit. A client can
489 detect when the previously scheduled clip is played out by using the read
490 ahead information and schedule the next clip. While this mode of operation
491 is still supported, it is recommended that new clients use the server side
492 queuing mechanism which is described in the following section.
495 2.8. Server Side Queueing APIs
496 ------------------------------
498 This section describes the APIs available to provide server side queueing.
500 The concept is that each unit maintains its own playlist, containing multiple
501 clips. Associated to the playlist is a generation number which is incremented
502 on each modification to the playlist. The current playlist generation is
503 provided in the status record in order for a client to know when to refresh
504 its presentation of the list. The status record also indicates which clip is
507 Actions that can be carried out on the playlist are summarised as:
509 * list - list all the clips and associated in/out points and size
510 * loading a clip - a load will wipe the current list and replace it with the
512 * appending a clip - append will always place the specified clip at the end
514 * inserting a clip - insert will place a new clip at the specified position
516 * moving a clip - move will allow clips can be moved in the playlist
517 * removing a clip - remove will remove the specified clip from the playlist
518 * clean - clean will remove all but the playing clip from the playlist
520 Additionally, the following existing actions are clip aware:
522 * goto allows you to move the current play position to a specific clip position
523 * set in/out points allows you to modify clip in and out points
525 Backward compatability has been maintained by the addition of a clip-aware
526 family of APIs which have the naming convention of mvcp_unit_clip_*.
528 These are listed in Appendix B.
530 The following shows an example of obtaining the clips queued on unit 0:
532 mvcp_list list = mvcp_list_init( client, 0 );
533 mvcp_list_entry_t entry;
536 printf( "Generation = %d\n", list->generation );
537 for ( index = 0; index < mvcp_list_count( list ); index ++ )
539 mvcp_list_get( list, index, &entry );
540 printf( "%d %s %d %d %d %d\n",
548 mvcp_list_close( list );
550 To load a clip on unit 0:
552 mvcp_unit_load( client, 0, "/path/clip.dv" );
554 To append a clip on unit 0:
556 mvcp_unit_append( client, 0, "/path/clip.dv", -1, -1 );
558 Note that the last two arguments specify the in and out points of the clip
559 with -1 denoting dfaults of the entirety of the file.
561 To insert a clip at position 0 on unit 0, we can use the following:
563 mvcp_unit_clip_insert( client, 0, clip_absolute, 0, "/path/clip.dv", -1, -1 );
565 The 3rd and 4th arguments here are common to all the mvcp_unit_clip functions.
566 They take the form of either [clip_absolute, n] to indicate an absolute clip
567 index, or [clip_relative, n] to indicate a clip index relative to the
568 currently playing clip.
570 So, to insert a clip immediately before the currently playing clip, we can
573 mvcp_unit_clip_insert( client, 0, clip_relative, -1, "/path/clip.dv", -1, -1 );
575 To move the current clip to the next position in the list:
577 mvcp_unit_clip_move( client, 0, clip_relative, 0, clip_relative, 1 );
579 To remove a specific clip:
581 mvcp_unit_clip_remove( client, 0, clip_absolute, index );
583 To remove all but the currently playing clip:
585 mvcp_unit_clean( client, 0 );
587 To goto the first frame in the first clip, you can use:
589 mvcp_unit_clip_goto( client, 0, clip_absolute, 0, 0 );
591 To set the in and out points on the current clip:
593 mvcp_unit_clip_set_in( client, 0, clip_relative, 0, 0 );
594 mvcp_unit_clip_set_out( client, 0, clip_relative, 0, 1000 );
596 A more complete example of use of the server side can queuing can be found
599 http://users.pandora.be/acp/rugen
601 The demo client provided with mvcp is used for retaining backward
602 compatability with the client side queuing API.
605 2.9. Accessing the Low Level Parser Directly
606 --------------------------------------------
608 The low level parser and its associated structures can be accessed directly
609 from the high level API, but is very occasionally actually needed.
611 The methods are provided via a pair of high level methods:
613 mvcp_error_code error = mvcp_execute( client, 1024, "USTA U%d", unit );
614 mvcp_response response = mvcp_get_last_response( client );
616 for ( index = 0; index < mvcp_response_count( response ); index ++ )
617 printf( "%d: %s\n", index, mvcp_response_get_line( response,index ) );
619 More details on the mvcp_response structure can be found in section 3 of this
626 Before the mvcp and parser go out of scope, you need to run:
628 mvcp_close( client );
629 mvcp_parser_close( parser );
631 Note that you should close all mvcp instances before closing the parser.
637 Please refer to mvcp-console and mvcp-client source for examples provided with
638 the project. Rugen is another example:
640 http://users.pandora.be/acp/rugen
643 3. The Low Level Parser API
644 ---------------------------
646 The low level parser API provides a very simple mechanism for constructing
647 commands and receiving responses.
649 As described in section 2, a parser is constructed as local or remote and
650 this is sufficient for constructing the low level parser.
653 3.1. Executing a Command
654 ------------------------
656 All commands can be executed via the single variable argument function
657 mvcp_parser_executef and this function returns a mvcp_response, ie:
659 mvcp_response response = mvcp_parser_executef( parser, "CLS \"%s\"", dir );
661 Note that no carriage return/line feed is required (adding this is
664 It is the receiver of the response who is responsible for closing it.
666 mvcp_response_close( response );
669 3.2. Interpreting mvcp_response
670 -----------------------------
672 The response received can be NULL, but it is safe to call:
674 int error = mvcp_response_get_error_code( response );
678 * -1 if response is NULL,
679 * -2 if there is no content to the response,
680 * 0 if the responses first line does not correspond to a valid MVCP response
681 * or the MVCP protocol error code returned on the first line of the response
683 A simple use of a mvcp_response structure is as follows:
685 mvcp_response response = mvcp_parser_executef( parser, "CLS \"%s\"", dir );
686 int error = mvcp_response_get_error_code( response );
690 for ( index = 0; index < mvcp_response_count( response ); index ++ )
691 printf( "%3d: %s\n", index, mvcp_response_get_line( response, index ) );
695 /* interpret error */
697 mvcp_response_close( response );
699 Note that it is safe to call mvcp_response_close regardless of the error
703 3.3. Accessing Unit Status
704 --------------------------
706 As with the high level parser, there are two alternatives to obtain unit
707 status information - either via the USTA MVCP command or via the
710 The latter is the recommended way for any applications which wish to extract
711 meaningful information from the status while avoiding the requirement to
712 duplicate the parsing process in a specific client.
714 The notifier can be obtained by:
716 mvcp_notifier notifier = mvcp_parser_get_notifier( parser );
718 The use of the notifier with the low level parser is identical to that
719 dictated in Section 2 - to obtain the last status associated to a unit,
723 mvcp_status_t status;
724 mvcp_notifier_get( notifier, &status, unit );
726 To wait for the next status from any unit, you can use:
728 mvcp_notifier_wait( notifier, &status );
731 APPENDIX A - COMPILATION AND LINKING
732 ------------------------------------
734 Compilation flags are:
738 where prefix defaults to /usr/local.
740 Linking flags for a client are:
742 -L <prefix>/lib/ -lmvcp
744 Or for a local parser:
746 -L <prefix>/lib/ -lmelted
748 Note that you never need both libs.
751 APPENDIX B - COMPLETE HIGH LEVEL PARSER WRAPPER API LISTING
752 -----------------------------------------------------------
754 mvcp mvcp_init( mvcp_parser );
756 mvcp_error_code mvcp_connect( mvcp );
758 mvcp_error_code mvcp_set( mvcp, char *, char * );
759 mvcp_error_code mvcp_get( mvcp, char *, char *, int );
761 mvcp_error_code mvcp_unit_add( mvcp, char * );
762 mvcp_error_code mvcp_unit_load( mvcp, int, char * );
763 mvcp_error_code mvcp_unit_load_clipped( mvcp,int,char *,long,long );
764 mvcp_error_code mvcp_unit_load_back( mvcp, int, char * );
765 mvcp_error_code mvcp_unit_load_back_clipped(mvcp,int,char *,long,long)
766 mvcp_error_code mvcp_unit_play( mvcp, int );
767 mvcp_error_code mvcp_unit_play_at_speed( mvcp, int, int );
768 mvcp_error_code mvcp_unit_stop( mvcp, int );
769 mvcp_error_code mvcp_unit_pause( mvcp, int );
770 mvcp_error_code mvcp_unit_rewind( mvcp, int );
771 mvcp_error_code mvcp_unit_fast_forward( mvcp, int );
772 mvcp_error_code mvcp_unit_step( mvcp, int, int );
773 mvcp_error_code mvcp_unit_goto( mvcp, int, int );
774 mvcp_error_code mvcp_unit_set_in( mvcp, int, int );
775 mvcp_error_code mvcp_unit_set_out( mvcp, int, int );
776 mvcp_error_code mvcp_unit_clear_in( mvcp, int );
777 mvcp_error_code mvcp_unit_clear_out( mvcp, int );
778 mvcp_error_code mvcp_unit_clear_in_out( mvcp, int );
779 mvcp_error_code mvcp_unit_set( mvcp, int, char *, char * );
780 mvcp_error_code mvcp_unit_get( mvcp, int, char * );
782 mvcp_error_code mvcp_unit_status( mvcp, int, mvcp_status );
783 mvcp_notifier mvcp_get_notifier( mvcp );
785 mvcp_dir mvcp_dir_init( mvcp, char * );
786 mvcp_error_code mvcp_dir_get( mvcp_dir, int, mvcp_dir_entry );
787 int mvcp_dir_count( mvcp_dir );
788 void mvcp_dir_close( mvcp_dir );
790 mvcp_nodes mvcp_nodes_init( mvcp );
791 mvcp_error_code mvcp_nodes_get(mvcp_nodes,int,mvcp_node_entry);
792 int mvcp_nodes_count( mvcp_nodes );
793 void mvcp_nodes_close( mvcp_nodes );
795 mvcp_units mvcp_units_init( mvcp );
796 mvcp_error_code mvcp_units_get(mvcp_units,int,mvcp_unit_entry);
797 int mvcp_units_count( mvcp_units );
798 void mvcp_units_close( mvcp_units );
800 mvcp_response mvcp_get_last_response( mvcp );
802 mvcp_error_code mvcp_execute( mvcp, size_t, char *, ... );
804 void mvcp_close( mvcp );
809 void mvcp_notifier_get( mvcp_notifier, mvcp_status, int );
810 void mvcp_notifier_put( mvcp_notifier, mvcp_status );
811 int mvcp_notifier_wait( mvcp_notifier, mvcp_status );
812 void mvcp_notifier_close( mvcp_notifier );
817 mvcp_list mvcp_list_init( mvcp, int )
818 mvcp_error_code mvcp_list_get_error_code( mvcp_list )
819 mvcp_error_code mvcp_list_get( mvcp_list, int, mvcp_list_entry )
820 int mvcp_list_count( mvcp_list )
821 void mvcp_list_close( mvcp_list )
823 mvcp_error_code mvcp_unit_clean( mvcp client, int unit )
824 mvcp_error_code mvcp_unit_append( mvcp client, int unit, char *file, int in, int out )
825 mvcp_error_code mvcp_unit_remove_current_clip( mvcp client, int unit )
827 mvcp_error_code mvcp_unit_clip_goto( mvcp client, int unit, mvcp_clip_offset offset, int clip, int position )
828 mvcp_error_code mvcp_unit_clip_set_in( mvcp client, int unit, mvcp_clip_offset offset, int clip, int in )
829 mvcp_error_code mvcp_unit_clip_set_out( mvcp client, int unit, mvcp_clip_offset offset, int clip, int in )
830 mvcp_error_code mvcp_unit_clip_move( mvcp client, int unit, mvcp_clip_offset offset, int src, mvcp_clip_offset offset, int dest )
831 mvcp_error_code mvcp_unit_clip_remove( mvcp client, int unit, mvcp_clip_offset offset, int clip )
832 mvcp_error_code mvcp_unit_clip_insert( mvcp client, int unit, mvcp_clip_offset offset, int clip, char *file, int in, int out )
836 APPENDIX C - COMPLETE LOW LEVEL PARSER API LISTING
837 --------------------------------------------------
839 mvcp_response mvcp_parser_connect( mvcp_parser );
840 mvcp_response mvcp_parser_execute( mvcp_parser, char * );
841 mvcp_response mvcp_parser_executef( mvcp_parser, char *, ... );
842 mvcp_response mvcp_parser_run( mvcp_parser, char * );
843 mvcp_notifier mvcp_parser_get_notifier( mvcp_parser );
844 void mvcp_parser_close( mvcp_parser );
846 mvcp_response mvcp_response_init( );
847 mvcp_response mvcp_response_clone( mvcp_response );
848 int mvcp_response_get_error_code( mvcp_response );
849 char *mvcp_response_get_error_string( mvcp_response );
850 char *mvcp_response_get_line( mvcp_response, int );
851 int mvcp_response_count( mvcp_response );
852 void mvcp_response_set_error( mvcp_response, int, char * );
853 int mvcp_response_printf( mvcp_response, size_t, char *, ... );
854 int mvcp_response_write( mvcp_response, char *, int );
855 void mvcp_response_close( mvcp_response );
858 APPENDIX D - REFERENCES
859 -----------------------
861 (1) doc/mvcp.txt - MVCP protocol
862 (2) doc/testing.txt - Test procedures