mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-18 14:26:43 +00:00
10639eb889
Fix parsing of residual bytes. This is a two-step process. First, remaining colums of full vertical resolution (<height>) need to be processed. Next, remaining bytes in the first row can be processed, while taking into account the fact that we may have filled in the first columns already. So, this is not full horizontal resolution. The following figure helps in understanding the expected order of operations, for a 8x5 MBs bitplane. 5 5 6 6 6 6 6 6 5 5 1 1 1 2 2 2 5 5 1 1 1 2 2 2 5 5 3 3 3 4 4 4 5 5 3 3 3 4 4 4 So, after tiles 1 to 4 are decoded, vertical tile 5 needs to be processed (2x5 MBs) and then the horizontal tile 6 (6x1 MBs). https://bugzilla.gnome.org/show_bug.cgi?id=692461 Signed-off-by: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
2192 lines
60 KiB
C
2192 lines
60 KiB
C
/* Gstreamer
|
|
* Copyright (C) <2011> Intel
|
|
* Copyright (C) <2011> Collabora Ltd.
|
|
* Copyright (C) <2011> Thibault Saunier <thibault.saunier@collabora.com>
|
|
*
|
|
* 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., 51 Franklin St, Fifth Floor,
|
|
* Boston, MA 02110-1301, USA.
|
|
*/
|
|
/**
|
|
* SECTION:gstvc1parser
|
|
* @short_description: Convenience library for parsing vc1 video
|
|
* bitstream.
|
|
*
|
|
* For more details about the structures, look at the
|
|
* smpte specifications (S421m-2006.pdf).
|
|
*
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
# include "config.h"
|
|
#endif
|
|
|
|
#include "gstvc1parser.h"
|
|
#include "parserutils.h"
|
|
#include <gst/base/gstbytereader.h>
|
|
#include <gst/base/gstbitreader.h>
|
|
#include <string.h>
|
|
|
|
#ifndef GST_DISABLE_GST_DEBUG
|
|
|
|
#define GST_CAT_DEFAULT ensure_debug_category()
|
|
|
|
static GstDebugCategory *
|
|
ensure_debug_category (void)
|
|
{
|
|
static gsize cat_gonce = 0;
|
|
|
|
if (g_once_init_enter (&cat_gonce)) {
|
|
gsize cat_done;
|
|
|
|
cat_done = (gsize) _gst_debug_category_new ("codecparsers_vc1", 0,
|
|
"VC1 codec parsing library");
|
|
|
|
g_once_init_leave (&cat_gonce, cat_done);
|
|
}
|
|
|
|
return (GstDebugCategory *) cat_gonce;
|
|
}
|
|
|
|
#else
|
|
|
|
#define ensure_debug_category() /* NOOP */
|
|
|
|
#endif /* GST_DISABLE_GST_DEBUG */
|
|
|
|
static const guint8 vc1_pquant_table[3][32] = {
|
|
{ /* Implicit quantizer */
|
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 6, 7, 8, 9, 10, 11, 12,
|
|
13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 27, 29, 31},
|
|
{ /* Explicit quantizer, pquantizer uniform */
|
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
|
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31},
|
|
{ /* Explicit quantizer, pquantizer non-uniform */
|
|
0, 1, 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
|
|
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 29, 31}
|
|
};
|
|
|
|
static const guint8 vc1_mvmode_table[2][5] = {
|
|
/* Table 47: P Picture High rate (PQUANT <= 12) MVMODE code table */
|
|
{
|
|
GST_VC1_MVMODE_1MV,
|
|
GST_VC1_MVMODE_MIXED_MV,
|
|
GST_VC1_MVMODE_1MV_HPEL,
|
|
GST_VC1_MVMODE_INTENSITY_COMP,
|
|
GST_VC1_MVMODE_1MV_HPEL_BILINEAR},
|
|
/* Table 46: P Picture Low rate (PQUANT > 12) MVMODE code table */
|
|
{
|
|
GST_VC1_MVMODE_1MV_HPEL_BILINEAR,
|
|
GST_VC1_MVMODE_1MV,
|
|
GST_VC1_MVMODE_1MV_HPEL,
|
|
GST_VC1_MVMODE_INTENSITY_COMP,
|
|
GST_VC1_MVMODE_MIXED_MV}
|
|
};
|
|
|
|
static const guint8 vc1_mvmode2_table[2][4] = {
|
|
/* Table 50: P Picture High rate (PQUANT <= 12) MVMODE2 code table */
|
|
{
|
|
GST_VC1_MVMODE_1MV,
|
|
GST_VC1_MVMODE_MIXED_MV,
|
|
GST_VC1_MVMODE_1MV_HPEL,
|
|
GST_VC1_MVMODE_1MV_HPEL_BILINEAR},
|
|
/* Table 49: P Picture Low rate (PQUANT > 12) MVMODE2 code table */
|
|
{
|
|
GST_VC1_MVMODE_1MV_HPEL_BILINEAR,
|
|
GST_VC1_MVMODE_1MV,
|
|
GST_VC1_MVMODE_1MV_HPEL,
|
|
GST_VC1_MVMODE_MIXED_MV}
|
|
};
|
|
|
|
/* Table 40: BFRACTION VLC Table */
|
|
static const VLCTable vc1_bfraction_vlc_table[] = {
|
|
{GST_VC1_BFRACTION_BASIS / 2, 0x00, 3},
|
|
{GST_VC1_BFRACTION_BASIS / 3, 0x01, 3},
|
|
{(GST_VC1_BFRACTION_BASIS * 2) / 3, 0x02, 3},
|
|
{GST_VC1_BFRACTION_BASIS / 4, 0x02, 3},
|
|
{(GST_VC1_BFRACTION_BASIS * 3) / 4, 0x04, 3},
|
|
{GST_VC1_BFRACTION_BASIS / 5, 0x05, 3},
|
|
{(GST_VC1_BFRACTION_BASIS * 2) / 5, 0x06, 3},
|
|
{(GST_VC1_BFRACTION_BASIS * 3) / 5, 0x70, 7},
|
|
{(GST_VC1_BFRACTION_BASIS * 4) / 5, 0x71, 7},
|
|
{GST_VC1_BFRACTION_BASIS / 6, 0x72, 7},
|
|
{(GST_VC1_BFRACTION_BASIS * 5) / 6, 0x73, 7},
|
|
{GST_VC1_BFRACTION_BASIS / 7, 0x74, 7},
|
|
{(GST_VC1_BFRACTION_BASIS * 2) / 7, 0x75, 7},
|
|
{(GST_VC1_BFRACTION_BASIS * 3) / 7, 0x76, 7},
|
|
{(GST_VC1_BFRACTION_BASIS * 4) / 7, 0x77, 7},
|
|
{(GST_VC1_BFRACTION_BASIS * 5) / 7, 0x78, 7},
|
|
{(GST_VC1_BFRACTION_BASIS * 6) / 7, 0x79, 7},
|
|
{GST_VC1_BFRACTION_BASIS / 8, 0x7a, 7},
|
|
{(GST_VC1_BFRACTION_BASIS * 3) / 8, 0x7b, 7},
|
|
{(GST_VC1_BFRACTION_BASIS * 5) / 8, 0x7c, 7},
|
|
{(GST_VC1_BFRACTION_BASIS * 7) / 8, 0x7d, 7},
|
|
{GST_VC1_BFRACTION_RESERVED, 0x7e, 7},
|
|
{GST_VC1_BFRACTION_PTYPE_BI, 0x7f, 7}
|
|
};
|
|
|
|
/* Imode types */
|
|
enum
|
|
{
|
|
IMODE_RAW,
|
|
IMODE_NORM2,
|
|
IMODE_DIFF2,
|
|
IMODE_NORM6,
|
|
IMODE_DIFF6,
|
|
IMODE_ROWSKIP,
|
|
IMODE_COLSKIP
|
|
};
|
|
|
|
/* Table 69: IMODE VLC Codetable */
|
|
static const VLCTable vc1_imode_vlc_table[] = {
|
|
{IMODE_NORM2, 0x02, 2},
|
|
{IMODE_NORM6, 0x03, 2},
|
|
{IMODE_ROWSKIP, 0x02, 3},
|
|
{IMODE_COLSKIP, 0x03, 3},
|
|
{IMODE_DIFF2, 0x01, 3},
|
|
{IMODE_DIFF6, 0x01, 4},
|
|
{IMODE_RAW, 0x00, 4}
|
|
};
|
|
|
|
/* Table 80: Norm-2/Diff-2 Code Table */
|
|
static const VLCTable vc1_norm2_vlc_table[4] = {
|
|
{0, 0, 1},
|
|
{2, 4, 3},
|
|
{1, 5, 3},
|
|
{3, 3, 2}
|
|
};
|
|
|
|
/* Table 81: Code table for 3x2 and 2x3 tiles */
|
|
static const VLCTable vc1_norm6_vlc_table[64] = {
|
|
{0, 1, 1},
|
|
{1, 2, 4},
|
|
{2, 3, 4},
|
|
{3, 0, 8},
|
|
{4, 4, 4},
|
|
{5, 1, 8},
|
|
{6, 2, 8},
|
|
{7, (2 << 5) | 7, 10},
|
|
{8, 5, 4},
|
|
{9, 3, 8},
|
|
{10, 4, 8},
|
|
{11, (2 << 5) | 11, 10},
|
|
{12, 5, 8},
|
|
{13, (2 << 5) | 13, 10},
|
|
{14, (2 << 5) | 14, 10},
|
|
{15, (3 << 8) | 14, 13},
|
|
{16, 6, 4},
|
|
{17, 6, 8},
|
|
{18, 7, 8},
|
|
{19, (2 << 5) | 19, 10},
|
|
{20, 8, 8},
|
|
{21, (2 << 5) | 21, 10},
|
|
{22, (2 << 5) | 22, 10},
|
|
{23, (3 << 8) | 13, 13},
|
|
{24, 9, 8},
|
|
{25, (2 << 5) | 25, 10},
|
|
{26, (2 << 5) | 26, 10},
|
|
{27, (3 << 8) | 12, 13},
|
|
{28, (2 << 5) | 28, 10},
|
|
{29, (3 << 8) | 11, 13},
|
|
{30, (3 << 8) | 10, 13},
|
|
{31, (3 << 4) | 7, 9},
|
|
{32, 7, 4},
|
|
{33, 10, 8},
|
|
{34, 11, 8},
|
|
{35, (2 << 5) | 3, 10},
|
|
{36, 12, 8},
|
|
{37, (2 << 5) | 5, 10},
|
|
{38, (2 << 5) | 6, 10},
|
|
{39, (3 << 8) | 9, 13},
|
|
{40, 13, 8},
|
|
{41, (2 << 5) | 9, 10},
|
|
{42, (2 << 5) | 10, 10},
|
|
{43, (3 << 8) | 8, 13},
|
|
{44, (2 << 5) | 12, 10},
|
|
{45, (3 << 8) | 7, 13},
|
|
{46, (3 << 8) | 6, 13},
|
|
{47, (3 << 4) | 6, 9},
|
|
{48, 14, 8},
|
|
{49, (2 << 5) | 17, 10},
|
|
{50, (2 << 5) | 18, 10},
|
|
{51, (3 << 8) | 5, 13},
|
|
{52, (2 << 5) | 20, 10},
|
|
{53, (3 << 8) | 4, 13},
|
|
{54, (3 << 8) | 3, 13},
|
|
{55, (3 << 4) | 5, 9},
|
|
{56, (2 << 5) | 24, 10},
|
|
{57, (3 << 8) | 2, 13},
|
|
{58, (3 << 8) | 1, 13},
|
|
{59, (3 << 4) | 4, 9},
|
|
{60, (3 << 8) | 0, 13},
|
|
{61, (3 << 4) | 3, 9},
|
|
{62, (3 << 4) | 2, 9},
|
|
{63, (3 << 1) | 1, 6}
|
|
};
|
|
|
|
/* SMPTE 421M Table 7 */
|
|
typedef struct
|
|
{
|
|
gint par_n, par_d;
|
|
} PAR;
|
|
|
|
static PAR aspect_ratios[] = {
|
|
{0, 0},
|
|
{1, 1},
|
|
{12, 11},
|
|
{10, 11},
|
|
{16, 11},
|
|
{40, 33},
|
|
{24, 11},
|
|
{20, 11},
|
|
{32, 11},
|
|
{80, 33},
|
|
{18, 11},
|
|
{15, 11},
|
|
{64, 33},
|
|
{160, 99},
|
|
{0, 0},
|
|
{0, 0}
|
|
};
|
|
|
|
/* SMPTE 421M Table 8 */
|
|
static const guint framerates_n[] = {
|
|
0,
|
|
24 * 1000,
|
|
25 * 1000,
|
|
30 * 1000,
|
|
50 * 1000,
|
|
60 * 1000,
|
|
48 * 1000,
|
|
72 * 1000
|
|
};
|
|
|
|
/* SMPTE 421M Table 9 */
|
|
static const guint framerates_d[] = {
|
|
0,
|
|
1000,
|
|
1001
|
|
};
|
|
|
|
|
|
static inline gboolean
|
|
decode_colskip (GstBitReader * br, guint8 * data, guint width, guint height,
|
|
guint stride, guint invert)
|
|
{
|
|
guint x, y;
|
|
guint8 colskip, v;
|
|
|
|
GST_DEBUG ("Parsing colskip");
|
|
|
|
invert &= 1;
|
|
for (x = 0; x < width; x++) {
|
|
READ_UINT8 (br, colskip, 1);
|
|
|
|
if (data) {
|
|
if (colskip) {
|
|
for (y = 0; y < height; y++) {
|
|
READ_UINT8 (br, v, 1);
|
|
data[y * stride] = v ^ invert;
|
|
}
|
|
} else {
|
|
for (y = 0; y < height; y++)
|
|
data[y * stride] = invert;
|
|
}
|
|
data++;
|
|
} else if (colskip)
|
|
SKIP (br, height);
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
failed:
|
|
GST_WARNING ("Failed to parse colskip");
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static inline gboolean
|
|
decode_rowskip (GstBitReader * br, guint8 * data, guint width, guint height,
|
|
guint stride, guint invert)
|
|
{
|
|
guint x, y;
|
|
guint8 rowskip, v;
|
|
|
|
GST_DEBUG ("Parsing rowskip");
|
|
|
|
invert &= 1;
|
|
for (y = 0; y < height; y++) {
|
|
READ_UINT8 (br, rowskip, 1);
|
|
|
|
if (data) {
|
|
if (!rowskip)
|
|
memset (data, invert, width);
|
|
else {
|
|
for (x = 0; x < width; x++) {
|
|
READ_UINT8 (br, v, 1);
|
|
data[x] = v ^ invert;
|
|
}
|
|
}
|
|
data += stride;
|
|
} else if (rowskip)
|
|
SKIP (br, width);
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
failed:
|
|
GST_WARNING ("Failed to parse rowskip");
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static inline gint8
|
|
decode012 (GstBitReader * br)
|
|
{
|
|
guint8 n;
|
|
|
|
READ_UINT8 (br, n, 1);
|
|
|
|
if (n == 0)
|
|
return 0;
|
|
|
|
READ_UINT8 (br, n, 1);
|
|
|
|
return n + 1;
|
|
|
|
failed:
|
|
GST_WARNING ("Could not decode 0 1 2 returning -1");
|
|
|
|
return -1;
|
|
}
|
|
|
|
static inline guint
|
|
calculate_nb_pan_scan_win (GstVC1AdvancedSeqHdr * advseqhdr,
|
|
GstVC1PicAdvanced * pic)
|
|
{
|
|
if (advseqhdr->interlace && !advseqhdr->psf) {
|
|
if (advseqhdr->pulldown)
|
|
return pic->rff + 2;
|
|
|
|
return 2;
|
|
|
|
} else {
|
|
if (advseqhdr->pulldown)
|
|
return pic->rptfrm + 1;
|
|
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
static gboolean
|
|
decode_refdist (GstBitReader * br, guint16 * value)
|
|
{
|
|
guint16 tmp;
|
|
gint i = 2;
|
|
|
|
if (!gst_bit_reader_peek_bits_uint16 (br, &tmp, i))
|
|
goto failed;
|
|
|
|
if (tmp < 0x03) {
|
|
READ_UINT16 (br, *value, i);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
do {
|
|
i++;
|
|
|
|
if (!gst_bit_reader_peek_bits_uint16 (br, &tmp, i))
|
|
goto failed;
|
|
|
|
if (!(tmp >> i)) {
|
|
READ_UINT16 (br, *value, i);
|
|
|
|
return TRUE;
|
|
}
|
|
} while (i < 16);
|
|
|
|
|
|
failed:
|
|
{
|
|
GST_WARNING ("Could not decode end 0 returning");
|
|
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
/*** bitplanes decoding ***/
|
|
static gboolean
|
|
bitplane_decoding (GstBitReader * br, guint8 * data,
|
|
GstVC1SeqHdr * seqhdr, guint8 * is_raw)
|
|
{
|
|
const guint width = seqhdr->mb_width;
|
|
const guint height = seqhdr->mb_height;
|
|
const guint stride = seqhdr->mb_stride;
|
|
guint imode, invert, invert_mask;
|
|
guint x, y, v, o;
|
|
guint8 *pdata = data;
|
|
|
|
*is_raw = FALSE;
|
|
|
|
GET_BITS (br, 1, &invert);
|
|
invert_mask = -invert;
|
|
|
|
if (!decode_vlc (br, &imode, vc1_imode_vlc_table,
|
|
G_N_ELEMENTS (vc1_imode_vlc_table)))
|
|
goto failed;
|
|
|
|
switch (imode) {
|
|
case IMODE_RAW:
|
|
|
|
GST_DEBUG ("Parsing IMODE_RAW");
|
|
|
|
*is_raw = TRUE;
|
|
return TRUE;
|
|
|
|
case IMODE_DIFF2:
|
|
invert_mask = 0;
|
|
/* fall-through */
|
|
case IMODE_NORM2:
|
|
invert_mask &= 3;
|
|
|
|
GST_DEBUG ("Parsing IMODE_DIFF2 or IMODE_NORM2 biplane");
|
|
|
|
x = 0;
|
|
o = (height * width) & 1;
|
|
if (o) {
|
|
GET_BITS (br, 1, &v);
|
|
if (pdata) {
|
|
*pdata++ = (v ^ invert_mask) & 1;
|
|
if (++x == width) {
|
|
x = 0;
|
|
pdata += stride - width;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (y = o; y < height * width; y += 2) {
|
|
if (!decode_vlc (br, &v, vc1_norm2_vlc_table,
|
|
G_N_ELEMENTS (vc1_norm2_vlc_table)))
|
|
goto failed;
|
|
if (pdata) {
|
|
v ^= invert_mask;
|
|
*pdata++ = v >> 1;
|
|
if (++x == width) {
|
|
x = 0;
|
|
pdata += stride - width;
|
|
}
|
|
*pdata++ = v & 1;
|
|
if (++x == width) {
|
|
x = 0;
|
|
pdata += stride - width;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case IMODE_DIFF6:
|
|
invert_mask = 0;
|
|
/* fall-through */
|
|
case IMODE_NORM6:
|
|
|
|
GST_DEBUG ("Parsing IMODE_DIFF6 or IMODE_NORM6 biplane");
|
|
|
|
if (!(height % 3) && (width % 3)) { /* decode 2x3 "vertical" tiles */
|
|
for (y = 0; y < height; y += 3) {
|
|
for (x = width & 1; x < width; x += 2) {
|
|
if (!decode_vlc (br, &v, vc1_norm6_vlc_table,
|
|
G_N_ELEMENTS (vc1_norm6_vlc_table)))
|
|
goto failed;
|
|
|
|
if (pdata) {
|
|
v ^= invert_mask;
|
|
pdata[x + 0] = v & 1;
|
|
pdata[x + 1] = (v >> 1) & 1;
|
|
pdata[x + 0 + stride] = (v >> 2) & 1;
|
|
pdata[x + 1 + stride] = (v >> 3) & 1;
|
|
pdata[x + 0 + stride * 2] = (v >> 4) & 1;
|
|
pdata[x + 1 + stride * 2] = (v >> 5) & 1;
|
|
}
|
|
}
|
|
if (pdata)
|
|
pdata += 3 * stride;
|
|
}
|
|
|
|
x = width & 1;
|
|
y = 0;
|
|
} else { /* decode 3x2 "horizontal" tiles */
|
|
|
|
if (pdata)
|
|
pdata += (height & 1) * stride;
|
|
for (y = height & 1; y < height; y += 2) {
|
|
for (x = width % 3; x < width; x += 3) {
|
|
if (!decode_vlc (br, &v, vc1_norm6_vlc_table,
|
|
G_N_ELEMENTS (vc1_norm6_vlc_table)))
|
|
goto failed;
|
|
|
|
if (pdata) {
|
|
v ^= invert_mask;
|
|
pdata[x + 0] = v & 1;
|
|
pdata[x + 1] = (v >> 1) & 1;
|
|
pdata[x + 2] = (v >> 2) & 1;
|
|
pdata[x + 0 + stride] = (v >> 3) & 1;
|
|
pdata[x + 1 + stride] = (v >> 4) & 1;
|
|
pdata[x + 2 + stride] = (v >> 5) & 1;
|
|
}
|
|
}
|
|
if (pdata)
|
|
pdata += 2 * stride;
|
|
}
|
|
|
|
x = width % 3;
|
|
y = height & 1;
|
|
}
|
|
|
|
if (x) {
|
|
if (data)
|
|
pdata = data;
|
|
if (!decode_colskip (br, pdata, x, height, stride, invert_mask))
|
|
goto failed;
|
|
}
|
|
|
|
if (y) {
|
|
if (data)
|
|
pdata = data + x;
|
|
if (!decode_rowskip (br, pdata, width - x, y, stride, invert_mask))
|
|
goto failed;
|
|
}
|
|
break;
|
|
case IMODE_ROWSKIP:
|
|
|
|
GST_DEBUG ("Parsing IMODE_ROWSKIP biplane");
|
|
|
|
if (!decode_rowskip (br, data, width, height, stride, invert_mask))
|
|
goto failed;
|
|
break;
|
|
case IMODE_COLSKIP:
|
|
|
|
GST_DEBUG ("Parsing IMODE_COLSKIP biplane");
|
|
|
|
if (!decode_colskip (br, data, width, height, stride, invert_mask))
|
|
goto failed;
|
|
break;
|
|
}
|
|
|
|
if (!data)
|
|
return TRUE;
|
|
|
|
/* Applying diff operator */
|
|
if (imode == IMODE_DIFF2 || imode == IMODE_DIFF6) {
|
|
pdata = data;
|
|
pdata[0] ^= invert;
|
|
|
|
for (x = 1; x < width; x++)
|
|
pdata[x] ^= pdata[x - 1];
|
|
|
|
for (y = 1; y < height; y++) {
|
|
pdata[stride] ^= pdata[0];
|
|
|
|
for (x = 1; x < width; x++) {
|
|
if (pdata[stride + x - 1] != pdata[x])
|
|
pdata[stride + x] ^= invert;
|
|
else
|
|
pdata[stride + x] ^= pdata[stride + x - 1];
|
|
}
|
|
pdata += stride;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
failed:
|
|
GST_WARNING ("Failed to decode bitplane");
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static gboolean
|
|
parse_vopdquant (GstBitReader * br, GstVC1FrameHdr * framehdr, guint8 dquant)
|
|
{
|
|
GstVC1VopDquant *vopdquant = &framehdr->vopdquant;
|
|
|
|
GST_DEBUG ("Parsing vopdquant");
|
|
|
|
vopdquant->dqbilevel = 0;
|
|
|
|
if (dquant == 2) {
|
|
vopdquant->dquantfrm = 0;
|
|
|
|
READ_UINT8 (br, vopdquant->pqdiff, 3);
|
|
|
|
if (vopdquant->pqdiff != 7)
|
|
vopdquant->altpquant = framehdr->pquant + vopdquant->pqdiff + 1;
|
|
else {
|
|
READ_UINT8 (br, vopdquant->abspq, 5);
|
|
vopdquant->altpquant = vopdquant->abspq;
|
|
}
|
|
} else {
|
|
READ_UINT8 (br, vopdquant->dquantfrm, 1);
|
|
GST_DEBUG (" %u DquantFrm %u", gst_bit_reader_get_pos (br),
|
|
vopdquant->dquantfrm);
|
|
|
|
if (vopdquant->dquantfrm) {
|
|
READ_UINT8 (br, vopdquant->dqprofile, 2);
|
|
|
|
switch (vopdquant->dqprofile) {
|
|
case GST_VC1_DQPROFILE_SINGLE_EDGE:
|
|
case GST_VC1_DQPROFILE_DOUBLE_EDGES:
|
|
READ_UINT8 (br, vopdquant->dqbedge, 2);
|
|
break;
|
|
|
|
case GST_VC1_DQPROFILE_ALL_MBS:
|
|
READ_UINT8 (br, vopdquant->dqbilevel, 1);
|
|
break;
|
|
}
|
|
|
|
if (vopdquant->dqbilevel
|
|
|| vopdquant->dqprofile != GST_VC1_DQPROFILE_ALL_MBS) {
|
|
{
|
|
READ_UINT8 (br, vopdquant->pqdiff, 3);
|
|
|
|
if (vopdquant->pqdiff != 7)
|
|
vopdquant->altpquant = framehdr->pquant + vopdquant->pqdiff + 1;
|
|
else {
|
|
READ_UINT8 (br, vopdquant->abspq, 5);
|
|
vopdquant->altpquant = vopdquant->abspq;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
failed:
|
|
GST_WARNING ("Failed to parse vopdquant");
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static inline gint
|
|
scan_for_start_codes (const guint8 * data, guint size)
|
|
{
|
|
GstByteReader br;
|
|
gst_byte_reader_init (&br, data, size);
|
|
|
|
/* NALU not empty, so we can at least expect 1 (even 2) bytes following sc */
|
|
return gst_byte_reader_masked_scan_uint32 (&br, 0xffffff00, 0x00000100,
|
|
0, size);
|
|
}
|
|
|
|
static inline gint
|
|
get_unary (GstBitReader * br, gint stop, gint len)
|
|
{
|
|
int i;
|
|
guint8 current = 0xff;
|
|
|
|
for (i = 0; i < len; i++) {
|
|
current = gst_bit_reader_get_bits_uint8_unchecked (br, 1);
|
|
if (current == stop)
|
|
return i;
|
|
}
|
|
|
|
return i;
|
|
}
|
|
|
|
static inline void
|
|
calculate_framerate_bitrate (guint8 frmrtq_postproc, guint8 bitrtq_postproc,
|
|
guint * framerate, guint * bitrate)
|
|
{
|
|
if (frmrtq_postproc == 0 && bitrtq_postproc == 31) {
|
|
*framerate = 0;
|
|
*bitrate = 0;
|
|
} else if (frmrtq_postproc == 0 && bitrtq_postproc == 30) {
|
|
*framerate = 2;
|
|
*bitrate = 1952;
|
|
} else if (frmrtq_postproc == 1 && bitrtq_postproc == 31) {
|
|
*framerate = 6;
|
|
*bitrate = 2016;
|
|
} else {
|
|
if (frmrtq_postproc == 7) {
|
|
*framerate = 30;
|
|
} else {
|
|
*framerate = 2 + (frmrtq_postproc * 4);
|
|
}
|
|
if (bitrtq_postproc == 31) {
|
|
*bitrate = 2016;
|
|
} else {
|
|
*bitrate = 32 + (bitrtq_postproc * 64);
|
|
}
|
|
}
|
|
}
|
|
|
|
static inline void
|
|
calculate_mb_size (GstVC1SeqHdr * seqhdr, guint width, guint height)
|
|
{
|
|
seqhdr->mb_width = (width + 15) >> 4;
|
|
seqhdr->mb_height = (height + 15) >> 4;
|
|
seqhdr->mb_stride = seqhdr->mb_width + 1;
|
|
}
|
|
|
|
static GstVC1ParserResult
|
|
parse_hrd_param_flag (GstBitReader * br, GstVC1HrdParam * hrd_param)
|
|
{
|
|
guint i;
|
|
|
|
GST_DEBUG ("Parsing Hrd param flag");
|
|
|
|
|
|
if (gst_bit_reader_get_remaining (br) < 13)
|
|
goto failed;
|
|
|
|
hrd_param->hrd_num_leaky_buckets =
|
|
gst_bit_reader_get_bits_uint8_unchecked (br, 5);
|
|
hrd_param->bit_rate_exponent =
|
|
gst_bit_reader_get_bits_uint8_unchecked (br, 4);
|
|
hrd_param->buffer_size_exponent =
|
|
gst_bit_reader_get_bits_uint8_unchecked (br, 4);
|
|
|
|
if (gst_bit_reader_get_remaining (br) <
|
|
(32 * hrd_param->hrd_num_leaky_buckets))
|
|
goto failed;
|
|
|
|
for (i = 0; i < hrd_param->hrd_num_leaky_buckets; i++) {
|
|
hrd_param->hrd_rate[i] = gst_bit_reader_get_bits_uint16_unchecked (br, 16);
|
|
hrd_param->hrd_buffer[i] =
|
|
gst_bit_reader_get_bits_uint16_unchecked (br, 16);
|
|
}
|
|
|
|
return GST_VC1_PARSER_OK;
|
|
|
|
failed:
|
|
GST_WARNING ("Failed to parse hrd param flag");
|
|
|
|
return GST_VC1_PARSER_ERROR;
|
|
}
|
|
|
|
static GstVC1ParserResult
|
|
parse_sequence_header_advanced (GstVC1SeqHdr * seqhdr, GstBitReader * br)
|
|
{
|
|
GstVC1AdvancedSeqHdr *advanced = &seqhdr->advanced;
|
|
guint8 tmp;
|
|
|
|
GST_DEBUG ("Parsing sequence header in advanced mode");
|
|
|
|
READ_UINT8 (br, tmp, 3);
|
|
advanced->level = tmp;
|
|
advanced->par_n = 0;
|
|
advanced->par_d = 0;
|
|
advanced->fps_n = 0;
|
|
advanced->fps_d = 0;
|
|
|
|
READ_UINT8 (br, advanced->colordiff_format, 2);
|
|
READ_UINT8 (br, advanced->frmrtq_postproc, 3);
|
|
READ_UINT8 (br, advanced->bitrtq_postproc, 5);
|
|
|
|
calculate_framerate_bitrate (advanced->frmrtq_postproc,
|
|
advanced->bitrtq_postproc, &advanced->framerate, &advanced->bitrate);
|
|
|
|
GST_DEBUG ("level %u, colordiff_format %u , frmrtq_postproc %u,"
|
|
" bitrtq_postproc %u", advanced->level, advanced->colordiff_format,
|
|
advanced->frmrtq_postproc, advanced->bitrtq_postproc);
|
|
|
|
if (gst_bit_reader_get_remaining (br) < 32)
|
|
goto failed;
|
|
|
|
advanced->postprocflag = gst_bit_reader_get_bits_uint8_unchecked (br, 1);
|
|
advanced->max_coded_width = gst_bit_reader_get_bits_uint16_unchecked (br, 12);
|
|
advanced->max_coded_height =
|
|
gst_bit_reader_get_bits_uint16_unchecked (br, 12);
|
|
advanced->max_coded_width = (advanced->max_coded_width + 1) << 1;
|
|
advanced->max_coded_height = (advanced->max_coded_height + 1) << 1;
|
|
calculate_mb_size (seqhdr, advanced->max_coded_width,
|
|
advanced->max_coded_height);
|
|
advanced->pulldown = gst_bit_reader_get_bits_uint8_unchecked (br, 1);
|
|
advanced->interlace = gst_bit_reader_get_bits_uint8_unchecked (br, 1);
|
|
advanced->tfcntrflag = gst_bit_reader_get_bits_uint8_unchecked (br, 1);
|
|
advanced->finterpflag = gst_bit_reader_get_bits_uint8_unchecked (br, 1);
|
|
|
|
GST_DEBUG ("postprocflag %u, max_coded_width %u, max_coded_height %u,"
|
|
"pulldown %u, interlace %u, tfcntrflag %u, finterpflag %u",
|
|
advanced->postprocflag, advanced->max_coded_width,
|
|
advanced->max_coded_height, advanced->pulldown,
|
|
advanced->interlace, advanced->tfcntrflag, advanced->finterpflag);
|
|
|
|
/* Skipping reserved bit */
|
|
gst_bit_reader_skip_unchecked (br, 1);
|
|
|
|
advanced->psf = gst_bit_reader_get_bits_uint8_unchecked (br, 1);
|
|
advanced->display_ext = gst_bit_reader_get_bits_uint8_unchecked (br, 1);
|
|
if (advanced->display_ext) {
|
|
READ_UINT16 (br, advanced->disp_horiz_size, 14);
|
|
READ_UINT16 (br, advanced->disp_vert_size, 14);
|
|
|
|
advanced->disp_horiz_size++;
|
|
advanced->disp_vert_size++;
|
|
|
|
READ_UINT8 (br, advanced->aspect_ratio_flag, 1);
|
|
|
|
if (advanced->aspect_ratio_flag) {
|
|
READ_UINT8 (br, advanced->aspect_ratio, 4);
|
|
|
|
if (advanced->aspect_ratio == 15) {
|
|
/* Aspect Width (6.1.14.3.2) and Aspect Height (6.1.14.3.3)
|
|
* syntax elements hold a binary encoding of sizes ranging
|
|
* from 1 to 256 */
|
|
READ_UINT8 (br, advanced->aspect_horiz_size, 8);
|
|
READ_UINT8 (br, advanced->aspect_vert_size, 8);
|
|
advanced->par_n = 1 + advanced->aspect_horiz_size;
|
|
advanced->par_d = 1 + advanced->aspect_vert_size;
|
|
} else {
|
|
advanced->par_n = aspect_ratios[advanced->aspect_ratio].par_n;
|
|
advanced->par_d = aspect_ratios[advanced->aspect_ratio].par_d;
|
|
}
|
|
}
|
|
READ_UINT8 (br, advanced->framerate_flag, 1);
|
|
if (advanced->framerate_flag) {
|
|
READ_UINT8 (br, advanced->framerateind, 1);
|
|
|
|
if (!advanced->framerateind) {
|
|
READ_UINT8 (br, advanced->frameratenr, 8);
|
|
READ_UINT8 (br, advanced->frameratedr, 4);
|
|
} else {
|
|
READ_UINT16 (br, advanced->framerateexp, 16);
|
|
}
|
|
if (advanced->frameratenr > 0 &&
|
|
advanced->frameratenr < 8 &&
|
|
advanced->frameratedr > 0 && advanced->frameratedr < 3) {
|
|
advanced->fps_n = framerates_n[advanced->frameratenr];
|
|
advanced->fps_d = framerates_d[advanced->frameratedr];
|
|
} else {
|
|
advanced->fps_n = advanced->framerateexp + 1;
|
|
advanced->fps_d = 32;
|
|
}
|
|
}
|
|
READ_UINT8 (br, advanced->color_format_flag, 1);
|
|
|
|
if (advanced->color_format_flag) {
|
|
if (gst_bit_reader_get_remaining (br) < 24)
|
|
goto failed;
|
|
|
|
advanced->color_prim = gst_bit_reader_get_bits_uint8_unchecked (br, 8);
|
|
advanced->transfer_char = gst_bit_reader_get_bits_uint8_unchecked (br, 8);
|
|
advanced->matrix_coef = gst_bit_reader_get_bits_uint8_unchecked (br, 8);
|
|
}
|
|
}
|
|
READ_UINT8 (br, advanced->hrd_param_flag, 1);
|
|
if (advanced->hrd_param_flag)
|
|
return parse_hrd_param_flag (br, &advanced->hrd_param);
|
|
|
|
return GST_VC1_PARSER_OK;
|
|
|
|
failed:
|
|
GST_WARNING ("Failed to parse advanced headers");
|
|
|
|
return GST_VC1_PARSER_ERROR;
|
|
}
|
|
|
|
static GstVC1ParserResult
|
|
parse_frame_header_advanced (GstBitReader * br, GstVC1FrameHdr * framehdr,
|
|
GstVC1SeqHdr * seqhdr, GstVC1BitPlanes * bitplanes, gboolean field2)
|
|
{
|
|
GstVC1AdvancedSeqHdr *advhdr = &seqhdr->advanced;
|
|
GstVC1PicAdvanced *pic = &framehdr->pic.advanced;
|
|
GstVC1EntryPointHdr *entrypthdr = &advhdr->entrypoint;
|
|
guint8 mvmodeidx;
|
|
|
|
GST_DEBUG ("Parsing Frame header advanced %u", advhdr->interlace);
|
|
|
|
/* Set the conveninence fields */
|
|
framehdr->profile = seqhdr->profile;
|
|
framehdr->dquant = entrypthdr->dquant;
|
|
|
|
if (advhdr->interlace) {
|
|
gint8 fcm = decode012 (br);
|
|
|
|
if (fcm < 0)
|
|
goto failed;
|
|
|
|
pic->fcm = (guint8) fcm;
|
|
} else
|
|
pic->fcm = GST_VC1_FRAME_PROGRESSIVE;
|
|
|
|
if (pic->fcm == GST_VC1_FIELD_INTERLACE) {
|
|
READ_UINT8 (br, pic->fptype, 3);
|
|
if (field2) {
|
|
switch (pic->fptype) {
|
|
case 0x00:
|
|
case 0x02:
|
|
framehdr->ptype = GST_VC1_PICTURE_TYPE_I;
|
|
break;
|
|
case 0x01:
|
|
case 0x03:
|
|
framehdr->ptype = GST_VC1_PICTURE_TYPE_P;
|
|
break;
|
|
case 0x04:
|
|
case 0x06:
|
|
framehdr->ptype = GST_VC1_PICTURE_TYPE_B;
|
|
break;
|
|
case 0x05:
|
|
case 0x07:
|
|
framehdr->ptype = GST_VC1_PICTURE_TYPE_BI;
|
|
break;
|
|
}
|
|
} else {
|
|
switch (pic->fptype) {
|
|
case 0x00:
|
|
case 0x01:
|
|
framehdr->ptype = GST_VC1_PICTURE_TYPE_I;
|
|
break;
|
|
case 0x02:
|
|
case 0x03:
|
|
framehdr->ptype = GST_VC1_PICTURE_TYPE_P;
|
|
break;
|
|
case 0x04:
|
|
case 0x05:
|
|
framehdr->ptype = GST_VC1_PICTURE_TYPE_B;
|
|
break;
|
|
case 0x06:
|
|
case 0x07:
|
|
framehdr->ptype = GST_VC1_PICTURE_TYPE_BI;
|
|
break;
|
|
}
|
|
}
|
|
} else
|
|
framehdr->ptype = (guint8) get_unary (br, 0, 4);
|
|
|
|
if (advhdr->tfcntrflag) {
|
|
READ_UINT8 (br, pic->tfcntr, 8);
|
|
GST_DEBUG ("tfcntr %u", pic->tfcntr);
|
|
}
|
|
|
|
if (advhdr->pulldown) {
|
|
if (!advhdr->interlace || advhdr->psf) {
|
|
|
|
READ_UINT8 (br, pic->rptfrm, 2);
|
|
GST_DEBUG ("rptfrm %u", pic->rptfrm);
|
|
|
|
} else {
|
|
|
|
READ_UINT8 (br, pic->tff, 1);
|
|
READ_UINT8 (br, pic->rff, 1);
|
|
GST_DEBUG ("tff %u, rff %u", pic->tff, pic->rff);
|
|
}
|
|
}
|
|
|
|
if (entrypthdr->panscan_flag) {
|
|
READ_UINT8 (br, pic->ps_present, 1);
|
|
|
|
if (pic->ps_present) {
|
|
guint i, nb_pan_scan_win = calculate_nb_pan_scan_win (advhdr, pic);
|
|
|
|
if (gst_bit_reader_get_remaining (br) < 64 * nb_pan_scan_win)
|
|
goto failed;
|
|
|
|
for (i = 0; i < nb_pan_scan_win; i++) {
|
|
pic->ps_hoffset = gst_bit_reader_get_bits_uint32_unchecked (br, 18);
|
|
pic->ps_voffset = gst_bit_reader_get_bits_uint32_unchecked (br, 18);
|
|
pic->ps_width = gst_bit_reader_get_bits_uint16_unchecked (br, 14);
|
|
pic->ps_height = gst_bit_reader_get_bits_uint16_unchecked (br, 14);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (framehdr->ptype == GST_VC1_PICTURE_TYPE_SKIPPED)
|
|
return GST_VC1_PARSER_OK;
|
|
|
|
READ_UINT8 (br, pic->rndctrl, 1);
|
|
|
|
if (advhdr->interlace) {
|
|
READ_UINT8 (br, pic->uvsamp, 1);
|
|
GST_DEBUG ("uvsamp %u", pic->uvsamp);
|
|
if (pic->fcm == GST_VC1_FIELD_INTERLACE && entrypthdr->refdist_flag &&
|
|
pic->fptype < 4)
|
|
decode_refdist (br, &pic->refdist);
|
|
else
|
|
pic->refdist = 0;
|
|
}
|
|
|
|
if (advhdr->finterpflag) {
|
|
READ_UINT8 (br, framehdr->interpfrm, 1);
|
|
GST_DEBUG ("interpfrm %u", framehdr->interpfrm);
|
|
}
|
|
|
|
if ((pic->fcm != GST_VC1_FIELD_INTERLACE &&
|
|
framehdr->ptype == GST_VC1_PICTURE_TYPE_B) ||
|
|
(pic->fcm == GST_VC1_FIELD_INTERLACE && (pic->fptype > 4))) {
|
|
|
|
guint bfraction;
|
|
|
|
if (!decode_vlc (br, &bfraction, vc1_bfraction_vlc_table,
|
|
G_N_ELEMENTS (vc1_bfraction_vlc_table)))
|
|
goto failed;
|
|
|
|
pic->bfraction = bfraction;
|
|
GST_DEBUG ("bfraction %u", pic->bfraction);
|
|
|
|
if (pic->bfraction == GST_VC1_BFRACTION_PTYPE_BI) {
|
|
framehdr->ptype = GST_VC1_PICTURE_TYPE_BI;
|
|
}
|
|
|
|
}
|
|
|
|
READ_UINT8 (br, framehdr->pqindex, 5);
|
|
if (!framehdr->pqindex)
|
|
goto failed;
|
|
|
|
/* compute pquant */
|
|
if (entrypthdr->quantizer == GST_VC1_QUANTIZER_IMPLICITLY)
|
|
framehdr->pquant = vc1_pquant_table[0][framehdr->pqindex];
|
|
else
|
|
framehdr->pquant = vc1_pquant_table[1][framehdr->pqindex];
|
|
|
|
framehdr->pquantizer = 1;
|
|
if (entrypthdr->quantizer == GST_VC1_QUANTIZER_IMPLICITLY)
|
|
framehdr->pquantizer = framehdr->pqindex < 9;
|
|
if (entrypthdr->quantizer == GST_VC1_QUANTIZER_NON_UNIFORM)
|
|
framehdr->pquantizer = 0;
|
|
|
|
if (framehdr->pqindex <= 8)
|
|
READ_UINT8 (br, framehdr->halfqp, 1);
|
|
else
|
|
framehdr->halfqp = 0;
|
|
|
|
if (entrypthdr->quantizer == GST_VC1_QUANTIZER_EXPLICITLY) {
|
|
READ_UINT8 (br, framehdr->pquantizer, 1);
|
|
}
|
|
|
|
if (advhdr->postprocflag)
|
|
READ_UINT8 (br, pic->postproc, 2);
|
|
|
|
GST_DEBUG ("Parsing %u picture, pqindex %u, pquant %u pquantizer %u"
|
|
"halfqp %u", framehdr->ptype, framehdr->pqindex, framehdr->pquant,
|
|
framehdr->pquantizer, framehdr->halfqp);
|
|
|
|
switch (framehdr->ptype) {
|
|
case GST_VC1_PICTURE_TYPE_I:
|
|
case GST_VC1_PICTURE_TYPE_BI:
|
|
if (pic->fcm == GST_VC1_FRAME_INTERLACE) {
|
|
if (!bitplane_decoding (br, bitplanes ? bitplanes->fieldtx : NULL,
|
|
seqhdr, &pic->fieldtx))
|
|
goto failed;
|
|
}
|
|
|
|
if (!bitplane_decoding (br, bitplanes ? bitplanes->acpred : NULL,
|
|
seqhdr, &pic->acpred))
|
|
goto failed;
|
|
|
|
if (entrypthdr->overlap && framehdr->pquant <= 8) {
|
|
pic->condover = decode012 (br);
|
|
|
|
if (pic->condover == (guint8) - 1)
|
|
goto failed;
|
|
|
|
else if (pic->condover == GST_VC1_CONDOVER_SELECT) {
|
|
if (!bitplane_decoding (br, bitplanes ? bitplanes->overflags : NULL,
|
|
seqhdr, &pic->overflags))
|
|
goto failed;
|
|
|
|
GST_DEBUG ("overflags %u", pic->overflags);
|
|
}
|
|
}
|
|
|
|
framehdr->transacfrm = get_unary (br, 0, 2);
|
|
pic->transacfrm2 = get_unary (br, 0, 2);
|
|
READ_UINT8 (br, framehdr->transdctab, 1);
|
|
|
|
if (framehdr->dquant)
|
|
parse_vopdquant (br, framehdr, framehdr->dquant);
|
|
|
|
GST_DEBUG
|
|
("acpred %u, condover %u, transacfrm %u, transacfrm2 %u, transdctab %u",
|
|
pic->acpred, pic->condover, framehdr->transacfrm, pic->transacfrm2,
|
|
framehdr->transdctab);
|
|
break;
|
|
|
|
case GST_VC1_PICTURE_TYPE_B:
|
|
if (entrypthdr->extended_mv)
|
|
pic->mvrange = get_unary (br, 0, 3);
|
|
else
|
|
pic->mvrange = 0;
|
|
|
|
if (pic->fcm != GST_VC1_FRAME_PROGRESSIVE) {
|
|
if (entrypthdr->extended_dmv)
|
|
pic->dmvrange = get_unary (br, 0, 3);
|
|
}
|
|
|
|
if (pic->fcm == GST_VC1_FRAME_INTERLACE)
|
|
READ_UINT8 (br, pic->intcomp, 1);
|
|
else
|
|
READ_UINT8 (br, pic->mvmode, 1);
|
|
|
|
if (pic->fcm == GST_VC1_FIELD_INTERLACE) {
|
|
|
|
if (!bitplane_decoding (br, bitplanes ? bitplanes->forwardmb : NULL,
|
|
seqhdr, &pic->forwardmb))
|
|
goto failed;
|
|
|
|
} else {
|
|
if (!bitplane_decoding (br, bitplanes ? bitplanes->directmb : NULL,
|
|
seqhdr, &pic->directmb))
|
|
goto failed;
|
|
|
|
if (!bitplane_decoding (br, bitplanes ? bitplanes->skipmb : NULL,
|
|
seqhdr, &pic->skipmb))
|
|
goto failed;
|
|
}
|
|
|
|
if (pic->fcm != GST_VC1_FRAME_PROGRESSIVE) {
|
|
if (gst_bit_reader_get_remaining (br) < 7)
|
|
goto failed;
|
|
|
|
pic->mbmodetab = gst_bit_reader_get_bits_uint8_unchecked (br, 2);
|
|
pic->imvtab = gst_bit_reader_get_bits_uint8_unchecked (br, 2);
|
|
pic->icbptab = gst_bit_reader_get_bits_uint8_unchecked (br, 3);
|
|
|
|
if (pic->fcm == GST_VC1_FRAME_INTERLACE)
|
|
READ_UINT8 (br, pic->mvbptab2, 2);
|
|
|
|
if (pic->fcm == GST_VC1_FRAME_INTERLACE ||
|
|
(pic->fcm == GST_VC1_FIELD_INTERLACE
|
|
&& pic->mvmode == GST_VC1_MVMODE_MIXED_MV))
|
|
READ_UINT8 (br, pic->mvbptab4, 2);
|
|
|
|
} else {
|
|
READ_UINT8 (br, pic->mvtab, 2);
|
|
READ_UINT8 (br, pic->cbptab, 2);
|
|
}
|
|
|
|
if (framehdr->dquant) {
|
|
parse_vopdquant (br, framehdr, framehdr->dquant);
|
|
}
|
|
|
|
if (entrypthdr->vstransform) {
|
|
READ_UINT8 (br, pic->ttmbf, 1);
|
|
|
|
if (pic->ttmbf) {
|
|
READ_UINT8 (br, pic->ttfrm, 2);
|
|
}
|
|
}
|
|
|
|
framehdr->transacfrm = get_unary (br, 0, 2);
|
|
READ_UINT8 (br, framehdr->transdctab, 1);
|
|
|
|
GST_DEBUG ("transacfrm %u transdctab %u mvmode %u mvtab %u,"
|
|
"cbptab %u directmb %u skipmb %u", framehdr->transacfrm,
|
|
framehdr->transdctab, pic->mvmode, pic->mvtab, pic->cbptab,
|
|
pic->directmb, pic->skipmb);
|
|
|
|
break;
|
|
case GST_VC1_PICTURE_TYPE_P:
|
|
if (pic->fcm == GST_VC1_FIELD_INTERLACE) {
|
|
READ_UINT8 (br, pic->numref, 1);
|
|
|
|
if (pic->numref)
|
|
READ_UINT8 (br, pic->reffield, 1);
|
|
}
|
|
|
|
if (entrypthdr->extended_mv)
|
|
pic->mvrange = get_unary (br, 0, 3);
|
|
else
|
|
pic->mvrange = 0;
|
|
|
|
if (pic->fcm != GST_VC1_FRAME_PROGRESSIVE) {
|
|
if (entrypthdr->extended_dmv)
|
|
pic->dmvrange = get_unary (br, 0, 3);
|
|
}
|
|
|
|
if (pic->fcm == GST_VC1_FRAME_INTERLACE) {
|
|
READ_UINT8 (br, pic->mvswitch4, 1);
|
|
READ_UINT8 (br, pic->intcomp, 1);
|
|
|
|
if (pic->intcomp) {
|
|
READ_UINT8 (br, pic->lumscale, 6);
|
|
READ_UINT8 (br, pic->lumshift, 6);
|
|
}
|
|
} else {
|
|
|
|
mvmodeidx = framehdr->pquant > 12;
|
|
pic->mvmode = vc1_mvmode_table[mvmodeidx][get_unary (br, 1, 4)];
|
|
|
|
if (pic->mvmode == GST_VC1_MVMODE_INTENSITY_COMP) {
|
|
pic->mvmode2 = vc1_mvmode2_table[mvmodeidx][get_unary (br, 1, 3)];
|
|
|
|
if (pic->fcm == GST_VC1_FIELD_INTERLACE)
|
|
pic->intcompfield = decode012 (br);
|
|
|
|
READ_UINT8 (br, pic->lumscale, 6);
|
|
READ_UINT8 (br, pic->lumshift, 6);
|
|
GST_DEBUG ("lumscale %u lumshift %u", pic->lumscale, pic->lumshift);
|
|
|
|
if (pic->fcm == GST_VC1_FIELD_INTERLACE && pic->intcompfield) {
|
|
READ_UINT8 (br, pic->lumscale2, 6);
|
|
READ_UINT8 (br, pic->lumshift2, 6);
|
|
}
|
|
}
|
|
|
|
if (pic->fcm == GST_VC1_FRAME_PROGRESSIVE) {
|
|
if (pic->mvmode == GST_VC1_MVMODE_MIXED_MV ||
|
|
(pic->mvmode == GST_VC1_MVMODE_INTENSITY_COMP &&
|
|
pic->mvmode2 == GST_VC1_MVMODE_MIXED_MV)) {
|
|
|
|
if (!bitplane_decoding (br, bitplanes ? bitplanes->mvtypemb : NULL,
|
|
seqhdr, &pic->mvtypemb))
|
|
goto failed;
|
|
|
|
GST_DEBUG ("mvtypemb %u", pic->mvtypemb);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pic->fcm != GST_VC1_FIELD_INTERLACE) {
|
|
if (!bitplane_decoding (br, bitplanes ? bitplanes->skipmb : NULL,
|
|
seqhdr, &pic->skipmb))
|
|
goto failed;
|
|
}
|
|
|
|
if (pic->fcm != GST_VC1_FRAME_PROGRESSIVE) {
|
|
if (gst_bit_reader_get_remaining (br) < 7)
|
|
goto failed;
|
|
|
|
pic->mbmodetab = gst_bit_reader_get_bits_uint8_unchecked (br, 2);
|
|
pic->imvtab = gst_bit_reader_get_bits_uint8_unchecked (br, 2);
|
|
pic->icbptab = gst_bit_reader_get_bits_uint8_unchecked (br, 3);
|
|
|
|
if (pic->fcm != GST_VC1_FIELD_INTERLACE) {
|
|
READ_UINT8 (br, pic->mvbptab2, 2);
|
|
|
|
if (pic->mvswitch4)
|
|
READ_UINT8 (br, pic->mvbptab4, 2);
|
|
|
|
} else if (pic->mvmode == GST_VC1_MVMODE_MIXED_MV)
|
|
READ_UINT8 (br, pic->mvbptab4, 2);
|
|
|
|
} else {
|
|
if (gst_bit_reader_get_remaining (br) < 4)
|
|
goto failed;
|
|
pic->mvtab = gst_bit_reader_get_bits_uint8_unchecked (br, 2);
|
|
pic->cbptab = gst_bit_reader_get_bits_uint8_unchecked (br, 2);
|
|
}
|
|
|
|
if (framehdr->dquant) {
|
|
parse_vopdquant (br, framehdr, framehdr->dquant);
|
|
}
|
|
|
|
if (entrypthdr->vstransform) {
|
|
READ_UINT8 (br, pic->ttmbf, 1);
|
|
|
|
if (pic->ttmbf) {
|
|
READ_UINT8 (br, pic->ttfrm, 2);
|
|
}
|
|
}
|
|
|
|
framehdr->transacfrm = get_unary (br, 0, 2);
|
|
READ_UINT8 (br, framehdr->transdctab, 1);
|
|
|
|
GST_DEBUG ("transacfrm %u transdctab %u mvmode %u mvtab %u,"
|
|
"cbptab %u skipmb %u", framehdr->transacfrm, framehdr->transdctab,
|
|
pic->mvmode, pic->mvtab, pic->cbptab, pic->skipmb);
|
|
|
|
break;
|
|
|
|
default:
|
|
goto failed;
|
|
break;
|
|
}
|
|
|
|
return GST_VC1_PARSER_OK;
|
|
|
|
failed:
|
|
GST_WARNING ("Failed to parse frame header");
|
|
|
|
return GST_VC1_PARSER_ERROR;
|
|
}
|
|
|
|
static GstVC1ParserResult
|
|
parse_frame_header (GstBitReader * br, GstVC1FrameHdr * framehdr,
|
|
GstVC1SeqHdr * seqhdr, GstVC1BitPlanes * bitplanes)
|
|
{
|
|
guint8 mvmodeidx, tmp;
|
|
GstVC1PicSimpleMain *pic = &framehdr->pic.simple;
|
|
GstVC1SeqStructC *structc = &seqhdr->struct_c;
|
|
|
|
GST_DEBUG ("Parsing frame header in simple or main mode");
|
|
|
|
/* Set the conveninence fields */
|
|
framehdr->profile = seqhdr->profile;
|
|
framehdr->dquant = structc->dquant;
|
|
|
|
framehdr->interpfrm = 0;
|
|
if (structc->finterpflag)
|
|
READ_UINT8 (br, framehdr->interpfrm, 1);
|
|
|
|
READ_UINT8 (br, pic->frmcnt, 2);
|
|
|
|
pic->rangeredfrm = 0;
|
|
if (structc->rangered) {
|
|
READ_UINT8 (br, pic->rangeredfrm, 1);
|
|
}
|
|
|
|
/* Figuring out the picture type */
|
|
READ_UINT8 (br, tmp, 1);
|
|
framehdr->ptype = tmp;
|
|
|
|
if (structc->maxbframes) {
|
|
if (!framehdr->ptype) {
|
|
READ_UINT8 (br, tmp, 1);
|
|
|
|
if (tmp)
|
|
framehdr->ptype = GST_VC1_PICTURE_TYPE_I;
|
|
else
|
|
framehdr->ptype = GST_VC1_PICTURE_TYPE_B;
|
|
|
|
} else
|
|
framehdr->ptype = GST_VC1_PICTURE_TYPE_P;
|
|
|
|
} else {
|
|
if (framehdr->ptype)
|
|
framehdr->ptype = GST_VC1_PICTURE_TYPE_P;
|
|
else
|
|
framehdr->ptype = GST_VC1_PICTURE_TYPE_I;
|
|
}
|
|
|
|
|
|
if (framehdr->ptype == GST_VC1_PICTURE_TYPE_B) {
|
|
guint bfraction;
|
|
if (!decode_vlc (br, &bfraction, vc1_bfraction_vlc_table,
|
|
G_N_ELEMENTS (vc1_bfraction_vlc_table)))
|
|
goto failed;
|
|
|
|
pic->bfraction = bfraction;
|
|
GST_DEBUG ("bfraction %d", pic->bfraction);
|
|
|
|
if (pic->bfraction == GST_VC1_BFRACTION_PTYPE_BI) {
|
|
framehdr->ptype = GST_VC1_PICTURE_TYPE_BI;
|
|
}
|
|
}
|
|
|
|
if (framehdr->ptype == GST_VC1_PICTURE_TYPE_I ||
|
|
framehdr->ptype == GST_VC1_PICTURE_TYPE_BI)
|
|
READ_UINT8 (br, pic->bf, 7);
|
|
|
|
READ_UINT8 (br, framehdr->pqindex, 5);
|
|
if (!framehdr->pqindex)
|
|
return GST_VC1_PARSER_ERROR;
|
|
|
|
GST_DEBUG ("pqindex %u", framehdr->pqindex);
|
|
|
|
/* compute pquant */
|
|
if (structc->quantizer == GST_VC1_QUANTIZER_IMPLICITLY)
|
|
framehdr->pquant = vc1_pquant_table[0][framehdr->pqindex];
|
|
else
|
|
framehdr->pquant = vc1_pquant_table[1][framehdr->pqindex];
|
|
|
|
GST_DEBUG ("pquant %u", framehdr->pquant);
|
|
|
|
if (framehdr->pqindex <= 8)
|
|
READ_UINT8 (br, framehdr->halfqp, 1);
|
|
else
|
|
framehdr->halfqp = 0;
|
|
|
|
/* Set pquantizer */
|
|
framehdr->pquantizer = 1;
|
|
if (structc->quantizer == GST_VC1_QUANTIZER_IMPLICITLY)
|
|
framehdr->pquantizer = framehdr->pqindex < 9;
|
|
else if (structc->quantizer == GST_VC1_QUANTIZER_NON_UNIFORM)
|
|
framehdr->pquantizer = 0;
|
|
|
|
if (structc->quantizer == GST_VC1_QUANTIZER_EXPLICITLY)
|
|
READ_UINT8 (br, framehdr->pquantizer, 1);
|
|
|
|
if (structc->extended_mv == 1) {
|
|
pic->mvrange = get_unary (br, 0, 3);
|
|
GST_DEBUG ("mvrange %u", pic->mvrange);
|
|
}
|
|
|
|
if (structc->multires && (framehdr->ptype == GST_VC1_PICTURE_TYPE_P ||
|
|
framehdr->ptype == GST_VC1_PICTURE_TYPE_I)) {
|
|
READ_UINT8 (br, pic->respic, 2);
|
|
GST_DEBUG ("Respic %u", pic->respic);
|
|
}
|
|
|
|
GST_DEBUG ("Parsing %u Frame, pquantizer %u, halfqp %u, rangeredfrm %u, "
|
|
"interpfrm %u", framehdr->ptype, framehdr->pquantizer, framehdr->halfqp,
|
|
pic->rangeredfrm, framehdr->interpfrm);
|
|
|
|
switch (framehdr->ptype) {
|
|
case GST_VC1_PICTURE_TYPE_I:
|
|
case GST_VC1_PICTURE_TYPE_BI:
|
|
framehdr->transacfrm = get_unary (br, 0, 2);
|
|
pic->transacfrm2 = get_unary (br, 0, 2);
|
|
READ_UINT8 (br, framehdr->transdctab, 1);
|
|
|
|
GST_DEBUG ("transacfrm %u, transacfrm2 %u, transdctab %u",
|
|
framehdr->transacfrm, pic->transacfrm2, framehdr->transdctab);
|
|
break;
|
|
|
|
case GST_VC1_PICTURE_TYPE_P:
|
|
mvmodeidx = framehdr->pquant > 12;
|
|
pic->mvmode = vc1_mvmode_table[mvmodeidx][get_unary (br, 1, 4)];
|
|
|
|
if (pic->mvmode == GST_VC1_MVMODE_INTENSITY_COMP) {
|
|
pic->mvmode2 = vc1_mvmode2_table[mvmodeidx][get_unary (br, 1, 3)];
|
|
READ_UINT8 (br, pic->lumscale, 6);
|
|
READ_UINT8 (br, pic->lumshift, 6);
|
|
GST_DEBUG ("lumscale %u lumshift %u", pic->lumscale, pic->lumshift);
|
|
}
|
|
|
|
if (pic->mvmode == GST_VC1_MVMODE_MIXED_MV ||
|
|
(pic->mvmode == GST_VC1_MVMODE_INTENSITY_COMP &&
|
|
pic->mvmode2 == GST_VC1_MVMODE_MIXED_MV)) {
|
|
if (!bitplane_decoding (br, bitplanes ? bitplanes->mvtypemb : NULL,
|
|
seqhdr, &pic->mvtypemb))
|
|
goto failed;
|
|
GST_DEBUG ("mvtypemb %u", pic->mvtypemb);
|
|
}
|
|
if (!bitplane_decoding (br, bitplanes ? bitplanes->skipmb : NULL,
|
|
seqhdr, &pic->skipmb))
|
|
goto failed;
|
|
|
|
READ_UINT8 (br, pic->mvtab, 2);
|
|
READ_UINT8 (br, pic->cbptab, 2);
|
|
|
|
if (framehdr->dquant) {
|
|
parse_vopdquant (br, framehdr, framehdr->dquant);
|
|
}
|
|
|
|
if (structc->vstransform) {
|
|
READ_UINT8 (br, pic->ttmbf, 1);
|
|
GST_DEBUG ("ttmbf %u", pic->ttmbf);
|
|
|
|
if (pic->ttmbf) {
|
|
READ_UINT8 (br, pic->ttfrm, 2);
|
|
GST_DEBUG ("ttfrm %u", pic->ttfrm);
|
|
}
|
|
}
|
|
|
|
framehdr->transacfrm = get_unary (br, 0, 2);
|
|
READ_UINT8 (br, framehdr->transdctab, 1);
|
|
|
|
GST_DEBUG ("transacfrm %u transdctab %u mvmode %u mvtab %u,"
|
|
"cbptab %u skipmb %u", framehdr->transacfrm, framehdr->transdctab,
|
|
pic->mvmode, pic->mvtab, pic->cbptab, pic->skipmb);
|
|
break;
|
|
|
|
case GST_VC1_PICTURE_TYPE_B:
|
|
READ_UINT8 (br, pic->mvmode, 1);
|
|
if (!bitplane_decoding (br, bitplanes ? bitplanes->directmb : NULL,
|
|
seqhdr, &pic->directmb))
|
|
goto failed;
|
|
|
|
if (!bitplane_decoding (br, bitplanes ? bitplanes->skipmb : NULL,
|
|
seqhdr, &pic->skipmb))
|
|
goto failed;
|
|
|
|
READ_UINT8 (br, pic->mvtab, 2);
|
|
READ_UINT8 (br, pic->cbptab, 2);
|
|
|
|
if (framehdr->dquant)
|
|
parse_vopdquant (br, framehdr, framehdr->dquant);
|
|
|
|
if (structc->vstransform) {
|
|
READ_UINT8 (br, pic->ttmbf, 1);
|
|
|
|
if (pic->ttmbf) {
|
|
READ_UINT8 (br, pic->ttfrm, 2);
|
|
}
|
|
}
|
|
|
|
framehdr->transacfrm = get_unary (br, 0, 2);
|
|
READ_UINT8 (br, framehdr->transdctab, 1);
|
|
|
|
GST_DEBUG ("transacfrm %u transdctab %u mvmode %u mvtab %u,"
|
|
"cbptab %u directmb %u skipmb %u", framehdr->transacfrm,
|
|
framehdr->transdctab, pic->mvmode, pic->mvtab, pic->cbptab,
|
|
pic->directmb, pic->skipmb);
|
|
|
|
break;
|
|
|
|
default:
|
|
goto failed;
|
|
break;
|
|
}
|
|
|
|
return GST_VC1_PARSER_OK;
|
|
|
|
failed:
|
|
GST_WARNING ("Failed to parse Simple picture header");
|
|
|
|
return GST_VC1_PARSER_ERROR;
|
|
}
|
|
|
|
static GstVC1ParserResult
|
|
parse_sequence_header_struct_a (GstBitReader * br, GstVC1SeqStructA * structa)
|
|
{
|
|
if (gst_bit_reader_get_remaining (br) < 64) {
|
|
GST_WARNING ("Failed to parse struct A");
|
|
|
|
return GST_VC1_PARSER_ERROR;
|
|
}
|
|
|
|
structa->vert_size = gst_bit_reader_get_bits_uint32_unchecked (br, 32);
|
|
structa->horiz_size = gst_bit_reader_get_bits_uint32_unchecked (br, 32);
|
|
|
|
return GST_VC1_PARSER_OK;
|
|
}
|
|
|
|
static GstVC1ParserResult
|
|
parse_sequence_header_struct_b (GstBitReader * br, GstVC1SeqStructB * structb)
|
|
{
|
|
if (gst_bit_reader_get_remaining (br) < 96) {
|
|
GST_WARNING ("Failed to parse sequence header");
|
|
|
|
return GST_VC1_PARSER_ERROR;
|
|
}
|
|
|
|
structb->level = gst_bit_reader_get_bits_uint8_unchecked (br, 3);
|
|
structb->cbr = gst_bit_reader_get_bits_uint8_unchecked (br, 1);
|
|
|
|
/* res4 */
|
|
gst_bit_reader_skip_unchecked (br, 4);
|
|
|
|
structb->hrd_buffer = gst_bit_reader_get_bits_uint32_unchecked (br, 24);
|
|
structb->hrd_rate = gst_bit_reader_get_bits_uint32_unchecked (br, 32);
|
|
structb->framerate = gst_bit_reader_get_bits_uint32_unchecked (br, 32);
|
|
|
|
return GST_VC1_PARSER_OK;
|
|
}
|
|
|
|
static GstVC1ParserResult
|
|
parse_sequence_header_struct_c (GstBitReader * br, GstVC1SeqStructC * structc)
|
|
{
|
|
guint8 old_interlaced_mode, tmp;
|
|
|
|
READ_UINT8 (br, tmp, 2);
|
|
structc->profile = tmp;
|
|
|
|
if (structc->profile == GST_VC1_PROFILE_ADVANCED)
|
|
return GST_VC1_PARSER_OK;
|
|
|
|
GST_DEBUG ("Parsing sequence header in simple or main mode");
|
|
|
|
if (gst_bit_reader_get_remaining (br) < 29)
|
|
goto failed;
|
|
|
|
/* Reserved bits */
|
|
old_interlaced_mode = gst_bit_reader_get_bits_uint8_unchecked (br, 1);
|
|
if (old_interlaced_mode)
|
|
GST_WARNING ("Old interlaced mode used");
|
|
|
|
structc->wmvp = gst_bit_reader_get_bits_uint8_unchecked (br, 1);
|
|
if (structc->wmvp)
|
|
GST_DEBUG ("WMVP mode");
|
|
|
|
structc->frmrtq_postproc = gst_bit_reader_get_bits_uint8_unchecked (br, 3);
|
|
structc->bitrtq_postproc = gst_bit_reader_get_bits_uint8_unchecked (br, 5);
|
|
structc->loop_filter = gst_bit_reader_get_bits_uint8_unchecked (br, 1);
|
|
|
|
calculate_framerate_bitrate (structc->frmrtq_postproc,
|
|
structc->bitrtq_postproc, &structc->framerate, &structc->bitrate);
|
|
|
|
/* Skipping reserved3 bit */
|
|
gst_bit_reader_skip_unchecked (br, 1);
|
|
|
|
structc->multires = gst_bit_reader_get_bits_uint8_unchecked (br, 1);
|
|
|
|
/* Skipping reserved4 bit */
|
|
gst_bit_reader_skip_unchecked (br, 1);
|
|
|
|
structc->fastuvmc = gst_bit_reader_get_bits_uint8_unchecked (br, 1);
|
|
structc->extended_mv = gst_bit_reader_get_bits_uint8_unchecked (br, 1);
|
|
structc->dquant = gst_bit_reader_get_bits_uint8_unchecked (br, 2);
|
|
structc->vstransform = gst_bit_reader_get_bits_uint8_unchecked (br, 1);
|
|
|
|
/* Skipping reserved5 bit */
|
|
gst_bit_reader_skip_unchecked (br, 1);
|
|
|
|
structc->overlap = gst_bit_reader_get_bits_uint8_unchecked (br, 1);
|
|
structc->syncmarker = gst_bit_reader_get_bits_uint8_unchecked (br, 1);
|
|
structc->rangered = gst_bit_reader_get_bits_uint8_unchecked (br, 1);
|
|
structc->maxbframes = gst_bit_reader_get_bits_uint8_unchecked (br, 3);
|
|
structc->quantizer = gst_bit_reader_get_bits_uint8_unchecked (br, 2);
|
|
structc->finterpflag = gst_bit_reader_get_bits_uint8_unchecked (br, 1);
|
|
|
|
GST_DEBUG ("frmrtq_postproc %u, bitrtq_postproc %u, loop_filter %u, "
|
|
"multires %u, fastuvmc %u, extended_mv %u, dquant %u, vstransform %u, "
|
|
"overlap %u, syncmarker %u, rangered %u, maxbframes %u, quantizer %u, "
|
|
"finterpflag %u", structc->frmrtq_postproc, structc->bitrtq_postproc,
|
|
structc->loop_filter, structc->multires, structc->fastuvmc,
|
|
structc->extended_mv, structc->dquant, structc->vstransform,
|
|
structc->overlap, structc->syncmarker, structc->rangered,
|
|
structc->maxbframes, structc->quantizer, structc->finterpflag);
|
|
|
|
if (structc->wmvp) {
|
|
if (gst_bit_reader_get_remaining (br) < 29)
|
|
goto failed;
|
|
|
|
structc->coded_width = gst_bit_reader_get_bits_uint16_unchecked (br, 11);
|
|
structc->coded_height = gst_bit_reader_get_bits_uint16_unchecked (br, 11);
|
|
structc->framerate = gst_bit_reader_get_bits_uint8_unchecked (br, 5);
|
|
gst_bit_reader_skip_unchecked (br, 1);
|
|
structc->slice_code = gst_bit_reader_get_bits_uint8_unchecked (br, 1);
|
|
|
|
GST_DEBUG ("coded_width %u, coded_height %u, framerate %u slice_code %u",
|
|
structc->coded_width, structc->coded_height, structc->framerate,
|
|
structc->slice_code);
|
|
}
|
|
|
|
return GST_VC1_PARSER_OK;
|
|
|
|
failed:
|
|
GST_WARNING ("Failed to struct C");
|
|
|
|
return GST_VC1_PARSER_ERROR;
|
|
}
|
|
|
|
/**** API ****/
|
|
/**
|
|
* gst_vc1_identify_next_bdu:
|
|
* @data: The data to parse
|
|
* @size: the size of @data
|
|
* @bdu: (out): The #GstVC1BDU where to store parsed bdu headers
|
|
*
|
|
* Parses @data and fills @bdu fields
|
|
*
|
|
* Returns: a #GstVC1ParserResult
|
|
*/
|
|
GstVC1ParserResult
|
|
gst_vc1_identify_next_bdu (const guint8 * data, gsize size, GstVC1BDU * bdu)
|
|
{
|
|
gint off1, off2;
|
|
|
|
g_return_val_if_fail (bdu != NULL, GST_VC1_PARSER_ERROR);
|
|
|
|
if (size < 4) {
|
|
GST_DEBUG ("Can't parse, buffer has too small size %" G_GSSIZE_FORMAT,
|
|
size);
|
|
return GST_VC1_PARSER_ERROR;
|
|
}
|
|
|
|
off1 = scan_for_start_codes (data, size);
|
|
|
|
if (off1 < 0) {
|
|
GST_DEBUG ("No start code prefix in this buffer");
|
|
return GST_VC1_PARSER_NO_BDU;
|
|
}
|
|
|
|
bdu->sc_offset = off1;
|
|
|
|
bdu->offset = off1 + 4;
|
|
bdu->data = (guint8 *) data;
|
|
bdu->type = (GstVC1StartCode) (data[bdu->offset - 1]);
|
|
|
|
if (bdu->type == GST_VC1_END_OF_SEQ) {
|
|
GST_DEBUG ("End-of-Seq BDU found");
|
|
bdu->size = 0;
|
|
return GST_VC1_PARSER_OK;
|
|
}
|
|
|
|
off2 = scan_for_start_codes (data + bdu->offset, size - bdu->offset);
|
|
if (off2 < 0) {
|
|
GST_DEBUG ("Bdu start %d, No end found", bdu->offset);
|
|
|
|
return GST_VC1_PARSER_NO_BDU_END;
|
|
}
|
|
|
|
if (off2 > 0 && data[bdu->offset + off2 - 1] == 00)
|
|
off2--;
|
|
|
|
bdu->size = off2;
|
|
|
|
GST_DEBUG ("Complete bdu found. Off: %d, Size: %d", bdu->offset, bdu->size);
|
|
return GST_VC1_PARSER_OK;
|
|
}
|
|
|
|
/**
|
|
* gst_vc1_parse_sequence_layer:
|
|
* @data: The data to parse
|
|
* @size: the size of @data
|
|
* @structa: The #GstVC1SeqLayer to set.
|
|
*
|
|
* Parses @data, and fills @seqlayer fields.
|
|
*
|
|
* Returns: a #GstVC1ParserResult
|
|
*/
|
|
GstVC1ParserResult
|
|
gst_vc1_parse_sequence_layer (const guint8 * data, gsize size,
|
|
GstVC1SeqLayer * seqlayer)
|
|
{
|
|
guint32 tmp;
|
|
GstBitReader br = GST_BIT_READER_INIT (data, size);
|
|
|
|
g_return_val_if_fail (seqlayer != NULL, GST_VC1_PARSER_ERROR);
|
|
|
|
READ_UINT32 (&br, tmp, 8);
|
|
if (tmp != 0xC5)
|
|
goto failed;
|
|
|
|
READ_UINT32 (&br, seqlayer->numframes, 24);
|
|
|
|
READ_UINT32 (&br, tmp, 32);
|
|
if (tmp != 0x04)
|
|
goto failed;
|
|
|
|
if (parse_sequence_header_struct_c (&br, &seqlayer->struct_c) ==
|
|
GST_VC1_PARSER_ERROR)
|
|
goto failed;
|
|
|
|
if (parse_sequence_header_struct_a (&br, &seqlayer->struct_a) ==
|
|
GST_VC1_PARSER_ERROR)
|
|
goto failed;
|
|
|
|
READ_UINT32 (&br, tmp, 32);
|
|
if (tmp != 0x0C)
|
|
goto failed;
|
|
|
|
if (parse_sequence_header_struct_b (&br, &seqlayer->struct_b) ==
|
|
GST_VC1_PARSER_ERROR)
|
|
goto failed;
|
|
|
|
return GST_VC1_PARSER_OK;
|
|
|
|
failed:
|
|
GST_WARNING ("Failed to parse sequence layer");
|
|
|
|
return GST_VC1_PARSER_ERROR;
|
|
}
|
|
|
|
/**
|
|
* gst_vc1_parse_sequence_header_struct_a:
|
|
* @data: The data to parse
|
|
* @size: the size of @data
|
|
* @structa: The #GstVC1SeqStructA to set.
|
|
*
|
|
* Parses @data, and fills @structa fields.
|
|
*
|
|
* Returns: a #GstVC1ParserResult
|
|
*/
|
|
GstVC1ParserResult
|
|
gst_vc1_parse_sequence_header_struct_a (const guint8 * data,
|
|
gsize size, GstVC1SeqStructA * structa)
|
|
{
|
|
GstBitReader br = GST_BIT_READER_INIT (data, size);
|
|
|
|
g_return_val_if_fail (structa != NULL, GST_VC1_PARSER_ERROR);
|
|
|
|
return parse_sequence_header_struct_a (&br, structa);
|
|
}
|
|
|
|
/**
|
|
* gst_vc1_parse_sequence_header_struct_b:
|
|
* @data: The data to parse
|
|
* @size: the size of @data
|
|
* @structa: The #GstVC1SeqStructB to set.
|
|
*
|
|
* Parses @data, and fills @structb fields.
|
|
*
|
|
* Returns: a #GstVC1ParserResult
|
|
*/
|
|
GstVC1ParserResult
|
|
gst_vc1_parse_sequence_header_struct_b (const guint8 * data,
|
|
gsize size, GstVC1SeqStructB * structb)
|
|
{
|
|
GstBitReader br = GST_BIT_READER_INIT (data, size);
|
|
|
|
g_return_val_if_fail (structb != NULL, GST_VC1_PARSER_ERROR);
|
|
|
|
return parse_sequence_header_struct_b (&br, structb);
|
|
}
|
|
|
|
/**
|
|
* gst_vc1_parse_sequence_header_struct_c:
|
|
* @data: The data to parse
|
|
* @size: the size of @data
|
|
* @structc: The #GstVC1SeqStructC to set.
|
|
*
|
|
* Parses @data, and fills @structc fields.
|
|
*
|
|
* Returns: a #GstVC1ParserResult
|
|
*/
|
|
GstVC1ParserResult
|
|
gst_vc1_parse_sequence_header_struct_c (const guint8 * data, gsize size,
|
|
GstVC1SeqStructC * structc)
|
|
{
|
|
GstBitReader br = GST_BIT_READER_INIT (data, size);
|
|
|
|
g_return_val_if_fail (structc != NULL, GST_VC1_PARSER_ERROR);
|
|
|
|
return parse_sequence_header_struct_c (&br, structc);
|
|
}
|
|
|
|
/**
|
|
* gst_vc1_parse_sequence_header:
|
|
* @data: The data to parse
|
|
* @size: the size of @data
|
|
* @seqhdr: The #GstVC1SeqHdr to set.
|
|
*
|
|
* Parses @data, and fills @seqhdr fields.
|
|
*
|
|
* Returns: a #GstVC1ParserResult
|
|
*/
|
|
GstVC1ParserResult
|
|
gst_vc1_parse_sequence_header (const guint8 * data, gsize size,
|
|
GstVC1SeqHdr * seqhdr)
|
|
{
|
|
GstBitReader br = GST_BIT_READER_INIT (data, size);
|
|
|
|
g_return_val_if_fail (seqhdr != NULL, GST_VC1_PARSER_ERROR);
|
|
|
|
if (parse_sequence_header_struct_c (&br, &seqhdr->struct_c) ==
|
|
GST_VC1_PARSER_ERROR)
|
|
goto failed;
|
|
|
|
/* Convenience field */
|
|
seqhdr->profile = seqhdr->struct_c.profile;
|
|
|
|
if (seqhdr->profile == GST_VC1_PROFILE_ADVANCED)
|
|
return parse_sequence_header_advanced (seqhdr, &br);
|
|
|
|
/* Compute MB height and width */
|
|
calculate_mb_size (seqhdr, seqhdr->struct_c.coded_width,
|
|
seqhdr->struct_c.coded_height);
|
|
|
|
return GST_VC1_PARSER_OK;
|
|
|
|
failed:
|
|
GST_WARNING ("Failed to parse sequence header");
|
|
|
|
return GST_VC1_PARSER_ERROR;
|
|
}
|
|
|
|
/**
|
|
* gst_vc1_parse_entry_point_header:
|
|
* @data: The data to parse
|
|
* @size: the size of @data
|
|
* @entrypoint: (out): The #GstVC1EntryPointHdr to set.
|
|
* @seqhdr: The #GstVC1SeqHdr currently being parsed
|
|
*
|
|
* Parses @data, and sets @entrypoint fields.
|
|
*
|
|
* Returns: a #GstVC1EntryPointHdr
|
|
*/
|
|
GstVC1ParserResult
|
|
gst_vc1_parse_entry_point_header (const guint8 * data, gsize size,
|
|
GstVC1EntryPointHdr * entrypoint, GstVC1SeqHdr * seqhdr)
|
|
{
|
|
GstBitReader br;
|
|
guint8 i;
|
|
GstVC1AdvancedSeqHdr *advanced = &seqhdr->advanced;
|
|
|
|
g_return_val_if_fail (entrypoint != NULL, GST_VC1_PARSER_ERROR);
|
|
|
|
gst_bit_reader_init (&br, data, size);
|
|
|
|
if (gst_bit_reader_get_remaining (&br) < 13)
|
|
goto failed;
|
|
|
|
entrypoint->broken_link = gst_bit_reader_get_bits_uint8_unchecked (&br, 1);
|
|
entrypoint->closed_entry = gst_bit_reader_get_bits_uint8_unchecked (&br, 1);
|
|
entrypoint->panscan_flag = gst_bit_reader_get_bits_uint8_unchecked (&br, 1);
|
|
entrypoint->refdist_flag = gst_bit_reader_get_bits_uint8_unchecked (&br, 1);
|
|
entrypoint->loopfilter = gst_bit_reader_get_bits_uint8_unchecked (&br, 1);
|
|
entrypoint->fastuvmc = gst_bit_reader_get_bits_uint8_unchecked (&br, 1);
|
|
entrypoint->extended_mv = gst_bit_reader_get_bits_uint8_unchecked (&br, 1);
|
|
entrypoint->dquant = gst_bit_reader_get_bits_uint8_unchecked (&br, 2);
|
|
entrypoint->vstransform = gst_bit_reader_get_bits_uint8_unchecked (&br, 1);
|
|
entrypoint->overlap = gst_bit_reader_get_bits_uint8_unchecked (&br, 1);
|
|
entrypoint->quantizer = gst_bit_reader_get_bits_uint8_unchecked (&br, 2);
|
|
|
|
if (advanced->hrd_param_flag) {
|
|
if (seqhdr->advanced.hrd_param.hrd_num_leaky_buckets >
|
|
MAX_HRD_NUM_LEAKY_BUCKETS) {
|
|
GST_WARNING
|
|
("hrd_num_leaky_buckets (%d) > MAX_HRD_NUM_LEAKY_BUCKETS (%d)",
|
|
seqhdr->advanced.hrd_param.hrd_num_leaky_buckets,
|
|
MAX_HRD_NUM_LEAKY_BUCKETS);
|
|
goto failed;
|
|
}
|
|
for (i = 0; i < seqhdr->advanced.hrd_param.hrd_num_leaky_buckets; i++)
|
|
READ_UINT8 (&br, entrypoint->hrd_full[i], 8);
|
|
}
|
|
|
|
READ_UINT8 (&br, entrypoint->coded_size_flag, 1);
|
|
if (entrypoint->coded_size_flag) {
|
|
READ_UINT16 (&br, entrypoint->coded_width, 12);
|
|
READ_UINT16 (&br, entrypoint->coded_height, 12);
|
|
entrypoint->coded_height = (entrypoint->coded_height + 1) << 1;
|
|
entrypoint->coded_width = (entrypoint->coded_width + 1) << 1;
|
|
calculate_mb_size (seqhdr, entrypoint->coded_width,
|
|
entrypoint->coded_height);
|
|
}
|
|
|
|
if (entrypoint->extended_mv)
|
|
READ_UINT8 (&br, entrypoint->extended_dmv, 1);
|
|
|
|
READ_UINT8 (&br, entrypoint->range_mapy_flag, 1);
|
|
if (entrypoint->range_mapy_flag)
|
|
READ_UINT8 (&br, entrypoint->range_mapy, 3);
|
|
|
|
READ_UINT8 (&br, entrypoint->range_mapuv_flag, 1);
|
|
if (entrypoint->range_mapy_flag)
|
|
READ_UINT8 (&br, entrypoint->range_mapuv, 3);
|
|
|
|
advanced->entrypoint = *entrypoint;
|
|
|
|
return GST_VC1_PARSER_OK;
|
|
|
|
failed:
|
|
GST_WARNING ("Failed to parse entry point header");
|
|
|
|
return GST_VC1_PARSER_ERROR;
|
|
}
|
|
|
|
/**
|
|
* gst_vc1_parse_frame_layer:
|
|
* @data: The data to parse
|
|
* @size: the size of @data
|
|
* @framelayer: The #GstVC1FrameLayer to fill.
|
|
*
|
|
* Parses @data, and fills @framelayer fields.
|
|
*
|
|
* Returns: a #GstVC1ParserResult
|
|
*/
|
|
GstVC1ParserResult
|
|
gst_vc1_parse_frame_layer (const guint8 * data, gsize size,
|
|
GstVC1FrameLayer * framelayer)
|
|
{
|
|
GstBitReader br = GST_BIT_READER_INIT (data, size);
|
|
|
|
if (gst_bit_reader_get_remaining (&br) < 64) {
|
|
GST_WARNING ("Could not parse frame layer");
|
|
|
|
return GST_VC1_PARSER_ERROR;
|
|
}
|
|
|
|
/* set default values */
|
|
framelayer->skiped_p_frame = 0;
|
|
|
|
framelayer->key = gst_bit_reader_get_bits_uint8_unchecked (&br, 1);
|
|
gst_bit_reader_skip_unchecked (&br, 7);
|
|
|
|
framelayer->framesize = gst_bit_reader_get_bits_uint32_unchecked (&br, 24);
|
|
|
|
if (framelayer->framesize == 0 || framelayer->framesize == 1)
|
|
framelayer->skiped_p_frame = 1;
|
|
|
|
/* compute next_framelayer_offset */
|
|
framelayer->next_framelayer_offset = framelayer->framesize + 8;
|
|
|
|
framelayer->timestamp = gst_bit_reader_get_bits_uint32_unchecked (&br, 32);
|
|
|
|
return GST_VC1_PARSER_OK;
|
|
}
|
|
|
|
/**
|
|
* gst_vc1_parse_frame_header:
|
|
* @data: The data to parse
|
|
* @size: the size of @data
|
|
* @framehdr: The #GstVC1FrameHdr to fill.
|
|
* @seqhdr: The #GstVC1SeqHdr currently being parsed
|
|
* @bitplanes: The #GstVC1BitPlanes to store bitplanes in or %NULL
|
|
*
|
|
* Parses @data, and fills @entrypoint fields.
|
|
*
|
|
* Returns: a #GstVC1ParserResult
|
|
*/
|
|
GstVC1ParserResult
|
|
gst_vc1_parse_frame_header (const guint8 * data, gsize size,
|
|
GstVC1FrameHdr * framehdr, GstVC1SeqHdr * seqhdr,
|
|
GstVC1BitPlanes * bitplanes)
|
|
{
|
|
GstBitReader br;
|
|
GstVC1ParserResult result;
|
|
|
|
gst_bit_reader_init (&br, data, size);
|
|
|
|
if (seqhdr->profile == GST_VC1_PROFILE_ADVANCED)
|
|
result = parse_frame_header_advanced (&br, framehdr, seqhdr, bitplanes,
|
|
FALSE);
|
|
else
|
|
result = parse_frame_header (&br, framehdr, seqhdr, bitplanes);
|
|
|
|
framehdr->header_size = gst_bit_reader_get_pos (&br);
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* gst_vc1_parse_field_header:
|
|
* @data: The data to parse
|
|
* @size: the size of @data
|
|
* @fieldhdr: The #GstVC1FrameHdr to fill.
|
|
* @seqhdr: The #GstVC1SeqHdr currently being parsed
|
|
* @bitplanes: The #GstVC1BitPlanes to store bitplanes in or %NULL
|
|
*
|
|
* Parses @data, and fills @fieldhdr fields.
|
|
*
|
|
* Returns: a #GstVC1ParserResult
|
|
*/
|
|
GstVC1ParserResult
|
|
gst_vc1_parse_field_header (const guint8 * data, gsize size,
|
|
GstVC1FrameHdr * fieldhdr, GstVC1SeqHdr * seqhdr,
|
|
GstVC1BitPlanes * bitplanes)
|
|
{
|
|
GstBitReader br;
|
|
GstVC1ParserResult result;
|
|
|
|
gst_bit_reader_init (&br, data, size);
|
|
|
|
result = parse_frame_header_advanced (&br, fieldhdr, seqhdr, bitplanes, TRUE);
|
|
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* gst_vc1_parse_slice_header:
|
|
* @data: The data to parse
|
|
* @size: The size of @data
|
|
* @slicehdr: The #GstVC1SliceHdr to fill
|
|
* @seqhdr: The #GstVC1SeqHdr that was previously parsed
|
|
*
|
|
* Parses @data, and fills @slicehdr fields.
|
|
*
|
|
* Returns: a #GstVC1ParserResult
|
|
*
|
|
* Since: 1.2
|
|
*/
|
|
GstVC1ParserResult
|
|
gst_vc1_parse_slice_header (const guint8 * data, gsize size,
|
|
GstVC1SliceHdr * slicehdr, GstVC1SeqHdr * seqhdr)
|
|
{
|
|
GstBitReader br;
|
|
GstVC1FrameHdr framehdr;
|
|
GstVC1ParserResult result;
|
|
guint8 pic_header_flag;
|
|
|
|
GST_DEBUG ("Parsing slice header");
|
|
|
|
if (seqhdr->profile != GST_VC1_PROFILE_ADVANCED)
|
|
return GST_VC1_PARSER_BROKEN_DATA;
|
|
|
|
gst_bit_reader_init (&br, data, size);
|
|
|
|
READ_UINT16 (&br, slicehdr->slice_addr, 9);
|
|
READ_UINT8 (&br, pic_header_flag, 1);
|
|
if (pic_header_flag)
|
|
result = parse_frame_header_advanced (&br, &framehdr, seqhdr, NULL, FALSE);
|
|
else
|
|
result = GST_VC1_PARSER_OK;
|
|
|
|
slicehdr->header_size = gst_bit_reader_get_pos (&br);
|
|
return result;
|
|
|
|
failed:
|
|
GST_WARNING ("Failed to parse slice header");
|
|
return GST_VC1_PARSER_ERROR;
|
|
}
|
|
|
|
/**
|
|
* gst_vc1_bitplanes_new:
|
|
* @seqhdr: The #GstVC1SeqHdr from which to set @bitplanes
|
|
*
|
|
* Creates a new #GstVC1BitPlanes. It should be freed with
|
|
* gst_vc1_bitplanes_free() after use.
|
|
*
|
|
* Returns: a new #GstVC1BitPlanes
|
|
*/
|
|
GstVC1BitPlanes *
|
|
gst_vc1_bitplanes_new (void)
|
|
{
|
|
return g_slice_new0 (GstVC1BitPlanes);
|
|
}
|
|
|
|
/**
|
|
* gst_vc1_bitplane_free:
|
|
* @bitplanes: the #GstVC1BitPlanes to free
|
|
*
|
|
* Frees @bitplanes.
|
|
*/
|
|
void
|
|
gst_vc1_bitplanes_free (GstVC1BitPlanes * bitplanes)
|
|
{
|
|
gst_vc1_bitplanes_free_1 (bitplanes);
|
|
g_slice_free (GstVC1BitPlanes, bitplanes);
|
|
}
|
|
|
|
/**
|
|
* gst_vc1_bitplane_free_1:
|
|
* @bitplanes: The #GstVC1BitPlanes to free
|
|
*
|
|
* Frees @bitplanes fields.
|
|
*/
|
|
void
|
|
gst_vc1_bitplanes_free_1 (GstVC1BitPlanes * bitplanes)
|
|
{
|
|
g_free (bitplanes->acpred);
|
|
g_free (bitplanes->fieldtx);
|
|
g_free (bitplanes->overflags);
|
|
g_free (bitplanes->mvtypemb);
|
|
g_free (bitplanes->skipmb);
|
|
g_free (bitplanes->directmb);
|
|
g_free (bitplanes->forwardmb);
|
|
}
|
|
|
|
/**
|
|
* gst_vc1_bitplanes_ensure_size:
|
|
* @bitplanes: The #GstVC1BitPlanes to reset
|
|
* @seqhdr: The #GstVC1SeqHdr from which to set @bitplanes
|
|
*
|
|
* Fills the @bitplanes structure from @seqhdr, this function
|
|
* should be called after #gst_vc1_parse_sequence_header if
|
|
* in simple or main mode, or after #gst_vc1_parse_entry_point_header
|
|
* if in advanced mode.
|
|
*
|
|
* Returns: %TRUE if everything went fine, %FALSE otherwize
|
|
*/
|
|
gboolean
|
|
gst_vc1_bitplanes_ensure_size (GstVC1BitPlanes * bitplanes,
|
|
GstVC1SeqHdr * seqhdr)
|
|
{
|
|
g_return_val_if_fail (bitplanes != NULL, FALSE);
|
|
g_return_val_if_fail (seqhdr != NULL, FALSE);
|
|
|
|
if (bitplanes->size) {
|
|
bitplanes->size = seqhdr->mb_height * seqhdr->mb_stride;
|
|
bitplanes->acpred =
|
|
g_realloc_n (bitplanes->acpred, bitplanes->size, sizeof (guint8));
|
|
bitplanes->fieldtx =
|
|
g_realloc_n (bitplanes->fieldtx, bitplanes->size, sizeof (guint8));
|
|
bitplanes->overflags =
|
|
g_realloc_n (bitplanes->overflags, bitplanes->size, sizeof (guint8));
|
|
bitplanes->mvtypemb =
|
|
g_realloc_n (bitplanes->mvtypemb, bitplanes->size, sizeof (guint8));
|
|
bitplanes->skipmb =
|
|
g_realloc_n (bitplanes->skipmb, bitplanes->size, sizeof (guint8));
|
|
bitplanes->directmb =
|
|
g_realloc_n (bitplanes->directmb, bitplanes->size, sizeof (guint8));
|
|
bitplanes->forwardmb =
|
|
g_realloc_n (bitplanes->forwardmb, bitplanes->size, sizeof (guint8));
|
|
} else {
|
|
bitplanes->size = seqhdr->mb_height * seqhdr->mb_stride;
|
|
bitplanes->acpred = g_malloc0 (bitplanes->size * sizeof (guint8));
|
|
bitplanes->fieldtx = g_malloc0 (bitplanes->size * sizeof (guint8));
|
|
bitplanes->overflags = g_malloc0 (bitplanes->size * sizeof (guint8));
|
|
bitplanes->mvtypemb = g_malloc0 (bitplanes->size * sizeof (guint8));
|
|
bitplanes->skipmb = g_malloc0 (bitplanes->size * sizeof (guint8));
|
|
bitplanes->directmb = g_malloc0 (bitplanes->size * sizeof (guint8));
|
|
bitplanes->forwardmb = g_malloc0 (bitplanes->size * sizeof (guint8));
|
|
}
|
|
|
|
return TRUE;
|
|
}
|