From e0ddcabd7ab63c8060b7259e4075a0e88e5bcf66 Mon Sep 17 00:00:00 2001 From: Carl-Anton Ingmarsson Date: Thu, 16 Apr 2009 23:43:24 +0200 Subject: vdpaumpegdec: handle multiple B_FRAMEs in a row --- sys/vdpau/gstvdpmpegdecoder.c | 81 ++++++++++++++++++++++++++----------------- sys/vdpau/gstvdpmpegdecoder.h | 3 +- sys/vdpau/mpegutil.c | 5 +-- 3 files changed, 51 insertions(+), 38 deletions(-) diff --git a/sys/vdpau/gstvdpmpegdecoder.c b/sys/vdpau/gstvdpmpegdecoder.c index 7c134afa..c40aee81 100644 --- a/sys/vdpau/gstvdpmpegdecoder.c +++ b/sys/vdpau/gstvdpmpegdecoder.c @@ -131,6 +131,12 @@ gst_vdp_mpeg_decoder_set_caps (GstVdpDecoder * dec, GstCaps * caps) return TRUE; } +typedef struct +{ + GstBuffer *buffer; + VdpPictureInfoMPEG1Or2 vdp_info; +} GstVdpBFrame; + static GstFlowReturn gst_vdp_mpeg_decoder_decode (GstVdpMpegDecoder * mpeg_dec) { @@ -150,13 +156,17 @@ gst_vdp_mpeg_decoder_decode (GstVdpMpegDecoder * mpeg_dec) /* if the frame is a B_FRAME we store it for future decoding */ if (mpeg_dec->vdp_info.picture_coding_type == B_FRAME) { - mpeg_dec->b_buffer = buffer; - memcpy (&mpeg_dec->b_vdp_info, &mpeg_dec->vdp_info, + GstVdpBFrame *b_frame; + + b_frame = g_slice_new (GstVdpBFrame); + + b_frame->buffer = buffer; + memcpy (&b_frame->vdp_info, &mpeg_dec->vdp_info, sizeof (VdpPictureInfoMPEG1Or2)); - /* unset forward_reference since next frame must be an I_FRAME */ - mpeg_dec->vdp_info.forward_reference = VDP_INVALID_HANDLE; + mpeg_dec->b_frames = g_slist_append (mpeg_dec->b_frames, b_frame); + gst_buffer_ref (mpeg_dec->f_buffer); mpeg_dec->vdp_info.slice_count = 0; return GST_FLOW_OK; @@ -188,35 +198,43 @@ gst_vdp_mpeg_decoder_decode (GstVdpMpegDecoder * mpeg_dec) return GST_FLOW_ERROR; } - /* if we have stored away a B_FRAME we can now decode it */ - if (mpeg_dec->b_buffer) { - GstVdpVideoBuffer *b_outbuf; - - b_outbuf = gst_vdp_video_buffer_new (dec->device, VDP_CHROMA_TYPE_420, - dec->width, dec->height); - mpeg_dec->b_vdp_info.backward_reference = - mpeg_dec->b_vdp_info.forward_reference; - mpeg_dec->b_vdp_info.forward_reference = surface; - vbit[0].struct_version = VDP_BITSTREAM_BUFFER_VERSION; - vbit[0].bitstream = GST_BUFFER_DATA (mpeg_dec->b_buffer); - vbit[0].bitstream_bytes = GST_BUFFER_SIZE (mpeg_dec->b_buffer); - - status = device->vdp_decoder_render (mpeg_dec->decoder, b_outbuf->surface, - (VdpPictureInfo *) & mpeg_dec->b_vdp_info, 1, vbit); - gst_buffer_unref (mpeg_dec->b_buffer); - mpeg_dec->b_buffer = NULL; - - if (status != VDP_STATUS_OK) { - GST_ELEMENT_ERROR (mpeg_dec, RESOURCE, READ, - ("Could not decode B_FRAME"), - ("Error returned from vdpau was: %s", - device->vdp_get_error_string (status))); - } + /* if we have stored away some B_FRAMEs we can now decode them */ + if (mpeg_dec->b_frames) { + GSList *iter; + + for (iter = mpeg_dec->b_frames; iter; iter = g_slist_next (iter)) { + GstVdpBFrame *b_frame; + GstVdpVideoBuffer *b_outbuf; - gst_vdp_decoder_push_video_buffer (GST_VDPAU_DECODER (mpeg_dec), b_outbuf); + b_frame = (GstVdpBFrame *) iter->data; + + b_outbuf = gst_vdp_video_buffer_new (dec->device, VDP_CHROMA_TYPE_420, + dec->width, dec->height); + + b_frame->vdp_info.forward_reference = surface; + vbit[0].struct_version = VDP_BITSTREAM_BUFFER_VERSION; + vbit[0].bitstream = GST_BUFFER_DATA (b_frame->buffer); + vbit[0].bitstream_bytes = GST_BUFFER_SIZE (b_frame->buffer); + + status = device->vdp_decoder_render (mpeg_dec->decoder, b_outbuf->surface, + (VdpPictureInfo *) & b_frame->vdp_info, 1, vbit); + gst_buffer_unref (b_frame->buffer); + g_slice_free (GstVdpBFrame, b_frame); + + if (status != VDP_STATUS_OK) { + GST_ELEMENT_ERROR (mpeg_dec, RESOURCE, READ, + ("Could not decode B_FRAME"), + ("Error returned from vdpau was: %s", + device->vdp_get_error_string (status))); + } + + gst_vdp_decoder_push_video_buffer (GST_VDPAU_DECODER (mpeg_dec), + b_outbuf); - if (mpeg_dec->b_vdp_info.forward_reference != VDP_INVALID_HANDLE) gst_buffer_unref (mpeg_dec->f_buffer); + } + g_slist_free (mpeg_dec->b_frames); + mpeg_dec->b_frames = NULL; } gst_buffer_ref (GST_BUFFER (outbuf)); @@ -295,7 +313,6 @@ gst_vdp_mpeg_decoder_parse_picture (GstVdpMpegDecoder * mpeg_dec, 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) { gst_buffer_unref (mpeg_dec->f_buffer); @@ -481,7 +498,7 @@ gst_vdp_mpeg_decoder_init (GstVdpMpegDecoder * mpeg_dec, mpeg_dec->decoder = VDP_INVALID_HANDLE; gst_vdp_mpeg_decoder_init_info (&mpeg_dec->vdp_info); - mpeg_dec->b_buffer = NULL; + mpeg_dec->b_frames = NULL; mpeg_dec->adapter = gst_adapter_new (); diff --git a/sys/vdpau/gstvdpmpegdecoder.h b/sys/vdpau/gstvdpmpegdecoder.h index 3761cff6..a03c17c2 100644 --- a/sys/vdpau/gstvdpmpegdecoder.h +++ b/sys/vdpau/gstvdpmpegdecoder.h @@ -48,8 +48,7 @@ struct _GstVdpMpegDecoder GstBuffer *f_buffer; /* holds B_FRAMES */ - GstBuffer *b_buffer; - VdpPictureInfoMPEG1Or2 b_vdp_info; + GSList *b_frames; GstAdapter *adapter; }; diff --git a/sys/vdpau/mpegutil.c b/sys/vdpau/mpegutil.c index 929df4ab..4586cd7d 100644 --- a/sys/vdpau/mpegutil.c +++ b/sys/vdpau/mpegutil.c @@ -285,14 +285,11 @@ mpeg_util_parse_picture_hdr (MPEGPictureHdr * hdr, guint8 * data, guint8 * end) /* Skip the sync word */ data += 4; - hdr->pic_type = (data[1] >> 3) & 0x07; + hdr->pic_type = read_bits (data + 1, 2, 3); if (hdr->pic_type == 0 || hdr->pic_type > 4) return FALSE; /* Corrupted picture packet */ if (hdr->pic_type == P_FRAME || hdr->pic_type == B_FRAME) { - if (G_UNLIKELY ((end - data) < 5)) - return FALSE; /* packet too small */ - hdr->full_pel_forward_vector = read_bits (data + 3, 5, 1); hdr->f_code[0][0] = hdr->f_code[0][1] = read_bits (data + 3, 6, 3); -- cgit v1.2.1