diff options
-rw-r--r-- | sys/vdpau/Makefile.am | 3 | ||||
-rw-r--r-- | sys/vdpau/gstvdpaudecoder.c | 144 | ||||
-rw-r--r-- | sys/vdpau/gstvdpaudecoder.h | 7 | ||||
-rw-r--r-- | sys/vdpau/gstvdpaumpegdecoder.c | 272 | ||||
-rw-r--r-- | sys/vdpau/gstvdpaumpegdecoder.h | 10 | ||||
-rw-r--r-- | sys/vdpau/mpegutil.c | 131 | ||||
-rw-r--r-- | sys/vdpau/mpegutil.h | 23 |
7 files changed, 529 insertions, 61 deletions
diff --git a/sys/vdpau/Makefile.am b/sys/vdpau/Makefile.am index b786be0d..ef43e5fd 100644 --- a/sys/vdpau/Makefile.am +++ b/sys/vdpau/Makefile.am @@ -6,7 +6,8 @@ libgstvdpau_la_SOURCES = \ mpegutil.c libgstvdpau_la_CFLAGS = $(GST_CFLAGS) $(X11_CFLAGS) -Ivdpau -libgstvdpau_la_LIBADD = $(GST_LIBS) $(X11_LIBS) -lvdpau +libgstvdpau_la_LIBADD = $(GST_LIBS) $(GST_BASE_LIBS) \ + $(GST_PLUGINS_BASE) $(X11_LIBS) -lgstvideo-$(GST_MAJORMINOR) -lvdpau libgstvdpau_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) libgstvdpau_la_LIBTOOLFLAGS = --tag=disable-static diff --git a/sys/vdpau/gstvdpaudecoder.c b/sys/vdpau/gstvdpaudecoder.c index c13b0173..fb2ce627 100644 --- a/sys/vdpau/gstvdpaudecoder.c +++ b/sys/vdpau/gstvdpaudecoder.c @@ -24,7 +24,7 @@ #endif #include <gst/gst.h> -#include <gst/controller/gstcontroller.h> +#include <gst/video/video.h> #include "gstvdpaudecoder.h" #include <vdpau/vdpau_x11.h> @@ -64,11 +64,12 @@ static void gst_vdpaudecoder_set_property (GObject * object, guint prop_id, static void gst_vdpaudecoder_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); -gboolean -gst_vdpaudecoder_push_video_surface (GstVdpauDecoder * dec, +GstFlowReturn +gst_vdpau_decoder_push_video_surface (GstVdpauDecoder * dec, VdpVideoSurface surface) { VdpauFunctions *f; + GstBuffer *buffer; f = dec->functions; @@ -77,34 +78,98 @@ gst_vdpaudecoder_push_video_surface (GstVdpauDecoder * dec, { gint size; GstFlowReturn result; - GstBuffer *buffer; VdpStatus status; guint8 *data[3]; + guint32 stride[3]; - size = dec->height * dec->width + dec->height * dec->width / 2; + size = + gst_video_format_get_size (GST_VIDEO_FORMAT_YV12, dec->width, + dec->height); result = gst_pad_alloc_buffer_and_set_caps (dec->src, GST_BUFFER_OFFSET_NONE, size, GST_PAD_CAPS (dec->src), &buffer); if (G_UNLIKELY (result != GST_FLOW_OK)) - return FALSE; - - data[0] = GST_BUFFER_DATA (buffer); - data[1] = data[0] + dec->height * dec->width; - data[2] = data[1] + dec->height * dec->width / 4; + return result; + + + data[0] = GST_BUFFER_DATA (buffer) + + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_YV12, + 0, dec->width, dec->height); + data[1] = data[0] + + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_YV12, + 2, dec->width, dec->height); + data[2] = data[0] + + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_YV12, + 1, dec->width, dec->height); + + stride[0] = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_YV12, + 0, dec->width); + stride[1] = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_YV12, + 2, dec->width); + stride[2] = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_YV12, + 1, dec->width); status = f->vdp_video_surface_get_bits_ycbcr (surface, VDP_YCBCR_FORMAT_YV12, - (void *) data, NULL); - if (G_UNLIKELY (status != VDP_STATUS_OK)) - return FALSE; + (void *) data, stride); + if (G_UNLIKELY (status != VDP_STATUS_OK)) { + GST_ELEMENT_ERROR (dec, RESOURCE, READ, + ("Couldn't get data from vdpau"), + ("Error returned from vdpau was: %s", + f->vdp_get_error_string (status))); + return GST_FLOW_ERROR; + } + break; + } + case GST_MAKE_FOURCC ('N', 'V', '1', '2'): + { + gint size; + GstFlowReturn result; + VdpStatus status; + guint8 *data[2]; + guint32 stride[2]; + + size = dec->width * dec->height + dec->width * dec->height / 2; + result = + gst_pad_alloc_buffer_and_set_caps (dec->src, GST_BUFFER_OFFSET_NONE, + size, GST_PAD_CAPS (dec->src), &buffer); + if (G_UNLIKELY (result != GST_FLOW_OK)) + return result; + + + data[0] = GST_BUFFER_DATA (buffer); + data[1] = data[0] + dec->width * dec->height; + stride[0] = dec->width; + stride[1] = dec->width; + + status = + f->vdp_video_surface_get_bits_ycbcr (surface, VDP_YCBCR_FORMAT_NV12, + (void *) data, stride); + if (G_UNLIKELY (status != VDP_STATUS_OK)) { + GST_ELEMENT_ERROR (dec, RESOURCE, READ, + ("Couldn't get data from vdpau"), + ("Error returned from vdpau was: %s", + f->vdp_get_error_string (status))); + return GST_FLOW_ERROR; + } break; } default: break; } - return TRUE; + GST_BUFFER_TIMESTAMP (buffer) = + gst_util_uint64_scale_int (GST_SECOND * dec->frame_nr, + dec->framerate_denominator, dec->framerate_numerator); + GST_BUFFER_DURATION (buffer) = + gst_util_uint64_scale_int (GST_SECOND, dec->framerate_denominator, + dec->framerate_numerator); + GST_BUFFER_OFFSET (buffer) = dec->frame_nr; + dec->frame_nr++; + GST_BUFFER_OFFSET_END (buffer) = dec->frame_nr; + + return gst_pad_push (dec->src, buffer); } typedef struct @@ -149,6 +214,38 @@ static VdpauFormats formats[6] = { } }; +VdpVideoSurface +gst_vdpau_decoder_create_video_surface (GstVdpauDecoder * dec) +{ + VdpauFunctions *f; + VdpChromaType chroma_type; + gint i; + VdpStatus status; + VdpVideoSurface surface; + + f = dec->functions; + + chroma_type = VDP_CHROMA_TYPE_422; + for (i = 0; i < 6; i++) { + if (formats[i].fourcc == dec->format) { + chroma_type = formats[i].chroma_type; + break; + } + } + + status = f->vdp_video_surface_create (dec->device, chroma_type, dec->width, + dec->height, &surface); + if (status != VDP_STATUS_OK) { + GST_ELEMENT_ERROR (dec, RESOURCE, READ, + ("Couldn't create a VdpVideoSurface"), + ("Error returned from vdpau was: %s", + f->vdp_get_error_string (status))); + return VDP_INVALID_HANDLE; + } + + return surface; +} + static GstCaps * gst_vdpaudecoder_get_vdpau_support (GstVdpauDecoder * dec) { @@ -355,6 +452,7 @@ gst_vdpaudecoder_sink_set_caps (GstPad * pad, GstCaps * caps) GstStructure *structure; gint width, height; gint framerate_numerator, framerate_denominator; + gint par_numerator, par_denominator; guint32 fourcc_format; gboolean res; @@ -363,21 +461,25 @@ gst_vdpaudecoder_sink_set_caps (GstPad * pad, GstCaps * caps) gst_structure_get_int (structure, "height", &height); gst_structure_get_fraction (structure, "framerate", &framerate_numerator, &framerate_denominator); + gst_structure_get_fraction (structure, "pixel-aspect-ratio", + &par_numerator, &par_denominator); src_caps = gst_pad_get_allowed_caps (dec->src); if (G_UNLIKELY (!src_caps)) return FALSE; - structure = gst_caps_get_structure (src_caps, 0); + new_caps = gst_caps_copy_nth (src_caps, 0); + gst_caps_unref (src_caps); + structure = gst_caps_get_structure (new_caps, 0); gst_structure_get_fourcc (structure, "format", &fourcc_format); gst_structure_set (structure, "width", G_TYPE_INT, width, "height", G_TYPE_INT, height, "framerate", GST_TYPE_FRACTION, framerate_numerator, - framerate_denominator, NULL); + framerate_denominator, + "pixel-aspect-ratio", GST_TYPE_FRACTION, par_numerator, + par_denominator, NULL); - new_caps = gst_caps_copy_nth (src_caps, 0); - gst_caps_unref (src_caps); gst_pad_fixate_caps (dec->src, new_caps); res = gst_pad_set_caps (dec->src, new_caps); @@ -388,6 +490,8 @@ gst_vdpaudecoder_sink_set_caps (GstPad * pad, GstCaps * caps) dec->width = width; dec->height = height; + dec->framerate_numerator = framerate_numerator; + dec->framerate_denominator = framerate_denominator; dec->format = fourcc_format; if (dec_class->set_caps && !dec_class->set_caps (dec, caps)) @@ -464,8 +568,12 @@ gst_vdpaudecoder_init (GstVdpauDecoder * dec, GstVdpauDecoderClass * klass) dec->height = 0; dec->width = 0; + dec->framerate_numerator = 0; + dec->framerate_denominator = 0; dec->format = 0; + dec->frame_nr = 0; + dec->functions = g_slice_new0 (VdpauFunctions); dec->src = gst_pad_new_from_static_template (&src_template, "src"); diff --git a/sys/vdpau/gstvdpaudecoder.h b/sys/vdpau/gstvdpaudecoder.h index 5cd83042..3ab3c9f3 100644 --- a/sys/vdpau/gstvdpaudecoder.h +++ b/sys/vdpau/gstvdpaudecoder.h @@ -56,8 +56,11 @@ struct _GstVdpauDecoder { GstCaps *src_caps; gint width, height; + gint framerate_numerator, framerate_denominator; guint32 format; + gint frame_nr; + gboolean silent; }; @@ -88,7 +91,9 @@ struct _VdpauFunctions { GType gst_vdpaudecoder_get_type (void); -gboolean gst_vdpaudecoder_push_video_surface (GstVdpauDecoder * dec, VdpVideoSurface surface); +gboolean gst_vdpau_decoder_push_video_surface (GstVdpauDecoder * dec, + VdpVideoSurface surface); +VdpVideoSurface gst_vdpau_decoder_create_video_surface (GstVdpauDecoder *dec); G_END_DECLS 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 diff --git a/sys/vdpau/gstvdpaumpegdecoder.h b/sys/vdpau/gstvdpaumpegdecoder.h index 0207ce31..36c02534 100644 --- a/sys/vdpau/gstvdpaumpegdecoder.h +++ b/sys/vdpau/gstvdpaumpegdecoder.h @@ -45,6 +45,7 @@ #define __GST_VDPAU_MPEG_DECODER_H__ #include <gst/gst.h> +#include <gst/base/gstadapter.h> #include "gstvdpaudecoder.h" @@ -66,7 +67,16 @@ struct _GstVdpauMpegDecoder gboolean silent; + gint version; + VdpDecoder decoder; + VdpPictureInfoMPEG1Or2 vdp_info; + + GstAdapter *adapter; + gint slices; + + GstBuffer *p_buffer; + VdpPictureInfoMPEG1Or2 p_vdp_info; }; struct _GstVdpauMpegDecoderClass diff --git a/sys/vdpau/mpegutil.c b/sys/vdpau/mpegutil.c index aa77a426..8bba8d1f 100644 --- a/sys/vdpau/mpegutil.c +++ b/sys/vdpau/mpegutil.c @@ -166,7 +166,6 @@ mpeg_util_parse_extension_packet (MPEGSeqHdr * hdr, guint8 * data, guint8 * end) /* Parse a Sequence Extension */ guint8 horiz_size_ext, vert_size_ext; guint8 fps_n_ext, fps_d_ext; - gint i, offset; if (G_UNLIKELY ((end - data) < 6)) /* need at least 10 bytes, minus 4 for the start code 000001b5 */ @@ -182,23 +181,6 @@ mpeg_util_parse_extension_packet (MPEGSeqHdr * hdr, guint8 * data, guint8 * end) hdr->fps_d *= (fps_d_ext + 1); hdr->width += (horiz_size_ext << 12); hdr->height += (vert_size_ext << 12); - - if (read_bits (data + 7, 6, 1)) { - for (i = 0; i < 64; i++) - hdr->intra_quantizer_matrix[mpeg2_scan[i]] = - read_bits (data + 7 + i, 7, 8); - offset = 64; - } else - memcpy (hdr->intra_quantizer_matrix, default_intra_quantizer_matrix, - 64); - - if (read_bits (data + 7 + offset, 7, 1)) { - for (i = 0; i < 64; i++) - hdr->non_intra_quantizer_matrix[mpeg2_scan[i]] = - read_bits (data + 8 + offset + i, 0, 8); - } else - memset (hdr->non_intra_quantizer_matrix, 0, 64); - break; } default: @@ -217,6 +199,7 @@ mpeg_util_parse_sequence_hdr (MPEGSeqHdr * hdr, guint8 * data, guint8 * end) gboolean constrained_flag; gboolean load_intra_flag; gboolean load_non_intra_flag; + gint i; if (G_UNLIKELY ((end - data) < 12)) return FALSE; /* Too small to be a sequence header */ @@ -241,19 +224,29 @@ mpeg_util_parse_sequence_hdr (MPEGSeqHdr * hdr, guint8 * data, guint8 * end) set_fps_from_code (hdr, fps_idx); constrained_flag = (data[7] >> 2) & 0x01; - load_intra_flag = (data[7] >> 1) & 0x01; + + load_intra_flag = read_bits (data + 7, 6, 1); if (load_intra_flag) { if (G_UNLIKELY ((end - data) < 64)) return FALSE; + for (i = 0; i < 64; i++) { + hdr->intra_quantizer_matrix[mpeg2_scan[i]] = + read_bits (data + 7 + i, 7, 8); + } data += 64; - } - load_non_intra_flag = data[7] & 0x01; + } else + memcpy (hdr->intra_quantizer_matrix, default_intra_quantizer_matrix, 64); + + load_non_intra_flag = read_bits (data + 7, 7 + load_intra_flag, 1); if (load_non_intra_flag) { if (G_UNLIKELY ((end - data) < 64)) return FALSE; - data += 64; - } + for (i = 0; i < 64; i++) + hdr->non_intra_quantizer_matrix[mpeg2_scan[i]] = + read_bits (data + 8 + i, 1 + load_intra_flag, 8); + } else + memset (hdr->non_intra_quantizer_matrix, 16, 64); /* Advance past the rest of the MPEG-1 header */ data += 8; @@ -282,14 +275,14 @@ mpeg_util_parse_picture_hdr (MPEGPictureHdr * hdr, guint8 * data, guint8 * end) { guint32 code; - if (G_UNLIKELY ((end - data) < 6)) + if (G_UNLIKELY ((end - data) < 8)) return FALSE; /* Packet too small */ code = GST_READ_UINT32_BE (data); if (G_UNLIKELY (code != (0x00000100 | MPEG_PACKET_PICTURE))) return FALSE; - /* Skip the start code */ + /* Skip the sync word */ data += 4; hdr->pic_type = (data[1] >> 3) & 0x07; @@ -297,7 +290,7 @@ mpeg_util_parse_picture_hdr (MPEGPictureHdr * hdr, guint8 * data, guint8 * end) return FALSE; /* Corrupted picture packet */ if (hdr->pic_type == P_FRAME || hdr->pic_type == B_FRAME) { - if (G_UNLIKELY ((end - data) < 7)) + if (G_UNLIKELY ((end - data) < 5)) return FALSE; /* packet too small */ hdr->full_pel_forward_vector = read_bits (data + 3, 5, 1); @@ -319,12 +312,19 @@ gboolean mpeg_util_parse_picture_coding_extension (MPEGPictureExt * ext, guint8 * data, guint8 * end) { - if (G_UNLIKELY ((end - data) < 7)) + guint32 code; + + if (G_UNLIKELY ((end - data) < 10)) return FALSE; /* Packet too small */ - if (G_UNLIKELY (read_bits (data, 0, 4) != MPEG_PACKET_EXT_PICTURE_CODING)) + code = GST_READ_UINT32_BE (data); + + if (G_UNLIKELY (G_UNLIKELY (code != (0x00000100 | MPEG_PACKET_EXTENSION)))) return FALSE; + /* Skip the sync word */ + data += 4; + ext->f_code[0][0] = read_bits (data, 4, 4); ext->f_code[0][1] = read_bits (data + 1, 0, 4); ext->f_code[1][0] = read_bits (data + 1, 4, 4); @@ -340,3 +340,78 @@ mpeg_util_parse_picture_coding_extension (MPEGPictureExt * ext, guint8 * data, return TRUE; } + +gboolean +mpeg_util_parse_picture_gop (MPEGPictureGOP * gop, guint8 * data, guint8 * end) +{ + guint32 code; + gint hour, minute, second; + + if (G_UNLIKELY ((end - data) < 8)) + return FALSE; /* Packet too small */ + + code = GST_READ_UINT32_BE (data); + + if (G_UNLIKELY (G_UNLIKELY (code != (0x00000100 | MPEG_PACKET_GOP)))) + return FALSE; + + /* Skip the sync word */ + data += 4; + + gop->drop_frame_flag = read_bits (data, 0, 1); + + hour = read_bits (data, 1, 5); + minute = read_bits (data, 6, 6); + second = read_bits (data + 1, 4, 6); + + gop->timestamp = hour * 3600 * GST_SECOND; + gop->timestamp += minute * 60 * GST_SECOND; + gop->timestamp += second * GST_SECOND; + + gop->frame = read_bits (data + 2, 3, 6); + + return TRUE; +} + +gboolean +mpeg_util_parse_quant_matrix (MPEGQuantMatrix * qm, guint8 * data, guint8 * end) +{ + guint32 code; + gboolean load_intra_flag, load_non_intra_flag; + gint i; + + if (G_UNLIKELY ((end - data) < 5)) + return FALSE; /* Packet too small */ + + code = GST_READ_UINT32_BE (data); + + if (G_UNLIKELY (G_UNLIKELY (code != (0x00000100 | MPEG_PACKET_GOP)))) + return FALSE; + + /* Skip the sync word */ + data += 4; + + load_intra_flag = read_bits (data, 0, 1); + if (load_intra_flag) { + if (G_UNLIKELY ((end - data) < 64)) + return FALSE; + for (i = 0; i < 64; i++) { + qm->intra_quantizer_matrix[mpeg2_scan[i]] = read_bits (data + i, 1, 8); + } + data += 64; + + } else + memcpy (qm->intra_quantizer_matrix, default_intra_quantizer_matrix, 64); + + load_non_intra_flag = read_bits (data, 1 + load_intra_flag, 1); + if (load_non_intra_flag) { + if (G_UNLIKELY ((end - data) < 64)) + return FALSE; + for (i = 0; i < 64; i++) + qm->non_intra_quantizer_matrix[mpeg2_scan[i]] = + read_bits (data + i, 2 + load_intra_flag, 8); + } else + memset (qm->non_intra_quantizer_matrix, 16, 64); + + return TRUE; +} diff --git a/sys/vdpau/mpegutil.h b/sys/vdpau/mpegutil.h index 929e4fbb..5fb47290 100644 --- a/sys/vdpau/mpegutil.h +++ b/sys/vdpau/mpegutil.h @@ -26,6 +26,8 @@ typedef struct MPEGSeqHdr MPEGSeqHdr; typedef struct MPEGPictureHdr MPEGPictureHdr; typedef struct MPEGPictureExt MPEGPictureExt; +typedef struct MPEGPictureGOP MPEGPictureGOP; +typedef struct MPEGQuantMatrix MPEGQuantMatrix; /* Packet ID codes for different packet types we * care about */ @@ -90,6 +92,20 @@ struct MPEGPictureExt guint8 intra_vlc_format; }; +struct MPEGPictureGOP +{ + guint8 drop_frame_flag; + guint8 frame; + + GstClockTime timestamp; +}; + +struct MPEGQuantMatrix +{ + guint8 intra_quantizer_matrix[64]; + guint8 non_intra_quantizer_matrix[64]; +}; + gboolean mpeg_util_parse_sequence_hdr (MPEGSeqHdr *hdr, guint8 *data, guint8 *end); @@ -97,4 +113,11 @@ gboolean mpeg_util_parse_picture_hdr (MPEGPictureHdr * hdr, guint8 * data, guint gboolean mpeg_util_parse_picture_coding_extension (MPEGPictureExt *ext, guint8 *data, guint8 *end); +gboolean mpeg_util_parse_picture_gop (MPEGPictureGOP * gop, guint8 * data, guint8 * end); + +gboolean mpeg_util_parse_quant_matrix (MPEGQuantMatrix * qm, guint8 * data, guint8 * end); + +guint8 *mpeg_util_find_start_code (guint32 * sync_word, guint8 * cur, guint8 * end); +guint32 read_bits (guint8 * buf, gint start_bit, gint n_bits); + #endif |