Sat Apr 26 2014 22:01:40

Asterisk developer's documentation


res_format_attr_h263.c
Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 2012, Digium, Inc.
00005  *
00006  * Joshua Colp <jcolp@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  *
00018  */
00019 
00020 /*! \file
00021  *
00022  * \brief H.263 Format Attribute Module
00023  *
00024  * \author\verbatim Joshua Colp <jcolp@digium.com> \endverbatim
00025  *
00026  * This is a format attribute module for the H.263 codec.
00027  * \ingroup applications
00028  */
00029 
00030 /*** MODULEINFO
00031    <support_level>core</support_level>
00032  ***/
00033 
00034 #include "asterisk.h"
00035 
00036 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 370060 $")
00037 
00038 #include "asterisk/module.h"
00039 #include "asterisk/format.h"
00040 
00041 enum h263_attr_keys {
00042    H263_ATTR_KEY_SQCIF,       /*!< Minimum picture interval for SQCIF resolution */
00043    H263_ATTR_KEY_QCIF,        /*!< Minimum picture interval for QCIF resolution */
00044    H263_ATTR_KEY_CIF,         /*!< Minimum picture interval for CIF resolution */
00045    H263_ATTR_KEY_CIF4,        /*!< Minimum picture interval for CIF4 resolution */
00046    H263_ATTR_KEY_CIF16,       /*!< Minimum picture interval for CIF16 resolution */
00047    H263_ATTR_KEY_VGA,         /*!< Minimum picture interval for VGA resolution */
00048    H263_ATTR_KEY_CUSTOM_XMAX, /*!< Custom resolution (Xmax) */
00049    H263_ATTR_KEY_CUSTOM_YMAX, /*!< Custom resolution (Ymax) */
00050    H263_ATTR_KEY_CUSTOM_MPI,  /*!< Custom resolution (MPI) */
00051    H263_ATTR_KEY_F,           /*!< F annex support */
00052    H263_ATTR_KEY_I,           /*!< I annex support */
00053    H263_ATTR_KEY_J,           /*!< J annex support */
00054    H263_ATTR_KEY_T,           /*!< T annex support */
00055    H263_ATTR_KEY_K,           /*!< K annex support */
00056    H263_ATTR_KEY_N,           /*!< N annex support */
00057    H263_ATTR_KEY_P_SUB1,      /*!< Reference picture resampling (sub mode 1) */
00058    H263_ATTR_KEY_P_SUB2,      /*!< Reference picture resampling (sub mode 2) */
00059    H263_ATTR_KEY_P_SUB3,      /*!< Reference picture resampling (sub mode 3) */
00060    H263_ATTR_KEY_P_SUB4,      /*!< Reference picture resampling (sub mode 4) */
00061    H263_ATTR_KEY_PAR_WIDTH,   /*!< Pixel aspect ratio (width) */
00062    H263_ATTR_KEY_PAR_HEIGHT,  /*!< Pixel aspect ratio (height) */
00063    H263_ATTR_KEY_BPP,         /*!< Bits per picture maximum */
00064    H263_ATTR_KEY_HRD,         /*!< Hypothetical reference decoder status */
00065    H263_ATTR_KEY_END,         /*!< End terminator for list */
00066 };
00067 
00068 static int h263_format_attr_get_joint(const struct ast_format_attr *fattr1, const struct ast_format_attr *fattr2, struct ast_format_attr *result)
00069 {
00070    int i;
00071 
00072    /* These are all receiver options so we just copy over what they sent */
00073    for (i = H263_ATTR_KEY_SQCIF; i < H263_ATTR_KEY_END; i++) {
00074       result->format_attr[i] = fattr1->format_attr[i] ? fattr1->format_attr[i] : fattr2->format_attr[i];
00075    }
00076 
00077    return 0;
00078 }
00079 
00080 static int h263_format_attr_sdp_parse(struct ast_format_attr *format_attr, const char *attributes)
00081 {
00082    char *attribs = ast_strdupa(attributes), *attrib;
00083 
00084    while ((attrib = strsep(&attribs, ";"))) {
00085       unsigned int val, val2 = 0, val3 = 0, val4 = 0;
00086 
00087       if (sscanf(attrib, "SQCIF=%30u", &val) == 1) {
00088          format_attr->format_attr[H263_ATTR_KEY_SQCIF] = val;
00089       } else if (sscanf(attrib, "QCIF=%30u", &val) == 1) {
00090          format_attr->format_attr[H263_ATTR_KEY_QCIF] = val;
00091       } else if (sscanf(attrib, "CIF=%30u", &val) == 1) {
00092          format_attr->format_attr[H263_ATTR_KEY_CIF] = val;
00093       } else if (sscanf(attrib, "CIF4=%30u", &val) == 1) {
00094          format_attr->format_attr[H263_ATTR_KEY_CIF4] = val;
00095       } else if (sscanf(attrib, "CIF16=%30u", &val) == 1) {
00096          format_attr->format_attr[H263_ATTR_KEY_CIF16] = val;
00097       } else if (sscanf(attrib, "VGA=%30u", &val) == 1) {
00098          format_attr->format_attr[H263_ATTR_KEY_VGA] = val;
00099       } else if (sscanf(attrib, "CUSTOM=%30u,%30u,%30u", &val, &val2, &val3) == 3) {
00100          format_attr->format_attr[H263_ATTR_KEY_CUSTOM_XMAX] = val;
00101          format_attr->format_attr[H263_ATTR_KEY_CUSTOM_YMAX] = val2;
00102          format_attr->format_attr[H263_ATTR_KEY_CUSTOM_MPI] = val3;
00103       } else if (sscanf(attrib, "F=%30u", &val) == 1) {
00104          format_attr->format_attr[H263_ATTR_KEY_F] = val;
00105       } else if (sscanf(attrib, "I=%30u", &val) == 1) {
00106          format_attr->format_attr[H263_ATTR_KEY_I] = val;
00107       } else if (sscanf(attrib, "J=%30u", &val) == 1) {
00108          format_attr->format_attr[H263_ATTR_KEY_J] = val;
00109       } else if (sscanf(attrib, "T=%30u", &val) == 1) {
00110          format_attr->format_attr[H263_ATTR_KEY_T] = val;
00111       } else if (sscanf(attrib, "K=%30u", &val) == 1) {
00112          format_attr->format_attr[H263_ATTR_KEY_K] = val;
00113       } else if (sscanf(attrib, "N=%30u", &val) == 1) {
00114          format_attr->format_attr[H263_ATTR_KEY_N] = val;
00115       } else if (sscanf(attrib, "PAR=%30u:%30u", &val, &val2) == 2) {
00116          format_attr->format_attr[H263_ATTR_KEY_PAR_WIDTH] = val;
00117          format_attr->format_attr[H263_ATTR_KEY_PAR_HEIGHT] = val2;
00118       } else if (sscanf(attrib, "BPP=%30u", &val) == 1) {
00119          format_attr->format_attr[H263_ATTR_KEY_BPP] = val;
00120       } else if (sscanf(attrib, "HRD=%30u", &val) == 1) {
00121          format_attr->format_attr[H263_ATTR_KEY_HRD] = val;
00122       } else if (sscanf(attrib, "P=%30u,%30u,%30u,%30u", &val, &val2, &val3, &val4) > 0) {
00123          format_attr->format_attr[H263_ATTR_KEY_P_SUB1] = val;
00124          format_attr->format_attr[H263_ATTR_KEY_P_SUB2] = val2;
00125          format_attr->format_attr[H263_ATTR_KEY_P_SUB3] = val3;
00126          format_attr->format_attr[H263_ATTR_KEY_P_SUB4] = val4;
00127       }
00128    }
00129 
00130    return 0;
00131 }
00132 
00133 /*! \brief Helper function which converts a key enum into a string value for SDP */
00134 static const char *h263_attr_key_to_str(enum h263_attr_keys key, const struct ast_format_attr *format_attr)
00135 {
00136    switch (key) {
00137    case H263_ATTR_KEY_SQCIF:
00138       return format_attr->format_attr[key] ? "SQCIF" : NULL;
00139    case H263_ATTR_KEY_QCIF:
00140       return format_attr->format_attr[key] ? "QCIF" : NULL;
00141    case H263_ATTR_KEY_CIF:
00142       return format_attr->format_attr[key] ? "CIF" : NULL;
00143    case H263_ATTR_KEY_CIF4:
00144       return format_attr->format_attr[key] ? "CIF4" : NULL;
00145    case H263_ATTR_KEY_CIF16:
00146       return format_attr->format_attr[key] ? "CIF16" : NULL;
00147    case H263_ATTR_KEY_VGA:
00148       return format_attr->format_attr[key] ? "VGA" : NULL;
00149    case H263_ATTR_KEY_F:
00150       return "F";
00151    case H263_ATTR_KEY_I:
00152       return "I";
00153    case H263_ATTR_KEY_J:
00154       return "J";
00155    case H263_ATTR_KEY_T:
00156       return "T";
00157    case H263_ATTR_KEY_K:
00158       return "K";
00159    case H263_ATTR_KEY_N:
00160       return "N";
00161    case H263_ATTR_KEY_BPP:
00162       return "BPP";
00163    case H263_ATTR_KEY_HRD:
00164       return "HRD";
00165    case H263_ATTR_KEY_CUSTOM_XMAX:
00166    case H263_ATTR_KEY_CUSTOM_YMAX:
00167    case H263_ATTR_KEY_CUSTOM_MPI:
00168    case H263_ATTR_KEY_P_SUB1:
00169    case H263_ATTR_KEY_P_SUB2:
00170    case H263_ATTR_KEY_P_SUB3:
00171    case H263_ATTR_KEY_P_SUB4:
00172    case H263_ATTR_KEY_PAR_WIDTH:
00173    case H263_ATTR_KEY_PAR_HEIGHT:
00174    case H263_ATTR_KEY_END:
00175    default:
00176       return NULL;
00177    }
00178 
00179    return NULL;
00180 }
00181 
00182 static void h263_format_attr_sdp_generate(const struct ast_format_attr *format_attr, unsigned int payload, struct ast_str **str)
00183 {
00184    int i, added = 0;
00185 
00186    for (i = H263_ATTR_KEY_SQCIF; i < H263_ATTR_KEY_END; i++) {
00187       const char *name;
00188 
00189       if (i == H263_ATTR_KEY_CUSTOM_XMAX) {
00190          if (!format_attr->format_attr[H263_ATTR_KEY_CUSTOM_XMAX] || !format_attr->format_attr[H263_ATTR_KEY_CUSTOM_YMAX] ||
00191              !format_attr->format_attr[H263_ATTR_KEY_CUSTOM_MPI]) {
00192             continue;
00193          }
00194 
00195          if (!added) {
00196             ast_str_append(str, 0, "a=fmtp:%d CUSTOM=%u,%u,%u", payload, format_attr->format_attr[H263_ATTR_KEY_CUSTOM_XMAX],
00197                       format_attr->format_attr[H263_ATTR_KEY_CUSTOM_YMAX], format_attr->format_attr[H263_ATTR_KEY_CUSTOM_MPI]);
00198             added = 1;
00199          } else {
00200             ast_str_append(str, 0, ";CUSTOM=%u,%u,%u", format_attr->format_attr[H263_ATTR_KEY_CUSTOM_XMAX],
00201                       format_attr->format_attr[H263_ATTR_KEY_CUSTOM_YMAX], format_attr->format_attr[H263_ATTR_KEY_CUSTOM_MPI]);
00202          }
00203       } else if (i == H263_ATTR_KEY_PAR_WIDTH) {
00204          if (!format_attr->format_attr[H263_ATTR_KEY_PAR_WIDTH] || !format_attr->format_attr[H263_ATTR_KEY_PAR_HEIGHT]) {
00205             continue;
00206          }
00207 
00208          if (!added) {
00209             ast_str_append(str, 0, "a=fmtp:%d PAR=%u:%u", payload, format_attr->format_attr[H263_ATTR_KEY_PAR_WIDTH],
00210                       format_attr->format_attr[H263_ATTR_KEY_PAR_HEIGHT]);
00211             added = 1;
00212          } else {
00213             ast_str_append(str, 0, ";PAR=%u:%u", format_attr->format_attr[H263_ATTR_KEY_PAR_WIDTH],
00214                       format_attr->format_attr[H263_ATTR_KEY_PAR_HEIGHT]);
00215          }
00216       } else if (i == H263_ATTR_KEY_P_SUB1) {
00217          if (!format_attr->format_attr[H263_ATTR_KEY_P_SUB1]) {
00218             continue;
00219          }
00220 
00221          if (!added) {
00222             ast_str_append(str, 0, "a=fmtp:%d P=%u", payload, format_attr->format_attr[H263_ATTR_KEY_P_SUB1]);
00223             added = 1;
00224          } else {
00225             ast_str_append(str, 0, ";P=%u", format_attr->format_attr[H263_ATTR_KEY_P_SUB1]);
00226          }
00227 
00228          if (format_attr->format_attr[H263_ATTR_KEY_P_SUB2]) {
00229             ast_str_append(str, 0, ",%u", format_attr->format_attr[H263_ATTR_KEY_P_SUB2]);
00230          }
00231                         if (format_attr->format_attr[H263_ATTR_KEY_P_SUB3]) {
00232                                 ast_str_append(str, 0, ",%u", format_attr->format_attr[H263_ATTR_KEY_P_SUB3]);
00233                         }
00234                         if (format_attr->format_attr[H263_ATTR_KEY_P_SUB4]) {
00235                                 ast_str_append(str, 0, ",%u", format_attr->format_attr[H263_ATTR_KEY_P_SUB4]);
00236                         }
00237 
00238       } else if ((name = h263_attr_key_to_str(i, format_attr))) {
00239          if (!added) {
00240             ast_str_append(str, 0, "a=fmtp:%d %s=%u", payload, name, format_attr->format_attr[i]);
00241             added = 1;
00242          } else {
00243             ast_str_append(str, 0, ";%s=%u", name, format_attr->format_attr[i]);
00244          }
00245       }
00246    }
00247 
00248    if (added) {
00249       ast_str_append(str, 0, "\r\n");
00250    }
00251 
00252    return;
00253 }
00254 
00255 static struct ast_format_attr_interface h263_format_attr_interface = {
00256    .id = AST_FORMAT_H263,
00257    .format_attr_get_joint = h263_format_attr_get_joint,
00258    .format_attr_sdp_parse = h263_format_attr_sdp_parse,
00259    .format_attr_sdp_generate = h263_format_attr_sdp_generate,
00260 };
00261 
00262 static struct ast_format_attr_interface h263p_format_attr_interface = {
00263         .id = AST_FORMAT_H263_PLUS,
00264    .format_attr_get_joint = h263_format_attr_get_joint,
00265         .format_attr_sdp_parse = h263_format_attr_sdp_parse,
00266         .format_attr_sdp_generate = h263_format_attr_sdp_generate,
00267 };
00268 
00269 static int unload_module(void)
00270 {
00271    ast_format_attr_unreg_interface(&h263_format_attr_interface);
00272    ast_format_attr_unreg_interface(&h263p_format_attr_interface);
00273 
00274    return 0;
00275 }
00276 
00277 static int load_module(void)
00278 {
00279    if (ast_format_attr_reg_interface(&h263_format_attr_interface)) {
00280       return AST_MODULE_LOAD_DECLINE;
00281    }
00282 
00283    if (ast_format_attr_reg_interface(&h263p_format_attr_interface)) {
00284       ast_format_attr_unreg_interface(&h263_format_attr_interface);
00285       return AST_MODULE_LOAD_DECLINE;
00286    }
00287 
00288    return AST_MODULE_LOAD_SUCCESS;
00289 }
00290 
00291 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "H.263 Format Attribute Module",
00292    .load = load_module,
00293    .unload = unload_module,
00294    .load_pri = AST_MODPRI_DEFAULT,
00295 );