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
#include <gst/gst.h>
#include <gst/base/gstbytereader.h>
#include <gst/base/gstbitreader.h>
#include <string.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,
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
gst_vdp_mpeg_decoder_set_caps (GstVdpDecoder * dec, GstCaps * caps)
{
GstVdpMpegDecoder *mpeg_dec;
GstStructure *structure;
const GValue *value;
GstBuffer *codec_data;
MPEGSeqHdr hdr = { 0, };
VdpDecoderProfile profile;
GstVdpDevice *device;
VdpStatus status;
@ -100,25 +170,44 @@ gst_vdp_mpeg_decoder_set_caps (GstVdpDecoder * dec, GstCaps * caps)
profile = VDP_DECODER_PROFILE_MPEG1;
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;
break;
default:
profile = VDP_DECODER_PROFILE_MPEG2_MAIN;
break;
if (value) {
GstBuffer *codec_data, *buf;
GstVdpMpegPacketizer packetizer;
codec_data = gst_value_get_buffer (value);
gst_vdp_mpeg_packetizer_init (&packetizer, 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) {
switch (ext.profile) {
case 5:
profile = VDP_DECODER_PROFILE_MPEG2_SIMPLE;
break;
default:
profile = VDP_DECODER_PROFILE_MPEG2_MAIN;
break;
}
}
gst_buffer_unref (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);
device = dec->device;
if (mpeg_dec->decoder != VDP_INVALID_HANDLE) {
@ -224,7 +313,7 @@ gst_vdp_mpeg_decoder_decode (GstVdpMpegDecoder * mpeg_dec,
static gboolean
gst_vdp_mpeg_decoder_parse_picture_coding (GstVdpMpegDecoder * mpeg_dec,
guint8 * data, guint8 * end)
GstBuffer * buffer)
{
GstVdpDecoder *dec;
MPEGPictureExt pic_ext;
@ -233,7 +322,7 @@ gst_vdp_mpeg_decoder_parse_picture_coding (GstVdpMpegDecoder * mpeg_dec,
dec = GST_VDP_DECODER (mpeg_dec);
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;
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
gst_vdp_mpeg_decoder_parse_sequence (GstVdpMpegDecoder * mpeg_dec,
guint8 * data, guint8 * end)
GstBuffer * buffer)
{
GstVdpDecoder *dec;
MPEGSeqHdr hdr;
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;
g_debug ("här");
memcpy (&mpeg_dec->vdp_info.intra_quantizer_matrix,
&hdr.intra_quantizer_matrix, 64);
memcpy (&mpeg_dec->vdp_info.non_intra_quantizer_matrix,
@ -272,14 +362,14 @@ gst_vdp_mpeg_decoder_parse_sequence (GstVdpMpegDecoder * mpeg_dec,
static gboolean
gst_vdp_mpeg_decoder_parse_picture (GstVdpMpegDecoder * mpeg_dec,
guint8 * data, guint8 * end)
GstBuffer * buffer)
{
GstVdpDecoder *dec;
MPEGPictureHdr pic_hdr;
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;
if (pic_hdr.pic_type != I_FRAME
@ -309,12 +399,12 @@ gst_vdp_mpeg_decoder_parse_picture (GstVdpMpegDecoder * mpeg_dec,
}
static gboolean
gst_vdp_mpeg_decoder_parse_gop (GstVdpMpegDecoder * mpeg_dec, guint8 * data,
guint8 * end)
gst_vdp_mpeg_decoder_parse_gop (GstVdpMpegDecoder * mpeg_dec,
GstBuffer * buffer)
{
MPEGPictureGOP gop;
MPEGGop gop;
if (!mpeg_util_parse_picture_gop (&gop, data, end))
if (!mpeg_util_parse_gop (&gop, buffer))
return FALSE;
mpeg_dec->broken_gop = gop.broken_gop;
@ -324,11 +414,11 @@ gst_vdp_mpeg_decoder_parse_gop (GstVdpMpegDecoder * mpeg_dec, guint8 * data,
static gboolean
gst_vdp_mpeg_decoder_parse_quant_matrix (GstVdpMpegDecoder * mpeg_dec,
guint8 * data, guint8 * end)
GstBuffer * buffer)
{
MPEGQuantMatrix qm;
if (!mpeg_util_parse_quant_matrix (&qm, data, end))
if (!mpeg_util_parse_quant_matrix (&qm, buffer))
return FALSE;
memcpy (&mpeg_dec->vdp_info.intra_quantizer_matrix,
@ -355,8 +445,8 @@ static GstFlowReturn
gst_vdp_mpeg_decoder_chain (GstPad * pad, GstBuffer * buffer)
{
GstVdpMpegDecoder *mpeg_dec;
guint8 *data, *end;
guint32 sync_word = 0xffffffff;
GstVdpMpegPacketizer packetizer;
GstBuffer *buf;
GstFlowReturn ret = GST_FLOW_OK;
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;
}
data = GST_BUFFER_DATA (buffer);
end = GST_BUFFER_DATA (buffer) + GST_BUFFER_SIZE (buffer);
gst_vdp_mpeg_packetizer_init (&packetizer, 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))) {
guint8 *packet_start;
guint8 *packet_end;
/* skip sync_code */
gst_bit_reader_get_bits_uint32 (&b_reader, &sync_code, 8 * 3);
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;
/* start_code */
gst_bit_reader_get_bits_uint8 (&b_reader, &start_code, 8);
if (start_code >= MPEG_PACKET_SLICE_MIN
&& start_code <= MPEG_PACKET_SLICE_MAX) {
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);
gst_buffer_ref (buf);
gst_adapter_push (mpeg_dec->adapter, buf);
mpeg_dec->vdp_info.slice_count++;
}
switch (data[0]) {
switch (start_code) {
case MPEG_PACKET_PICTURE:
GST_DEBUG_OBJECT (mpeg_dec, "MPEG_PACKET_PICTURE");
if (!gst_vdp_mpeg_decoder_parse_picture (mpeg_dec, packet_start,
packet_end)) {
if (!gst_vdp_mpeg_decoder_parse_picture (mpeg_dec, buf)) {
return GST_FLOW_OK;
}
break;
case MPEG_PACKET_SEQUENCE:
GST_DEBUG_OBJECT (mpeg_dec, "MPEG_PACKET_SEQUENCE");
gst_vdp_mpeg_decoder_parse_sequence (mpeg_dec, packet_start,
packet_end);
gst_vdp_mpeg_decoder_parse_sequence (mpeg_dec, buf);
break;
case MPEG_PACKET_EXTENSION:
{
guint8 ext_code;
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:
GST_DEBUG_OBJECT (mpeg_dec, "MPEG_PACKET_EXT_PICTURE_CODING");
gst_vdp_mpeg_decoder_parse_picture_coding (mpeg_dec, packet_start,
packet_end);
gst_vdp_mpeg_decoder_parse_picture_coding (mpeg_dec, buf);
break;
case 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,
packet_end);
gst_vdp_mpeg_decoder_parse_quant_matrix (mpeg_dec, buf);
break;
default:
break;
}
break;
}
case 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;
default:
break;
}
gst_buffer_unref (buf);
}
if (mpeg_dec->vdp_info.slice_count > 0)

View file

@ -18,6 +18,7 @@
* Boston, MA 02111-1307, USA.
*/
#include <gst/base/gstbitreader.h>
#include <string.h>
#include "mpegutil.h"
@ -53,58 +54,6 @@ guint8 mpeg2_scan[64] = {
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
set_fps_from_code (MPEGSeqHdr * hdr, guint8 fps_code)
{
@ -150,157 +99,169 @@ set_par_from_dar (MPEGSeqHdr * hdr, guint8 asr_code)
}
}
static gboolean
mpeg_util_parse_extension_packet (MPEGSeqHdr * hdr, guint8 * data, guint8 * end)
gboolean
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))
return FALSE; /* short extension packet */
/* skip sync word */
if (!gst_bit_reader_skip (&reader, 8 * 4))
return FALSE;
ext_code = read_bits (data, 0, 4);
/* skip extension code */
if (!gst_bit_reader_skip (&reader, 4))
return FALSE;
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;
/* skip profile and level escape bit */
if (!gst_bit_reader_skip (&reader, 1))
return FALSE;
if (G_UNLIKELY ((end - data) < 6))
/* need at least 10 bytes, minus 4 for the start code 000001b5 */
return FALSE;
if (!gst_bit_reader_get_bits_uint8 (&reader, &hdr->profile, 3))
return FALSE;
if (!gst_bit_reader_get_bits_uint8 (&reader, &hdr->level, 4))
return FALSE;
hdr->profile = read_bits (data, 7, 3);
/* progressive */
if (!gst_bit_reader_get_bits_uint8 (&reader, &hdr->progressive, 1))
return FALSE;
horiz_size_ext = read_bits (data + 1, 7, 2);
vert_size_ext = read_bits (data + 2, 1, 2);
/* chroma format */
if (!gst_bit_reader_get_bits_uint8 (&reader, &hdr->chroma_format, 2))
return FALSE;
fps_n_ext = read_bits (data + 5, 1, 2);
fps_d_ext = read_bits (data + 5, 3, 5);
/* 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;
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;
}
/* 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;
}
gboolean
mpeg_util_parse_sequence_hdr (MPEGSeqHdr * hdr, guint8 * data, guint8 * end)
mpeg_util_parse_sequence_hdr (MPEGSeqHdr * hdr, GstBuffer * buffer)
{
guint32 code;
guint8 dar_idx, fps_idx;
guint32 sync_word = 0xffffffff;
gboolean constrained_flag;
gboolean load_intra_flag;
gboolean load_non_intra_flag;
gint i;
GstBitReader reader = GST_BIT_READER_INIT_FROM_BUFFER (buffer);
guint8 dar_idx, par_idx;
guint8 load_intra_flag, 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)))
/* skip sync word */
if (!gst_bit_reader_skip (&reader, 8 * 4))
return FALSE;
/* Skip the sync word */
data += 4;
/* resolution */
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 */
hdr->mpeg_version = 1;
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);
/* aspect ratio */
if (!gst_bit_reader_get_bits_uint8 (&reader, &dar_idx, 4))
return FALSE;
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))
return FALSE;
set_fps_from_code (hdr, par_idx);
load_intra_flag = read_bits (data + 7, 6, 1);
/* 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) {
if (G_UNLIKELY ((end - data) < 64))
return FALSE;
gint i;
for (i = 0; i < 64; i++) {
hdr->intra_quantizer_matrix[mpeg2_scan[i]] =
read_bits (data + 7 + i, 7, 8);
if (!gst_bit_reader_get_bits_uint8 (&reader,
&hdr->intra_quantizer_matrix[mpeg2_scan[i]], 8))
return FALSE;
}
data += 64;
} else
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 (!gst_bit_reader_get_bits_uint8 (&reader, &load_non_intra_flag, 1))
return FALSE;
if (load_non_intra_flag) {
if (G_UNLIKELY ((end - data) < 64))
return FALSE;
for (i = 0; i < 64; i++)
hdr->non_intra_quantizer_matrix[mpeg2_scan[i]] =
read_bits (data + 8 + i, 1 + load_intra_flag, 8);
gint i;
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
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;
}
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))
return FALSE; /* Packet too small */
code = GST_READ_UINT32_BE (data);
if (G_UNLIKELY (code != (0x00000100 | MPEG_PACKET_PICTURE)))
/* skip sync word */
if (!gst_bit_reader_skip (&reader, 8 * 4))
return FALSE;
/* Skip the sync word */
data += 4;
/* temperal sequence number */
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)
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 */
/* VBV delay */
if (!gst_bit_reader_get_bits_uint16 (&reader, &hdr->vbv_delay, 16))
return FALSE;
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);
if (hdr->pic_type == P_FRAME || hdr->pic_type == B_FRAME) {
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) {
hdr->full_pel_backward_vector = read_bits (data + 4, 1, 1);
hdr->f_code[1][0] = hdr->f_code[1][1] = read_bits (data + 4, 2, 3);
if (!gst_bit_reader_get_bits_uint8 (&reader,
&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
hdr->full_pel_backward_vector = 0;
} else {
@ -312,104 +273,143 @@ mpeg_util_parse_picture_hdr (MPEGPictureHdr * hdr, guint8 * data, guint8 * end)
}
gboolean
mpeg_util_parse_picture_coding_extension (MPEGPictureExt * ext, guint8 * data,
guint8 * end)
mpeg_util_parse_picture_coding_extension (MPEGPictureExt * ext,
GstBuffer * buffer)
{
guint32 code;
GstBitReader reader = GST_BIT_READER_INIT_FROM_BUFFER (buffer);
if (G_UNLIKELY ((end - data) < 9))
return FALSE; /* Packet too small */
code = GST_READ_UINT32_BE (data);
if (G_UNLIKELY (G_UNLIKELY (code != (0x00000100 | MPEG_PACKET_EXTENSION))))
/* skip sync word */
if (!gst_bit_reader_skip (&reader, 8 * 4))
return FALSE;
/* Skip the sync word */
data += 4;
/* skip extension code */
if (!gst_bit_reader_skip (&reader, 4))
return FALSE;
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);
ext->f_code[1][1] = read_bits (data + 2, 0, 4);
/* f_code */
if (!gst_bit_reader_get_bits_uint8 (&reader, &ext->f_code[0][0], 4))
return FALSE;
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);
ext->picture_structure = read_bits (data + 2, 6, 2);
ext->top_field_first = read_bits (data + 3, 0, 1);
ext->frame_pred_frame_dct = read_bits (data + 3, 1, 1);
ext->concealment_motion_vectors = read_bits (data + 3, 2, 1);
ext->q_scale_type = read_bits (data + 3, 3, 1);
ext->intra_vlc_format = read_bits (data + 3, 4, 1);
ext->alternate_scan = read_bits (data + 3, 5, 1);
/* intra DC precision */
if (!gst_bit_reader_get_bits_uint8 (&reader, &ext->intra_dc_precision, 2))
return FALSE;
/* picture structure */
if (!gst_bit_reader_get_bits_uint8 (&reader, &ext->picture_structure, 2))
return FALSE;
/* 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;
}
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))
return FALSE; /* Packet too small */
code = GST_READ_UINT32_BE (data);
if (G_UNLIKELY (G_UNLIKELY (code != (0x00000100 | MPEG_PACKET_GOP))))
/* skip sync word */
if (!gst_bit_reader_skip (&reader, 8 * 4))
return FALSE;
/* Skip the sync word */
data += 4;
if (!gst_bit_reader_get_bits_uint8 (&reader, &gop->drop_frame_flag, 1))
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);
gop->minute = read_bits (data, 6, 6);
gop->second = read_bits (data + 1, 4, 6);
gop->frame = read_bits (data + 2, 3, 6);
if (!gst_bit_reader_get_bits_uint8 (&reader, &gop->minute, 6))
return FALSE;
gop->closed_gop = read_bits (data + 3, 1, 1);
gop->broken_gop = read_bits (data + 3, 2, 1);
/* skip unused bit */
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;
}
gboolean
mpeg_util_parse_quant_matrix (MPEGQuantMatrix * qm, guint8 * data, guint8 * end)
mpeg_util_parse_quant_matrix (MPEGQuantMatrix * qm, GstBuffer * buffer)
{
guint32 code;
gboolean load_intra_flag, load_non_intra_flag;
gint i;
GstBitReader reader = GST_BIT_READER_INIT_FROM_BUFFER (buffer);
guint8 load_intra_flag, load_non_intra_flag;
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_EXTENSION))))
/* skip sync word */
if (!gst_bit_reader_skip (&reader, 8 * 4))
return FALSE;
/* Skip the sync word */
data += 4;
/* skip extension code */
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 (G_UNLIKELY ((end - data) < 64))
return FALSE;
for (i = 0; i < 64; i++)
qm->intra_quantizer_matrix[mpeg2_scan[i]] = read_bits (data + i, 5, 8);
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;
}
} else
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 (!gst_bit_reader_get_bits_uint8 (&reader, &load_non_intra_flag, 1))
return FALSE;
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, 6 + load_intra_flag, 8);
gint i;
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
memset (qm->non_intra_quantizer_matrix, 16, 64);

