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)
+};