OSD, again :)

Alban Bedel <[email protected]>
Newsgroups gmane.comp.video.mplayer.g2.devel
Message-ID <[email protected]>
Hi,

The system is based on what i called "osd display". The display role is
to manage draw/clear of the various objects currently attached to the
display. Once a display is configured then you just feed it with some
mp_image and it will draw the objects.
The "osd display" doesn't do any drawing/clearing. It just take care
of what have to be done, draw are handled by the object themself, and
clear by a callback.
The system make the drawing/clearing decisions upon the "buffer type".
The display itself have a buffer type but it's also possible to define
some area with a different buffer type. There is 3
buffer types :
 TEMP   : We never clear it, everything is redrawn at every frame
 STATIC : We need to clear it if it change but we don't need to
          redraw it at every frame.
 LOCKED : This forbid drawing.

So TEMP is the movie area, STATIC the black bands and LOCKED is for
IP/B, PRESERVE, etc.

The osd filter is just like expand (should have took it ;) But by
default the filter will use LOCKED area for IP/B so you won't see
anythig unless you either expand enouth or use force=1 (wich then
allow DR only on TEMP).
The osd object need freetype (with freetype-config for the build).
So you also need to pass it a font name. Use something like:
-vop osd=force=1:objs=test=font=/path/to/your/font
and you should see some text comming from the right :)


Ok, this is "just some experiment", feedback appreciated :)
	Albeu

-- 

Everything is controlled by a small evil group
to which, unfortunately, no one we know belongs.

_______________________________________________
MPlayer-G2-dev mailing list
[email protected]
http://mplayerhq.hu/mailman/listinfo/mplayer-g2-dev
g2.osd.diff (application/octet-stream, 31.8 KB)
--- /home/alban/MP/g2/Makefile	Thu Jul 10 22:54:15 2003
+++ /home/alban/MP/g2.dev/Makefile	Sat Jul 19 20:40:02 2003
@@ -10,7 +10,7 @@
 STREAM_DEPS = demux/libmpdemux.a stream/libmpstream.a stream/mpdvdkit2/libmpdvdkit.a
 CODECS_DEPS = audio/libmpacodecs.a video/libmpvcodecs.a libavcodec/libavcodec.a libavcodec/libpostproc/libpostproc.a \
     audio/libaf/libaf.a video/libmpeg2/libmpeg2.a \
-    audio/mp3lib/libMP3.a swscale/libswscale.a
+    audio/mp3lib/libMP3.a swscale/libswscale.a osd/libmposd.a
 PLAYER_DEPS = libao2/libao2.a libvo2/libvo2.a
 
 AO_LIBS = $(ARTS_LIB) $(ESD_LIB) $(NAS_LIB) $(SGIAUDIO_LIB) $(ALSA_LIB) $(SDL_LIB)
@@ -79,7 +79,7 @@
 	$(CC) $(OBJS) test-codecs.o osdep/cpudetect.o -o test-codecs $(CODECS_DEPS) $(STREAM_DEPS) $(PLAYER_DEPS) $(EXTRA_LIB) $(CDPARANOIA_LIB) osdep/libosdep.a $(SMBCLIENT_LIB) $(AO_LIBS) $(VO_LIBS) $(THEORA_LIB) $(VORBIS_LIB) $(I18NLIBS) -lm
 
 test-play: $(OBJS) $(CODECS_DEPS) $(STREAM_DEPS) $(PLAYER_DEPS) osdep/libosdep.a test-play.o input/libinput.a 
-	$(CC) $(OBJS) test-play.o -o test-play $(CODECS_DEPS) $(STREAM_DEPS) $(PLAYER_DEPS) input/libinput.a osdep/libosdep.a $(EXTRA_LIB) $(CDPARANOIA_LIB)  $(SMBCLIENT_LIB) $(AO_LIBS) $(VO_LIBS) $(TERMCAP_LIB) $(LIRC_LIB) $(THEORA_LIB) $(VORBIS_LIB) $(I18NLIBS) -lm
+	$(CC) $(OBJS) test-play.o -o test-play $(CODECS_DEPS) $(STREAM_DEPS) $(PLAYER_DEPS) input/libinput.a osdep/libosdep.a $(EXTRA_LIB) $(CDPARANOIA_LIB)  $(SMBCLIENT_LIB) $(AO_LIBS) $(VO_LIBS) $(TERMCAP_LIB) $(LIRC_LIB) $(THEORA_LIB) $(VORBIS_LIB) $(I18NLIBS) -lm `freetype-config --libs`
 
 test-input: test-input.o input/libinput.a osdep/libosdep.a mp_msg.o get_path.o
 	$(CC) test-input.o -o test-input input/libinput.a osdep/libosdep.a mp_msg.o get_path.o $(EXTRA_LIB) $(TERMCAP_LIB) $(LIRC_LIB) $(I18NLIBS) $(MACOSX_FRAMEWORKS)
