summaryrefslogtreecommitdiffstats
path: root/sys/vdpau/gstvdpaumpegdecoder.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/vdpau/gstvdpaumpegdecoder.c')
-rw-r--r--sys/vdpau/gstvdpaumpegdecoder.c272
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