blob: 98a30e7975ef0d026fd501e3fa8cd54f564959b9 [file] [log] [blame]
/* 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, &params->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 (" 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;
}