/***************************************************************************** * Display: Map p_image onto the screen *****************************************************************************/ static void Display( vout_thread_t *p_vout, picture_t *p_pic ) { uint32_t i_width, i_height, i_x, i_y; uint32_t i_offset = 0; vout_PlacePicture( p_vout, p_vout->p_sys->i_width, p_vout->p_sys->i_height, &i_x, &i_y, &i_width, &i_height ); msg_Dbg( p_vout, "PlacePicture at x_left = %d, y_left = %d, x_bottom = %d, y_bottom = %d", i_x, i_y, i_width, i_height ); /* Currently the only pixel format supported is 32bpp RGBA.*/ p_vout->p_sys->p_screen->LockScreen(); /* Unlock the shared memory region first. */ if( p_pic->p_sys->p_image->Unlock() ) { msg_Err( p_vout, "unlocking shared memory failed. Expect threading problems." ); } p_vout->p_sys->p_screen->Blit( CascadePoint( (u32) i_x, (u32) i_y ), /* Place bitmap at */ (*p_pic->p_sys->p_image) , /* Image data */ (u32) i_offset, /* Offset in SharedMemoryZone */ (u32) i_width, /* Source bitmap width */ (u32) i_height, /* Source bitmap height */ (u32) p_vout->p_sys->i_screen_depth, /* Source pixel depth */ CascadeRect( (u32) i_x, (u32) i_y, (u32) i_width, (u32) i_height ) ); p_vout->p_sys->p_screen->UnlockScreen(); }
/***************************************************************************** * Display: displays previously rendered output ***************************************************************************** * This function sends the currently rendered image to the display. *****************************************************************************/ static void Display( vout_thread_t *p_vout, picture_t *p_pic ) { unsigned int x, y, w, h; SDL_Rect disp; vout_PlacePicture( p_vout, p_vout->p_sys->i_width, p_vout->p_sys->i_height, &x, &y, &w, &h ); disp.x = x; disp.y = y; disp.w = w; disp.h = h; if( p_vout->p_sys->p_overlay == NULL ) { /* RGB picture */ SDL_Flip( p_vout->p_sys->p_display ); } else { /* Overlay picture */ SDL_UnlockYUVOverlay( p_pic->p_sys->p_overlay); SDL_DisplayYUVOverlay( p_pic->p_sys->p_overlay , &disp ); SDL_LockYUVOverlay( p_pic->p_sys->p_overlay); } }
/***************************************************************************** * Display: displays previously rendered output ***************************************************************************** * This function sends the currently rendered image to screen. *****************************************************************************/ static void Display( vout_thread_t *p_vout, picture_t *p_pic ) { unsigned int x, y, w, h; vout_PlacePicture( p_vout, p_vout->output.i_width, p_vout->output.i_height, &x, &y, &w, &h ); #if 0 msg_Dbg(p_vout, "+qte::Display( p_vout, i_width=%d, i_height=%d, x=%u, y=%u, w=%u, h=%u", p_vout->output.i_width, p_vout->output.i_height, x, y, w, h ); #endif if(p_vout->p_sys->p_VideoWidget) { // shameless borrowed from opie mediaplayer.... #ifndef USE_DIRECT_PAINTER msg_Dbg(p_vout, "not using direct painter"); QPainter p(p_vout->p_sys->p_VideoWidget); /* rotate frame */ int dd = QPixmap::defaultDepth(); int bytes = ( dd == 16 ) ? 2 : 4; int rw = h, rh = w; QImage rotatedFrame( rw, rh, bytes << 3 ); ushort* in = (ushort*)p_pic->p_sys->pQImage->bits(); ushort* out = (ushort*)rotatedFrame.bits(); int spl = rotatedFrame.bytesPerLine() / bytes; for (int x=0; x<h; x++) { if ( bytes == 2 ) { ushort* lout = out++ + (w - 1)*spl; for (int y=0; y<w; y++) { *lout=*in++; lout-=spl; } } else { ulong* lout = ((ulong *)out)++ + (w - 1)*spl; for (int y=0; y<w; y++) { *lout=*((ulong*)in)++; lout-=spl; } } } p.drawImage( x, y, rotatedFrame, 0, 0, rw, rh ); #else QDirectPainter p(p_vout->p_sys->p_VideoWidget); p.transformOrientation(); // just copy the image to the frame buffer... memcpy(p.frameBuffer(), (p_pic->p_sys->pQImage->jumpTable())[0], h * p.lineStep()); #endif } }
/***************************************************************************** * Display: displays previously rendered output *****************************************************************************/ static void Display( vout_thread_t *p_vout, picture_t *p_pic ) { /* No need to do anything, the fake direct buffers stay as they are */ int i_width, i_height, i_x, i_y; vout_PlacePicture( p_vout, p_vout->p_sys->i_width, p_vout->p_sys->i_height, &i_x, &i_y, &i_width, &i_height ); aa_flush(p_vout->p_sys->aa_context); }
/***************************************************************************** * SwapBuffers: swap front/back buffers *****************************************************************************/ static void SwapBuffers( vout_thread_t *p_vout ) { vout_sys_t *p_sys = p_vout->p_sys; int i_width, i_height, i_x, i_y; vout_PlacePicture( p_vout, p_vout->p_sys->p_win->i_width, p_vout->p_sys->p_win->i_height, &i_x, &i_y, &i_width, &i_height ); glViewport( 0, 0, (GLint)i_width, (GLint)i_height ); if( p_sys->b_glx13 ) { glXSwapBuffers( p_sys->p_display, p_sys->gwnd ); } else { glXSwapBuffers( p_sys->p_display, p_sys->p_win->video_window ); } }
/***************************************************************************** * VLCVIew::MouseMoved *****************************************************************************/ void VLCView::MouseMoved(BPoint point, uint32 transit, const BMessage* dragMessage) { fLastMouseMovedTime = mdate(); fCursorHidden = false; fCursorInside = ( transit == B_INSIDE_VIEW || transit == B_ENTERED_VIEW ); if( !fCursorInside ) { return; } vlc_value_t val; unsigned int i_width, i_height, i_x, i_y; vout_PlacePicture( p_vout, (unsigned int)Bounds().Width(), (unsigned int)Bounds().Height(), &i_x, &i_y, &i_width, &i_height ); val.i_int = ( (int)point.x - i_x ) * p_vout->render.i_width / i_width; var_Set( p_vout, "mouse-x", val ); val.i_int = ( (int)point.y - i_y ) * p_vout->render.i_height / i_height; var_Set( p_vout, "mouse-y", val ); val.b_bool = true; var_Set( p_vout, "mouse-moved", val ); }
/***************************************************************************** * Manage: handle Sys events ***************************************************************************** * This function should be called regularly by video output thread. It returns * a non null value if an error occurred. *****************************************************************************/ static int Manage( vout_thread_t *p_vout ) { SDL_Event event; /* SDL event */ vlc_value_t val; unsigned int i_width, i_height, i_x, i_y; /* Process events */ while( SDL_PollEvent(&event) ) { switch( event.type ) { case SDL_VIDEORESIZE: /* Resizing of window */ /* Update dimensions */ p_vout->i_changes |= VOUT_SIZE_CHANGE; p_vout->i_window_width = p_vout->p_sys->i_width = event.resize.w; p_vout->i_window_height = p_vout->p_sys->i_height = event.resize.h; break; case SDL_MOUSEMOTION: vout_PlacePicture( p_vout, p_vout->p_sys->i_width, p_vout->p_sys->i_height, &i_x, &i_y, &i_width, &i_height ); val.i_int = ( event.motion.x - i_x ) * p_vout->render.i_width / i_width; var_Set( p_vout, "mouse-x", val ); val.i_int = ( event.motion.y - i_y ) * p_vout->render.i_height / i_height; var_Set( p_vout, "mouse-y", val ); val.b_bool = VLC_TRUE; var_Set( p_vout, "mouse-moved", val ); if( p_vout->p_sys->b_cursor && (abs(event.motion.xrel) > 2 || abs(event.motion.yrel) > 2) ) { if( p_vout->p_sys->b_cursor_autohidden ) { p_vout->p_sys->b_cursor_autohidden = 0; SDL_ShowCursor( 1 ); } else { p_vout->p_sys->i_lastmoved = mdate(); } } break; case SDL_MOUSEBUTTONUP: switch( event.button.button ) { case SDL_BUTTON_LEFT: val.b_bool = VLC_TRUE; var_Set( p_vout, "mouse-clicked", val ); break; case SDL_BUTTON_RIGHT: { intf_thread_t *p_intf; p_intf = vlc_object_find( p_vout, VLC_OBJECT_INTF, FIND_ANYWHERE ); if( p_intf ) { p_intf->b_menu_change = 1; vlc_object_release( p_intf ); } } break; } break; case SDL_MOUSEBUTTONDOWN: switch( event.button.button ) { case SDL_BUTTON_LEFT: /* In this part we will eventually manage * clicks for DVD navigation for instance. */ /* detect double-clicks */ if( ( mdate() - p_vout->p_sys->i_lastpressed ) < 300000 ) p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE; p_vout->p_sys->i_lastpressed = mdate(); break; case 4: break; case 5: break; } break; case SDL_QUIT: p_vout->p_vlc->b_die = 1; break; case SDL_KEYDOWN: /* if a key is pressed */ switch( event.key.keysym.sym ) { case SDLK_ESCAPE: if( p_vout->b_fullscreen ) { p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE; } else { p_vout->p_vlc->b_die = 1; } break; case SDLK_q: /* quit */ p_vout->p_vlc->b_die = 1; break; case SDLK_f: /* switch to fullscreen */ p_vout->i_changes |= VOUT_FULLSCREEN_CHANGE; break; case SDLK_c: /* toggle grayscale */ p_vout->b_grayscale = ! p_vout->b_grayscale; p_vout->i_changes |= VOUT_GRAYSCALE_CHANGE; break; case SDLK_i: /* toggle info */ p_vout->b_info = ! p_vout->b_info; p_vout->i_changes |= VOUT_INFO_CHANGE; break; case SDLK_s: /* toggle scaling */ p_vout->b_scale = ! p_vout->b_scale; p_vout->i_changes |= VOUT_SCALE_CHANGE; break; case SDLK_SPACE: /* toggle interface */ p_vout->b_interface = ! p_vout->b_interface; p_vout->i_changes |= VOUT_INTF_CHANGE; break; case SDLK_MENU: { intf_thread_t *p_intf; p_intf = vlc_object_find( p_vout, VLC_OBJECT_INTF, FIND_ANYWHERE ); if( p_intf != NULL ) { p_intf->b_menu_change = 1; vlc_object_release( p_intf ); } } break; case SDLK_LEFT: break; case SDLK_RIGHT: break; case SDLK_UP: break; case SDLK_DOWN: break; case SDLK_b: { audio_volume_t i_volume; if ( !aout_VolumeDown( p_vout, 1, &i_volume ) ) { msg_Dbg( p_vout, "audio volume is now %d", i_volume ); } else { msg_Dbg( p_vout, "audio volume: operation not supported" ); } } break; case SDLK_n: { audio_volume_t i_volume; if ( !aout_VolumeUp( p_vout, 1, &i_volume ) ) { msg_Dbg( p_vout, "audio volume is now %d", i_volume ); } else { msg_Dbg( p_vout, "audio volume: operation not supported" ); } } break; default: break; } break; default: break; } } /* Fullscreen change */ if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE ) { p_vout->b_fullscreen = ! p_vout->b_fullscreen; p_vout->p_sys->b_cursor_autohidden = 0; SDL_ShowCursor( p_vout->p_sys->b_cursor && ! p_vout->p_sys->b_cursor_autohidden ); p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE; p_vout->i_changes |= VOUT_SIZE_CHANGE; } /* * Size change */ if( p_vout->i_changes & VOUT_SIZE_CHANGE ) { msg_Dbg( p_vout, "video display resized (%dx%d)", p_vout->p_sys->i_width, p_vout->p_sys->i_height ); CloseDisplay( p_vout ); OpenDisplay( p_vout ); /* We don't need to signal the vout thread about the size change if * we can handle rescaling ourselves */ if( p_vout->p_sys->p_overlay != NULL ) p_vout->i_changes &= ~VOUT_SIZE_CHANGE; } /* Pointer change */ if( ! p_vout->p_sys->b_cursor_autohidden && ( mdate() - p_vout->p_sys->i_lastmoved > 2000000 ) ) { /* Hide the mouse automatically */ p_vout->p_sys->b_cursor_autohidden = 1; SDL_ShowCursor( 0 ); } return VLC_SUCCESS; }
/***************************************************************************** * NewPicture: allocate a picture ***************************************************************************** * Returns 0 on success, -1 otherwise *****************************************************************************/ static int NewPicture( vout_thread_t *p_vout, picture_t *p_pic, int index ) { /* We know the chroma, allocate a buffer which will be used * directly by the decoder */ p_pic->p_sys = malloc( sizeof( picture_sys_t ) ); if( p_pic->p_sys == NULL ) { return -1; } switch( p_vout->p_sys->i_mode ) { case MODE_NORMAL_MEM: case MODE_SHARED_MEM: /* create images for [shared] memory blit */ if( !( p_pic->p_sys->p_image = PhCreateImage( NULL, p_vout->p_sys->dim.w, p_vout->p_sys->dim.h, p_vout->p_sys->i_img_type, NULL, 0, p_vout->p_sys->i_mode == MODE_SHARED_MEM ) ) ) { msg_Err( p_vout, "cannot create image" ); free( p_pic->p_sys ); return( -1 ); } p_pic->p->p_pixels = p_pic->p_sys->p_image->image; p_pic->p->i_lines = p_pic->p_sys->p_image->size.h; p_pic->p->i_visible_lines = p_pic->p_sys->p_image->size.h; p_pic->p->i_pitch = p_pic->p_sys->p_image->bpl; p_pic->p->i_pixel_pitch = p_vout->p_sys->i_bytes_per_pixel; p_pic->p->i_visible_pitch = p_vout->p_sys->i_bytes_per_pixel * p_pic->p_sys->p_image->size.w; p_pic->i_planes = 1; break; case MODE_VIDEO_MEM: /* create offscreen contexts for video memory blit */ if( ( p_pic->p_sys->p_ctx[0] = PdCreateOffscreenContext( 0, p_vout->p_sys->dim.w, p_vout->p_sys->dim.h, Pg_OSC_MEM_PAGE_ALIGN) ) == NULL ) { msg_Err( p_vout, "unable to create offscreen context" ); free( p_pic->p_sys ); return( -1 ); } /* get context pointers */ if( ( p_pic->p_sys->p_buf[0] = PdGetOffscreenContextPtr ( p_pic->p_sys->p_ctx[0] ) ) == NULL ) { msg_Err( p_vout, "unable to get offscreen context ptr" ); PhDCRelease ( p_pic->p_sys->p_ctx[0] ); p_pic->p_sys->p_ctx[0] = NULL; free( p_pic->p_sys ); return( -1 ); } p_vout->p_sys->i_bytes_per_line = p_pic->p_sys->p_ctx[0]->pitch; memset( p_pic->p_sys->p_buf[0], 0, p_vout->p_sys->i_bytes_per_line * p_vout->p_sys->dim.h ); p_pic->p->p_pixels = p_pic->p_sys->p_buf[0]; p_pic->p->i_lines = p_pic->p_sys->p_ctx[0]->dim.h; p_pic->p->i_visible_lines = p_pic->p_sys->p_ctx[0]->dim.h; p_pic->p->i_pitch = p_pic->p_sys->p_ctx[0]->pitch; p_pic->p->i_pixel_pitch = p_vout->p_sys->i_bytes_per_pixel; p_pic->p->i_visible_pitch = p_vout->p_sys->i_bytes_per_pixel * p_pic->p_sys->p_ctx[0]->dim.w; p_pic->i_planes = 1; break; case MODE_VIDEO_OVERLAY: if (index == 0) { p_pic->p_sys->p_ctx[Y_PLANE] = p_vout->p_sys->p_channel->yplane1; p_pic->p_sys->p_ctx[U_PLANE] = p_vout->p_sys->p_channel->uplane1; p_pic->p_sys->p_ctx[V_PLANE] = p_vout->p_sys->p_channel->vplane1; } else { p_pic->p_sys->p_ctx[Y_PLANE] = p_vout->p_sys->p_channel->yplane2; p_pic->p_sys->p_ctx[U_PLANE] = p_vout->p_sys->p_channel->uplane2; p_pic->p_sys->p_ctx[V_PLANE] = p_vout->p_sys->p_channel->vplane2; } p_pic->p_sys->p_buf[Y_PLANE] = PdGetOffscreenContextPtr( p_pic->p_sys->p_ctx[Y_PLANE] ); if( p_pic->p_sys->p_buf[Y_PLANE] == NULL ) { msg_Err( p_vout, "unable to get video channel ctx ptr" ); return( 1 ); } switch (p_vout->p_sys->i_vc_format) { case Pg_VIDEO_FORMAT_YUV420: p_vout->output.i_chroma = VLC_CODEC_I420; p_pic->p_sys->p_buf[U_PLANE] = PdGetOffscreenContextPtr( p_pic->p_sys->p_ctx[U_PLANE] ); p_pic->p_sys->p_buf[V_PLANE] = PdGetOffscreenContextPtr( p_pic->p_sys->p_ctx[V_PLANE] ); if( p_pic->p_sys->p_buf[U_PLANE] == NULL || p_pic->p_sys->p_buf[V_PLANE] == NULL ) { msg_Err( p_vout, "unable to get video channel ctx ptr" ); return( 1 ); } p_pic->Y_PIXELS = p_pic->p_sys->p_buf[Y_PLANE]; p_pic->p[Y_PLANE].i_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h; p_pic->p[Y_PLANE].i_visible_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h; p_pic->p[Y_PLANE].i_pitch = p_pic->p_sys->p_ctx[Y_PLANE]->pitch; p_pic->p[Y_PLANE].i_pixel_pitch = 1; p_pic->p[Y_PLANE].i_visible_pitch = p_pic->p[Y_PLANE].i_pitch; p_pic->U_PIXELS = p_pic->p_sys->p_buf[U_PLANE]; p_pic->p[U_PLANE].i_lines = p_pic->p_sys->p_ctx[U_PLANE]->dim.h; p_pic->p[U_PLANE].i_visible_lines = p_pic->p_sys->p_ctx[U_PLANE]->dim.h; p_pic->p[U_PLANE].i_pitch = p_pic->p_sys->p_ctx[U_PLANE]->pitch; p_pic->p[U_PLANE].i_pixel_pitch = 1; p_pic->p[U_PLANE].i_visible_pitch = p_pic->p[U_PLANE].i_pitch; p_pic->V_PIXELS = p_pic->p_sys->p_buf[V_PLANE]; p_pic->p[V_PLANE].i_lines = p_pic->p_sys->p_ctx[V_PLANE]->dim.h; p_pic->p[V_PLANE].i_visible_lines = p_pic->p_sys->p_ctx[V_PLANE]->dim.h; p_pic->p[V_PLANE].i_pitch = p_pic->p_sys->p_ctx[V_PLANE]->pitch; p_pic->p[V_PLANE].i_pixel_pitch = 1; p_pic->p[V_PLANE].i_visible_pitch = p_pic->p[V_PLANE].i_pitch; p_pic->i_planes = 3; break; case Pg_VIDEO_FORMAT_YV12: p_vout->output.i_chroma = VLC_CODEC_YV12; p_pic->p_sys->p_buf[U_PLANE] = PdGetOffscreenContextPtr( p_pic->p_sys->p_ctx[U_PLANE] ); p_pic->p_sys->p_buf[V_PLANE] = PdGetOffscreenContextPtr( p_pic->p_sys->p_ctx[V_PLANE] ); if( p_pic->p_sys->p_buf[U_PLANE] == NULL || p_pic->p_sys->p_buf[V_PLANE] == NULL ) { msg_Err( p_vout, "unable to get video channel ctx ptr" ); return( 1 ); } p_pic->Y_PIXELS = p_pic->p_sys->p_buf[Y_PLANE]; p_pic->p[Y_PLANE].i_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h; p_pic->p[Y_PLANE].i_visible_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h; p_pic->p[Y_PLANE].i_pitch = p_pic->p_sys->p_ctx[Y_PLANE]->pitch; p_pic->p[Y_PLANE].i_pixel_pitch = 1; p_pic->p[Y_PLANE].i_visible_pitch = p_pic->p[Y_PLANE].i_pitch; p_pic->U_PIXELS = p_pic->p_sys->p_buf[U_PLANE]; p_pic->p[U_PLANE].i_lines = p_pic->p_sys->p_ctx[U_PLANE]->dim.h; p_pic->p[U_PLANE].i_visible_lines = p_pic->p_sys->p_ctx[U_PLANE]->dim.h; p_pic->p[U_PLANE].i_pitch = p_pic->p_sys->p_ctx[U_PLANE]->pitch; p_pic->p[U_PLANE].i_pixel_pitch = 1; p_pic->p[U_PLANE].i_visible_pitch = p_pic->p[U_PLANE].i_pitch; p_pic->V_PIXELS = p_pic->p_sys->p_buf[V_PLANE]; p_pic->p[V_PLANE].i_lines = p_pic->p_sys->p_ctx[V_PLANE]->dim.h; p_pic->p[V_PLANE].i_visible_lines = p_pic->p_sys->p_ctx[V_PLANE]->dim.h; p_pic->p[V_PLANE].i_pitch = p_pic->p_sys->p_ctx[V_PLANE]->pitch; p_pic->p[V_PLANE].i_pixel_pitch = 1; p_pic->p[V_PLANE].i_visible_pitch = p_pic->p[V_PLANE].i_pitch; p_pic->i_planes = 3; break; case Pg_VIDEO_FORMAT_UYVY: case Pg_VIDEO_FORMAT_YUY2: if (p_vout->p_sys->i_vc_format == Pg_VIDEO_FORMAT_UYVY) { p_vout->output.i_chroma = VLC_CODEC_UYVY; } else { p_vout->output.i_chroma = VLC_CODEC_YUYV; } p_pic->p->p_pixels = p_pic->p_sys->p_buf[Y_PLANE]; p_pic->p->i_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h; p_pic->p->i_visible_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h; p_pic->p->i_pitch = p_pic->p_sys->p_ctx[Y_PLANE]->pitch; p_pic->p->i_pixel_pitch = 4; p_pic->p->i_visible_pitch = p_pic->p->i_pitch; p_pic->i_planes = 1; break; case Pg_VIDEO_FORMAT_RGB555: p_vout->output.i_chroma = VLC_CODEC_RGB15; p_vout->output.i_rmask = 0x001f; p_vout->output.i_gmask = 0x03e0; p_vout->output.i_bmask = 0x7c00; p_pic->p->p_pixels = p_pic->p_sys->p_buf[Y_PLANE]; p_pic->p->i_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h; p_pic->p->i_visible_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h; p_pic->p->i_pitch = p_pic->p_sys->p_ctx[Y_PLANE]->pitch; p_pic->p->i_pixel_pitch = 2; p_pic->p->i_visible_pitch = 2 * p_pic->p_sys->p_ctx[Y_PLANE]->dim.w; p_pic->i_planes = 1; break; case Pg_VIDEO_FORMAT_RGB565: p_vout->output.i_chroma = VLC_CODEC_RGB16; p_vout->output.i_rmask = 0x001f; p_vout->output.i_gmask = 0x07e0; p_vout->output.i_bmask = 0xf800; p_pic->p->p_pixels = p_pic->p_sys->p_buf[Y_PLANE]; p_pic->p->i_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h; p_pic->p->i_visible_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h; p_pic->p->i_pitch = p_pic->p_sys->p_ctx[Y_PLANE]->pitch; p_pic->p->i_pixel_pitch = 4; p_pic->p->i_visible_pitch = 4 * p_pic->p_sys->p_ctx[Y_PLANE]->dim.w; p_pic->i_planes = 1; break; case Pg_VIDEO_FORMAT_RGB8888: p_vout->output.i_chroma = VLC_CODEC_RGB32; p_vout->output.i_rmask = 0x000000ff; p_vout->output.i_gmask = 0x0000ff00; p_vout->output.i_bmask = 0x00ff0000; p_pic->p->p_pixels = p_pic->p_sys->p_buf[Y_PLANE]; p_pic->p->i_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h; p_pic->p->i_visible_lines = p_pic->p_sys->p_ctx[Y_PLANE]->dim.h; p_pic->p->i_pitch = p_pic->p_sys->p_ctx[Y_PLANE]->pitch; p_pic->p->i_pixel_pitch = 4; p_pic->p->i_visible_pitch = 4 * p_pic->p_sys->p_ctx[Y_PLANE]->dim.w; p_pic->i_planes = 1; break; } #if 0 switch( p_vout->output.i_chroma ) { #ifdef MODULE_NAME_IS_xvideo case VLC_CODEC_Y211: p_pic->p->p_pixels = p_pic->p_sys->p_image->data + p_pic->p_sys->p_image->offsets[0]; p_pic->p->i_lines = p_vout->output.i_height; p_pic->p->i_visible_lines = p_vout->output.i_height; /* XXX: this just looks so plain wrong... check it out ! */ p_pic->p->i_pitch = p_pic->p_sys->p_image->pitches[0] / 4; p_pic->p->i_pixel_pitch = 4; p_pic->p->i_visible_pitch = p_pic->p->i_pitch; p_pic->i_planes = 1; break; #endif #endif default: /* This shouldn't happen ! */ break; } return 0; } /***************************************************************************** * FreePicture: destroy a picture allocated with NewPicture ***************************************************************************** * Destroy XImage AND associated data. If using Shm, detach shared memory * segment from server and process, then free it. The XDestroyImage manpage * says that both the image structure _and_ the data pointed to by the * image structure are freed, so no need to free p_image->data. *****************************************************************************/ static void FreePicture( vout_thread_t *p_vout, picture_t *p_pic ) { if( ( p_vout->p_sys->i_mode == MODE_NORMAL_MEM || p_vout->p_sys->i_mode == MODE_SHARED_MEM ) && p_pic->p_sys->p_image ) { PhReleaseImage( p_pic->p_sys->p_image ); free( p_pic->p_sys->p_image ); } else if( p_vout->p_sys->i_mode == MODE_VIDEO_MEM && p_pic->p_sys->p_ctx[0] ) { PhDCRelease( p_pic->p_sys->p_ctx[0] ); } free( p_pic->p_sys ); } static int ResizeOverlayOutput(vout_thread_t *p_vout) { int i_width, i_height, i_x, i_y; int i_ret; PgScalerProps_t props; props.size = sizeof( props ); props.format = p_vout->p_sys->i_vc_format; props.flags = Pg_SCALER_PROP_SCALER_ENABLE | Pg_SCALER_PROP_DOUBLE_BUFFER; /* enable chroma keying if available */ if( p_vout->p_sys->i_vc_flags & Pg_SCALER_CAP_DST_CHROMA_KEY ) { props.flags |= Pg_SCALER_PROP_CHROMA_ENABLE; } /* set viewport position */ props.viewport.ul.x = p_vout->p_sys->pos.x; props.viewport.ul.y = p_vout->p_sys->pos.y; if( !p_vout->b_fullscreen ) { props.viewport.ul.x += p_vout->p_sys->frame.ul.x; props.viewport.ul.y += p_vout->p_sys->frame.ul.y; } /* set viewport dimension */ vout_PlacePicture( p_vout, p_vout->p_sys->dim.w, p_vout->p_sys->dim.h, &i_x, &i_y, &i_width, &i_height ); props.viewport.ul.x += i_x; props.viewport.ul.y += i_y; props.viewport.lr.x = i_width + props.viewport.ul.x; props.viewport.lr.y = i_height + props.viewport.ul.y; /* set source dimension */ props.src_dim.w = p_vout->output.i_width; props.src_dim.h = p_vout->output.i_height; /* configure scaler channel */ i_ret = PgConfigScalerChannel( p_vout->p_sys->p_channel, &props ); if( i_ret == -1 ) { msg_Err( p_vout, "unable to configure video channel" ); return( 1 ); } return ( 0 ); }
/***************************************************************************** * UpdateRects: update clipping rectangles ***************************************************************************** * This function is called when the window position or size are changed, and * its job is to update the source and destination RECTs used to display the * picture. *****************************************************************************/ void UpdateRects( vout_thread_t *p_vout, bool b_force ) { #define rect_src p_vout->p_sys->rect_src #define rect_src_clipped p_vout->p_sys->rect_src_clipped #define rect_dest p_vout->p_sys->rect_dest #define rect_dest_clipped p_vout->p_sys->rect_dest_clipped unsigned int i_width, i_height, i_x, i_y; RECT rect; POINT point; /* Retrieve the window size */ GetClientRect( p_vout->p_sys->hwnd, &rect ); /* Retrieve the window position */ point.x = point.y = 0; ClientToScreen( p_vout->p_sys->hwnd, &point ); /* If nothing changed, we can return */ if( !b_force && p_vout->p_sys->i_window_width == rect.right && p_vout->p_sys->i_window_height == rect.bottom && p_vout->p_sys->i_window_x == point.x && p_vout->p_sys->i_window_y == point.y ) { return; } /* Update the window position and size */ p_vout->p_sys->i_window_x = point.x; p_vout->p_sys->i_window_y = point.y; p_vout->p_sys->i_window_width = rect.right; p_vout->p_sys->i_window_height = rect.bottom; vout_PlacePicture( p_vout, rect.right, rect.bottom, &i_x, &i_y, &i_width, &i_height ); if( p_vout->p_sys->hvideownd ) SetWindowPos( p_vout->p_sys->hvideownd, 0, i_x, i_y, i_width, i_height, SWP_NOCOPYBITS|SWP_NOZORDER|SWP_ASYNCWINDOWPOS ); /* Destination image position and dimensions */ rect_dest.left = point.x + i_x; rect_dest.right = rect_dest.left + i_width; rect_dest.top = point.y + i_y; rect_dest.bottom = rect_dest.top + i_height; #ifdef MODULE_NAME_IS_directx /* Apply overlay hardware constraints */ if( p_vout->p_sys->b_using_overlay ) { if( p_vout->p_sys->i_align_dest_boundary ) rect_dest.left = ( rect_dest.left + p_vout->p_sys->i_align_dest_boundary / 2 ) & ~p_vout->p_sys->i_align_dest_boundary; if( p_vout->p_sys->i_align_dest_size ) rect_dest.right = (( rect_dest.right - rect_dest.left + p_vout->p_sys->i_align_dest_size / 2 ) & ~p_vout->p_sys->i_align_dest_size) + rect_dest.left; } /* UpdateOverlay directdraw function doesn't automatically clip to the * display size so we need to do it otherwise it will fail */ /* Clip the destination window */ if( !IntersectRect( &rect_dest_clipped, &rect_dest, &p_vout->p_sys->rect_display ) ) { SetRectEmpty( &rect_src_clipped ); return; } #ifndef NDEBUG msg_Dbg( p_vout, "DirectXUpdateRects image_dst_clipped coords:" " %li,%li,%li,%li", rect_dest_clipped.left, rect_dest_clipped.top, rect_dest_clipped.right, rect_dest_clipped.bottom ); #endif #else /* MODULE_NAME_IS_directx */ /* AFAIK, there are no clipping constraints in Direct3D, OpenGL and GDI */ rect_dest_clipped = rect_dest; #endif /* the 2 following lines are to fix a bug when clicking on the desktop */ if( (rect_dest_clipped.right - rect_dest_clipped.left)==0 || (rect_dest_clipped.bottom - rect_dest_clipped.top)==0 ) { SetRectEmpty( &rect_src_clipped ); return; } /* src image dimensions */ rect_src.left = 0; rect_src.top = 0; rect_src.right = p_vout->render.i_width; rect_src.bottom = p_vout->render.i_height; /* Clip the source image */ rect_src_clipped.left = p_vout->fmt_out.i_x_offset + (rect_dest_clipped.left - rect_dest.left) * p_vout->fmt_out.i_visible_width / (rect_dest.right - rect_dest.left); rect_src_clipped.right = p_vout->fmt_out.i_x_offset + p_vout->fmt_out.i_visible_width - (rect_dest.right - rect_dest_clipped.right) * p_vout->fmt_out.i_visible_width / (rect_dest.right - rect_dest.left); rect_src_clipped.top = p_vout->fmt_out.i_y_offset + (rect_dest_clipped.top - rect_dest.top) * p_vout->fmt_out.i_visible_height / (rect_dest.bottom - rect_dest.top); rect_src_clipped.bottom = p_vout->fmt_out.i_y_offset + p_vout->fmt_out.i_visible_height - (rect_dest.bottom - rect_dest_clipped.bottom) * p_vout->fmt_out.i_visible_height / (rect_dest.bottom - rect_dest.top); #ifdef MODULE_NAME_IS_directx /* Apply overlay hardware constraints */ if( p_vout->p_sys->b_using_overlay ) { if( p_vout->p_sys->i_align_src_boundary ) rect_src_clipped.left = ( rect_src_clipped.left + p_vout->p_sys->i_align_src_boundary / 2 ) & ~p_vout->p_sys->i_align_src_boundary; if( p_vout->p_sys->i_align_src_size ) rect_src_clipped.right = (( rect_src_clipped.right - rect_src_clipped.left + p_vout->p_sys->i_align_src_size / 2 ) & ~p_vout->p_sys->i_align_src_size) + rect_src_clipped.left; } #endif #ifndef NDEBUG msg_Dbg( p_vout, "DirectXUpdateRects image_src_clipped" " coords: %li,%li,%li,%li", rect_src_clipped.left, rect_src_clipped.top, rect_src_clipped.right, rect_src_clipped.bottom ); #endif #ifdef MODULE_NAME_IS_directx /* The destination coordinates need to be relative to the current * directdraw primary surface (display) */ rect_dest_clipped.left -= p_vout->p_sys->rect_display.left; rect_dest_clipped.right -= p_vout->p_sys->rect_display.left; rect_dest_clipped.top -= p_vout->p_sys->rect_display.top; rect_dest_clipped.bottom -= p_vout->p_sys->rect_display.top; if( p_vout->p_sys->b_using_overlay ) DirectDrawUpdateOverlay( p_vout ); #endif #ifndef UNDER_CE /* Windows 7 taskbar thumbnail code */ LPTASKBARLIST3 p_taskbl; OSVERSIONINFO winVer; winVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); if( GetVersionEx(&winVer) && winVer.dwMajorVersion > 5 ) { CoInitialize( 0 ); if( S_OK == CoCreateInstance( &clsid_ITaskbarList, NULL, CLSCTX_INPROC_SERVER, &IID_ITaskbarList3, &p_taskbl) ) { RECT rect_video, rect_parent, rect_relative; HWND hroot = GetAncestor(p_vout->p_sys->hwnd,GA_ROOT); p_taskbl->vt->HrInit(p_taskbl); GetWindowRect(p_vout->p_sys->hvideownd, &rect_video); GetWindowRect(hroot, &rect_parent); rect_relative.left = rect_video.left - rect_parent.left - 8; rect_relative.right = rect_video.right - rect_video.left + rect_relative.left; rect_relative.top = rect_video.top - rect_parent.top - 10; rect_relative.bottom = rect_video.bottom - rect_video.top + rect_relative.top - 25; if (S_OK != p_taskbl->vt->SetThumbnailClip(p_taskbl, hroot, &rect_relative)) msg_Err( p_vout, "SetThumbNailClip failed"); p_taskbl->vt->Release(p_taskbl); } CoUninitialize(); } #endif /* Signal the change in size/position */ p_vout->p_sys->i_changes |= DX_POSITION_CHANGE; #undef rect_src #undef rect_src_clipped #undef rect_dest #undef rect_dest_clipped }
void CommonManage( vout_thread_t *p_vout ) { /* If we do not control our window, we check for geometry changes * ourselves because the parent might not send us its events. */ vlc_mutex_lock( &p_vout->p_sys->lock ); if( p_vout->p_sys->hparent && !p_vout->b_fullscreen ) { RECT rect_parent; POINT point; vlc_mutex_unlock( &p_vout->p_sys->lock ); GetClientRect( p_vout->p_sys->hparent, &rect_parent ); point.x = point.y = 0; ClientToScreen( p_vout->p_sys->hparent, &point ); OffsetRect( &rect_parent, point.x, point.y ); if( !EqualRect( &rect_parent, &p_vout->p_sys->rect_parent ) ) { p_vout->p_sys->rect_parent = rect_parent; /* FIXME I find such #ifdef quite weirds. Are they really needed ? */ #if defined(MODULE_NAME_IS_direct3d) SetWindowPos( p_vout->p_sys->hwnd, 0, 0, 0, rect_parent.right - rect_parent.left, rect_parent.bottom - rect_parent.top, SWP_NOZORDER ); UpdateRects( p_vout, true ); #else /* This one is to force the update even if only * the position has changed */ SetWindowPos( p_vout->p_sys->hwnd, 0, 1, 1, rect_parent.right - rect_parent.left, rect_parent.bottom - rect_parent.top, 0 ); SetWindowPos( p_vout->p_sys->hwnd, 0, 0, 0, rect_parent.right - rect_parent.left, rect_parent.bottom - rect_parent.top, 0 ); #if defined(MODULE_NAME_IS_wingdi) || defined(MODULE_NAME_IS_wingapi) unsigned int i_x, i_y, i_width, i_height; vout_PlacePicture( p_vout, rect_parent.right - rect_parent.left, rect_parent.bottom - rect_parent.top, &i_x, &i_y, &i_width, &i_height ); SetWindowPos( p_vout->p_sys->hvideownd, HWND_TOP, i_x, i_y, i_width, i_height, 0 ); #endif #endif } } else { vlc_mutex_unlock( &p_vout->p_sys->lock ); } /* autoscale toggle */ if( p_vout->i_changes & VOUT_SCALE_CHANGE ) { p_vout->i_changes &= ~VOUT_SCALE_CHANGE; p_vout->b_autoscale = var_GetBool( p_vout, "autoscale" ); p_vout->i_zoom = (int) ZOOM_FP_FACTOR; UpdateRects( p_vout, true ); } /* scaling factor */ if( p_vout->i_changes & VOUT_ZOOM_CHANGE ) { p_vout->i_changes &= ~VOUT_ZOOM_CHANGE; p_vout->b_autoscale = false; p_vout->i_zoom = (int)( ZOOM_FP_FACTOR * var_GetFloat( p_vout, "scale" ) ); UpdateRects( p_vout, true ); } /* Check for cropping / aspect changes */ if( p_vout->i_changes & VOUT_CROP_CHANGE || p_vout->i_changes & VOUT_ASPECT_CHANGE ) { p_vout->i_changes &= ~VOUT_CROP_CHANGE; p_vout->i_changes &= ~VOUT_ASPECT_CHANGE; p_vout->fmt_out.i_x_offset = p_vout->fmt_in.i_x_offset; p_vout->fmt_out.i_y_offset = p_vout->fmt_in.i_y_offset; p_vout->fmt_out.i_visible_width = p_vout->fmt_in.i_visible_width; p_vout->fmt_out.i_visible_height = p_vout->fmt_in.i_visible_height; p_vout->fmt_out.i_aspect = p_vout->fmt_in.i_aspect; p_vout->fmt_out.i_sar_num = p_vout->fmt_in.i_sar_num; p_vout->fmt_out.i_sar_den = p_vout->fmt_in.i_sar_den; p_vout->output.i_aspect = p_vout->fmt_in.i_aspect; UpdateRects( p_vout, true ); } /* We used to call the Win32 PeekMessage function here to read the window * messages. But since window can stay blocked into this function for a * long time (for example when you move your window on the screen), I * decided to isolate PeekMessage in another thread. */ /* * Fullscreen change */ if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE || p_vout->p_sys->i_changes & VOUT_FULLSCREEN_CHANGE ) { Win32ToggleFullscreen( p_vout ); p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE; p_vout->p_sys->i_changes &= ~VOUT_FULLSCREEN_CHANGE; } /* * Pointer change */ EventThreadMouseAutoHide( p_vout->p_sys->p_event ); /* * "Always on top" status change */ if( p_vout->p_sys->b_on_top_change ) { HMENU hMenu = GetSystemMenu( p_vout->p_sys->hwnd, FALSE ); bool b = var_GetBool( p_vout, "video-on-top" ); /* Set the window on top if necessary */ if( b && !( GetWindowLong( p_vout->p_sys->hwnd, GWL_EXSTYLE ) & WS_EX_TOPMOST ) ) { CheckMenuItem( hMenu, IDM_TOGGLE_ON_TOP, MF_BYCOMMAND | MFS_CHECKED ); SetWindowPos( p_vout->p_sys->hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE ); } else /* The window shouldn't be on top */ if( !b && ( GetWindowLong( p_vout->p_sys->hwnd, GWL_EXSTYLE ) & WS_EX_TOPMOST ) ) { CheckMenuItem( hMenu, IDM_TOGGLE_ON_TOP, MF_BYCOMMAND | MFS_UNCHECKED ); SetWindowPos( p_vout->p_sys->hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE ); } p_vout->p_sys->b_on_top_change = false; } }
/***************************************************************************** * Init: initialize omap framebuffer video thread output method *****************************************************************************/ static int Init( vout_thread_t *p_vout ) { vout_sys_t *p_sys = (vout_sys_t *)p_vout->p_sys; // We want to keep the same aspect p_vout->fmt_out.i_aspect = p_vout->output.i_aspect = p_vout->render.i_aspect; // We ask where the video should be displayed in the video area vout_PlacePicture( p_vout, p_sys->main_window.i_width, p_sys->main_window.i_height, &p_sys->output_window.i_x, &p_sys->output_window.i_y, &p_sys->output_window.i_width, &p_sys->output_window.i_height ); p_sys->output_window.i_x = ( p_sys->output_window.i_x + p_sys->main_window.i_x ) & ~1; p_sys->output_window.i_y = ( p_sys->output_window.i_y + p_sys->main_window.i_y ) & ~1; // Hardware upscaling better than software if( p_vout->fmt_render.i_width <= p_sys->main_window.i_width && p_vout->fmt_render.i_height <= p_sys->main_window.i_height ) { p_sys->i_video_width = p_vout->output.i_width = p_vout->fmt_out.i_width = p_vout->fmt_out.i_visible_width = p_vout->fmt_render.i_width; p_sys->i_video_height = p_vout->output.i_height = p_vout->fmt_out.i_height = p_vout->fmt_out.i_visible_height = p_vout->fmt_render.i_height; } else { p_sys->i_video_width = p_vout->output.i_width = p_vout->fmt_out.i_width = p_vout->fmt_out.i_visible_width = p_sys->output_window.i_width; p_sys->i_video_height = p_vout->output.i_height = p_vout->fmt_out.i_height = p_vout->fmt_out.i_visible_height = p_sys->output_window.i_height; } p_vout->output.i_chroma = p_vout->fmt_out.i_chroma = VLC_CODEC_I420; p_sys->i_color_format = OMAPFB_COLOR_YUV420; // place in the framebuffer where we have to write p_sys->p_center = p_sys->p_video + p_sys->output_window.i_x*p_sys->i_bytes_per_pixel + p_sys->output_window.i_y*p_sys->i_line_len; // We get and set a direct render vlc picture I_OUTPUTPICTURES = 0; picture_t *p_pic = NULL; int i_index; for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ ) { if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE ) { p_pic = p_vout->p_picture + i_index; break; } } /* Allocate the picture */ if( p_pic == NULL ) { return VLC_EGENERIC; } p_sys->p_output_picture = p_pic; p_pic->p->p_pixels = p_vout->p_sys->p_center; p_pic->p->i_pixel_pitch = p_vout->p_sys->i_bytes_per_pixel; p_pic->p->i_lines = p_sys->i_video_height; p_pic->p->i_visible_lines = p_sys->i_video_height; p_pic->p->i_pitch = p_sys->i_line_len; p_pic->p->i_visible_pitch = p_sys->i_line_len; p_pic->i_planes = 1; p_pic->i_status = DESTROYED_PICTURE; p_pic->i_type = DIRECT_PICTURE; PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic; I_OUTPUTPICTURES++; return VLC_SUCCESS; }