diff options
Diffstat (limited to 'toxav/codec.c')
-rw-r--r-- | toxav/codec.c | 98 |
1 files changed, 11 insertions, 87 deletions
diff --git a/toxav/codec.c b/toxav/codec.c index d55cc345..671be1ac 100644 --- a/toxav/codec.c +++ b/toxav/codec.c | |||
@@ -46,78 +46,13 @@ | |||
46 | #define MAX_VIDEOFRAME_SIZE 0x40000 /* 256KiB */ | 46 | #define MAX_VIDEOFRAME_SIZE 0x40000 /* 256KiB */ |
47 | #define VIDEOFRAME_HEADER_SIZE 0x2 | 47 | #define VIDEOFRAME_HEADER_SIZE 0x2 |
48 | 48 | ||
49 | /* FIXME: Might not be enough */ | 49 | /* FIXME: Might not be enough? NOTE: I think it is enough */ |
50 | #define VIDEO_DECODE_BUFFER_SIZE 20 | 50 | #define VIDEO_DECODE_BUFFER_SIZE 20 |
51 | 51 | ||
52 | #define ARRAY(TYPE__) struct { uint16_t size; TYPE__ data[]; } | 52 | #define ARRAY(TYPE__) struct { uint16_t size; TYPE__ data[]; } |
53 | 53 | ||
54 | typedef ARRAY(uint8_t) Payload; | 54 | typedef ARRAY(uint8_t) Payload; |
55 | 55 | ||
56 | typedef struct { | ||
57 | uint16_t size; /* Max size */ | ||
58 | uint16_t start; | ||
59 | uint16_t end; | ||
60 | Payload **packets; | ||
61 | } PayloadBuffer; | ||
62 | |||
63 | static bool buffer_full(const PayloadBuffer *b) | ||
64 | { | ||
65 | return (b->end + 1) % b->size == b->start; | ||
66 | } | ||
67 | |||
68 | static bool buffer_empty(const PayloadBuffer *b) | ||
69 | { | ||
70 | return b->end == b->start; | ||
71 | } | ||
72 | |||
73 | static void buffer_write(PayloadBuffer *b, Payload *p) | ||
74 | { | ||
75 | b->packets[b->end] = p; | ||
76 | b->end = (b->end + 1) % b->size; | ||
77 | |||
78 | if (b->end == b->start) b->start = (b->start + 1) % b->size; /* full, overwrite */ | ||
79 | } | ||
80 | |||
81 | static void buffer_read(PayloadBuffer *b, Payload **p) | ||
82 | { | ||
83 | *p = b->packets[b->start]; | ||
84 | b->start = (b->start + 1) % b->size; | ||
85 | } | ||
86 | |||
87 | static void buffer_clear(PayloadBuffer *b) | ||
88 | { | ||
89 | while (!buffer_empty(b)) { | ||
90 | Payload *p; | ||
91 | buffer_read(b, &p); | ||
92 | free(p); | ||
93 | } | ||
94 | } | ||
95 | |||
96 | static PayloadBuffer *buffer_new(int size) | ||
97 | { | ||
98 | PayloadBuffer *buf = calloc(sizeof(PayloadBuffer), 1); | ||
99 | |||
100 | if (!buf) return NULL; | ||
101 | |||
102 | buf->size = size + 1; /* include empty elem */ | ||
103 | |||
104 | if (!(buf->packets = calloc(buf->size, sizeof(Payload *)))) { | ||
105 | free(buf); | ||
106 | return NULL; | ||
107 | } | ||
108 | |||
109 | return buf; | ||
110 | } | ||
111 | |||
112 | static void buffer_free(PayloadBuffer *b) | ||
113 | { | ||
114 | if (b) { | ||
115 | buffer_clear(b); | ||
116 | free(b->packets); | ||
117 | free(b); | ||
118 | } | ||
119 | } | ||
120 | |||
121 | /* JITTER BUFFER WORK */ | 56 | /* JITTER BUFFER WORK */ |
122 | typedef struct JitterBuffer_s { | 57 | typedef struct JitterBuffer_s { |
123 | RTPMessage **queue; | 58 | RTPMessage **queue; |
@@ -318,7 +253,7 @@ bool reconfigure_audio_decoder(CSession* cs, int32_t sampling_rate, int8_t chann | |||
318 | int status; | 253 | int status; |
319 | OpusDecoder* new_dec = opus_decoder_create(sampling_rate, channels, &status ); | 254 | OpusDecoder* new_dec = opus_decoder_create(sampling_rate, channels, &status ); |
320 | if ( status != OPUS_OK ) { | 255 | if ( status != OPUS_OK ) { |
321 | LOGGER_ERROR("Error while starting audio decoder: %s", opus_strerror(status)); | 256 | LOGGER_ERROR("Error while starting audio decoder(%d %d): %s", sampling_rate, channels, opus_strerror(status)); |
322 | return false; | 257 | return false; |
323 | } | 258 | } |
324 | 259 | ||
@@ -336,7 +271,6 @@ bool reconfigure_audio_decoder(CSession* cs, int32_t sampling_rate, int8_t chann | |||
336 | } | 271 | } |
337 | 272 | ||
338 | /* PUBLIC */ | 273 | /* PUBLIC */ |
339 | |||
340 | void cs_do(CSession *cs) | 274 | void cs_do(CSession *cs) |
341 | { | 275 | { |
342 | /* Codec session should always be protected by call mutex so no need to check for cs validity | 276 | /* Codec session should always be protected by call mutex so no need to check for cs validity |
@@ -416,9 +350,9 @@ void cs_do(CSession *cs) | |||
416 | } | 350 | } |
417 | 351 | ||
418 | /********************* VIDEO *********************/ | 352 | /********************* VIDEO *********************/ |
419 | if (cs->vbuf_raw && !buffer_empty(cs->vbuf_raw)) { | 353 | if (cs->vbuf_raw && !rb_empty(cs->vbuf_raw)) { |
420 | /* Decode video */ | 354 | /* Decode video */ |
421 | buffer_read(cs->vbuf_raw, &p); | 355 | rb_read(cs->vbuf_raw, (void**)&p); |
422 | 356 | ||
423 | /* Leave space for (possibly) other thread to queue more data after we read it here */ | 357 | /* Leave space for (possibly) other thread to queue more data after we read it here */ |
424 | LOGGED_UNLOCK(cs->queue_mutex); | 358 | LOGGED_UNLOCK(cs->queue_mutex); |
@@ -447,7 +381,6 @@ void cs_do(CSession *cs) | |||
447 | 381 | ||
448 | LOGGED_UNLOCK(cs->queue_mutex); | 382 | LOGGED_UNLOCK(cs->queue_mutex); |
449 | } | 383 | } |
450 | |||
451 | CSession *cs_new(uint32_t peer_video_frame_piece_size) | 384 | CSession *cs_new(uint32_t peer_video_frame_piece_size) |
452 | { | 385 | { |
453 | CSession *cs = calloc(sizeof(CSession), 1); | 386 | CSession *cs = calloc(sizeof(CSession), 1); |
@@ -510,7 +443,7 @@ CSession *cs_new(uint32_t peer_video_frame_piece_size) | |||
510 | goto AUDIO_DECODER_CLEANUP; | 443 | goto AUDIO_DECODER_CLEANUP; |
511 | } | 444 | } |
512 | 445 | ||
513 | if ( !(cs->vbuf_raw = buffer_new(VIDEO_DECODE_BUFFER_SIZE)) ) { | 446 | if ( !(cs->vbuf_raw = rb_new(VIDEO_DECODE_BUFFER_SIZE)) ) { |
514 | free(cs->frame_buf); | 447 | free(cs->frame_buf); |
515 | vpx_codec_destroy(cs->v_decoder); | 448 | vpx_codec_destroy(cs->v_decoder); |
516 | goto AUDIO_DECODER_CLEANUP; | 449 | goto AUDIO_DECODER_CLEANUP; |
@@ -542,7 +475,7 @@ CSession *cs_new(uint32_t peer_video_frame_piece_size) | |||
542 | return cs; | 475 | return cs; |
543 | 476 | ||
544 | VIDEO_DECODER_CLEANUP: | 477 | VIDEO_DECODER_CLEANUP: |
545 | buffer_free(cs->vbuf_raw); | 478 | rb_free(cs->vbuf_raw); |
546 | free(cs->frame_buf); | 479 | free(cs->frame_buf); |
547 | vpx_codec_destroy(cs->v_decoder); | 480 | vpx_codec_destroy(cs->v_decoder); |
548 | AUDIO_DECODER_CLEANUP: | 481 | AUDIO_DECODER_CLEANUP: |
@@ -553,7 +486,6 @@ FAILURE: | |||
553 | free(cs); | 486 | free(cs); |
554 | return NULL; | 487 | return NULL; |
555 | } | 488 | } |
556 | |||
557 | void cs_kill(CSession *cs) | 489 | void cs_kill(CSession *cs) |
558 | { | 490 | { |
559 | if (!cs) | 491 | if (!cs) |
@@ -567,22 +499,21 @@ void cs_kill(CSession *cs) | |||
567 | vpx_codec_destroy(cs->v_decoder); | 499 | vpx_codec_destroy(cs->v_decoder); |
568 | opus_encoder_destroy(cs->audio_encoder); | 500 | opus_encoder_destroy(cs->audio_encoder); |
569 | opus_decoder_destroy(cs->audio_decoder); | 501 | opus_decoder_destroy(cs->audio_decoder); |
570 | buffer_free(cs->vbuf_raw); | 502 | rb_free(cs->vbuf_raw); |
571 | jbuf_free(cs->j_buf); | 503 | jbuf_free(cs->j_buf); |
572 | free(cs->frame_buf); | 504 | free(cs->frame_buf); |
505 | free(cs->split_video_frame); | ||
573 | 506 | ||
574 | pthread_mutex_destroy(cs->queue_mutex); | 507 | pthread_mutex_destroy(cs->queue_mutex); |
575 | 508 | ||
576 | LOGGER_DEBUG("Terminated codec state: %p", cs); | 509 | LOGGER_DEBUG("Terminated codec state: %p", cs); |
577 | free(cs); | 510 | free(cs); |
578 | } | 511 | } |
579 | |||
580 | void cs_init_video_splitter_cycle(CSession* cs) | 512 | void cs_init_video_splitter_cycle(CSession* cs) |
581 | { | 513 | { |
582 | cs->split_video_frame[0] = cs->frameid_out++; | 514 | cs->split_video_frame[0] = cs->frameid_out++; |
583 | cs->split_video_frame[1] = 0; | 515 | cs->split_video_frame[1] = 0; |
584 | } | 516 | } |
585 | |||
586 | int cs_update_video_splitter_cycle(CSession *cs, const uint8_t *payload, uint16_t length) | 517 | int cs_update_video_splitter_cycle(CSession *cs, const uint8_t *payload, uint16_t length) |
587 | { | 518 | { |
588 | cs->processing_video_frame = payload; | 519 | cs->processing_video_frame = payload; |
@@ -590,7 +521,6 @@ int cs_update_video_splitter_cycle(CSession *cs, const uint8_t *payload, uint16_ | |||
590 | 521 | ||
591 | return ((length - 1) / VIDEOFRAME_PIECE_SIZE) + 1; | 522 | return ((length - 1) / VIDEOFRAME_PIECE_SIZE) + 1; |
592 | } | 523 | } |
593 | |||
594 | const uint8_t *cs_iterate_split_video_frame(CSession *cs, uint16_t *size) | 524 | const uint8_t *cs_iterate_split_video_frame(CSession *cs, uint16_t *size) |
595 | { | 525 | { |
596 | if (!cs || !size) return NULL; | 526 | if (!cs || !size) return NULL; |
@@ -616,9 +546,6 @@ const uint8_t *cs_iterate_split_video_frame(CSession *cs, uint16_t *size) | |||
616 | 546 | ||
617 | return cs->split_video_frame; | 547 | return cs->split_video_frame; |
618 | } | 548 | } |
619 | |||
620 | |||
621 | |||
622 | int cs_reconfigure_video_encoder(CSession* cs, int32_t bitrate, uint16_t width, uint16_t height) | 549 | int cs_reconfigure_video_encoder(CSession* cs, int32_t bitrate, uint16_t width, uint16_t height) |
623 | { | 550 | { |
624 | vpx_codec_enc_cfg_t cfg = *cs->v_encoder[0].config.enc; | 551 | vpx_codec_enc_cfg_t cfg = *cs->v_encoder[0].config.enc; |
@@ -637,7 +564,6 @@ int cs_reconfigure_video_encoder(CSession* cs, int32_t bitrate, uint16_t width, | |||
637 | 564 | ||
638 | return 0; | 565 | return 0; |
639 | } | 566 | } |
640 | |||
641 | int cs_reconfigure_audio_encoder(CSession* cs, int32_t bitrate, int32_t sampling_rate, uint8_t channels) | 567 | int cs_reconfigure_audio_encoder(CSession* cs, int32_t bitrate, int32_t sampling_rate, uint8_t channels) |
642 | { | 568 | { |
643 | /* Values are checked in toxav.c */ | 569 | /* Values are checked in toxav.c */ |
@@ -667,8 +593,6 @@ int cs_reconfigure_audio_encoder(CSession* cs, int32_t bitrate, int32_t sampling | |||
667 | LOGGER_DEBUG ("Reconfigured audio encoder br: %d sr: %d cc:%d", bitrate, sampling_rate, channels); | 593 | LOGGER_DEBUG ("Reconfigured audio encoder br: %d sr: %d cc:%d", bitrate, sampling_rate, channels); |
668 | return 0; | 594 | return 0; |
669 | } | 595 | } |
670 | |||
671 | |||
672 | /* Called from RTP */ | 596 | /* Called from RTP */ |
673 | void queue_message(RTPSession *session, RTPMessage *msg) | 597 | void queue_message(RTPSession *session, RTPMessage *msg) |
674 | { | 598 | { |
@@ -705,10 +629,10 @@ void queue_message(RTPSession *session, RTPMessage *msg) | |||
705 | if (p) { | 629 | if (p) { |
706 | LOGGED_LOCK(cs->queue_mutex); | 630 | LOGGED_LOCK(cs->queue_mutex); |
707 | 631 | ||
708 | if (buffer_full(cs->vbuf_raw)) { | 632 | if (rb_full(cs->vbuf_raw)) { |
709 | LOGGER_DEBUG("Dropped video frame"); | 633 | LOGGER_DEBUG("Dropped video frame"); |
710 | Payload *tp; | 634 | Payload *tp; |
711 | buffer_read(cs->vbuf_raw, &tp); | 635 | rb_read(cs->vbuf_raw, (void**)&tp); |
712 | free(tp); | 636 | free(tp); |
713 | } else { | 637 | } else { |
714 | p->size = cs->frame_size; | 638 | p->size = cs->frame_size; |
@@ -720,7 +644,7 @@ void queue_message(RTPSession *session, RTPMessage *msg) | |||
720 | cs->lcfd = t_lcfd > 100 ? cs->lcfd : t_lcfd; | 644 | cs->lcfd = t_lcfd > 100 ? cs->lcfd : t_lcfd; |
721 | cs->linfts = current_time_monotonic(); | 645 | cs->linfts = current_time_monotonic(); |
722 | 646 | ||
723 | buffer_write(cs->vbuf_raw, p); | 647 | rb_write(cs->vbuf_raw, p); |
724 | LOGGED_UNLOCK(cs->queue_mutex); | 648 | LOGGED_UNLOCK(cs->queue_mutex); |
725 | } else { | 649 | } else { |
726 | LOGGER_WARNING("Allocation failed! Program might misbehave!"); | 650 | LOGGER_WARNING("Allocation failed! Program might misbehave!"); |