summaryrefslogtreecommitdiff
path: root/doc/hackersguide/library.docbook
diff options
context:
space:
mode:
Diffstat (limited to 'doc/hackersguide/library.docbook')
-rw-r--r--doc/hackersguide/library.docbook410
1 files changed, 410 insertions, 0 deletions
diff --git a/doc/hackersguide/library.docbook b/doc/hackersguide/library.docbook
new file mode 100644
index 000000000..01412e362
--- /dev/null
+++ b/doc/hackersguide/library.docbook
@@ -0,0 +1,410 @@
+<chapter id="xine-library">
+ <title>Using the xine library</title>
+
+ <sect1>
+ <title>xine architecture as visible to libxine clients</title>
+ <para>
+ The following drawing shows the components of xine as outside applications
+ see them. For every component, the functions for creating and destroying it
+ are given. Every other function works in the context it is enclosed in.
+ Functions that facilitate the connection of the individual components are
+ also given.
+ </para>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="library.png" format="PNG" />
+ </imageobject>
+ <imageobject>
+ <imagedata fileref="library.eps" format="EPS" />
+ </imageobject>
+ <caption>
+ <para>outside view on xine components</para>
+ </caption>
+ </mediaobject>
+ <para>
+ The function are named just to give you an overview of what is actually
+ there. It is all thoroughly documented in the plublic header
+ <filename>xine.h</filename>, which is the main and preferably the only xine
+ header, clients should include. (xine/xineutils.h and the XML parser might
+ make an exception.)
+ </para>
+ <para>
+ Details on the OSD feature can be found in the <link linkend="osd">OSD section</link>.
+ </para>
+ </sect1>
+
+ <sect1>
+ <title>Writing a new frontend to xine</title>
+ <para>
+ The best way to explain this seems to be actual code. Below you
+ will find a very easy and hopefully self-explaining xine frontend
+ to give you a start.
+ </para>
+ <para>
+ One important thing to note is that any X11 based xine-lib frontend
+ must call <function>XInitThreads()</function> before calling the
+ first Xlib function, because xine will access the display from
+ within a different thread than the frontend.
+ </para>
+ <sect2>
+ <title>Source code of a simple X11 frontend</title>
+ <programlisting>
+/*
+** Copyright (C) 2003 Daniel Caujolle-Bert &lt;segfault@club-internet.fr&gt;
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+**
+*/
+
+/*
+ * compile-command: "gcc -Wall -O2 `pkg-config --cflags --libs libxine` -L/usr/X11R6/lib -lX11 -lm -o xinimin xinimin.c"
+ */
+
+#include &lt;stdio.h&gt;
+#include &lt;string.h&gt;
+#include &lt;math.h&gt;
+
+#include &lt;X11/X.h&gt;
+#include &lt;X11/Xlib.h&gt;
+#include &lt;X11/Xutil.h&gt;
+#include &lt;X11/keysym.h&gt;
+#include &lt;X11/Xatom.h&gt;
+#include &lt;X11/Xutil.h&gt;
+#include &lt;X11/extensions/XShm.h&gt;
+
+#include &lt;xine.h&gt;
+#include &lt;xine/xineutils.h&gt;
+
+
+#define MWM_HINTS_DECORATIONS (1L &lt;&lt; 1)
+#define PROP_MWM_HINTS_ELEMENTS 5
+typedef struct {
+ uint32_t flags;
+ uint32_t functions;
+ uint32_t decorations;
+ int32_t input_mode;
+ uint32_t status;
+} MWMHints;
+
+static xine_t *xine;
+static xine_stream_t *stream;
+static xine_video_port_t *vo_port;
+static xine_audio_port_t *ao_port;
+static xine_event_queue_t *event_queue;
+
+static Display *display;
+static int screen;
+static Window window[2];
+static int xpos, ypos, width, height, fullscreen;
+static double pixel_aspect;
+
+static int running = 1;
+
+#define INPUT_MOTION (ExposureMask | ButtonPressMask | KeyPressMask | \
+ ButtonMotionMask | StructureNotifyMask | \
+ PropertyChangeMask | PointerMotionMask)
+
+/* this will be called by xine, if it wants to know the target size of a frame */
+static void dest_size_cb(void *data, int video_width, int video_height, double video_pixel_aspect,
+ int *dest_width, int *dest_height, double *dest_pixel_aspect) {
+ *dest_width = width;
+ *dest_height = height;
+ *dest_pixel_aspect = pixel_aspect;
+}
+
+/* this will be called by xine when it's about to draw the frame */
+static void frame_output_cb(void *data, int video_width, int video_height,
+ double video_pixel_aspect, int *dest_x, int *dest_y,
+ int *dest_width, int *dest_height,
+ double *dest_pixel_aspect, int *win_x, int *win_y) {
+ *dest_x = 0;
+ *dest_y = 0;
+ *win_x = xpos;
+ *win_y = ypos;
+ *dest_width = width;
+ *dest_height = height;
+ *dest_pixel_aspect = pixel_aspect;
+}
+
+static void event_listener(void *user_data, const xine_event_t *event) {
+ switch(event-&gt;type) {
+ case XINE_EVENT_UI_PLAYBACK_FINISHED:
+ running = 0;
+ break;
+
+ case XINE_EVENT_PROGRESS:
+ {
+ xine_progress_data_t *pevent = (xine_progress_data_t *) event-&gt;data;
+
+ printf("%s [%d%%]\n", pevent-&gt;description, pevent-&gt;percent);
+ }
+ break;
+
+ /* you can handle a lot of other interesting events here */
+ }
+}
+
+int main(int argc, char **argv) {
+ char configfile[2048];
+ x11_visual_t vis;
+ double res_h, res_v;
+ char *vo_driver = "auto";
+ char *ao_driver = "auto";
+ char *mrl = NULL;
+ int i;
+ Atom XA_NO_BORDER;
+ MWMHints mwmhints;
+
+ /* parsing command line */
+ for (i = 1; i &lt; argc; i++) {
+ if (strcmp(argv[i], "-vo") == 0) {
+ vo_driver = argv[++i];
+ }
+ else if (strcmp(argv[i], "-ao") == 0) {
+ ao_driver = argv[++i];
+ }
+ else
+ mrl = argv[i];
+ }
+
+ if (!mrl) {
+ printf("specify an mrl\n");
+ return 1;
+ }
+ printf("mrl: '%s'\n", mrl);
+
+ if (!XInitThreads()) {
+ printf("XInitThreads() failed\n");
+ return 1;
+ }
+
+ /* load xine config file and init xine */
+ xine = xine_new();
+ snprintf(configfile, sizeof(configfile), "%s%s", xine_get_homedir(), "/.xine/config");
+ xine_config_load(xine, configfile);
+ xine_init(xine);
+
+ display = XOpenDisplay(NULL);
+ screen = XDefaultScreen(display);
+ xpos = 0;
+ ypos = 0;
+ width = 320;
+ height = 200;
+
+ /* some initalization for the X11 Window we will be showing video in */
+ XLockDisplay(display);
+ fullscreen = 0;
+ window[0] = XCreateSimpleWindow(display, XDefaultRootWindow(display),
+ xpos, ypos, width, height, 1, 0, 0);
+
+ window[1] = XCreateSimpleWindow(display, XDefaultRootWindow(display),
+ 0, 0, (DisplayWidth(display, screen)),
+ (DisplayHeight(display, screen)), 0, 0, 0);
+
+ XSelectInput(display, window[0], INPUT_MOTION);
+
+ XSelectInput(display, window[1], INPUT_MOTION);
+
+ XA_NO_BORDER = XInternAtom(display, "_MOTIF_WM_HINTS", False);
+ mwmhints.flags = MWM_HINTS_DECORATIONS;
+ mwmhints.decorations = 0;
+ XChangeProperty(display, window[1],
+ XA_NO_BORDER, XA_NO_BORDER, 32, PropModeReplace, (unsigned char *) &amp;mwmhints,
+ PROP_MWM_HINTS_ELEMENTS);
+
+ XMapRaised(display, window[fullscreen]);
+
+ res_h = (DisplayWidth(display, screen) * 1000 / DisplayWidthMM(display, screen));
+ res_v = (DisplayHeight(display, screen) * 1000 / DisplayHeightMM(display, screen));
+ XSync(display, False);
+ XUnlockDisplay(display);
+
+ /* filling in the xine visual struct */
+ vis.display = display;
+ vis.screen = screen;
+ vis.d = window[fullscreen];
+ vis.dest_size_cb = dest_size_cb;
+ vis.frame_output_cb = frame_output_cb;
+ vis.user_data = NULL;
+ pixel_aspect = res_v / res_h;
+
+ /* opening xine output ports */
+ vo_port = xine_open_video_driver(xine, vo_driver, XINE_VISUAL_TYPE_X11, (void *)&amp;vis);
+ ao_port = xine_open_audio_driver(xine , ao_driver, NULL);
+
+ /* open a xine stream connected to these ports */
+ stream = xine_stream_new(xine, ao_port, vo_port);
+ /* hook our event handler into the streams events */
+ event_queue = xine_event_new_queue(stream);
+ xine_event_create_listener_thread(event_queue, event_listener, NULL);
+
+ /* make the video window visible to xine */
+ xine_port_send_gui_data(vo_port, XINE_GUI_SEND_DRAWABLE_CHANGED, (void *) window[fullscreen]);
+ xine_port_send_gui_data(vo_port, XINE_GUI_SEND_VIDEOWIN_VISIBLE, (void *) 1);
+
+ /* start playback */
+ if (!xine_open(stream, mrl) || !xine_play(stream, 0, 0)) {
+ printf("Unable to open mrl '%s'\n", mrl);
+ return 1;
+ }
+
+ while (running) {
+ XEvent xevent;
+ int got_event;
+
+ XLockDisplay(display);
+ got_event = XPending(display);
+ if( got_event )
+ XNextEvent(display, &amp;xevent);
+ XUnlockDisplay(display);
+
+ if( !got_event ) {
+ xine_usec_sleep(20000);
+ continue;
+ }
+
+ switch(xevent.type) {
+
+ case KeyPress:
+ {
+ XKeyEvent kevent;
+ KeySym ksym;
+ char kbuf[256];
+ int len;
+
+ kevent = xevent.xkey;
+
+ XLockDisplay(display);
+ len = XLookupString(&amp;kevent, kbuf, sizeof(kbuf), &amp;ksym, NULL);
+ XUnlockDisplay(display);
+
+ switch (ksym) {
+
+ case XK_q:
+ case XK_Q:
+ /* user pressed q => quit */
+ running = 0;
+ break;
+
+ case XK_f:
+ case XK_F:
+ {
+ /* user pressed f => toggle fullscreen */
+ Window tmp_win;
+
+ XLockDisplay(display);
+ XUnmapWindow(display, window[fullscreen]);
+ fullscreen = !fullscreen;
+ XMapRaised(display, window[fullscreen]);
+ XSync(display, False);
+ XTranslateCoordinates(display, window[fullscreen],
+ DefaultRootWindow(display),
+ 0, 0, &amp;xpos, &amp;ypos, &amp;tmp_win);
+ XUnlockDisplay(display);
+
+ xine_port_send_gui_data(vo_port, XINE_GUI_SEND_DRAWABLE_CHANGED,
+ (void*) window[fullscreen]);
+ }
+ break;
+
+ case XK_Up:
+ /* cursor up => increase volume */
+ xine_set_param(stream, XINE_PARAM_AUDIO_VOLUME,
+ (xine_get_param(stream, XINE_PARAM_AUDIO_VOLUME) + 1));
+ break;
+
+ case XK_Down:
+ /* cursor down => decrease volume */
+ xine_set_param(stream, XINE_PARAM_AUDIO_VOLUME,
+ (xine_get_param(stream, XINE_PARAM_AUDIO_VOLUME) - 1));
+ break;
+
+ case XK_plus:
+ /* plus => next audio channel */
+ xine_set_param(stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL,
+ (xine_get_param(stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL) + 1));
+ break;
+
+ case XK_minus:
+ /* minus => previous audio channel */
+ xine_set_param(stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL,
+ (xine_get_param(stream, XINE_PARAM_AUDIO_CHANNEL_LOGICAL) - 1));
+ break;
+
+ case XK_space:
+ /* space => toggle pause mode */
+ if (xine_get_param(stream, XINE_PARAM_SPEED) != XINE_SPEED_PAUSE)
+ xine_set_param(stream, XINE_PARAM_SPEED, XINE_SPEED_PAUSE);
+ else
+ xine_set_param(stream, XINE_PARAM_SPEED, XINE_SPEED_NORMAL);
+ break;
+
+ }
+ }
+ break;
+
+ case Expose:
+ /* this handles (partial) occlusion of our video window */
+ if (xevent.xexpose.count != 0)
+ break;
+ xine_port_send_gui_data(vo_port, XINE_GUI_SEND_EXPOSE_EVENT, &amp;xevent);
+ break;
+
+ case ConfigureNotify:
+ {
+ XConfigureEvent *cev = (XConfigureEvent *) &amp;xevent;
+ Window tmp_win;
+
+ width = cev-&gt;width;
+ height = cev-&gt;height;
+
+ if ((cev-&gt;x == 0) &amp;&amp; (cev-&gt;y == 0)) {
+ XLockDisplay(display);
+ XTranslateCoordinates(display, cev-&gt;window,
+ DefaultRootWindow(cev-&gt;display),
+ 0, 0, &amp;xpos, &amp;ypos, &amp;tmp_win);
+ XUnlockDisplay(display);
+ } else {
+ xpos = cev-&gt;x;
+ ypos = cev-&gt;y;
+ }
+ }
+ break;
+
+ }
+ }
+
+ /* cleanup */
+ xine_close(stream);
+ xine_event_dispose_queue(event_queue);
+ xine_dispose(stream);
+ xine_close_audio_driver(xine, ao_port);
+ xine_close_video_driver(xine, vo_port);
+ xine_exit(xine);
+
+ XLockDisplay(display);
+ XUnmapWindow(display, window[fullscreen]);
+ XDestroyWindow(display, window[0]);
+ XDestroyWindow(display, window[1]);
+ XUnlockDisplay(display);
+
+ XCloseDisplay (display);
+
+ return 0;
+}</programlisting>
+ </sect2>
+ </sect1>
+
+</chapter>