[vlc-devel] [PATCH 08/19] deinterlace: implement draining of extra pictures
Steve Lhomme
robux4 at ycbcr.xyz
Tue Oct 13 15:51:51 CEST 2020
Each filter using the common deinterlacing code now calls DoDrain (similar to
DoDeinterlacing) to do its draining.
We no longer return pictures chained using vlc_picture_chain_AppendChain().
DoDraining calls DoDeinterlacing internally with a NULL input picture. To
create secondary pictures, the state to create the same pictures that were
appended before is kept in the filter p_sys. The prev_pic is the original
picture used to create the primary and secondary pictures. The picture is
released when there is no more pictures to produce from this picture or during
a Flush.
Now DoDeinterlacing() only outputs one picture at a time. By default it outputs
the current_field == 0 picture, then extra pictures up to max_fields.
---
modules/hw/d3d11/d3d11_deinterlace.c | 12 ++
modules/hw/d3d9/dxva2_deinterlace.c | 7 +
modules/video_filter/deinterlace/common.c | 152 +++++++++---------
modules/video_filter/deinterlace/common.h | 5 +
.../video_filter/deinterlace/deinterlace.c | 7 +
5 files changed, 107 insertions(+), 76 deletions(-)
diff --git a/modules/hw/d3d11/d3d11_deinterlace.c b/modules/hw/d3d11/d3d11_deinterlace.c
index a61160a9c05..c15e01d9164 100644
--- a/modules/hw/d3d11/d3d11_deinterlace.c
+++ b/modules/hw/d3d11/d3d11_deinterlace.c
@@ -174,6 +174,17 @@ static picture_t *Deinterlace(filter_t *p_filter, picture_t *p_pic)
return res;
}
+static picture_t *Drain(filter_t *p_filter)
+{
+ filter_sys_t *p_sys = p_filter->p_sys;
+
+ d3d11_device_lock( p_sys->d3d_dev );
+ picture_t *res = DoDraining( p_filter, &p_sys->context );
+ d3d11_device_unlock( p_sys->d3d_dev );
+
+ return res;
+}
+
static const struct filter_mode_t *GetFilterMode(const char *mode)
{
if ( mode == NULL || !strcmp( mode, "auto" ) )
@@ -244,6 +255,7 @@ static void D3D11CloseDeinterlace(filter_t *filter)
static const struct vlc_filter_operations filter_ops = {
.filter_video = Deinterlace, .flush = Flush, .close = D3D11CloseDeinterlace,
+ .drain_video = Drain,
};
int D3D11OpenDeinterlace(filter_t *filter)
diff --git a/modules/hw/d3d9/dxva2_deinterlace.c b/modules/hw/d3d9/dxva2_deinterlace.c
index 65cacdad59b..ba8a0ebfed4 100644
--- a/modules/hw/d3d9/dxva2_deinterlace.c
+++ b/modules/hw/d3d9/dxva2_deinterlace.c
@@ -268,6 +268,12 @@ static picture_t *Deinterlace(filter_t *p_filter, picture_t *p_pic)
return DoDeinterlacing( p_filter, &p_sys->context, p_pic );
}
+static picture_t *Drain(filter_t *p_filter)
+{
+ filter_sys_t *p_sys = p_filter->p_sys;
+ return DoDraining( p_filter, &p_sys->context );
+}
+
static const struct filter_mode_t *GetFilterMode(const char *mode)
{
if ( mode == NULL || !strcmp( mode, "auto" ) )
@@ -337,6 +343,7 @@ static void D3D9CloseDeinterlace(filter_t *filter)
static const struct vlc_filter_operations filter_ops = {
.filter_video = Deinterlace, .flush = Flush, .close = D3D9CloseDeinterlace,
+ .drain_video = Drain,
};
int D3D9OpenDeinterlace(filter_t *filter)
diff --git a/modules/video_filter/deinterlace/common.c b/modules/video_filter/deinterlace/common.c
index 94a6280e37e..1f55b6c4d3b 100644
--- a/modules/video_filter/deinterlace/common.c
+++ b/modules/video_filter/deinterlace/common.c
@@ -49,6 +49,10 @@ void InitDeinterlacingContext( struct deinterlace_ctx *p_context )
cannot have offset) */
for( int i = 0; i < HISTORY_SIZE; i++ )
p_context->pp_history[i] = NULL;
+
+ p_context->prev_pic = NULL;
+ p_context->current_field = 0;
+ p_context->max_fields = 0;
}
void FlushDeinterlacing(struct deinterlace_ctx *p_context)
@@ -67,6 +71,11 @@ void FlushDeinterlacing(struct deinterlace_ctx *p_context)
picture_Release( p_context->pp_history[i] );
p_context->pp_history[i] = NULL;
}
+ if ( p_context->prev_pic )
+ {
+ picture_Release( p_context->prev_pic );
+ p_context->prev_pic = NULL;
+ }
}
vlc_tick_t GetFieldDuration(const struct deinterlace_ctx *p_context,
@@ -127,7 +136,6 @@ void GetDeinterlacingOutput( const struct deinterlace_ctx *p_context,
picture_t *DoDeinterlacing( filter_t *p_filter,
struct deinterlace_ctx *p_context, picture_t *p_pic )
{
- picture_t *p_dst[DEINTERLACE_DST_SIZE];
int i_double_rate_alloc_end;
/* Remember the frame offset that we should use for this frame.
The value in p_sys will be updated to reflect the correct value
@@ -137,20 +145,32 @@ picture_t *DoDeinterlacing( filter_t *p_filter,
bool b_top_field_first;
- /* Request output picture */
- p_dst[0] = AllocPicture( p_filter );
- if( p_dst[0] == NULL )
+ if ( p_context->current_field == p_context->max_fields )
{
- picture_Release( p_pic );
- return NULL;
+ if( p_pic == NULL )
+ return NULL; // there's nothing else to drain
+ }
+ if ( p_context->current_field != 0 )
+ {
+ assert(p_pic == NULL); // we are draining the output
+ p_pic = p_context->prev_pic;
}
- picture_CopyProperties( p_dst[0], p_pic );
- /* Any unused p_dst pointers must be NULL, because they are used to
- check how many output frames we have. */
- for( int i = 1; i < DEINTERLACE_DST_SIZE; ++i )
- p_dst[i] = NULL;
+ /* Request output picture */
+ picture_t *p_dst = AllocPicture( p_filter );
+ if( p_dst == NULL )
+ {
+ if ( p_context->current_field != 0 )
+ msg_Err( p_filter, "Framerate doubler: could not allocate "\
+ "output frame %d", p_context->current_field+1 );
+ goto exit;
+ }
+ picture_CopyProperties( p_dst, p_pic );
+ p_dst->b_progressive = true;
+ p_dst->i_nb_fields = 2;
+ if ( p_context->current_field == 0 )
+ {
/* Update the input frame history, if the currently active algorithm
needs it. */
if( p_context->settings.b_use_frame_history )
@@ -173,6 +193,7 @@ picture_t *DoDeinterlacing( filter_t *p_filter,
p_context->meta[METADATA_SIZE-1].pi_date = p_pic->date;
p_context->meta[METADATA_SIZE-1].pi_nb_fields = p_pic->i_nb_fields;
p_context->meta[METADATA_SIZE-1].pb_top_field_first = p_pic->b_top_field_first;
+ }
/* Remember the frame offset that we should use for this frame.
The value in p_sys will be updated to reflect the correct value
@@ -206,6 +227,8 @@ picture_t *DoDeinterlacing( filter_t *p_filter,
i_nb_fields = p_pic->i_nb_fields; /* unused */
}
+ if ( p_context->current_field == 0 )
+ {
/* For framerate doublers, determine field duration and allocate
output frames. */
i_double_rate_alloc_end = 0; /* One past last for allocated output
@@ -229,57 +252,39 @@ picture_t *DoDeinterlacing( filter_t *p_filter,
i_nb_fields, DEINTERLACE_DST_SIZE );
i_double_rate_alloc_end = DEINTERLACE_DST_SIZE;
}
-
- /* Allocate output frames. */
- for( int i = 1; i < i_double_rate_alloc_end ; ++i )
- {
- p_dst[i] = AllocPicture( p_filter );
- if( p_dst[i] )
- {
- vlc_picture_chain_AppendChain( p_dst[i-1], p_dst[i] );
- picture_CopyProperties( p_dst[i], p_pic );
- }
- else
- {
- msg_Err( p_filter, "Framerate doubler: could not allocate "\
- "output frame %d", i+1 );
- i_double_rate_alloc_end = i; /* Inform the PTS logic about the
- correct end position. */
- break; /* If this happens, the rest of the allocations
- aren't likely to work, either... */
- }
- }
- /* Now we have allocated *up to* the correct number of frames;
- normally, exactly the correct number. Upon alloc failure,
- we may have succeeded in allocating *some* output frames,
- but fewer than were desired. In such a case, as many will
- be rendered as were successfully allocated.
-
- Note that now p_dst[i] != NULL
- for 0 <= i < i_double_rate_alloc_end. */
}
- assert( p_context->settings.b_double_rate || p_dst[1] == NULL );
- assert( i_nb_fields > 2 || p_dst[2] == NULL );
+ assert( p_context->settings.b_double_rate || i_double_rate_alloc_end == 0 );
+ assert( i_nb_fields > 2 || i_double_rate_alloc_end <= 2 );
+ p_context->max_fields = i_double_rate_alloc_end;
+ }
/* Render */
if ( !p_context->settings.b_double_rate )
{
- if ( p_context->pf_render_single_pic( p_filter, p_dst[0], p_pic ) )
+ if ( p_context->pf_render_single_pic( p_filter, p_dst, p_pic ) )
goto drop;
}
else
{
/* Note: RenderIVTC will automatically drop the duplicate frames
produced by IVTC. This is part of normal operation. */
- if ( p_context->pf_render_ordered( p_filter, p_dst[0], p_pic,
- 0, !b_top_field_first ) )
- goto drop;
- if ( p_dst[1] )
- p_context->pf_render_ordered( p_filter, p_dst[1], p_pic,
- 1, b_top_field_first );
- if ( p_dst[2] )
- p_context->pf_render_ordered( p_filter, p_dst[2], p_pic,
- 2, !b_top_field_first );
+ if ( p_context->current_field == 0 )
+ {
+ assert(p_context->prev_pic == NULL);
+ p_context->prev_pic = p_pic;
+ if ( p_context->pf_render_ordered( p_filter, p_dst, p_pic,
+ 0, !b_top_field_first ) )
+ goto drop;
+ }
+ else
+ {
+ if ( p_context->current_field == 1 )
+ p_context->pf_render_ordered( p_filter, p_dst, p_pic,
+ 1, b_top_field_first );
+ else
+ p_context->pf_render_ordered( p_filter, p_dst, p_pic,
+ 2, !b_top_field_first );
+ }
}
if ( p_context->settings.b_custom_pts )
@@ -313,43 +318,33 @@ picture_t *DoDeinterlacing( filter_t *p_filter,
b_double_rate = false), this effectively does nothing.
This is needed to correct the timestamp
when i_frame_offset > 0. */
- p_dst[0]->date = i_base_pts;
+ p_dst->date = i_base_pts;
- if( p_context->settings.b_double_rate )
+ if( p_context->current_field != 0 )
{
- vlc_tick_t i_field_dur = GetFieldDuration( p_context, &p_filter->fmt_out.video, p_pic );
- /* Processing all actually allocated output frames. */
- for( int i = 1; i < i_double_rate_alloc_end; ++i )
+ /* XXX it's not really good especially for the first picture, but
+ * I don't think that delaying by one frame is worth it */
+ if( i_base_pts != VLC_TICK_INVALID )
{
- /* XXX it's not really good especially for the first picture, but
- * I don't think that delaying by one frame is worth it */
- if( i_base_pts != VLC_TICK_INVALID )
- p_dst[i]->date = i_base_pts + i * i_field_dur;
- else
- p_dst[i]->date = VLC_TICK_INVALID;
+ vlc_tick_t i_field_dur = GetFieldDuration( p_context, &p_filter->fmt_out.video, p_pic );
+ p_dst->date += p_context->current_field * i_field_dur;
}
}
}
- for( int i = 0; i < DEINTERLACE_DST_SIZE; ++i )
+ if ( ++p_context->current_field >= p_context->max_fields )
{
- if( p_dst[i] )
- {
- p_dst[i]->b_progressive = true;
- p_dst[i]->i_nb_fields = 2;
- }
+ picture_Release( p_pic );
+ p_context->prev_pic = NULL;
+ p_context->current_field = 0;
+ p_context->max_fields = 0;
}
- picture_Release( p_pic );
- return p_dst[0];
+ return p_dst;
drop:
- picture_Release( p_dst[0] );
- for( int i = 1; i < DEINTERLACE_DST_SIZE; ++i )
- {
- if( p_dst[i] )
- picture_Release( p_dst[i] );
- }
+ picture_Release( p_dst );
+exit:
#ifndef NDEBUG
picture_Release( p_pic );
return NULL;
@@ -357,3 +352,8 @@ drop:
return p_pic;
#endif
}
+
+picture_t *DoDraining( filter_t *p_filter, struct deinterlace_ctx *p_context )
+{
+ return DoDeinterlacing( p_filter, p_context, NULL );
+}
diff --git a/modules/video_filter/deinterlace/common.h b/modules/video_filter/deinterlace/common.h
index 144523647c2..c4966530e36 100644
--- a/modules/video_filter/deinterlace/common.h
+++ b/modules/video_filter/deinterlace/common.h
@@ -88,6 +88,10 @@ struct deinterlace_ctx
int order, int i_field);
int (*pf_render_single_pic)(filter_t *, picture_t *p_dst, picture_t *p_pic);
};
+
+ int current_field;
+ int max_fields;
+ picture_t *prev_pic;
};
#define DEINTERLACE_DST_SIZE 3
@@ -116,6 +120,7 @@ void GetDeinterlacingOutput( const struct deinterlace_ctx *,
* @return The deinterlaced picture or NULL if it failed
*/
picture_t *DoDeinterlacing( filter_t *, struct deinterlace_ctx *, picture_t * );
+picture_t *DoDraining( filter_t *, struct deinterlace_ctx * );
/**
* @brief Flush the deinterlacer context
diff --git a/modules/video_filter/deinterlace/deinterlace.c b/modules/video_filter/deinterlace/deinterlace.c
index 62bd077c0a2..e0517ee0f46 100644
--- a/modules/video_filter/deinterlace/deinterlace.c
+++ b/modules/video_filter/deinterlace/deinterlace.c
@@ -444,6 +444,12 @@ picture_t *Deinterlace( filter_t *p_filter, picture_t *p_pic )
return DoDeinterlacing( p_filter, &p_sys->context, p_pic );
}
+static picture_t *Drain(filter_t *p_filter )
+{
+ filter_sys_t *p_sys = p_filter->p_sys;
+ return DoDraining( p_filter, &p_sys->context );
+}
+
/*****************************************************************************
* Flush
*****************************************************************************/
@@ -486,6 +492,7 @@ static void Close( filter_t *p_filter )
static const struct vlc_filter_operations filter_ops = {
.filter_video = Deinterlace,
+ .drain_video = Drain,
.flush = Flush,
.video_mouse = Mouse,
.close = Close,
--
2.26.2
More information about the vlc-devel
mailing list