diff options
Diffstat (limited to 'doc/hackersguide/library.docbook')
| -rw-r--r-- | doc/hackersguide/library.docbook | 410 | 
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..03a863c39 --- /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 <segfault@club-internet.fr> +**   +** 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 <stdio.h> +#include <string.h> +#include <math.h> + +#include <X11/X.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/keysym.h> +#include <X11/Xatom.h> +#include <X11/Xutil.h> +#include <X11/extensions/XShm.h> + +#include <xine.h> +#include <xine/xineutils.h> + + +#define MWM_HINTS_DECORATIONS   (1L << 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->type) {  +  case XINE_EVENT_UI_PLAYBACK_FINISHED: +    running = 0; +    break; + +  case XINE_EVENT_PROGRESS: +    { +      xine_progress_data_t *pevent = (xine_progress_data_t *) event->data; +       +      printf("%s [%d%%]\n", pevent->description, pevent->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 < 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 *) &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 *)&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, &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(&kevent, kbuf, sizeof(kbuf), &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, &xpos, &ypos, &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, &xevent); +      break; +       +    case ConfigureNotify: +      { +        XConfigureEvent *cev = (XConfigureEvent *) &xevent; +        Window           tmp_win; +         +        width  = cev->width; +        height = cev->height; +         +        if ((cev->x == 0) && (cev->y == 0)) { +          XLockDisplay(display); +          XTranslateCoordinates(display, cev->window, +                                DefaultRootWindow(cev->display), +                                0, 0, &xpos, &ypos, &tmp_win); +          XUnlockDisplay(display); +        } else { +          xpos = cev->x; +          ypos = cev->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> | 