--- /dev/null	Mon Jul 18 01:46:18 1994
+++ /home/alban/MP/g2.dev/osd/Makefile	Sat Jul 19 20:26:17 2003
@@ -0,0 +1,46 @@
+
+BASE=..
+
+include $(BASE)/config.mak
+
+LIBNAME = libmposd.a
+
+SRCS=osd.c obj_test.c
+OBJS=$(SRCS:.c=.o)
+
+#CFLAGS  = $(OPTFLAGS) -I. -Inative -I.. -I../libmpdemux -I../loader $(EXTRA_INC) -D_GNU_SOURCE
+CFLAGS  = $(OPTFLAGS) -I. -I$(BASE) -I$(BASE)/video `freetype-config --cflags` $(EXTRA_INC) -D_GNU_SOURCE
+
+.SUFFIXES: .c .o
+
+# .PHONY: all clean
+
+.c.o:
+	$(CC) -c $(CFLAGS) -o $@ $<
+
+all:    $(LIBNAME) $(LIBNAME2)
+
+$(LIBNAME):     $(OBJS)
+	$(AR) sr $(LIBNAME) $(OBJS)
+
+$(LIBNAME2):     $(OBJS2)
+	$(AR) sr $(LIBNAME2) $(OBJS2)
+
+clean:
+	rm -f *.o *.a *~
+
+distclean:
+	rm -f Makefile.bak $(OBJS) $(OBJS2) $(LIBNAME) $(LIBNAME2) *~ .depend
+
+dep:    depend
+
+depend:
+	$(CC) -MM $(CFLAGS) $(SRCS) $(SRCS2) 1>.depend
+
+#
+# include dependency files if they exist
+#
+ifneq ($(wildcard .depend),)
+include .depend
+endif
+
--- /dev/null	Mon Jul 18 01:46:18 1994
+++ /home/alban/MP/g2.dev/osd/obj_test.c	Sun Jul 20 18:13:50 2003
@@ -0,0 +1,192 @@
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "cfg.h"
+#include "img_format.h"
+#include "mp_image.h"
+#include "osd.h"
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+static struct config_data_s {
+  int w,h;
+  int x,y;
+  int pw,ph;
+  char* txt;
+  char* path;
+} cfg_def = {
+  480,100,
+  10,10,
+  80,80,
+  "G2 Rocks :)",
+  "Hogb.TTF"
+};
+
+static config_t cfg_opts[] = {
+  {"w",&cfg_def.w, CONF_TYPE_INT, CONF_MIN, 1, 0, NULL, "object width"},
+  {"h",&cfg_def.h, CONF_TYPE_INT, CONF_MIN, 1, 0, NULL, "object height"},
+  {"x",&cfg_def.x, CONF_TYPE_INT, 0, 0, 0, NULL, "position on x-axis"},
+  {"y",&cfg_def.y, CONF_TYPE_INT, 0, 0, 0, NULL, "position on y-axis"},
+  {"font",&cfg_def.path, CONF_TYPE_STRING, 0, 0, 0, NULL, "path of the font to use\n"},
+  {"txt",&cfg_def.txt,CONF_TYPE_STRING, 0, 0, 0, NULL, "text to display"},
+  {NULL, NULL, 0, 0, 0, 0, NULL, NULL}
+};
+
+struct osd_obj_priv_st {
+  FT_Library ft_lib;
+  FT_Face ft_face;
+  char* txt;
+};
+
+static int init(osd_obj_t*obj,void* param) {
+  int err;
+  config_data_t* cfg = param ? param : &cfg_def;
+
+  printf("Obj init :)\n");
+  
+  obj->x = cfg->x;
+  obj->y = cfg->y;
+  obj->w = cfg->w;
+  obj->h = cfg->h;
+
+  obj->priv = malloc(sizeof(osd_obj_priv_t));
+
+  if(FT_Init_FreeType(&obj->priv->ft_lib)) {
+    printf("Freetype init failed\n");
+    free(obj->priv);
+    obj->priv = NULL;
+    return 0;
+  }
+
+  err = FT_New_Face(obj->priv->ft_lib, cfg->path, 0, &obj->priv->ft_face );
+  if(err) {
+    printf("Unable to open font file");
+    if(err == FT_Err_Unknown_File_Format )
+      printf(" unknow font format\n");
+    else
+      printf(" ... bad path/permissions ?\n");
+    free(obj->priv);
+    obj->priv = NULL;
+    return 0;
+  }
+
+  if(FT_Set_Pixel_Sizes(obj->priv->ft_face, cfg->ph,cfg->pw)) {
+    printf("Failed to set pixel size\n");
+    free(obj->priv);
+    obj->priv = NULL;
+    return 0;
+  }
+
+  obj->priv->txt = strdup(cfg->txt);
+
+  return 1;
+}
+
+static int config(osd_obj_t* obj,int width,int height,unsigned format){
+  switch(format) {
+  case IMGFMT_YV12:
+  case IMGFMT_I420:
+    return 1;
+  default:
+    printf("Unsuported colorspace\n");
+    return 0;
+  }
+}
+
+static int draw(osd_obj_t* obj,mp_image_t* mpi){
+  int c,i,j,pen_x,pen_y;
+  char* dst,*src;
+  char* txt = obj->priv->txt;
+  unsigned int idx;
+  FT_GlyphSlot slot = obj->priv->ft_face->glyph; /* a small shortcut */
+
+  if(!mpi) return 0;
+
+  pen_x = -mpi->x;
+  pen_y = -mpi->y;
+
+  obj->bb_x = obj->bb_y = 0;
+  obj->bb_w = obj->bb_h = 0;
+  obj->flags |= OSD_OBJ_HAS_BBOX;
+
+  for(c = 0 ; txt[c] != '\0' ; c++) {
+
+    if(pen_x >= mpi->width ||
+       pen_y >= mpi->height) break;
+
+    idx = FT_Get_Char_Index(obj->priv->ft_face,txt[c]);
+    if(FT_Load_Glyph( obj->priv->ft_face, idx, FT_LOAD_DEFAULT )) {
+      printf("Failed to load gliph for char '%c' (0x%x)\n",c,idx);
+      continue;
+    }
+
+    if(FT_Render_Glyph(obj->priv->ft_face->glyph, ft_render_mode_normal )) {
+      printf("Failed to render gliph for char '%c' (0x%x)\n",c,idx);
+      continue;
+    }
+
+    if(pen_x + slot->bitmap.width  <= 0 || pen_y + slot->bitmap.rows  <= 0) {
+      pen_x += slot->advance.x >> 6;
+      pen_y += slot->advance.y >> 6;
+      continue;
+    }
+
+    src = slot->bitmap.buffer; 
+    dst = mpi->planes[0] + pen_y * mpi->stride[0] + pen_x;
+    
+    i = 0;
+    for(j = 0 ; j < slot->bitmap.rows && pen_y  + j < mpi->height ; j++) {
+      if(pen_y + j >= 0) {
+	for(i = 0 ; i < slot->bitmap.width && pen_x + i < mpi->width  ; i++)
+	  if(pen_x + i >= 0 && src[i]) dst[i] = src[i];
+      }
+      dst += mpi->stride[0];
+      src += slot->bitmap.pitch;
+    }
+
+    if(pen_y + j > obj->bb_h)
+      obj->bb_h = pen_y + j;
+    if(pen_x + i > obj->bb_w)
+      obj->bb_w = pen_x + i;
+
+    pen_x += slot->advance.x >> 6;
+    pen_y += slot->advance.y >> 6;
+  }
+  //obj->w;
+  obj->status = OSD_OBJ_SHOWN;
+  //printf("\nObject drawn %d at %d x %d (%d x %d)\n",obj->draw_id,obj->x,obj->y,
+  //	 obj->w,obj->h);
+  return 1;
+}
+
+static int control(osd_obj_t* obj,int request,void* data){
+  return 0;
+}
+
+static void uninit(osd_obj_t* obj){
+}
+
+
+static osd_obj_driver_t driver = {
+  init,
+  config,
+  draw,
+  control,
+  uninit
+};
+
+module_info_t osd_obj_test_driver = {
+  MODULE_TYPE_OSD,0,
+  &driver,
+  "test",
+  "Testing object",
+  "Albeu",
+  "Albeu",
+  "No comment",
+  0,
+  cfg_opts, &cfg_def, sizeof(struct config_data_s)
+};
--- /dev/null	Mon Jul 18 01:46:18 1994
+++ /home/alban/MP/g2.dev/osd/osd.c	Sun Jul 20 16:57:10 2003
@@ -0,0 +1,469 @@
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "cfg.h"
+#include "img_format.h"
+#include "mp_image.h"
+#include "osd.h"
+
+extern module_info_t osd_obj_test_driver;
+
+static module_info_t* obj_drivers[] = {
+  &osd_obj_test_driver,
+  NULL
+};
+
+module_info_t* find_osd_obj(char* name) {
+  int i;
+  
+  for(i = 0 ; obj_drivers[i] ; i++) {
+    if(strcmp(obj_drivers[i]->name,name)) continue;
+    return obj_drivers[i];
+  }
+  return NULL;
+}
+
+#define osd_obj_in(o,buf_type) osd_disp_rect_in(o->display,buf_type,o->x,o->y,o->w,o->h)
+
+static int osd_disp_rect_in(osd_display_t* disp,int buf_type, int x,int y,int w,int h){
+  osd_area_t* a;
+  
+  // First search in the areas
+  for(a = disp->areas ; a ; a = a->next) {
+    // Doesn't cross
+    if(x+w <= a->x || x >= a->x+a->w ||
+       y+h <= a->y || y >= a->y+a->h)
+      continue;
+
+    // Not the right buffer type, we must check the resting parts (if any)
+    if(a->buffer_type != buf_type) {
+      int y2 = y < a->y ? a->y : y;
+      int h2 = (y+h < a->y+a->h ? y+h : a->y+a->h) - y2;
+      // TOP rect
+      if( y < a->y && osd_disp_rect_in(disp,buf_type,x,y,w,a->y-y) )
+	return 1;
+      // Left
+      if(x < a->x && osd_disp_rect_in(disp,buf_type,x, y2,a->x-x,h2))
+	return 1;
+      // right
+      if(x+w > a->x+a->w && osd_disp_rect_in(disp,buf_type,a->x+a->w,y2,x+w-a->x-a->w,h2))
+	return 1;
+      // bottom
+      if(y+h > a->y+a->h && osd_disp_rect_in(disp,buf_type,x,a->y+a->h,w,y+h-a->y-a->h))
+	return 1;
+      return 0;
+    } else
+      return 1;
+  }
+
+  // Fallback on display buffer type
+  return (disp->buffer_type == buf_type);
+}
+
+/*
+ * TODO : Fix STATIC in TEMP (not really needed for a player anyway)
+ */
+static int osd_disp_clear_rect(osd_display_t* disp,mp_image_t* mpi,
+			       int x,int y,int w,int h){
+  osd_area_t* a;
+  
+  // Clamp to image size
+  if(x < 0) {
+    w += x;
+    x = 0;
+  } else if (x > mpi->width)
+    return 0;
+  if(x+w > mpi->width)
+    w = mpi->width-x;
+  if(y < 0) {
+    h += y;
+    y = 0;
+  } else if(y > mpi->height)
+    return 0;
+  if(y+h > mpi->height)
+    h = mpi->height-y;
+
+  for(a = disp->areas ; a ; a = a->next) {
+    if(a->buffer_type == OSD_BUF_STATIC) continue;
+    
+    if(x+w <= a->x || x >= a->x+a->w ||
+       y+h <= a->y || y >= a->y+a->h)
+      continue;
+    
+    if(a->buffer_type == OSD_BUF_TEMP) {
+      int n = 0;
+      int y2 = y < a->y ? a->y : y;
+      int h2 = (y+h < a->y+a->h ? y+h : a->y+a->h) - y2;
+      // TOP rect
+      if(y < a->y)
+	n += osd_disp_clear_rect(disp,mpi,x,y,w,a->y-y);
+      // Left
+      if(x < a->x)
+	n += osd_disp_clear_rect(disp,mpi,x, y2,
+				 a->x-x,h2);
+      // right
+      if(x+w > a->x+a->w)
+	n += osd_disp_clear_rect(disp,mpi,a->x+a->w,y2,
+				 x+w-a->x-a->w,h2);
+      // bottom
+      if(y+h > a->y+a->h)
+	n += osd_disp_clear_rect(disp,mpi,x,a->y+a->h,w,y+h-a->y-a->h);
+      return n;
+    } 
+  }
+
+  return disp->clear(disp,mpi,x,y,w,h);
+}
+
+static int get_obj_mpi(osd_obj_t* o,mp_image_t* mpi,mp_image_t* dmpi) {
+  int x1,y1,x2,y2;
+  if(!mpi) return 0;
+
+  // Cut the object if needed
+  x1 = o->x < 0 ? 0 : o->x;
+  y1 = o->y < 0 ? 0 : o->y;
+  x2 = o->x + o->w > mpi->width ? mpi->width : o->x + o->w;
+  y2 = o->y + o->h > mpi->height ? mpi->height : o->y + o->h;
+ 
+  // Legal size ?
+  if(x2 - x1 <= 0 || y2 - y1 <= 0) return 0;
+
+  // Setup the format stuff and the buffers
+  dmpi->x = o->x < 0 ? -o->x : 0;
+  dmpi->y = o->y < 0 ? -o->y : 0;
+  dmpi->width = x2 - x1;
+  dmpi->height = y2 - y1;
+
+  if(dmpi->imgfmt != mpi->imgfmt || 
+     mpi->width != dmpi->width ||
+     mpi->height != dmpi->height)
+    mp_image_setfmt(dmpi,mpi->imgfmt);
+
+  if(mpi->flags&MP_IMGFLAG_PLANAR) {
+    dmpi->planes[0] = mpi->planes[0] +
+      y1 * mpi->stride[0] + x1;
+    dmpi->planes[1] = mpi->planes[1] +
+      (y1>>mpi->chroma_y_shift) * mpi->stride[1] + 
+      (x1>>mpi->chroma_x_shift);
+    dmpi->planes[2] = mpi->planes[2] +
+      (y1>>mpi->chroma_y_shift) * mpi->stride[2] +
+      (x1>>mpi->chroma_x_shift);
+    memcpy(dmpi->stride,mpi->stride,3*sizeof(int));
+  } else {
+    dmpi->planes[0] = mpi->planes[0] +
+      y1 * mpi->stride[0] + x1 * ((mpi->bpp+7)/8);
+    dmpi->stride[0] = mpi->stride[0];
+  }  
+  return 1;
+}
+
+int osd_object_draw(osd_obj_t* o,mp_image_t* mpi) {
+  mp_image_t* i = NULL;
+  osd_obj_status_t *rec;
+  int r,drawing = (o->status == OSD_OBJ_DRAWING) ? 1 : 0;
+
+
+ if(o->status != OSD_OBJ_DRAWING &&
+     o->status != OSD_OBJ_SHOWN)
+      return 0;
+
+ // On locked area, kill it
+ if(osd_obj_in(o,OSD_BUF_LOCKED)) {
+   o->status = OSD_OBJ_HIDEN;
+   return 0;
+ }
+
+ 
+ // Try to find the buffer, in the records
+ for(rec = o->recs ; rec && rec->buffer != mpi->planes[0] ; rec = rec->next)
+   /* NOP */;
+ // Not found, allocate
+ if(!rec) {
+   rec = calloc(sizeof(osd_obj_status_t),1);
+   rec->buffer = mpi->planes[0];
+   rec->next = o->recs;
+   o->recs = rec;
+   printf("--- Allocate new object records for buffer %p\n",mpi->planes[0]);
+   
+ }
+
+ 
+ // Get the mpi if we need to draw:
+ // We draw if the object is not drawn on the buffer,
+ // or the object must be updated, or we the object is over
+ // some TEMP area.
+ if( !rec->draw_id || o->draw_id != rec->draw_id ||
+     drawing || osd_obj_in(o,OSD_BUF_TEMP) ) {
+  if(!get_obj_mpi(o,mpi,&rec->mpi)) return 0;
+   i = &rec->mpi;
+ }
+ 
+
+ // Call the draw function. Call with NULL mpi mean that there
+ // is nothing to draw. This let the driver a chance to set itself to
+ // OSD_OBJ_DRAWING, so he can drawn something new at the next frame.
+ r = o->driver->draw(o,i);
+ if(r > 0) { // Success
+   if(i && drawing) // We draw something new
+     o->draw_id++; // Set the new draw id
+     // We record only objects wich are over STATIC
+   rec->draw_id = osd_obj_in(o,OSD_BUF_STATIC) ? o->draw_id : 0;
+   rec->x = o->x + i->x;
+   rec->y = o->y + i->y;
+   if(o->flags & OSD_OBJ_HAS_BBOX) {
+     rec->x += o->bb_x;
+     rec->y += o->bb_y;
+     rec->w = o->bb_w;
+     rec->h = o->bb_h;
+   } else {
+     rec->w = i->width;
+     rec->h = i->height;
+   }
+   return (i != NULL) ? 1 : 0;
+ }
+ return r;
+}
+
+int osd_object_clear(osd_obj_t* o,mp_image_t* mpi) {
+  osd_obj_status_t *rec,*last = NULL;
+  int r = 0;
+
+  //printf("Clear buffer %p\n",mpi->planes[0]);
+  for(rec = o->recs ; rec && rec->buffer != mpi->planes[0] ; rec = rec->next)
+    last = rec;
+  // Never seen this buffer
+  if(!rec) return 0;
+  // Not drawn over this buffer
+  if(!rec->draw_id) return 0;
+  // Alredy drawn, don't need to update
+  if(o->status == OSD_OBJ_SHOWN && rec->draw_id == o->draw_id) return 0;
+  
+  //printf("Really Clear buffer %p\n",mpi->planes[0]);
+  // Clear it
+  if(o->display->clear) r = osd_disp_clear_rect(o->display,mpi,
+						rec->x,rec->y,
+						rec->w,rec->h);
+
+  // Some default clear would be nice
+  rec->draw_id = 0;
+
+  // Object must be deleted, remove this record
+  if(o->status == OSD_OBJ_DESTROY) {
+    if(last) last->next = rec->next;
+    else o->recs = rec->next;
+    free(rec);
+  }
+  
+  return r;
+}
+
+int osd_display_draw(osd_display_t* disp, mp_image_t* mpi) {
+  osd_obj_t *o;
+  osd_obj_status_t *rec;
+  int ret = 0,r;
+
+
+  for(o = disp->objs ; o ; o = o->next ) {
+    r = osd_object_draw(o,mpi);
+    if(r < 0) {
+      printf("Error while drawing osd object\n");
+      continue;
+    }
+    ret += r;
+  }
+
+  return ret;
+}
+
+int osd_display_clear(osd_display_t* disp, mp_image_t* mpi) {
+  osd_obj_t *o,*last = NULL,*next;
+  osd_obj_status_t *rec;
+  int clr = 0,r;
+
+  for(o = disp->objs ; o ; o = next ) {    
+    // Clear if needed
+    if(o->recs) {
+      r = osd_object_clear(o,mpi);
+      if(r < 0) printf("Clear failed\n");
+      else clr += r;
+    }
+    next = o->next;
+    if(o->status == OSD_OBJ_DESTROY && o->recs == NULL) {
+      if(last) last->next = o->next;
+      else disp->objs = o->next;
+      free(o);
+    } else
+      last = o;
+  }
+
+  return clr;
+}
+
+osd_display_t* osd_display_new(int width,int height,unsigned int format,
+			       int buf_type) {
+  osd_display_t* disp = calloc(1,sizeof(osd_display_t));
+
+  disp->width = width;
+  disp->height = height;
+  disp->format = format;
+  disp->buffer_type = buf_type;
+
+  return disp;
+}
+
+osd_area_t* osd_display_add_area(osd_display_t* disp,int x,int y, int w, int h,
+			 int buffer_type) {
+  osd_area_t* ret;
+
+  // TODO Check area size etc
+
+  ret = calloc(sizeof(osd_area_t),1);
+  ret->x = x;
+  ret->y = y;
+  ret->w = w;
+  ret->h = h;
+  ret->buffer_type = buffer_type;
+  
+  ret->next = disp->areas;
+  disp->areas = ret;
+  return ret;
+}
+			 
+void osd_display_del_area(osd_display_t* disp,osd_area_t* area) {
+  osd_area_t *a,*l = NULL;
+
+  for(a = disp->areas ; a ; a = a->next) {
+    if(a != area) {
+      l = a;
+      continue;
+    }
+    if(l)
+      l->next = a->next;
+    else
+      disp->areas = NULL;
+    free(a);
+    return;
+  }
+  return;
+}
+
+osd_obj_t* osd_display_add_object(osd_display_t* disp,module_info_t* module,
+			    void* cfg) {
+  osd_obj_t* obj;
+  obj = calloc(1,sizeof(osd_obj_t));
+  obj->driver = module->entry;
+  obj->display = disp;
+
+  if(!obj->driver->init(obj,cfg)) {
+    free(obj);
+    return NULL;
+  }
+
+  obj->next = disp->objs;
+  disp->objs = obj;
+  
+  return obj;
+}
+
+
+int osd_object_set_size(osd_obj_t* obj,int width, int height) {
+  
+  if(obj->status == OSD_OBJ_DESTROY) {
+    printf("Wrong object state: %d\n",obj->status);
+    return 0;
+  }
+
+  if(!obj->driver->config(obj,width,height,obj->display->format)) {
+    printf("Failed to set config %d x %d 0x%x\n",width,height,
+	   obj->display->format);
+    return 0;
+  }
+
+  if(obj->status == OSD_OBJ_DISABLED)
+    obj->status = OSD_OBJ_HIDEN;
+
+  return 1;
+}
+
+void osd_object_move(osd_obj_t* o,int x, int y,int abs) {
+
+  if(abs) {
+    o->x = x;
+    o->y = y;
+  } else {
+    o->x += x;
+    o->y += y;
+  }
+  
+  if(o->status == OSD_OBJ_SHOWN)
+    o->status = OSD_OBJ_DRAWING;
+}
+
+int osd_object_show(osd_obj_t* obj,int show) {
+  if(obj->status == OSD_OBJ_DESTROY || obj->status == OSD_OBJ_DISABLED) {
+    printf("Wrong object state: %d\n",obj->status);
+    return 0;
+  }
+
+  if(show)
+    obj->status = OSD_OBJ_DRAWING;
+  else
+    obj->status = OSD_OBJ_HIDEN;
+
+  return 1;
+}
+
+
+void osd_display_del_object(osd_display_t* disp,osd_obj_t* obj) {
+  osd_obj_t *o;
+
+  for(o = disp->objs ; o ; o = o->next ) {
+    if(o != obj) continue;
+    if(o->driver && o->driver->uninit)
+      o->driver->uninit(o);
+    // Set the destroy state
+    o->status = OSD_OBJ_DESTROY;
+    return;
+  }
+  return;
+}
+
+int osd_display_config(osd_display_t* disp,int width,int height,unsigned format) {
+  osd_obj_t *o;
+  int fail = 0;
+
+  disp->width = width;
+  disp->height = height;
+  disp->format = format;
+
+  for(o = disp->objs ; o ; o = o->next ) {
+    if(o->status == OSD_OBJ_DESTROY) continue;
+    if(!o->driver->config(o,o->w,o->h,format)) {
+      o->status = OSD_OBJ_DISABLED;
+      fail++;
+      continue;
+    }
+    if(o->status == OSD_OBJ_DISABLED)
+      o->status = OSD_OBJ_HIDEN;
+  }
+  return fail;
+}
+
+int osd_display_show_all(osd_display_t* disp) {
+  osd_obj_t *o;
+  int fail = 0;
+
+  for(o = disp->objs ; o ; o = o->next ) {
+    if(!osd_object_show(o,1))
+      fail++;
+  }
+  return fail;
+}
+
+void osd_display_free(osd_display_t* disp) {
+  // TODO
+  
+}
+
--- /dev/null	Mon Jul 18 01:46:18 1994
+++ /home/alban/MP/g2.dev/osd/osd.h	Sun Jul 20 16:48:41 2003
@@ -0,0 +1,118 @@
+
+// TEMP:
+//  osd need to be redraw all the time
+
+// STATIC:
+//  osd don't need to be redraw at every frames
+//  original data must be saved to clear the buffer (or call a provided
+//  clear func)
+
+// IP(B):
+//  we can't draw osd on that.
+#define OSD_BUF_TEMP   0
+#define OSD_BUF_STATIC 1
+#define OSD_BUF_LOCKED 2
+
+// Area flags
+#define OSD_AREA_UPDATED 1
+
+// Object status
+#define OSD_OBJ_DISABLED 0
+#define OSD_OBJ_HIDEN 1
+#define OSD_OBJ_DRAWING 2
+#define OSD_OBJ_SHOWN 3
+#define OSD_OBJ_DESTROY 4
+
+#define OSD_OBJ_HAS_BBOX 1
+
+typedef struct osd_area_st osd_area_t;
+struct osd_area_st {
+  int x,y;
+  int w,h;
+  int buffer_type; // TEMP, STATIC, LOCKED
+  int flags; // unused atm
+  osd_area_t* next;
+};
+
+typedef struct osd_obj_st osd_obj_t;
+typedef struct osd_display_st osd_display_t;
+
+typedef struct osd_obj_driver_st {
+  int (*init)(osd_obj_t*,void* param);
+  int (*config)(osd_obj_t*,int width,int height,unsigned format);
+  int (*draw)(osd_obj_t*,mp_image_t*);
+  int (*control)(osd_obj_t*,int,void*);
+  void (*uninit)(osd_obj_t*);
+} osd_obj_driver_t;
+
+
+typedef struct osd_obj_status_st osd_obj_status_t;
+typedef struct osd_obj_priv_st osd_obj_priv_t;
+
+struct osd_obj_st {
+  int x,y;
+  int w,h;
+  int bb_x,bb_y,bb_h,bb_w; // If the object is in fact smaller than the requested size
+  int status;
+  int flags; // HAS_BBOX
+  unsigned int draw_id; // auto inc at each new draw
+  osd_display_t* display;  // display to wich we are attached
+  osd_obj_t* next;
+  osd_obj_driver_t* driver;
+  osd_obj_status_t* recs; // Per buffer status records
+  osd_obj_priv_t* priv;
+};
+
+// Callback used to clear static areas
+typedef int (*osd_clear_func_t)(osd_display_t* disp, mp_image_t* mpi,
+				int x,int y,int w, int h);
+
+struct osd_obj_status_st {
+  mp_image_t mpi; // Image used for draws in this buffer
+  void* buffer; // Pointer to the buffer start (as id)
+  int x,y; // Upper left corner of the mpi
+  int w,h;
+  unsigned int draw_id; // Draw id
+  osd_obj_status_t* next;
+};
+
+struct osd_display_st {
+  int width,height;
+  float aspect_ratio;
+  unsigned int format;
+  int buffer_type; // TEMP, STATIC
+  int flags; // dirty flags for static
+  osd_area_t* areas; // desc of various sub area properties
+  // clear callback
+  osd_clear_func_t clear;
+  // objs attached to the display
+  osd_obj_t* objs;
+};
+
+
+osd_display_t* osd_display_new(int width,int height,unsigned int format,
+			       int buf_type);
+
+osd_area_t* osd_display_add_area(osd_display_t* disp,int x,int y, int w, int h,
+				 int buffer_type);
+void osd_display_del_area(osd_display_t* disp,osd_area_t* area);
+
+osd_obj_t* osd_display_add_object(osd_display_t* disp,module_info_t* module,
+				  void* cfg);
+
+int osd_display_config(osd_display_t* disp,int width,int height,unsigned format);
+
+void osd_object_move(osd_obj_t* obj,int x, int y,int abs);
+int osd_object_set_size(osd_obj_t* obj,int width, int height);
+int osd_object_show(osd_obj_t* obj,int show);
+
+int osd_display_show_all(osd_display_t* disp);
+void osd_display_del_object(osd_display_t* disp,osd_obj_t* obj);
+
+
+int osd_display_draw(osd_display_t* disp, mp_image_t* mpi);
+int osd_display_clear(osd_display_t* disp, mp_image_t* mpi);
+
+void osd_display_free(osd_display_t* disp);
+
+module_info_t* find_osd_obj(char* name);
--- /home/alban/MP/g2/video/Makefile	Mon May 12 01:47:03 2003
+++ /home/alban/MP/g2.dev/video/Makefile	Fri Jul 18 18:13:06 2003
@@ -12,7 +12,7 @@
 VIDEO_SRCS=dec_video.c vd.c $(VIDEO_SRCS_NAT) $(VIDEO_SRCS_LIB) $(VIDEO_SRCS_OPT)
 
 # vf_vo.c 
