|
MythTV
0.26-pre
|
00001 /* Based on xqcam.c by Paul Chinn <loomer@svpal.org> */ 00002 00003 // C headers 00004 #include <cmath> 00005 00006 // POSIX headers 00007 #include <sys/ipc.h> 00008 #include <sys/shm.h> 00009 00010 // MythTV headers 00011 #include "osd.h" 00012 #include "osdchromakey.h" 00013 00014 #include "mythlogging.h" 00015 #include "videoout_xv.h" 00016 #include "mythxdisplay.h" 00017 00018 #ifdef MMX 00019 extern "C" { 00020 #include "ffmpeg-mmx.h" 00021 } 00022 #endif 00023 00024 #define LOC QString("OSDChroma: ") 00025 00026 ChromaKeyOSD::~ChromaKeyOSD(void) 00027 { 00028 TearDown(); 00029 } 00030 00031 bool ChromaKeyOSD::CreateShmImage(QSize area) 00032 { 00033 if (!videoOutput || area.isEmpty()) 00034 return false; 00035 00036 uint size = 0; 00037 MythXDisplay *disp = videoOutput->disp; 00038 MythXLocker lock(disp); 00039 Display *d = disp->GetDisplay(); 00040 int screen_num = disp->GetScreen(); 00041 00042 XImage *shm_img = 00043 XShmCreateImage(d, DefaultVisual(d,screen_num), 00044 disp->GetDepth(), ZPixmap, 0, 00045 &shm_infos, area.width(),area.height()); 00046 if (shm_img) 00047 size = shm_img->bytes_per_line * (shm_img->height+1) + 128; 00048 00049 shm_infos.shmid = 0; 00050 shm_infos.shmaddr = NULL; 00051 if (shm_img) 00052 { 00053 shm_infos.shmid = shmget(IPC_PRIVATE, size, IPC_CREAT|0777); 00054 if (shm_infos.shmid >= 0) 00055 { 00056 shm_infos.shmaddr = (char*) shmat(shm_infos.shmid, 0, 0); 00057 00058 shm_img->data = shm_infos.shmaddr; 00059 shm_infos.readOnly = False; 00060 00061 XShmAttach(d, &shm_infos); 00062 disp->Sync(); // needed for FreeBSD? 00063 00064 // Mark for delete immediately. 00065 // It won't actually be removed until after we detach it. 00066 shmctl(shm_infos.shmid, IPC_RMID, 0); 00067 img = shm_img; 00068 return true; 00069 } 00070 } 00071 return false; 00072 } 00073 00074 void ChromaKeyOSD::DestroyShmImage(void) 00075 { 00076 if (!img || !videoOutput) 00077 return; 00078 00079 MythXDisplay *disp = videoOutput->disp; 00080 disp->Lock(); 00081 XShmDetach(disp->GetDisplay(), &shm_infos); 00082 XFree(img); 00083 img = NULL; 00084 disp->Unlock(); 00085 00086 if (shm_infos.shmaddr) 00087 shmdt(shm_infos.shmaddr); 00088 if (shm_infos.shmid > 0) 00089 shmctl(shm_infos.shmid, IPC_RMID, 0); 00090 00091 memset(&shm_infos, 0, sizeof(XShmSegmentInfo)); 00092 } 00093 00094 bool ChromaKeyOSD::Init(QSize new_size) 00095 { 00096 if (current_size == new_size) 00097 return true; 00098 00099 TearDown(); 00100 00101 bool success = CreateShmImage(new_size); 00102 image = new QImage(new_size, QImage::Format_ARGB32_Premultiplied); 00103 painter = new MythQImagePainter(); 00104 00105 if (success && image && painter) 00106 { 00107 current_size = new_size; 00108 image->fill(0); 00109 LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Created ChromaOSD size %1x%2") 00110 .arg(current_size.width()) 00111 .arg(current_size.height())); 00112 return true; 00113 } 00114 00115 LOG(VB_PLAYBACK, LOG_ERR, LOC + QString("Failed to create ChromaOSD.")); 00116 return false; 00117 } 00118 00119 void ChromaKeyOSD::TearDown(void) 00120 { 00121 DestroyShmImage(); 00122 00123 if (image) 00124 { 00125 delete image; 00126 image = NULL; 00127 } 00128 00129 if (painter) 00130 { 00131 delete painter; 00132 painter = NULL; 00133 } 00134 } 00135 00136 #define MASK 0xFE000000 00137 #define MMX_MASK 0xFE000000FE000000LL 00138 00139 void ChromaKeyOSD::BlendOrCopy(uint32_t colour, const QRect &rect) 00140 { 00141 int width = rect.width(); 00142 int height = rect.height(); 00143 if (!width || !height) 00144 return; 00145 00146 uint src_stride = image->bytesPerLine(); 00147 uint dst_stride = img->bytes_per_line; 00148 unsigned char *src = image->bits() + 00149 (rect.top() * src_stride) + (rect.left() << 2); 00150 unsigned char *dst = (unsigned char*)shm_infos.shmaddr + 00151 (rect.top() * dst_stride) + (rect.left() << 2); 00152 00153 if (colour == 0x0) 00154 { 00155 for (int i = 0; i < height; i++) 00156 { 00157 memcpy(dst, src, width << 2); 00158 src += src_stride; 00159 dst += dst_stride; 00160 } 00161 return; 00162 } 00163 00164 src_stride = src_stride >> 2; 00165 dst_stride = dst_stride >> 2; 00166 00167 #ifdef MMX 00168 bool odd_start = rect.left() & 0x1; 00169 bool odd_end = (rect.left() + rect.width()) & 0x1; 00170 static mmx_t mask = {MMX_MASK}; 00171 static mmx_t zero = {0x0000000000000000LL}; 00172 uint32_t *src_start = (uint32_t*)src; 00173 uint32_t *dst_start = (uint32_t*)dst; 00174 uint32_t *src_end = NULL; 00175 uint32_t *dst_end = NULL; 00176 00177 if (odd_end) 00178 { 00179 width--; 00180 src_end = src_start + width; 00181 dst_end = dst_start + width; 00182 } 00183 00184 if (odd_start) 00185 { 00186 src += 4; dst += 4; 00187 width--; 00188 } 00189 00190 uint64_t *source = (uint64_t*)src; 00191 uint64_t *dest = (uint64_t*)dst; 00192 #else 00193 uint32_t *source = (uint32_t*)src; 00194 uint32_t *dest = (uint32_t*)dst; 00195 #endif 00196 00197 for (int i = 0; i < height; i++) 00198 { 00199 #ifdef MMX 00200 if (odd_start) 00201 { 00202 dst_start[0] = (src_start[0] & MASK) ? src_start[0] : colour; 00203 src_start += src_stride; 00204 dst_start += dst_stride; 00205 } 00206 00207 if (odd_end) 00208 { 00209 dst_end[0] = (src_end[0] & MASK) ? src_end[0] : colour; 00210 src_end += src_stride; 00211 dst_end += dst_stride; 00212 } 00213 00214 punpckldq_m2r (colour, mm0); 00215 punpckhdq_r2r (mm0, mm0); 00216 for (int j = 0; j < (width >> 1); j++) 00217 { 00218 movq_m2r (source[j], mm1); 00219 pand_m2r (mask, mm1); 00220 pcmpeqd_m2r (zero, mm1); 00221 movq_r2r (mm1, mm2); 00222 pand_r2r (mm0, mm1); 00223 pandn_m2r (source[j], mm2); 00224 por_r2r (mm1, mm2); 00225 movq_r2m (mm2, dest[j]); 00226 } 00227 source += src_stride >> 1; 00228 dest += dst_stride >> 1; 00229 #else 00230 for (int j = 0; j < width; j++) 00231 dest[j] = (source[j] & MASK) ? source[j] : colour; 00232 source += src_stride; 00233 dest += dst_stride; 00234 #endif 00235 } 00236 00237 #ifdef MMX 00238 emms(); 00239 #endif 00240 } 00241 00246 bool ChromaKeyOSD::ProcessOSD(OSD *osd) 00247 { 00248 if (!osd || !videoOutput) 00249 return false; 00250 00251 QRect osd_rect = videoOutput->GetTotalOSDBounds(); 00252 if (!Init(osd_rect.size())) 00253 return false; 00254 00255 bool was_visible = visible; 00256 QRect video_rect = videoOutput->window.GetDisplayVideoRect(); 00257 QRegion dirty = QRegion(); 00258 QRegion vis_area = osd->Draw(painter, image, current_size, dirty); 00259 visible = !vis_area.isEmpty(); 00260 00261 if (dirty.isEmpty() && (video_rect == current_rect)) 00262 return (visible || was_visible); 00263 00264 if (video_rect != current_rect) 00265 dirty = osd_rect; 00266 00267 current_rect = video_rect; 00268 uint32_t letterbox = (uint32_t)videoOutput->XJ_letterbox_colour; 00269 uint32_t colorkey = (uint32_t)videoOutput->xv_colorkey; 00270 00271 int boboff = (int) round( 00272 ((double)current_size.height()) / 456 - 0.00001); 00273 boboff = (videoOutput->m_deinterlacing && 00274 videoOutput->m_deintfiltername == "bobdeint") ? boboff : 0; 00275 00276 video_rect.adjust(0, boboff, 0, -boboff); 00277 video_rect = video_rect.intersected(osd_rect); 00278 00279 QRect top = QRect(0, 0, osd_rect.width(), video_rect.top()); 00280 QRect left = QRect(0, video_rect.top(), video_rect.left(), video_rect.height()); 00281 QRect right = QRect(video_rect.left() + video_rect.width(), video_rect.top(), 00282 osd_rect.width() - video_rect.width() - video_rect.left(), 00283 video_rect.height()); 00284 QRect bot = QRect(0, video_rect.top() + video_rect.height(), osd_rect.width(), 00285 osd_rect.height() - video_rect.top() - video_rect.height()); 00286 00287 QVector<QRect> update = dirty.rects(); 00288 for (int i = 0; i < update.size(); i++) 00289 { 00290 BlendOrCopy(letterbox, update[i].intersected(top)); 00291 BlendOrCopy(letterbox, update[i].intersected(left)); 00292 BlendOrCopy(colorkey, update[i].intersected(video_rect)); 00293 BlendOrCopy(letterbox, update[i].intersected(right)); 00294 BlendOrCopy(letterbox, update[i].intersected(bot)); 00295 } 00296 00297 return (visible || was_visible); 00298 } 00299
1.7.6.1