1 /* X11 layer of subversion library to intercept RealPlayer socket and
2 device I/O. --20011101 */
12 static unsigned long root_window
=0;
13 static unsigned long rpshell_window
=0;
14 static unsigned long rpmain_window
=0;
15 static unsigned long rpmenu_window
=0;
16 static unsigned long rpplay_window
=0;
17 static long rpplay_width
=0;
18 static long rpplay_height
=0;
20 static long logo_y
=-1;
21 static long logo_prev
=-1;
23 static long play_blackleft
=-1;
24 static long play_blackright
=-1;
25 static long play_blackupper
=-1;
26 static long play_blacklower
=-1;
28 static unsigned long rpvideo_window
=0;
29 static int video_width
=-1;
30 static int video_height
=-1;
32 static unsigned long rpauth_shell
=0;
33 static unsigned long rpauth_main
=0;
34 static unsigned long rpauth_password
=0;
35 static unsigned long rpauth_username
=0;
36 static unsigned long rpauth_okbutton
=0;
37 static unsigned long rpauth_cancel
=0;
38 static int rpauth_count
=0;
39 static int rpauth_already
=0;
41 static unsigned long rploc_shell
=0;
42 static unsigned long rploc_button
=0;
43 static unsigned long rploc_clear
=0;
44 static unsigned long rploc_entry
=0;
45 static unsigned long rploc_ok
=0;
46 static unsigned long rploc_main
=0;
47 static int rploc_count
=0;
49 static unsigned long rpfile_shell
=0;
50 static unsigned long rpfile_main
=0;
51 static unsigned long rpfile_entry
=0;
52 static int rpfile_lowest
=0;
54 static void queue_task(void (*f
)(void));
55 static void initialize();
56 static int videocount
=0;
57 static int videotime
=0;
59 static int depthwarningflag
;
61 static void XGetGeometryRoot(unsigned long id
,int *root_x
,int *root_y
){
64 while(id
!=root_window
){
65 Window root_return
,parent_return
,*children
;
66 int x_return
, y_return
;
67 unsigned int width_return
, height_return
, border_width_return
,
70 XGetGeometry(Xdisplay
,id
,&root_return
, &x_return
, &y_return
,
71 &width_return
,&height_return
,&border_width_return
,
75 XQueryTree(Xdisplay
,id
,&root_return
,&parent_return
,&children
,&depth_return
);
83 /* Robot events *********************************************************/
85 static void FakeKeycode(int keycode
, int modmask
, unsigned long window
){
87 memset(&event
,0,sizeof(event
));
89 event
.display
=Xdisplay
;
90 event
.type
=2; /* key down */
91 event
.keycode
=keycode
;
92 event
.root
=root_window
;
96 XSendEvent(Xdisplay
,(Window
)window
,0,0,(XEvent
*)&event
);
98 /* Don't send the keyups; RP doesn't care and a 'return' or 'space'
99 can close a window... resulting in sending a keyup to a drawable
100 that doesn't exist. */
102 //event.type=3; /* key up */
104 //XSendEvent(Xdisplay,(Window)window,0,0,(XEvent *)&event);
108 static void FakeKeySym(int keysym
, int modmask
, unsigned long window
){
109 KeyCode c
=XKeysymToKeycode(Xdisplay
,keysym
);
111 if((int)XKeycodeToKeysym(Xdisplay
,c
,0)==keysym
){
112 FakeKeycode(c
,modmask
,window
);
114 FakeKeycode(c
,1|modmask
,window
);
119 void FakeButton1(unsigned long window
){
123 XGetGeometryRoot(window
,&root_x
,&root_y
);
124 memset(&event
,0,sizeof(event
));
125 event
.display
=Xdisplay
;
126 event
.type
=4; /* button down */
128 event
.root
=root_window
;
131 event
.x_root
=root_x
+4;
132 event
.y_root
=root_y
+4;
137 XSendEvent(Xdisplay
,(Window
)window
,0,0,(XEvent
*)&event
);
139 event
.type
=5; /* button up */
142 XSendEvent(Xdisplay
,(Window
)window
,0,0,(XEvent
*)&event
);
146 void FakeExposeRPPlay(void){
148 memset(&event
,0,sizeof(event
));
150 event
.display
=Xdisplay
;
152 event
.window
=rpplay_window
;
153 event
.width
=rpplay_width
;
154 event
.height
=rpplay_height
;
156 XSendEvent(Xdisplay
,(Window
)rpplay_window
,0,0,(XEvent
*)&event
);
159 void FakeTypeString(unsigned char *buf
,unsigned long window
){
162 FakeKeySym(*buf
,0,window
);
167 static void UsernameAndPassword(void){
169 fprintf(stderr
," ...: filling in username and password...\n");
171 FakeTypeString(username
,rpauth_username
);
173 FakeTypeString(password
,rpauth_password
);
174 FakeButton1(rpauth_okbutton
);
185 static void Location(void){
187 fprintf(stderr
," ...: filling in location field...\n");
189 FakeButton1(rploc_clear
);
192 FakeTypeString(location
,rploc_entry
);
194 FakeButton1(rploc_ok
);
204 static void FileEntry(void){
206 fprintf(stderr
," ...: filling in file field...\n");
210 FakeKeySym(XStringToKeysym("BackSpace"),0,rpfile_entry
);
213 FakeTypeString(openfile
,rpfile_entry
);
215 FakeKeySym(XStringToKeysym("Return"),0,rpfile_entry
);
222 /* captured calls ******************************************************/
224 Display
*XOpenDisplay(const char *d
){
228 fprintf(stderr
,"**ERROR: Unable to set multithreading support in Xlib.\n"
229 " exit(1)ing...\n\n");
232 Xdisplay
=(*xlib_xopen
)(d
);
233 pthread_mutex_lock(&display_mutex
);
234 pthread_cond_signal(&display_cond
);
235 pthread_mutex_unlock(&display_mutex
);
239 /* we assume the * window is ready when we see the last polylines put
240 into the chosen button window */
241 int XDrawSegments(Display
*display
, Drawable id
, GC gc
, XSegment
*segments
, int nsegments
){
243 int ret
=(*xlib_xdrawsegments
)(display
, id
, gc
, segments
, nsegments
);
245 if(id
==rpauth_cancel
){
247 queue_task(UsernameAndPassword
);
250 if(id
==rploc_entry
&& rploc_button
){
252 queue_task(Location
);
255 if(id
==rpfile_entry
&& rpfile_shell
){
257 queue_task(FileEntry
);
262 Window
XCreateWindow(Display
*display
,Window parent
,
264 unsigned int width
, unsigned int height
,
265 unsigned int border_width
,
269 unsigned long valuemask
,
270 XSetWindowAttributes
*attributes
){
272 Window id
=(*xlib_xcreatewindow
)(display
,parent
,x
,y
,width
,height
,border_width
,
273 depth
,class,visual
,valuemask
,attributes
);
278 /* Main player windows */
279 if(parent
==rpshell_window
){
284 " ...: RealPlayer main window id=%lx\n",rpmain_window
);
286 }else if(rpshell_window
){
287 if(parent
==rpmain_window
){
293 " ...: RealPlayer console window id=%lx\n",rpplay_window
);
297 }else if(parent
==rpplay_window
){
301 " ...: RealPlayer video window id=%lx\n",rpvideo_window
);
305 /* Auth dialog windows */
306 if(parent
==rpauth_shell
){
309 if(parent
==rpauth_main
){
310 switch(rpauth_count
++){
313 fprintf(stderr
," ...: username window: %lx\n",id
);
317 fprintf(stderr
," ...: password window: %lx\n",id
);
321 fprintf(stderr
," ...: OK button: %lx\n",id
);
325 fprintf(stderr
," ...: cancel button: %lx\n",id
);
330 /* Location dialog windows */
331 if(parent
==rploc_shell
){
334 if(parent
==rploc_main
|| parent
==rploc_button
){
335 switch(rploc_count
++){
340 fprintf(stderr
," ...: clear button: %lx\n",id
);
344 fprintf(stderr
," ...: ok button: %lx\n",id
);
351 fprintf(stderr
," ...: text entry: %lx\n",id
);
357 /* File dialog windows */
358 if(parent
==rpfile_shell
){
362 if(parent
==rpfile_main
){
372 int XConfigureWindow(Display
*display
,Window id
,unsigned int bitmask
,XWindowChanges
*values
){
374 int ret
=(*xlib_xconfigurewindow
)(display
, id
, bitmask
, values
);
376 if(id
==rpplay_window
){
378 if(bitmask
& CWHeight
){
379 rpplay_height
=values
->height
;
382 if(bitmask
& CWWidth
){
383 rpplay_width
=values
->width
;
388 if(id
==rpvideo_window
){
389 if(bitmask
& CWHeight
){
390 video_height
=values
->height
;
393 if(bitmask
& CWWidth
){
394 video_width
=values
->width
;
402 int XResizeWindow(Display
*display
,Window id
,unsigned int width
,unsigned int height
){
404 int ret
=(*xlib_xresizewindow
)(display
, id
, width
, height
);
406 if(id
==rpplay_window
){
407 rpplay_height
=height
;
412 if(id
==rpvideo_window
){
421 int XChangeProperty(Display
*display
,Window id
,Atom property
,Atom type
,int format
,int mode
,
422 const unsigned char *data
,int n
){
424 int ret
=(*xlib_xchangeproperty
)(display
, id
, property
, type
, format
, mode
, data
, n
);
426 if(property
!=67 || type
!=31)return(ret
); /* not interested if not WM_CLASS and STRING */
428 /* look for the RealPlayer shell window; the other player windows
429 descend from it in a predicatble pattern */
431 if(rpshell_window
==0){
434 " ...: looking for our shell window...\n"
435 " candidate: id=%lx, name=%s class=%s\n",
436 id
,(data
?(char *)data
:""),(data
?strchr((char *)data
,'\0')+1:""));
438 if(n
>26 && !memcmp(data
,"RealPlayer\0RCACoreAppShell\0",27)){
439 /* it's our shell window above the WM parent */
457 fprintf(stderr
," GOT IT!\n");
460 fprintf(stderr
," nope...\n");
464 /* watch for the auth password window */
465 if(username
|| password
){
467 if(n
>=32 && !memcmp(data
,"AuthDialogShell\0RCACoreAppShell\0",32)){
468 if(rpauth_already
>2){
470 "**ERROR: Password not accepted.\n");
475 " ...: RealPlayer popped auth window. Watching for username\n"
476 " password and ok button windows\n");
487 /* watch for the open location window */
489 if(n
>=40 && !memcmp(data
,"OpenLocationDialogShell\0RCACoreAppShell\0",40)){
491 " ...: RealPlayer popped open location dialog. Watching for\n"
492 " dialog window tree...\n");
501 /* watch for the open file window */
502 if(n
>=32 && !memcmp(data
,"OpenFileDialogShell\0RCACoreAppShell\0",32)){
504 " ...: RealPlayer popped open file dialog.\n");
512 /* hash the image: Real (for some reason) sometimes blits at >> the
513 encoded video framerate [it's not interlaced, so not sure why], so
514 there are lotsa dupes. Hash to see if the frame actually changed.
515 Again, CPU overhead is likely more than made up for in bandwidth
518 static char *workbuffer
;
519 static long worksize
;
521 /* yes, it's additional CPU load where we don't want any, but the
522 savings in required disk bandwidth is more than worth it (YUV 2:4:0
525 void YUVout(XImage
*image
){
526 pthread_mutex_lock(&output_mutex
);
531 long yuv_w
=(image
->width
>>1)<<1; /* must be even for yuv12 */
532 long yuv_h
=(image
->height
>>1)<<1; /* must be even for yuv12 */
533 long yuv_n
=yuv_w
*yuv_h
*3/2;
537 pthread_mutex_unlock(&output_mutex
);
539 len
=sprintf(cbuf
,"YUV12 %ld %ld %d %d %ld:",a
,b
,yuv_w
,
544 workbuffer
=malloc(yuv_n
);
546 workbuffer
=realloc(workbuffer
,yuv_n
);
551 unsigned char *y1
=workbuffer
;
552 unsigned char *y2
=workbuffer
+yuv_w
;
553 unsigned char *u
=workbuffer
+yuv_w
*yuv_h
;
554 unsigned char *v
=u
+yuv_w
*yuv_h
/4;
555 if(image
->byte_order
){
557 for(i
=0;i
<yuv_h
;i
+=2){
558 unsigned char *ptr1
=image
->data
+i
*image
->bytes_per_line
;
559 unsigned char *ptr2
=ptr1
+image
->bytes_per_line
;
560 for(j
=0;j
<yuv_w
;j
+=2){
563 yval
= ptr1
[1]*19595 + ptr1
[2]*38470 + ptr1
[3]*7471;
564 uval
= ptr1
[3]*65536 - ptr1
[1]*22117 - ptr1
[2]*43419;
565 vval
= ptr1
[1]*65536 - ptr1
[2]*54878 - ptr1
[3]*10658;
568 yval
= ptr1
[5]*19595 + ptr1
[6]*38470 + ptr1
[7]*7471;
569 uval
+= ptr1
[7]*65536 - ptr1
[5]*22117 - ptr1
[6]*43419;
570 vval
+= ptr1
[5]*65536 - ptr1
[6]*54878 - ptr1
[7]*10658;
573 yval
= ptr2
[1]*19595 + ptr2
[2]*38470 + ptr2
[3]*7471;
574 uval
+= ptr2
[3]*65536 - ptr2
[1]*22117 - ptr2
[2]*43419;
575 vval
+= ptr2
[1]*65536 - ptr2
[2]*54878 - ptr2
[3]*10658;
578 yval
= ptr2
[5]*19595 + ptr2
[6]*38470 + ptr2
[7]*7471;
579 uval
+= ptr2
[7]*65536 - ptr2
[5]*22117 - ptr2
[6]*43419;
580 vval
+= ptr2
[5]*65536 - ptr2
[6]*54878 - ptr2
[7]*10658;
583 *u
++ = (uval
>>19)+128;
584 *v
++ = (vval
>>19)+128;
595 for(i
=0;i
<yuv_h
;i
+=2){
596 unsigned char *ptr1
=image
->data
+i
*image
->bytes_per_line
;
597 unsigned char *ptr2
=ptr1
+image
->bytes_per_line
;
598 for(j
=0;j
<yuv_w
;j
+=2){
601 yval
= ptr1
[2]*19595 + ptr1
[1]*38470 + ptr1
[0]*7471;
602 uval
= ptr1
[0]*65536 - ptr1
[2]*22117 - ptr1
[1]*43419;
603 vval
= ptr1
[2]*65536 - ptr1
[1]*54878 - ptr1
[0]*10658;
606 yval
= ptr1
[6]*19595 + ptr1
[5]*38470 + ptr1
[4]*7471;
607 uval
+= ptr1
[4]*65536 - ptr1
[6]*22117 - ptr1
[5]*43419;
608 vval
+= ptr1
[6]*65536 - ptr1
[5]*54878 - ptr1
[4]*10658;
611 yval
= ptr2
[2]*19595 + ptr2
[1]*38470 + ptr2
[0]*7471;
612 uval
+= ptr2
[0]*65536 - ptr2
[2]*22117 - ptr2
[1]*43419;
613 vval
+= ptr2
[2]*65536 - ptr2
[1]*54878 - ptr2
[0]*10658;
616 yval
= ptr2
[6]*19595 + ptr2
[5]*38470 + ptr2
[4]*7471;
617 uval
+= ptr2
[4]*65536 - ptr2
[6]*22117 - ptr2
[5]*43419;
618 vval
+= ptr2
[6]*65536 - ptr2
[5]*54878 - ptr2
[4]*10658;
621 *u
++ = (uval
>>19)+128;
622 *v
++ = (vval
>>19)+128;
632 pthread_mutex_lock(&output_mutex
);
633 gwrite(outfile_fd
,cbuf
,len
);
634 gwrite(outfile_fd
,workbuffer
,yuv_n
);
636 pthread_mutex_unlock(&output_mutex
);
640 int XPutImage(Display
*display
,Drawable id
,GC gc
,XImage
*image
,
643 unsigned int d_width
,
644 unsigned int d_height
){
648 if(id
==rpvideo_window
){
649 double t
=bigtime(NULL
,NULL
);
656 if(snatch_active
==1 && id
==rpvideo_window
){
657 pthread_mutex_lock(&output_mutex
);
658 if(outfile_fd
>=0 && !output_video_p
)CloseOutputFile(1);
659 if(outfile_fd
<0 && videocount
>4)OpenOutputFile();
660 pthread_mutex_unlock(&output_mutex
);
661 /* only do 24 bit zPixmaps for now */
663 if(image
->format
==2 && image
->depth
>16 && image
->depth
<=24){
666 if(!depthwarningflag
)
667 fprintf(stderr
,"**ERROR: Right now, Snatch only works with 17-24 bit ZPixmap\n"
668 " based visuals packed into 8bpp 32 bit units. This\n"
669 " X server is not in a 24/32 bit mode. \n");
675 /* Subvert the Real sign on logo; paste the Snatch logo in.
676 Although this might seem like a vanity issue, the primary reason
677 for doing this is to give the user a clear indication Snatch is
678 working properly, so some care should be taken to get it right. */
680 /* Real uses putimage here even on the local display with MIT-SHM support */
682 if(id
==rpplay_window
){
683 int width
=image
->width
;
684 int height
=image
->height
;
685 int endian
=image
->byte_order
;
687 if(image
->format
==2 && image
->depth
>16 && image
->depth
<=24){
689 char *ptr
=image
->data
;
692 /* after a resize, look where to put the logo... */
693 if(logo_y
==-1 && height
==rpplay_height
&& width
==rpplay_width
){
700 for(play_blackleft
=20;play_blackleft
>0;play_blackleft
--)
701 if(ptr
[play_blackupper
*width
*4+play_blackleft
*4+1]!=0)break;
703 for(play_blackright
=width
-20;play_blackright
<width
;play_blackright
++)
704 if(ptr
[play_blackupper
*width
*4+play_blackright
*4+1]!=0)break;
706 if(play_blacklower
==-1){
708 for(;play_blacklower
<height
;play_blacklower
++)
709 if(ptr
[play_blacklower
*width
*4+81]!=0)break;
711 if(play_blacklower
==height
)play_blacklower
=-1;
714 for(test
=play_blackupper
;test
<height
;test
++)
715 if(ptr
[test
*width
*4+(width
/2*4)+1]!=0)break;
717 if(test
<height
&& test
+snatchheight
<play_blacklower
){
720 /* verify enough room to display... */
724 for(blacklower
=test
;blacklower
<height
;blacklower
++)
725 if(ptr
[blacklower
*width
*4+(20*4)+1]!=0)break;
727 if(blacklower
-test
<snatchheight
){
734 /* blank background */
735 if(x
==0 && y
==0 && (int)d_width
==rpplay_width
&&
736 (int)d_height
==rpplay_height
){
745 for(i
=play_blackupper
;i
<play_blacklower
;i
++)
746 for(j
=play_blackleft
;j
<play_blackright
;j
++){
747 ptr
[i
*width
*4+j
*4]=0x00;
748 ptr
[i
*width
*4+j
*4+1]=bptr
[0];
749 ptr
[i
*width
*4+j
*4+2]=bptr
[1];
750 ptr
[i
*width
*4+j
*4+3]=bptr
[2];
753 for(i
=play_blackupper
;i
<play_blacklower
;i
++)
754 for(j
=play_blackleft
;j
<play_blackright
;j
++){
755 ptr
[i
*width
*4+j
*4+3]=0x00;
756 ptr
[i
*width
*4+j
*4+2]=bptr
[0];
757 ptr
[i
*width
*4+j
*4+1]=bptr
[1];
758 ptr
[i
*width
*4+j
*4]=bptr
[2];
765 unsigned char *logo
=NULL
;
769 switch(snatch_active
){
773 logoheight
=realheight
;
777 logowidth
=snatchwidth
;
778 logoheight
=snatchheight
;
782 logowidth
=snatchwidth
;
783 logoheight
=snatchheight
;
787 for(i
=0;i
<logoheight
;i
++){
792 real
=ptr
+width
*4*(i
+logo_y
)+(rpplay_width
-logowidth
)/2*4; /* not the same as *2 */
793 snatch
=logo
+logowidth
*3*i
;
797 for(k
=0,j
=0;k
<logowidth
*3 && j
<width
*4;){
798 real
[++j
]=snatch
[k
++];
799 real
[++j
]=snatch
[k
++];
800 real
[++j
]=snatch
[k
++];
805 for(k
=0,j
=0;k
<logowidth
*3 && j
<width
*4;j
+=4){
806 real
[j
+2]=snatch
[k
++];
807 real
[j
+1]=snatch
[k
++];
816 if(!depthwarningflag
)
817 fprintf(stderr
,"**ERROR: Right now, Snatch only works with 17-24 bit ZPixmap\n"
818 " based visuals packed into 8bpp 32 bit units. This\n"
819 " X server is not in a 24/32 bit mode. \n");
825 ret
=(*xlib_xputimage
)(display
,id
,gc
,image
,src_x
,src_y
,x
,y
,d_width
,d_height
);
830 int XShmPutImage(Display
*display
,Drawable id
,GC gc
,XImage
*image
,
831 int src_x
, int src_y
, int dest_x
, int dest_y
,
832 unsigned int width
, unsigned int height
,
836 if(id
==rpvideo_window
){
837 double t
=bigtime(NULL
,NULL
);
844 if(snatch_active
==1 && id
==rpvideo_window
){
845 pthread_mutex_lock(&output_mutex
);
846 if(outfile_fd
>=0 && !output_video_p
)CloseOutputFile(1);
847 if(outfile_fd
<0 && videocount
>4)OpenOutputFile();
848 pthread_mutex_unlock(&output_mutex
);
850 /* only do 24 bit zPixmaps for now */
851 if(image
->format
==2 && image
->depth
>16 && image
->depth
<=24){
854 if(!depthwarningflag
)
855 fprintf(stderr
,"**ERROR: Right now, Snatch only works with 17-24 bit ZPixmap\n"
856 " based visuals packed into 8bpp 32 bit units. This\n"
857 " X server is not in a 24/32 bit mode. \n");
863 ret
=(*xlib_xshmputimage
)(display
, id
, gc
, image
, src_x
, src_y
,
864 dest_x
, dest_y
, width
, height
, send_event
);
870 int XCloseDisplay(Display
*d
){
871 int ret
=(*xlib_xclose
)(d
);
873 if(debug
)fprintf(stderr
," ...: X display closed; goodbye.\n\n");