mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 20:21:24 +00:00
h264: initial port to new GstVaapiDecoder API
This commit is contained in:
parent
8fbd05ca82
commit
7e6660fcae
1 changed files with 160 additions and 102 deletions
|
@ -412,7 +412,6 @@ G_DEFINE_TYPE(GstVaapiDecoderH264,
|
|||
GstVaapiDecoderH264Private))
|
||||
|
||||
struct _GstVaapiDecoderH264Private {
|
||||
GstAdapter *adapter;
|
||||
GstH264NalParser *parser;
|
||||
/* Last decoded SPS. May not be the last activated one. Just here because
|
||||
it may not fit stack memory allocation in decode_sps() */
|
||||
|
@ -779,25 +778,15 @@ gst_vaapi_decoder_h264_close(GstVaapiDecoderH264 *decoder)
|
|||
gst_h264_nal_parser_free(priv->parser);
|
||||
priv->parser = NULL;
|
||||
}
|
||||
|
||||
if (priv->adapter) {
|
||||
gst_adapter_clear(priv->adapter);
|
||||
g_object_unref(priv->adapter);
|
||||
priv->adapter = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_vaapi_decoder_h264_open(GstVaapiDecoderH264 *decoder, GstBuffer *buffer)
|
||||
gst_vaapi_decoder_h264_open(GstVaapiDecoderH264 *decoder)
|
||||
{
|
||||
GstVaapiDecoderH264Private * const priv = decoder->priv;
|
||||
|
||||
gst_vaapi_decoder_h264_close(decoder);
|
||||
|
||||
priv->adapter = gst_adapter_new();
|
||||
if (!priv->adapter)
|
||||
return FALSE;
|
||||
|
||||
priv->parser = gst_h264_nal_parser_new();
|
||||
if (!priv->parser)
|
||||
return FALSE;
|
||||
|
@ -2031,7 +2020,7 @@ init_picture(
|
|||
picture->frame_num = priv->frame_num;
|
||||
picture->frame_num_wrap = priv->frame_num;
|
||||
picture->output_flag = TRUE; /* XXX: conformant to Annex A only */
|
||||
base_picture->pts = gst_adapter_prev_timestamp(priv->adapter, NULL);
|
||||
base_picture->pts = GST_VAAPI_DECODER_CODEC_FRAME(decoder)->pts;
|
||||
|
||||
/* Reset decoder state for IDR pictures */
|
||||
if (nalu->type == GST_H264_NAL_SLICE_IDR) {
|
||||
|
@ -2894,93 +2883,23 @@ decode_buffer(GstVaapiDecoderH264 *decoder, GstBuffer *buffer)
|
|||
GstVaapiDecoderStatus status;
|
||||
GstH264ParserResult result;
|
||||
GstH264NalUnit nalu;
|
||||
gboolean is_eos;
|
||||
const guchar *buf;
|
||||
guint i, buf_size, nalu_size, size;
|
||||
guint32 start_code;
|
||||
gint ofs;
|
||||
|
||||
buf = GST_BUFFER_DATA(buffer);
|
||||
buf_size = GST_BUFFER_SIZE(buffer);
|
||||
is_eos = GST_BUFFER_IS_EOS(buffer);
|
||||
if (buf && buf_size > 0)
|
||||
gst_adapter_push(priv->adapter, gst_buffer_ref(buffer));
|
||||
|
||||
size = gst_adapter_available(priv->adapter);
|
||||
do {
|
||||
if (size == 0) {
|
||||
status = GST_VAAPI_DECODER_STATUS_SUCCESS;
|
||||
break;
|
||||
}
|
||||
|
||||
status = gst_vaapi_decoder_check_status(GST_VAAPI_DECODER(decoder));
|
||||
if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
|
||||
break;
|
||||
|
||||
status = GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
|
||||
if (priv->is_avc) {
|
||||
if (size < priv->nal_length_size)
|
||||
break;
|
||||
buf = gst_adapter_peek(priv->adapter, priv->nal_length_size);
|
||||
|
||||
nalu_size = 0;
|
||||
for (i = 0; i < priv->nal_length_size; i++)
|
||||
nalu_size = (nalu_size << 8) | buf[i];
|
||||
|
||||
buf_size = priv->nal_length_size + nalu_size;
|
||||
if (size < buf_size)
|
||||
break;
|
||||
buffer = gst_adapter_take_buffer(priv->adapter, buf_size);
|
||||
size -= buf_size;
|
||||
guchar *buf;
|
||||
guint buf_size;
|
||||
|
||||
buf = GST_BUFFER_DATA(buffer);
|
||||
buf_size = GST_BUFFER_SIZE(buffer);
|
||||
|
||||
result = gst_h264_parser_identify_nalu_avc(
|
||||
priv->parser,
|
||||
buf, 0, buf_size, priv->nal_length_size,
|
||||
&nalu
|
||||
);
|
||||
}
|
||||
else {
|
||||
if (size < 4)
|
||||
break;
|
||||
ofs = scan_for_start_code(priv->adapter, 0, size, &start_code);
|
||||
if (ofs < 0)
|
||||
break;
|
||||
gst_adapter_flush(priv->adapter, ofs);
|
||||
size -= ofs;
|
||||
|
||||
ofs = G_UNLIKELY(size < 8) ? -1 :
|
||||
scan_for_start_code(priv->adapter, 4, size - 4, NULL);
|
||||
if (ofs < 0) {
|
||||
// Assume the whole NAL unit is present if end-of-stream
|
||||
if (!is_eos)
|
||||
break;
|
||||
ofs = size;
|
||||
}
|
||||
buffer = gst_adapter_take_buffer(priv->adapter, ofs);
|
||||
size -= ofs;
|
||||
|
||||
buf = GST_BUFFER_DATA(buffer);
|
||||
buf_size = GST_BUFFER_SIZE(buffer);
|
||||
|
||||
result = gst_h264_parser_identify_nalu_unchecked(
|
||||
priv->parser,
|
||||
buf, 0, buf_size,
|
||||
&nalu
|
||||
);
|
||||
}
|
||||
if (priv->is_avc)
|
||||
result = gst_h264_parser_identify_nalu_avc(priv->parser,
|
||||
buf, 0, buf_size, priv->nal_length_size, &nalu);
|
||||
else
|
||||
result = gst_h264_parser_identify_nalu_unchecked(priv->parser,
|
||||
buf, 0, buf_size, &nalu);
|
||||
status = get_status(result);
|
||||
if (status == GST_VAAPI_DECODER_STATUS_SUCCESS)
|
||||
status = decode_nalu(decoder, &nalu);
|
||||
gst_buffer_unref(buffer);
|
||||
} while (status == GST_VAAPI_DECODER_STATUS_SUCCESS);
|
||||
|
||||
if (is_eos && (status == GST_VAAPI_DECODER_STATUS_SUCCESS ||
|
||||
status == GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA))
|
||||
status = decode_sequence_end(decoder);
|
||||
if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
|
||||
return status;
|
||||
|
||||
return decode_nalu(decoder, &nalu);
|
||||
}
|
||||
|
||||
static GstVaapiDecoderStatus
|
||||
|
@ -3049,10 +2968,9 @@ decode_codec_data(GstVaapiDecoderH264 *decoder, GstBuffer *buffer)
|
|||
return status;
|
||||
}
|
||||
|
||||
GstVaapiDecoderStatus
|
||||
gst_vaapi_decoder_h264_decode(GstVaapiDecoder *base, GstBuffer *buffer)
|
||||
static GstVaapiDecoderStatus
|
||||
ensure_decoder(GstVaapiDecoderH264 *decoder)
|
||||
{
|
||||
GstVaapiDecoderH264 * const decoder = GST_VAAPI_DECODER_H264(base);
|
||||
GstVaapiDecoderH264Private * const priv = decoder->priv;
|
||||
GstVaapiDecoderStatus status;
|
||||
GstBuffer *codec_data;
|
||||
|
@ -3061,7 +2979,7 @@ gst_vaapi_decoder_h264_decode(GstVaapiDecoder *base, GstBuffer *buffer)
|
|||
GST_VAAPI_DECODER_STATUS_ERROR_INIT_FAILED);
|
||||
|
||||
if (!priv->is_opened) {
|
||||
priv->is_opened = gst_vaapi_decoder_h264_open(decoder, buffer);
|
||||
priv->is_opened = gst_vaapi_decoder_h264_open(decoder);
|
||||
if (!priv->is_opened)
|
||||
return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC;
|
||||
|
||||
|
@ -3072,7 +2990,147 @@ gst_vaapi_decoder_h264_decode(GstVaapiDecoder *base, GstBuffer *buffer)
|
|||
return status;
|
||||
}
|
||||
}
|
||||
return decode_buffer(decoder, buffer);
|
||||
return GST_VAAPI_DECODER_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static GstVaapiDecoderStatus
|
||||
gst_vaapi_decoder_h264_parse(GstVaapiDecoder *base_decoder,
|
||||
GstAdapter *adapter, gboolean at_eos, GstVaapiDecoderUnit **unit_ptr)
|
||||
{
|
||||
GstVaapiDecoderH264 * const decoder = GST_VAAPI_DECODER_H264(base_decoder);
|
||||
GstVaapiDecoderH264Private * const priv = decoder->priv;
|
||||
GstVaapiDecoderUnit *unit;
|
||||
GstVaapiDecoderStatus status;
|
||||
GstH264NalUnit nalu;
|
||||
GstH264ParserResult result;
|
||||
guchar *buf;
|
||||
guint i, size, buf_size, nalu_size, flags;
|
||||
guint32 start_code;
|
||||
gint ofs;
|
||||
|
||||
status = ensure_decoder(decoder);
|
||||
if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
|
||||
return status;
|
||||
|
||||
size = gst_adapter_available(adapter);
|
||||
|
||||
if (priv->is_avc) {
|
||||
if (size < priv->nal_length_size)
|
||||
return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
|
||||
|
||||
buf = (guchar *)&start_code;
|
||||
g_assert(priv->nal_length_size <= sizeof(start_code));
|
||||
gst_adapter_copy(adapter, buf, 0, priv->nal_length_size);
|
||||
|
||||
nalu_size = 0;
|
||||
for (i = 0; i < priv->nal_length_size; i++)
|
||||
nalu_size = (nalu_size << 8) | buf[i];
|
||||
|
||||
buf_size = priv->nal_length_size + nalu_size;
|
||||
if (size < buf_size)
|
||||
return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
|
||||
}
|
||||
else {
|
||||
if (size < 4)
|
||||
return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
|
||||
ofs = scan_for_start_code(adapter, 0, size, NULL);
|
||||
if (ofs < 0)
|
||||
return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
|
||||
gst_adapter_flush(adapter, ofs);
|
||||
size -= ofs;
|
||||
|
||||
ofs = G_UNLIKELY(size < 8) ? -1 :
|
||||
scan_for_start_code(adapter, 4, size - 4, NULL);
|
||||
if (ofs < 0) {
|
||||
// Assume the whole NAL unit is present if end-of-stream
|
||||
if (!at_eos)
|
||||
return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
|
||||
ofs = size;
|
||||
}
|
||||
buf_size = ofs;
|
||||
}
|
||||
|
||||
buf = (guchar *)gst_adapter_peek(adapter, buf_size);
|
||||
if (!buf)
|
||||
return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
|
||||
|
||||
unit = gst_vaapi_decoder_unit_new(buf_size);
|
||||
if (!unit)
|
||||
return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
|
||||
|
||||
if (priv->is_avc)
|
||||
result = gst_h264_parser_identify_nalu_avc(priv->parser,
|
||||
buf, 0, buf_size, priv->nal_length_size, &nalu);
|
||||
else
|
||||
result = gst_h264_parser_identify_nalu_unchecked(priv->parser,
|
||||
buf, 0, buf_size, &nalu);
|
||||
status = get_status(result);
|
||||
if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) {
|
||||
gst_vaapi_decoder_unit_unref(unit);
|
||||
return status;
|
||||
}
|
||||
|
||||
flags = 0;
|
||||
switch (nalu.type) {
|
||||
case GST_H264_NAL_AU_DELIMITER:
|
||||
flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START;
|
||||
/* fall-through */
|
||||
case GST_H264_NAL_FILLER_DATA:
|
||||
flags |= GST_VAAPI_DECODER_UNIT_FLAG_SKIP;
|
||||
break;
|
||||
case GST_H264_NAL_STREAM_END:
|
||||
flags |= GST_VAAPI_DECODER_UNIT_FLAG_STREAM_END;
|
||||
/* fall-through */
|
||||
case GST_H264_NAL_SEQ_END:
|
||||
flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_END;
|
||||
break;
|
||||
case GST_H264_NAL_SPS:
|
||||
case GST_H264_NAL_PPS:
|
||||
case GST_H264_NAL_SEI:
|
||||
flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START;
|
||||
break;
|
||||
case GST_H264_NAL_SLICE_IDR:
|
||||
case GST_H264_NAL_SLICE:
|
||||
flags |= GST_VAAPI_DECODER_UNIT_FLAG_SLICE;
|
||||
/* XXX: assume we got a new frame if first_mb_in_slice is set
|
||||
to zero, thus ignoring Arbitrary Slice Order (ASO) feature
|
||||
from Baseline profile */
|
||||
if (nalu.offset + 2 <= nalu.size &&
|
||||
(nalu.data[nalu.offset + 1] & 0x80))
|
||||
flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START;
|
||||
break;
|
||||
default:
|
||||
if (nalu.type >= 14 && nalu.type <= 18)
|
||||
flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START;
|
||||
break;
|
||||
}
|
||||
GST_VAAPI_DECODER_UNIT_FLAG_SET(unit, flags);
|
||||
|
||||
*unit_ptr = unit;
|
||||
return GST_VAAPI_DECODER_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static GstVaapiDecoderStatus
|
||||
gst_vaapi_decoder_h264_decode(GstVaapiDecoder *base_decoder,
|
||||
GstVaapiDecoderUnit *unit)
|
||||
{
|
||||
GstVaapiDecoderH264 * const decoder = GST_VAAPI_DECODER_H264(base_decoder);
|
||||
GstVaapiDecoderStatus status;
|
||||
|
||||
status = ensure_decoder(decoder);
|
||||
if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
|
||||
return status;
|
||||
|
||||
unit->buffer = gst_buffer_create_sub(
|
||||
GST_VAAPI_DECODER_CODEC_FRAME(decoder)->input_buffer,
|
||||
unit->offset, unit->size);
|
||||
if (!unit->buffer)
|
||||
return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
|
||||
|
||||
status = decode_buffer(decoder, unit->buffer);
|
||||
if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
|
||||
return status;
|
||||
return GST_VAAPI_DECODER_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -3110,6 +3168,7 @@ gst_vaapi_decoder_h264_class_init(GstVaapiDecoderH264Class *klass)
|
|||
object_class->finalize = gst_vaapi_decoder_h264_finalize;
|
||||
object_class->constructed = gst_vaapi_decoder_h264_constructed;
|
||||
|
||||
decoder_class->parse = gst_vaapi_decoder_h264_parse;
|
||||
decoder_class->decode = gst_vaapi_decoder_h264_decode;
|
||||
}
|
||||
|
||||
|
@ -3132,7 +3191,6 @@ gst_vaapi_decoder_h264_init(GstVaapiDecoderH264 *decoder)
|
|||
priv->RefPicList0_count = 0;
|
||||
priv->RefPicList1_count = 0;
|
||||
priv->nal_length_size = 0;
|
||||
priv->adapter = NULL;
|
||||
priv->field_poc[0] = 0;
|
||||
priv->field_poc[1] = 0;
|
||||
priv->poc_msb = 0;
|
||||
|
|
Loading…
Reference in a new issue