| /* 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 |
| * @title: 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/gstbytewriter.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 const 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_GSIZE_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 |
| * @seqlayer: 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; |
| guint8 tmp8; |
| guint8 structA[8] = { 0, }; |
| guint8 structB[12] = { 0, }; |
| GstBitReader br; |
| GstByteReader byter = GST_BYTE_READER_INIT (data, size); |
| GstByteWriter bytew; |
| |
| g_return_val_if_fail (seqlayer != NULL, GST_VC1_PARSER_ERROR); |
| |
| /* Thanks to the specification, structA and structB fields are defined |
| * as unisgned integer msb first. |
| * But in sequence-layer there are serialized in little-endian byte order, |
| * so we must take care of their endianness before using bit reader */ |
| |
| if (!gst_byte_reader_get_uint24_le (&byter, &seqlayer->numframes)) |
| goto failed; |
| |
| if (!gst_byte_reader_get_uint8 (&byter, &tmp8)) |
| goto failed; |
| |
| if (tmp8 != 0xC5) |
| goto failed; |
| |
| /* 0x00000004 */ |
| if (!gst_byte_reader_get_uint32_le (&byter, &tmp)) |
| goto failed; |
| |
| if (tmp != 0x04) |
| goto failed; |
| |
| /* As an exception, structC is serialized in big-endian byte order so |
| * no endianness issue here but we should at least have 4 bytes */ |
| if (gst_byte_reader_get_remaining (&byter) < 4) |
| goto failed; |
| |
| gst_bit_reader_init (&br, data + gst_byte_reader_get_pos (&byter), 4); |
| if (parse_sequence_header_struct_c (&br, &seqlayer->struct_c) == |
| GST_VC1_PARSER_ERROR) |
| goto failed; |
| |
| gst_byte_reader_skip (&byter, 4); |
| |
| /* structA */ |
| gst_byte_writer_init_with_data (&bytew, structA, 8, TRUE); |
| gst_byte_reader_get_uint32_le (&byter, &tmp); |
| gst_byte_writer_put_uint32_be (&bytew, tmp); |
| gst_byte_reader_get_uint32_le (&byter, &tmp); |
| gst_byte_writer_put_uint32_be (&bytew, tmp); |
| |
| gst_bit_reader_init (&br, structA, 8); |
| if (parse_sequence_header_struct_a (&br, &seqlayer->struct_a) == |
| GST_VC1_PARSER_ERROR) |
| goto failed; |
| |
| /* 0x0000000C */ |
| if (!gst_byte_reader_get_uint32_le (&byter, &tmp)) |
| goto failed; |
| |
| if (tmp != 0x0C) |
| goto failed; |
| |
| /* structB */ |
| gst_byte_writer_reset (&bytew); |
| gst_byte_writer_init_with_data (&bytew, structB, 12, TRUE); |
| gst_byte_reader_get_uint32_le (&byter, &tmp); |
| gst_byte_writer_put_uint32_be (&bytew, tmp); |
| gst_byte_reader_get_uint32_le (&byter, &tmp); |
| gst_byte_writer_put_uint32_be (&bytew, tmp); |
| gst_byte_reader_get_uint32_le (&byter, &tmp); |
| gst_byte_writer_put_uint32_be (&bytew, tmp); |
| |
| gst_bit_reader_init (&br, structB, 12); |
| 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 |
| * @structb: 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: |
| * |
| * 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 otherwise |
| */ |
| 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; |
| } |