Skip to content

Commit

Permalink
Improved support for crop/ar changes.
Browse files Browse the repository at this point in the history
Crop/AR settings can now be changed by the video filters.
Crop/AR changes done by the decoder are now applied to the exact
picture and without any picture loss (before this patch, it was applied
too soon and due to the recreation of the vout display, some pictures where
lost).
  • Loading branch information
Laurent Aimar committed Nov 7, 2010
1 parent 045ec34 commit 71e844a
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 15 deletions.
31 changes: 31 additions & 0 deletions src/video_output/display.c
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ static int vout_display_Control(vout_display_t *vd, int query, ...)

return result;
}

static void vout_display_Manage(vout_display_t *vd)
{
if (vd->manage)
Expand Down Expand Up @@ -1088,6 +1089,36 @@ picture_t *vout_FilterDisplay(vout_display_t *vd, picture_t *picture)
return filter_chain_VideoFilter(osys->filters, picture);
}

void vout_UpdateDisplaySourceProperties(vout_display_t *vd, const video_format_t *source)
{
vout_display_owner_sys_t *osys = vd->owner.sys;

if (source->i_sar_num * osys->source.i_sar_den !=
source->i_sar_den * osys->source.i_sar_num) {

osys->source.i_sar_num = source->i_sar_num;
osys->source.i_sar_den = source->i_sar_den;
vlc_ureduce(&osys->source.i_sar_num, &osys->source.i_sar_den,
osys->source.i_sar_num, osys->source.i_sar_den, 0);

/* FIXME it will override any AR that the user would have forced */
osys->ch_sar = true;
osys->sar.num = osys->source.i_sar_num;
osys->sar.den = osys->source.i_sar_den;
}
if (source->i_x_offset != osys->source.i_x_offset ||
source->i_y_offset != osys->source.i_y_offset ||
source->i_visible_width != osys->source.i_visible_width ||
source->i_visible_height != osys->source.i_visible_height) {

video_format_CopyCrop(&osys->source, source);

/* Force the vout to reapply the current user crop settings over the new decoder
* crop settings. */
osys->ch_crop = true;
}
}

