vdpaumpegdec: use GstBitReader to parse bitstream

This commit is contained in:
Carl-Anton Ingmarsson 2009-06-04 18:11:06 +02:00 committed by Jan Schmidt
parent 426a6eaba9
commit 127765d19c
3 changed files with 413 additions and 301 deletions

View file

@ -36,6 +36,8 @@
#endif #endif
#include <gst/gst.h> #include <gst/gst.h>
#include <gst/base/gstbytereader.h>
#include <gst/base/gstbitreader.h>
#include <string.h> #include <string.h>
#include "mpegutil.h" #include "mpegutil.h"
@ -80,14 +82,82 @@ static void gst_vdp_mpeg_decoder_set_property (GObject * object,
static void gst_vdp_mpeg_decoder_get_property (GObject * object, static void gst_vdp_mpeg_decoder_get_property (GObject * object,
guint prop_id, GValue * value, GParamSpec * pspec); guint prop_id, GValue * value, GParamSpec * pspec);
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;
}
typedef struct
{
GstBuffer *buffer;
guint8 *cur;
guint8 *end;
} GstVdpMpegPacketizer;
static GstBuffer *
gst_vdp_mpeg_packetizer_get_next_packet (GstVdpMpegPacketizer * packetizer)
{
guint32 sync_word = 0xffffff;
guint8 *packet_start;
guint8 *packet_end;
if (!packetizer->cur)
return NULL;
packet_start = packetizer->cur - 3;
packetizer->cur = packet_end = mpeg_util_find_start_code (&sync_word,
packetizer->cur, packetizer->end);
if (packet_end)
packet_end -= 3;
else
packet_end = packetizer->end;
return gst_buffer_create_sub (packetizer->buffer,
packet_start - GST_BUFFER_DATA (packetizer->buffer),
packet_end - packet_start);
}
static void
gst_vdp_mpeg_packetizer_init (GstVdpMpegPacketizer * packetizer,
GstBuffer * buffer)
{
guint32 sync_word = 0xffffffff;
packetizer->buffer = buffer;
packetizer->end = GST_BUFFER_DATA (buffer) + GST_BUFFER_SIZE (buffer);
packetizer->cur = mpeg_util_find_start_code (&sync_word,
GST_BUFFER_DATA (buffer), packetizer->end);
}
static gboolean static gboolean
gst_vdp_mpeg_decoder_set_caps (GstVdpDecoder * dec, GstCaps * caps) gst_vdp_mpeg_decoder_set_caps (GstVdpDecoder * dec, GstCaps * caps)
{ {
GstVdpMpegDecoder *mpeg_dec; GstVdpMpegDecoder *mpeg_dec;
GstStructure *structure; GstStructure *structure;
const GValue *value; const GValue *value;
GstBuffer *codec_data;
MPEGSeqHdr hdr = { 0, };
VdpDecoderProfile profile; VdpDecoderProfile profile;
GstVdpDevice *device; GstVdpDevice *device;
VdpStatus status; VdpStatus status;
@ -100,11 +170,30 @@ gst_vdp_mpeg_decoder_set_caps (GstVdpDecoder * dec, GstCaps * caps)
profile = VDP_DECODER_PROFILE_MPEG1; profile = VDP_DECODER_PROFILE_MPEG1;
value = gst_structure_get_value (structure, "codec_data"); value = gst_structure_get_value (structure, "codec_data");
if (value) {
GstBuffer *codec_data, *buf;
GstVdpMpegPacketizer packetizer;
codec_data = gst_value_get_buffer (value); codec_data = gst_value_get_buffer (value);
mpeg_util_parse_sequence_hdr (&hdr, GST_BUFFER_DATA (codec_data), gst_vdp_mpeg_packetizer_init (&packetizer, codec_data);
GST_BUFFER_DATA (codec_data) + GST_BUFFER_SIZE (codec_data)); if ((buf = gst_vdp_mpeg_packetizer_get_next_packet (&packetizer))) {
MPEGSeqHdr hdr;
mpeg_util_parse_sequence_hdr (&hdr, buf);
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);
gst_buffer_unref (buf);
if ((buf = gst_vdp_mpeg_packetizer_get_next_packet (&packetizer))) {
MPEGSeqExtHdr ext;
mpeg_util_parse_sequence_extension (&ext, buf);
if (mpeg_dec->version != 1) { if (mpeg_dec->version != 1) {
switch (hdr.profile) { switch (ext.profile) {
case 5: case 5:
profile = VDP_DECODER_PROFILE_MPEG2_SIMPLE; profile = VDP_DECODER_PROFILE_MPEG2_SIMPLE;
break; break;
@ -114,10 +203,10 @@ gst_vdp_mpeg_decoder_set_caps (GstVdpDecoder * dec, GstCaps * caps)
} }
} }
memcpy (&mpeg_dec->vdp_info.intra_quantizer_matrix, gst_buffer_unref (buf);
&hdr.intra_quantizer_matrix, 64); }
memcpy (&mpeg_dec->vdp_info.non_intra_quantizer_matrix, }
&hdr.non_intra_quantizer_matrix, 64); }
device = dec->device; device = dec->device;
@ -224,7 +313,7 @@ gst_vdp_mpeg_decoder_decode (GstVdpMpegDecoder * mpeg_dec,
static gboolean static gboolean
gst_vdp_mpeg_decoder_parse_picture_coding (GstVdpMpegDecoder * mpeg_dec, gst_vdp_mpeg_decoder_parse_picture_coding (GstVdpMpegDecoder * mpeg_dec,
guint8 * data, guint8 * end) GstBuffer * buffer)
{ {
GstVdpDecoder *dec; GstVdpDecoder *dec;
MPEGPictureExt pic_ext; MPEGPictureExt pic_ext;
@ -233,7 +322,7 @@ gst_vdp_mpeg_decoder_parse_picture_coding (GstVdpMpegDecoder * mpeg_dec,
dec = GST_VDP_DECODER (mpeg_dec); dec = GST_VDP_DECODER (mpeg_dec);
info = &mpeg_dec->vdp_info; info = &mpeg_dec->vdp_info;
if (!mpeg_util_parse_picture_coding_extension (&pic_ext, data, end)) if (!mpeg_util_parse_picture_coding_extension (&pic_ext, buffer))
return FALSE; return FALSE;
memcpy (&mpeg_dec->vdp_info.f_code, &pic_ext.f_code, 4); memcpy (&mpeg_dec->vdp_info.f_code, &pic_ext.f_code, 4);
@ -252,16 +341,17 @@ gst_vdp_mpeg_decoder_parse_picture_coding (GstVdpMpegDecoder * mpeg_dec,
static gboolean static gboolean
gst_vdp_mpeg_decoder_parse_sequence (GstVdpMpegDecoder * mpeg_dec, gst_vdp_mpeg_decoder_parse_sequence (GstVdpMpegDecoder * mpeg_dec,
guint8 * data, guint8 * end) GstBuffer * buffer)
{ {
GstVdpDecoder *dec; GstVdpDecoder *dec;
MPEGSeqHdr hdr; MPEGSeqHdr hdr;
dec = GST_VDP_DECODER (mpeg_dec); dec = GST_VDP_DECODER (mpeg_dec);
if (!mpeg_util_parse_sequence_hdr (&hdr, data, end)) if (!mpeg_util_parse_sequence_hdr (&hdr, buffer))
return FALSE; return FALSE;
g_debug ("här");
memcpy (&mpeg_dec->vdp_info.intra_quantizer_matrix, memcpy (&mpeg_dec->vdp_info.intra_quantizer_matrix,
&hdr.intra_quantizer_matrix, 64); &hdr.intra_quantizer_matrix, 64);
memcpy (&mpeg_dec->vdp_info.non_intra_quantizer_matrix, memcpy (&mpeg_dec->vdp_info.non_intra_quantizer_matrix,
@ -272,14 +362,14 @@ gst_vdp_mpeg_decoder_parse_sequence (GstVdpMpegDecoder * mpeg_dec,
static gboolean static gboolean
gst_vdp_mpeg_decoder_parse_picture (GstVdpMpegDecoder * mpeg_dec, gst_vdp_mpeg_decoder_parse_picture (GstVdpMpegDecoder * mpeg_dec,
guint8 * data, guint8 * end) GstBuffer * buffer)
{ {
GstVdpDecoder *dec; GstVdpDecoder *dec;
MPEGPictureHdr pic_hdr; MPEGPictureHdr pic_hdr;
dec = GST_VDP_DECODER (mpeg_dec); dec = GST_VDP_DECODER (mpeg_dec);
if (!mpeg_util_parse_picture_hdr (&pic_hdr, data, end)) if (!mpeg_util_parse_picture_hdr (&pic_hdr, buffer))
return FALSE; return FALSE;
if (pic_hdr.pic_type != I_FRAME if (pic_hdr.pic_type != I_FRAME
@ -309,12 +399,12 @@ gst_vdp_mpeg_decoder_parse_picture (GstVdpMpegDecoder * mpeg_dec,
} }
static gboolean static gboolean
gst_vdp_mpeg_decoder_parse_gop (GstVdpMpegDecoder * mpeg_dec, guint8 * data, gst_vdp_mpeg_decoder_parse_gop (GstVdpMpegDecoder * mpeg_dec,
guint8 * end) GstBuffer * buffer)
{ {
MPEGPictureGOP gop; MPEGGop gop;
if (!mpeg_util_parse_picture_gop (&gop, data, end)) if (!mpeg_util_parse_gop (&gop, buffer))
return FALSE; return FALSE;
mpeg_dec->broken_gop = gop.broken_gop; mpeg_dec->broken_gop = gop.broken_gop;
@ -324,11 +414,11 @@ gst_vdp_mpeg_decoder_parse_gop (GstVdpMpegDecoder * mpeg_dec, guint8 * data,
static gboolean static gboolean
gst_vdp_mpeg_decoder_parse_quant_matrix (GstVdpMpegDecoder * mpeg_dec, gst_vdp_mpeg_decoder_parse_quant_matrix (GstVdpMpegDecoder * mpeg_dec,
guint8 * data, guint8 * end) GstBuffer * buffer)
{ {
MPEGQuantMatrix qm; MPEGQuantMatrix qm;
if (!mpeg_util_parse_quant_matrix (&qm, data, end)) if (!mpeg_util_parse_quant_matrix (&qm, buffer))
return FALSE; return FALSE;
memcpy (&mpeg_dec->vdp_info.intra_quantizer_matrix, memcpy (&mpeg_dec->vdp_info.intra_quantizer_matrix,
@ -355,8 +445,8 @@ static GstFlowReturn
gst_vdp_mpeg_decoder_chain (GstPad * pad, GstBuffer * buffer) gst_vdp_mpeg_decoder_chain (GstPad * pad, GstBuffer * buffer)
{ {
GstVdpMpegDecoder *mpeg_dec; GstVdpMpegDecoder *mpeg_dec;
guint8 *data, *end; GstVdpMpegPacketizer packetizer;
guint32 sync_word = 0xffffffff; GstBuffer *buf;
GstFlowReturn ret = GST_FLOW_OK; GstFlowReturn ret = GST_FLOW_OK;
mpeg_dec = GST_VDP_MPEG_DECODER (GST_OBJECT_PARENT (pad)); mpeg_dec = GST_VDP_MPEG_DECODER (GST_OBJECT_PARENT (pad));
@ -367,69 +457,70 @@ gst_vdp_mpeg_decoder_chain (GstPad * pad, GstBuffer * buffer)
return GST_FLOW_OK; return GST_FLOW_OK;
} }
data = GST_BUFFER_DATA (buffer); gst_vdp_mpeg_packetizer_init (&packetizer, buffer);
end = GST_BUFFER_DATA (buffer) + GST_BUFFER_SIZE (buffer); while ((buf = gst_vdp_mpeg_packetizer_get_next_packet (&packetizer))) {
GstBitReader b_reader = GST_BIT_READER_INIT_FROM_BUFFER (buf);
guint32 sync_code;
guint8 start_code;
while ((data = mpeg_util_find_start_code (&sync_word, data, end))) { /* skip sync_code */
guint8 *packet_start; gst_bit_reader_get_bits_uint32 (&b_reader, &sync_code, 8 * 3);
guint8 *packet_end;
packet_start = data - 3; /* start_code */
packet_end = mpeg_util_find_start_code (&sync_word, data, end); gst_bit_reader_get_bits_uint8 (&b_reader, &start_code, 8);
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;
if (start_code >= MPEG_PACKET_SLICE_MIN
&& start_code <= MPEG_PACKET_SLICE_MAX) {
GST_DEBUG_OBJECT (mpeg_dec, "MPEG_PACKET_SLICE"); GST_DEBUG_OBJECT (mpeg_dec, "MPEG_PACKET_SLICE");
subbuf =
gst_buffer_create_sub (buffer, gst_buffer_ref (buf);
packet_start - GST_BUFFER_DATA (buffer), packet_end - packet_start); gst_adapter_push (mpeg_dec->adapter, buf);
gst_adapter_push (mpeg_dec->adapter, subbuf);
mpeg_dec->vdp_info.slice_count++; mpeg_dec->vdp_info.slice_count++;
} }
switch (data[0]) { switch (start_code) {
case MPEG_PACKET_PICTURE: case MPEG_PACKET_PICTURE:
GST_DEBUG_OBJECT (mpeg_dec, "MPEG_PACKET_PICTURE"); GST_DEBUG_OBJECT (mpeg_dec, "MPEG_PACKET_PICTURE");
if (!gst_vdp_mpeg_decoder_parse_picture (mpeg_dec, packet_start, if (!gst_vdp_mpeg_decoder_parse_picture (mpeg_dec, buf)) {
packet_end)) {
return GST_FLOW_OK; return GST_FLOW_OK;
} }
break; break;
case MPEG_PACKET_SEQUENCE: case MPEG_PACKET_SEQUENCE:
GST_DEBUG_OBJECT (mpeg_dec, "MPEG_PACKET_SEQUENCE"); GST_DEBUG_OBJECT (mpeg_dec, "MPEG_PACKET_SEQUENCE");
gst_vdp_mpeg_decoder_parse_sequence (mpeg_dec, packet_start, gst_vdp_mpeg_decoder_parse_sequence (mpeg_dec, buf);
packet_end);
break; break;
case MPEG_PACKET_EXTENSION: case MPEG_PACKET_EXTENSION:
{
guint8 ext_code;
GST_DEBUG_OBJECT (mpeg_dec, "MPEG_PACKET_EXTENSION"); GST_DEBUG_OBJECT (mpeg_dec, "MPEG_PACKET_EXTENSION");
switch (read_bits (data + 1, 0, 4)) {
/* ext_code */
gst_bit_reader_get_bits_uint8 (&b_reader, &ext_code, 4);
switch (ext_code) {
case MPEG_PACKET_EXT_PICTURE_CODING: case MPEG_PACKET_EXT_PICTURE_CODING:
GST_DEBUG_OBJECT (mpeg_dec, "MPEG_PACKET_EXT_PICTURE_CODING"); GST_DEBUG_OBJECT (mpeg_dec, "MPEG_PACKET_EXT_PICTURE_CODING");
gst_vdp_mpeg_decoder_parse_picture_coding (mpeg_dec, packet_start, gst_vdp_mpeg_decoder_parse_picture_coding (mpeg_dec, buf);
packet_end);
break; break;
case MPEG_PACKET_EXT_QUANT_MATRIX: case MPEG_PACKET_EXT_QUANT_MATRIX:
GST_DEBUG_OBJECT (mpeg_dec, "MPEG_PACKET_EXT_QUANT_MATRIX"); GST_DEBUG_OBJECT (mpeg_dec, "MPEG_PACKET_EXT_QUANT_MATRIX");
gst_vdp_mpeg_decoder_parse_quant_matrix (mpeg_dec, packet_start, gst_vdp_mpeg_decoder_parse_quant_matrix (mpeg_dec, buf);
packet_end);
break; break;
default: default:
break; break;
} }
break; break;
}
case MPEG_PACKET_GOP: case MPEG_PACKET_GOP:
GST_DEBUG_OBJECT (mpeg_dec, "MPEG_PACKET_GOP"); GST_DEBUG_OBJECT (mpeg_dec, "MPEG_PACKET_GOP");
gst_vdp_mpeg_decoder_parse_gop (mpeg_dec, packet_start, packet_end); gst_vdp_mpeg_decoder_parse_gop (mpeg_dec, buf);
break; break;
default: default:
break; break;
} }
gst_buffer_unref (buf);
} }
if (mpeg_dec->vdp_info.slice_count > 0) if (mpeg_dec->vdp_info.slice_count > 0)

View file

@ -18,6 +18,7 @@
* Boston, MA 02111-1307, USA. * Boston, MA 02111-1307, USA.
*/ */
#include <gst/base/gstbitreader.h>
#include <string.h> #include <string.h>
#include "mpegutil.h" #include "mpegutil.h"
@ -53,58 +54,6 @@ guint8 mpeg2_scan[64] = {
53, 60, 61, 54, 47, 55, 62, 63 53, 60, 61, 54, 47, 55, 62, 63
}; };
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 static void
set_fps_from_code (MPEGSeqHdr * hdr, guint8 fps_code) set_fps_from_code (MPEGSeqHdr * hdr, guint8 fps_code)
{ {
@ -150,157 +99,169 @@ set_par_from_dar (MPEGSeqHdr * hdr, guint8 asr_code)
} }
} }
static gboolean gboolean
mpeg_util_parse_extension_packet (MPEGSeqHdr * hdr, guint8 * data, guint8 * end) mpeg_util_parse_sequence_extension (MPEGSeqExtHdr * hdr, GstBuffer * buffer)
{ {
guint8 ext_code; GstBitReader reader = GST_BIT_READER_INIT_FROM_BUFFER (buffer);;
if (G_UNLIKELY (data >= end)) /* skip sync word */
return FALSE; /* short extension packet */ if (!gst_bit_reader_skip (&reader, 8 * 4))
ext_code = read_bits (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; return FALSE;
hdr->profile = read_bits (data, 7, 3); /* skip extension code */
if (!gst_bit_reader_skip (&reader, 4))
return FALSE;
horiz_size_ext = read_bits (data + 1, 7, 2); /* skip profile and level escape bit */
vert_size_ext = read_bits (data + 2, 1, 2); if (!gst_bit_reader_skip (&reader, 1))
return FALSE;
fps_n_ext = read_bits (data + 5, 1, 2); if (!gst_bit_reader_get_bits_uint8 (&reader, &hdr->profile, 3))
fps_d_ext = read_bits (data + 5, 3, 5); return FALSE;
if (!gst_bit_reader_get_bits_uint8 (&reader, &hdr->level, 4))
return FALSE;
hdr->fps_n *= (fps_n_ext + 1); /* progressive */
hdr->fps_d *= (fps_d_ext + 1); if (!gst_bit_reader_get_bits_uint8 (&reader, &hdr->progressive, 1))
hdr->width += (horiz_size_ext << 12); return FALSE;
hdr->height += (vert_size_ext << 12);
break; /* chroma format */
} if (!gst_bit_reader_get_bits_uint8 (&reader, &hdr->chroma_format, 2))
default: return FALSE;
break;
} /* resolution extension */
if (!gst_bit_reader_get_bits_uint8 (&reader, &hdr->horiz_size_ext, 2))
return FALSE;
if (!gst_bit_reader_get_bits_uint8 (&reader, &hdr->vert_size_ext, 2))
return FALSE;
/* skip to framerate extension */
if (!gst_bit_reader_skip (&reader, 22))
return FALSE;
/* framerate extension */
if (!gst_bit_reader_get_bits_uint8 (&reader, &hdr->fps_n_ext, 2))
return FALSE;
if (!gst_bit_reader_get_bits_uint8 (&reader, &hdr->fps_d_ext, 2))
return FALSE;
return TRUE; return TRUE;
} }
gboolean gboolean
mpeg_util_parse_sequence_hdr (MPEGSeqHdr * hdr, guint8 * data, guint8 * end) mpeg_util_parse_sequence_hdr (MPEGSeqHdr * hdr, GstBuffer * buffer)
{ {
guint32 code; GstBitReader reader = GST_BIT_READER_INIT_FROM_BUFFER (buffer);
guint8 dar_idx, fps_idx; guint8 dar_idx, par_idx;
guint32 sync_word = 0xffffffff; guint8 load_intra_flag, load_non_intra_flag;
gboolean constrained_flag;
gboolean load_intra_flag;
gboolean load_non_intra_flag;
gint i;
if (G_UNLIKELY ((end - data) < 12)) /* skip sync word */
return FALSE; /* Too small to be a sequence header */ if (!gst_bit_reader_skip (&reader, 8 * 4))
code = GST_READ_UINT32_BE (data);
if (G_UNLIKELY (code != (0x00000100 | MPEG_PACKET_SEQUENCE)))
return FALSE; return FALSE;
/* Skip the sync word */ /* resolution */
data += 4; if (!gst_bit_reader_get_bits_uint16 (&reader, &hdr->width, 12))
return FALSE;
if (!gst_bit_reader_get_bits_uint16 (&reader, &hdr->height, 12))
return FALSE;
/* Parse the MPEG 1 bits */ /* aspect ratio */
hdr->mpeg_version = 1; if (!gst_bit_reader_get_bits_uint8 (&reader, &dar_idx, 4))
return FALSE;
code = GST_READ_UINT32_BE (data);
hdr->width = read_bits (data, 0, 12);
hdr->height = read_bits (data + 1, 4, 12);
dar_idx = read_bits (data + 3, 0, 4);
set_par_from_dar (hdr, dar_idx); set_par_from_dar (hdr, dar_idx);
fps_idx = read_bits (data + 3, 4, 4);
set_fps_from_code (hdr, fps_idx);
constrained_flag = read_bits (data + 7, 5, 1); /* framerate */
if (!gst_bit_reader_get_bits_uint8 (&reader, &par_idx, 4))
load_intra_flag = read_bits (data + 7, 6, 1);
if (load_intra_flag) {
if (G_UNLIKELY ((end - data) < 64))
return FALSE; return FALSE;
for (i = 0; i < 64; i++) { set_fps_from_code (hdr, par_idx);
hdr->intra_quantizer_matrix[mpeg2_scan[i]] =
read_bits (data + 7 + i, 7, 8);
}
data += 64;
/* bitrate */
if (!gst_bit_reader_get_bits_uint32 (&reader, &hdr->bitrate, 18))
return FALSE;
if (!gst_bit_reader_skip (&reader, 1))
return FALSE;
/* VBV buffer size */
if (!gst_bit_reader_get_bits_uint16 (&reader, &hdr->vbv_buffer, 10))
return FALSE;
/* constrained parameters flag */
if (!gst_bit_reader_get_bits_uint8 (&reader,
&hdr->constrained_parameters_flag, 1))
return FALSE;
/* intra quantizer matrix */
if (!gst_bit_reader_get_bits_uint8 (&reader, &load_intra_flag, 1))
return FALSE;
if (load_intra_flag) {
gint i;
for (i = 0; i < 64; i++) {
if (!gst_bit_reader_get_bits_uint8 (&reader,
&hdr->intra_quantizer_matrix[mpeg2_scan[i]], 8))
return FALSE;
}
} else } else
memcpy (hdr->intra_quantizer_matrix, default_intra_quantizer_matrix, 64); memcpy (hdr->intra_quantizer_matrix, default_intra_quantizer_matrix, 64);
load_non_intra_flag = read_bits (data + 7, 7 + load_intra_flag, 1); /* non intra quantizer matrix */
if (load_non_intra_flag) { if (!gst_bit_reader_get_bits_uint8 (&reader, &load_non_intra_flag, 1))
if (G_UNLIKELY ((end - data) < 64))
return FALSE; return FALSE;
for (i = 0; i < 64; i++) if (load_non_intra_flag) {
hdr->non_intra_quantizer_matrix[mpeg2_scan[i]] = gint i;
read_bits (data + 8 + i, 1 + load_intra_flag, 8); for (i = 0; i < 64; i++) {
if (!gst_bit_reader_get_bits_uint8 (&reader,
&hdr->non_intra_quantizer_matrix[mpeg2_scan[i]], 8))
return FALSE;
}
} else } else
memset (hdr->non_intra_quantizer_matrix, 16, 64); memset (hdr->non_intra_quantizer_matrix, 16, 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; return TRUE;
} }
gboolean gboolean
mpeg_util_parse_picture_hdr (MPEGPictureHdr * hdr, guint8 * data, guint8 * end) mpeg_util_parse_picture_hdr (MPEGPictureHdr * hdr, GstBuffer * buffer)
{ {
guint32 code; GstBitReader reader = GST_BIT_READER_INIT_FROM_BUFFER (buffer);
if (G_UNLIKELY ((end - data) < 8)) /* skip sync word */
return FALSE; /* Packet too small */ if (!gst_bit_reader_skip (&reader, 8 * 4))
code = GST_READ_UINT32_BE (data);
if (G_UNLIKELY (code != (0x00000100 | MPEG_PACKET_PICTURE)))
return FALSE; return FALSE;
/* Skip the sync word */ /* temperal sequence number */
data += 4; if (!gst_bit_reader_get_bits_uint16 (&reader, &hdr->tsn, 10))
return FALSE;
/* frame type */
if (!gst_bit_reader_get_bits_uint8 (&reader, &hdr->pic_type, 3))
return FALSE;
hdr->pic_type = (data[1] >> 3) & 0x07;
if (hdr->pic_type == 0 || hdr->pic_type > 4) if (hdr->pic_type == 0 || hdr->pic_type > 4)
return FALSE; /* Corrupted picture packet */ return FALSE; /* Corrupted picture packet */
if (hdr->pic_type == P_FRAME || hdr->pic_type == B_FRAME) { /* VBV delay */
if (G_UNLIKELY ((end - data) < 5)) if (!gst_bit_reader_get_bits_uint16 (&reader, &hdr->vbv_delay, 16))
return FALSE; /* packet too small */ return FALSE;
hdr->full_pel_forward_vector = read_bits (data + 3, 5, 1); if (hdr->pic_type == P_FRAME || hdr->pic_type == B_FRAME) {
hdr->f_code[0][0] = hdr->f_code[0][1] = read_bits (data + 3, 6, 3);
if (!gst_bit_reader_get_bits_uint8 (&reader, &hdr->full_pel_forward_vector,
1))
return FALSE;
if (!gst_bit_reader_get_bits_uint8 (&reader, &hdr->f_code[0][0], 3))
return FALSE;
hdr->f_code[0][1] = hdr->f_code[0][0];
if (hdr->pic_type == B_FRAME) { if (hdr->pic_type == B_FRAME) {
hdr->full_pel_backward_vector = read_bits (data + 4, 1, 1); if (!gst_bit_reader_get_bits_uint8 (&reader,
hdr->f_code[1][0] = hdr->f_code[1][1] = read_bits (data + 4, 2, 3); &hdr->full_pel_backward_vector, 1))
return FALSE;
if (!gst_bit_reader_get_bits_uint8 (&reader, &hdr->f_code[1][0], 3))
return FALSE;
hdr->f_code[1][1] = hdr->f_code[1][0];
} else } else
hdr->full_pel_backward_vector = 0; hdr->full_pel_backward_vector = 0;
} else { } else {
@ -312,104 +273,143 @@ mpeg_util_parse_picture_hdr (MPEGPictureHdr * hdr, guint8 * data, guint8 * end)
} }
gboolean gboolean
mpeg_util_parse_picture_coding_extension (MPEGPictureExt * ext, guint8 * data, mpeg_util_parse_picture_coding_extension (MPEGPictureExt * ext,
guint8 * end) GstBuffer * buffer)
{ {
guint32 code; GstBitReader reader = GST_BIT_READER_INIT_FROM_BUFFER (buffer);
if (G_UNLIKELY ((end - data) < 9)) /* skip sync word */
return FALSE; /* Packet too small */ if (!gst_bit_reader_skip (&reader, 8 * 4))
code = GST_READ_UINT32_BE (data);
if (G_UNLIKELY (G_UNLIKELY (code != (0x00000100 | MPEG_PACKET_EXTENSION))))
return FALSE; return FALSE;
/* Skip the sync word */ /* skip extension code */
data += 4; if (!gst_bit_reader_skip (&reader, 4))
return FALSE;
ext->f_code[0][0] = read_bits (data, 4, 4); /* f_code */
ext->f_code[0][1] = read_bits (data + 1, 0, 4); if (!gst_bit_reader_get_bits_uint8 (&reader, &ext->f_code[0][0], 4))
ext->f_code[1][0] = read_bits (data + 1, 4, 4); return FALSE;
ext->f_code[1][1] = read_bits (data + 2, 0, 4); if (!gst_bit_reader_get_bits_uint8 (&reader, &ext->f_code[0][1], 4))
return FALSE;
if (!gst_bit_reader_get_bits_uint8 (&reader, &ext->f_code[1][0], 4))
return FALSE;
if (!gst_bit_reader_get_bits_uint8 (&reader, &ext->f_code[1][1], 4))
return FALSE;
ext->intra_dc_precision = read_bits (data + 2, 4, 2); /* intra DC precision */
ext->picture_structure = read_bits (data + 2, 6, 2); if (!gst_bit_reader_get_bits_uint8 (&reader, &ext->intra_dc_precision, 2))
ext->top_field_first = read_bits (data + 3, 0, 1); return FALSE;
ext->frame_pred_frame_dct = read_bits (data + 3, 1, 1);
ext->concealment_motion_vectors = read_bits (data + 3, 2, 1); /* picture structure */
ext->q_scale_type = read_bits (data + 3, 3, 1); if (!gst_bit_reader_get_bits_uint8 (&reader, &ext->picture_structure, 2))
ext->intra_vlc_format = read_bits (data + 3, 4, 1); return FALSE;
ext->alternate_scan = read_bits (data + 3, 5, 1);
/* top field first */
if (!gst_bit_reader_get_bits_uint8 (&reader, &ext->top_field_first, 1))
return FALSE;
/* frame pred frame dct */
if (!gst_bit_reader_get_bits_uint8 (&reader, &ext->frame_pred_frame_dct, 1))
return FALSE;
/* concealment motion vectors */
if (!gst_bit_reader_get_bits_uint8 (&reader, &ext->concealment_motion_vectors,
1))
return FALSE;
/* q scale type */
if (!gst_bit_reader_get_bits_uint8 (&reader, &ext->q_scale_type, 1))
return FALSE;
/* intra vlc format */
if (!gst_bit_reader_get_bits_uint8 (&reader, &ext->intra_vlc_format, 1))
return FALSE;
/* alternate scan */
if (!gst_bit_reader_get_bits_uint8 (&reader, &ext->alternate_scan, 1))
return FALSE;
/* repeat first field */
if (!gst_bit_reader_get_bits_uint8 (&reader, &ext->repeat_first_field, 1))
return FALSE;
return TRUE; return TRUE;
} }
gboolean gboolean
mpeg_util_parse_picture_gop (MPEGPictureGOP * gop, guint8 * data, guint8 * end) mpeg_util_parse_gop (MPEGGop * gop, GstBuffer * buffer)
{ {
guint32 code; GstBitReader reader = GST_BIT_READER_INIT_FROM_BUFFER (buffer);
if (G_UNLIKELY ((end - data) < 8)) /* skip sync word */
return FALSE; /* Packet too small */ if (!gst_bit_reader_skip (&reader, 8 * 4))
code = GST_READ_UINT32_BE (data);
if (G_UNLIKELY (G_UNLIKELY (code != (0x00000100 | MPEG_PACKET_GOP))))
return FALSE; return FALSE;
/* Skip the sync word */ if (!gst_bit_reader_get_bits_uint8 (&reader, &gop->drop_frame_flag, 1))
data += 4; return FALSE;
gop->drop_frame_flag = read_bits (data, 0, 1); if (!gst_bit_reader_get_bits_uint8 (&reader, &gop->hour, 5))
return FALSE;
gop->hour = read_bits (data, 1, 5); if (!gst_bit_reader_get_bits_uint8 (&reader, &gop->minute, 6))
gop->minute = read_bits (data, 6, 6); return FALSE;
gop->second = read_bits (data + 1, 4, 6);
gop->frame = read_bits (data + 2, 3, 6);
gop->closed_gop = read_bits (data + 3, 1, 1); /* skip unused bit */
gop->broken_gop = read_bits (data + 3, 2, 1); if (!gst_bit_reader_skip (&reader, 1))
return FALSE;
if (!gst_bit_reader_get_bits_uint8 (&reader, &gop->second, 6))
return FALSE;
if (!gst_bit_reader_get_bits_uint8 (&reader, &gop->frame, 6))
return FALSE;
if (!gst_bit_reader_get_bits_uint8 (&reader, &gop->closed_gop, 1))
return FALSE;
if (!gst_bit_reader_get_bits_uint8 (&reader, &gop->broken_gop, 1))
return FALSE;
return TRUE; return TRUE;
} }
gboolean gboolean
mpeg_util_parse_quant_matrix (MPEGQuantMatrix * qm, guint8 * data, guint8 * end) mpeg_util_parse_quant_matrix (MPEGQuantMatrix * qm, GstBuffer * buffer)
{ {
guint32 code; GstBitReader reader = GST_BIT_READER_INIT_FROM_BUFFER (buffer);
gboolean load_intra_flag, load_non_intra_flag; guint8 load_intra_flag, load_non_intra_flag;
gint i;
if (G_UNLIKELY ((end - data) < 5)) /* skip sync word */
return FALSE; /* Packet too small */ if (!gst_bit_reader_skip (&reader, 8 * 4))
code = GST_READ_UINT32_BE (data);
if (G_UNLIKELY (G_UNLIKELY (code != (0x00000100 | MPEG_PACKET_EXTENSION))))
return FALSE; return FALSE;
/* Skip the sync word */ /* skip extension code */
data += 4; if (!gst_bit_reader_skip (&reader, 4))
return FALSE;
load_intra_flag = read_bits (data, 4, 1); /* intra quantizer matrix */
if (!gst_bit_reader_get_bits_uint8 (&reader, &load_intra_flag, 1))
return FALSE;
if (load_intra_flag) { if (load_intra_flag) {
if (G_UNLIKELY ((end - data) < 64)) gint i;
for (i = 0; i < 64; i++) {
if (!gst_bit_reader_get_bits_uint8 (&reader,
&qm->intra_quantizer_matrix[mpeg2_scan[i]], 8))
return FALSE; return FALSE;
for (i = 0; i < 64; i++) }
qm->intra_quantizer_matrix[mpeg2_scan[i]] = read_bits (data + i, 5, 8);
data += 64;
} else } else
memcpy (qm->intra_quantizer_matrix, default_intra_quantizer_matrix, 64); memcpy (qm->intra_quantizer_matrix, default_intra_quantizer_matrix, 64);
load_non_intra_flag = read_bits (data, 5 + load_intra_flag, 1); /* non intra quantizer matrix */
if (load_non_intra_flag) { if (!gst_bit_reader_get_bits_uint8 (&reader, &load_non_intra_flag, 1))
if (G_UNLIKELY ((end - data) < 64))
return FALSE; return FALSE;
for (i = 0; i < 64; i++) if (load_non_intra_flag) {
qm->non_intra_quantizer_matrix[mpeg2_scan[i]] = gint i;
read_bits (data + i, 6 + load_intra_flag, 8); for (i = 0; i < 64; i++) {
if (!gst_bit_reader_get_bits_uint8 (&reader,
&qm->non_intra_quantizer_matrix[mpeg2_scan[i]], 8))
return FALSE;
}
} else } else
memset (qm->non_intra_quantizer_matrix, 16, 64); memset (qm->non_intra_quantizer_matrix, 16, 64);

View file

@ -24,9 +24,10 @@
#include <gst/gst.h> #include <gst/gst.h>
typedef struct MPEGSeqHdr MPEGSeqHdr; typedef struct MPEGSeqHdr MPEGSeqHdr;
typedef struct MPEGSeqExtHdr MPEGSeqExtHdr;
typedef struct MPEGPictureHdr MPEGPictureHdr; typedef struct MPEGPictureHdr MPEGPictureHdr;
typedef struct MPEGPictureExt MPEGPictureExt; typedef struct MPEGPictureExt MPEGPictureExt;
typedef struct MPEGPictureGOP MPEGPictureGOP; typedef struct MPEGGop MPEGGop;
typedef struct MPEGQuantMatrix MPEGQuantMatrix; typedef struct MPEGQuantMatrix MPEGQuantMatrix;
/* Packet ID codes for different packet types we /* Packet ID codes for different packet types we
@ -53,26 +54,44 @@ typedef struct MPEGQuantMatrix MPEGQuantMatrix;
struct MPEGSeqHdr struct MPEGSeqHdr
{ {
/* 0 for unknown, else 1 or 2 */
guint8 mpeg_version;
/* Pixel-Aspect Ratio from DAR code via set_par_from_dar */ /* Pixel-Aspect Ratio from DAR code via set_par_from_dar */
gint par_w, par_h; guint par_w, par_h;
/* Width and Height of the video */ /* Width and Height of the video */
gint width, height; guint16 width, height;
/* Framerate */ /* Framerate */
gint fps_n, fps_d; guint fps_n, fps_d;
/* mpeg2 decoder profile */ guint32 bitrate;
gint profile; guint16 vbv_buffer;
guint8 constrained_parameters_flag;
guint8 intra_quantizer_matrix[64]; guint8 intra_quantizer_matrix[64];
guint8 non_intra_quantizer_matrix[64]; guint8 non_intra_quantizer_matrix[64];
}; };
struct MPEGSeqExtHdr
{
/* mpeg2 decoder profile */
guint8 profile;
/* mpeg2 decoder level */
guint8 level;
guint8 progressive;
guint8 chroma_format;
guint8 horiz_size_ext, vert_size_ext;
guint8 fps_n_ext, fps_d_ext;
};
struct MPEGPictureHdr struct MPEGPictureHdr
{ {
guint16 tsn;
guint8 pic_type; guint8 pic_type;
guint16 vbv_delay;
guint8 full_pel_forward_vector, full_pel_backward_vector; guint8 full_pel_forward_vector, full_pel_backward_vector;
@ -91,9 +110,10 @@ struct MPEGPictureExt
guint8 q_scale_type; guint8 q_scale_type;
guint8 intra_vlc_format; guint8 intra_vlc_format;
guint8 alternate_scan; guint8 alternate_scan;
guint8 repeat_first_field;
}; };
struct MPEGPictureGOP struct MPEGGop
{ {
guint8 drop_frame_flag; guint8 drop_frame_flag;
@ -109,18 +129,19 @@ struct MPEGQuantMatrix
guint8 non_intra_quantizer_matrix[64]; guint8 non_intra_quantizer_matrix[64];
}; };
gboolean mpeg_util_parse_sequence_hdr (MPEGSeqHdr *hdr, gboolean mpeg_util_parse_sequence_hdr (MPEGSeqHdr *hdr, GstBuffer *buffer);
guint8 *data, guint8 *end);
gboolean mpeg_util_parse_picture_hdr (MPEGPictureHdr * hdr, guint8 * data, guint8 * end); gboolean mpeg_util_parse_sequence_extension (MPEGSeqExtHdr *hdr,
GstBuffer *buffer);
gboolean mpeg_util_parse_picture_coding_extension (MPEGPictureExt *ext, guint8 *data, guint8 *end); gboolean mpeg_util_parse_picture_hdr (MPEGPictureHdr * hdr, GstBuffer *buffer);
gboolean mpeg_util_parse_picture_gop (MPEGPictureGOP * gop, guint8 * data, guint8 * end); gboolean mpeg_util_parse_picture_coding_extension (MPEGPictureExt *ext,
GstBuffer *buffer);
gboolean mpeg_util_parse_quant_matrix (MPEGQuantMatrix * qm, guint8 * data, guint8 * end); gboolean mpeg_util_parse_gop (MPEGGop * gop, GstBuffer *buffer);
guint8 *mpeg_util_find_start_code (guint32 * sync_word, guint8 * cur, guint8 * end); gboolean mpeg_util_parse_quant_matrix (MPEGQuantMatrix * qm, GstBuffer *buffer);
guint32 read_bits (guint8 * buf, gint start_bit, gint n_bits);
#endif #endif