decoder: h264: dynamically allocate the DPB.

Dynamically allocate the Decoded Picture Buffer (DPB) and add provisions
for supporting the MVC allocation requirements.
This commit is contained in:
Gwenole Beauchesne 2014-05-01 19:16:09 +02:00
parent ae1d8267d9
commit 42b112f8bd

View file

@ -424,9 +424,11 @@ struct _GstVaapiDecoderH264Private {
GstVaapiParserInfoH264 *prev_pi;
GstVaapiParserInfoH264 *prev_slice_pi;
GstVaapiFrameStore *prev_frame;
GstVaapiFrameStore *dpb[16];
GstVaapiFrameStore **dpb;
guint dpb_count;
guint dpb_size;
guint dpb_size_max;
guint max_views;
GstVaapiProfile profile;
GstVaapiEntrypoint entrypoint;
GstVaapiChromaType chroma_type;
@ -481,6 +483,14 @@ struct _GstVaapiDecoderH264Class {
static gboolean
exec_ref_pic_marking(GstVaapiDecoderH264 *decoder, GstVaapiPictureH264 *picture);
/* Determines if the supplied profile is one of the MVC set */
static gboolean
is_mvc_profile(GstH264Profile profile)
{
return profile == GST_H264_PROFILE_MULTIVIEW_HIGH ||
profile == GST_H264_PROFILE_STEREO_HIGH;
}
/* Determines the view order index (VOIdx) from the supplied view_id */
static gint
get_view_order_index(GstH264SPS *sps, guint16 view_id)
@ -500,10 +510,19 @@ get_view_order_index(GstH264SPS *sps, guint16 view_id)
return -1;
}
/* Determines NumViews */
static guint
get_num_views(GstH264SPS *sps)
{
return 1 + (sps->extension_type == GST_H264_NAL_EXTENSION_MVC ?
sps->extension.mvc.num_views_minus1 : 0);
}
/* Get number of reference frames to use */
static guint
get_max_dec_frame_buffering(GstH264SPS *sps)
{
guint num_views, max_dpb_frames;
guint max_dec_frame_buffering, PicSizeMbs;
GstVaapiLevelH264 level;
const GstVaapiH264LevelLimits *level_limits;
@ -514,13 +533,18 @@ get_max_dec_frame_buffering(GstH264SPS *sps)
else
level = gst_vaapi_utils_h264_get_level(sps->level_idc);
level_limits = gst_vaapi_utils_h264_get_level_limits(level);
if (!level_limits)
return 16;
PicSizeMbs = ((sps->pic_width_in_mbs_minus1 + 1) *
(sps->pic_height_in_map_units_minus1 + 1) *
(sps->frame_mbs_only_flag ? 1 : 2));
max_dec_frame_buffering = level_limits->MaxDpbMbs / PicSizeMbs;
if (G_UNLIKELY(!level_limits)) {
GST_FIXME("unsupported level_idc value (%d)", sps->level_idc);
max_dec_frame_buffering = 16;
}
else {
PicSizeMbs = ((sps->pic_width_in_mbs_minus1 + 1) *
(sps->pic_height_in_map_units_minus1 + 1) *
(sps->frame_mbs_only_flag ? 1 : 2));
max_dec_frame_buffering = level_limits->MaxDpbMbs / PicSizeMbs;
}
if (is_mvc_profile(sps->profile_idc))
max_dec_frame_buffering <<= 1;
/* VUI parameters */
if (sps->vui_parameters_present_flag) {
@ -542,8 +566,10 @@ get_max_dec_frame_buffering(GstH264SPS *sps)
}
}
if (max_dec_frame_buffering > 16)
max_dec_frame_buffering = 16;
num_views = get_num_views(sps);
max_dpb_frames = 16 * (num_views > 1 ? g_bit_storage(num_views - 1) : 1);
if (max_dec_frame_buffering > max_dpb_frames)
max_dec_frame_buffering = max_dpb_frames;
else if (max_dec_frame_buffering < sps->num_ref_frames)
max_dec_frame_buffering = sps->num_ref_frames;
return MAX(1, max_dec_frame_buffering);
@ -760,13 +786,30 @@ dpb_add(GstVaapiDecoderH264 *decoder, GstVaapiPictureH264 *picture)
return TRUE;
}
static inline void
dpb_reset(GstVaapiDecoderH264 *decoder, GstH264SPS *sps)
static gboolean
dpb_reset(GstVaapiDecoderH264 *decoder, guint dpb_size)
{
GstVaapiDecoderH264Private * const priv = &decoder->priv;
priv->dpb_size = get_max_dec_frame_buffering(sps);
if (dpb_size < priv->dpb_count)
return FALSE;
if (dpb_size > priv->dpb_size_max) {
priv->dpb = g_try_realloc_n(priv->dpb, dpb_size, sizeof(*priv->dpb));
if (!priv->dpb)
return FALSE;
memset(&priv->dpb[priv->dpb_size_max], 0,
(dpb_size - priv->dpb_size_max) * sizeof(*priv->dpb));
priv->dpb_size_max = dpb_size;
}
if (priv->dpb_size < dpb_size)
priv->dpb_size = dpb_size;
else if (dpb_size < priv->dpb_count)
return FALSE;
GST_DEBUG("DPB size %u", priv->dpb_size);
return TRUE;
}
static GstVaapiDecoderStatus
@ -831,6 +874,10 @@ gst_vaapi_decoder_h264_destroy(GstVaapiDecoder *base_decoder)
gst_vaapi_decoder_h264_close(decoder);
g_free(priv->dpb);
priv->dpb = NULL;
priv->dpb_size = 0;
for (i = 0; i < G_N_ELEMENTS(priv->pps); i++)
gst_vaapi_parser_info_h264_replace(&priv->pps[i], NULL);
gst_vaapi_parser_info_h264_replace(&priv->active_pps, NULL);
@ -965,7 +1012,13 @@ ensure_context(GstVaapiDecoderH264 *decoder, GstH264SPS *sps)
GstVaapiProfile profile;
GstVaapiChromaType chroma_type;
gboolean reset_context = FALSE;
guint mb_width, mb_height;
guint mb_width, mb_height, dpb_size;
dpb_size = get_max_dec_frame_buffering(sps);
if (priv->dpb_size < dpb_size) {
GST_DEBUG("DPB size increased");
reset_context = TRUE;
}
profile = get_profile(decoder, sps);
if (!profile) {
@ -1022,14 +1075,15 @@ ensure_context(GstVaapiDecoderH264 *decoder, GstH264SPS *sps)
info.chroma_type = priv->chroma_type;
info.width = sps->width;
info.height = sps->height;
info.ref_frames = get_max_dec_frame_buffering(sps);
info.ref_frames = dpb_size;
if (!gst_vaapi_decoder_ensure_context(GST_VAAPI_DECODER(decoder), &info))
return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
priv->has_context = TRUE;
/* Reset DPB */
dpb_reset(decoder, sps);
if (!dpb_reset(decoder, dpb_size))
return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
return GST_VAAPI_DECODER_STATUS_SUCCESS;
}
@ -1153,6 +1207,9 @@ parse_sps(GstVaapiDecoderH264 *decoder, GstVaapiDecoderUnit *unit)
if (result != GST_H264_PARSER_OK)
return get_status(result);
/* Reset defaults */
priv->max_views = 1;
priv->parser_state |= GST_H264_VIDEO_STATE_GOT_SPS;
return GST_VAAPI_DECODER_STATUS_SUCCESS;
}
@ -1231,6 +1288,7 @@ parse_slice(GstVaapiDecoderH264 *decoder, GstVaapiDecoderUnit *unit)
GstH264SliceHdr * const slice_hdr = &pi->data.slice_hdr;
GstH264NalUnit * const nalu = &pi->nalu;
GstH264ParserResult result;
guint num_views;
GST_DEBUG("parse slice");
@ -1275,6 +1333,12 @@ parse_slice(GstVaapiDecoderH264 *decoder, GstVaapiDecoderUnit *unit)
if (result != GST_H264_PARSER_OK)
return get_status(result);
num_views = get_num_views(slice_hdr->pps->sequence);
if (priv->max_views < num_views) {
priv->max_views = num_views;
GST_DEBUG("maximum number of views changed to %u", num_views);
}
priv->parser_state |= GST_H264_VIDEO_STATE_GOT_SLICE;
return GST_VAAPI_DECODER_STATUS_SUCCESS;
}