summaryrefslogtreecommitdiff
path: root/toxav/toxav.c
diff options
context:
space:
mode:
authorzoff99 <zoff@zoff.cc>2018-01-19 22:59:42 +0100
committeriphydf <iphydf@users.noreply.github.com>2018-02-11 23:31:46 +0000
commit721358208b6650c62aa654be922867f10a5d6f38 (patch)
tree988aef376cc8c74b19b5e605133072bdf3d23e27 /toxav/toxav.c
parent0647c2c5bc8c871dbcaed64de40eb252d13d303c (diff)
Improve video key frame sending.
This change does not include the addition of VP9. We do that in a separate pull request. Changes: * fix the video bug (video frames larger than 65KBytes) by sending full frame length in alternate header field * improve video frame reconstruction logic with slots * configure video encoder and decoder to be multihtreaded * set error resilience flags on video codec * change encoder and decoder softdeadline
Diffstat (limited to 'toxav/toxav.c')
-rw-r--r--toxav/toxav.c90
1 files changed, 67 insertions, 23 deletions
diff --git a/toxav/toxav.c b/toxav/toxav.c
index c48fc192..4e45b747 100644
--- a/toxav/toxav.c
+++ b/toxav/toxav.c
@@ -36,7 +36,18 @@
36#include <stdlib.h> 36#include <stdlib.h>
37#include <string.h> 37#include <string.h>
38 38
39#define MAX_ENCODE_TIME_US ((1000 / 24) * 1000) 39// TODO: don't hardcode this, let the application choose it
40// VPX Info: Time to spend encoding, in microseconds (it's a *soft* deadline)
41#define WANTED_MAX_ENCODER_FPS (40)
42#define MAX_ENCODE_TIME_US (1000000 / WANTED_MAX_ENCODER_FPS) // to allow x fps
43
44#define VIDEO_SEND_X_KEYFRAMES_FIRST 7 // force the first n frames to be keyframes!
45
46/*
47VPX_DL_REALTIME (1) deadline parameter analogous to VPx REALTIME mode.
48VPX_DL_GOOD_QUALITY (1000000) deadline parameter analogous to VPx GOOD QUALITY mode.
49VPX_DL_BEST_QUALITY (0) deadline parameter analogous to VPx BEST QUALITY mode.
50*/
40 51
41typedef struct ToxAVCall_s { 52typedef struct ToxAVCall_s {
42 ToxAV *av; 53 ToxAV *av;
@@ -752,13 +763,12 @@ bool toxav_audio_send_frame(ToxAV *av, uint32_t friend_number, const int16_t *pc
752 goto END; 763 goto END;
753 } 764 }
754 765
755 if (rtp_send_data(call->audio.first, dest, vrc + sizeof(sampling_rate), av->m->log) != 0) { 766 if (rtp_send_data(call->audio.first, dest, vrc + sizeof(sampling_rate), false, av->m->log) != 0) {
756 LOGGER_WARNING(av->m->log, "Failed to send audio packet"); 767 LOGGER_WARNING(av->m->log, "Failed to send audio packet");
757 rc = TOXAV_ERR_SEND_FRAME_RTP_FAILED; 768 rc = TOXAV_ERR_SEND_FRAME_RTP_FAILED;
758 } 769 }
759 } 770 }
760 771
761
762 pthread_mutex_unlock(call->mutex_audio); 772 pthread_mutex_unlock(call->mutex_audio);
763 773
764END: 774END:
@@ -769,12 +779,15 @@ END:
769 779
770 return rc == TOXAV_ERR_SEND_FRAME_OK; 780 return rc == TOXAV_ERR_SEND_FRAME_OK;
771} 781}
782
772bool toxav_video_send_frame(ToxAV *av, uint32_t friend_number, uint16_t width, uint16_t height, const uint8_t *y, 783bool toxav_video_send_frame(ToxAV *av, uint32_t friend_number, uint16_t width, uint16_t height, const uint8_t *y,
773 const uint8_t *u, const uint8_t *v, TOXAV_ERR_SEND_FRAME *error) 784 const uint8_t *u, const uint8_t *v, TOXAV_ERR_SEND_FRAME *error)
774{ 785{
775 TOXAV_ERR_SEND_FRAME rc = TOXAV_ERR_SEND_FRAME_OK; 786 TOXAV_ERR_SEND_FRAME rc = TOXAV_ERR_SEND_FRAME_OK;
776 ToxAVCall *call; 787 ToxAVCall *call;
777 788
789 int vpx_encode_flags = 0;
790
778 if (m_friend_exists(av->m, friend_number) == 0) { 791 if (m_friend_exists(av->m, friend_number) == 0) {
779 rc = TOXAV_ERR_SEND_FRAME_FRIEND_NOT_FOUND; 792 rc = TOXAV_ERR_SEND_FRAME_FRIEND_NOT_FOUND;
780 goto END; 793 goto END;
@@ -810,12 +823,28 @@ bool toxav_video_send_frame(ToxAV *av, uint32_t friend_number, uint16_t width, u
810 goto END; 823 goto END;
811 } 824 }
812 825
813 if (vc_reconfigure_encoder(call->video.second, call->video_bit_rate * 1000, width, height) != 0) { 826 if (vc_reconfigure_encoder(call->video.second, call->video_bit_rate * 1000, width, height, -1) != 0) {
814 pthread_mutex_unlock(call->mutex_video); 827 pthread_mutex_unlock(call->mutex_video);
815 rc = TOXAV_ERR_SEND_FRAME_INVALID; 828 rc = TOXAV_ERR_SEND_FRAME_INVALID;
816 goto END; 829 goto END;
817 } 830 }
818 831
832 if (call->video.first->ssrc < VIDEO_SEND_X_KEYFRAMES_FIRST) {
833 // Key frame flag for first frames
834 vpx_encode_flags = VPX_EFLAG_FORCE_KF;
835 LOGGER_INFO(av->m->log, "I_FRAME_FLAG:%d only-i-frame mode", call->video.first->ssrc);
836
837 call->video.first->ssrc++;
838 } else if (call->video.first->ssrc == VIDEO_SEND_X_KEYFRAMES_FIRST) {
839 // normal keyframe placement
840 vpx_encode_flags = 0;
841 LOGGER_INFO(av->m->log, "I_FRAME_FLAG:%d normal mode", call->video.first->ssrc);
842
843 call->video.first->ssrc++;
844 }
845
846 // we start with I-frames (full frames) and then switch to normal mode later
847
819 { /* Encode */ 848 { /* Encode */
820 vpx_image_t img; 849 vpx_image_t img;
821 img.w = img.h = img.d_w = img.d_h = 0; 850 img.w = img.h = img.d_w = img.d_h = 0;
@@ -829,7 +858,7 @@ bool toxav_video_send_frame(ToxAV *av, uint32_t friend_number, uint16_t width, u
829 memcpy(img.planes[VPX_PLANE_V], v, (width / 2) * (height / 2)); 858 memcpy(img.planes[VPX_PLANE_V], v, (width / 2) * (height / 2));
830 859
831 vpx_codec_err_t vrc = vpx_codec_encode(call->video.second->encoder, &img, 860 vpx_codec_err_t vrc = vpx_codec_encode(call->video.second->encoder, &img,
832 call->video.second->frame_counter, 1, 0, MAX_ENCODE_TIME_US); 861 call->video.second->frame_counter, 1, vpx_encode_flags, MAX_ENCODE_TIME_US);
833 862
834 vpx_img_free(&img); 863 vpx_img_free(&img);
835 864
@@ -847,22 +876,31 @@ bool toxav_video_send_frame(ToxAV *av, uint32_t friend_number, uint16_t width, u
847 vpx_codec_iter_t iter = nullptr; 876 vpx_codec_iter_t iter = nullptr;
848 const vpx_codec_cx_pkt_t *pkt; 877 const vpx_codec_cx_pkt_t *pkt;
849 878
850 while ((pkt = vpx_codec_get_cx_data(call->video.second->encoder, &iter))) { 879 while ((pkt = vpx_codec_get_cx_data(call->video.second->encoder, &iter)) != nullptr) {
851 if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) { 880 if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) {
852 const uint8_t *buf = (const uint8_t *)pkt->data.frame.buf; 881 const bool is_keyframe = (pkt->data.frame.flags & VPX_FRAME_IS_KEY) != 0;
853 const uint8_t *end = buf + pkt->data.frame.sz; 882
854 883 // https://www.webmproject.org/docs/webm-sdk/structvpx__codec__cx__pkt.html
855 while (buf < end) { 884 // pkt->data.frame.sz -> size_t
856 uint16_t size = MIN(UINT16_MAX, end - buf); 885 const uint32_t frame_length_in_bytes = pkt->data.frame.sz;
857 886
858 if (rtp_send_data(call->video.first, buf, size, av->m->log) < 0) { 887 const int res = rtp_send_data(
859 pthread_mutex_unlock(call->mutex_video); 888 call->video.first,
860 LOGGER_WARNING(av->m->log, "Could not send video frame: %s\n", strerror(errno)); 889 (const uint8_t *)pkt->data.frame.buf,
861 rc = TOXAV_ERR_SEND_FRAME_RTP_FAILED; 890 frame_length_in_bytes,
862 goto END; 891 is_keyframe,
863 } 892 av->m->log);
864 893
865 buf += size; 894 LOGGER_DEBUG(av->m->log, "+ _sending_FRAME_TYPE_==%s bytes=%d frame_len=%d", is_keyframe ? "K" : ".",
895 (int)pkt->data.frame.sz, (int)frame_length_in_bytes);
896 LOGGER_DEBUG(av->m->log, "+ _sending_FRAME_ b0=%d b1=%d", ((const uint8_t *)pkt->data.frame.buf)[0],
897 ((const uint8_t *)pkt->data.frame.buf)[1]);
898
899 if (res < 0) {
900 pthread_mutex_unlock(call->mutex_video);
901 LOGGER_WARNING(av->m->log, "Could not send video frame: %s", strerror(errno));
902 rc = TOXAV_ERR_SEND_FRAME_RTP_FAILED;
903 goto END;
866 } 904 }
867 } 905 }
868 } 906 }
@@ -878,6 +916,7 @@ END:
878 916
879 return rc == TOXAV_ERR_SEND_FRAME_OK; 917 return rc == TOXAV_ERR_SEND_FRAME_OK;
880} 918}
919
881void toxav_callback_audio_receive_frame(ToxAV *av, toxav_audio_receive_frame_cb *callback, void *user_data) 920void toxav_callback_audio_receive_frame(ToxAV *av, toxav_audio_receive_frame_cb *callback, void *user_data)
882{ 921{
883 pthread_mutex_lock(av->mutex); 922 pthread_mutex_lock(av->mutex);
@@ -885,6 +924,7 @@ void toxav_callback_audio_receive_frame(ToxAV *av, toxav_audio_receive_frame_cb
885 av->acb.second = user_data; 924 av->acb.second = user_data;
886 pthread_mutex_unlock(av->mutex); 925 pthread_mutex_unlock(av->mutex);
887} 926}
927
888void toxav_callback_video_receive_frame(ToxAV *av, toxav_video_receive_frame_cb *callback, void *user_data) 928void toxav_callback_video_receive_frame(ToxAV *av, toxav_video_receive_frame_cb *callback, void *user_data)
889{ 929{
890 pthread_mutex_lock(av->mutex); 930 pthread_mutex_lock(av->mutex);
@@ -893,7 +933,6 @@ void toxav_callback_video_receive_frame(ToxAV *av, toxav_video_receive_frame_cb
893 pthread_mutex_unlock(av->mutex); 933 pthread_mutex_unlock(av->mutex);
894} 934}
895 935
896
897/******************************************************************************* 936/*******************************************************************************
898 * 937 *
899 * :: Internal 938 * :: Internal
@@ -913,7 +952,8 @@ void callback_bwc(BWController *bwc, uint32_t friend_number, float loss, void *u
913 952
914 LOGGER_DEBUG(call->av->m->log, "Reported loss of %f%%", loss * 100); 953 LOGGER_DEBUG(call->av->m->log, "Reported loss of %f%%", loss * 100);
915 954
916 if (loss < .01f) { 955 /* if less than 10% data loss we do nothing! */
956 if (loss < 0.1f) {
917 return; 957 return;
918 } 958 }
919 959
@@ -1079,6 +1119,7 @@ bool invoke_call_state_callback(ToxAV *av, uint32_t friend_number, uint32_t stat
1079 1119
1080 return true; 1120 return true;
1081} 1121}
1122
1082ToxAVCall *call_new(ToxAV *av, uint32_t friend_number, TOXAV_ERR_CALL *error) 1123ToxAVCall *call_new(ToxAV *av, uint32_t friend_number, TOXAV_ERR_CALL *error)
1083{ 1124{
1084 /* Assumes mutex locked */ 1125 /* Assumes mutex locked */
@@ -1100,7 +1141,6 @@ ToxAVCall *call_new(ToxAV *av, uint32_t friend_number, TOXAV_ERR_CALL *error)
1100 goto END; 1141 goto END;
1101 } 1142 }
1102 1143
1103
1104 call = (ToxAVCall *)calloc(sizeof(ToxAVCall), 1); 1144 call = (ToxAVCall *)calloc(sizeof(ToxAVCall), 1);
1105 1145
1106 if (call == nullptr) { 1146 if (call == nullptr) {
@@ -1161,6 +1201,7 @@ END:
1161 1201
1162 return call; 1202 return call;
1163} 1203}
1204
1164ToxAVCall *call_get(ToxAV *av, uint32_t friend_number) 1205ToxAVCall *call_get(ToxAV *av, uint32_t friend_number)
1165{ 1206{
1166 /* Assumes mutex locked */ 1207 /* Assumes mutex locked */
@@ -1170,6 +1211,7 @@ ToxAVCall *call_get(ToxAV *av, uint32_t friend_number)
1170 1211
1171 return av->calls[friend_number]; 1212 return av->calls[friend_number];
1172} 1213}
1214
1173ToxAVCall *call_remove(ToxAVCall *call) 1215ToxAVCall *call_remove(ToxAVCall *call)
1174{ 1216{
1175 if (call == nullptr) { 1217 if (call == nullptr) {
@@ -1217,6 +1259,7 @@ CLEAR:
1217 1259
1218 return nullptr; 1260 return nullptr;
1219} 1261}
1262
1220bool call_prepare_transmission(ToxAVCall *call) 1263bool call_prepare_transmission(ToxAVCall *call)
1221{ 1264{
1222 /* Assumes mutex locked */ 1265 /* Assumes mutex locked */
@@ -1305,6 +1348,7 @@ FAILURE_3:
1305 pthread_mutex_destroy(call->mutex_audio); 1348 pthread_mutex_destroy(call->mutex_audio);
1306 return false; 1349 return false;
1307} 1350}
1351
1308void call_kill_transmission(ToxAVCall *call) 1352void call_kill_transmission(ToxAVCall *call)
1309{ 1353{
1310 if (call == nullptr || call->active == 0) { 1354 if (call == nullptr || call->active == 0) {