Commit 958ae35d authored by Laurent Aimar's avatar Laurent Aimar

Reworked the way pictures are handled by the vout core.

As a side effects, it may improve a bit frame stepping.
parent 889ae4fb
/*****************************************************************************
* chrono.h: vout chrono
*****************************************************************************
* Copyright (C) 2009-2010 Laurent Aimar
* $Id$
*
* Authors: Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#if defined(__PLUGIN__) || defined(__BUILTIN__) || !defined(__LIBVLC__)
# error This header file can only be included from LibVLC.
#endif
#ifndef _VOUT_CHRONO_H
#define _VOUT_CHRONO_H
typedef struct {
int shift;
mtime_t avg;
mtime_t avg_initial;
int shift_var;
mtime_t var;
mtime_t start;
} vout_chrono_t;
static inline void vout_chrono_Init(vout_chrono_t *chrono, int shift, mtime_t avg_initial)
{
chrono->shift = shift;
chrono->avg_initial =
chrono->avg = avg_initial;
chrono->shift_var = shift+1;
chrono->var = avg_initial / 2;
chrono->start = VLC_TS_INVALID;
}
static inline void vout_chrono_Clean(vout_chrono_t *chrono)
{
VLC_UNUSED(chrono);
}
static inline void vout_chrono_Start(vout_chrono_t *chrono)
{
chrono->start = mdate();
}
static inline mtime_t vout_chrono_GetHigh(vout_chrono_t *chrono)
{
return chrono->avg + 2 * chrono->var;
}
static inline mtime_t vout_chrono_GetLow(vout_chrono_t *chrono)
{
return __MAX(chrono->avg - 2 * chrono->var, 0);
}
static inline void vout_chrono_Stop(vout_chrono_t *chrono)
{
assert(chrono->start != VLC_TS_INVALID);
/* */
const mtime_t duration = mdate() - chrono->start;
const mtime_t var = llabs( duration - chrono->avg );
/* Update average only if the current point is 'valid' */
if( duration < vout_chrono_GetHigh( chrono ) )
chrono->avg = (((1 << chrono->shift) - 1) * chrono->avg + duration) >> chrono->shift;
/* Always update the variance */
chrono->var = (((1 << chrono->shift_var) - 1) * chrono->var + var) >> chrono->shift_var;
/* For assert */
chrono->start = VLC_TS_INVALID;
}
static inline void vout_chrono_Reset(vout_chrono_t *chrono)
{
vout_chrono_t ch = *chrono;
vout_chrono_Clean(chrono);
vout_chrono_Init(chrono, ch.shift, ch.avg_initial);
}
#endif
...@@ -58,7 +58,7 @@ static picture_t *VideoBufferNew(filter_t *filter) ...@@ -58,7 +58,7 @@ static picture_t *VideoBufferNew(filter_t *filter)
vd->fmt.i_width == fmt->i_width && vd->fmt.i_width == fmt->i_width &&
vd->fmt.i_height == fmt->i_height); vd->fmt.i_height == fmt->i_height);
picture_pool_t *pool = vout_display_Pool(vd, 1); picture_pool_t *pool = vout_display_Pool(vd, 3);
if (!pool) if (!pool)
return NULL; return NULL;
return picture_pool_Get(pool); return picture_pool_Get(pool);
......
This diff is collapsed.
...@@ -30,9 +30,12 @@ ...@@ -30,9 +30,12 @@
#ifndef _VOUT_INTERNAL_H #ifndef _VOUT_INTERNAL_H
#define _VOUT_INTERNAL_H 1 #define _VOUT_INTERNAL_H 1
#include <vlc_picture_fifo.h>
#include <vlc_picture_pool.h>
#include "vout_control.h" #include "vout_control.h"
#include "snapshot.h" #include "snapshot.h"
#include "statistic.h" #include "statistic.h"
#include "chrono.h"
/* Number of pictures required to computes the FPS rate */ /* Number of pictures required to computes the FPS rate */
#define VOUT_FPS_SAMPLES 20 #define VOUT_FPS_SAMPLES 20
...@@ -40,19 +43,6 @@ ...@@ -40,19 +43,6 @@
/* */ /* */
typedef struct vout_sys_t vout_sys_t; typedef struct vout_sys_t vout_sys_t;
/**
* Video picture heap, either render (to store pictures used
* by the decoder) or output (to store pictures displayed by the vout plugin)
*/
typedef struct
{
int i_pictures; /**< current heap size */
/* Real pictures */
picture_t* pp_picture[VOUT_MAX_PICTURES]; /**< pictures */
int i_last_used_pic; /**< last used pic in heap */
} picture_heap_t;
/* */ /* */
struct vout_thread_sys_t struct vout_thread_sys_t
{ {
...@@ -73,27 +63,28 @@ struct vout_thread_sys_t ...@@ -73,27 +63,28 @@ struct vout_thread_sys_t
bool b_error; bool b_error;
/* */ /* */
bool b_picture_displayed;
bool b_picture_empty; bool b_picture_empty;
mtime_t i_picture_displayed_date;
picture_t *p_picture_displayed;
int i_picture_qtype;
bool b_picture_interlaced;
vlc_cond_t picture_wait; vlc_cond_t picture_wait;
struct {
mtime_t clock;
mtime_t timestampX;
int qtype;
bool is_interlaced;
picture_t *decoded;
} displayed;
struct {
bool is_requested;
mtime_t last;
mtime_t timestamp;
} step;
/* */ /* */
vlc_mutex_t vfilter_lock; /**< video filter2 lock */ vlc_mutex_t vfilter_lock; /**< video filter2 lock */
/* */ /* */
uint32_t render_time; /**< last picture render time */
unsigned int i_par_num; /**< monitor pixel aspect-ratio */ unsigned int i_par_num; /**< monitor pixel aspect-ratio */
unsigned int i_par_den; /**< monitor pixel aspect-ratio */ unsigned int i_par_den; /**< monitor pixel aspect-ratio */
bool is_late_dropped;
/**
* These numbers are not supposed to be accurate, but are a
* good indication of the thread status */
count_t c_fps_samples; /**< picture counts */
mtime_t p_fps_sample[VOUT_FPS_SAMPLES]; /**< FPS samples dates */
/* Statistics */ /* Statistics */
vout_statistic_t statistic; vout_statistic_t statistic;
...@@ -129,24 +120,21 @@ struct vout_thread_sys_t ...@@ -129,24 +120,21 @@ struct vout_thread_sys_t
/* */ /* */
vlc_mutex_t picture_lock; /**< picture heap lock */ vlc_mutex_t picture_lock; /**< picture heap lock */
picture_pool_t *private_pool;
picture_pool_t *display_pool;
picture_pool_t *decoder_pool;
picture_fifo_t *decoder_fifo;
bool is_decoder_pool_slow;
vout_chrono_t render; /**< picture render time estimator */
vlc_mutex_t change_lock; /**< thread change lock */ vlc_mutex_t change_lock; /**< thread change lock */
uint16_t i_changes; /**< changes made to the thread. uint16_t i_changes; /**< changes made to the thread.
\see \ref vout_changes */ \see \ref vout_changes */
unsigned b_fullscreen:1; /**< toogle fullscreen display */ unsigned b_fullscreen:1; /**< toogle fullscreen display */
unsigned b_on_top:1; /**< stay always on top of other windows */ unsigned b_on_top:1; /**< stay always on top of other windows */
picture_heap_t render; /**< rendered pictures */
picture_heap_t output; /**< direct buffers */
picture_t p_picture[2*VOUT_MAX_PICTURES+1]; /**< pictures */
}; };
#define I_OUTPUTPICTURES p_vout->p->output.i_pictures
#define PP_OUTPUTPICTURE p_vout->p->output.pp_picture
#define I_RENDERPICTURES p_vout->p->render.i_pictures
#define PP_RENDERPICTURE p_vout->p->render.pp_picture
/** \defgroup vout_changes Flags for changes /** \defgroup vout_changes Flags for changes
* These flags are set in the vout_thread_t::i_changes field when another * These flags are set in the vout_thread_t::i_changes field when another
* thread changed a variable * thread changed a variable
...@@ -164,20 +152,10 @@ struct vout_thread_sys_t ...@@ -164,20 +152,10 @@ struct vout_thread_sys_t
#define VOUT_CROP_CHANGE 0x1000 #define VOUT_CROP_CHANGE 0x1000
/** aspect ratio changed */ /** aspect ratio changed */
#define VOUT_ASPECT_CHANGE 0x2000 #define VOUT_ASPECT_CHANGE 0x2000
/** change/recreate picture buffers */
#define VOUT_PICTURE_BUFFERS_CHANGE 0x4000
/**@}*/ /**@}*/
/* */ /* */
int vout_AllocatePicture( vlc_object_t *, picture_t *, uint32_t i_chroma, int i_width, int i_height, int i_sar_num, int i_sar_den );
#define vout_AllocatePicture(a,b,c,d,e,f,g) \
vout_AllocatePicture(VLC_OBJECT(a),b,c,d,e,f,g)
/* DO NOT use vout_RenderPicture/vout_IntfInit unless you are in src/video_ouput */
picture_t *vout_RenderPicture( vout_thread_t *, picture_t *,
subpicture_t *,
mtime_t render_date );
void vout_IntfInit( vout_thread_t * ); void vout_IntfInit( vout_thread_t * );
/* DO NOT use vout_UsePictureLocked unless you are in src/video_ouput /* DO NOT use vout_UsePictureLocked unless you are in src/video_ouput
......
This diff is collapsed.
...@@ -30,6 +30,9 @@ ...@@ -30,6 +30,9 @@
# include "config.h" # include "config.h"
#endif #endif
#include <assert.h>
#include <limits.h>
#include <vlc_common.h> #include <vlc_common.h>
#include <vlc_vout.h> #include <vlc_vout.h>
#include <vlc_block.h> #include <vlc_block.h>
...@@ -39,9 +42,6 @@ ...@@ -39,9 +42,6 @@
#include "vout_internal.h" #include "vout_internal.h"
#include <vlc_image.h> #include <vlc_image.h>
#include <assert.h>
#include <limits.h>
/***************************************************************************** /*****************************************************************************
* Local prototypes * Local prototypes
*****************************************************************************/ *****************************************************************************/
......
...@@ -44,12 +44,18 @@ struct vout_sys_t { ...@@ -44,12 +44,18 @@ struct vout_sys_t {
char *title; char *title;
vout_display_t *vd; vout_display_t *vd;
bool use_dr; bool use_dr;
};
struct picture_sys_t { picture_t *filtered;
picture_t *direct;
}; };
/* Minimum number of direct pictures the video output will accept without
* creating additional pictures in system memory */
#ifdef OPTIMIZE_MEMORY
# define VOUT_MIN_DIRECT_PICTURES (VOUT_MAX_PICTURES/2)
#else
# define VOUT_MIN_DIRECT_PICTURES (3*VOUT_MAX_PICTURES/4)
#endif
/***************************************************************************** /*****************************************************************************
* Local prototypes * Local prototypes
*****************************************************************************/ *****************************************************************************/
...@@ -115,6 +121,7 @@ int vout_OpenWrapper(vout_thread_t *vout, const char *name) ...@@ -115,6 +121,7 @@ int vout_OpenWrapper(vout_thread_t *vout, const char *name)
/* */ /* */
vout->p->p_sys = sys; vout->p->p_sys = sys;
vout->p->decoder_pool = NULL;
return VLC_SUCCESS; return VLC_SUCCESS;
} }
...@@ -130,6 +137,8 @@ void vout_CloseWrapper(vout_thread_t *vout) ...@@ -130,6 +137,8 @@ void vout_CloseWrapper(vout_thread_t *vout)
var_DelCallback(vout, "direct3d-desktop", Forward, NULL); var_DelCallback(vout, "direct3d-desktop", Forward, NULL);
var_DelCallback(vout, "video-wallpaper", Forward, NULL); var_DelCallback(vout, "video-wallpaper", Forward, NULL);
#endif #endif
vout->p->decoder_pool = NULL; /* FIXME remove */
vout_DeleteDisplay(sys->vd, NULL); vout_DeleteDisplay(sys->vd, NULL);
free(sys->title); free(sys->title);
free(sys ); free(sys );
...@@ -165,6 +174,7 @@ int vout_InitWrapper(vout_thread_t *vout) ...@@ -165,6 +174,7 @@ int vout_InitWrapper(vout_thread_t *vout)
vout->fmt_in.i_y_offset != source.i_y_offset ) vout->fmt_in.i_y_offset != source.i_y_offset )
vout->p->i_changes |= VOUT_CROP_CHANGE; vout->p->i_changes |= VOUT_CROP_CHANGE;
#warning "vout_InitWrapper: vout_SetWindowState should NOT be called there"
if (vout->p->b_on_top) if (vout->p->b_on_top)
vout_SetWindowState(vd, VOUT_WINDOW_STATE_ABOVE); vout_SetWindowState(vd, VOUT_WINDOW_STATE_ABOVE);
...@@ -174,52 +184,22 @@ int vout_InitWrapper(vout_thread_t *vout) ...@@ -174,52 +184,22 @@ int vout_InitWrapper(vout_thread_t *vout)
*/ */
sys->use_dr = !vout_IsDisplayFiltered(vd); sys->use_dr = !vout_IsDisplayFiltered(vd);
const bool allow_dr = !vd->info.has_pictures_invalid && sys->use_dr; const bool allow_dr = !vd->info.has_pictures_invalid && sys->use_dr;
const int picture_max = allow_dr ? VOUT_MAX_PICTURES : 1;
for (vout->p->output.i_pictures = 0;
vout->p->output.i_pictures < picture_max;
vout->p->output.i_pictures++) {
/* Find an empty picture slot */
picture_t *picture = NULL;
for (int index = 0; index < VOUT_MAX_PICTURES; index++) {
if (vout->p->p_picture[index].i_status == FREE_PICTURE) {
picture = &vout->p->p_picture[index];
break;
}
}
if (!picture)
break;
memset(picture, 0, sizeof(*picture));
picture->p_sys = malloc(sizeof(*picture->p_sys));
if (sys->use_dr) {
picture_pool_t *pool = vout_display_Pool(vd, picture_max);
if (!pool)
break;
picture_t *direct = picture_pool_Get(pool);
if (!direct)
break;
picture->format = direct->format;
picture->i_planes = direct->i_planes;
for (int i = 0; i < direct->i_planes; i++)
picture->p[i] = direct->p[i];
picture->b_slow = vd->info.is_slow;
picture->p_sys->direct = direct;
} else {
vout_AllocatePicture(VLC_OBJECT(vd), picture,
vd->source.i_chroma,
vd->source.i_width, vd->source.i_height,
vd->source.i_sar_num, vd->source.i_sar_den);
if (!picture->i_planes)
break;
picture->p_sys->direct = NULL;
}
picture->i_status = DESTROYED_PICTURE;
picture->i_type = DIRECT_PICTURE;
vout->p->output.pp_picture[vout->p->output.i_pictures] = picture; picture_pool_t *display_pool = vout_display_Pool(vd, allow_dr ? VOUT_MAX_PICTURES : 3);
if (allow_dr && picture_pool_GetSize(display_pool) >= VOUT_MIN_DIRECT_PICTURES) {
vout->p->decoder_pool = display_pool;
vout->p->display_pool = display_pool;
vout->p->is_decoder_pool_slow = vd->info.is_slow;
} else if (!vout->p->decoder_pool) {
vout->p->decoder_pool = picture_pool_NewFromFormat(&source, VOUT_MAX_PICTURES);
if (sys->use_dr)
vout->p->display_pool = display_pool;
else
vout->p->display_pool = picture_pool_Reserve(vout->p->decoder_pool, 1);;
vout->p->is_decoder_pool_slow = false;
} }
vout->p->private_pool = picture_pool_Reserve(vout->p->decoder_pool, 3); /* XXX 2 for filter, 1 for SPU */
sys->filtered = NULL;
return VLC_SUCCESS; return VLC_SUCCESS;
} }
...@@ -230,22 +210,15 @@ void vout_EndWrapper(vout_thread_t *vout) ...@@ -230,22 +210,15 @@ void vout_EndWrapper(vout_thread_t *vout)
{ {
vout_sys_t *sys = vout->p->p_sys; vout_sys_t *sys = vout->p->p_sys;
for (int i = 0; i < VOUT_MAX_PICTURES; i++) { assert(!sys->filtered);
picture_t *picture = &vout->p->p_picture[i]; if (vout->p->private_pool)
picture_pool_Delete(vout->p->private_pool);
if (picture->i_type != DIRECT_PICTURE) if (vout->p->decoder_pool != vout->p->display_pool) {
continue;
if (picture->p_sys->direct)
picture_Release(picture->p_sys->direct);
if (!sys->use_dr) if (!sys->use_dr)
free(picture->p_data_orig); picture_pool_Delete(vout->p->display_pool);
free(picture->p_sys); picture_pool_Delete(vout->p->decoder_pool);
picture->i_status = FREE_PICTURE;
} }
if (sys->use_dr && vout_AreDisplayPicturesInvalid(sys->vd))
vout_ManageDisplay(sys->vd, true);
} }
/***************************************************************************** /*****************************************************************************
...@@ -333,10 +306,12 @@ int vout_ManageWrapper(vout_thread_t *vout) ...@@ -333,10 +306,12 @@ int vout_ManageWrapper(vout_thread_t *vout)
} }
if (sys->use_dr && vout_AreDisplayPicturesInvalid(vd)) { bool reset_display_pool = sys->use_dr && vout_AreDisplayPicturesInvalid(vd);
vout->p->i_changes |= VOUT_PICTURE_BUFFERS_CHANGE; vout_ManageDisplay(vd, !sys->use_dr || reset_display_pool);
}
vout_ManageDisplay(vd, !sys->use_dr); if (reset_display_pool)
vout->p->display_pool = vout_display_Pool(vd, 3);
return VLC_SUCCESS; return VLC_SUCCESS;
} }
...@@ -348,17 +323,14 @@ void vout_RenderWrapper(vout_thread_t *vout, picture_t *picture) ...@@ -348,17 +323,14 @@ void vout_RenderWrapper(vout_thread_t *vout, picture_t *picture)
vout_sys_t *sys = vout->p->p_sys; vout_sys_t *sys = vout->p->p_sys;
vout_display_t *vd = sys->vd; vout_display_t *vd = sys->vd;
assert(sys->use_dr || !picture->p_sys->direct);
assert(vout_IsDisplayFiltered(vd) == !sys->use_dr); assert(vout_IsDisplayFiltered(vd) == !sys->use_dr);
if (sys->use_dr) { if (sys->use_dr) {
assert(picture->p_sys->direct); vout_display_Prepare(vd, picture);
vout_display_Prepare(vd, picture->p_sys->direct);
} else { } else {
picture_t *direct = picture->p_sys->direct = vout_FilterDisplay(vd, picture); sys->filtered = vout_FilterDisplay(vd, picture);
if (direct) { if (sys->filtered)
vout_display_Prepare(vd, direct); vout_display_Prepare(vd, sys->filtered);
}
} }
} }
...@@ -370,25 +342,8 @@ void vout_DisplayWrapper(vout_thread_t *vout, picture_t *picture) ...@@ -370,25 +342,8 @@ void vout_DisplayWrapper(vout_thread_t *vout, picture_t *picture)
vout_sys_t *sys = vout->p->p_sys; vout_sys_t *sys = vout->p->p_sys;
vout_display_t *vd = sys->vd; vout_display_t *vd = sys->vd;
picture_t *direct = picture->p_sys->direct; vout_display_Display(vd, sys->filtered ? sys->filtered : picture);
if (!direct) sys->filtered = NULL;
return;
/* XXX This is a hack that will work with current vout_display_t modules */
if (sys->use_dr)
picture_Hold(direct);
vout_display_Display(vd, direct);
if (sys->use_dr) {
for (int i = 0; i < picture->i_planes; i++) {
picture->p[i].p_pixels = direct->p[i].p_pixels;
picture->p[i].i_pitch = direct->p[i].i_pitch;
picture->p[i].i_lines = direct->p[i].i_lines;
}
} else {
picture->p_sys->direct = NULL;
}
} }
static void VoutGetDisplayCfg(vout_thread_t *vout, vout_display_cfg_t *cfg, const char *title) static void VoutGetDisplayCfg(vout_thread_t *vout, vout_display_cfg_t *cfg, const char *title)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment