2 * Copyright (C) 2005-2013 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
21 #include "utils/log.h"
22 #include "DVDOverlayRenderer.h"
23 #include "DVDCodecs/Overlay/DVDOverlaySpu.h"
24 #include "DVDCodecs/Overlay/DVDOverlayText.h"
25 #include "DVDCodecs/Overlay/DVDOverlayImage.h"
26 #include "DVDCodecs/Overlay/DVDOverlaySSA.h"
28 #define CLAMP(a, min, max) ((a) > (max) ? (max) : ( (a) < (min) ? (min) : a ))
31 void CDVDOverlayRenderer::Render(DVDPictureRenderer* pPicture, CDVDOverlay* pOverlay, double pts)
33 if (pOverlay->IsOverlayType(DVDOVERLAY_TYPE_SPU))
35 // display subtitle, if bForced is true, it's a menu overlay and we should crop it
36 Render_SPU_YUV(pPicture, pOverlay, pOverlay->bForced);
38 else if (pOverlay->IsOverlayType(DVDOVERLAY_TYPE_IMAGE))
40 Render(pPicture, (CDVDOverlayImage*)pOverlay);
42 else if (pOverlay->IsOverlayType(DVDOVERLAY_TYPE_SSA))
44 Render(pPicture, (CDVDOverlaySSA*)pOverlay, pts);
46 else if (false && pOverlay->IsOverlayType(DVDOVERLAY_TYPE_TEXT))
48 CDVDOverlayText* pOverlayText = (CDVDOverlayText*)pOverlay;
50 //CLog::Log(LOGDEBUG, " - s: %i, e: %i", (int)(pOverlayText->iPTSStartTime / 1000), (int)(pOverlayText->iPTSStopTime / 1000));
52 CDVDOverlayText::CElement* e = pOverlayText->m_pHead;
55 if (e->IsElementType(CDVDOverlayText::ELEMENT_TYPE_TEXT))
57 CDVDOverlayText::CElementText* t = (CDVDOverlayText::CElementText*)e;
58 CLog::Log(LOGDEBUG, " - %s", t->m_text);
66 void CDVDOverlayRenderer::Render(DVDPictureRenderer* pPicture, CDVDOverlaySSA* pOverlay, double pts)
70 height = pPicture->height;
71 width = pPicture->width;
73 ASS_Image* img = pOverlay->m_libass->RenderImage(width, height, pts);
77 DWORD color = img->color;
78 BYTE alpha = (BYTE)(color &0xff);
80 // fully transparent or width or height is 0 -> not displayed
81 if(alpha == 255 || img->w == 0 || img->h == 0)
87 //ASS_Image colors are RGBA
88 double r = ((color >> 24) & 0xff) / 255.0;
89 double g = ((color >> 16) & 0xff) / 255.0;
90 double b = ((color >> 8 ) & 0xff) / 255.0;
92 BYTE luma = (BYTE)( 255 * CLAMP( 0.299 * r + 0.587 * g + 0.114 * b, 0.0, 1.0));
93 BYTE v = (BYTE)(127.5 + 255 * CLAMP( 0.500 * r - 0.419 * g - 0.081 * b, -0.5, 0.5));
94 BYTE u = (BYTE)(127.5 + 255 * CLAMP(-0.169 * r - 0.331 * g + 0.500 * b, -0.5, 0.5));
96 int y = std::max(0,std::min(img->dst_y, pPicture->height-img->h));
97 int x = std::max(0,std::min(img->dst_x, pPicture->width-img->w));
99 for(int i=0; i<img->h; i++)
101 if(y + i >= pPicture->height)
104 BYTE* line = img->bitmap + img->stride*i;
107 target[0] = pPicture->data[0] + pPicture->stride[0]*(i + y) + x;
108 target[1] = pPicture->data[1] + pPicture->stride[1]*((i + y)>>1) + (x>>1);
109 target[2] = pPicture->data[2] + pPicture->stride[2]*((i + y)>>1) + (x>>1);
111 for(int j=0; j<img->w; j++)
113 if(x + j >= pPicture->width)
116 unsigned char index, opacity, k;
119 //Blend the image with the underlying picture
120 opacity = 255 - alpha;
121 k = (unsigned char)index * opacity / 255;
123 target[0][j] = (k*luma + (255-k)*target[0][j])/255;
124 target[1][j>>1] = (k*u + (255-k)*target[1][j>>1])/255;
125 target[2][j>>1] = (k*v + (255-k)*target[2][j>>1])/255;
132 void CDVDOverlayRenderer::Render(DVDPictureRenderer* pPicture, CDVDOverlayImage* pOverlay)
136 palette[i] = (BYTE*)calloc(1, pOverlay->palette_colors);
138 for(int i=0;i<pOverlay->palette_colors;i++)
140 uint32_t color = pOverlay->palette[i];
142 palette[3][i] = (BYTE)((color >> 24) & 0xff);
144 double r = ((color >> 16) & 0xff) / 255.0;
145 double g = ((color >> 8 ) & 0xff) / 255.0;
146 double b = ((color >> 0 ) & 0xff) / 255.0;
148 palette[0][i] = (BYTE)(255 * CLAMP(0.299 * r + 0.587 * g + 0.114 * b, 0.0, 1.0));
149 palette[1][i] = (BYTE)(127.5 + 255 * CLAMP( 0.500 * r - 0.419 * g - 0.081 * b, -0.5, 0.5));
150 palette[2][i] = (BYTE)(127.5 + 255 * CLAMP(-0.169 * r - 0.331 * g + 0.500 * b, -0.5, 0.5));
153 // we try o fit it in if it's outside the image
154 int y = std::max(0,std::min(pOverlay->y, pPicture->height-pOverlay->height));
155 int x = std::max(0,std::min(pOverlay->x, pPicture->width-pOverlay->width));
157 for(int i=0;i<pOverlay->height;i++)
159 if(y + i >= pPicture->height)
162 BYTE* line = pOverlay->data + pOverlay->linesize*i;
165 target[0] = pPicture->data[0] + pPicture->stride[0]*(i + y) + x;
166 target[1] = pPicture->data[1] + pPicture->stride[1]*((i + y)>>1) + (x>>1);
167 target[2] = pPicture->data[2] + pPicture->stride[2]*((i + y)>>1) + (x>>1);
169 for(int j=0;j<pOverlay->width;j++)
171 if(x + j >= pPicture->width)
174 unsigned char index = line[j];
175 if(index > pOverlay->palette_colors)
177 CLog::Log(LOGWARNING, "%s - out of range color index %u", __FUNCTION__, index);
181 if(palette[3][index] == 0)
184 int s_blend = palette[3][index] + 1;
185 int t_blend = 256 - s_blend;
187 target[0][j] = (target[0][j] * t_blend + palette[0][index] * s_blend) >> 8;
190 target[1][j>>1] = (target[1][j>>1] * t_blend + palette[1][index] * s_blend) >> 8;
191 target[2][j>>1] = (target[2][j>>1] * t_blend + palette[2][index] * s_blend) >> 8;
200 // render the parsed sub (parsed rle) onto the yuv image
201 void CDVDOverlayRenderer::Render_SPU_YUV(DVDPictureRenderer* pPicture, CDVDOverlay* pOverlaySpu, bool bCrop)
203 CDVDOverlaySpu* pOverlay = (CDVDOverlaySpu*)pOverlaySpu;
205 unsigned __int8* p_destptr = NULL;
206 unsigned __int16* p_source = (unsigned __int16*)pOverlay->result;
207 unsigned __int8* p_dest[3];
210 int rp_len, i_color, pixels_to_draw;
211 unsigned __int16 i_colprecomp, i_destalpha;
213 int btn_x_start = pOverlay->crop_i_x_start;
214 int btn_x_end = pOverlay->crop_i_x_end;
215 int btn_y_start = pOverlay->crop_i_y_start;
216 int btn_y_end = pOverlay->crop_i_y_end;
221 p_dest[0] = pPicture->data[0] + pPicture->stride[0] * pOverlay->y;
222 p_dest[1] = pPicture->data[1] + pPicture->stride[1] * (pOverlay->y >> 1);
223 p_dest[2] = pPicture->data[2] + pPicture->stride[2] * (pOverlay->y >> 1);
225 /* Draw until we reach the bottom of the subtitle */
226 for (i_y = pOverlay->y; i_y < pOverlay->y + pOverlay->height; i_y++)
228 /* Draw until we reach the end of the line */
229 for (i_x = pOverlay->x; i_x < pOverlay->x + pOverlay->width ; i_x += rp_len)
231 /* Get the RLE part, then draw the line */
232 i_color = *p_source & 0x3;
233 rp_len = *p_source++ >> 2;
237 pixels_to_draw = rp_len;
239 p_color = pOverlay->color[i_color];
240 p_alpha = pOverlay->alpha[i_color];
244 if (i_y >= btn_y_start && i_y <= btn_y_end)
246 if (i_x < btn_x_start && i_x + rp_len >= btn_x_start) // starts outside
247 pixels_to_draw = btn_x_start - i_x;
248 else if( i_x >= btn_x_start && i_x <= btn_x_end ) // starts inside
250 p_color = pOverlay->highlight_color[i_color];
251 p_alpha = pOverlay->highlight_alpha[i_color];
252 pixels_to_draw = btn_x_end - i_x + 1; // don't draw part that is outside
255 /* make sure we are not requested to draw to far */
256 /* that part will be taken care of in next pass */
257 if( pixels_to_draw > rp_len )
258 pixels_to_draw = rp_len;
267 memset(p_dest[0] + i_x, p_color[0], pixels_to_draw);
268 if (!(i_y & 1)) // Only draw even lines
270 memset(p_dest[1] + (i_x >> 1), p_color[2], pixels_to_draw >> 1);
271 memset(p_dest[2] + (i_x >> 1), p_color[1], pixels_to_draw >> 1);
276 /* To be able to divide by 16 (>>4) we add 1 to the alpha.
277 * This means Alpha 0 won't be completely transparent, but
278 * that's handled in a special case above anyway. */
279 // First we deal with Y
280 i_colprecomp = (unsigned __int16)p_color[0]
281 * (unsigned __int16)(p_alpha + 1);
282 i_destalpha = 15 - p_alpha;
284 for (p_destptr = p_dest[0] + i_x; p_destptr < p_dest[0] + i_x + pixels_to_draw; p_destptr++)
286 *p_destptr = (( i_colprecomp + (unsigned __int16) * p_destptr * i_destalpha ) >> 4) & 0xFF;
289 if (!(i_y & 1)) // Only draw even lines
292 i_colprecomp = (unsigned __int16)p_color[2]
293 * (unsigned __int16)(p_alpha + 1);
294 for ( p_destptr = p_dest[1] + (i_x >> 1); p_destptr < p_dest[1] + ((i_x + pixels_to_draw) >> 1); p_destptr++)
296 *p_destptr = (( i_colprecomp + (unsigned __int16) * p_destptr * i_destalpha ) >> 4) & 0xFF;
299 i_colprecomp = (unsigned __int16)p_color[1]
300 * (unsigned __int16)(p_alpha + 1);
301 for ( p_destptr = p_dest[2] + (i_x >> 1); p_destptr < p_dest[2] + ((i_x + pixels_to_draw) >> 1); p_destptr++)
303 *p_destptr = (( i_colprecomp + (unsigned __int16) * p_destptr * i_destalpha ) >> 4) & 0xFF;
309 /* add/subtract what we just drew */
310 rp_len -= pixels_to_draw;
311 i_x += pixels_to_draw;
315 p_dest[0] += pPicture->stride[0];
318 p_dest[1] += pPicture->stride[1];
319 p_dest[2] += pPicture->stride[2];