extensions.c (23462B)
1 /* Copyright (c) 2022 Amazon */ 2 /* 3 Redistribution and use in source and binary forms, with or without 4 modification, are permitted provided that the following conditions 5 are met: 6 7 - Redistributions of source code must retain the above copyright 8 notice, this list of conditions and the following disclaimer. 9 10 - Redistributions in binary form must reproduce the above copyright 11 notice, this list of conditions and the following disclaimer in the 12 documentation and/or other materials provided with the distribution. 13 14 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 15 ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 16 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 17 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 18 OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 21 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 22 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 23 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #ifdef HAVE_CONFIG_H 28 #include "config.h" 29 #endif 30 31 32 #include "opus_types.h" 33 #include "opus_defines.h" 34 #include "arch.h" 35 #include "os_support.h" 36 #include "opus_private.h" 37 38 39 /* Given an extension payload (i.e., excluding the initial ID byte), advance 40 data to the next extension and return the length of the remaining 41 extensions. 42 N.B., a "Repeat These Extensions" extension (ID==2) does not advance past 43 the repeated extension payloads. 44 That requires higher-level logic. */ 45 static opus_int32 skip_extension_payload(const unsigned char **pdata, 46 opus_int32 len, opus_int32 *pheader_size, int id_byte, 47 opus_int32 trailing_short_len) 48 { 49 const unsigned char *data; 50 opus_int32 header_size; 51 int id, L; 52 data = *pdata; 53 header_size = 0; 54 id = id_byte>>1; 55 L = id_byte&1; 56 if ((id == 0 && L == 1) || id == 2) 57 { 58 /* Nothing to do. */ 59 } else if (id > 0 && id < 32) 60 { 61 if (len < L) 62 return -1; 63 data += L; 64 len -= L; 65 } else { 66 if (L==0) 67 { 68 if (len < trailing_short_len) return -1; 69 data += len - trailing_short_len; 70 len = trailing_short_len; 71 } else { 72 opus_int32 bytes=0; 73 opus_int32 lacing; 74 do { 75 if (len < 1) 76 return -1; 77 lacing = *data++; 78 bytes += lacing; 79 header_size++; 80 len -= lacing + 1; 81 } while (lacing == 255); 82 if (len < 0) 83 return -1; 84 data += bytes; 85 } 86 } 87 *pdata = data; 88 *pheader_size = header_size; 89 return len; 90 } 91 92 /* Given an extension, advance data to the next extension and return the 93 length of the remaining extensions. 94 N.B., a "Repeat These Extensions" extension (ID==2) only advances past the 95 extension ID byte. 96 Higher-level logic is required to skip the extension payloads that come 97 after it.*/ 98 static opus_int32 skip_extension(const unsigned char **pdata, opus_int32 len, 99 opus_int32 *pheader_size) 100 { 101 const unsigned char *data; 102 int id_byte; 103 if (len == 0) { 104 *pheader_size = 0; 105 return 0; 106 } 107 if (len < 1) 108 return -1; 109 data = *pdata; 110 id_byte = *data++; 111 len--; 112 len = skip_extension_payload(&data, len, pheader_size, id_byte, 0); 113 if (len >= 0) { 114 *pdata = data; 115 (*pheader_size)++; 116 } 117 return len; 118 } 119 120 void opus_extension_iterator_init(OpusExtensionIterator *iter, 121 const unsigned char *data, opus_int32 len, opus_int32 nb_frames) { 122 celt_assert(len >= 0); 123 celt_assert(data != NULL || len == 0); 124 celt_assert(nb_frames >= 0 && nb_frames <= 48); 125 iter->repeat_data = iter->curr_data = iter->data = data; 126 iter->last_long = iter->src_data = NULL; 127 iter->curr_len = iter->len = len; 128 iter->repeat_len = iter->src_len = 0; 129 iter->trailing_short_len = 0; 130 iter->frame_max = iter->nb_frames = nb_frames; 131 iter->repeat_frame = iter->curr_frame = 0; 132 iter->repeat_l = 0; 133 } 134 135 /* Reset the iterator so it can start iterating again from the first 136 extension. */ 137 void opus_extension_iterator_reset(OpusExtensionIterator *iter) { 138 iter->repeat_data = iter->curr_data = iter->data; 139 iter->last_long = NULL; 140 iter->curr_len = iter->len; 141 iter->repeat_frame = iter->curr_frame = 0; 142 iter->trailing_short_len = 0; 143 } 144 145 /* Tell the iterator not to return any extensions for frames of index 146 frame_max or larger. 147 This can allow it to stop iterating early if these extensions are not 148 needed. */ 149 void opus_extension_iterator_set_frame_max(OpusExtensionIterator *iter, 150 int frame_max) { 151 iter->frame_max = frame_max; 152 } 153 154 /* Return the next repeated extension. 155 The return value is non-zero if one is found, negative on error, or 0 if we 156 have finished repeating extensions. */ 157 static int opus_extension_iterator_next_repeat(OpusExtensionIterator *iter, 158 opus_extension_data *ext) { 159 opus_int32 header_size; 160 celt_assert(iter->repeat_frame > 0); 161 for (;iter->repeat_frame < iter->nb_frames; iter->repeat_frame++) { 162 while (iter->src_len > 0) { 163 const unsigned char *curr_data0; 164 int repeat_id_byte; 165 repeat_id_byte = *iter->src_data; 166 iter->src_len = skip_extension(&iter->src_data, iter->src_len, 167 &header_size); 168 /* We skipped this extension earlier, so it should not fail now. */ 169 celt_assert(iter->src_len >= 0); 170 /* Don't repeat padding or frame separators with a 0 increment. */ 171 if (repeat_id_byte <= 3) continue; 172 /* If the "Repeat These Extensions" extension had L == 0 and this 173 is the last repeated long extension, then force decoding the 174 payload with L = 0. */ 175 if (iter->repeat_l == 0 176 && iter->repeat_frame + 1 >= iter->nb_frames 177 && iter->src_data == iter->last_long) { 178 repeat_id_byte &= ~1; 179 } 180 curr_data0 = iter->curr_data; 181 iter->curr_len = skip_extension_payload(&iter->curr_data, 182 iter->curr_len, &header_size, repeat_id_byte, 183 iter->trailing_short_len); 184 if (iter->curr_len < 0) { 185 return OPUS_INVALID_PACKET; 186 } 187 celt_assert(iter->curr_data - iter->data 188 == iter->len - iter->curr_len); 189 /* If we were asked to stop at frame_max, skip extensions for later 190 frames. */ 191 if (iter->repeat_frame >= iter->frame_max) { 192 continue; 193 } 194 if (ext != NULL) { 195 ext->id = repeat_id_byte >> 1; 196 ext->frame = iter->repeat_frame; 197 ext->data = curr_data0 + header_size; 198 ext->len = iter->curr_data - curr_data0 - header_size; 199 } 200 return 1; 201 } 202 /* We finished repeating the extensions for this frame. */ 203 iter->src_data = iter->repeat_data; 204 iter->src_len = iter->repeat_len; 205 } 206 /* We finished repeating extensions. */ 207 iter->repeat_data = iter->curr_data; 208 iter->last_long = NULL; 209 /* If L == 0, advance the frame number to handle the case where we did 210 not consume all of the data with an L == 0 long extension. */ 211 if (iter->repeat_l == 0) { 212 iter->curr_frame++; 213 /* Ignore additional padding if this was already the last frame. */ 214 if (iter->curr_frame >= iter->nb_frames) { 215 iter->curr_len = 0; 216 } 217 } 218 iter->repeat_frame = 0; 219 return 0; 220 } 221 222 /* Return the next extension (excluding real padding, separators, and repeat 223 indicators, but including the repeated extensions) in bitstream order. 224 Due to the extension repetition mechanism, extensions are not necessarily 225 returned in frame order. */ 226 int opus_extension_iterator_next(OpusExtensionIterator *iter, 227 opus_extension_data *ext) { 228 opus_int32 header_size; 229 if (iter->curr_len < 0) { 230 return OPUS_INVALID_PACKET; 231 } 232 if (iter->repeat_frame > 0) { 233 int ret; 234 /* We are in the process of repeating some extensions. */ 235 ret = opus_extension_iterator_next_repeat(iter, ext); 236 if (ret) return ret; 237 } 238 /* Checking this here allows opus_extension_iterator_set_frame_max() to be 239 called at any point. */ 240 if (iter->curr_frame >= iter->frame_max) { 241 return 0; 242 } 243 while (iter->curr_len > 0) { 244 const unsigned char *curr_data0; 245 int id; 246 int L; 247 curr_data0 = iter->curr_data; 248 id = *curr_data0>>1; 249 L = *curr_data0&1; 250 iter->curr_len = skip_extension(&iter->curr_data, iter->curr_len, 251 &header_size); 252 if (iter->curr_len < 0) { 253 return OPUS_INVALID_PACKET; 254 } 255 celt_assert(iter->curr_data - iter->data == iter->len - iter->curr_len); 256 if (id == 1) { 257 if (L == 0) { 258 iter->curr_frame++; 259 } 260 else { 261 /* A frame increment of 0 is a no-op. */ 262 if (!curr_data0[1]) continue; 263 iter->curr_frame += curr_data0[1]; 264 } 265 if (iter->curr_frame >= iter->nb_frames) { 266 iter->curr_len = -1; 267 return OPUS_INVALID_PACKET; 268 } 269 /* If we were asked to stop at frame_max, skip extensions for later 270 frames. */ 271 if (iter->curr_frame >= iter->frame_max) { 272 iter->curr_len = 0; 273 } 274 iter->repeat_data = iter->curr_data; 275 iter->last_long = NULL; 276 iter->trailing_short_len = 0; 277 } 278 else if (id == 2) { 279 int ret; 280 iter->repeat_l = L; 281 iter->repeat_frame = iter->curr_frame + 1; 282 iter->repeat_len = curr_data0 - iter->repeat_data; 283 iter->src_data = iter->repeat_data; 284 iter->src_len = iter->repeat_len; 285 ret = opus_extension_iterator_next_repeat(iter, ext); 286 if (ret) return ret; 287 } 288 else if (id > 2) { 289 /* Update the location of the last long extension. 290 This lets us know when we need to modify the last L flag if we 291 repeat these extensions with L=0. */ 292 if (id >= 32) { 293 iter->last_long = iter->curr_data; 294 iter->trailing_short_len = 0; 295 } 296 /* Otherwise, keep track of how many payload bytes follow the last 297 long extension. */ 298 else iter->trailing_short_len += L; 299 if (ext != NULL) { 300 ext->id = id; 301 ext->frame = iter->curr_frame; 302 ext->data = curr_data0 + header_size; 303 ext->len = iter->curr_data - curr_data0 - header_size; 304 } 305 return 1; 306 } 307 } 308 return 0; 309 } 310 311 int opus_extension_iterator_find(OpusExtensionIterator *iter, 312 opus_extension_data *ext, int id) { 313 opus_extension_data curr_ext; 314 int ret; 315 for(;;) { 316 ret = opus_extension_iterator_next(iter, &curr_ext); 317 if (ret <= 0) { 318 return ret; 319 } 320 if (curr_ext.id == id) { 321 *ext = curr_ext; 322 return ret; 323 } 324 } 325 } 326 327 /* Count the number of extensions, excluding real padding, separators, and 328 repeat indicators, but including the repeated extensions. */ 329 opus_int32 opus_packet_extensions_count(const unsigned char *data, 330 opus_int32 len, int nb_frames) 331 { 332 OpusExtensionIterator iter; 333 int count; 334 opus_extension_iterator_init(&iter, data, len, nb_frames); 335 for (count=0; opus_extension_iterator_next(&iter, NULL) > 0; count++); 336 return count; 337 } 338 339 /* Count the number of extensions for each frame, excluding real padding and 340 separators and repeat indicators, but including the repeated extensions. */ 341 opus_int32 opus_packet_extensions_count_ext(const unsigned char *data, 342 opus_int32 len, opus_int32 *nb_frame_exts, int nb_frames) { 343 OpusExtensionIterator iter; 344 opus_extension_data ext; 345 int count; 346 opus_extension_iterator_init(&iter, data, len, nb_frames); 347 OPUS_CLEAR(nb_frame_exts, nb_frames); 348 for (count=0; opus_extension_iterator_next(&iter, &ext) > 0; count++) { 349 nb_frame_exts[ext.frame]++; 350 } 351 return count; 352 } 353 354 /* Extract extensions from Opus padding (excluding real padding, separators, 355 and repeat indicators, but including the repeated extensions) in bitstream 356 order. 357 Due to the extension repetition mechanism, extensions are not necessarily 358 returned in frame order. */ 359 opus_int32 opus_packet_extensions_parse(const unsigned char *data, 360 opus_int32 len, opus_extension_data *extensions, opus_int32 *nb_extensions, 361 int nb_frames) { 362 OpusExtensionIterator iter; 363 int count; 364 int ret; 365 celt_assert(nb_extensions != NULL); 366 celt_assert(extensions != NULL || *nb_extensions == 0); 367 opus_extension_iterator_init(&iter, data, len, nb_frames); 368 for (count=0;; count++) { 369 opus_extension_data ext; 370 ret = opus_extension_iterator_next(&iter, &ext); 371 if (ret <= 0) break; 372 if (count == *nb_extensions) { 373 return OPUS_BUFFER_TOO_SMALL; 374 } 375 extensions[count] = ext; 376 } 377 *nb_extensions = count; 378 return ret; 379 } 380 381 /* Extract extensions from Opus padding (excluding real padding, separators, 382 and repeat indicators, but including the repeated extensions) in frame 383 order. 384 nb_frame_exts must be filled with the output of 385 opus_packet_extensions_count_ext(). */ 386 opus_int32 opus_packet_extensions_parse_ext(const unsigned char *data, 387 opus_int32 len, opus_extension_data *extensions, opus_int32 *nb_extensions, 388 const opus_int32 *nb_frame_exts, int nb_frames) { 389 OpusExtensionIterator iter; 390 opus_extension_data ext; 391 opus_int32 nb_frames_cum[49]; 392 int count; 393 int prev_total; 394 int ret; 395 celt_assert(nb_extensions != NULL); 396 celt_assert(extensions != NULL || *nb_extensions == 0); 397 celt_assert(nb_frames <= 48); 398 /* Convert the frame extension count array to a cumulative sum. */ 399 prev_total = 0; 400 for (count=0; count<nb_frames; count++) { 401 int total; 402 total = nb_frame_exts[count] + prev_total; 403 nb_frames_cum[count] = prev_total; 404 prev_total = total; 405 } 406 nb_frames_cum[count] = prev_total; 407 opus_extension_iterator_init(&iter, data, len, nb_frames); 408 for (count=0;; count++) { 409 opus_int32 idx; 410 ret = opus_extension_iterator_next(&iter, &ext); 411 if (ret <= 0) break; 412 idx = nb_frames_cum[ext.frame]++; 413 if (idx >= *nb_extensions) { 414 return OPUS_BUFFER_TOO_SMALL; 415 } 416 celt_assert(idx < nb_frames_cum[ext.frame + 1]); 417 extensions[idx] = ext; 418 } 419 *nb_extensions = count; 420 return ret; 421 } 422 423 static int write_extension_payload(unsigned char *data, opus_int32 len, 424 opus_int32 pos, const opus_extension_data *ext, int last) { 425 celt_assert(ext->id >= 3 && ext->id <= 127); 426 if (ext->id < 32) 427 { 428 if (ext->len < 0 || ext->len > 1) 429 return OPUS_BAD_ARG; 430 if (ext->len > 0) { 431 if (len-pos < ext->len) 432 return OPUS_BUFFER_TOO_SMALL; 433 if (data) data[pos] = ext->data[0]; 434 pos++; 435 } 436 } else { 437 opus_int32 length_bytes; 438 if (ext->len < 0) 439 return OPUS_BAD_ARG; 440 length_bytes = 1 + ext->len/255; 441 if (last) 442 length_bytes = 0; 443 if (len-pos < length_bytes + ext->len) 444 return OPUS_BUFFER_TOO_SMALL; 445 if (!last) 446 { 447 opus_int32 j; 448 for (j=0;j<ext->len/255;j++) { 449 if (data) data[pos] = 255; 450 pos++; 451 } 452 if (data) data[pos] = ext->len % 255; 453 pos++; 454 } 455 if (data) OPUS_COPY(&data[pos], ext->data, ext->len); 456 pos += ext->len; 457 } 458 return pos; 459 } 460 461 static int write_extension(unsigned char *data, opus_int32 len, opus_int32 pos, 462 const opus_extension_data *ext, int last) { 463 if (len-pos < 1) 464 return OPUS_BUFFER_TOO_SMALL; 465 celt_assert(ext->id >= 3 && ext->id <= 127); 466 if (data) data[pos] = (ext->id<<1) + (ext->id < 32 ? ext->len : !last); 467 pos++; 468 return write_extension_payload(data, len, pos, ext, last); 469 } 470 471 opus_int32 opus_packet_extensions_generate(unsigned char *data, opus_int32 len, 472 const opus_extension_data *extensions, opus_int32 nb_extensions, 473 int nb_frames, int pad) 474 { 475 opus_int32 frame_min_idx[48]; 476 opus_int32 frame_max_idx[48]; 477 opus_int32 frame_repeat_idx[48]; 478 opus_int32 i; 479 int f; 480 int curr_frame = 0; 481 opus_int32 pos = 0; 482 opus_int32 written = 0; 483 484 celt_assert(len >= 0); 485 if (nb_frames > 48) return OPUS_BAD_ARG; 486 487 /* Do a little work up-front to make this O(nb_extensions) instead of 488 O(nb_extensions*nb_frames) so long as the extensions are in frame 489 order (without requiring that they be in frame order). */ 490 for (f=0;f<nb_frames;f++) frame_min_idx[f] = nb_extensions; 491 OPUS_CLEAR(frame_max_idx, nb_frames); 492 for (i=0;i<nb_extensions;i++) 493 { 494 f = extensions[i].frame; 495 if (f < 0 || f >= nb_frames) return OPUS_BAD_ARG; 496 if (extensions[i].id < 3 || extensions[i].id > 127) return OPUS_BAD_ARG; 497 frame_min_idx[f] = IMIN(frame_min_idx[f], i); 498 frame_max_idx[f] = IMAX(frame_max_idx[f], i+1); 499 } 500 for (f=0;f<nb_frames;f++) frame_repeat_idx[f] = frame_min_idx[f]; 501 for (f=0;f<nb_frames;f++) 502 { 503 opus_int32 last_long_idx; 504 int repeat_count; 505 repeat_count = 0; 506 last_long_idx = -1; 507 if (f + 1 < nb_frames) 508 { 509 for (i=frame_min_idx[f];i<frame_max_idx[f];i++) 510 { 511 if (extensions[i].frame == f) 512 { 513 int g; 514 /* Test if we can repeat this extension in future frames. */ 515 for (g=f+1;g<nb_frames;g++) 516 { 517 if (frame_repeat_idx[g] >= frame_max_idx[g]) break; 518 celt_assert(extensions[frame_repeat_idx[g]].frame == g); 519 if (extensions[frame_repeat_idx[g]].id != extensions[i].id) 520 { 521 break; 522 } 523 if (extensions[frame_repeat_idx[g]].id < 32 524 && extensions[frame_repeat_idx[g]].len 525 != extensions[i].len) 526 { 527 break; 528 } 529 } 530 if (g < nb_frames) break; 531 /* We can! */ 532 /* If this is a long extension, save the index of the last 533 instance, so we can modify its L flag. */ 534 if (extensions[i].id >= 32) { 535 last_long_idx = frame_repeat_idx[nb_frames-1]; 536 } 537 /* Using the repeat mechanism almost always makes the 538 encoding smaller (or at least no larger). 539 However, there's one case where that might not be true: if 540 the last repeated long extension in the last frame was 541 previously the last extension, but using the repeat 542 mechanism makes that no longer true (because there are other 543 non-repeated extensions in earlier frames that must now be 544 coded after it), and coding its length requires more bytes 545 than the repeat mechanism saves. 546 This can only be true if its length is at least 255 bytes 547 (although sometimes it requires even more). 548 Currently we do not check for that, and just always use the 549 repeat mechanism if we can. 550 See git history for code that does the check. */ 551 /* Advance the repeat pointers. */ 552 for (g=f+1; g<nb_frames; g++) 553 { 554 int j; 555 for (j=frame_repeat_idx[g]+1; j<frame_max_idx[g] 556 && extensions[j].frame != g; j++); 557 frame_repeat_idx[g] = j; 558 } 559 repeat_count++; 560 /* Point the repeat pointer for this frame to the current 561 extension, so we know when to trigger the repeats. */ 562 frame_repeat_idx[f] = i; 563 } 564 } 565 } 566 for (i=frame_min_idx[f];i<frame_max_idx[f];i++) 567 { 568 if (extensions[i].frame == f) 569 { 570 /* Insert separator when needed. */ 571 if (f != curr_frame) { 572 int diff = f - curr_frame; 573 if (len-pos < 2) 574 return OPUS_BUFFER_TOO_SMALL; 575 if (diff == 1) { 576 if (data) data[pos] = 0x02; 577 pos++; 578 } else { 579 if (data) data[pos] = 0x03; 580 pos++; 581 if (data) data[pos] = diff; 582 pos++; 583 } 584 curr_frame = f; 585 } 586 587 pos = write_extension(data, len, pos, extensions + i, 588 written == nb_extensions - 1); 589 if (pos < 0) return pos; 590 written++; 591 592 if (repeat_count > 0 && frame_repeat_idx[f] == i) { 593 int nb_repeated; 594 int last; 595 int g; 596 /* Add the repeat indicator. */ 597 nb_repeated = repeat_count*(nb_frames - (f + 1)); 598 last = written + nb_repeated == nb_extensions 599 || (last_long_idx < 0 && i+1 >= frame_max_idx[f]); 600 if (len-pos < 1) 601 return OPUS_BUFFER_TOO_SMALL; 602 if (data) data[pos] = 0x04 + !last; 603 pos++; 604 for (g=f+1;g<nb_frames;g++) 605 { 606 int j; 607 for (j=frame_min_idx[g];j<frame_repeat_idx[g];j++) 608 { 609 if (extensions[j].frame == g) 610 { 611 pos = write_extension_payload(data, len, pos, 612 extensions + j, last && j == last_long_idx); 613 if (pos < 0) return pos; 614 written++; 615 } 616 } 617 frame_min_idx[g] = j; 618 } 619 if (last) curr_frame++; 620 } 621 } 622 } 623 } 624 celt_assert(written == nb_extensions); 625 /* If we need to pad, just prepend 0x01 bytes. Even better would be to fill the 626 end with zeros, but that requires checking that turning the last extension into 627 an L=1 case still fits. */ 628 if (pad && pos < len) 629 { 630 opus_int32 padding = len - pos; 631 if (data) { 632 OPUS_MOVE(data+padding, data, pos); 633 for (i=0;i<padding;i++) 634 data[i] = 0x01; 635 } 636 pos += padding; 637 } 638 return pos; 639 } 640 641 #if 0 642 #include <stdio.h> 643 int main() 644 { 645 opus_extension_data ext[] = {{2, 0, (const unsigned char *)"a", 1}, 646 {32, 10, (const unsigned char *)"DRED", 4}, 647 {33, 1, (const unsigned char *)"NOT DRED", 8}, 648 {3, 4, (const unsigned char *)NULL, 0} 649 }; 650 opus_extension_data ext2[10]; 651 int i, len; 652 int nb_ext = 10; 653 unsigned char packet[10000]; 654 len = opus_packet_extensions_generate(packet, 32, ext, 4, 1); 655 for (i=0;i<len;i++) 656 { 657 printf("%#04x ", packet[i]); 658 if (i%16 == 15) 659 printf("\n"); 660 } 661 printf("\n"); 662 printf("count = %d\n", opus_packet_extensions_count(packet, len)); 663 opus_packet_extensions_parse(packet, len, ext2, &nb_ext); 664 for (i=0;i<nb_ext;i++) 665 { 666 int j; 667 printf("%d %d {", ext2[i].id, ext2[i].frame); 668 for (j=0;j<ext2[i].len;j++) printf("%#04x ", ext2[i].data[j]); 669 printf("} %d\n", ext2[i].len); 670 } 671 } 672 #endif