OSD

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

I worked a bit on OSD. Here is my current work. Comment are welcome :)
	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, 27.4 KB)
--- /home/alban/MP/g2/Makefile	Thu Jul 10 22:54:15 2003
+++ /home/alban/MP/g2.dev/Makefile	Fri Jul 18 18:15:06 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)
--- /home/alban/MP/g2/cfg-l1.c	Sat Jul  5 22:27:02 2003
+++ /home/alban/MP/g2.dev/cfg-l1.c	Fri Jul 18 13:38:59 2003
@@ -12,6 +12,34 @@
 
 #define CFG_STRING_LIST_SEPARATOR ','
 
+static char* esc_strchr(char* str,char c) {
+  int esc;
+
+  if(!str) return NULL;
+
+  for(esc = 0 ; str[0] ; str++) {
+    if(str[0] == '(') esc++;
+    else if(str[0] == ')') esc--;
+    else if(esc > 0) continue;
+    else if(str[0] == c) break;
+  }
+
+  return str[0] == c ? str : NULL;
+}
+
+static char* esc_strdup(char* str) {
+  int l;
+  if(!str) return NULL;
+  l = strlen(str);
+  if(l < 2) return strdup(str);
+  if(str[0] == '(' && str[l-1] == ')') {
+    char* r = strdup(str+1);
+    r[l-2] = '\0';
+    return r;
+  }
+  return strdup(str);
+}
+
 int mpconfig_parse_param(module_info_t* mod, config_t* cd, config_data_t* cfg, char* param){
 //    int i;
     long tmp_int;
@@ -173,10 +201,11 @@
 	    while(m){
 		module_info_t* mymod=NULL;
 		config_modinfo_t mi_func=cd->priv;
-		char* q=strchr(m,',');
+		char* q=esc_strchr(m,',');
 		char* r;
 		if(q){ *q=0; ++q; }
 		r=strchr(m,'=');
+		if(q && r > q) r = NULL;
 		if(r){ *r=0; ++r; }
 		mymod=mi_func(m); // find module
 		if(!mymod){
@@ -304,9 +333,9 @@
 	mp_msg(MSGT_CFGPARSER, MSGL_ERR, "[%s] this module have no config options\n",mod->name);
 	return CFG_ERR_INVALID;
     }
-    p=subconfig=strdup(subconfig);
+    p=subconfig=esc_strdup(subconfig);
     while(p && *p){
-	q=strchr(p,':');
+	q=esc_strchr(p,':');
 	if(q){ *q=0; ++q; };
 	r=strchr(p,'=');
 	if(r){
--- /home/alban/MP/g2/cfg.h	Thu Jul 10 22:03:45 2003
+++ /home/alban/MP/g2.dev/cfg.h	Fri Jul 18 17:35:57 2003
@@ -101,7 +101,9 @@
   MODULE_TYPE_AF,
   MODULE_TYPE_AD,
   MODULE_TYPE_AE,
-  MODULE_TYPE_AO
+  MODULE_TYPE_AO,
+
+  MODULE_TYPE_OSD
 } module_type_t;
 
 typedef struct config_data_s config_data_t;
--- /dev/null	Mon Jul 18 01:46:18 1994
+++ /home/alban/MP/g2.dev/osd/Makefile	Fri Jul 18 18:24:12 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 $(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	Sat Jul 19 14:48:34 2003
@@ -0,0 +1,79 @@
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "cfg.h"
+#include "img_format.h"
+#include "mp_image.h"
+#include "osd.h"
+
+
+
+static int init(osd_obj_t*obj,void* param) {
+  printf("Obj init :)\n");
+  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 i,j;
+  char* dst;
+
+  if(!mpi) return 0;
+
+  dst = mpi->planes[0];
+  for(i = 0 ; i < mpi->height ; i++) {
+    for(j = 0 ; j < mpi->height ; j++) {
+      if(!((j+(i%2))% 4))
+	 dst[j] = 255;
+      //else
+      //dst[j] = 255;
+    }
+    dst += mpi->stride[0];
+  }
+  obj->status = OSD_OBJ_SHOWN;
+  printf("\nObject drawn %d\n",obj->draw_id);
+  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,
+  NULL,
+  NULL,
+  0
+};
--- /dev/null	Mon Jul 18 01:46:18 1994
+++ /home/alban/MP/g2.dev/osd/osd.c	Sat Jul 19 14:50:34 2003
@@ -0,0 +1,371 @@
+#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;
+}
+
+
+static int osd_obj_in(osd_obj_t* o,int buf_type) {
+  osd_display_t* disp = o->display;
+  osd_area_t* a;
+  
+  for(a = disp->areas ; a ; a = a->next) {
+    if(a->buffer_type != buf_type) {
+      // Fully contained in the wrong buffer type
+      if(o->x >= a->x && o->x+o->w <= a->x+a->w &&
+	 o->y >= a->y && o->y+o->h <= a->y+a->h)
+	return 0;
+      // FIX ME
+      // Here we should in fact check the resting parts
+      // of the object but atm it doesn't matter.
+      continue;
+    }
+    // Doesn't cross the area
+    if(o->x+o->w < a->x || o->x >= a->x+a->w ||
+       o->y+o->h < a->y || o->y >= a->y+a->h)
+      continue;
+    // Match !!!
+    return 1;
+  }
+  return (disp && buf_type == disp->buffer_type);
+}
+
+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)
+    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 -1;
+   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;
+   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;
+
+  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;
+  
+  // Clear it
+  if(o->display->clear) r = o->display->clear(o->display,&rec->mpi);
+  // 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;
+}
+
+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	Sat Jul 19 12:35:30 2003
@@ -0,0 +1,120 @@
+
+// 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
+
+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; // dirty flags for static
+  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;
+
+struct osd_obj_st {
+  int x,y;
+  int w,h;
+  int status;
+  int flags;
+  unsigned int draw_id; // auto inc at each (real) draw
+  mp_image_t mpi; // Mpi we give to this object for draw
+  osd_display_t* display;
+  osd_obj_t* next;
+  osd_obj_driver_t* driver;
+  osd_obj_status_t* recs; // Per buffer records
+};
+
+typedef int (*osd_clear_func_t)(osd_display_t* disp, mp_image_t* mpi);
+
+struct osd_obj_status_st {
+  void* buffer; // Pointer to the buffer start (as id)
+  unsigned int draw_id; // Draw id
+  mp_image_t mpi;
+  osd_obj_status_t* next;
+};
+
+typedef struct osd_buffer_st osd_buffer_t;
+struct osd_buffer_st {
+  void* buffer;
+  int age;
+  osd_obj_status_t* objs;
+  osd_buffer_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;
+  osd_buffer_t* bufs; // buffers record for clearing
+  
+  // 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);
+
+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/test-play.c	Sun Jul 13 23:03:00 2003
+++ /home/alban/MP/g2.dev/test-play.c	Thu Jul 17 01:26:57 2003
@@ -468,16 +468,19 @@
 //		    time_frame=0;
 	    }
 	    // do sleeping!
-	    if(time_frame>0){
+	    if( !(video_out->buffer_flags & VO_BUFFER_FLAG_SLEEP)  ||
+		frame_time_remaining ) {
+	      if(time_frame>0){
 		time_frame/=playback_speed;
 		mp_msg(MSGT_AVSYNC,MSGL_DBG2,"time_frame=%5.3f\n",time_frame);
 		//usec_sleep((int)(time_frame*1000000.0));
 		time_frame=sleep_accurate(time_frame)*playback_speed;
+	      }
 	    }
 	    // display!
 	    if(!frame_time_remaining){
 		if(mpi && mpi->priv && video_out->show_frame)
-		    video_out->show_frame(video_out,(vo_buffer_t*)mpi->priv,0);
+		    video_out->show_frame(video_out,(vo_buffer_t*)mpi->priv,video_out->buffer_flags & VO_BUFFER_FLAG_SLEEP && time_frame > 0 ? time_frame/playback_speed : 0);
 		if(d_sub && !d_sub->eof)
 		  test_subs(d_sub,v_pts);
 		mpi=NULL;
@@ -509,7 +512,7 @@
 #endif
 	    sh_audio->delay+=x; c_total+=x;
 	    time_frame-=x; // for -autosync
-	    mp_msg(MSGT_AVSYNC,MSGL_STATUS,"A:%8.3f (%5.3f) V:%8.3f (%5.3f) A-V:%+7.4f ct:%7.4f d:%5.3f x:%+5.3f \r",
+	    mp_msg(MSGT_AVSYNC,MSGL_STATUS,"A:%8.3f (%5.3f) V:%8.3f (%+5.3f) A-V:%+7.4f ct:%7.4f d:%5.3f x:%+5.3f \r",
 		(float)(a_pts-delay), (float)((a_pts-delay) - old_apts),
 		 (float)v_pts, (float)(v_pts - old_vpts),
 		 AV_delay, c_total, delay, x);
--- /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	Fri Jul 18 18:12:46 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,
--- /dev/null	Mon Jul 18 01:46:18 1994
+++ /home/alban/MP/g2.dev/video/vf_osd.c	Sat Jul 19 14:51:03 2003
@@ -0,0 +1,245 @@
+
+#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) {
+  printf("------- Clear ------\n");
+  vf_mpi_clear(mpi,0,0,mpi->width,mpi->height);
+  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;
+    }
+    osd_display_clear(vf->priv->disp,dmpi);
+  }
+}
+    
+
+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*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*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;
+    osd_display_clear(vf->priv->disp,dmpi);
+    copy_mpi(dmpi,mpi,vf->priv->exp_x,vf->priv->exp_y);
+  } else
+    vf_clone_mpi(dmpi,mpi);
+
+  osd_display_draw(vf->priv->disp,dmpi);
+
+
+  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);
+    }
+  }
+  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);
+	o->w = o->h = 60;
+	o->x = o->y = 80;
+      }
+    }
+  }
+
+  
+
+  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.