Asterisk - The Open Source Telephony Project  18.5.0
res_format_attr_h263.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2012, Digium, Inc.
5  *
6  * Joshua Colp <[email protected]>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  *
18  */
19 
20 /*! \file
21  *
22  * \brief H.263 Format Attribute Module
23  *
24  * \author\verbatim Joshua Colp <[email protected]> \endverbatim
25  *
26  * This is a format attribute module for the H.263 codec.
27  * \ingroup applications
28  */
29 
30 /*** MODULEINFO
31  <support_level>core</support_level>
32  ***/
33 
34 #include "asterisk.h"
35 
36 #include <ctype.h> /* for toupper */
37 
38 #include "asterisk/module.h"
39 #include "asterisk/format.h"
40 #include "asterisk/strings.h" /* for ast_str_append */
41 #include "asterisk/utils.h" /* for ast_strip */
42 
43 /*! \brief Value that indicates an attribute is actually unset */
44 #define H263_ATTR_KEY_UNSET UINT8_MAX
45 
46 struct h263_attr {
47  unsigned int SQCIF; /*!< Minimum picture interval for SQCIF resolution */
48  unsigned int QCIF; /*!< Minimum picture interval for QCIF resolution */
49  unsigned int CIF; /*!< Minimum picture interval for CIF resolution */
50  unsigned int CIF4; /*!< Minimum picture interval for CIF4 resolution */
51  unsigned int CIF16; /*!< Minimum picture interval for CIF16 resolution */
52  unsigned int VGA; /*!< Minimum picture interval for VGA resolution */
53  unsigned int CUSTOM_XMAX; /*!< Custom resolution (Xmax) */
54  unsigned int CUSTOM_YMAX; /*!< Custom resolution (Ymax) */
55  unsigned int CUSTOM_MPI; /*!< Custom resolution (MPI) */
56  unsigned int CPCF; /*!< Custom Picture Clock Frequency */
57  unsigned int CPCF_2;
58  unsigned int CPCF_3;
59  unsigned int CPCF_4;
60  unsigned int CPCF_5;
61  unsigned int CPCF_6;
62  unsigned int CPCF_7;
63  unsigned int CPCF_MPI;
64  unsigned int F; /*!< F annex support */
65  unsigned int I; /*!< I annex support */
66  unsigned int J; /*!< J annex support */
67  unsigned int T; /*!< T annex support */
68  unsigned int K; /*!< K annex support */
69  unsigned int N; /*!< N annex support */
70  unsigned int P_SUB1; /*!< Reference picture resampling (sub mode 1) */
71  unsigned int P_SUB2; /*!< Reference picture resampling (sub mode 2) */
72  unsigned int P_SUB3; /*!< Reference picture resampling (sub mode 3) */
73  unsigned int P_SUB4; /*!< Reference picture resampling (sub mode 4) */
74  unsigned int PAR_WIDTH; /*!< Pixel aspect ratio (width) */
75  unsigned int PAR_HEIGHT; /*!< Pixel aspect ratio (height) */
76  unsigned int BPP; /*!< Bits per picture maximum */
77  unsigned int HRD; /*!< Hypothetical reference decoder status */
78  unsigned int MaxBR; /*!< Vendor Specific: CounterPath Bria (Solo) */
79 };
80 
81 static void h263_destroy(struct ast_format *format)
82 {
83  struct h263_attr *attr = ast_format_get_attribute_data(format);
84 
85  ast_free(attr);
86 }
87 
88 static int h263_clone(const struct ast_format *src, struct ast_format *dst)
89 {
90  struct h263_attr *original = ast_format_get_attribute_data(src);
91  struct h263_attr *attr = ast_calloc(1, sizeof(*attr));
92 
93  if (!attr) {
94  return -1;
95  }
96 
97  if (original) {
98  *attr = *original;
99  }
100 
102 
103  return 0;
104 }
105 
106 static enum ast_format_cmp_res h263_cmp(const struct ast_format *format1, const struct ast_format *format2)
107 {
108  struct h263_attr *attr1 = ast_format_get_attribute_data(format1);
109  struct h263_attr *attr2 = ast_format_get_attribute_data(format2);
110 
111  if (!attr1 || !attr2 || (attr1 && attr2 && !memcmp(attr1, attr2, sizeof(*attr1)))) {
112  return AST_FORMAT_CMP_EQUAL;
113  }
115 }
116 
117 #define DETERMINE_JOINT(joint, attr1, attr2, field) (joint->field = (attr1 && attr1->field) ? attr1->field : (attr2 && attr2->field) ? attr2->field : 0)
118 
119 static struct ast_format *h263_getjoint(const struct ast_format *format1, const struct ast_format *format2)
120 {
121  struct ast_format *cloned;
122  struct h263_attr *attr, *attr1, *attr2;
123 
124  cloned = ast_format_clone(format1);
125  if (!cloned) {
126  return NULL;
127  }
128  attr = ast_format_get_attribute_data(cloned);
129 
130  attr1 = ast_format_get_attribute_data(format1);
131  attr2 = ast_format_get_attribute_data(format2);
132 
133  DETERMINE_JOINT(attr, attr1, attr2, SQCIF);
134  DETERMINE_JOINT(attr, attr1, attr2, QCIF);
135  DETERMINE_JOINT(attr, attr1, attr2, CIF);
136  DETERMINE_JOINT(attr, attr1, attr2, CIF4);
137  DETERMINE_JOINT(attr, attr1, attr2, CIF16);
138  DETERMINE_JOINT(attr, attr1, attr2, VGA);
139  DETERMINE_JOINT(attr, attr1, attr2, CUSTOM_XMAX);
140  DETERMINE_JOINT(attr, attr1, attr2, CUSTOM_YMAX);
141  DETERMINE_JOINT(attr, attr1, attr2, CUSTOM_MPI);
142  DETERMINE_JOINT(attr, attr1, attr2, CPCF);
143  DETERMINE_JOINT(attr, attr1, attr2, CPCF_2);
144  DETERMINE_JOINT(attr, attr1, attr2, CPCF_3);
145  DETERMINE_JOINT(attr, attr1, attr2, CPCF_4);
146  DETERMINE_JOINT(attr, attr1, attr2, CPCF_5);
147  DETERMINE_JOINT(attr, attr1, attr2, CPCF_6);
148  DETERMINE_JOINT(attr, attr1, attr2, CPCF_7);
149  DETERMINE_JOINT(attr, attr1, attr2, CPCF_MPI);
150  DETERMINE_JOINT(attr, attr1, attr2, F);
151  DETERMINE_JOINT(attr, attr1, attr2, I);
152  DETERMINE_JOINT(attr, attr1, attr2, J);
153  DETERMINE_JOINT(attr, attr1, attr2, T);
154  DETERMINE_JOINT(attr, attr1, attr2, K);
155  DETERMINE_JOINT(attr, attr1, attr2, N);
156  DETERMINE_JOINT(attr, attr1, attr2, P_SUB1);
157  DETERMINE_JOINT(attr, attr1, attr2, P_SUB2);
158  DETERMINE_JOINT(attr, attr1, attr2, P_SUB3);
159  DETERMINE_JOINT(attr, attr1, attr2, P_SUB4);
160  DETERMINE_JOINT(attr, attr1, attr2, PAR_WIDTH);
161  DETERMINE_JOINT(attr, attr1, attr2, PAR_HEIGHT);
162  DETERMINE_JOINT(attr, attr1, attr2, BPP);
163  DETERMINE_JOINT(attr, attr1, attr2, HRD);
164  DETERMINE_JOINT(attr, attr1, attr2, MaxBR);
165 
166  return cloned;
167 }
168 
169 static struct ast_format *h263_parse_sdp_fmtp(const struct ast_format *format, const char *attributes)
170 {
171  char *attribs = ast_strdupa(attributes), *attrib;
172  struct ast_format *cloned;
173  struct h263_attr *attr;
174 
175  cloned = ast_format_clone(format);
176  if (!cloned) {
177  return NULL;
178  }
179  attr = ast_format_get_attribute_data(cloned);
180 
181  /* upper-case everything, so we are case-insensitive */
182  for (attrib = attribs; *attrib; ++attrib) {
183  *attrib = toupper(*attrib);
184  } /* based on channels/chan_sip.c:process_a_sdp_image() */
185 
186  attr->BPP = H263_ATTR_KEY_UNSET;
187  attr->MaxBR = H263_ATTR_KEY_UNSET;
190 
191  while ((attrib = strsep(&attribs, ";"))) {
192  unsigned int val, val2 = 0, val3 = 0, val4 = 0, val5 = 0, val6 = 0, val7 = 0, val8 = 0;
193 
194  attrib = ast_strip(attrib);
195 
196  if (sscanf(attrib, "SQCIF=%30u", &val) == 1) {
197  attr->SQCIF = val;
198  } else if (strcmp(attrib, "SQCIF") == 0) {
199  attr->SQCIF = 1;
200  } else if (sscanf(attrib, "QCIF=%30u", &val) == 1) {
201  attr->QCIF = val;
202  } else if (strcmp(attrib, "QCIF") == 0) {
203  attr->QCIF = 1;
204  } else if (sscanf(attrib, "CIF=%30u", &val) == 1) {
205  attr->CIF = val;
206  } else if (strcmp(attrib, "CIF") == 0) {
207  attr->CIF = 1;
208  } else if (sscanf(attrib, "CIF4=%30u", &val) == 1) {
209  attr->CIF4 = val;
210  } else if (strcmp(attrib, "CIF4") == 0) {
211  attr->CIF4 = 1;
212  } else if (sscanf(attrib, "CIF16=%30u", &val) == 1) {
213  attr->CIF16 = val;
214  } else if (strcmp(attrib, "CIF16") == 0) {
215  attr->CIF16 = 1;
216  } else if (sscanf(attrib, "VGA=%30u", &val) == 1) {
217  attr->VGA = val;
218  } else if (strcmp(attrib, "VGA") == 0) {
219  attr->VGA = 1;
220  } else if (sscanf(attrib, "CUSTOM=%30u,%30u,%30u", &val, &val2, &val3) == 3) {
221  attr->CUSTOM_XMAX = val;
222  attr->CUSTOM_YMAX = val2;
223  attr->CUSTOM_MPI = val3;
224  } else if (sscanf(attrib, "CPCF=%30u,%30u,%30u,%30u,%30u,%30u,%30u,%30u",
225  &val, &val2, &val3, &val4, &val5, &val6, &val7, &val8) == 8) {
226  attr->CPCF = val;
227  attr->CPCF_2 = val2;
228  attr->CPCF_3 = val3;
229  attr->CPCF_4 = val4;
230  attr->CPCF_5 = val5;
231  attr->CPCF_6 = val6;
232  attr->CPCF_7 = val7;
233  attr->CPCF_MPI = val8;
234  } else if (sscanf(attrib, "F=%30u", &val) == 1) {
235  attr->F = val;
236  } else if (sscanf(attrib, "I=%30u", &val) == 1) {
237  attr->I = val;
238  } else if (sscanf(attrib, "J=%30u", &val) == 1) {
239  attr->J = val;
240  } else if (sscanf(attrib, "T=%30u", &val) == 1) {
241  attr->T = val;
242  } else if (sscanf(attrib, "K=%30u", &val) == 1) {
243  attr->K = val;
244  } else if (sscanf(attrib, "N=%30u", &val) == 1) {
245  attr->N = val;
246  } else if (sscanf(attrib, "PAR=%30u:%30u", &val, &val2) == 2) {
247  attr->PAR_WIDTH = val;
248  attr->PAR_HEIGHT = val2;
249  } else if (sscanf(attrib, "BPP=%30u", &val) == 1) {
250  attr->BPP = val;
251  } else if (sscanf(attrib, "HRD=%30u", &val) == 1) {
252  attr->HRD = val;
253  } else if (sscanf(attrib, "P=%30u,%30u,%30u,%30u", &val, &val2, &val3, &val4) > 0) {
254  attr->P_SUB1 = val;
255  attr->P_SUB2 = val2;
256  attr->P_SUB3 = val3;
257  attr->P_SUB4 = val4;
258  } else if (sscanf(attrib, "MAXBR=%30u", &val) == 1) {
259  attr->MaxBR = val;
260  }
261  }
262 
263  return cloned;
264 }
265 
266 #define APPEND_IF_NOT_H263_UNSET(field, str, name) do { \
267  if (field != H263_ATTR_KEY_UNSET) { \
268  if (added) { \
269  ast_str_append(str, 0, ";"); \
270  } else if (0 < ast_str_append(str, 0, "a=fmtp:%u ", payload)) { \
271  added = 1; \
272  } \
273  ast_str_append(str, 0, "%s=%u", name, field); \
274  } \
275 } while (0)
276 
277 #define APPEND_IF_NONZERO(field, str, name) do { \
278  if (field) { \
279  if (added) { \
280  ast_str_append(str, 0, ";"); \
281  } else if (0 < ast_str_append(str, 0, "a=fmtp:%u ", payload)) { \
282  added = 1; \
283  } \
284  ast_str_append(str, 0, "%s=%u", name, field); \
285  } \
286 } while (0)
287 
288 static void h263_generate_sdp_fmtp(const struct ast_format *format, unsigned int payload, struct ast_str **str)
289 {
290  struct h263_attr *attr = ast_format_get_attribute_data(format);
291  int added = 0;
292 
293  if (!attr) {
294  return;
295  }
296 
297  if (attr->CPCF) {
298  if (added) {
299  ast_str_append(str, 0, ";");
300  } else if (0 < ast_str_append(str, 0, "a=fmtp:%u ", payload)) {
301  added = 1;
302  }
303  ast_str_append(str, 0, "CPCF=%u,%u,%u,%u,%u,%u,%u,%u", attr->CPCF, attr->CPCF_2, attr->CPCF_3,
304  attr->CPCF_4, attr->CPCF_5, attr->CPCF_6, attr->CPCF_7, attr->CPCF_MPI);
305  }
306 
307  APPEND_IF_NONZERO(attr->CIF16, str, "CIF16");
308  APPEND_IF_NONZERO(attr->CIF4, str, "CIF4");
309  APPEND_IF_NONZERO(attr->VGA, str, "VGA");
310  APPEND_IF_NONZERO(attr->CIF, str, "CIF");
311  APPEND_IF_NONZERO(attr->QCIF, str, "QCIF");
312  APPEND_IF_NONZERO(attr->SQCIF, str, "SQCIF");
313 
314  if (attr->CUSTOM_XMAX && attr->CUSTOM_YMAX && attr->CUSTOM_MPI) {
315  if (added) {
316  ast_str_append(str, 0, ";");
317  } else if (0 < ast_str_append(str, 0, "a=fmtp:%u ", payload)) {
318  added = 1;
319  }
320  ast_str_append(str, 0, "CUSTOM=%u,%u,%u", attr->CUSTOM_XMAX, attr->CUSTOM_YMAX, attr->CUSTOM_MPI);
321  }
322 
323  APPEND_IF_NONZERO(attr->F, str, "F");
324  APPEND_IF_NONZERO(attr->I, str, "I");
325  APPEND_IF_NONZERO(attr->J, str, "J");
326  APPEND_IF_NONZERO(attr->T, str, "T");
327  APPEND_IF_NONZERO(attr->K, str, "K");
328  APPEND_IF_NONZERO(attr->N, str, "N");
329 
330  if (attr->P_SUB1) {
331  if (added) {
332  ast_str_append(str, 0, ";");
333  } else if (0 < ast_str_append(str, 0, "a=fmtp:%u ", payload)) {
334  added = 1;
335  }
336  ast_str_append(str, 0, "P=%u", attr->P_SUB1);
337  if (attr->P_SUB2) {
338  ast_str_append(str, 0, ",%u", attr->P_SUB2);
339  }
340  if (attr->P_SUB3) {
341  ast_str_append(str, 0, ",%u", attr->P_SUB3);
342  }
343  if (attr->P_SUB4) {
344  ast_str_append(str, 0, ",%u", attr->P_SUB4);
345  }
346  }
347 
348  if (attr->PAR_WIDTH != H263_ATTR_KEY_UNSET && attr->PAR_HEIGHT != H263_ATTR_KEY_UNSET) {
349  if (added) {
350  ast_str_append(str, 0, ";");
351  } else if (0 < ast_str_append(str, 0, "a=fmtp:%u ", payload)) {
352  added = 1; \
353  }
354  ast_str_append(str, 0, "PAR=%u:%u", attr->PAR_WIDTH, attr->PAR_HEIGHT);
355  }
356 
357  APPEND_IF_NOT_H263_UNSET(attr->BPP, str, "BPP");
358 
359  APPEND_IF_NONZERO(attr->HRD, str, "HRD");
360 
361  APPEND_IF_NOT_H263_UNSET(attr->MaxBR, str, "MaxBR");
362 
363  ast_str_append(str, 0, "\r\n");
364 
365  return;
366 }
367 
370  .format_clone = h263_clone,
371  .format_cmp = h263_cmp,
372  .format_get_joint = h263_getjoint,
373  .format_parse_sdp_fmtp = h263_parse_sdp_fmtp,
374  .format_generate_sdp_fmtp = h263_generate_sdp_fmtp,
375 };
376 
377 static int unload_module(void)
378 {
379  return 0;
380 }
381 
382 static int load_module(void)
383 {
384  if (ast_format_interface_register("h263", &h263_interface)) {
386  }
387 
388  if (ast_format_interface_register("h263p", &h263_interface)) {
390  }
391 
393 }
394 
395 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "H.263 Format Attribute Module",
396  .support_level = AST_MODULE_SUPPORT_CORE,
397  .load = load_module,
398  .unload = unload_module,
399 );
static void h263_destroy(struct ast_format *format)
#define APPEND_IF_NONZERO(field, str, name)
unsigned int N
Asterisk main include file. File version handling, generic pbx functions.
unsigned int HRD
unsigned int CIF4
Optional format interface to extend format operations.
Definition: format.h:44
unsigned int VGA
String manipulation functions.
static int h263_clone(const struct ast_format *src, struct ast_format *dst)
Definition: ast_expr2.c:325
#define H263_ATTR_KEY_UNSET
Value that indicates an attribute is actually unset.
static int unload_module(void)
unsigned int CIF16
unsigned int CPCF_5
#define APPEND_IF_NOT_H263_UNSET(field, str, name)
unsigned int CUSTOM_MPI
Definition of a media format.
Definition: format.c:43
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1091
void * ast_format_get_attribute_data(const struct ast_format *format)
Get the attribute data on a format.
Definition: format.c:125
unsigned int CPCF_6
const char * str
Definition: app_jack.c:147
unsigned int P_SUB2
#define NULL
Definition: resample.c:96
Utility functions.
Media Format API.
unsigned int P_SUB4
static void h263_generate_sdp_fmtp(const struct ast_format *format, unsigned int payload, struct ast_str **str)
struct ast_format * ast_format_clone(const struct ast_format *format)
Clone an existing media format so it can be modified.
Definition: format.c:180
unsigned int CPCF_3
void(*const format_destroy)(struct ast_format *format)
Callback for when the format is destroyed, used to release attribute resources.
Definition: format.h:50
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition: strings.h:219
unsigned int BPP
ast_format_cmp_res
Format comparison results.
Definition: format.h:34
unsigned int P_SUB1
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
unsigned int CPCF_4
static enum ast_format_cmp_res h263_cmp(const struct ast_format *format1, const struct ast_format *format2)
unsigned int T
unsigned int CPCF
unsigned int I
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
#define ast_format_interface_register(codec, interface)
Register a format interface for use with the provided codec.
Definition: format.h:273
unsigned int PAR_HEIGHT
unsigned int SQCIF
unsigned int CPCF_MPI
unsigned int PAR_WIDTH
static struct ast_format * h263_getjoint(const struct ast_format *format1, const struct ast_format *format2)
#define ast_free(a)
Definition: astmm.h:182
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
unsigned int K
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
unsigned int P_SUB3
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS|AST_MODFLAG_LOAD_ORDER, "HTTP Phone Provisioning",.support_level=AST_MODULE_SUPPORT_EXTENDED,.load=load_module,.unload=unload_module,.reload=reload,.load_pri=AST_MODPRI_CHANNEL_DEPEND,.requires="http",)
unsigned int CUSTOM_YMAX
unsigned int CPCF_7
char * strsep(char **str, const char *delims)
void ast_format_set_attribute_data(struct ast_format *format, void *attribute_data)
Set the attribute data on a format.
Definition: format.c:130
unsigned int CUSTOM_XMAX
static int load_module(void)
unsigned int QCIF
#define DETERMINE_JOINT(joint, attr1, attr2, field)
static struct ast_format * h263_parse_sdp_fmtp(const struct ast_format *format, const char *attributes)
unsigned int CIF
unsigned int CPCF_2
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
Asterisk module definitions.
static snd_pcm_format_t format
Definition: chan_alsa.c:102
unsigned int F
static struct ast_format_interface h263_interface
unsigned int J
unsigned int MaxBR