-VFILTER_SRCS=vf.c vf_scale.c vf_vo2.c vf_vd.c vf_pp.c vf_format.c vf_tfields.c # vf_crop.c vf_expand.c # vf_format.c vf_flip.c vf_rgb2bgr.c vf_rotate.c vf_mirror.c vf_palette.c vf_lavc.c vf_dvbscale.c vf_cropdetect.c vf_test.c vf_noise.c vf_rectangle.c vf_eq.c vf_eq2.c vf_halfpack.c vf_dint.c vf_1bpp.c vf_bmovl.c vf_2xsai.c vf_unsharp.c vf_swapuv.c vf_il.c vf_boxblur.c vf_sab.c vf_smartblur.c vf_perspective.c vf_down3dright.c vf_field.c vf_denoise3d.c vf_hqdn3d.c vf_detc.c vf_telecine.c vf_tfields.c 
+VFILTER_SRCS=vf.c vf_scale.c vf_vo2.c vf_vd.c vf_pp.c vf_format.c vf_tfields.c vf_osd.c # vf_crop.c vf_expand.c # vf_format.c vf_flip.c vf_rgb2bgr.c vf_rotate.c vf_mirror.c vf_palette.c vf_lavc.c vf_dvbscale.c vf_cropdetect.c vf_test.c vf_noise.c vf_rectangle.c vf_eq.c vf_eq2.c vf_halfpack.c vf_dint.c vf_1bpp.c vf_bmovl.c vf_2xsai.c vf_unsharp.c vf_swapuv.c vf_il.c vf_boxblur.c vf_sab.c vf_smartblur.c vf_perspective.c vf_down3dright.c vf_field.c vf_denoise3d.c vf_hqdn3d.c vf_detc.c vf_telecine.c vf_tfields.c 
 ENCODER_SRCS=ve.c # ve_lavc.c # ve_divx4.c ve_vfw.c ve_rawrgb.c ve_libdv.c ve_xvid.c ve_qtvideo.c ve_nuv.c
 
 # NATIVE_SRCS=native/RTjpegN.c native/cinepak.c native/fli.c native/minilzo.c native/msvidc.c native/nuppelvideo.c native/qtrle.c native/qtrpza.c native/qtsmc.c native/roqav.c native/xa_gsm.c native/svq1.c
