From 29d0c5bdd8beeb2b1ed25e8bf37eec9a135c5422 Mon Sep 17 00:00:00 2001 From: Carl-Anton Ingmarsson Date: Fri, 27 Mar 2009 16:55:19 +0100 Subject: vdpau: extract mpeg2 profile from codec_data --- sys/vdpau/Makefile.am | 10 +- sys/vdpau/gstvdpaudecoder.c | 4 +- sys/vdpau/gstvdpaumpegdecoder.c | 29 ++++- sys/vdpau/gstvdpaumpegdecoder.h | 4 +- sys/vdpau/mpegutil.c | 227 ++++++++++++++++++++++++++++++++++++++++ sys/vdpau/mpegutil.h | 63 +++++++++++ 6 files changed, 325 insertions(+), 12 deletions(-) create mode 100644 sys/vdpau/mpegutil.c create mode 100644 sys/vdpau/mpegutil.h (limited to 'sys/vdpau') diff --git a/sys/vdpau/Makefile.am b/sys/vdpau/Makefile.am index 94f7efbc..f66c4aa4 100644 --- a/sys/vdpau/Makefile.am +++ b/sys/vdpau/Makefile.am @@ -1,8 +1,9 @@ plugin_LTLIBRARIES = libgstvdpau.la libgstvdpau_la_SOURCES = \ - gstvdpaudecoder.c\ - gstvdpaumpegdecoder.c + gstvdpaudecoder.c \ + gstvdpaumpegdecoder.c \ + mpegutil.c libgstvdpau_la_CFLAGS = $(GST_CFLAGS) $(X11_CFLAGS) -Ivdpau libgstvdpau_la_LIBADD = $(GST_LIBS) $(X11_LIBS) -lvdpau @@ -10,8 +11,9 @@ libgstvdpau_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) libgstvdpau_la_LIBTOOLFLAGS = --tag=disable-static noinst_HEADERS = \ - gstvdpaudecoder.h\ + gstvdpaudecoder.h \ vdpauvariables.h \ - gstvdpaumpegdecoder.h + gstvdpaumpegdecoder.h \ + mpegutil.h diff --git a/sys/vdpau/gstvdpaudecoder.c b/sys/vdpau/gstvdpaudecoder.c index 36a566e0..7d4ecb39 100644 --- a/sys/vdpau/gstvdpaudecoder.c +++ b/sys/vdpau/gstvdpaudecoder.c @@ -302,6 +302,8 @@ gst_vdpaudecoder_sink_set_caps (GstPad * pad, GstCaps * caps) &framerate_numerator, &framerate_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); gst_structure_get_fourcc (structure, "format", &fourcc_format); @@ -318,7 +320,7 @@ gst_vdpaudecoder_sink_set_caps (GstPad * pad, GstCaps * caps) gst_caps_unref (new_caps); - if (!res) + if (G_UNLIKELY (!res)) return FALSE; dec->width = width; diff --git a/sys/vdpau/gstvdpaumpegdecoder.c b/sys/vdpau/gstvdpaumpegdecoder.c index 380cf602..e5da459f 100644 --- a/sys/vdpau/gstvdpaumpegdecoder.c +++ b/sys/vdpau/gstvdpaumpegdecoder.c @@ -1,7 +1,5 @@ /* * GStreamer - * Copyright (C) 2005 Thomas Vander Stichele - * Copyright (C) 2005 Ronald S. Bultje * Copyright (C) 2009 Carl-Anton Ingmarsson * * Permission is hereby granted, free of charge, to any person obtaining a @@ -62,6 +60,7 @@ #include +#include "mpegutil.h" #include "gstvdpaumpegdecoder.h" GST_DEBUG_CATEGORY_STATIC (gst_vdpau_mpeg_decoder_debug); @@ -88,7 +87,7 @@ static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, GST_STATIC_CAPS ("video/mpeg, mpegversion = (int) [ 1, 2 ], " - "systemstream = (boolean) false") + "systemstream = (boolean) false, parsed = (boolean) true") ); GST_BOILERPLATE (GstVdpauMpegDecoder, gst_vdpau_mpeg_decoder, GstVdpauDecoder, @@ -104,11 +103,33 @@ gst_vdpau_mpeg_decoder_set_caps (GstVdpauDecoder * dec, GstCaps * caps) { GstVdpauMpegDecoder *mpeg_dec; GstStructure *structure; + gint version; mpeg_dec = GST_VDPAU_MPEG_DECODER (dec); structure = gst_caps_get_structure (caps, 0); - gst_structure_get_int (structure, "mpegversion", &mpeg_dec->version); + gst_structure_get_int (structure, "mpegversion", &version); + if (version == 1) + mpeg_dec->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)); + switch (hdr.profile) { + case 5: + mpeg_dec->profile = VDP_DECODER_PROFILE_MPEG2_SIMPLE; + break; + default: + mpeg_dec->profile = VDP_DECODER_PROFILE_MPEG2_MAIN; + break; + } + } return TRUE; } diff --git a/sys/vdpau/gstvdpaumpegdecoder.h b/sys/vdpau/gstvdpaumpegdecoder.h index 97462942..830cc671 100644 --- a/sys/vdpau/gstvdpaumpegdecoder.h +++ b/sys/vdpau/gstvdpaumpegdecoder.h @@ -1,7 +1,5 @@ /* * GStreamer - * Copyright (C) 2005 Thomas Vander Stichele - * Copyright (C) 2005 Ronald S. Bultje * Copyright (C) 2009 Carl-Anton Ingmarsson * * Permission is hereby granted, free of charge, to any person obtaining a @@ -68,7 +66,7 @@ struct _GstVdpauMpegDecoder gboolean silent; - gint version; + VdpDecoderProfile profile; }; struct _GstVdpauMpegDecoderClass diff --git a/sys/vdpau/mpegutil.c b/sys/vdpau/mpegutil.c new file mode 100644 index 00000000..274fa853 --- /dev/null +++ b/sys/vdpau/mpegutil.c @@ -0,0 +1,227 @@ +/* GStreamer + * Copyright (C) 2007 Jan Schmidt + * Copyright (C) 2009 Carl-Anton Ingmarsson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "mpegutil.h" + +guint8 bits[] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; + +guint32 +read_bits (guint8 * buf, gint start_bit, gint n_bits) +{ + gint i; + guint32 ret = 0x00; + + buf += start_bit / 8; + start_bit %= 8; + + for (i = 0; i < n_bits; i++) { + guint32 tmp; + + tmp = ((*buf & bits[start_bit]) >> (7 - start_bit)); + ret = (ret | (tmp << (n_bits - i - 1))); + if (++start_bit == 8) { + buf += 1; + start_bit = 0; + } + } + + return ret; +} + +guint8 * +mpeg_util_find_start_code (guint32 * sync_word, guint8 * cur, guint8 * end) +{ + guint32 code; + + if (G_UNLIKELY (cur == NULL)) + return NULL; + + code = *sync_word; + + while (cur < end) { + code <<= 8; + + if (code == 0x00000100) { + /* Reset the sync word accumulator */ + *sync_word = 0xffffffff; + return cur; + } + + /* Add the next available byte to the collected sync word */ + code |= *cur++; + } + + *sync_word = code; + return NULL; +} + +static void +set_fps_from_code (MPEGSeqHdr * hdr, guint8 fps_code) +{ + const gint framerates[][2] = { + {30, 1}, {24000, 1001}, {24, 1}, {25, 1}, + {30000, 1001}, {30, 1}, {50, 1}, {60000, 1001}, + {60, 1}, {30, 1} + }; + + if (fps_code < 10) { + hdr->fps_n = framerates[fps_code][0]; + hdr->fps_d = framerates[fps_code][1]; + } else { + /* Force a valid framerate */ + hdr->fps_n = 30000; + hdr->fps_d = 1001; + } +} + +/* Set the Pixel Aspect Ratio in our hdr from a DAR code in the data */ +static void +set_par_from_dar (MPEGSeqHdr * hdr, guint8 asr_code) +{ + /* Pixel_width = DAR_width * display_vertical_size */ + /* Pixel_height = DAR_height * display_horizontal_size */ + switch (asr_code) { + case 0x02: /* 3:4 DAR = 4:3 pixels */ + hdr->par_w = 4 * hdr->height; + hdr->par_h = 3 * hdr->width; + break; + case 0x03: /* 9:16 DAR */ + hdr->par_w = 16 * hdr->height; + hdr->par_h = 9 * hdr->width; + break; + case 0x04: /* 1:2.21 DAR */ + hdr->par_w = 221 * hdr->height; + hdr->par_h = 100 * hdr->width; + break; + case 0x01: /* Square pixels */ + default: + hdr->par_w = hdr->par_h = 1; + break; + } +} + +static gboolean +mpeg_util_parse_extension_packet (MPEGSeqHdr * hdr, guint8 * data, guint8 * end) +{ + guint8 ext_code; + + if (G_UNLIKELY (data >= end)) + return FALSE; /* short extension packet */ + + ext_code = data[0] >> 4; + + switch (ext_code) { + case MPEG_PACKET_EXT_SEQUENCE: + { + /* Parse a Sequence Extension */ + guint8 horiz_size_ext, vert_size_ext; + guint8 fps_n_ext, fps_d_ext; + + if (G_UNLIKELY ((end - data) < 6)) + /* need at least 10 bytes, minus 4 for the start code 000001b5 */ + return FALSE; + + horiz_size_ext = ((data[1] << 1) & 0x02) | ((data[2] >> 7) & 0x01); + vert_size_ext = (data[2] >> 5) & 0x03; + hdr->profile = read_bits (data, 7, 3); + fps_n_ext = (data[5] >> 5) & 0x03; + fps_d_ext = data[5] & 0x1f; + + hdr->fps_n *= (fps_n_ext + 1); + hdr->fps_d *= (fps_d_ext + 1); + hdr->width += (horiz_size_ext << 12); + hdr->height += (vert_size_ext << 12); + break; + } + default: + break; + } + + return TRUE; +} + +gboolean +mpeg_util_parse_sequence_hdr (MPEGSeqHdr * hdr, guint8 * data, guint8 * end) +{ + guint32 code; + guint8 dar_idx, fps_idx; + guint32 sync_word = 0xffffffff; + gboolean constrained_flag; + gboolean load_intra_flag; + gboolean load_non_intra_flag; + + if (G_UNLIKELY ((end - data) < 12)) + return FALSE; /* Too small to be a sequence header */ + + code = GST_READ_UINT32_BE (data); + if (G_UNLIKELY (code != (0x00000100 | MPEG_PACKET_SEQUENCE))) + return FALSE; + + /* Skip the sync word */ + data += 4; + + /* Parse the MPEG 1 bits */ + hdr->mpeg_version = 1; + + code = GST_READ_UINT32_BE (data); + hdr->width = (code >> 20) & 0xfff; + hdr->height = (code >> 8) & 0xfff; + + dar_idx = (code >> 4) & 0xf; + set_par_from_dar (hdr, dar_idx); + fps_idx = code & 0xf; + set_fps_from_code (hdr, fps_idx); + + constrained_flag = (data[7] >> 2) & 0x01; + load_intra_flag = (data[7] >> 1) & 0x01; + if (load_intra_flag) { + if (G_UNLIKELY ((end - data) < 64)) + return FALSE; + data += 64; + } + + load_non_intra_flag = data[7] & 0x01; + if (load_non_intra_flag) { + if (G_UNLIKELY ((end - data) < 64)) + return FALSE; + data += 64; + } + + /* Advance past the rest of the MPEG-1 header */ + data += 8; + + /* Read MPEG-2 sequence extensions */ + data = mpeg_util_find_start_code (&sync_word, data, end); + while (data != NULL) { + if (G_UNLIKELY (data >= end)) + return FALSE; + + /* data points at the last byte of the start code */ + if (data[0] == MPEG_PACKET_EXTENSION) { + if (!mpeg_util_parse_extension_packet (hdr, data + 1, end)) + return FALSE; + + hdr->mpeg_version = 2; + } + data = mpeg_util_find_start_code (&sync_word, data, end); + } + + return TRUE; +} diff --git a/sys/vdpau/mpegutil.h b/sys/vdpau/mpegutil.h new file mode 100644 index 00000000..f0f8aca0 --- /dev/null +++ b/sys/vdpau/mpegutil.h @@ -0,0 +1,63 @@ +/* GStreamer + * Copyright (C) 2007 Jan Schmidt + * Copyright (C) 2009 Carl-Anton Ingmarsson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __MPEGUTIL_H__ +#define __MPEGUTIL_H__ + +#include + +typedef struct MPEGSeqHdr MPEGSeqHdr; + +/* Packet ID codes for different packet types we + * care about */ +#define MPEG_PACKET_PICTURE 0x00 +#define MPEG_PACKET_SLICE_MIN 0x01 +#define MPEG_PACKET_SLICE_MAX 0xaf +#define MPEG_PACKET_SEQUENCE 0xb3 +#define MPEG_PACKET_EXTENSION 0xb5 +#define MPEG_PACKET_SEQUENCE_END 0xb7 +#define MPEG_PACKET_GOP 0xb8 +#define MPEG_PACKET_NONE 0xff + +/* Extension codes we care about */ +#define MPEG_PACKET_EXT_SEQUENCE 0x01 +#define MPEG_PACKET_EXT_SEQUENCE_DISPLAY 0x02 +#define MPEG_PACKET_EXT_QUANT_MATRIX 0x03 + +struct MPEGSeqHdr +{ + /* 0 for unknown, else 1 or 2 */ + guint8 mpeg_version; + + /* Pixel-Aspect Ratio from DAR code via set_par_from_dar */ + gint par_w, par_h; + /* Width and Height of the video */ + gint width, height; + /* Framerate */ + gint fps_n, fps_d; + + /* mpeg2 decoder profile */ + gint profile; +}; + +gboolean mpeg_util_parse_sequence_hdr (MPEGSeqHdr *hdr, + guint8 *data, guint8 *end); + +#endif -- cgit v1.2.1