diff options
Diffstat (limited to 'sys/vdpau/gstvdpaumpegdecoder.c')
-rw-r--r-- | sys/vdpau/gstvdpaumpegdecoder.c | 272 |
1 files changed, 259 insertions, 13 deletions
diff --git a/sys/vdpau/gstvdpaumpegdecoder.c b/sys/vdpau/gstvdpaumpegdecoder.c index 6ff9b42a..6f75181b 100644 --- a/sys/vdpau/gstvdpaumpegdecoder.c +++ b/sys/vdpau/gstvdpaumpegdecoder.c @@ -59,6 +59,7 @@ #endif #include <gst/gst.h> +#include <string.h> #include "mpegutil.h" #include "gstvdpaumpegdecoder.h" @@ -103,7 +104,9 @@ gst_vdpau_mpeg_decoder_set_caps (GstVdpauDecoder * dec, GstCaps * caps) { GstVdpauMpegDecoder *mpeg_dec; GstStructure *structure; - gint version; + const GValue *value; + GstBuffer *codec_data; + MPEGSeqHdr hdr = { 0, }; VdpDecoderProfile profile; VdpauFunctions *f; VdpStatus status; @@ -111,19 +114,15 @@ gst_vdpau_mpeg_decoder_set_caps (GstVdpauDecoder * dec, GstCaps * caps) mpeg_dec = GST_VDPAU_MPEG_DECODER (dec); structure = gst_caps_get_structure (caps, 0); - gst_structure_get_int (structure, "mpegversion", &version); - if (version == 1) + gst_structure_get_int (structure, "mpegversion", &mpeg_dec->version); + if (mpeg_dec->version == 1) profile = VDP_DECODER_PROFILE_MPEG1; - else { - const GValue *value; - GstBuffer *codec_data; - MPEGSeqHdr hdr = { 0, }; - - value = gst_structure_get_value (structure, "codec_data"); - codec_data = gst_value_get_buffer (value); - mpeg_util_parse_sequence_hdr (&hdr, GST_BUFFER_DATA (codec_data), - GST_BUFFER_DATA (codec_data) + GST_BUFFER_SIZE (codec_data)); + value = gst_structure_get_value (structure, "codec_data"); + codec_data = gst_value_get_buffer (value); + mpeg_util_parse_sequence_hdr (&hdr, GST_BUFFER_DATA (codec_data), + GST_BUFFER_DATA (codec_data) + GST_BUFFER_SIZE (codec_data)); + if (mpeg_dec->version != 1) { switch (hdr.profile) { case 5: profile = VDP_DECODER_PROFILE_MPEG2_SIMPLE; @@ -133,6 +132,10 @@ gst_vdpau_mpeg_decoder_set_caps (GstVdpauDecoder * dec, GstCaps * caps) break; } } + memcpy (&mpeg_dec->vdp_info.intra_quantizer_matrix, + &hdr.intra_quantizer_matrix, 64); + memcpy (&mpeg_dec->vdp_info.non_intra_quantizer_matrix, + &hdr.non_intra_quantizer_matrix, 64); f = dec->functions; status = f->vdp_decoder_create (dec->device, profile, dec->width, @@ -147,6 +150,228 @@ gst_vdpau_mpeg_decoder_set_caps (GstVdpauDecoder * dec, GstCaps * caps) return TRUE; } +static GstFlowReturn +gst_vdpau_mpeg_decoder_decode (GstVdpauMpegDecoder * mpeg_dec) +{ + GstVdpauDecoder *dec; + GstBuffer *buffer; + VdpVideoSurface surface; + VdpauFunctions *f; + VdpBitstreamBuffer vbit[1]; + VdpStatus status; + GstFlowReturn ret; + + dec = GST_VDPAU_DECODER (mpeg_dec); + + buffer = gst_adapter_take_buffer (mpeg_dec->adapter, + gst_adapter_available (mpeg_dec->adapter)); + + if (mpeg_dec->vdp_info.picture_coding_type == P_FRAME) { + mpeg_dec->p_buffer = buffer; + } + + surface = + gst_vdpau_decoder_create_video_surface (GST_VDPAU_DECODER (mpeg_dec)); + + f = dec->functions; + + vbit[0].struct_version = VDP_BITSTREAM_BUFFER_VERSION; + vbit[0].bitstream = GST_BUFFER_DATA (buffer); + vbit[0].bitstream_bytes = GST_BUFFER_SIZE (buffer); + + status = f->vdp_decoder_render (mpeg_dec->decoder, surface, + (VdpPictureInfo *) & mpeg_dec->vdp_info, 1, vbit); + gst_buffer_unref (buffer); + mpeg_dec->vdp_info.slice_count = 0; + + if (status != VDP_STATUS_OK) { + GST_ELEMENT_ERROR (mpeg_dec, RESOURCE, READ, + ("Could not decode"), + ("Error returned from vdpau was: %s", + f->vdp_get_error_string (status))); + + if (mpeg_dec->vdp_info.forward_reference != VDP_INVALID_HANDLE) + f->vdp_video_surface_destroy (mpeg_dec->vdp_info.forward_reference); + + f->vdp_video_surface_destroy (surface); + + return GST_FLOW_ERROR; + } + + ret = + gst_vdpau_decoder_push_video_surface (GST_VDPAU_DECODER (mpeg_dec), + surface); + + if (mpeg_dec->vdp_info.forward_reference != VDP_INVALID_HANDLE) + f->vdp_video_surface_destroy (mpeg_dec->vdp_info.forward_reference); + + mpeg_dec->vdp_info.forward_reference = surface; + + return ret; +} + +static gboolean +gst_vdpau_mpeg_decoder_parse_picture_coding (GstVdpauMpegDecoder * mpeg_dec, + guint8 * data, guint8 * end) +{ + GstVdpauDecoder *dec; + MPEGPictureExt pic_ext; + VdpPictureInfoMPEG1Or2 *info; + + dec = GST_VDPAU_DECODER (mpeg_dec); + info = &mpeg_dec->vdp_info; + + if (!mpeg_util_parse_picture_coding_extension (&pic_ext, data, end)) + return FALSE; + + memcpy (&mpeg_dec->vdp_info.f_code, &pic_ext.f_code, 4); + + info->intra_dc_precision = pic_ext.intra_dc_precision; + info->picture_structure = pic_ext.picture_structure; + info->top_field_first = pic_ext.top_field_first; + info->frame_pred_frame_dct = pic_ext.frame_pred_frame_dct; + info->concealment_motion_vectors = pic_ext.concealment_motion_vectors; + info->q_scale_type = pic_ext.q_scale_type; + info->intra_vlc_format = pic_ext.intra_vlc_format; + + return TRUE; +} + +static gboolean +gst_vdpau_mpeg_decoder_parse_picture (GstVdpauMpegDecoder * mpeg_dec, + guint8 * data, guint8 * end) +{ + GstVdpauDecoder *dec; + MPEGPictureHdr pic_hdr; + + dec = GST_VDPAU_DECODER (mpeg_dec); + + if (!mpeg_util_parse_picture_hdr (&pic_hdr, data, end)) + return FALSE; + + mpeg_dec->vdp_info.picture_coding_type = pic_hdr.pic_type; + + + if (pic_hdr.pic_type == I_FRAME && + mpeg_dec->vdp_info.forward_reference != VDP_INVALID_HANDLE) { + dec->functions->vdp_video_surface_destroy (mpeg_dec->vdp_info. + forward_reference); + mpeg_dec->vdp_info.forward_reference = VDP_INVALID_HANDLE; + } + + if (mpeg_dec->version == 1) { + mpeg_dec->vdp_info.full_pel_forward_vector = + pic_hdr.full_pel_forward_vector; + mpeg_dec->vdp_info.full_pel_backward_vector = + pic_hdr.full_pel_backward_vector; + memcpy (&mpeg_dec->vdp_info.f_code, &pic_hdr.f_code, 4); + } + + return TRUE; +} + +static gboolean +gst_vdpau_mpeg_decoder_parse_gop (GstVdpauMpegDecoder * mpeg_dec, guint8 * data, + guint8 * end) +{ + MPEGPictureGOP gop; + + if (!mpeg_util_parse_picture_gop (&gop, data, end)) + return FALSE; + + return TRUE; +} + +static gboolean +gst_vdpau_mpeg_decoder_parse_quant_matrix (GstVdpauMpegDecoder * mpeg_dec, + guint8 * data, guint8 * end) +{ + MPEGQuantMatrix qm; + + if (!mpeg_util_parse_quant_matrix (&qm, data, end)) + return FALSE; + + memcpy (&mpeg_dec->vdp_info.intra_quantizer_matrix, + &qm.intra_quantizer_matrix, 64); + memcpy (&mpeg_dec->vdp_info.non_intra_quantizer_matrix, + &qm.non_intra_quantizer_matrix, 64); + return TRUE; +} + +static GstFlowReturn +gst_vdpau_mpeg_decoder_chain (GstPad * pad, GstBuffer * buffer) +{ + GstVdpauMpegDecoder *mpeg_dec; + guint8 *data, *end; + guint32 sync_word = 0xffffffff; + + mpeg_dec = GST_VDPAU_MPEG_DECODER (GST_OBJECT_PARENT (pad)); + + data = GST_BUFFER_DATA (buffer); + end = GST_BUFFER_DATA (buffer) + GST_BUFFER_SIZE (buffer); + + while ((data = mpeg_util_find_start_code (&sync_word, data, end))) { + guint8 *packet_start; + guint8 *packet_end; + + packet_start = data - 3; + packet_end = mpeg_util_find_start_code (&sync_word, data, end); + if (packet_end) + packet_end -= 3; + else + packet_end = end; + + if (data[0] >= MPEG_PACKET_SLICE_MIN && data[0] <= MPEG_PACKET_SLICE_MAX) { + GstBuffer *subbuf; + + GST_DEBUG_OBJECT (mpeg_dec, "MPEG_PACKET_SLICE"); + subbuf = + gst_buffer_create_sub (buffer, + packet_start - GST_BUFFER_DATA (buffer), packet_end - packet_start); + gst_adapter_push (mpeg_dec->adapter, subbuf); + mpeg_dec->vdp_info.slice_count++; + } else if (mpeg_dec->vdp_info.slice_count > 0) { + if (gst_vdpau_mpeg_decoder_decode (mpeg_dec) != GST_FLOW_OK) + return GST_FLOW_ERROR; + } + + switch (data[0]) { + case MPEG_PACKET_PICTURE: + GST_DEBUG_OBJECT (mpeg_dec, "MPEG_PACKET_PICTURE"); + gst_vdpau_mpeg_decoder_parse_picture (mpeg_dec, packet_start, + packet_end); + break; + case MPEG_PACKET_SEQUENCE: + GST_DEBUG_OBJECT (mpeg_dec, "MPEG_PACKET_SEQUENCE"); + break; + case MPEG_PACKET_EXTENSION: + GST_DEBUG_OBJECT (mpeg_dec, "MPEG_PACKET_EXTENSION"); + switch (read_bits (data + 1, 0, 4)) { + case MPEG_PACKET_EXT_PICTURE_CODING: + gst_vdpau_mpeg_decoder_parse_picture_coding (mpeg_dec, packet_start, + packet_end); + break; + default: + break; + } + break; + case MPEG_PACKET_EXT_QUANT_MATRIX: + GST_DEBUG_OBJECT (mpeg_dec, "MPEG_PACKET_EXT_QUANT_MATRIX"); + gst_vdpau_mpeg_decoder_parse_quant_matrix (mpeg_dec, packet_start, + packet_end); + break; + case MPEG_PACKET_GOP: + GST_DEBUG_OBJECT (mpeg_dec, "MPEG_PACKET_GOP"); + gst_vdpau_mpeg_decoder_parse_gop (mpeg_dec, packet_start, packet_end); + break; + default: + break; + } + } + + return GST_FLOW_OK; +} + /* GObject vmethod implementations */ static void @@ -187,12 +412,33 @@ gst_vdpau_mpeg_decoder_class_init (GstVdpauMpegDecoderClass * klass) } static void +gst_vdpau_mpeg_decoder_init_info (VdpPictureInfoMPEG1Or2 * vdp_info) +{ + vdp_info->forward_reference = VDP_INVALID_HANDLE; + vdp_info->backward_reference = VDP_INVALID_HANDLE; + vdp_info->slice_count = 0; + vdp_info->picture_structure = 0; + vdp_info->picture_coding_type = 0; + vdp_info->intra_dc_precision = 0; + vdp_info->frame_pred_frame_dct = 0; + vdp_info->concealment_motion_vectors = 0; +} + +static void gst_vdpau_mpeg_decoder_init (GstVdpauMpegDecoder * mpeg_dec, GstVdpauMpegDecoderClass * gclass) { - mpeg_dec->silent = FALSE; + GstVdpauDecoder *dec; + + dec = GST_VDPAU_DECODER (mpeg_dec); + mpeg_dec->silent = FALSE; mpeg_dec->decoder = VDP_INVALID_HANDLE; + gst_vdpau_mpeg_decoder_init_info (&mpeg_dec->vdp_info); + + mpeg_dec->adapter = gst_adapter_new (); + + gst_pad_set_chain_function (dec->sink, gst_vdpau_mpeg_decoder_chain); } static void |