| /* GStreamer H.263 Parser |
| * Copyright (C) <2010> Arun Raghavan <arun.raghavan@collabora.co.uk> |
| * Copyright (C) <2010> Edward Hervey <edward.hervey@collabora.co.uk> |
| * Copyright (C) <2010> Collabora Multimedia |
| * Copyright (C) <2010> Nokia Corporation |
| * |
| * 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. |
| */ |
| |
| #ifdef HAVE_CONFIG_H |
| #include "config.h" |
| #endif |
| |
| #include <gst/base/gstbitreader.h> |
| #include "gsth263parse.h" |
| |
| GST_DEBUG_CATEGORY_EXTERN (h263_parse_debug); |
| #define GST_CAT_DEFAULT h263_parse_debug |
| |
| gboolean |
| gst_h263_parse_is_delta_unit (const H263Params * params) |
| { |
| return (params->type == PICTURE_I); |
| } |
| |
| /* Reads adapter and tries to populate params. 'fast' mode can be used to |
| * extract a subset of the data (for now, it quits once we have the picture |
| * type. */ |
| GstFlowReturn |
| gst_h263_parse_get_params (H263Params * params, GstBuffer * buffer, |
| gboolean fast, H263ParseState * state) |
| { |
| static const guint8 partable[6][2] = { |
| {1, 0}, |
| {1, 1}, |
| {12, 11}, |
| {10, 11}, |
| {16, 11}, |
| {40, 33} |
| }; |
| |
| static const guint16 sizetable[8][2] = { |
| {0, 0}, |
| {128, 96}, |
| {176, 144}, |
| {352, 288}, |
| {704, 576}, |
| {1408, 1152} |
| }; |
| |
| #ifndef GST_DISABLE_GST_DEBUG |
| static const gchar *source_format_name[] = { |
| "Forbidden", |
| "sub-QCIF", |
| "QCIF", |
| "CIF", |
| "4CIF", |
| "16CIF", |
| "Reserved", |
| "Extended PType" |
| }; |
| #endif |
| |
| GstBitReader br; |
| GstMapInfo map; |
| guint8 tr; |
| guint32 psc = 0, temp32; |
| guint8 temp8, pquant; |
| gboolean hasplusptype; |
| |
| gst_buffer_map (buffer, &map, GST_MAP_READ); |
| |
| /* FIXME: we can optimise a little by checking the value of available |
| * instead of calling using the bit reader's get_bits_* functions. */ |
| gst_bit_reader_init (&br, map.data, map.size); |
| |
| /* Default PCF is CIF PCF = 30000/1001 */ |
| params->pcfnum = 30000; |
| params->pcfdenom = 1001; |
| |
| GST_DEBUG ("NEW BUFFER"); |
| if (!gst_bit_reader_get_bits_uint32 (&br, &psc, 22) || |
| !gst_bit_reader_get_bits_uint8 (&br, &tr, 8) || |
| !gst_bit_reader_get_bits_uint8 (&br, &temp8, 8)) |
| goto more; |
| |
| /* PSC : Picture Start Code 22 bits |
| * TR : Temporal Reference 8 bits |
| * PTYPE : Type Information variable |
| * bit 1 : Always "1" |
| * bit 2 : Always "0" |
| * bit 3 : Split Screen Indicator |
| * bit 4 : Document Camera Indicator |
| * bit 6-8 : Source Format |
| * if 111 : extended PTYPE is present */ |
| |
| /* 5.1.1 PSC : Picture Start Code (0x0020) 22 bits */ |
| /* FIXME : Scan for the PSC instead of assuming it's always present |
| * and at the beginning. */ |
| if (G_UNLIKELY (psc != 0x0020)) { |
| GST_WARNING ("Invalid PSC"); |
| goto beach; |
| } |
| |
| /* 5.1.2 TR : Temporal Reference 8 bits */ |
| GST_DEBUG (" Temporal Reference : %d", tr); |
| params->temporal_ref = tr; |
| |
| if ((temp8 >> 6) != 0x2) { |
| GST_WARNING ("Invalid PTYPE"); |
| goto beach; |
| } |
| |
| /* 5.1.3 PTYPE : Type Information variable length */ |
| params->splitscreen = (temp8 & 0x20) == 0x20; |
| params->documentcamera = (temp8 & 0x10) == 0x10; |
| params->fullpicturefreezerelease = (temp8 & 0x08) == 0x08; |
| params->format = temp8 & 0x07; |
| |
| hasplusptype = (temp8 & 0x07) == 0x07; |
| |
| GST_DEBUG (" Split Screen Indicator : %s", |
| params->splitscreen ? "on" : "off"); |
| GST_DEBUG (" Document camera indicator : %s", |
| params->documentcamera ? "on" : "off"); |
| GST_DEBUG (" Full Picture Freeze Release : %s", |
| params->fullpicturefreezerelease ? "on" : "off"); |
| GST_DEBUG (" Source format 0x%x (%s)", params->format, |
| source_format_name[params->format]); |
| |
| if (!hasplusptype) { |
| guint8 ptype2; |
| |
| /* Fill in width/height based on format */ |
| params->width = sizetable[params->format][0]; |
| params->height = sizetable[params->format][1]; |
| GST_DEBUG (" Picture width x height: %d x %d", |
| params->width, params->height); |
| |
| /* Default PAR is 12/11 */ |
| params->parnum = 12; |
| params->pardenom = 11; |
| |
| /* 5.1.3 : Remainder of PTYPE 5 bits */ |
| if (!gst_bit_reader_get_bits_uint8 (&br, &ptype2, 5)) |
| goto more; |
| |
| params->type = (ptype2 & 0x10) == 0x10; |
| if ((ptype2 & 0x08) == 0x08) |
| params->features |= H263_OPTION_UMV_MODE; |
| if ((ptype2 & 0x04) == 0x04) |
| params->features |= H263_OPTION_SAC_MODE; |
| if ((ptype2 & 0x02) == 0x02) |
| params->features |= H263_OPTION_AP_MODE; |
| if ((ptype2 & 0x01) == 0x01) { |
| params->features |= H263_OPTION_PB_MODE; |
| params->type = PICTURE_PB; |
| } |
| |
| GST_DEBUG (" Picture Coding Type : %s", |
| (ptype2 & 0x10) == 0x10 ? "INTER (P-picture)" : "INTRA (I-picture)"); |
| GST_DEBUG (" Unrestricted Motion Vector mode (Annex D) : %s", |
| (ptype2 & 0x08) == 0x08 ? "on" : "off"); |
| GST_DEBUG (" Syntax-basex Arithmetic Coding mode (Annex E) : %s", |
| (ptype2 & 0x04) == 0x04 ? "on" : "off"); |
| GST_DEBUG (" Advanced Prediction mode (Annex F) : %s", |
| (ptype2 & 0x02) == 0x02 ? "on" : "off"); |
| GST_DEBUG (" PB Frames mode (Annex G) : %s", |
| (ptype2 & 0x01) == 0x01 ? "on" : "off"); |
| |
| if (fast) |
| goto done; |
| } |
| |
| if (hasplusptype) { |
| guint8 ufep; |
| guint8 cpm; |
| guint32 opptype = 0, mpptype = 0; |
| |
| /* 5.1.4 PLUSPTYPE */ |
| |
| /* 5.1.4.1 UFEP : Update Full Extended PTYPE (3 bits) */ |
| if (!gst_bit_reader_get_bits_uint8 (&br, &ufep, 3)) |
| goto more; |
| GST_DEBUG (" UFEP 0x%x", ufep); |
| |
| if (ufep == 1) { |
| /* 5.1.4.2 OPPTYPE : The Optional Part of PLUSPTYPE (OPPTYPE) (18 bits) */ |
| if (!gst_bit_reader_get_bits_uint32 (&br, &opptype, 18)) |
| goto more; |
| |
| /* Last 4 bits are always "1000" */ |
| if ((opptype & 0xf) != 0x8) { |
| GST_WARNING ("Corrupted OPTTYPE"); |
| goto beach; |
| } |
| params->format = opptype >> 15; |
| params->custompcfpresent = (opptype & 0x4000) == 0x4000; |
| if (opptype & 0x2000) |
| params->features |= H263_OPTION_UMV_MODE; |
| if (opptype & 0x1000) |
| params->features |= H263_OPTION_SAC_MODE; |
| if (opptype & 0x0800) |
| params->features |= H263_OPTION_AP_MODE; |
| if (opptype & 0x0400) |
| params->features |= H263_OPTION_AIC_MODE; |
| if (opptype & 0x0200) |
| params->features |= H263_OPTION_DF_MODE; |
| if (opptype & 0x0100) |
| params->features |= H263_OPTION_SS_MODE; |
| if (opptype & 0x0080) |
| params->features |= H263_OPTION_RPS_MODE; |
| if (opptype & 0x0040) |
| params->features |= H263_OPTION_ISD_MODE; |
| if (opptype & 0x0020) |
| params->features |= H263_OPTION_AIV_MODE; |
| if (opptype & 0x0010) |
| params->features |= H263_OPTION_MQ_MODE; |
| /* Bit 15 is set to 1 to avoid looking like a start code */ |
| if (opptype & 0x0004) |
| params->features |= H263_OPTION_ERPS_MODE; |
| if (opptype & 0x0002) |
| params->features |= H263_OPTION_DPS_MODE; |
| } |
| |
| /* 5.1.4.3 MPPTYPE : The mandatory part of PLUSPTYPE (9 bits) */ |
| if (!gst_bit_reader_get_bits_uint32 (&br, &mpptype, 9)) |
| goto more; |
| |
| /* Last 3 bits are always "001" */ |
| if ((mpptype & 0x7) != 1) { |
| GST_WARNING ("Corrupted MPPTYPE"); |
| goto beach; |
| } |
| |
| params->type = mpptype >> 6; |
| GST_DEBUG (" Picture Coding Type : %d", params->type); |
| |
| if (fast) |
| goto done; |
| |
| if (mpptype & 0x2000) |
| params->features |= H263_OPTION_RPR_MODE; |
| if (mpptype & 0x1000) |
| params->features |= H263_OPTION_RRU_MODE; |
| |
| /* 5.1.20 CPM : Continuous Presence Multipoint and Video Multiplex (1 bit) */ |
| if (!gst_bit_reader_get_bits_uint8 (&br, &cpm, 1)) |
| goto more; |
| GST_DEBUG (" Continuous Presence Multipoint and Video Multiplex : %d", cpm); |
| |
| if (cpm) { |
| /* 5.1.21 PSBI : Picture Sub-Bitstream Indicator (2 bits) */ |
| guint8 psbi; |
| if (!gst_bit_reader_get_bits_uint8 (&br, &psbi, 2)) |
| goto more; |
| GST_DEBUG (" Picture Sub-Bitstream Indicator (PSBI):%d", psbi); |
| } |
| |
| if (ufep == 1) { |
| if (params->format == 6) { |
| /* A fixed length codeword of 23 bits that is present only if the use of |
| * a custom picture format is signalled in PLUSPTYPE and UFEP is 001 */ |
| guint32 cpfmt = 0; |
| |
| /* 5.1.5 CPFMT : Custom Picture Format (23 bits) */ |
| if (!gst_bit_reader_get_bits_uint32 (&br, &cpfmt, 23)) |
| goto more; |
| if (!(cpfmt & 0x200)) { |
| GST_WARNING ("Corrupted CPFMT (0x%x)", cpfmt); |
| goto beach; |
| } |
| temp8 = cpfmt >> 19; |
| /* Bits 5-13: Picture Width Indication: Range [0, ... , 511]; |
| * Number of pixels per line = (PWI + 1) * 4 */ |
| params->width = (((cpfmt >> 10) & 0x1ff) + 1) * 4; |
| /* Bits 15-23 Picture Height Indication: Range [1, ... , 288]; |
| * Number of lines = PHI * 4 */ |
| params->height = (cpfmt & 0x1ff) * 4; |
| |
| if (temp8 == 0xf) { |
| guint32 epar = 0; |
| /* 5.1.6 EPAR : Extended Pixel Aspect Ratio (16bits) */ |
| if (!gst_bit_reader_get_bits_uint32 (&br, &epar, 16)) |
| goto more; |
| params->parnum = epar >> 8; |
| params->pardenom = epar & 0xf; |
| } else { |
| params->parnum = partable[temp8][0]; |
| params->pardenom = partable[temp8][1]; |
| } |
| } else { |
| /* Fill in width/height based on format */ |
| params->width = sizetable[params->format][0]; |
| params->height = sizetable[params->format][1]; |
| GST_DEBUG (" Picture width x height: %d x %d", |
| params->width, params->height); |
| /* Fill in default Pixel aspect ratios */ |
| params->parnum = 12; |
| params->pardenom = 11; |
| } |
| |
| if (params->custompcfpresent) { |
| /* 5.1.7 CPCFC : Custom Picture Clock Frequency Code (8bits) */ |
| /* (we store this as a frame rate) */ |
| if (!gst_bit_reader_get_bits_uint8 (&br, &temp8, 8)) |
| goto more; |
| GST_DEBUG (" Custom PCF is present (%d)", (int) temp8); |
| params->pcfnum = gst_util_uint64_scale_int (1800000, 1, temp8 & 0x7f); |
| params->pcfdenom = (temp8 & 0x80) ? 1001 : 1000; |
| /* 5.1.8 ETR : Extended Temp8oral Reference (2bits) */ |
| if (!gst_bit_reader_get_bits_uint8 (&br, &temp8, 2)) |
| goto more; |
| params->temporal_ref |= temp8 << 8; |
| } |
| |
| if (params->features & H263_OPTION_UMV_MODE) { |
| guint8 i; |
| /* 5.1.9 UUI : Unlimited Unrestricted Motion Vectors Indicator (variable length) */ |
| if (!gst_bit_reader_get_bits_uint8 (&br, &i, 1)) |
| goto more; |
| if (i == 0) { |
| if (!gst_bit_reader_get_bits_uint8 (&br, &i, 1)) |
| goto more; |
| if (i != 1) { |
| GST_WARNING ("Corrupted UUI (0%u)", (guint) i); |
| goto beach; |
| } |
| params->uui = UUI_IS_01; |
| } else { |
| params->uui = UUI_IS_1; |
| } |
| } |
| |
| if (params->features & H263_OPTION_SS_MODE) { |
| /* 5.1.10 SSS : Slice Structured Submode bits (2bits) */ |
| if (!gst_bit_reader_get_bits_uint8 (&br, ¶ms->sss, 2)) |
| goto more; |
| } |
| |
| /* WE DO NOT SUPPORT optional Temporal, SNR, and Spatial Scalability mode */ |
| /* 5.1.11 ELNUM : Enhancement Layer Number (4bits) */ |
| /* 5.1.12 RLNUM : Reference Layer Number (4bits) */ |
| |
| if (params->features & H263_OPTION_RPS_MODE) { |
| /* 5.1.13 RPSMF : Reference Picture Selection Mode Flags (3bits) */ |
| /* FIXME : We just swallow the bits */ |
| if (!gst_bit_reader_get_bits_uint8 (&br, &temp8, 3)) |
| goto more; |
| |
| /* 5.1.14 TRPI : Temporal Reference for Prediction Indication (1bit) */ |
| if (!gst_bit_reader_get_bits_uint8 (&br, &temp8, 1)) |
| goto more; |
| |
| if (temp8) { |
| /* 5.1.15 TRP : Temporal Reference for Prediction (10bits) */ |
| /* FIXME : We just swallow the bits */ |
| if (!gst_bit_reader_get_bits_uint32 (&br, &temp32, 10)) |
| goto more; |
| } |
| |
| /* 5.1.16 BCI Back-Channel message Indication (variable length) */ |
| if (!gst_bit_reader_get_bits_uint8 (&br, &temp8, 1)) |
| goto more; |
| if (temp8 == 1) { |
| /* 5.1.17 BCM Back-Channel Message (variable length) */ |
| GST_ERROR ("We won't support Back-Channel Message (BCM)"); |
| goto beach; |
| } else { |
| if (!gst_bit_reader_get_bits_uint8 (&br, &temp8, 1)) |
| goto more; |
| if (temp8 != 1) { |
| GST_WARNING ("Corrupted BCI"); |
| goto beach; |
| } |
| } |
| } /* END H263_OPTION_RPS_MODE */ |
| } |
| |
| GST_DEBUG (" Unrestricted Motion Vector mode (Annex D) : %s", |
| (params->features & H263_OPTION_UMV_MODE) ? "on" : "off"); |
| GST_DEBUG (" Syntax-basex Arithmetic Coding mode (Annex E) : %s", |
| (params->features & H263_OPTION_SAC_MODE) ? "on" : "off"); |
| GST_DEBUG (" Advanced Prediction mode (Annex F) : %s", |
| (params->features & H263_OPTION_AP_MODE) ? "on" : "off"); |
| GST_DEBUG (" Advanced INTRA Coding mode (Annex I) : %s", |
| (params->features & H263_OPTION_AIC_MODE ? "on" : "off")); |
| GST_DEBUG (" Deblocking Filter mode (Annex J) : %s", |
| (params->features & H263_OPTION_DF_MODE ? "on" : "off")); |
| GST_DEBUG (" Slice Structured mode (Annex K) : %s", |
| (params->features & H263_OPTION_SS_MODE ? "on" : "off")); |
| GST_DEBUG (" Reference Picture Selection mode (Annex N) : %s", |
| (params->features & H263_OPTION_RPS_MODE ? "on" : "off")); |
| GST_DEBUG (" Independent Segment Decoding mode (Annex R) : %s", |
| (params->features & H263_OPTION_ISD_MODE ? "on" : "off")); |
| GST_DEBUG (" Alternative INTER VLC mode (Annex S) : %s", |
| (params->features & H263_OPTION_AIV_MODE ? "on" : "off")); |
| GST_DEBUG (" Modified Quantization mode (Annex T) : %s", |
| (params->features & H263_OPTION_MQ_MODE ? "on" : "off")); |
| GST_DEBUG (" Enhanced Reference Picture Selection mode (Annex U) : %s", |
| (params->features & H263_OPTION_ERPS_MODE ? "on" : "off")); |
| GST_DEBUG (" Enhanced Data Partitioned Slices mode (Annex V) : %s", |
| (params->features & H263_OPTION_DPS_MODE ? "on" : "off")); |
| |
| /* END ufep == 1 */ |
| /* WE DO NOT SUPPORT optional Reference Picture Resampling mode */ |
| /* 5.1.18 RPRP : Reference Picture Resampling Parameters (variable length) */ |
| } |
| |
| /* END hasplusptype */ |
| /* 5.1.19 PQUANT : Quantizer Information (5 bits) */ |
| if (!gst_bit_reader_get_bits_uint8 (&br, &pquant, 5)) |
| goto more; |
| GST_DEBUG (" PQUANT : 0x%x", pquant); |
| |
| if (!hasplusptype) { |
| guint8 cpm; |
| /* 5.1.20 CPM : Continuous Presence Multipoint and Video Multiplex (1 bit) */ |
| if (!gst_bit_reader_get_bits_uint8 (&br, &cpm, 1)) |
| goto more; |
| GST_DEBUG (" Continuous Presence Multipoint and Video Multiplex : %d", cpm); |
| |
| if (cpm) { |
| /* 5.1.21 PSBI : Picture Sub-Bitstream Indicator (2 bits) */ |
| guint8 psbi; |
| if (!gst_bit_reader_get_bits_uint8 (&br, &psbi, 2)) |
| goto more; |
| GST_DEBUG (" Picture Sub-Bitstream Indicator (PSBI):%d", psbi); |
| } |
| } |
| |
| if (params->type & (PICTURE_PB | PICTURE_IMPROVED_PB)) { |
| /* 5.1.22 TRb : Temporal Reference for B-pictures in PB-frames (3/5bits) */ |
| /* FIXME : We just swallow the bits */ |
| if (!gst_bit_reader_get_bits_uint8 (&br, &temp8, |
| params->custompcfpresent ? 5 : 3)) |
| goto more; |
| |
| /* 5.1.23 DBQUANT : Quantization information for B-pictures in PB-frames (2bits) */ |
| if (!gst_bit_reader_get_bits_uint8 (&br, &temp8, 2)) |
| goto more; |
| } |
| |
| GST_DEBUG (" Framerate defined by the stream is %d/%d", |
| params->pcfnum, params->pcfdenom); |
| |
| /* We ignore the PEI and PSUPP - these may occur in any frame, and can be |
| * ignored by decoders that don't support them, except for bits of Annex W */ |
| |
| /* FIXME: Annex H (Forward Error Correction) requires that we poke into the |
| * stream data. */ |
| |
| /* FIXME: Annex P (Reference Picture Resampling) can be signaled implicitly |
| * as well as in the header. Should we set the field to false in caps if it |
| * is not specfied by the header? */ |
| |
| /* FIXME: Annex U (Enhanced Reference Picture Selection) poses a problem - we |
| * have no means of specifying what sub-modes, if any, are used. */ |
| |
| done: |
| *state = GOT_HEADER; |
| more: |
| gst_buffer_unmap (buffer, &map); |
| return GST_FLOW_OK; |
| |
| beach: |
| *state = PASSTHROUGH; |
| gst_buffer_unmap (buffer, &map); |
| return GST_FLOW_OK; |
| } |
| |
| gint |
| gst_h263_parse_get_profile (const H263Params * params) |
| { |
| gboolean c, d, d1, d21, e, f, f2, g, h, i, j, k, k0, k1, l, m, n, o, |
| p, q, r, s, t, u, v, w; |
| |
| /* FIXME: some parts of Annex C can be discovered, others can not */ |
| c = FALSE; |
| d = (params->features & H263_OPTION_UMV_MODE) != 0; |
| /* d1: Annex D.1; d21: Annex D.2 with UUI=1; d22: Annex D.2 with UUI=01 */ |
| d1 = (d && params->uui == UUI_ABSENT); |
| d21 = (d && params->uui == UUI_IS_1); |
| /* d22 = (d && params->uui == UUI_IS_01); */ |
| e = (params->features & H263_OPTION_SAC_MODE) != 0; |
| /* f:Annex F.2 or F.3 may be used; f2: only Annex F.2 is used (we have no |
| * way of detecting this right now */ |
| f = (params->features & H263_OPTION_AP_MODE) != 0; |
| f2 = FALSE; |
| g = (params->features & H263_OPTION_PB_MODE) != 0; |
| h = FALSE; |
| i = (params->features & H263_OPTION_AIC_MODE) != 0; |
| j = (params->features & H263_OPTION_DF_MODE) != 0; |
| k = (params->features & H263_OPTION_SS_MODE) != 0; |
| /* k0: Annex K without submodes; k1: Annex K with ASO; k2: Annex K with RS */ |
| k0 = (k && params->sss == 0x0); |
| k1 = (k && params->sss == 0x2); |
| /* k2 = (k && params->sss == 0x1); */ |
| l = FALSE; |
| m = (params->type == PICTURE_IMPROVED_PB); |
| n = (params->features & H263_OPTION_RPS_MODE) != 0; |
| o = FALSE; |
| p = FALSE; |
| q = (params->features & H263_OPTION_RRU_MODE) != 0; |
| r = (params->features & H263_OPTION_ISD_MODE) != 0; |
| s = (params->features & H263_OPTION_AIV_MODE) != 0; |
| t = (params->features & H263_OPTION_MQ_MODE) != 0; |
| u = (params->features & H263_OPTION_ERPS_MODE) != 0; |
| v = (params->features & H263_OPTION_DPS_MODE) != 0; |
| w = FALSE; |
| |
| /* FIXME: The use of UUI in Annex D seems to be in contradiction with the |
| * profile definition in Annex X. Afaict, D.2 with UUI not present is not a |
| * meaningful state. */ |
| |
| /* FIXME: We have no way to distinguish between the use of section F.2 (four |
| * motion vectors per macroblock) and F.3 (overlapped block motion |
| * compensation), so we assume that they are either both present else neither |
| * is. This means if a profile supports only F.2 and not F.3, but we see that |
| * Advanced Prediction mode (Annex F) is used, we assume this profile does |
| * not apply. */ |
| |
| /* FIXME: We assume there is no error correction (Annex H) to avoid having to |
| * parse the stream to look for its existence. */ |
| |
| /* FIXME: Profiles 1 and 5-8 need the detection of Annex L.4 which can happen |
| * anywhere in the stream, so we just assume it doesn't exist and hope for |
| * the best. */ |
| |
| /* FIXME: Annex O support is TBD. */ |
| |
| /* FIXME: see note for Annex P elsewhere in this file. */ |
| |
| /* FIXME: Annex W.6.3.{8,11} suffer the same fate as Annex L.4 above. */ |
| |
| /* FIXME: We have no way of figuring out submodes when Annex U is used. Here |
| * we always assume no submode is used. */ |
| |
| if (!c && !d && !e && !f && !g && !h && !i && !j && !k && !l && !m && !n && |
| !o && !p && !q && !r && !s && !t && !u && !v && !w) |
| return 0; |
| if (!c && (!d || d1) && !e && (!f || f2) && !g && !h && !k && !l && !m && |
| !n && !o && !p && !q && !r && !s && !u && !v && !w) |
| return 1; |
| if (!c && (!d || d1) && !e && !g && !h && !i && !j && !k && !l && !m && !n && |
| !o && !p && !q && !r && !s && !t && !u && !v && !w) |
| return 2; |
| if (!c && (!d || d1) && !e && (!f || f2) && !g && !h && (!k || k0) && !l && |
| !m && !n && !o && !p && !q && !r && !s && !u && !v && !w) |
| return 3; |
| if (!c && (!d || d1) && !e && (!f || f2) && !g && !h && (!k || k0) && !l && |
| !m && !n && !o && !p && !q && !r && !s && !u && !w) |
| return 4; |
| if (!c && (!d || d1 || d21) && !e && !g && !h && !k && !l && !m && !n && |
| !o && !p && !q && !r && !s && !v && !w) |
| return 5; |
| if (!c && (!d || d1 || d21) && !e && !g && !h && (!k || k0 || k1) && !l && |
| !m && !n && !o && !p && !q && !r && !s && !v && !w) |
| return 6; |
| if (!c && (!d || d1 || d21) && !e && !g && !h && !k && !l && !m && !n && |
| !o && !p && !q && !r && !s && !v && !w) |
| return 7; |
| if (!c && (!d || d1 || d21) && !e && !g && !h && (!k || k0 || k1) && !l && |
| !m && !n && !o && !p && !q && !r && !s && !v && !w) |
| /* FIXME: needs Annex O and Annex P support */ |
| return 8; |
| |
| return -1; |
| } |
| |
| #define H263_PROFILE_NOT_0_2(profile) \ |
| ((profile) != -1 && (profile) != 0 && (profile) != 2) |
| |
| #define H263_FMT_UPTO_QCIF(params) \ |
| ((params)->format == PICTURE_FMT_SUB_QCIF || \ |
| (params)->format == PICTURE_FMT_QCIF) |
| #define H263_FMT_UPTO_CIF(params) \ |
| ((params)->format == PICTURE_FMT_SUB_QCIF || \ |
| (params)->format == PICTURE_FMT_QCIF || \ |
| (params)->format == PICTURE_FMT_CIF) |
| #define H263_FMT_CUSTOM_UPTO_QCIF(params) \ |
| ((params)->format == PICTURE_FMT_RESERVED1 && \ |
| (params)->height <= 144 && \ |
| (params)->width <= 176) |
| #define H263_FMT_CUSTOM_UPTO_CIF(params) \ |
| ((params)->format == PICTURE_FMT_RESERVED1 && \ |
| (params)->height <= 288 && \ |
| (params)->width <= 352) |
| |
| #define GST_FRACTION_LE(f1, f2) \ |
| ((gst_value_compare (&(f1), &(f2)) == GST_VALUE_LESS_THAN) || \ |
| (gst_value_compare (&(f1), &(f2)) == GST_VALUE_EQUAL)) |
| |
| gint |
| gst_h263_parse_get_level (const H263Params * params, gint profile, |
| guint bitrate, gint fps_num, gint fps_denom) |
| { |
| GValue fps15 = { 0, }; |
| GValue fps30 = { 0, }; |
| GValue fps50 = { 0, }; |
| GValue fps60 = { 0, }; |
| GValue fps = { 0, }; |
| |
| if (bitrate == 0) { |
| GST_DEBUG ("Can't calculate level since bitrate is unknown"); |
| return -1; |
| } |
| |
| g_value_init (&fps15, GST_TYPE_FRACTION); |
| g_value_init (&fps30, GST_TYPE_FRACTION); |
| g_value_init (&fps50, GST_TYPE_FRACTION); |
| g_value_init (&fps60, GST_TYPE_FRACTION); |
| g_value_init (&fps, GST_TYPE_FRACTION); |
| |
| gst_value_set_fraction (&fps15, 15000, 1001); |
| gst_value_set_fraction (&fps30, 30000, 1001); |
| gst_value_set_fraction (&fps50, 50, 1); |
| gst_value_set_fraction (&fps60, 60000, 1001); |
| |
| gst_value_set_fraction (&fps, fps_num, fps_denom); |
| |
| /* Level 10 */ |
| if (H263_FMT_UPTO_QCIF (params) && GST_FRACTION_LE (fps, fps15) && |
| bitrate <= 64000) |
| return 10; |
| |
| /* Level 20 */ |
| if (((H263_FMT_UPTO_QCIF (params) && GST_FRACTION_LE (fps, fps30)) || |
| (params->format == PICTURE_FMT_CIF && GST_FRACTION_LE (fps, fps15))) |
| && bitrate <= 128000) |
| return 20; |
| |
| /* Level 30 */ |
| if (H263_FMT_UPTO_CIF (params) && GST_FRACTION_LE (fps, fps30) && |
| bitrate <= 384000) |
| return 30; |
| |
| /* Level 40 */ |
| if (H263_FMT_UPTO_CIF (params) && GST_FRACTION_LE (fps, fps30) && |
| bitrate <= 2048000) |
| return 40; |
| |
| /* Level 45 */ |
| if ((H263_FMT_UPTO_QCIF (params) || (H263_FMT_CUSTOM_UPTO_QCIF (params) && |
| H263_PROFILE_NOT_0_2 (profile))) && |
| GST_FRACTION_LE (fps, fps15) && |
| /* (!h263parse->custompcfpresent || H263_PROFILE_NOT_0_2(profile)) && */ |
| bitrate <= 128000) |
| return 45; |
| |
| /* Level 50 */ |
| if ((H263_FMT_UPTO_CIF (params) || H263_FMT_CUSTOM_UPTO_CIF (params)) && |
| (GST_FRACTION_LE (fps, fps50) || |
| (params->width <= 352 && params->height <= 240 && |
| GST_FRACTION_LE (fps, fps60))) && (bitrate <= 4096000)) |
| return 50; |
| |
| /* Level 60 */ |
| if (((params->width <= 720 && params->height <= 288 && |
| GST_FRACTION_LE (fps, fps50)) || |
| (params->width <= 720 && params->height <= 240 && |
| GST_FRACTION_LE (fps, fps60))) && (bitrate <= 8192000)) |
| return 60; |
| |
| /* Level 70 */ |
| if (((params->width <= 720 && params->height <= 576 && |
| GST_FRACTION_LE (fps, fps50)) || |
| (params->width <= 720 && params->height <= 480 && |
| GST_FRACTION_LE (fps, fps60))) && (bitrate <= 16384000)) |
| return 70; |
| |
| GST_DEBUG ("Weird - didn't match any profile!"); |
| return -1; |
| } |
| |
| void |
| gst_h263_parse_get_framerate (const H263Params * params, gint * num, |
| gint * denom) |
| { |
| *num = params->pcfnum; |
| *denom = params->pcfdenom; |
| } |
| |
| void |
| gst_h263_parse_get_par (const H263Params * params, gint * num, gint * denom) |
| { |
| *num = params->parnum; |
| *denom = params->pardenom; |
| } |