View file

@ -24,9 +24,10 @@
#include <gst/gst.h>
typedef struct MPEGSeqHdr MPEGSeqHdr;
typedef struct MPEGSeqExtHdr MPEGSeqExtHdr;
typedef struct MPEGPictureHdr MPEGPictureHdr;
typedef struct MPEGPictureExt MPEGPictureExt;
typedef struct MPEGPictureGOP MPEGPictureGOP;
typedef struct MPEGGop MPEGGop;
typedef struct MPEGQuantMatrix MPEGQuantMatrix;
/* Packet ID codes for different packet types we
@ -53,27 +54,45 @@ typedef struct MPEGQuantMatrix MPEGQuantMatrix;
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;
guint par_w, par_h;
/* Width and Height of the video */
gint width, height;
guint16 width, height;
/* Framerate */
gint fps_n, fps_d;
guint fps_n, fps_d;
/* mpeg2 decoder profile */
gint profile;
guint32 bitrate;
guint16 vbv_buffer;
guint8 constrained_parameters_flag;
guint8 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
{
guint16 tsn;
guint8 pic_type;
guint16 vbv_delay;
guint8 full_pel_forward_vector, full_pel_backward_vector;
guint8 f_code[2][2];
@ -91,9 +110,10 @@ struct MPEGPictureExt
guint8 q_scale_type;
guint8 intra_vlc_format;
guint8 alternate_scan;
guint8 repeat_first_field;
};
struct MPEGPictureGOP
struct MPEGGop
{
guint8 drop_frame_flag;
@ -109,18 +129,19 @@ struct MPEGQuantMatrix
guint8 non_intra_quantizer_matrix[64];
};
gboolean mpeg_util_parse_sequence_hdr (MPEGSeqHdr *hdr,
guint8 *data, guint8 *end);
gboolean mpeg_util_parse_sequence_hdr (MPEGSeqHdr *hdr, GstBuffer *buffer);
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);
guint32 read_bits (guint8 * buf, gint start_bit, gint n_bits);
gboolean mpeg_util_parse_quant_matrix (MPEGQuantMatrix * qm, GstBuffer *buffer);
#endif