diff options
author | Dubois Nicolas <sn00py.2@laposte.net> | 2007-12-27 14:24:48 +0000 |
---|---|---|
committer | Dubois Nicolas <sn00py.2@laposte.net> | 2007-12-27 14:24:48 +0000 |
commit | 84e2f56c6cc81e9bed8ba03b29a8c69aa7d08d89 (patch) | |
tree | d6ffee7ab1c4e184afd2459ae60d06de03e0d081 | |
parent | 0fed3e1eccfdbae81961b3aadff0375c54c9f8d5 (diff) | |
download | xine-lib-84e2f56c6cc81e9bed8ba03b29a8c69aa7d08d89.tar.gz xine-lib-84e2f56c6cc81e9bed8ba03b29a8c69aa7d08d89.tar.bz2 |
[Subtitles] SSA-tags patch
I watch a lot of movies with subtitles and I need "vobsub subtitles"
work in xine, then I decide to write this patch.
It may support SSA tags for all text subtiles (ssa, ass, srt, ...)
This patch :
1. Remove all SSA tags from stream (they are ugly : {\a6})
2. Handle some of them (b, i, a, an, pos). The other ones control
colours, shadow, animation, ... I can't make them work in an easy way.
3. Correct wrap algorithm which have minors bugs (we can see them only
with SSA patch...)
Modified files :
libsputext/demux_sputext.c
just remove unneeded code (which remove some of SSA-tags)
libsputext/xine_sputext_decoder.c
the main modified file.
video_out/video_out_xshm.c
video_out/video_out_xv.c
xine-engine/video_out.h
get video output (position and size). See below.
1.
Removing SSA tags is done in ogm_render_line_internal() like for
html-like tags. (this was done in the previous version of xine)
2.
b(bold) and i(italic) are implemented like html-ones, in
ogm_render_line_internal().
The other tags this patch support are :
aX : alignment in SSA-code
anX : alignment in numpad code
pos(X,Y) : position, depend on alignment
For those ones, I need in first a full-screen OSD, not a five lines one.
Then, I need to remember where the last subtitle was drawn, in order to
erase it. At last, I need a translation function to convert subtitle
coordinates in screen coordinates.
For this last point, I first write a full-screen translation (don't care
about blacks borders), but it's not really good: the 'pos' tag is
sometime used to point out something in the video. (Moreover, ASS spec
say we have to draw subtitle on the video)
For doing this, I need the real video output size and position, which
are only know by the video output driver! Then I had 4 VO properties
(in xine-engine/video_out.h) for video driver could give us those
informations.
I implement it only in xshm and xv drivers (I can't test other ones).
If video driver can't give us those informations, the patch fallback in
a full-screen translation.
3.
there was 3 problem with the wrap algorithm :
1. It was in double: exactly the same, twice. Look like a merge problem.
I remove one and all work fine.
2. It want to cut string in equivalent display length but it cut it in
equivalent byte length. In most cases, this is the same, but if we have
UTF-8 chars or long SSA-tags (which will not be displayed) the result is
strange.
3. If we have a too-long part (in bytes) of the string without spaces
(bad subtitle file or long SSA-code), the algorithm don't know what to
do. (this case is not handled)
I re-write the wrap algorithm to correct those problems. Note that my
version is slower than previous one : working with bytes is really
faster than computing text-length. Maybe I should had to propose an
other patch for this part...
-rw-r--r-- | src/libsputext/demux_sputext.c | 25 | ||||
-rw-r--r-- | src/libsputext/xine_sputext_decoder.c | 551 | ||||
-rw-r--r-- | src/video_out/video_out_xshm.c | 8 | ||||
-rw-r--r-- | src/video_out/video_out_xv.c | 12 | ||||
-rw-r--r-- | src/xine-engine/video_out.h | 6 |
5 files changed, 389 insertions, 213 deletions
diff --git a/src/libsputext/demux_sputext.c b/src/libsputext/demux_sputext.c index 502ef6580..acf8e10f6 100644 --- a/src/libsputext/demux_sputext.c +++ b/src/libsputext/demux_sputext.c @@ -382,31 +382,6 @@ static subtitle_t *sub_read_line_subrip(demux_sputext_t *this,subtitle_t *curren } else temp_line[temp_index++]=*p; break; - case '{': -#if 0 /* italic not implemented in renderer, ignore them for now */ - if(!strncmp(p,"{\\i1}",5) && temp_index+3<SUB_BUFSIZE) { - temp_line[temp_index++]='<'; - temp_line[temp_index++]='i'; - temp_line[temp_index++]='>'; -#else - if(!strncmp(p,"{\\i1}",5)) { -#endif - p+=4; - } -#if 0 /* italic not implemented in renderer, ignore them for now */ - else if(!strncmp(p,"{\\i0}",5) && temp_index+4<SUB_BUFSIZE) { - temp_line[temp_index++]='<'; - temp_line[temp_index++]='/'; - temp_line[temp_index++]='i'; - temp_line[temp_index++]='>'; -#else - else if(!strncmp(p,"{\\i0}",5)) { -#endif - p+=4; - } - else - temp_line[temp_index++]=*p; - break; case '\r': /* just ignore '\r's */ break; case '\n': diff --git a/src/libsputext/xine_sputext_decoder.c b/src/libsputext/xine_sputext_decoder.c index ed09380d4..1de1eb099 100644 --- a/src/libsputext/xine_sputext_decoder.c +++ b/src/libsputext/xine_sputext_decoder.c @@ -41,6 +41,26 @@ #define SUB_MAX_TEXT 5 /* lines */ #define SUB_BUFSIZE 256 /* chars per line */ +/* alignment in SSA codes */ +#define ALIGN_LEFT 1 +#define ALIGN_CENTER 2 +#define ALIGN_RIGHT 3 +#define ALIGN_BOTTOM 0 +#define ALIGN_TOP 4 +#define ALIGN_MIDDLE 8 +#define GET_X_ALIGNMENT(a) ((a) & 3) +#define GET_Y_ALIGNMENT(a) ((a) - ((a) & 3)) + +/* subtitles projection */ +/* for subrip file with SSA tags, those values are always correct.*/ +/* But for SSA files, those values are the default ones. we have */ +/* to use PlayResX and PlayResY defined in [Script Info] section. */ +/* not implemented yet... */ +#define SPU_PROJECTION_X 384 +#define SPU_PROJECTION_Y 288 + + + #define rgb2yuv(R,G,B) ((((((66*R+129*G+25*B+128)>>8)+16)<<8)|(((112*R-94*G-18*B+128)>>8)+128))<<8|(((-38*R-74*G+112*B+128)>>8)+128)) static uint32_t sub_palette[22]={ @@ -106,6 +126,15 @@ typedef struct sputext_class_s { } sputext_class_t; +/* Convert subtiles coordinates in window coordinates. */ +/* (a, b) --> (x + a * dx, y + b * dy) */ +typedef struct video2wnd_s { + int x; + int y; + double dx; + double dy; +} video2wnd_t; + typedef struct sputext_decoder_s { spu_decoder_t spu_decoder; @@ -141,7 +170,9 @@ typedef struct sputext_decoder_s { int64_t last_subtitle_end; /* no new subtitle before this vpts */ int unscaled; /* use unscaled OSD */ + int last_y; /* location of the previous subtitle */ int last_lines; /* number of lines of the previous subtitle */ + video2wnd_t video2wnd; } sputext_decoder_t; static inline char *get_font (sputext_class_t *class) @@ -156,8 +187,6 @@ static inline char *get_font (sputext_class_t *class) static void update_font_size (sputext_decoder_t *this, int force_update) { static int sizes[SUBTITLE_SIZE_NUM] = { 16, 20, 24, 32, 48, 64 }; - int y; - if ((this->subtitle_size != this->class->subtitle_size) || (this->vertical_offset != this->class->vertical_offset) || force_update) { @@ -170,21 +199,17 @@ static void update_font_size (sputext_decoder_t *this, int force_update) { this->line_height = this->font_size + 10; - y = this->height - (SUB_MAX_TEXT * this->line_height) - 5; - - if(((y - this->class->vertical_offset) >= 0) && ((y - this->class->vertical_offset) <= this->height)) - y -= this->class->vertical_offset; - + /* Create a full-window OSD */ if( this->osd ) this->renderer->free_object (this->osd); - lprintf("new osd object, width %d, height %d*%d\n", this->width, SUB_MAX_TEXT, this->line_height); this->osd = this->renderer->new_object (this->renderer, this->width, - SUB_MAX_TEXT * this->line_height); + this->height); this->renderer->set_font (this->osd, get_font (this->class), this->font_size); - this->renderer->set_position (this->osd, 0, y); + + this->renderer->set_position (this->osd, 0, 0); } } @@ -208,7 +233,7 @@ static void update_output_size (sputext_decoder_t *this) { VO_PROP_WINDOW_HEIGHT) || !this->img_duration || !this->osd ) { - int width = 0, height = 0; /* dummy */ + int width = 0, height = 0; this->stream->video_out->status(this->stream->video_out, NULL, &width, &height, &this->img_duration ); @@ -220,8 +245,36 @@ static void update_output_size (sputext_decoder_t *this) { VO_PROP_WINDOW_HEIGHT); if(!this->osd || (this->width && this->height)) { + + /* in unscaled mode, we have to convert subtitle position in window coordinates. */ + /* we have a scale factor because video may be zommed */ + /* and a displacement factor because video may have blacks lines. */ + int output_width, output_height, output_xoffset, output_yoffset; + + output_width = this->stream->video_out->get_property(this->stream->video_out, + VO_PROP_OUTPUT_WIDTH); + output_height = this->stream->video_out->get_property(this->stream->video_out, + VO_PROP_OUTPUT_HEIGHT); + output_xoffset = this->stream->video_out->get_property(this->stream->video_out, + VO_PROP_OUTPUT_XOFFSET); + output_yoffset = this->stream->video_out->get_property(this->stream->video_out, + VO_PROP_OUTPUT_YOFFSET); + + /* driver don't seen to be capable to give us those values */ + /* fallback to a default full-window values */ + if (output_width <= 0 || output_height <= 0) { + output_width = this->width; + output_height = this->height; + output_xoffset = 0; + output_yoffset = 0; + } + + this->video2wnd.x = output_xoffset; + this->video2wnd.y = output_yoffset; + this->video2wnd.dx = (double)output_width / SPU_PROJECTION_X; + this->video2wnd.dy = (double)output_height / SPU_PROJECTION_Y; + this->renderer = this->stream->osd_renderer; - update_font_size (this, 1); } } @@ -238,6 +291,12 @@ static void update_output_size (sputext_decoder_t *this) { if(!this->osd || ( this->width && this->height)) { this->renderer = this->stream->osd_renderer; + /* in scaled mode, we have to convert subtitle position in film coordinates. */ + this->video2wnd.x = 0; + this->video2wnd.y = 0; + this->video2wnd.dx = (double)this->width / SPU_PROJECTION_X; + this->video2wnd.dy = (double)this->height / SPU_PROJECTION_Y; + update_font_size (this, 1); } } @@ -270,7 +329,8 @@ static int parse_utf8_size(unsigned char *c) static int ogm_render_line_internal(sputext_decoder_t *this, int x, int y, const char *text, int render) { - int i = 0, w, dummy; + int i = 0, w, value; + char* end; char letter[5]={0, 0, 0, 0, 0}; const char *encoding = this->buf_encoding ? this->buf_encoding : this->class->src_encoding; @@ -278,55 +338,82 @@ static int ogm_render_line_internal(sputext_decoder_t *this, int x, int y, const size_t length = strlen (text); while (i <= length) { - switch (text[i]) { - case '<': + + if (text[i] == '<') { if (!strncmp("<b>", text+i, 3)) { /* enable Bold color */ if (render) this->current_osd_text = OSD_TEXT2; i=i+3; - break; + continue; } else if (!strncmp("</b>", text+i, 4)) { /* disable BOLD */ if (render) this->current_osd_text = OSD_TEXT1; i=i+4; - break; + continue; } else if (!strncmp("<i>", text+i, 3)) { /* enable italics color */ if (render) this->current_osd_text = OSD_TEXT3; i=i+3; - break; + continue; } else if (!strncmp("</i>", text+i, 4)) { /* disable italics */ if (render) this->current_osd_text = OSD_TEXT1; i=i+4; - break; + continue; } else if (!strncmp("<font>", text+i, 6)) { /*Do somethink to disable typing fixme - no teststreams*/ i=i+6; - break; + continue; } else if (!strncmp("</font>", text+i, 7)) { /*Do somethink to enable typing fixme - no teststreams*/ i=i+7; - break; - } - default: - shift = isutf8 ? parse_utf8_size (&text[i]) : 1; - memcpy(letter,&text[i],shift); - letter[shift]=0; - - if (render) - this->renderer->render_text(this->osd, x, y, letter, this->current_osd_text); - this->renderer->get_text_size(this->osd, letter, &w, &dummy); - x=x+w; - i+=shift; + continue; + } + } + if (text[i] == '{') { + + if (!strncmp("{\\", text+i, 2)) { + + if (sscanf(text+i, "{\\b%d}", &value) == 1) { + if (render) { + if (value) + this->current_osd_text = OSD_TEXT2; + else + this->current_osd_text = OSD_TEXT1; + } + } else if (sscanf(text+i, "{\\i%d}", &value) == 1) { + if (render) { + if (value) + this->current_osd_text = OSD_TEXT3; + else + this->current_osd_text = OSD_TEXT1; + } + } + end = strstr(text+i+2, "}"); + if (end) { + i=end-text+1; + continue; + } + } } + + shift = isutf8 ? parse_utf8_size (&text[i]) : 1; + memcpy(letter,&text[i],shift); + letter[shift]=0; + + if (render) + this->renderer->render_text(this->osd, x, y, letter, this->current_osd_text); + this->renderer->get_text_size(this->osd, letter, &w, &value); + x=x+w; + i+=shift; } + return x; } @@ -338,16 +425,103 @@ static inline void ogm_render_line(sputext_decoder_t *this, int x, int y, char* ogm_render_line_internal (this, x, y, text, 1); } +/* read SSA tags at begening of text. Suported tags are : */ +/* \a : alignment in SSA code (see #defines) */ +/* \an : alignment in 'numpad code' */ +/* \pos : absolute position of subtitles. Alignment define origin. */ +static void read_ssa_tag(sputext_decoder_t *this, const char* text, + int* alignment, int* sub_x, int* sub_y, int* max_width) { + + int in_tag = 0; + + (*alignment) = 2; + (*sub_x) = -1; + (*sub_y) = -1; + + while (*text) { + + /* wait for tag begin, allow space and tab */ + if (in_tag == 0) { + if (*text == '{') in_tag = 1; + else if ((*text != ' ') && (*text != '\t')) break; + + /* parse SSA command */ + } else { + if (*text == '\\') { + if (sscanf(text, "\\pos(%d,%d)", sub_x, sub_y) == 2) { + text += 8; /* just for speed up, 8 is the minimal with */ + } + + if (sscanf(text, "\\a%d", alignment) == 1) { + text += 2; + } + + if (sscanf(text, "\\an%d", alignment) == 1) { + text += 3; + if ((*alignment) > 6) (*alignment) = (*alignment) - 2; + else if ((*alignment) > 3) (*alignment) = (*alignment) + 5; + } + } + + if (*text == '}') in_tag = 0; + } + + text++; + } + + + /* check alignment validity */ + if ((*alignment) < 1 || (*alignment) > 11) { + (*alignment) = 2; + } + + /* convert to window coordinates */ + if ((*sub_x) >= 0 && (*sub_y) >= 0) { + (*sub_x) = this->video2wnd.x + this->video2wnd.dx * (*sub_x); + (*sub_y) = this->video2wnd.y + this->video2wnd.dy * (*sub_y); + } + + /* check validity, compute max width */ + if ( (*sub_x) < 0 || (*sub_x) >= this->width || + (*sub_y) < 0 || (*sub_y) >= this->height ) { + (*sub_x) = -1; + (*sub_y) = -1; + (*max_width) = this->width; + } else { + switch (GET_X_ALIGNMENT(*alignment)) { + case ALIGN_LEFT: + (*max_width) = this->width - (*sub_x); + break; + case ALIGN_CENTER: + (*max_width) = this->width; + break; + case ALIGN_RIGHT: + (*max_width) = (*sub_x); + break; + } + } + + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + "libsputext: position : (%d, %d), max width : %d, alignment : %d\n", + (*sub_x), (*sub_y), (*max_width), (*alignment)); +} + static void draw_subtitle(sputext_decoder_t *this, int64_t sub_start, int64_t sub_end ) { int line, y; int font_size; char *font; + int sub_x, sub_y, max_width; + int alignment; + int rebuild_all; + _x_assert(this->renderer != NULL); if ( ! this->renderer ) return; + read_ssa_tag(this, this->text[0], &alignment, &sub_x, &sub_y, &max_width); + update_font_size(this, 0); font = get_font (this->class); @@ -363,178 +537,181 @@ static void draw_subtitle(sputext_decoder_t *this, int64_t sub_start, int64_t su else this->renderer->set_encoding(this->osd, this->class->src_encoding); - for (line = 0; line < this->lines; line++) /* first, check lenghts and word-wrap if needed */ - { - int w; - w = ogm_get_width( this, this->text[line]); - if( w > this->width ) { /* line is too long */ - int chunks=(int)(w/this->width)+(w%this->width?1:0); - if( this->lines+chunks <= SUB_MAX_TEXT && chunks>1 ) { /* try adding newlines while keeping existing ones */ - int a; - xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG,"Partial subtitle line splitting in %i chunks\n",chunks); - for(a=this->lines-1;a>=0;a--) { - if(a>line) /* lines after the too-long one */ - memcpy(this->text[a+chunks-1],this->text[a],SUB_BUFSIZE); - else if(a==line) { /* line to be splitted */ - int b,len=strlen(this->text[line]); - char *p=this->text[line]; - for(b=0;b<chunks;b++) { - char *c; - if(b==chunks-1) { /* if we are reading the last chunk, copy it completly */ - strncpy(this->text[line+b],p,SUB_BUFSIZE); - this->text[line+b][SUB_BUFSIZE - 1] = '\0'; - } else { - for(c=p+(int)(len/chunks)+(len%chunks?1:0);*c!=' ' && c>p && c!='\0';c--); - if(*c==' ') { - *c='\0'; - if(b) { /* we are reading something that has to be moved to another line */ - strncpy(this->text[line+b],p,SUB_BUFSIZE); - this->text[line+b][SUB_BUFSIZE - 1] = '\0'; - } - p=c+1; - } - } - } - } - } - this->lines+=chunks-1; - } else { /* regenerate all the lines to find something that better fits */ - char buf[SUB_BUFSIZE*SUB_MAX_TEXT]; - int a,w,chunks; - buf[0]='\0'; - for(a=0;a<this->lines;a++) { - if(a) { - int len=strlen(buf); - buf[len]=' '; - buf[len+1]='\0'; - } - strcat(buf,this->text[a]); + + rebuild_all = 0; + for (line = 0; line < this->lines; line++) { + int line_width = ogm_get_width(this, this->text[line]); + + /* line too long */ + if (line_width > max_width) { + char *current_cut, *best_cut; + int a; + + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + "libsputext: Line too long: %d > %d, split at max size.\n", + line_width, max_width); + + /* can't fit with keeping existing lines */ + if (this->lines + 1 > SUB_MAX_TEXT) { + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + "libsputext: Can't fit with keeping existing line, we have to rebuild all the subtitle\n"); + rebuild_all = 1; + break; + } + + /* find the longest sequence witch fit */ + line_width = 0; + current_cut = this->text[line]; + best_cut = NULL; + while (line_width < max_width) { + while (*current_cut && *current_cut != ' ') current_cut++; + if (*current_cut == ' ') { + *current_cut = 0; + line_width = ogm_get_width(this, this->text[line]); + *current_cut = ' '; + if (line_width < max_width) best_cut = current_cut; + current_cut++; + } else { + break; /* end of line */ } - w = ogm_get_width( this, buf); - chunks=(int)(w/this->width)+(w%this->width?1:0); - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "Complete subtitle line splitting in %i chunks\n",chunks); - if(chunks<=SUB_MAX_TEXT) {/* if the length is over than SUB_MAX_TEXT*this->width nothing can be done */ - int b,len=strlen(buf); - char *p=buf; - for(b=0;b<chunks;b++) { - char *c; - if(b==chunks-1) { /* if we are reading the last chunk, copy it completly */ - strncpy(this->text[b],p,SUB_BUFSIZE); - this->text[b][SUB_BUFSIZE - 1] = '\0'; - } else { - for(c=p+(int)(len/chunks)+(len%chunks?1:0);*c!=' ' && c>p && c!='\0';c--); - if(*c==' ') { - *c='\0'; - strncpy(this->text[b],p,SUB_BUFSIZE); - this->text[b][SUB_BUFSIZE - 1] = '\0'; - p=c+1; - } - } - } - this->lines=chunks; - } else - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "Subtitle too long to be splited\n"); - line=this->lines; } + + if (best_cut == NULL) { + xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, + "libsputext: Can't wrap line: a word is too long, abort.\n"); + break; + } + + /* move other lines */ + for (a = this->lines - 1; a > line; a--) + memcpy(this->text[a + 1], this->text[a], SUB_BUFSIZE); + + /* split current one */ + strncpy(this->text[line + 1], best_cut + 1, SUB_BUFSIZE); + *best_cut = 0; + + this->lines = this->lines + 1; } } - font_size = this->font_size; - if (this->buf_encoding) - this->renderer->set_encoding(this->osd, this->buf_encoding); - else - this->renderer->set_encoding(this->osd, this->class->src_encoding); + /* regenerate all the lines to find something that better fits */ + if (rebuild_all) { + int line, line_width; + char *stream, *current_cut, *best_cut; + char buf[SUB_BUFSIZE * SUB_MAX_TEXT]; + + buf[0] = 0; + for(line = 0; line < this->lines; line++) { + int len = strlen(buf); + if (len) { + buf[len] = ' '; + len++; + } + strncpy(buf + len, this->text[line], SUB_BUFSIZE); + *(buf + len + SUB_BUFSIZE) = 0; + } - for (line = 0; line < this->lines; line++) /* first, check lenghts and word-wrap if needed */ - { - int w; - w = ogm_get_width( this, this->text[line]); - if( w > this->width ) { /* line is too long */ - int chunks=(int)(w/this->width)+(w%this->width?1:0); - if( this->lines+chunks <= SUB_MAX_TEXT && chunks>1 ) { /* try adding newlines while keeping existing ones */ - int a; - xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG,"Partial subtitle line splitting in %i chunks\n",chunks); - for(a=this->lines-1;a>=0;a--) { - if(a>line) /* lines after the too-long one */ - memcpy(this->text[a+chunks-1],this->text[a],SUB_BUFSIZE); - else if(a==line) { /* line to be splitted */ - int b,len=strlen(this->text[line]); - char *p=this->text[line]; - for(b=0;b<chunks;b++) { - char *c; - if(b==chunks-1) { /* if we are reading the last chunk, copy it completly */ - strncpy(this->text[line+b],p,SUB_BUFSIZE); - this->text[line+b][SUB_BUFSIZE - 1] = '\0'; - } else { - for(c=p+(int)(len/chunks)+(len%chunks?1:0);*c!=' ' && c>p && c!='\0';c--); - if(*c==' ') { - *c='\0'; - if(b) { /* we are reading something that has to be moved to another line */ - strncpy(this->text[line+b],p,SUB_BUFSIZE); - this->text[line+b][SUB_BUFSIZE - 1] = '\0'; - } - p=c+1; - } - } - } - } - } - this->lines+=chunks-1; - } else { /* regenerate all the lines to find something that better fits */ - char buf[SUB_BUFSIZE*SUB_MAX_TEXT]; - int a,w,chunks; - buf[0]='\0'; - for(a=0;a<this->lines;a++) { - if(a) { - int len=strlen(buf); - buf[len]=' '; - buf[len+1]='\0'; + stream = buf; + this->lines = 0; + + do { + + if (this->lines + 1 < SUB_MAX_TEXT) { + + /* find the longest sequence witch fit */ + line_width = 0; + current_cut = stream; + best_cut = NULL; + while (line_width < max_width) { + while (*current_cut && *current_cut != ' ') current_cut++; + if (*current_cut == ' ') { + *current_cut = 0; + line_width = ogm_get_width(this, stream); + *current_cut = ' '; + if (line_width < max_width) best_cut = current_cut; + current_cut++; + } else { + line_width = ogm_get_width(this, stream); + if (line_width < max_width) best_cut = current_cut; + break; /* end of line */ } - strcat(buf,this->text[a]); } - w = ogm_get_width( this, buf); - chunks=(int)(w/this->width)+(w%this->width?1:0); - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "Complete subtitle line splitting in %i chunks\n",chunks); - if(chunks<=SUB_MAX_TEXT) {/* if the length is over than SUB_MAX_TEXT*this->width nothing can be done */ - int b,len=strlen(buf); - char *p=buf; - for(b=0;b<chunks;b++) { - char *c; - if(b==chunks-1) { /* if we are reading the last chunk, copy it completly */ - strncpy(this->text[b],p,SUB_BUFSIZE); - this->text[b][SUB_BUFSIZE - 1] = '\0'; - } else { - for(c=p+(int)(len/chunks)+(len%chunks?1:0);*c!=' ' && c>p && c!='\0';c--); - if(*c==' ') { - *c='\0'; - strncpy(this->text[b],p,SUB_BUFSIZE); - this->text[b][SUB_BUFSIZE - 1] = '\0'; - p=c+1; - } - } - } - this->lines=chunks; - } else - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "Subtitle too long to be splited\n"); - line=this->lines; } - } + + /* line maybe too long, but we have reached last subtitle line */ + else { + best_cut = current_cut = stream + strlen(stream); + } + + /* copy current line */ + if (best_cut != NULL) *best_cut = 0; + strncpy(this->text[this->lines], stream, SUB_BUFSIZE); + this->lines = this->lines + 1; + + stream = best_cut + 1; + + } while (best_cut != current_cut); + } - if (this->last_lines) - this->renderer->filled_rect (this->osd, 0, this->line_height * (SUB_MAX_TEXT - this->last_lines), - this->width - 1, this->line_height * SUB_MAX_TEXT - 1, 0); - this->last_lines = this->lines; - y = (SUB_MAX_TEXT - this->lines) * this->line_height; + + /* Erase subtitle : use last_y and last_lines saved last turn. */ + if (this->last_lines) { + this->renderer->filled_rect (this->osd, 0, this->last_y, + this->width - 1, this->last_y + this->last_lines * this->line_height, + 0); + } + + switch (GET_Y_ALIGNMENT(alignment)) { + case ALIGN_TOP: + if (sub_y >= 0) y = sub_y; + else y = 5; + break; + + case ALIGN_MIDDLE: + if (sub_y >= 0) y = sub_y - (this->lines * this->line_height) / 2; + else y = (this->height - this->lines * this->line_height) / 2; + break; + + case ALIGN_BOTTOM: + default: + if (sub_y >= 0) y = sub_y - this->lines * this->line_height; + else y = this->height - this->lines * this->line_height - this->class->vertical_offset; + break; + } + if (y < 0 || y >= this->height) + y = this->height - this->line_height * this->lines; + + this->last_lines = this->lines; + this->last_y = y; + for (line = 0; line < this->lines; line++) { int w, x; while(1) { w = ogm_get_width( this, this->text[line]); - x = (this->width - w) / 2; - - if( w > this->width && font_size > 16 ) { + + switch (GET_X_ALIGNMENT(alignment)) { + case ALIGN_LEFT: + if (sub_x >= 0) x = sub_x; + else x = 5; + break; + + case ALIGN_RIGHT: + if (sub_x >= 0) x = sub_x - w; + else x = max_width - w - 5; + break; + + case ALIGN_CENTER: + default: + if (sub_x >= 0) x = sub_x - w / 2; + else x = (max_width - w) / 2; + break; + } + + + if( w > max_width && font_size > 16 ) { font_size -= 4; this->renderer->set_font (this->osd, get_font (this->class), font_size); } else { diff --git a/src/video_out/video_out_xshm.c b/src/video_out/video_out_xshm.c index bf0d3b7f0..932f22e3a 100644 --- a/src/video_out/video_out_xshm.c +++ b/src/video_out/video_out_xshm.c @@ -820,6 +820,14 @@ static int xshm_get_property (vo_driver_t *this_gen, int property) { return this->sc.gui_width; case VO_PROP_WINDOW_HEIGHT: return this->sc.gui_height; + case VO_PROP_OUTPUT_WIDTH: + return this->cur_frame->sc.output_width; + case VO_PROP_OUTPUT_HEIGHT: + return this->cur_frame->sc.output_height; + case VO_PROP_OUTPUT_XOFFSET: + return this->cur_frame->sc.output_xoffset; + case VO_PROP_OUTPUT_YOFFSET: + return this->cur_frame->sc.output_yoffset; default: xprintf(this->xine, XINE_VERBOSITY_DEBUG, "video_out_xshm: tried to get unsupported property %d\n", property); diff --git a/src/video_out/video_out_xv.c b/src/video_out/video_out_xv.c index 7ff7b64e5..3bb0a93dc 100644 --- a/src/video_out/video_out_xv.c +++ b/src/video_out/video_out_xv.c @@ -871,6 +871,18 @@ static int xv_get_property (vo_driver_t *this_gen, int property) { case VO_PROP_WINDOW_HEIGHT: this->props[property].value = this->sc.gui_height; break; + case VO_PROP_OUTPUT_WIDTH: + this->props[property].value = this->sc.output_width; + break; + case VO_PROP_OUTPUT_HEIGHT: + this->props[property].value = this->sc.output_height; + break; + case VO_PROP_OUTPUT_XOFFSET: + this->props[property].value = this->sc.output_xoffset; + break; + case VO_PROP_OUTPUT_YOFFSET: + this->props[property].value = this->sc.output_yoffset; + break; } lprintf("video_out_xv: property #%d = %d\n", property, this->props[property].value); diff --git a/src/xine-engine/video_out.h b/src/xine-engine/video_out.h index 308e809f1..4d9c80565 100644 --- a/src/xine-engine/video_out.h +++ b/src/xine-engine/video_out.h @@ -245,7 +245,11 @@ struct xine_video_port_s { #define VO_PROP_WINDOW_HEIGHT 16 /* read-only */ #define VO_PROP_BUFS_IN_FIFO 17 /* read-only */ #define VO_PROP_NUM_STREAMS 18 /* read-only */ -#define VO_NUM_PROPERTIES 19 +#define VO_PROP_OUTPUT_WIDTH 19 /* read-only */ +#define VO_PROP_OUTPUT_HEIGHT 20 /* read-only */ +#define VO_PROP_OUTPUT_XOFFSET 21 /* read-only */ +#define VO_PROP_OUTPUT_YOFFSET 22 /* read-only */ +#define VO_NUM_PROPERTIES 23 /* number of colors in the overlay palette. Currently limited to 256 at most, because some alphablend functions use an 8-bit index into |