1 // LiVES - vjack playback engine
2 // (c) G. Finch 2006 - 2008 <salsaman@xs4all.nl,salsaman@gmail.com>
3 // released under the GNU GPL 3 or later
4 // see file COPYING or www.gnu.org for details
5 
6 #include "videoplugin.h"
7 
8 #include <stdio.h>
9 
10 /////////////////////////////////////////////////////////////////
11 
12 static char plugin_version[64] = "LiVES videojack output client 1.1";
13 static char fps_list[256];
14 static int palette_list[2];
15 static int mypalette;
16 
17 //////////////////////////////////////////////////////////////////
18 
19 #include <jack/jack.h>
20 #include <jack/video.h>
21 #include <jack/ringbuffer.h>
22 
23 static jack_ringbuffer_t *rb;
24 static size_t frame_size;
25 static jack_port_t *output_port;
26 static jack_client_t *client;
27 
server_process(jack_nframes_t nframes,void * arg)28 int server_process(jack_nframes_t nframes, void *arg) {
29   // jack calls this
30   uint8_t *in;
31 
32   if (rb == NULL) return 0;
33 
34   in = jack_port_get_buffer(output_port, nframes);
35   while (jack_ringbuffer_read_space(rb) >= frame_size) {
36     jack_ringbuffer_read(rb, (void *) in, frame_size);
37   }
38   return 0;
39 }
40 
41 //////////////////////////////////////////////
get_fps_list(int palette)42 const char *get_fps_list(int palette) {
43   double fps = (double)jack_get_sample_rate(client);
44   snprintf(fps_list, 256, "%.8f", fps);
45   return fps_list;
46 }
47 
module_check_init(void)48 const char *module_check_init(void) {
49   const char *client_name = "LiVES";
50   jack_options_t options = JackNullOption;
51   jack_status_t status;
52   const char *server_name = NULL; // set to "video0" if running with audio on "default"
53 
54   // connect to vjack
55   client = jack_client_open(client_name, options, &status, server_name);
56   if (client == NULL) {
57     fprintf(stderr, "jack_client_open() failed, "
58             "status = 0x%2.0x\n", status);
59     if (status & JackServerFailed) {
60       fprintf(stderr, "vjack_output: Unable to connect to JACK server\n");
61     }
62     return "unable to connect";
63   }
64   if (status & JackServerStarted) {
65     fprintf(stderr, "JACK server started\n");
66   }
67   if (status & JackNameNotUnique) {
68     client_name = jack_get_client_name(client);
69     fprintf(stderr, "unique name `%s' assigned\n", client_name);
70   }
71 
72   fprintf(stderr, "engine sample rate: %" PRIu32 "\n",
73           jack_get_sample_rate(client));
74 
75   output_port = jack_port_register(client,
76                                    "video_out",
77                                    JACK_DEFAULT_VIDEO_TYPE,
78                                    JackPortIsOutput,
79                                    0);
80 
81   if (output_port == NULL) {
82     fprintf(stderr, "vjack_output: no more JACK ports available\n");
83     return "no jack ports available";
84   }
85 
86   rb = NULL;
87 
88   // set process callback and start
89   jack_set_process_callback(client, server_process, NULL);
90 
91   // and start the processing
92   if (jack_activate(client)) {
93     fprintf(stderr, "vjack_output: cannot activate client\n");
94     return "cannot activate client";
95   }
96 
97   return NULL;
98 }
99 
version(void)100 const char *version(void) {
101   return plugin_version;
102 }
103 
get_description(void)104 const char *get_description(void) {
105   return "The vjack_output plugin allows sending frames to videojack.\nThis is an experimental plugin\n";
106 }
107 
get_capabilities(int palette)108 uint64_t get_capabilities(int palette) {
109   return 0;
110 }
111 
get_palette_list(void)112 int *get_palette_list(void) {
113   palette_list[0] = WEED_PALETTE_RGBA32;
114   palette_list[1] = WEED_PALETTE_END;
115   return palette_list;
116 }
117 
set_palette(int palette)118 boolean set_palette(int palette) {
119   if (palette == WEED_PALETTE_RGBA32) {
120     mypalette = palette;
121     return TRUE;
122   }
123   // invalid palette
124   return FALSE;
125 }
126 
init_screen(int width,int height,boolean fullscreen,uint64_t window_id,int argc,char ** argv)127 boolean init_screen(int width, int height, boolean fullscreen, uint64_t window_id, int argc, char **argv) {
128   jack_video_set_width_and_height(client, output_port, width, height);
129   frame_size = width * height * 4;
130   rb = jack_ringbuffer_create(16 * frame_size);
131   return TRUE;
132 }
133 
render_frame(int hsize,int vsize,int64_t tc,void ** pixel_data,void ** return_data)134 boolean render_frame(int hsize, int vsize, int64_t tc, void **pixel_data, void **return_data) {
135   // hsize and vsize are in pixels (n-byte)
136 
137   jack_ringbuffer_write(rb, pixel_data[0], frame_size);
138   return TRUE;
139 }
140 
exit_screen(int16_t mouse_x,int16_t mouse_y)141 void exit_screen(int16_t mouse_x, int16_t mouse_y) {
142   if (rb != NULL) jack_ringbuffer_free(rb);
143   rb = NULL;
144 }
145 
module_unload(void)146 void module_unload(void) {
147   if (jack_deactivate(client)) {
148     fprintf(stderr, "vjack_output error: cannot deactivate client\n");
149   }
150 
151   // disconnect from vjack
152   jack_client_close(client);
153   fprintf(stderr, "vjack_output: jack port unregistered\n");
154 }
155