[vlc-commits] [Git][videolan/vlc][master] 2 commits: vpx_alpha: don't lock while the decoders are flushing
Steve Lhomme (@robUx4)
gitlab at videolan.org
Sat Jun 1 08:58:17 UTC 2024
Steve Lhomme pushed to branch master at VideoLAN / VLC
Commits:
a6d32f4f by Steve Lhomme at 2024-06-01T08:45:45+00:00
vpx_alpha: don't lock while the decoders are flushing
They may call FormatUpdate (lavc) and other things that lock.
We don't need a lock on the decoder as it cannot change during the
lifetime of our pseudo-decoder.
- - - - -
b09808a6 by Steve Lhomme at 2024-06-01T08:45:45+00:00
vpx_alpha: handle bitstreams with intermittent alpha content
It seems some sources set the alpha flag but don't always attach an alpha layer to each frame.
Ref #28653
- - - - -
1 changed file:
- modules/codec/vpx_alpha.c
Changes:
=====================================
modules/codec/vpx_alpha.c
=====================================
@@ -45,6 +45,8 @@ typedef struct
vlc_video_context *vctx;
picture_t *(*pf_combine)(decoder_t *, picture_t *opaque, picture_t *alpha, vlc_video_context *);
+ struct VLC_VECTOR(vlc_tick_t) missing_alpha;
+
picture_pool_t *pool;
} vpx_alpha;
@@ -63,14 +65,15 @@ struct cpu_alpha_context
{
picture_context_t ctx;
picture_t *opaque;
- picture_t *alpha;
+ picture_t *alpha; // may be NULL if the alpha layer was missing
};
static void cpu_alpha_destroy(picture_context_t *ctx)
{
struct cpu_alpha_context *pctx = container_of(ctx, struct cpu_alpha_context, ctx);
picture_Release(pctx->opaque);
- picture_Release(pctx->alpha);
+ if (pctx->alpha)
+ picture_Release(pctx->alpha);
free(pctx);
}
@@ -82,10 +85,21 @@ static picture_context_t *cpu_alpha_copy(picture_context_t *src)
return NULL;
alpha_ctx->ctx = *src;
alpha_ctx->opaque = picture_Hold(pctx->opaque);
- alpha_ctx->alpha = picture_Hold(pctx->alpha);
+ alpha_ctx->alpha = alpha_ctx->alpha ? picture_Hold(pctx->alpha) : NULL;
return &alpha_ctx->ctx;
}
+struct pic_alpha_plane
+{
+ plane_t p;
+ uint8_t buffer[];
+};
+
+static void DestroyPoolPic(picture_t *pic)
+{
+ free(pic->p_sys);
+}
+
static picture_t *CombinePicturesCPU(decoder_t *bdec, picture_t *opaque, picture_t *alpha, vlc_video_context *vctx)
{
assert(vctx == NULL); VLC_UNUSED(vctx);
@@ -104,12 +118,42 @@ static picture_t *CombinePicturesCPU(decoder_t *bdec, picture_t *opaque, picture
cpu_alpha_destroy, cpu_alpha_copy, NULL
};
alpha_ctx->opaque = picture_Hold(opaque);
- alpha_ctx->alpha = picture_Hold(alpha);
+ alpha_ctx->alpha = alpha ? picture_Hold(alpha) : NULL;
out->context = &alpha_ctx->ctx;
for (int i=0; i<opaque->i_planes; i++)
out->p[i] = opaque->p[i];
- out->p[opaque->i_planes] = alpha->p[0];
+ if (alpha)
+ out->p[opaque->i_planes] = alpha->p[0];
+ else
+ {
+ // use the dummy opaque plane attached in the picture p_sys
+ struct pic_alpha_plane *p = out->p_sys;
+ if (out->p_sys == NULL)
+ {
+ int plane_size = bdec->fmt_out.video.i_width * bdec->fmt_out.video.i_height;
+ p = malloc(sizeof(*p) + plane_size);
+ if (likely(p != NULL))
+ {
+ p->p.i_lines = bdec->fmt_out.video.i_height;
+ p->p.i_visible_lines = bdec->fmt_out.video.i_y_offset + bdec->fmt_out.video.i_visible_height;
+
+ p->p.i_pitch = bdec->fmt_out.video.i_width;
+ p->p.i_visible_pitch = bdec->fmt_out.video.i_x_offset + bdec->fmt_out.video.i_visible_width;
+ p->p.i_pixel_pitch = 1;
+ p->p.p_pixels = p->buffer;
+ memset(p->p.p_pixels, 0xFF, plane_size);
+
+ out->p_sys = p;
+ }
+ }
+ if (unlikely(p == NULL))
+ {
+ picture_Release(out);
+ return NULL;
+ }
+ out->p[opaque->i_planes] = p->p;
+ }
return out;
}
@@ -127,7 +171,8 @@ static int SetupCPU(decoder_t *bdec)
for (; i<ARRAY_SIZE(pics); i++)
{
- pics[i] = picture_NewFromResource(&bdec->fmt_out.video, &(picture_resource_t){0});
+ picture_resource_t res = { .pf_destroy = DestroyPoolPic };
+ pics[i] = picture_NewFromResource(&bdec->fmt_out.video, &res);
if (pics[i] == NULL)
goto error;
}
@@ -187,7 +232,9 @@ static int FormatUpdate( decoder_t *dec, vlc_video_context *vctx )
// not ready
bdec->fmt_out.video.i_chroma = bdec->fmt_out.i_codec = dec->fmt_out.video.i_chroma;
p_sys->pf_combine = CombineKeepOpaque;
- goto done;
+ if (p_sys->missing_alpha.size == 0)
+ goto done;
+ // we need to send pictures without waiting for the alpha
}
}
es_format_Clean(&bdec->fmt_out);
@@ -255,15 +302,44 @@ done:
return res;
}
+static bool CheckMissingAlpha(decoder_t *bdec, vlc_tick_t pts)
+{
+ vpx_alpha *p_sys = bdec->p_sys;
+ vlc_tick_t missing_pts;
+ vlc_vector_foreach(missing_pts, &p_sys->missing_alpha)
+ {
+ if (missing_pts == pts)
+ return true;
+ if (missing_pts < pts)
+ break;
+ }
+ return false;
+}
+
+static void PurgeMissingAlpha(decoder_t *bdec, vlc_tick_t pts)
+{
+ vpx_alpha *p_sys = bdec->p_sys;
+ size_t count = 0;
+ vlc_tick_t missing_pts;
+ vlc_vector_foreach(missing_pts, &p_sys->missing_alpha)
+ {
+ if (missing_pts > pts)
+ break; // in VPx there are not frames out of order
+ count++;
+ }
+ if (count > 0)
+ vlc_vector_remove_slice(&p_sys->missing_alpha, 0, count);
+}
+
static bool SendMergedLocked(decoder_t *bdec)
{
vpx_alpha *p_sys = bdec->p_sys;
picture_t *opaque = vlc_picture_chain_PeekFront(&p_sys->opaque->decoded);
picture_t *alpha = vlc_picture_chain_PeekFront(&p_sys->alpha->decoded);
- while (opaque != NULL && alpha != NULL)
+ while (opaque != NULL && (alpha != NULL || CheckMissingAlpha(bdec, opaque->date)))
{
- if (opaque->date == alpha->date)
+ if (alpha == NULL || opaque->date == alpha->date)
{
// dequeue if both first of the queue match DTS/PTS
// merge alpha and opaque pictures with same DTS/PTS and send them
@@ -277,11 +353,15 @@ static bool SendMergedLocked(decoder_t *bdec)
vlc_picture_chain_PopFront(&p_sys->opaque->decoded);
picture_Release(opaque);
- vlc_picture_chain_PopFront(&p_sys->alpha->decoded);
- picture_Release(alpha);
+ if (alpha != NULL)
+ {
+ vlc_picture_chain_PopFront(&p_sys->alpha->decoded);
+ picture_Release(alpha);
+ }
+ PurgeMissingAlpha(bdec, opaque->date);
if (out == NULL)
- return false;
+ break;
decoder_QueueVideo(bdec, out);
return true;
@@ -384,17 +464,12 @@ static int Decode( decoder_t *dec, vlc_frame_t *frame )
{
struct vlc_ancillary *p_alpha;
p_alpha = vlc_frame_GetAncillary(frame, VLC_ANCILLARY_ID_VPX_ALPHA);
- if (p_alpha == NULL)
- {
- msg_Err(dec, "missing alpha data");
- return VLCDEC_ECRITICAL;
- }
struct alpha_frame *alpha_frame = malloc(sizeof(*alpha_frame));
if (unlikely(alpha_frame == NULL))
return VLCDEC_ECRITICAL;
- vlc_vpx_alpha_t *alpha = vlc_ancillary_GetData(p_alpha);
+ vlc_vpx_alpha_t *alpha = p_alpha ? vlc_ancillary_GetData(p_alpha) : NULL;
static const struct vlc_frame_callbacks cbs_alpha = {
ReleaseAlphaFrame,
@@ -407,12 +482,16 @@ static int Decode( decoder_t *dec, vlc_frame_t *frame )
alpha_frame->frame = frame;
vlc_atomic_rc_init(&alpha_frame->rc);
- vlc_frame_Init(&alpha_frame->alpha, &cbs_alpha, alpha->data, alpha->size);
- vlc_atomic_rc_inc(&alpha_frame->rc);
- alpha_frame->alpha.i_dts = frame->i_dts;
- alpha_frame->alpha.i_pts = frame->i_pts;
- alpha_frame->alpha.i_length = frame->i_length;
- alpha_frame->alpha.i_flags = frame->i_flags;
+ bool b_has_alpha = alpha != NULL;
+ if (b_has_alpha)
+ {
+ vlc_frame_Init(&alpha_frame->alpha, &cbs_alpha, alpha->data, alpha->size);
+ vlc_atomic_rc_inc(&alpha_frame->rc);
+ alpha_frame->alpha.i_dts = frame->i_dts;
+ alpha_frame->alpha.i_pts = frame->i_pts;
+ alpha_frame->alpha.i_length = frame->i_length;
+ alpha_frame->alpha.i_flags = frame->i_flags;
+ }
vlc_frame_Init(&alpha_frame->opaque, &cbs_opaque, frame->p_buffer, frame->i_buffer);
alpha_frame->opaque.i_dts = frame->i_dts;
@@ -420,17 +499,25 @@ static int Decode( decoder_t *dec, vlc_frame_t *frame )
alpha_frame->opaque.i_length = frame->i_length;
alpha_frame->opaque.i_flags = frame->i_flags;
- res = p_sys->opaque->dec.pf_decode(&p_sys->opaque->dec, &alpha_frame->opaque);
- if (res != VLCDEC_SUCCESS)
+ if (b_has_alpha)
{
- ReleaseOpaqueFrame(&alpha_frame->opaque);
- return VLCDEC_ECRITICAL;
+ res = p_sys->alpha->dec.pf_decode(&p_sys->alpha->dec, &alpha_frame->alpha);
+ if (res != VLCDEC_SUCCESS)
+ {
+ ReleaseAlphaFrame(&alpha_frame->alpha);
+ return VLCDEC_ECRITICAL;
+ }
+ }
+ else
+ {
+ assert(frame->i_pts != VLC_TICK_INVALID);
+ vlc_vector_push(&p_sys->missing_alpha, frame->i_pts);
}
- res = p_sys->alpha->dec.pf_decode(&p_sys->alpha->dec, &alpha_frame->alpha);
+ res = p_sys->opaque->dec.pf_decode(&p_sys->opaque->dec, &alpha_frame->opaque);
if (res != VLCDEC_SUCCESS)
{
- ReleaseAlphaFrame(&alpha_frame->alpha);
+ ReleaseOpaqueFrame(&alpha_frame->opaque);
return VLCDEC_ECRITICAL;
}
}
@@ -457,7 +544,6 @@ static int Decode( decoder_t *dec, vlc_frame_t *frame )
static void Flush( decoder_t *dec )
{
vpx_alpha *p_sys = dec->p_sys;
- vlc_mutex_lock(&p_sys->lock);
if ( p_sys->opaque->dec.pf_flush != NULL )
p_sys->opaque->dec.pf_flush( &p_sys->opaque->dec );
@@ -465,6 +551,7 @@ static void Flush( decoder_t *dec )
if ( p_sys->alpha->dec.pf_flush != NULL )
p_sys->alpha->dec.pf_flush( &p_sys->alpha->dec );
+ vlc_mutex_lock(&p_sys->lock);
picture_t *picture;
while ((picture = vlc_picture_chain_PopFront(&p_sys->opaque->decoded)) != NULL)
picture_Release(picture);
@@ -515,6 +602,7 @@ int OpenDecoder(vlc_object_t *o)
es_format_Init(&p_sys->alpha->fmt_out, VIDEO_ES, 0);
vlc_mutex_init(&p_sys->lock);
+ vlc_vector_init(&p_sys->missing_alpha);
dec->p_sys = p_sys;
static const struct decoder_owner_callbacks dec_cbs =
@@ -569,4 +657,5 @@ void CloseDecoder(vlc_object_t *o)
if (p_sys->vctx)
vlc_video_context_Release(p_sys->vctx);
+ vlc_vector_destroy(&p_sys->missing_alpha);
}
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/78a7672419049bc75c91993a85ef0466805fb2ef...b09808a6cff06f0c1981f264f8ef4f197a8beccc
--
This project does not include diff previews in email notifications.
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/78a7672419049bc75c91993a85ef0466805fb2ef...b09808a6cff06f0c1981f264f8ef4f197a8beccc
You're receiving this email because of your account on code.videolan.org.
VideoLAN code repository instance
More information about the vlc-commits
mailing list