void vout_SetDisplayFullscreen(vout_display_t *vd, bool is_fullscreen)
{
vout_display_owner_sys_t *osys = vd->owner.sys;
Expand Down
2 changes: 2 additions & 0 deletions src/video_output/display.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,3 +117,5 @@ vout_display_t *vout_NewSplitter(vout_thread_t *vout,
void vout_SendDisplayEventMouse(vout_thread_t *, const vlc_mouse_t *);
vout_window_t *vout_NewDisplayWindow(vout_thread_t *, vout_display_t *, const vout_window_cfg_t *);
void vout_DeleteDisplayWindow(vout_thread_t *, vout_display_t *, vout_window_t *);
void vout_UpdateDisplaySourceProperties(vout_display_t *vd, const video_format_t *);

77 changes: 62 additions & 15 deletions src/video_output/video_output.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,22 @@ static int VoutValidateFormat(video_format_t *dst,
video_format_FixRgb(dst);
return VLC_SUCCESS;
}
static void VideoFormatCopyCropAr(video_format_t *dst,
const video_format_t *src)
{
video_format_CopyCrop(dst, src);
dst->i_sar_num = src->i_sar_num;
dst->i_sar_den = src->i_sar_den;
}
static bool VideoFormatIsCropArEqual(video_format_t *dst,
const video_format_t *src)
{
return dst->i_sar_num * src->i_sar_den == dst->i_sar_den * src->i_sar_num &&
dst->i_x_offset == src->i_x_offset &&
dst->i_y_offset == src->i_y_offset &&
dst->i_visible_width == src->i_visible_width &&
dst->i_visible_height == src->i_visible_height;
}

static vout_thread_t *VoutCreate(vlc_object_t *object,
const vout_configuration_t *cfg)
Expand Down Expand Up @@ -386,6 +402,7 @@ picture_t *vout_GetPicture(vout_thread_t *vout)
if (picture) {
picture_Reset(picture);
picture->p_next = NULL;
VideoFormatCopyCropAr(&picture->format, &vout->p->original);
}
vlc_mutex_unlock(&vout->p->picture_lock);

Expand Down Expand Up @@ -641,12 +658,14 @@ void vout_DeleteDisplayWindow(vout_thread_t *vout, vout_display_t *vd,
}

/* */

static picture_t *VoutVideoFilterInteractiveNewPicture(filter_t *filter)
{
vout_thread_t *vout = (vout_thread_t*)filter->p_owner;

return picture_pool_Get(vout->p->private_pool);
picture_t *picture = picture_pool_Get(vout->p->private_pool);
if (picture)
VideoFormatCopyCropAr(&picture->format, &filter->fmt_out.video);
return picture;
}
static picture_t *VoutVideoFilterStaticNewPicture(filter_t *filter)
{
Expand All @@ -655,6 +674,7 @@ static picture_t *VoutVideoFilterStaticNewPicture(filter_t *filter)
vlc_assert_locked(&vout->p->filter.lock);
if (filter_chain_GetLength(vout->p->filter.chain_interactive) == 0)
return VoutVideoFilterInteractiveNewPicture(filter);

return picture_NewFromFormat(&filter->fmt_out.video);
}
static void VoutVideoFilterDelPicture(filter_t *filter, picture_t *picture)
Expand All @@ -676,8 +696,7 @@ static int VoutVideoFilterInteractiveAllocationSetup(filter_t *filter, void *dat
filter->p_owner = data; /* vout */
return VLC_SUCCESS;
}

static void ThreadFilterFlush(vout_thread_t *vout)
static void ThreadFilterFlush(vout_thread_t *vout, bool is_locked)
{
if (vout->p->displayed.current)
picture_Release( vout->p->displayed.current );
Expand All @@ -687,20 +706,25 @@ static void ThreadFilterFlush(vout_thread_t *vout)
picture_Release( vout->p->displayed.next );
vout->p->displayed.next = NULL;

vlc_mutex_lock(&vout->p->filter.lock);
if (!is_locked)
vlc_mutex_lock(&vout->p->filter.lock);
filter_chain_VideoFlush(vout->p->filter.chain_static);
filter_chain_VideoFlush(vout->p->filter.chain_interactive);
vlc_mutex_unlock(&vout->p->filter.lock);
if (!is_locked)
vlc_mutex_unlock(&vout->p->filter.lock);
}

typedef struct {
char *name;
config_chain_t *cfg;
} vout_filter_t;

static void ThreadChangeFilters(vout_thread_t *vout, const char *filters)
static void ThreadChangeFilters(vout_thread_t *vout,
const video_format_t *source,
const char *filters,
bool is_locked)
{
ThreadFilterFlush(vout);
ThreadFilterFlush(vout, is_locked);

vlc_array_t array_static;
vlc_array_t array_interactive;
Expand Down Expand Up @@ -732,13 +756,14 @@ static void ThreadChangeFilters(vout_thread_t *vout, const char *filters)
current = next;
}

if (!is_locked)
vlc_mutex_lock(&vout->p->filter.lock);

es_format_t fmt_target;
es_format_InitFromVideo(&fmt_target, &vout->p->original);
es_format_InitFromVideo(&fmt_target, source ? source : &vout->p->filter.format);

es_format_t fmt_current = fmt_target;

vlc_mutex_lock(&vout->p->filter.lock);

for (int a = 0; a < 2; a++) {
vlc_array_t *array = a == 0 ? &array_static :
&array_interactive;
Expand All @@ -759,6 +784,7 @@ static void ThreadChangeFilters(vout_thread_t *vout, const char *filters)
fmt_current = *filter_chain_GetFmtOut(chain);
vlc_array_clear(array);
}
VideoFormatCopyCropAr(&fmt_target.video, &fmt_current.video);
if (!es_format_IsSimilar(&fmt_current, &fmt_target)) {
msg_Dbg(vout, "Adding a filter to compensate for format changes");
if (!filter_chain_AppendFilter(vout->p->filter.chain_interactive, NULL, NULL,
Expand All @@ -769,9 +795,20 @@ static void ThreadChangeFilters(vout_thread_t *vout, const char *filters)
}
}

vlc_mutex_unlock(&vout->p->filter.lock);
if (vout->p->filter.configuration != filters) {
free(vout->p->filter.configuration);
vout->p->filter.configuration = filters ? strdup(filters) : NULL;
}
if (source) {
video_format_Clean(&vout->p->filter.format);
video_format_Copy(&vout->p->filter.format, source);
}

if (!is_locked)
vlc_mutex_unlock(&vout->p->filter.lock);
}


/* */
static int ThreadDisplayPreparePicture(vout_thread_t *vout, bool reuse, bool is_late_dropped)
{
Expand Down Expand Up @@ -800,6 +837,9 @@ static int ThreadDisplayPreparePicture(vout_thread_t *vout, bool reuse, bool is_
msg_Dbg(vout, "picture might be displayed late (missing %d ms)", (int)(late/1000));
}
}
if (decoded &&
!VideoFormatIsCropArEqual(&decoded->format, &vout->p->filter.format))
ThreadChangeFilters(vout, &decoded->format, vout->p->filter.configuration, true);
}
if (!decoded)
break;
Expand Down Expand Up @@ -895,6 +935,7 @@ static int ThreadDisplayRenderPicture(vout_thread_t *vout, bool is_forced)
} else {
direct = render;
}
VideoFormatCopyCropAr(&direct->format, &filtered->format);
picture_Release(filtered);
filtered = NULL;
} else {
Expand Down Expand Up @@ -1080,7 +1121,7 @@ static void ThreadChangePause(vout_thread_t *vout, bool is_paused, mtime_t date)
vout->p->displayed.decoded->date += duration;
spu_OffsetSubtitleDate(vout->p->spu, duration);

ThreadFilterFlush(vout);
ThreadFilterFlush(vout, false);
} else {
vout->p->step.timestamp = VLC_TS_INVALID;
vout->p->step.last = VLC_TS_INVALID;
Expand All @@ -1094,7 +1135,7 @@ static void ThreadFlush(vout_thread_t *vout, bool below, mtime_t date)
vout->p->step.timestamp = VLC_TS_INVALID;
vout->p->step.last = VLC_TS_INVALID;

ThreadFilterFlush(vout); /* FIXME too much */
ThreadFilterFlush(vout, false); /* FIXME too much */

picture_t *last = vout->p->displayed.decoded;
if (last) {
Expand Down Expand Up @@ -1210,6 +1251,8 @@ static int ThreadStart(vout_thread_t *vout, const vout_display_state_t *state)
vout->p->display_pool = NULL;
vout->p->private_pool = NULL;

vout->p->filter.configuration = NULL;
video_format_Copy(&vout->p->filter.format, &vout->p->original);
vout->p->filter.chain_static =
filter_chain_New( vout, "video filter2", true,
VoutVideoFilterStaticAllocationSetup, NULL, vout);
Expand Down Expand Up @@ -1263,6 +1306,8 @@ static void ThreadStop(vout_thread_t *vout, vout_display_state_t *state)
/* Destroy the video filters2 */
filter_chain_Delete(vout->p->filter.chain_interactive);
filter_chain_Delete(vout->p->filter.chain_static);
video_format_Clean(&vout->p->filter.format);
free(vout->p->filter.configuration);

if (vout->p->decoder_fifo)
picture_fifo_Delete(vout->p->decoder_fifo);
Expand Down Expand Up @@ -1301,6 +1346,8 @@ static int ThreadReinit(vout_thread_t *vout,
ThreadClean(vout);
return VLC_EGENERIC;
}
/* We ignore crop/ar changes at this point, they are dynamically supported */
VideoFormatCopyCropAr(&vout->p->original, &original);
if (video_format_IsSimilar(&original, &vout->p->original)) {
if (cfg->dpb_size <= vout->p->dpb_size)
return VLC_SUCCESS;
Expand Down Expand Up @@ -1384,7 +1431,7 @@ static void *Thread(void *object)
ThreadDisplayOsdTitle(vout, cmd.u.string);
break;
case VOUT_CONTROL_CHANGE_FILTERS:
ThreadChangeFilters(vout, cmd.u.string);
ThreadChangeFilters(vout, NULL, cmd.u.string, false);
break;
case VOUT_CONTROL_CHANGE_SUB_FILTERS:
ThreadChangeSubFilters(vout, cmd.u.string);
Expand Down
2 changes: 2 additions & 0 deletions src/video_output/vout_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,8 @@ struct vout_thread_sys_t
/* Video filter2 chain */
struct {
vlc_mutex_t lock;
char *configuration;
video_format_t format;
filter_chain_t *chain_static;
filter_chain_t *chain_interactive;
} filter;
Expand Down
1 change: 1 addition & 0 deletions src/video_output/vout_wrapper.c
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ void vout_RenderWrapper(vout_thread_t *vout, picture_t *picture)

assert(vout_IsDisplayFiltered(vd) == !sys->display.use_dr);

vout_UpdateDisplaySourceProperties(vd, &picture->format);
if (sys->display.use_dr) {
vout_display_Prepare(vd, picture);
} else {
Expand Down

0 comments on commit 71e844a

Please sign in to comment.