diff options
author | Gwenole Beauchesne <gwenole.beauchesne@intel.com> | 2011-10-05 15:56:36 +0200 |
---|---|---|
committer | Gwenole Beauchesne <gwenole.beauchesne@intel.com> | 2012-01-16 11:40:51 +0100 |
commit | 032486912f37446ab2b367f56c362e537295a509 (patch) | |
tree | 5b0bf46ca892b845c414edeffc67da8b823164a5 /gst-libs | |
parent | 5aea02a66f9d174d7d57635b85cf809704cc0ae9 (diff) |
vc1: handle encapsulated bitstreams.
Diffstat (limited to 'gst-libs')
-rw-r--r-- | gst-libs/gst/vaapi/gstvaapidecoder_vc1.c | 153 |
1 files changed, 119 insertions, 34 deletions
diff --git a/gst-libs/gst/vaapi/gstvaapidecoder_vc1.c b/gst-libs/gst/vaapi/gstvaapidecoder_vc1.c index a3446100..dd7a0e9b 100644 --- a/gst-libs/gst/vaapi/gstvaapidecoder_vc1.c +++ b/gst-libs/gst/vaapi/gstvaapidecoder_vc1.c @@ -60,6 +60,8 @@ struct _GstVaapiDecoderVC1Private { GstVaapiPicture *prev_picture; GstVaapiTSB *tsb; GstBuffer *sub_buffer; + guint8 *rbdu_buffer; + guint rbdu_buffer_size; guint is_constructed : 1; guint is_opened : 1; guint is_first_field : 1; @@ -152,6 +154,12 @@ gst_vaapi_decoder_vc1_destroy(GstVaapiDecoderVC1 *decoder) GstVaapiDecoderVC1Private * const priv = decoder->priv; gst_vaapi_decoder_vc1_close(decoder); + + if (priv->rbdu_buffer) { + g_free(priv->rbdu_buffer); + priv->rbdu_buffer = NULL; + priv->rbdu_buffer_size = 0; + } } static gboolean @@ -243,7 +251,7 @@ decode_current_picture(GstVaapiDecoderVC1 *decoder) } static GstVaapiDecoderStatus -decode_sequence(GstVaapiDecoderVC1 *decoder, guchar *buf, guint buf_size) +decode_sequence(GstVaapiDecoderVC1 *decoder, GstVC1BDU *rbdu, GstVC1BDU *ebdu) { GstVaapiDecoder * const base_decoder = GST_VAAPI_DECODER(decoder); GstVaapiDecoderVC1Private * const priv = decoder->priv; @@ -254,7 +262,11 @@ decode_sequence(GstVaapiDecoderVC1 *decoder, guchar *buf, guint buf_size) GstVaapiProfile profile; guint width, height, fps_n, fps_d; - result = gst_vc1_parse_sequence_header(buf, buf_size, seq_hdr); + result = gst_vc1_parse_sequence_header( + rbdu->data + rbdu->offset, + rbdu->size, + seq_hdr + ); if (result != GST_VC1_PARSER_OK) { GST_DEBUG("failed to parse sequence layer"); return get_status(result); @@ -402,7 +414,7 @@ decode_sequence_end(GstVaapiDecoderVC1 *decoder) } static GstVaapiDecoderStatus -decode_entry_point(GstVaapiDecoderVC1 *decoder, guchar *buf, guint buf_size) +decode_entry_point(GstVaapiDecoderVC1 *decoder, GstVC1BDU *rbdu, GstVC1BDU *ebdu) { GstVaapiDecoderVC1Private * const priv = decoder->priv; GstVC1SeqHdr * const seq_hdr = &priv->seq_hdr; @@ -410,7 +422,8 @@ decode_entry_point(GstVaapiDecoderVC1 *decoder, guchar *buf, guint buf_size) GstVC1ParserResult result; result = gst_vc1_parse_entry_point_header( - buf, buf_size, + rbdu->data + rbdu->offset, + rbdu->size, entrypoint_hdr, seq_hdr ); @@ -833,7 +846,7 @@ fill_picture(GstVaapiDecoderVC1 *decoder, GstVaapiPicture *picture) } static GstVaapiDecoderStatus -decode_frame(GstVaapiDecoderVC1 *decoder, guchar *buf, guint buf_size) +decode_frame(GstVaapiDecoderVC1 *decoder, GstVC1BDU *rbdu, GstVC1BDU *ebdu) { GstVaapiDecoder * const base_decoder = GST_VAAPI_DECODER(decoder); GstVaapiDecoderVC1Private * const priv = decoder->priv; @@ -871,7 +884,8 @@ decode_frame(GstVaapiDecoderVC1 *decoder, guchar *buf, guint buf_size) memset(frame_hdr, 0, sizeof(*frame_hdr)); result = gst_vc1_parse_frame_header( - buf, buf_size, + rbdu->data + rbdu->offset, + rbdu->size, frame_hdr, seq_hdr, priv->bitplanes @@ -921,7 +935,12 @@ decode_frame(GstVaapiDecoderVC1 *decoder, guchar *buf, guint buf_size) if (!fill_picture(decoder, picture)) return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN; - slice = gst_vaapi_decoder_new_slice(base_decoder, picture, buf, buf_size); + slice = gst_vaapi_decoder_new_slice( + base_decoder, + picture, + ebdu->data + ebdu->sc_offset, + ebdu->size + ebdu->offset - ebdu->sc_offset + ); if (!slice) { GST_DEBUG("failed to allocate slice"); return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; @@ -929,22 +948,107 @@ decode_frame(GstVaapiDecoderVC1 *decoder, guchar *buf, guint buf_size) /* Fill in VASliceParameterBufferVC1 */ slice_param = slice->param; - slice_param->macroblock_offset = frame_hdr->header_size; + slice_param->macroblock_offset = 8 * (ebdu->offset - ebdu->sc_offset) + frame_hdr->header_size; slice_param->slice_vertical_position = 0; /* Decode picture right away, we got the full frame */ return decode_current_picture(decoder); } +static gboolean +decode_rbdu(GstVaapiDecoderVC1 *decoder, GstVC1BDU *rbdu, GstVC1BDU *ebdu) +{ + GstVaapiDecoderVC1Private * const priv = decoder->priv; + guint8 *rbdu_buffer; + guint i, j, rbdu_buffer_size; + + /* BDU are encapsulated in advanced profile mode only */ + if (priv->profile != GST_VAAPI_PROFILE_VC1_ADVANCED) { + memcpy(rbdu, ebdu, sizeof(*rbdu)); + return TRUE; + } + + /* Reallocate unescaped bitstream buffer */ + rbdu_buffer = priv->rbdu_buffer; + if (!rbdu_buffer || ebdu->size > priv->rbdu_buffer_size) { + rbdu_buffer = g_realloc(priv->rbdu_buffer, ebdu->size); + if (!rbdu_buffer) + return FALSE; + priv->rbdu_buffer = rbdu_buffer; + priv->rbdu_buffer_size = ebdu->size; + } + + /* Unescape bitstream buffer */ + if (ebdu->size < 4) { + memcpy(rbdu_buffer, ebdu->data + ebdu->offset, ebdu->size); + rbdu_buffer_size = ebdu->size; + } + else { + guint8 * const bdu_buffer = ebdu->data + ebdu->offset; + for (i = 0, j = 0; i < ebdu->size; i++) { + if (i >= 2 && i < ebdu->size - 1 && + bdu_buffer[i - 1] == 0x00 && + bdu_buffer[i - 2] == 0x00 && + bdu_buffer[i ] == 0x03 && + bdu_buffer[i + 1] <= 0x03) + i++; + rbdu_buffer[j++] = bdu_buffer[i]; + } + rbdu_buffer_size = j; + } + + /* Reconstruct RBDU */ + rbdu->type = ebdu->type; + rbdu->size = rbdu_buffer_size; + rbdu->sc_offset = 0; + rbdu->offset = 0; + rbdu->data = rbdu_buffer; + return TRUE; +} + +static GstVaapiDecoderStatus +decode_ebdu(GstVaapiDecoderVC1 *decoder, GstVC1BDU *ebdu) +{ + GstVaapiDecoderStatus status; + GstVC1BDU rbdu; + + if (!decode_rbdu(decoder, &rbdu, ebdu)) + return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED; + + switch (ebdu->type) { + case GST_VC1_SEQUENCE: + status = decode_sequence(decoder, &rbdu, ebdu); + break; + case GST_VC1_ENTRYPOINT: + status = decode_entry_point(decoder, &rbdu, ebdu); + break; + case GST_VC1_FRAME: + status = decode_frame(decoder, &rbdu, ebdu); + break; + case GST_VC1_SLICE: + GST_DEBUG("decode slice"); + status = GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + break; + case GST_VC1_END_OF_SEQ: + status = decode_sequence_end(decoder); + break; + default: + GST_DEBUG("unsupported BDU type %d", ebdu->type); + status = GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; + break; + } + return status; +} + static GstVaapiDecoderStatus decode_buffer(GstVaapiDecoderVC1 *decoder, GstBuffer *buffer) { GstVaapiDecoderVC1Private * const priv = decoder->priv; GstVaapiDecoderStatus status; GstVC1ParserResult result; - GstVC1BDU bdu; + GstVC1BDU ebdu; guchar *buf; - guint buf_size, bdu_size, ofs; + guint buf_size, ofs; buf = GST_BUFFER_DATA(buffer); buf_size = GST_BUFFER_SIZE(buffer); @@ -968,7 +1072,7 @@ decode_buffer(GstVaapiDecoderVC1 *decoder, GstBuffer *buffer) result = gst_vc1_identify_next_bdu( buf + ofs, buf_size - ofs, - &bdu + &ebdu ); status = get_status(result); @@ -979,29 +1083,8 @@ decode_buffer(GstVaapiDecoderVC1 *decoder, GstBuffer *buffer) if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) break; - ofs += bdu.offset; - switch (bdu.type) { - case GST_VC1_SEQUENCE: - status = decode_sequence(decoder, buf + ofs, bdu.size); - break; - case GST_VC1_ENTRYPOINT: - status = decode_entry_point(decoder, buf + ofs, bdu.size); - break; - case GST_VC1_FRAME: - status = decode_frame(decoder, buf + ofs, bdu.size); - break; - case GST_VC1_SLICE: - GST_DEBUG("decode slice"); - break; - case GST_VC1_END_OF_SEQ: - status = decode_sequence_end(decoder); - break; - default: - GST_DEBUG("unsupported BDU type %d", bdu.type); - status = GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER; - break; - } - ofs += bdu.size; + ofs += ebdu.offset + ebdu.size; + status = decode_ebdu(decoder, &ebdu); } while (status == GST_VAAPI_DECODER_STATUS_SUCCESS); return status; } @@ -1078,6 +1161,8 @@ gst_vaapi_decoder_vc1_init(GstVaapiDecoderVC1 *decoder) priv->prev_picture = NULL; priv->tsb = NULL; priv->sub_buffer = NULL; + priv->rbdu_buffer = NULL; + priv->rbdu_buffer_size = 0; priv->is_constructed = FALSE; priv->is_opened = FALSE; priv->is_first_field = FALSE; |