--- /home/alban/MP/g2/video/vf.c	Sun Jul 13 23:52:25 2003
+++ /home/alban/MP/g2.dev/video/vf.c	Sat Jul 19 16:07:52 2003
@@ -60,11 +60,13 @@
 extern vf_info_t vf_info_detc;
 extern vf_info_t vf_info_telecine;
 extern vf_info_t vf_info_tfields;
+extern vf_info_t vf_info_osd;
 
 //char** vo_plugin_args=(char**) NULL;
 
 // list of available filters:
 static vf_info_t* filter_list[]={
+    &vf_info_osd,
     &vf_info_scale,
     &vf_info_vo2,
     &vf_info_vd,
@@ -128,7 +130,7 @@
     int y;
     if(mpi->flags&MP_IMGFLAG_PLANAR){
 	y0&=~1;h+=h&1;
-	if(x0==0 && w==mpi->width){
+	if(x0==0 && w==mpi->width && w == mpi->stride[0]){
 	    // full width clear:
 	    memset(mpi->planes[0]+mpi->stride[0]*y0,0,mpi->stride[0]*h);
 	    memset(mpi->planes[1]+mpi->stride[1]*(y0>>mpi->chroma_y_shift),128,mpi->stride[1]*(h>>mpi->chroma_y_shift));
--- /dev/null	Mon Jul 18 01:46:18 1994
+++ /home/alban/MP/g2.dev/video/vf_osd.c	Sun Jul 20 18:07:01 2003
@@ -0,0 +1,253 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "config.h"
+#include "mp_msg.h"
+
+#include "img_format.h"
+#include "mp_image.h"
+#include "vf.h"
+#include "fastmemcpy.h"
+
+#include "cfg.h"
+#include "osd/osd.h"
+
+
+static struct config_data_s {
+  int w,h;
+  int x,y;
+  int force_osd;
+  config_modlist_t* objs;
+} cfg_def = {
+  0,0,
+  -1,-1,
+  0,
+  NULL
+};
+
+static config_t cfg_opts[] = {
+  {"w",&cfg_def.w, CONF_TYPE_INT, CONF_MIN, 0, 0, NULL, "Expand to width"},
+  {"h",&cfg_def.h, CONF_TYPE_INT, CONF_MIN, 0, 0, NULL, "Expand to height"},
+  {"x",&cfg_def.x, CONF_TYPE_INT, CONF_MIN, -1, 0, NULL, "Expand offset"},
+  {"y",&cfg_def.y, CONF_TYPE_INT, CONF_MIN, -1, 0, NULL, "Expand offset"},
+  {"force",&cfg_def.force_osd, CONF_TYPE_FLAG,0, 0, 1, NULL, "Alway draw osd everywhere"},
+  {"objs",&cfg_def.objs, CONF_TYPE_MODLIST, 0, 0, 0, find_osd_obj, "object"},
+  {NULL, NULL, 0, 0, 0, 0, NULL, NULL}
+};
+
+
+struct vf_priv_s {
+  osd_display_t* disp;
+  osd_area_t* m_area;
+  int exp_x,exp_y,exp_w,exp_h;
+  int x,y,w,h;
+  int force_osd;
+  int n;
+};
+
+static int osd_clear_func(osd_display_t* disp, mp_image_t* mpi,
+			  int x,int y,int w, int h) {
+  //printf("------- Clear ------  %d x %d (%d x %d)\n",x,y,w,h);
+  vf_mpi_clear(mpi,x,y,w,h);
+  return 1;
+}
+
+int config(struct vf_instance_s* vf,
+        int width, int height, int d_width, int d_height,
+	   unsigned int flags, unsigned int outfmt) {
+  vf->priv->exp_w = vf->priv->w > width ? vf->priv->w : width;
+  vf->priv->exp_h = vf->priv->h > height ? vf->priv->h : height;
+
+  vf->priv->exp_x = vf->priv->x >= 0 ? vf->priv->x : (vf->priv->exp_w - width)/2;
+  vf->priv->exp_y = vf->priv->y >= 0 ? vf->priv->y : (vf->priv->exp_h - height)/2;
+
+  if(vf->priv->exp_x + width > vf->priv->exp_w ||
+     vf->priv->exp_y + height > vf->priv->exp_h)
+    return 0;
+
+  if(vf->priv->exp_w > width || vf->priv->exp_h > height) {
+    if(!vf->priv->m_area) {
+      vf->priv->m_area = osd_display_add_area(vf->priv->disp,
+					      vf->priv->exp_x,
+					      vf->priv->exp_y,
+					      width,height,
+					      OSD_BUF_TEMP);
+      vf->priv->disp->buffer_type = OSD_BUF_STATIC;
+    } else {
+      vf->priv->m_area->x = vf->priv->exp_x;
+      vf->priv->m_area->y = vf->priv->exp_y;
+      vf->priv->m_area->w = width;
+      vf->priv->m_area->h = height;
+    }
+  } else {
+    if(vf->priv->m_area) {
+      osd_display_del_area(vf->priv->disp,vf->priv->m_area);
+      vf->priv->m_area = NULL;
+      vf->priv->disp->buffer_type = OSD_BUF_TEMP;
+    }
+  }
+  osd_display_config(vf->priv->disp,vf->priv->exp_w,vf->priv->exp_h,outfmt);
+  //osd_display_show_all(vf->priv->disp);
+  return vf_next_config(vf,vf->priv->exp_w,vf->priv->exp_h,vf->priv->exp_w,vf->priv->exp_h,flags,outfmt);
+}
+
+void get_image(struct vf_instance_s* vf,
+	       mp_image_t *mpi) {
+  mp_image_t *dmpi = NULL;
+
+  if(vf->priv->exp_w==mpi->width ||
+     (mpi->flags&(MP_IMGFLAG_ACCEPT_STRIDE|MP_IMGFLAG_ACCEPT_WIDTH)) ){
+    // try full DR !
+    if(vf->priv->force_osd && mpi->type != MP_IMGTYPE_TEMP)
+      return;
+    mpi->priv=dmpi=vf_get_image_cloned(vf->next,mpi,mpi->imgfmt,
+				mpi->type, mpi->flags, 
+				vf->priv->exp_w,vf->priv->exp_h);
+    // set up mpi as a cropped-down image of dmpi:
+    if(mpi->flags&MP_IMGFLAG_PLANAR){
+      mpi->planes[0]=dmpi->planes[0]+
+	vf->priv->exp_y*dmpi->stride[0]+vf->priv->exp_x;
+      mpi->planes[1]=dmpi->planes[1]+
+	(vf->priv->exp_y>>mpi->chroma_y_shift)*dmpi->stride[1]+(vf->priv->exp_x>>mpi->chroma_x_shift);
+      mpi->planes[2]=dmpi->planes[2]+
+	(vf->priv->exp_y>>mpi->chroma_y_shift)*dmpi->stride[2]+(vf->priv->exp_x>>mpi->chroma_x_shift);
+      mpi->stride[1]=dmpi->stride[1];
+      mpi->stride[2]=dmpi->stride[2];
+    } else {
+      mpi->planes[0]=dmpi->planes[0]+
+	vf->priv->exp_y*dmpi->stride[0]+
+	vf->priv->exp_x*(dmpi->bpp/8);
+    }
+    mpi->stride[0]=dmpi->stride[0];
+    //    mpi->width=dmpi->width;
+    mpi->flags|=MP_IMGFLAG_DIRECT;
+    if(mpi->type != MP_IMGTYPE_TEMP) {
+      if(vf->priv->m_area)
+	vf->priv->m_area->buffer_type = OSD_BUF_LOCKED;
+      else
+	vf->priv->disp->buffer_type = OSD_BUF_LOCKED;
+    } else {
+      if(vf->priv->m_area)
+	vf->priv->m_area->buffer_type = OSD_BUF_TEMP;
+      else
+	vf->priv->disp->buffer_type = OSD_BUF_TEMP;
+    }
+  }
+}
+    
+
+inline static void copy_mpi(mp_image_t *dmpi, mp_image_t *mpi, int x, int y) {
+  if(mpi->flags&MP_IMGFLAG_PLANAR){
+    memcpy_pic(dmpi->planes[0] + y*dmpi->stride[0] + x,
+	       mpi->planes[0], mpi->width, mpi->height,
+	       dmpi->stride[0],mpi->stride[0]);
+    memcpy_pic(dmpi->planes[1] + y/2*dmpi->stride[1] + x/2,
+	       mpi->planes[1], mpi->chroma_width, mpi->chroma_height,
+	       dmpi->stride[1],mpi->stride[1]);
+    memcpy_pic(dmpi->planes[2] + y/2*dmpi->stride[2] + x/2,
+	       mpi->planes[2], mpi->chroma_width, mpi->chroma_height,
+	       dmpi->stride[2],mpi->stride[2]);
+  } else {
+    memcpy_pic(dmpi->planes[0] + y*dmpi->stride[0] + x*(dmpi->bpp/8),
+	       mpi->planes[0],
+	       mpi->width*(mpi->bpp/8), mpi->height,
+	       dmpi->stride[0],mpi->stride[0]);
+  }
+}
+
+mp_image_t* process_image(struct vf_instance_s* vf, mp_image_t* mpi,int drop) {
+  mp_image_t* dmpi = mpi->priv;
+
+
+  if(!(mpi->flags&MP_IMGFLAG_DIRECT) || !dmpi) {
+    dmpi = vf_get_image_cloned(vf->next,mpi,mpi->imgfmt,
+			       MP_IMGTYPE_TEMP, 0,
+			       vf->priv->exp_w, vf->priv->exp_h);
+    if(!dmpi) return NULL;
+    copy_mpi(dmpi,mpi,vf->priv->exp_x,vf->priv->exp_y);
+  } else
+    vf_clone_mpi(dmpi,mpi);
+
+  osd_display_clear(vf->priv->disp,dmpi);
+  osd_display_draw(vf->priv->disp,dmpi);
+
+
+  if(vf->priv->disp->objs) {
+    if(vf->priv->n%12 == 0)
+      osd_object_move(vf->priv->disp->objs,
+		     dmpi->width-( vf->priv->n % (dmpi->width + vf->priv->disp->objs->w) ),10,1);
+    if(vf->priv->n == 0)
+      osd_object_show(vf->priv->disp->objs,1);
+  }
+
+#if 0
+  if(vf->priv->disp->objs && vf->priv->n % 25 == 0) {
+    if(vf->priv->n % 50 == 0) {
+      printf("---- SHOW ---- \n");
+      osd_object_show(vf->priv->disp->objs,1);
+    } else {
+      printf("===== HIDE =====\n");
+      osd_object_show(vf->priv->disp->objs,0);
+    }
+  }
+#endif
+  vf->priv->n++;
+
+  return dmpi;
+}
+
+static int open(vf_instance_t *vf, void* cfg){
+  config_data_t* opts = vf->cfg ? vf->cfg : &cfg_def;
+
+  vf->config=config;
+  vf->get_image=get_image;
+  vf->process_image=process_image;
+  vf->priv=calloc(1,sizeof(struct vf_priv_s));
+
+  
+  
+  
+  vf->priv->disp = calloc(sizeof(osd_display_t),1);
+  vf->priv->disp->clear = osd_clear_func;
+  vf->priv->disp->buffer_type = OSD_BUF_TEMP;
+
+  vf->priv->x = opts->x;
+  vf->priv->y = opts->y;
+  vf->priv->w = opts->w;
+  vf->priv->h = opts->h;
+  vf->priv->force_osd = opts->force_osd;
+
+  if(opts->objs) {
+    int i;
+    printf("\n\n ADDIDNG OSD OBJ \n\n");
+    for(i = 0 ; opts->objs[i].mod ; i++) {
+      osd_obj_t* o = osd_display_add_object(vf->priv->disp, opts->objs[i].mod,
+					    opts->objs[i].cfg);
+      if(!o)
+	printf("Failed to add object %s\n",opts->objs[i].mod->name);
+      else {
+	printf("Added osd object %s\n",opts->objs[i].mod->name);
+      }
+    }
+  }
+
+  
+
+  return 1;
+}
+  
+  
+vf_info_t vf_info_osd  = {
+  MODULE_TYPE_VF, MODULE_VERSION,
+  open,
+  "osd",
+  "on screen display",
+  "Albeu",
+  "Albeu",
+  "",
+  0,
+  cfg_opts, &cfg_def, sizeof(struct config_data_s)
+};
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.