diff options
author | mannol <eniz_vukovic@hotmail.com> | 2014-11-29 13:42:19 +0100 |
---|---|---|
committer | mannol <eniz_vukovic@hotmail.com> | 2014-11-29 13:42:19 +0100 |
commit | e62ded3a6dfc1203418e3d7a2c936794c4c9ec1c (patch) | |
tree | 74db9ab7f52295304e6079d8e90b8d5b5f3afc67 /toxav/codec.c | |
parent | 975ce25af0e469f3b2d80478695d3bbe8e79be79 (diff) |
More av cleanup
Diffstat (limited to 'toxav/codec.c')
-rw-r--r-- | toxav/codec.c | 190 |
1 files changed, 55 insertions, 135 deletions
diff --git a/toxav/codec.c b/toxav/codec.c index 2849ed69..020cde81 100644 --- a/toxav/codec.c +++ b/toxav/codec.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #endif /* HAVE_CONFIG_H */ | 27 | #endif /* HAVE_CONFIG_H */ |
28 | 28 | ||
29 | #include "../toxcore/logger.h" | 29 | #include "../toxcore/logger.h" |
30 | #include "../toxcore/util.h" | ||
30 | 31 | ||
31 | #include <stdio.h> | 32 | #include <stdio.h> |
32 | #include <stdlib.h> | 33 | #include <stdlib.h> |
@@ -50,14 +51,10 @@ | |||
50 | /* FIXME: Might not be enough */ | 51 | /* FIXME: Might not be enough */ |
51 | #define VIDEO_DECODE_BUFFER_SIZE 20 | 52 | #define VIDEO_DECODE_BUFFER_SIZE 20 |
52 | 53 | ||
53 | #define ARRAY(TYPE__) struct { uint16_t size; TYPE__ data[]; } | 54 | #define ARRAY(TYPE__) struct { uint16_t size; TYPE__ data[]; } |
54 | #define PAIR(TYPE1__, TYPE2__) struct { TYPE1__ first; TYPE2__ second; } | ||
55 | 55 | ||
56 | typedef ARRAY(uint8_t) Payload; | 56 | typedef ARRAY(uint8_t) Payload; |
57 | 57 | ||
58 | static PAIR(CSVideoCallback, void *) vpcallback; | ||
59 | static PAIR(CSAudioCallback, void *) apcallback; | ||
60 | |||
61 | typedef struct { | 58 | typedef struct { |
62 | uint16_t size; /* Max size */ | 59 | uint16_t size; /* Max size */ |
63 | uint16_t start; | 60 | uint16_t start; |
@@ -319,24 +316,12 @@ static int init_audio_encoder(CSSession *cs) | |||
319 | return 0; | 316 | return 0; |
320 | } | 317 | } |
321 | 318 | ||
322 | static float calculate_sum_sq (int16_t *n, uint16_t k) | ||
323 | { | ||
324 | float result = 0; | ||
325 | uint16_t i = 0; | ||
326 | |||
327 | for ( ; i < k; i ++) result += (float) (n[i] * n[i]); | ||
328 | |||
329 | return result; | ||
330 | } | ||
331 | |||
332 | |||
333 | |||
334 | /* PUBLIC */ | 319 | /* PUBLIC */ |
335 | int cs_split_video_payload(CSSession *cs, const uint8_t *payload, uint16_t length) | 320 | int cs_split_video_payload(CSSession *cs, const uint8_t *payload, uint16_t length) |
336 | { | 321 | { |
337 | if (!cs || !length || length > cs->max_video_frame_size) { | 322 | if (!cs || !length || length > cs->max_video_frame_size) { |
338 | LOGGER_ERROR("Invalid CodecState or video frame size: %u", length); | 323 | LOGGER_ERROR("Invalid CodecState or video frame size: %u", length); |
339 | return -1; | 324 | return cs_ErrorSplittingVideoPayload; |
340 | } | 325 | } |
341 | 326 | ||
342 | cs->split_video_frame[0] = cs->frameid_out++; | 327 | cs->split_video_frame[0] = cs->frameid_out++; |
@@ -375,43 +360,23 @@ const uint8_t *cs_get_split_video_frame(CSSession *cs, uint16_t *size) | |||
375 | 360 | ||
376 | void cs_do(CSSession *cs) | 361 | void cs_do(CSSession *cs) |
377 | { | 362 | { |
363 | /* Codec session should always be protected by call mutex so no need to check for cs validity | ||
364 | */ | ||
365 | |||
378 | if (!cs) return; | 366 | if (!cs) return; |
379 | 367 | ||
380 | pthread_mutex_lock(cs->queue_mutex); | ||
381 | |||
382 | if (!cs->active) { | ||
383 | pthread_mutex_unlock(cs->queue_mutex); | ||
384 | return; | ||
385 | } | ||
386 | |||
387 | /* | ||
388 | /* Iterate over whole buffers and call playback callback * / | ||
389 | if (cs->abuf_ready) while (!DecodedAudioBuffer_empty(cs->abuf_ready)) { | ||
390 | DecodedAudio* p; | ||
391 | DecodedAudioBuffer_read(cs->abuf_ready, &p); | ||
392 | if (apcallback.first) | ||
393 | apcallback.first(cs->agent, cs->call_idx, p->data, p->size, apcallback.second); | ||
394 | |||
395 | free(p); | ||
396 | } | ||
397 | |||
398 | if (cs->vbuf_ready) while (!DecodedVideoBuffer_empty(cs->vbuf_ready)) { | ||
399 | vpx_image_t* p; | ||
400 | DecodedVideoBuffer_read(cs->vbuf_ready, &p); | ||
401 | if (vpcallback.first) | ||
402 | vpcallback.first(cs->agent, cs->call_idx, p, vpcallback.second); | ||
403 | |||
404 | vpx_img_free(p); | ||
405 | } | ||
406 | */ | ||
407 | |||
408 | Payload *p; | 368 | Payload *p; |
409 | int rc; | 369 | int rc; |
410 | 370 | ||
371 | pthread_mutex_lock(cs->queue_mutex); | ||
411 | if (cs->abuf_raw && !buffer_empty(cs->abuf_raw)) { | 372 | if (cs->abuf_raw && !buffer_empty(cs->abuf_raw)) { |
412 | /* Decode audio */ | 373 | /* Decode audio */ |
413 | buffer_read(cs->abuf_raw, &p); | 374 | buffer_read(cs->abuf_raw, &p); |
414 | 375 | ||
376 | /* Leave space for (possibly) other thread to queue more data after we read it here */ | ||
377 | pthread_mutex_unlock(cs->queue_mutex); | ||
378 | |||
379 | |||
415 | uint16_t fsize = (cs->audio_decoder_channels * | 380 | uint16_t fsize = (cs->audio_decoder_channels * |
416 | (cs->audio_decoder_sample_rate * cs->audio_decoder_frame_duration) / 1000); | 381 | (cs->audio_decoder_sample_rate * cs->audio_decoder_frame_duration) / 1000); |
417 | int16_t tmp[fsize]; | 382 | int16_t tmp[fsize]; |
@@ -421,15 +386,20 @@ void cs_do(CSSession *cs) | |||
421 | 386 | ||
422 | if (rc < 0) | 387 | if (rc < 0) |
423 | LOGGER_WARNING("Decoding error: %s", opus_strerror(rc)); | 388 | LOGGER_WARNING("Decoding error: %s", opus_strerror(rc)); |
424 | else | 389 | else if (cs->acb.first) |
425 | /* Play */ | 390 | /* Play */ |
426 | apcallback.first(cs->agent, cs->call_idx, tmp, rc, apcallback.second); | 391 | cs->acb.first(cs->agent, cs->call_idx, tmp, rc, cs->acb.second); |
392 | |||
393 | pthread_mutex_lock(cs->queue_mutex); | ||
427 | } | 394 | } |
428 | 395 | ||
429 | if (cs->vbuf_raw && !buffer_empty(cs->vbuf_raw)) { | 396 | if (cs->vbuf_raw && !buffer_empty(cs->vbuf_raw)) { |
430 | /* Decode video */ | 397 | /* Decode video */ |
431 | buffer_read(cs->vbuf_raw, &p); | 398 | buffer_read(cs->vbuf_raw, &p); |
432 | 399 | ||
400 | /* Leave space for (possibly) other thread to queue more data after we read it here */ | ||
401 | pthread_mutex_unlock(cs->queue_mutex); | ||
402 | |||
433 | rc = vpx_codec_decode(&cs->v_decoder, p->data, p->size, NULL, MAX_DECODE_TIME_US); | 403 | rc = vpx_codec_decode(&cs->v_decoder, p->data, p->size, NULL, MAX_DECODE_TIME_US); |
434 | free(p); | 404 | free(p); |
435 | 405 | ||
@@ -441,27 +411,17 @@ void cs_do(CSSession *cs) | |||
441 | 411 | ||
442 | /* Play decoded images */ | 412 | /* Play decoded images */ |
443 | for (; dest; dest = vpx_codec_get_frame(&cs->v_decoder, &iter)) { | 413 | for (; dest; dest = vpx_codec_get_frame(&cs->v_decoder, &iter)) { |
444 | vpcallback.first(cs->agent, cs->call_idx, dest, vpcallback.second); | 414 | if (cs->vcb.first) |
415 | cs->vcb.first(cs->agent, cs->call_idx, dest, cs->vcb.second); | ||
445 | vpx_img_free(dest); | 416 | vpx_img_free(dest); |
446 | } | 417 | } |
447 | } | 418 | } |
419 | return; | ||
448 | } | 420 | } |
449 | 421 | ||
450 | pthread_mutex_unlock(cs->queue_mutex); | 422 | pthread_mutex_unlock(cs->queue_mutex); |
451 | } | 423 | } |
452 | 424 | ||
453 | void cs_register_audio_callback(CSAudioCallback cb, void *data) | ||
454 | { | ||
455 | apcallback.first = cb; | ||
456 | apcallback.second = data; | ||
457 | } | ||
458 | |||
459 | void cs_register_video_callback(CSVideoCallback cb, void *data) | ||
460 | { | ||
461 | vpcallback.first = cb; | ||
462 | vpcallback.second = data; | ||
463 | } | ||
464 | |||
465 | int cs_set_video_encoder_resolution(CSSession *cs, uint16_t width, uint16_t height) | 425 | int cs_set_video_encoder_resolution(CSSession *cs, uint16_t width, uint16_t height) |
466 | { | 426 | { |
467 | vpx_codec_enc_cfg_t cfg = *cs->v_encoder.config.enc; | 427 | vpx_codec_enc_cfg_t cfg = *cs->v_encoder.config.enc; |
@@ -470,7 +430,7 @@ int cs_set_video_encoder_resolution(CSSession *cs, uint16_t width, uint16_t heig | |||
470 | return 0; | 430 | return 0; |
471 | 431 | ||
472 | if (width * height > cs->max_width * cs->max_height) | 432 | if (width * height > cs->max_width * cs->max_height) |
473 | return -1; | 433 | return cs_ErrorSettingVideoResolution; |
474 | 434 | ||
475 | LOGGER_DEBUG("New video resolution: %u %u", width, height); | 435 | LOGGER_DEBUG("New video resolution: %u %u", width, height); |
476 | cfg.g_w = width; | 436 | cfg.g_w = width; |
@@ -479,7 +439,7 @@ int cs_set_video_encoder_resolution(CSSession *cs, uint16_t width, uint16_t heig | |||
479 | 439 | ||
480 | if ( rc != VPX_CODEC_OK) { | 440 | if ( rc != VPX_CODEC_OK) { |
481 | LOGGER_ERROR("Failed to set encoder control setting: %s", vpx_codec_err_to_string(rc)); | 441 | LOGGER_ERROR("Failed to set encoder control setting: %s", vpx_codec_err_to_string(rc)); |
482 | return -1; | 442 | return cs_ErrorSettingVideoResolution; |
483 | } | 443 | } |
484 | 444 | ||
485 | return 0; | 445 | return 0; |
@@ -498,7 +458,7 @@ int cs_set_video_encoder_bitrate(CSSession *cs, uint32_t video_bitrate) | |||
498 | 458 | ||
499 | if ( rc != VPX_CODEC_OK) { | 459 | if ( rc != VPX_CODEC_OK) { |
500 | LOGGER_ERROR("Failed to set encoder control setting: %s", vpx_codec_err_to_string(rc)); | 460 | LOGGER_ERROR("Failed to set encoder control setting: %s", vpx_codec_err_to_string(rc)); |
501 | return -1; | 461 | return cs_ErrorSettingVideoBitrate; |
502 | } | 462 | } |
503 | 463 | ||
504 | return 0; | 464 | return 0; |
@@ -513,6 +473,11 @@ CSSession *cs_new(const ToxAvCSettings *cs_self, const ToxAvCSettings *cs_peer, | |||
513 | return NULL; | 473 | return NULL; |
514 | } | 474 | } |
515 | 475 | ||
476 | if (create_recursive_mutex(cs->queue_mutex) != 0) { | ||
477 | LOGGER_WARNING("Failed to create recursive mutex!"); | ||
478 | return NULL; | ||
479 | } | ||
480 | |||
516 | if ( !(cs->j_buf = jbuf_new(jbuf_size)) ) { | 481 | if ( !(cs->j_buf = jbuf_new(jbuf_size)) ) { |
517 | LOGGER_WARNING("Jitter buffer creaton failed!"); | 482 | LOGGER_WARNING("Jitter buffer creaton failed!"); |
518 | goto error; | 483 | goto error; |
@@ -529,38 +494,22 @@ CSSession *cs_new(const ToxAvCSettings *cs_self, const ToxAvCSettings *cs_peer, | |||
529 | cs->audio_decoder_frame_duration = cs_peer->audio_frame_duration; | 494 | cs->audio_decoder_frame_duration = cs_peer->audio_frame_duration; |
530 | 495 | ||
531 | 496 | ||
532 | cs->capabilities |= ( 0 == init_audio_encoder(cs) ) ? a_encoding : 0; | 497 | cs->capabilities |= ( 0 == init_audio_encoder(cs) ) ? cs_AudioEncoding : 0; |
533 | cs->capabilities |= ( 0 == init_audio_decoder(cs) ) ? a_decoding : 0; | 498 | cs->capabilities |= ( 0 == init_audio_decoder(cs) ) ? cs_AudioDecoding : 0; |
534 | 499 | ||
535 | if ( !(cs->capabilities & a_encoding) || !(cs->capabilities & a_decoding) ) goto error; | 500 | if ( !(cs->capabilities & cs_AudioEncoding) || !(cs->capabilities & cs_AudioDecoding) ) goto error; |
536 | 501 | ||
537 | if ( !(cs->abuf_raw = buffer_new(jbuf_size)) ) goto error; | 502 | if ( !(cs->abuf_raw = buffer_new(jbuf_size)) ) goto error; |
538 | 503 | ||
539 | pthread_mutexattr_t attr; | ||
540 | |||
541 | if (pthread_mutexattr_init(&attr) != 0) goto error; | ||
542 | |||
543 | if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) != 0) { | ||
544 | if (pthread_mutexattr_destroy(&attr) != 0) | ||
545 | LOGGER_WARNING("Failed to destroy mutex attribute!"); | ||
546 | |||
547 | goto error; | ||
548 | } | ||
549 | |||
550 | if (pthread_mutex_init(cs->queue_mutex, &attr) != 0) { | ||
551 | pthread_mutexattr_destroy(&attr); | ||
552 | goto error; | ||
553 | } | ||
554 | |||
555 | if ((cs->support_video = has_video)) { | 504 | if ((cs->support_video = has_video)) { |
556 | cs->max_video_frame_size = MAX_VIDEOFRAME_SIZE; | 505 | cs->max_video_frame_size = MAX_VIDEOFRAME_SIZE; |
557 | cs->video_frame_piece_size = VIDEOFRAME_PIECE_SIZE; | 506 | cs->video_frame_piece_size = VIDEOFRAME_PIECE_SIZE; |
558 | 507 | ||
559 | cs->capabilities |= ( 0 == init_video_encoder(cs, cs_self->max_video_width, | 508 | cs->capabilities |= ( 0 == init_video_encoder(cs, cs_self->max_video_width, |
560 | cs_self->max_video_height, cs_self->video_bitrate) ) ? v_encoding : 0; | 509 | cs_self->max_video_height, cs_self->video_bitrate) ) ? cs_VideoEncoding : 0; |
561 | cs->capabilities |= ( 0 == init_video_decoder(cs) ) ? v_decoding : 0; | 510 | cs->capabilities |= ( 0 == init_video_decoder(cs) ) ? cs_VideoDecoding : 0; |
562 | 511 | ||
563 | if ( !(cs->capabilities & v_encoding) || !(cs->capabilities & v_decoding) ) goto error; | 512 | if ( !(cs->capabilities & cs_VideoEncoding) || !(cs->capabilities & cs_VideoDecoding) ) goto error; |
564 | 513 | ||
565 | if ( !(cs->frame_buf = calloc(cs->max_video_frame_size, 1)) ) goto error; | 514 | if ( !(cs->frame_buf = calloc(cs->max_video_frame_size, 1)) ) goto error; |
566 | 515 | ||
@@ -569,17 +518,14 @@ CSSession *cs_new(const ToxAvCSettings *cs_self, const ToxAvCSettings *cs_peer, | |||
569 | 518 | ||
570 | if ( !(cs->vbuf_raw = buffer_new(VIDEO_DECODE_BUFFER_SIZE)) ) goto error; | 519 | if ( !(cs->vbuf_raw = buffer_new(VIDEO_DECODE_BUFFER_SIZE)) ) goto error; |
571 | } | 520 | } |
572 | 521 | ||
573 | if (pthread_mutexattr_destroy(&attr) != 0) | ||
574 | LOGGER_WARNING("Failed to destroy mutex attribute!"); | ||
575 | |||
576 | |||
577 | cs->active = 1; | ||
578 | return cs; | 522 | return cs; |
579 | 523 | ||
580 | error: | 524 | error: |
581 | LOGGER_WARNING("Error initializing codec session! Application might misbehave!"); | 525 | LOGGER_WARNING("Error initializing codec session! Application might misbehave!"); |
582 | 526 | ||
527 | pthread_mutex_destroy(cs->queue_mutex); | ||
528 | |||
583 | buffer_free(cs->abuf_raw); | 529 | buffer_free(cs->abuf_raw); |
584 | 530 | ||
585 | if ( cs->audio_encoder ) opus_encoder_destroy(cs->audio_encoder); | 531 | if ( cs->audio_encoder ) opus_encoder_destroy(cs->audio_encoder); |
@@ -588,9 +534,9 @@ error: | |||
588 | 534 | ||
589 | 535 | ||
590 | if (has_video) { | 536 | if (has_video) { |
591 | if ( cs->capabilities & v_decoding ) vpx_codec_destroy(&cs->v_decoder); | 537 | if ( cs->capabilities & cs_VideoDecoding ) vpx_codec_destroy(&cs->v_decoder); |
592 | 538 | ||
593 | if ( cs->capabilities & v_encoding ) vpx_codec_destroy(&cs->v_encoder); | 539 | if ( cs->capabilities & cs_VideoEncoding ) vpx_codec_destroy(&cs->v_encoder); |
594 | 540 | ||
595 | buffer_free(cs->vbuf_raw); | 541 | buffer_free(cs->vbuf_raw); |
596 | 542 | ||
@@ -608,13 +554,7 @@ void cs_kill(CSSession *cs) | |||
608 | { | 554 | { |
609 | if (!cs) return; | 555 | if (!cs) return; |
610 | 556 | ||
611 | /* Lock running mutex and signal that cs is no longer active */ | 557 | /* queue_message will not be called since it's unregistered before cs_kill is called */ |
612 | pthread_mutex_lock(cs->queue_mutex); | ||
613 | cs->active = 0; | ||
614 | |||
615 | /* Wait threads to close */ | ||
616 | pthread_mutex_unlock(cs->queue_mutex); | ||
617 | |||
618 | pthread_mutex_destroy(cs->queue_mutex); | 558 | pthread_mutex_destroy(cs->queue_mutex); |
619 | 559 | ||
620 | 560 | ||
@@ -624,10 +564,10 @@ void cs_kill(CSSession *cs) | |||
624 | if ( cs->audio_decoder ) | 564 | if ( cs->audio_decoder ) |
625 | opus_decoder_destroy(cs->audio_decoder); | 565 | opus_decoder_destroy(cs->audio_decoder); |
626 | 566 | ||
627 | if ( cs->capabilities & v_decoding ) | 567 | if ( cs->capabilities & cs_VideoDecoding ) |
628 | vpx_codec_destroy(&cs->v_decoder); | 568 | vpx_codec_destroy(&cs->v_decoder); |
629 | 569 | ||
630 | if ( cs->capabilities & v_encoding ) | 570 | if ( cs->capabilities & cs_VideoEncoding ) |
631 | vpx_codec_destroy(&cs->v_encoder); | 571 | vpx_codec_destroy(&cs->v_encoder); |
632 | 572 | ||
633 | jbuf_free(cs->j_buf); | 573 | jbuf_free(cs->j_buf); |
@@ -639,43 +579,23 @@ void cs_kill(CSSession *cs) | |||
639 | free(cs); | 579 | free(cs); |
640 | } | 580 | } |
641 | 581 | ||
642 | void cs_set_vad_treshold(CSSession *cs, uint32_t treshold, uint16_t frame_duration) | ||
643 | { | ||
644 | cs->EVAD_tolerance = treshold > frame_duration ? treshold / frame_duration : frame_duration; | ||
645 | } | ||
646 | |||
647 | int cs_calculate_vad(CSSession *cs, int16_t *PCM, uint16_t frame_size, float energy) | ||
648 | { | ||
649 | float frame_energy = sqrt(calculate_sum_sq(PCM, frame_size)) / frame_size; | ||
650 | |||
651 | if ( frame_energy > energy) { | ||
652 | cs->EVAD_tolerance_cr = cs->EVAD_tolerance; /* Reset counter */ | ||
653 | return 1; | ||
654 | } | ||
655 | |||
656 | if ( cs->EVAD_tolerance_cr ) { | ||
657 | cs->EVAD_tolerance_cr --; | ||
658 | return 1; | ||
659 | } | ||
660 | |||
661 | return 0; | ||
662 | } | ||
663 | |||
664 | 582 | ||
665 | 583 | ||
666 | 584 | ||
667 | /* Called from RTP */ | 585 | /* Called from RTP */ |
668 | void queue_message(RTPSession *session, RTPMessage *msg) | 586 | void queue_message(RTPSession *session, RTPMessage *msg) |
669 | { | 587 | { |
588 | /* This function is unregistered during call termination befor destroing | ||
589 | * Codec session so no need to check for validity of cs | ||
590 | */ | ||
670 | CSSession *cs = session->cs; | 591 | CSSession *cs = session->cs; |
671 | 592 | ||
672 | if (!cs || !cs->active) return; | 593 | if (!cs) return; |
673 | 594 | ||
674 | /* Audio */ | 595 | /* Audio */ |
675 | if (session->payload_type == type_audio % 128) { | 596 | if (session->payload_type == msi_TypeAudio % 128) { |
676 | jbuf_write(cs->j_buf, msg); | 597 | jbuf_write(cs->j_buf, msg); |
677 | 598 | ||
678 | pthread_mutex_lock(cs->queue_mutex); | ||
679 | int success = 0; | 599 | int success = 0; |
680 | 600 | ||
681 | while ((msg = jbuf_read(cs->j_buf, &success)) || success == 2) { | 601 | while ((msg = jbuf_read(cs->j_buf, &success)) || success == 2) { |
@@ -698,13 +618,13 @@ void queue_message(RTPSession *session, RTPMessage *msg) | |||
698 | } | 618 | } |
699 | 619 | ||
700 | if (p) { | 620 | if (p) { |
621 | pthread_mutex_lock(cs->queue_mutex); | ||
701 | buffer_write(cs->abuf_raw, p); | 622 | buffer_write(cs->abuf_raw, p); |
623 | pthread_mutex_unlock(cs->queue_mutex); | ||
702 | } else { | 624 | } else { |
703 | LOGGER_WARNING("Allocation failed! Program might misbehave!"); | 625 | LOGGER_WARNING("Allocation failed! Program might misbehave!"); |
704 | } | 626 | } |
705 | } | 627 | } |
706 | |||
707 | pthread_mutex_unlock(cs->queue_mutex); | ||
708 | } | 628 | } |
709 | /* Video */ | 629 | /* Video */ |
710 | else { | 630 | else { |