struct _GstVaapiPictureH264 {
GstVaapiPicture base;
VAPictureH264 info;
+ GstH264PPS *pps;
gint32 poc;
gint32 frame_num; // Original frame_num from slice_header()
gint32 frame_num_wrap; // Temporary for ref pic marking: FrameNumWrap
struct _GstVaapiDecoderH264Private {
GstAdapter *adapter;
GstH264NalParser *parser;
- GstH264SPS *sps;
+ /* Last decoded SPS. May not be the last activated one. Just here because
+ it may not fit stack memory allocation in decode_sps() */
GstH264SPS last_sps;
- GstH264PPS *pps;
+ /* Last decoded PPS. May not be the last activated one. Just here because
+ it may not fit stack memory allocation in decode_pps() */
GstH264PPS last_pps;
GstVaapiPictureH264 *current_picture;
GstVaapiPictureH264 *dpb[16];
guint dpb_count;
guint dpb_size;
GstVaapiProfile profile;
+ GstVaapiEntrypoint entrypoint;
+ GstVaapiChromaType chroma_type;
GstVaapiPictureH264 *short_ref[32];
guint short_ref_count;
GstVaapiPictureH264 *long_ref[32];
guint nal_length_size;
guint width;
guint height;
- guint mb_x;
- guint mb_y;
- guint mb_width;
- guint mb_height;
gint32 field_poc[2]; // 0:TopFieldOrderCnt / 1:BottomFieldOrderCnt
gint32 poc_msb; // PicOrderCntMsb
gint32 poc_lsb; // pic_order_cnt_lsb (from slice_header())
return TRUE;
}
+static guint
+h264_get_profile(GstH264SPS *sps)
+{
+ guint profile = 0;
+
+ switch (sps->profile_idc) {
+ case 66:
+ profile = GST_VAAPI_PROFILE_H264_BASELINE;
+ break;
+ case 77:
+ profile = GST_VAAPI_PROFILE_H264_MAIN;
+ break;
+ case 100:
+ profile = GST_VAAPI_PROFILE_H264_HIGH;
+ break;
+ }
+ return profile;
+}
+
+static guint
+h264_get_chroma_type(GstH264SPS *sps)
+{
+ guint chroma_type = 0;
+
+ switch (sps->chroma_format_idc) {
+ case 1:
+ chroma_type = GST_VAAPI_CHROMA_TYPE_YUV420;
+ break;
+ case 2:
+ chroma_type = GST_VAAPI_CHROMA_TYPE_YUV422;
+ break;
+ case 3:
+ if (!sps->separate_colour_plane_flag)
+ chroma_type = GST_VAAPI_CHROMA_TYPE_YUV444;
+ break;
+ }
+ return chroma_type;
+}
+
+static GstVaapiProfile
+get_profile(GstVaapiDecoderH264 *decoder, GstH264SPS *sps)
+{
+ GstVaapiDecoderH264Private * const priv = decoder->priv;
+ GstVaapiDisplay * const display = GST_VAAPI_DECODER_DISPLAY(decoder);
+ GstVaapiProfile profile, profiles[2];
+ guint i, n_profiles = 0;
+
+ profile = h264_get_profile(sps);
+ if (!profile)
+ return GST_VAAPI_PROFILE_UNKNOWN;
+
+ profiles[n_profiles++] = profile;
+ switch (profile) {
+ case GST_VAAPI_PROFILE_H264_MAIN:
+ profiles[n_profiles++] = GST_VAAPI_PROFILE_H264_HIGH;
+ break;
+ default:
+ break;
+ }
+
+ /* If the preferred profile (profiles[0]) matches one that we already
+ found, then just return it now instead of searching for it again */
+ if (profiles[0] == priv->profile)
+ return priv->profile;
+
+ for (i = 0; i < n_profiles; i++) {
+ if (gst_vaapi_display_has_decoder(display, profiles[i], priv->entrypoint))
+ return profiles[i];
+ }
+ return GST_VAAPI_PROFILE_UNKNOWN;
+}
+
static GstVaapiDecoderStatus
ensure_context(GstVaapiDecoderH264 *decoder, GstH264SPS *sps)
{
+ GstVaapiDecoder * const base_decoder = GST_VAAPI_DECODER_CAST(decoder);
GstVaapiDecoderH264Private * const priv = decoder->priv;
- GstVaapiProfile profiles[2];
- GstVaapiEntrypoint entrypoint = GST_VAAPI_ENTRYPOINT_VLD;
- guint i, n_profiles = 0;
- gboolean success, reset_context = FALSE;
+ GstVaapiContextInfo info;
+ GstVaapiProfile profile;
+ GstVaapiChromaType chroma_type;
+ gboolean reset_context = FALSE;
- if (!priv->has_context || priv->sps->profile_idc != sps->profile_idc) {
+ profile = get_profile(decoder, sps);
+ if (!profile) {
+ GST_ERROR("unsupported profile_idc %u", sps->profile_idc);
+ return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
+ }
+
+ if (priv->profile != profile) {
GST_DEBUG("profile changed");
reset_context = TRUE;
+ priv->profile = profile;
+ }
- switch (sps->profile_idc) {
- case 66:
- profiles[n_profiles++] = GST_VAAPI_PROFILE_H264_BASELINE;
- break;
- case 77:
- profiles[n_profiles++] = GST_VAAPI_PROFILE_H264_MAIN;
- // fall-through
- case 100:
- profiles[n_profiles++] = GST_VAAPI_PROFILE_H264_HIGH;
- break;
- default:
- GST_DEBUG("unsupported profile %d", sps->profile_idc);
- return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
- }
-
- for (i = 0; i < n_profiles; i++) {
- success = gst_vaapi_display_has_decoder(
- GST_VAAPI_DECODER_DISPLAY(decoder),
- profiles[i],
- entrypoint
- );
- if (success)
- break;
- }
- if (i == n_profiles)
- return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
- priv->profile = profiles[i];
+ chroma_type = h264_get_chroma_type(sps);
+ if (!chroma_type || chroma_type != GST_VAAPI_CHROMA_TYPE_YUV420) {
+ GST_ERROR("unsupported chroma_format_idc %u", sps->chroma_format_idc);
+ return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CHROMA_FORMAT;
}
- if (!priv->has_context ||
- priv->sps->chroma_format_idc != sps->chroma_format_idc) {
+ if (priv->chroma_type != chroma_type) {
GST_DEBUG("chroma format changed");
- reset_context = TRUE;
-
- /* XXX: theoritically, we could handle 4:2:2 format */
- if (sps->chroma_format_idc != 1)
- return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CHROMA_FORMAT;
+ reset_context = TRUE;
+ priv->chroma_type = chroma_type;
}
- if (!priv->has_context ||
- priv->sps->width != sps->width ||
- priv->sps->height != sps->height) {
+ if (priv->width != sps->width || priv->height != sps->height) {
GST_DEBUG("size changed");
- reset_context = TRUE;
-
- priv->width = sps->width;
- priv->height = sps->height;
- priv->mb_width = sps->pic_width_in_mbs_minus1 + 1;
- priv->mb_height = sps->pic_height_in_map_units_minus1 + 1;
- priv->mb_height *= 2 - sps->frame_mbs_only_flag;
+ reset_context = TRUE;
+ priv->width = sps->width;
+ priv->height = sps->height;
}
- if (reset_context) {
- GstVaapiContextInfo info;
+ gst_vaapi_decoder_set_pixel_aspect_ratio(
+ base_decoder,
+ sps->vui_parameters.par_n,
+ sps->vui_parameters.par_d
+ );
- info.profile = priv->profile;
- info.entrypoint = entrypoint;
- info.width = priv->width;
- info.height = priv->height;
- info.ref_frames = get_max_dec_frame_buffering(sps);
+ if (!reset_context && priv->has_context)
+ return GST_VAAPI_DECODER_STATUS_SUCCESS;
- if (!gst_vaapi_decoder_ensure_context(GST_VAAPI_DECODER(decoder), &info))
- return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
- priv->has_context = TRUE;
+ info.profile = priv->profile;
+ info.entrypoint = priv->entrypoint;
+ info.width = priv->width;
+ info.height = priv->height;
+ info.ref_frames = get_max_dec_frame_buffering(sps);
- /* Reset DPB */
- dpb_reset(decoder, sps);
- }
+ 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);
return GST_VAAPI_DECODER_STATUS_SUCCESS;
}
static GstVaapiDecoderStatus
ensure_quant_matrix(GstVaapiDecoderH264 *decoder, GstVaapiPictureH264 *picture)
{
- GstVaapiDecoderH264Private * const priv = decoder->priv;
- GstH264SPS * const sps = priv->sps;
- GstH264PPS * const pps = priv->pps;
GstVaapiPicture * const base_picture = &picture->base;
+ GstH264PPS * const pps = picture->pps;
+ GstH264SPS * const sps = pps->sequence;
VAIQMatrixBufferH264 *iq_matrix;
base_picture->iq_matrix = GST_VAAPI_IQ_MATRIX_NEW(H264, decoder);
return GST_VAAPI_DECODER_STATUS_SUCCESS;
}
-static gboolean
+static GstVaapiDecoderStatus
decode_current_picture(GstVaapiDecoderH264 *decoder)
{
GstVaapiDecoderH264Private * const priv = decoder->priv;
GstVaapiPictureH264 * const picture = priv->current_picture;
- gboolean success = FALSE;
+ GstVaapiDecoderStatus status;
if (!picture)
- return TRUE;
+ return GST_VAAPI_DECODER_STATUS_SUCCESS;
+
+ status = ensure_context(decoder, picture->pps->sequence);
+ if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+ return status;
if (!decode_picture_end(decoder, picture))
- goto end;
+ goto error;
if (!gst_vaapi_picture_decode(GST_VAAPI_PICTURE_CAST(picture)))
- goto end;
- success = TRUE;
-end:
+ goto error;
gst_vaapi_picture_replace(&priv->current_picture, NULL);
- return success;
+ return GST_VAAPI_DECODER_STATUS_SUCCESS;
+
+error:
+ gst_vaapi_picture_replace(&priv->current_picture, NULL);
+ return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
}
static GstVaapiDecoderStatus
decode_sps(GstVaapiDecoderH264 *decoder, GstH264NalUnit *nalu)
{
- GstVaapiDecoder * const base_decoder = GST_VAAPI_DECODER(decoder);
GstVaapiDecoderH264Private * const priv = decoder->priv;
GstH264SPS * const sps = &priv->last_sps;
GstH264ParserResult result;
GST_DEBUG("decode SPS");
- if (priv->current_picture && !decode_current_picture(decoder))
- return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
-
memset(sps, 0, sizeof(*sps));
result = gst_h264_parser_parse_sps(priv->parser, nalu, sps, TRUE);
if (result != GST_H264_PARSER_OK)
return get_status(result);
- gst_vaapi_decoder_set_pixel_aspect_ratio(
- base_decoder,
- sps->vui_parameters.par_n,
- sps->vui_parameters.par_d
- );
- return ensure_context(decoder, sps);
+ return GST_VAAPI_DECODER_STATUS_SUCCESS;
}
static GstVaapiDecoderStatus
GST_DEBUG("decode PPS");
- if (priv->current_picture && !decode_current_picture(decoder))
- return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
-
memset(pps, 0, sizeof(*pps));
result = gst_h264_parser_parse_pps(priv->parser, nalu, pps);
if (result != GST_H264_PARSER_OK)
static GstVaapiDecoderStatus
decode_sequence_end(GstVaapiDecoderH264 *decoder)
{
- GstVaapiDecoderH264Private * const priv = decoder->priv;
+ GstVaapiDecoderStatus status;
GST_DEBUG("decode sequence-end");
- if (priv->current_picture && !decode_current_picture(decoder))
- return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+ status = decode_current_picture(decoder);
+ if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+ return status;
+
dpb_flush(decoder);
return GST_VAAPI_DECODER_STATUS_END_OF_STREAM;
}
exec_ref_pic_marking_sliding_window(GstVaapiDecoderH264 *decoder)
{
GstVaapiDecoderH264Private * const priv = decoder->priv;
- GstH264SPS * const sps = priv->sps;
+ GstH264PPS * const pps = priv->current_picture->pps;
+ GstH264SPS * const sps = pps->sequence;
guint i, max_num_ref_frames, lowest_frame_num_index;
gint32 lowest_frame_num;
{
GstVaapiDecoderH264Private * const priv = decoder->priv;
GstVaapiPicture * const base_picture = &picture->base;
- GstH264SPS * const sps = priv->sps;
- GstH264PPS * const pps = priv->pps;
+ GstH264PPS * const pps = picture->pps;
+ GstH264SPS * const sps = pps->sequence;
VAPictureParameterBufferH264 * const pic_param = base_picture->param;
guint i, n;
#define COPY_BFM(a, s, f) \
pic_param->a.bits.f = (s)->f
- pic_param->picture_width_in_mbs_minus1 = priv->mb_width - 1;
- pic_param->picture_height_in_mbs_minus1 = priv->mb_height - 1;
- pic_param->frame_num = priv->frame_num;
+ pic_param->picture_width_in_mbs_minus1 = ((priv->width + 15) >> 4) - 1;
+ pic_param->picture_height_in_mbs_minus1 = ((priv->height + 15) >> 4) - 1;
+ pic_param->frame_num = priv->frame_num;
COPY_FIELD(sps, bit_depth_luma_minus8);
COPY_FIELD(sps, bit_depth_chroma_minus8);
GstH264PPS * const pps = slice_hdr->pps;
GstH264SPS * const sps = pps->sequence;
- status = ensure_context(decoder, sps);
- if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) {
- GST_ERROR("failed to reset context");
+ status = decode_current_picture(decoder);
+ if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
return status;
- }
- if (priv->current_picture && !decode_current_picture(decoder))
- return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+ status = ensure_context(decoder, sps);
+ if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+ return status;
picture = gst_vaapi_picture_h264_new(decoder);
if (!picture) {
}
priv->current_picture = picture;
- priv->sps = sps;
- priv->pps = pps;
+ picture->pps = pps;
status = ensure_quant_matrix(decoder, picture);
if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) {
}
picture = priv->current_picture;
- priv->mb_x = slice_hdr->first_mb_in_slice % priv->mb_width;
- priv->mb_y = slice_hdr->first_mb_in_slice / priv->mb_width; // FIXME: MBAFF or field
-
if (!fill_slice(decoder, slice, nalu)) {
status = GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
goto error;
GST_VAAPI_PICTURE_CAST(picture),
GST_VAAPI_SLICE_CAST(slice)
);
-
- /* Commit picture for decoding if we reached the last slice */
- if (++priv->mb_y >= priv->mb_height) {
- if (!decode_current_picture(decoder)) {
- status = GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
- goto error;
- }
- GST_DEBUG("done");
- }
return GST_VAAPI_DECODER_STATUS_SUCCESS;
error:
priv = GST_VAAPI_DECODER_H264_GET_PRIVATE(decoder);
decoder->priv = priv;
priv->parser = NULL;
- priv->sps = &priv->last_sps;
- priv->pps = &priv->last_pps;
priv->current_picture = NULL;
priv->dpb_count = 0;
priv->dpb_size = 0;
- priv->profile = GST_VAAPI_PROFILE_H264_HIGH;
+ priv->profile = GST_VAAPI_PROFILE_UNKNOWN;
+ priv->entrypoint = GST_VAAPI_ENTRYPOINT_VLD;
+ priv->chroma_type = GST_VAAPI_CHROMA_TYPE_YUV420;
priv->short_ref_count = 0;
priv->long_ref_count = 0;
priv->RefPicList0_count = 0;
priv->nal_length_size = 0;
priv->width = 0;
priv->height = 0;
- priv->mb_x = 0;
- priv->mb_y = 0;
- priv->mb_width = 0;
- priv->mb_height = 0;
priv->adapter = NULL;
priv->field_poc[0] = 0;
priv->field_poc[1] = 0;