- free( p_vout->p->psz_filter_chain );
- free( p_vout->p->psz_title );
-
- config_ChainDestroy( p_vout->p_cfg );
-
- free( p_vout->p );
-
-#ifndef __APPLE__
- vout_thread_t *p_another_vout;
-
- /* This is a dirty hack mostly for Linux, where there is no way to get the
- * GUI back if you closed it while playing video. This is solved in
- * Mac OS X, where we have this novelty called menubar, that will always
- * allow you access to the applications main functionality. They should try
- * that on linux sometime. */
- p_another_vout = vlc_object_find( p_this->p_libvlc,
- VLC_OBJECT_VOUT, FIND_ANYWHERE );
- if( p_another_vout == NULL )
- var_SetBool( p_this->p_libvlc, "intf-show", true );
- else
- vlc_object_release( p_another_vout );
-#endif
-}
-
-/* */
-void vout_ChangePause( vout_thread_t *p_vout, bool b_paused, mtime_t i_date )
-{
- vlc_mutex_lock( &p_vout->change_lock );
-
- assert( !p_vout->p->b_paused || !b_paused );
-
- vlc_mutex_lock( &p_vout->picture_lock );
-
- p_vout->p->i_picture_displayed_date = 0;
-
- if( p_vout->p->b_paused )
- {
- const mtime_t i_duration = i_date - p_vout->p->i_pause_date;
-
- for( int i_index = 0; i_index < I_RENDERPICTURES; i_index++ )
- {
- picture_t *p_pic = PP_RENDERPICTURE[i_index];
-
- if( p_pic->i_status == READY_PICTURE )
- p_pic->date += i_duration;
- }
- vlc_cond_signal( &p_vout->p->picture_wait );
- vlc_mutex_unlock( &p_vout->picture_lock );
-
- spu_OffsetSubtitleDate( p_vout->p_spu, i_duration );
- }
- else
- {
- vlc_mutex_unlock( &p_vout->picture_lock );
- }
- p_vout->p->b_paused = b_paused;
- p_vout->p->i_pause_date = i_date;
-
- vlc_mutex_unlock( &p_vout->change_lock );
-}
-
-void vout_GetResetStatistic( vout_thread_t *p_vout, int *pi_displayed, int *pi_lost )
-{
- vlc_mutex_lock( &p_vout->change_lock );
-
- *pi_displayed = p_vout->p->i_picture_displayed;
- *pi_lost = p_vout->p->i_picture_lost;
-
- p_vout->p->i_picture_displayed = 0;
- p_vout->p->i_picture_lost = 0;
-
- vlc_mutex_unlock( &p_vout->change_lock );
-}
-
-void vout_Flush( vout_thread_t *p_vout, mtime_t i_date )
-{
- vlc_mutex_lock( &p_vout->picture_lock );
- p_vout->p->i_picture_displayed_date = 0;
- for( int i = 0; i < p_vout->render.i_pictures; i++ )
- {
- picture_t *p_pic = p_vout->render.pp_picture[i];
-
- if( p_pic->i_status == READY_PICTURE ||
- p_pic->i_status == DISPLAYED_PICTURE )
- {
- /* We cannot change picture status if it is in READY_PICTURE state,
- * Just make sure they won't be displayed */
- if( p_pic->date > i_date )
- p_pic->date = i_date;
- }
- }
- vlc_cond_signal( &p_vout->p->picture_wait );
- vlc_mutex_unlock( &p_vout->picture_lock );
-}
-
-void vout_FixLeaks( vout_thread_t *p_vout, bool b_forced )
-{
- int i_pic, i_ready_pic;
-
- vlc_mutex_lock( &p_vout->picture_lock );
-
- for( i_pic = 0, i_ready_pic = 0; i_pic < p_vout->render.i_pictures && !b_forced; i_pic++ )
- {
- const picture_t *p_pic = p_vout->render.pp_picture[i_pic];
-
- if( p_pic->i_status == READY_PICTURE )
- {
- i_ready_pic++;
- /* If we have at least 2 ready pictures, wait for the vout thread to
- * process one */
- if( i_ready_pic >= 2 )
- break;
-
- continue;
- }
-
- if( p_pic->i_status == DISPLAYED_PICTURE )
- {
- /* If at least one displayed picture is not referenced
- * let vout free it */
- if( p_pic->i_refcount == 0 )
- break;
- }
- }
- if( i_pic < p_vout->render.i_pictures && !b_forced )
- {
- vlc_mutex_unlock( &p_vout->picture_lock );
- return;
- }
-
- /* Too many pictures are still referenced, there is probably a bug
- * with the decoder */
- if( !b_forced )
- msg_Err( p_vout, "pictures leaked, resetting the heap" );
-
- /* Just free all the pictures */
- for( i_pic = 0; i_pic < p_vout->render.i_pictures; i_pic++ )
- {
- picture_t *p_pic = p_vout->render.pp_picture[i_pic];
-
- msg_Dbg( p_vout, "[%d] %d %d", i_pic, p_pic->i_status, p_pic->i_refcount );
- p_pic->i_refcount = 0;
-
- switch( p_pic->i_status )
- {
- case READY_PICTURE:
- case DISPLAYED_PICTURE:
- case RESERVED_PICTURE:
- if( p_pic != p_vout->p->p_picture_displayed )
- vout_UsePictureLocked( p_vout, p_pic );
- break;
- }
- }
- vlc_cond_signal( &p_vout->p->picture_wait );
- vlc_mutex_unlock( &p_vout->picture_lock );
-}
-void vout_NextPicture( vout_thread_t *p_vout, mtime_t *pi_duration )
-{
- vlc_mutex_lock( &p_vout->picture_lock );
-
- const mtime_t i_displayed_date = p_vout->p->i_picture_displayed_date;
-
- p_vout->p->b_picture_displayed = false;
- p_vout->p->b_picture_empty = false;
- if( p_vout->p->p_picture_displayed )
- {
- p_vout->p->p_picture_displayed->date = 1;
- vlc_cond_signal( &p_vout->p->picture_wait );
- }
-
- while( !p_vout->p->b_picture_displayed && !p_vout->p->b_picture_empty )
- vlc_cond_wait( &p_vout->p->picture_wait, &p_vout->picture_lock );
-
- *pi_duration = __MAX( p_vout->p->i_picture_displayed_date - i_displayed_date, 0 );
-
- /* TODO advance subpicture by the duration ... */
-
- vlc_mutex_unlock( &p_vout->picture_lock );
-}
-
-void vout_DisplayTitle( vout_thread_t *p_vout, const char *psz_title )
-{
- assert( psz_title );
-
- if( !config_GetInt( p_vout, "osd" ) )
- return;
-
- vlc_mutex_lock( &p_vout->change_lock );
- free( p_vout->p->psz_title );
- p_vout->p->psz_title = strdup( psz_title );
- vlc_mutex_unlock( &p_vout->change_lock );
-}
-
-/*****************************************************************************
- * InitThread: initialize video output thread
- *****************************************************************************
- * This function is called from RunThread and performs the second step of the
- * initialization. It returns 0 on success. Note that the thread's flag are not
- * modified inside this function.
- * XXX You have to enter it with change_lock taken.
- *****************************************************************************/
-static int ChromaCreate( vout_thread_t *p_vout );
-static void ChromaDestroy( vout_thread_t *p_vout );
-
-static bool ChromaIsEqual( const picture_heap_t *p_output, const picture_heap_t *p_render )
-{
- if( !vout_ChromaCmp( p_output->i_chroma, p_render->i_chroma ) )
- return false;
-
- if( p_output->i_chroma != VLC_CODEC_RGB15 &&
- p_output->i_chroma != VLC_CODEC_RGB16 &&
- p_output->i_chroma != VLC_CODEC_RGB24 &&
- p_output->i_chroma != VLC_CODEC_RGB32 )
- return true;
-
- return p_output->i_rmask == p_render->i_rmask &&
- p_output->i_gmask == p_render->i_gmask &&
- p_output->i_bmask == p_render->i_bmask;
-}
-
-static int InitThread( vout_thread_t *p_vout )
-{
- int i, i_aspect_x, i_aspect_y;
-
- /* Initialize output method, it allocates direct buffers for us */
- if( p_vout->pf_init( p_vout ) )
- return VLC_EGENERIC;
-
- p_vout->p->p_picture_displayed = NULL;
-
- if( !I_OUTPUTPICTURES )
- {
- msg_Err( p_vout, "plugin was unable to allocate at least "
- "one direct buffer" );
- p_vout->pf_end( p_vout );
- return VLC_EGENERIC;
- }
-
- if( I_OUTPUTPICTURES > VOUT_MAX_PICTURES )
- {
- msg_Err( p_vout, "plugin allocated too many direct buffers, "
- "our internal buffers must have overflown." );
- p_vout->pf_end( p_vout );
- return VLC_EGENERIC;
- }
-
- msg_Dbg( p_vout, "got %i direct buffer(s)", I_OUTPUTPICTURES );
-
- AspectRatio( p_vout->fmt_render.i_aspect, &i_aspect_x, &i_aspect_y );
-
- AspectRatio( p_vout->fmt_in.i_aspect, &i_aspect_x, &i_aspect_y );
-
- if( !p_vout->fmt_out.i_width || !p_vout->fmt_out.i_height )
- {
- p_vout->fmt_out.i_width = p_vout->fmt_out.i_visible_width =
- p_vout->output.i_width;
- p_vout->fmt_out.i_height = p_vout->fmt_out.i_visible_height =
- p_vout->output.i_height;
- p_vout->fmt_out.i_x_offset = p_vout->fmt_out.i_y_offset = 0;
-
- p_vout->fmt_out.i_aspect = p_vout->output.i_aspect;
- p_vout->fmt_out.i_chroma = p_vout->output.i_chroma;
- }
- if( !p_vout->fmt_out.i_sar_num || !p_vout->fmt_out.i_sar_num )
- {
- p_vout->fmt_out.i_sar_num = p_vout->fmt_out.i_aspect *
- p_vout->fmt_out.i_height;
- p_vout->fmt_out.i_sar_den = VOUT_ASPECT_FACTOR *
- p_vout->fmt_out.i_width;
- }
-
- vlc_ureduce( &p_vout->fmt_out.i_sar_num, &p_vout->fmt_out.i_sar_den,
- p_vout->fmt_out.i_sar_num, p_vout->fmt_out.i_sar_den, 0 );
-
- AspectRatio( p_vout->fmt_out.i_aspect, &i_aspect_x, &i_aspect_y );
-
- /* FIXME removed the need of both fmt_* and heap infos */
- /* Calculate shifts from system-updated masks */
- PictureHeapFixRgb( &p_vout->render );
- VideoFormatImportRgb( &p_vout->fmt_render, &p_vout->render );
-
- PictureHeapFixRgb( &p_vout->output );
- VideoFormatImportRgb( &p_vout->fmt_out, &p_vout->output );
-
- /* print some usefull debug info about different vout formats
- */
- msg_Dbg( p_vout, "pic render sz %ix%i, of (%i,%i), vsz %ix%i, 4cc %4.4s, ar %i:%i, sar %i:%i, msk r0x%x g0x%x b0x%x",
- p_vout->fmt_render.i_width, p_vout->fmt_render.i_height,
- p_vout->fmt_render.i_x_offset, p_vout->fmt_render.i_y_offset,
- p_vout->fmt_render.i_visible_width,
- p_vout->fmt_render.i_visible_height,
- (char*)&p_vout->fmt_render.i_chroma,
- i_aspect_x, i_aspect_y,
- p_vout->fmt_render.i_sar_num, p_vout->fmt_render.i_sar_den,
- p_vout->fmt_render.i_rmask, p_vout->fmt_render.i_gmask, p_vout->fmt_render.i_bmask );
-
- msg_Dbg( p_vout, "pic in sz %ix%i, of (%i,%i), vsz %ix%i, 4cc %4.4s, ar %i:%i, sar %i:%i, msk r0x%x g0x%x b0x%x",
- p_vout->fmt_in.i_width, p_vout->fmt_in.i_height,
- p_vout->fmt_in.i_x_offset, p_vout->fmt_in.i_y_offset,
- p_vout->fmt_in.i_visible_width,
- p_vout->fmt_in.i_visible_height,
- (char*)&p_vout->fmt_in.i_chroma,
- i_aspect_x, i_aspect_y,
- p_vout->fmt_in.i_sar_num, p_vout->fmt_in.i_sar_den,
- p_vout->fmt_in.i_rmask, p_vout->fmt_in.i_gmask, p_vout->fmt_in.i_bmask );
-
- msg_Dbg( p_vout, "pic out sz %ix%i, of (%i,%i), vsz %ix%i, 4cc %4.4s, ar %i:%i, sar %i:%i, msk r0x%x g0x%x b0x%x",
- p_vout->fmt_out.i_width, p_vout->fmt_out.i_height,
- p_vout->fmt_out.i_x_offset, p_vout->fmt_out.i_y_offset,
- p_vout->fmt_out.i_visible_width,
- p_vout->fmt_out.i_visible_height,
- (char*)&p_vout->fmt_out.i_chroma,
- i_aspect_x, i_aspect_y,
- p_vout->fmt_out.i_sar_num, p_vout->fmt_out.i_sar_den,
- p_vout->fmt_out.i_rmask, p_vout->fmt_out.i_gmask, p_vout->fmt_out.i_bmask );
-
- /* Check whether we managed to create direct buffers similar to
- * the render buffers, ie same size and chroma */
- if( ( p_vout->output.i_width == p_vout->render.i_width )
- && ( p_vout->output.i_height == p_vout->render.i_height )
- && ( ChromaIsEqual( &p_vout->output, &p_vout->render ) ) )
- {
- /* Cool ! We have direct buffers, we can ask the decoder to
- * directly decode into them ! Map the first render buffers to
- * the first direct buffers, but keep the first direct buffer
- * for memcpy operations */
- p_vout->p->b_direct = true;
-
- for( i = 1; i < VOUT_MAX_PICTURES; i++ )
- {
- if( p_vout->p_picture[ i ].i_type != DIRECT_PICTURE &&
- I_RENDERPICTURES >= VOUT_MIN_DIRECT_PICTURES - 1 &&
- p_vout->p_picture[ i - 1 ].i_type == DIRECT_PICTURE )
- {
- /* We have enough direct buffers so there's no need to
- * try to use system memory buffers. */
- break;
- }
- PP_RENDERPICTURE[ I_RENDERPICTURES ] = &p_vout->p_picture[ i ];
- I_RENDERPICTURES++;
- }
-
- msg_Dbg( p_vout, "direct render, mapping "
- "render pictures 0-%i to system pictures 1-%i",
- VOUT_MAX_PICTURES - 2, VOUT_MAX_PICTURES - 1 );
- }
- else
- {
- /* Rats... Something is wrong here, we could not find an output
- * plugin able to directly render what we decode. See if we can
- * find a chroma plugin to do the conversion */
- p_vout->p->b_direct = false;
-
- if( ChromaCreate( p_vout ) )
- {
- p_vout->pf_end( p_vout );
- return VLC_EGENERIC;
- }
-
- msg_Dbg( p_vout, "indirect render, mapping "
- "render pictures 0-%i to system pictures %i-%i",
- VOUT_MAX_PICTURES - 1, I_OUTPUTPICTURES,
- I_OUTPUTPICTURES + VOUT_MAX_PICTURES - 1 );
-
- /* Append render buffers after the direct buffers */
- for( i = I_OUTPUTPICTURES; i < 2 * VOUT_MAX_PICTURES; i++ )
- {
- PP_RENDERPICTURE[ I_RENDERPICTURES ] = &p_vout->p_picture[ i ];
- I_RENDERPICTURES++;
-
- /* Check if we have enough render pictures */
- if( I_RENDERPICTURES == VOUT_MAX_PICTURES )
- break;
- }
- }
-
- return VLC_SUCCESS;
-}
-
-/*****************************************************************************
- * RunThread: video output thread
- *****************************************************************************
- * Video output thread. This function does only returns when the thread is
- * terminated. It handles the pictures arriving in the video heap and the
- * display device events.
- *****************************************************************************/
-static void* RunThread( void *p_this )
-{
- vout_thread_t *p_vout = p_this;
- int i_idle_loops = 0; /* loops without displaying a picture */
- int i_picture_qtype_last = QTYPE_NONE;
-
- bool b_drop_late;
-
- /*
- * Initialize thread
- */
- vlc_mutex_lock( &p_vout->change_lock );
- p_vout->b_error = InitThread( p_vout );
-
- b_drop_late = var_CreateGetBool( p_vout, "drop-late-frames" );
-
- /* signal the creation of the vout */
- p_vout->p->b_ready = true;
- vlc_cond_signal( &p_vout->p->change_wait );
-
- if( p_vout->b_error )
- {
- EndThread( p_vout );
- vlc_mutex_unlock( &p_vout->change_lock );