diff options
Diffstat (limited to 'toxav/av_test.c')
-rw-r--r-- | toxav/av_test.c | 234 |
1 files changed, 158 insertions, 76 deletions
diff --git a/toxav/av_test.c b/toxav/av_test.c index f0ad6a01..b7260d7d 100644 --- a/toxav/av_test.c +++ b/toxav/av_test.c | |||
@@ -1,4 +1,4 @@ | |||
1 | #include "toxav.h" | 1 | #include "../toxav/toxav.h" |
2 | #include "../toxcore/tox.h" | 2 | #include "../toxcore/tox.h" |
3 | 3 | ||
4 | /* For playing audio data */ | 4 | /* For playing audio data */ |
@@ -11,9 +11,7 @@ | |||
11 | /* For reading and displaying video data */ | 11 | /* For reading and displaying video data */ |
12 | #include <opencv/cv.h> | 12 | #include <opencv/cv.h> |
13 | #include <opencv/highgui.h> | 13 | #include <opencv/highgui.h> |
14 | 14 | #include <opencv/cvwimage.h> | |
15 | /* For converting images TODO remove */ | ||
16 | #include <vpx/vpx_image.h> | ||
17 | 15 | ||
18 | 16 | ||
19 | #include <sys/stat.h> | 17 | #include <sys/stat.h> |
@@ -29,6 +27,23 @@ | |||
29 | #define c_sleep(x) usleep(1000*x) | 27 | #define c_sleep(x) usleep(1000*x) |
30 | 28 | ||
31 | 29 | ||
30 | #define CLIP(X) ( (X) > 255 ? 255 : (X) < 0 ? 0 : X) | ||
31 | |||
32 | // RGB -> YUV | ||
33 | #define RGB2Y(R, G, B) CLIP(( ( 66 * (R) + 129 * (G) + 25 * (B) + 128) >> 8) + 16) | ||
34 | #define RGB2U(R, G, B) CLIP(( ( -38 * (R) - 74 * (G) + 112 * (B) + 128) >> 8) + 128) | ||
35 | #define RGB2V(R, G, B) CLIP(( ( 112 * (R) - 94 * (G) - 18 * (B) + 128) >> 8) + 128) | ||
36 | |||
37 | // YUV -> RGB | ||
38 | #define C(Y) ( (Y) - 16 ) | ||
39 | #define D(U) ( (U) - 128 ) | ||
40 | #define E(V) ( (V) - 128 ) | ||
41 | |||
42 | #define YUV2R(Y, U, V) CLIP(( 298 * C(Y) + 409 * E(V) + 128) >> 8) | ||
43 | #define YUV2G(Y, U, V) CLIP(( 298 * C(Y) - 100 * D(U) - 208 * E(V) + 128) >> 8) | ||
44 | #define YUV2B(Y, U, V) CLIP(( 298 * C(Y) + 516 * D(U) + 128) >> 8) | ||
45 | |||
46 | |||
32 | /* Enable/disable tests */ | 47 | /* Enable/disable tests */ |
33 | #define TEST_REGULAR_AV 0 | 48 | #define TEST_REGULAR_AV 0 |
34 | #define TEST_REGULAR_A 0 | 49 | #define TEST_REGULAR_A 0 |
@@ -36,8 +51,8 @@ | |||
36 | #define TEST_REJECT 0 | 51 | #define TEST_REJECT 0 |
37 | #define TEST_CANCEL 0 | 52 | #define TEST_CANCEL 0 |
38 | #define TEST_MUTE_UNMUTE 0 | 53 | #define TEST_MUTE_UNMUTE 0 |
39 | #define TEST_TRANSFER_A 1 | 54 | #define TEST_TRANSFER_A 0 |
40 | #define TEST_TRANSFER_V 0 | 55 | #define TEST_TRANSFER_V 1 |
41 | 56 | ||
42 | 57 | ||
43 | typedef struct { | 58 | typedef struct { |
@@ -83,38 +98,32 @@ void t_toxav_receive_video_frame_cb(ToxAV *av, uint32_t friend_number, | |||
83 | uint8_t const *planes[], int32_t const stride[], | 98 | uint8_t const *planes[], int32_t const stride[], |
84 | void *user_data) | 99 | void *user_data) |
85 | { | 100 | { |
86 | IplImage output_img; | 101 | uint16_t *img_data = malloc(height * width * 6); |
87 | const int bpl = stride[VPX_PLANE_Y]; | 102 | |
88 | const int cxbpl = stride[VPX_PLANE_V]; | 103 | unsigned long int i, j; |
89 | 104 | for (i = 0; i < height; ++i) { | |
90 | output_img.imageData = malloc(width * height * 3); | 105 | for (j = 0; j < width; ++j) { |
91 | output_img.imageSize = width * height * 3; | 106 | uint8_t *point = (void*)img_data + 3 * ((i * width) + j); |
92 | output_img.width = width; | 107 | int y = planes[0][(i * stride[0]) + j]; |
93 | output_img.height = height; | 108 | int u = planes[1][((i / 2) * stride[1]) + (j / 2)]; |
94 | 109 | int v = planes[2][((i / 2) * stride[2]) + (j / 2)]; | |
95 | /* FIXME: possible bug? */ | 110 | |
96 | const uint8_t* yData = planes[VPX_PLANE_Y]; | 111 | point[0] = YUV2R(y, u, v); |
97 | const uint8_t* uData = planes[VPX_PLANE_V]; | 112 | point[1] = YUV2G(y, u, v); |
98 | const uint8_t* vData = planes[VPX_PLANE_U]; | 113 | point[2] = YUV2B(y, u, v); |
99 | |||
100 | // convert from planar to packed | ||
101 | int y = 0; | ||
102 | for (; y < height; ++y) | ||
103 | { | ||
104 | int x = 0; | ||
105 | for (; x < width; ++x) | ||
106 | { | ||
107 | uint8_t Y = planes[VPX_PLANE_Y][x + y * bpl]; | ||
108 | uint8_t U = planes[VPX_PLANE_V][x/(1 << 1) + y/(1 << 1)*cxbpl]; | ||
109 | uint8_t V = planes[VPX_PLANE_U][x/(1 << 1) + y/(1 << 1)*cxbpl]; | ||
110 | output_img.imageData[width * 3 * y + x * 3 + 0] = Y; | ||
111 | output_img.imageData[width * 3 * y + x * 3 + 1] = U; | ||
112 | output_img.imageData[width * 3 * y + x * 3 + 2] = V; | ||
113 | } | 114 | } |
114 | } | 115 | } |
115 | 116 | ||
116 | cvShowImage(vdout, &output_img); | 117 | |
117 | free(output_img.imageData); | 118 | CvMat mat = cvMat(height, width, CV_8UC3, img_data); |
119 | |||
120 | CvSize sz = {.height = height, .width = width}; | ||
121 | |||
122 | IplImage* header = cvCreateImageHeader(sz, 1, 3); | ||
123 | IplImage* img = cvGetImage(&mat, header); | ||
124 | cvShowImage(vdout, img); | ||
125 | cvWaitKey(1); | ||
126 | free(img_data); | ||
118 | } | 127 | } |
119 | void t_toxav_receive_audio_frame_cb(ToxAV *av, uint32_t friend_number, | 128 | void t_toxav_receive_audio_frame_cb(ToxAV *av, uint32_t friend_number, |
120 | int16_t const *pcm, | 129 | int16_t const *pcm, |
@@ -140,7 +149,7 @@ void t_toxav_receive_audio_frame_cb(ToxAV *av, uint32_t friend_number, | |||
140 | return; | 149 | return; |
141 | 150 | ||
142 | 151 | ||
143 | alBufferData(bufid, channels == 2 ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16, | 152 | alBufferData(bufid, channels == 1 ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16, |
144 | pcm, sample_count * 2, sampling_rate); | 153 | pcm, sample_count * 2, sampling_rate); |
145 | alSourceQueueBuffers(adout, 1, &bufid); | 154 | alSourceQueueBuffers(adout, 1, &bufid); |
146 | 155 | ||
@@ -244,45 +253,42 @@ int iterate_tox(Tox* bootstrap, ToxAV* AliceAV, ToxAV* BobAV) | |||
244 | } | 253 | } |
245 | 254 | ||
246 | int send_opencv_img(ToxAV* av, uint32_t friend_number, const IplImage* img) | 255 | int send_opencv_img(ToxAV* av, uint32_t friend_number, const IplImage* img) |
247 | { | 256 | { |
248 | /* I use vpx image coz i'm noob TODO use opencv conversion */ | 257 | int32_t strides[3] = { 1280, 640, 640 }; |
249 | vpx_image_t vpx_img; | 258 | uint8_t* planes[3] = { |
250 | vpx_img.w = vpx_img.h = vpx_img.d_w = vpx_img.d_h = 0; | 259 | malloc(img->height * img->width), |
251 | 260 | malloc(img->height * img->width / 2), | |
252 | const int w = img->width; | 261 | malloc(img->height * img->width / 2), |
253 | const int h = img->height; | 262 | }; |
254 | 263 | ||
255 | vpx_img_alloc(&vpx_img, VPX_IMG_FMT_VPXI420, w, h, 1); | 264 | int x_chroma_shift = 1; |
265 | int y_chroma_shift = 1; | ||
256 | 266 | ||
257 | int y = 0; | 267 | int x, y; |
258 | for (; y < h; ++y) | 268 | for (y = 0; y < img->height; ++y) { |
259 | { | 269 | for (x = 0; x < img->width; ++x) { |
260 | int x = 0; | 270 | uint8_t r = img->imageData[(x + y * img->width) * 3 + 0]; |
261 | for (; x < w; ++x) | 271 | uint8_t g = img->imageData[(x + y * img->width) * 3 + 1]; |
262 | { | 272 | uint8_t b = img->imageData[(x + y * img->width) * 3 + 2]; |
263 | uint8_t b = img->imageData[(x + y * w) * 3 + 0]; | ||
264 | uint8_t g = img->imageData[(x + y * w) * 3 + 1]; | ||
265 | uint8_t r = img->imageData[(x + y * w) * 3 + 2]; | ||
266 | 273 | ||
267 | vpx_img.planes[VPX_PLANE_Y][x + y * vpx_img.stride[VPX_PLANE_Y]] = ((66 * r + 129 * g + 25 * b) >> 8) + 16; | 274 | planes[0][x + y * strides[0]] = RGB2Y(r, g, b); |
268 | 275 | if (!(x % (1 << x_chroma_shift)) && !(y % (1 << y_chroma_shift))) { | |
269 | if (!(x % (1 << vpx_img.x_chroma_shift)) && !(y % (1 << vpx_img.y_chroma_shift))) | 276 | const int i = x / (1 << x_chroma_shift); |
270 | { | 277 | const int j = y / (1 << y_chroma_shift); |
271 | const int i = x / (1 << vpx_img.x_chroma_shift); | 278 | planes[1][i + j * strides[1]] = RGB2U(r, g, b); |
272 | const int j = y / (1 << vpx_img.y_chroma_shift); | 279 | planes[2][i + j * strides[2]] = RGB2V(r, g, b); |
273 | vpx_img.planes[VPX_PLANE_U][i + j * vpx_img.stride[VPX_PLANE_U]] = ((112 * r + -94 * g + -18 * b) >> 8) + 128; | ||
274 | vpx_img.planes[VPX_PLANE_V][i + j * vpx_img.stride[VPX_PLANE_V]] = ((-38 * r + -74 * g + 112 * b) >> 8) + 128; | ||
275 | } | 280 | } |
276 | } | 281 | } |
277 | } | 282 | } |
278 | 283 | ||
279 | int rc = toxav_send_video_frame(av, friend_number, w, h, | ||
280 | vpx_img.planes[VPX_PLANE_Y], | ||
281 | vpx_img.planes[VPX_PLANE_U], | ||
282 | vpx_img.planes[VPX_PLANE_V], NULL); | ||
283 | 284 | ||
284 | vpx_img_free(&vpx_img); | 285 | // int rc = toxav_send_video_frame(av, friend_number, img->width, img->height, planes[0], planes[1], planes[2], NULL); |
285 | return rc; | 286 | t_toxav_receive_video_frame_cb(av, 0, img->width, img->height, (const uint8_t**) planes, strides, NULL); |
287 | free(planes[0]); | ||
288 | free(planes[1]); | ||
289 | free(planes[2]); | ||
290 | // return rc; | ||
291 | return 0; | ||
286 | } | 292 | } |
287 | 293 | ||
288 | ALCdevice* open_audio_device(const char* audio_out_dev_name) | 294 | ALCdevice* open_audio_device(const char* audio_out_dev_name) |
@@ -403,6 +409,32 @@ int main (int argc, char** argv) | |||
403 | } | 409 | } |
404 | } | 410 | } |
405 | 411 | ||
412 | |||
413 | cvNamedWindow(vdout, CV_WINDOW_AUTOSIZE); | ||
414 | |||
415 | CvCapture* capture = cvCreateFileCapture(vf_name); | ||
416 | if (!capture) { | ||
417 | printf("Failed to open video file: %s\n", vf_name); | ||
418 | exit(1); | ||
419 | } | ||
420 | |||
421 | IplImage* frame; | ||
422 | time_t start_time = time(NULL); | ||
423 | |||
424 | int frame_rate = cvGetCaptureProperty(capture, CV_CAP_PROP_FPS); | ||
425 | while(start_time + 4 > time(NULL)) { | ||
426 | frame = cvQueryFrame( capture ); | ||
427 | if (!frame) | ||
428 | break; | ||
429 | |||
430 | send_opencv_img(NULL, 0, frame); | ||
431 | c_sleep(1); | ||
432 | } | ||
433 | |||
434 | cvReleaseCapture(&capture); | ||
435 | cvDestroyWindow(vdout); | ||
436 | |||
437 | return 0; | ||
406 | const char* audio_out_dev_name = NULL; | 438 | const char* audio_out_dev_name = NULL; |
407 | 439 | ||
408 | int i = 0; | 440 | int i = 0; |
@@ -706,19 +738,19 @@ int main (int argc, char** argv) | |||
706 | time_t expected_time = af_info.frames / af_info.samplerate + 2; | 738 | time_t expected_time = af_info.frames / af_info.samplerate + 2; |
707 | 739 | ||
708 | while ( start_time + expected_time > time(NULL) ) { | 740 | while ( start_time + expected_time > time(NULL) ) { |
709 | int frame_size = (af_info.samplerate * frame_duration / 1000); | 741 | int frame_size = (af_info.samplerate * frame_duration / 1000) * af_info.channels; |
710 | 742 | ||
711 | int64_t count = sf_read_short(af_handle, PCM, frame_size); | 743 | int64_t count = sf_read_short(af_handle, PCM, frame_size); |
712 | if (count > 0) { | 744 | if (count > 0) { |
713 | t_toxav_receive_audio_frame_cb(BobAV, 0, PCM, count, af_info.channels, af_info.samplerate, NULL); | 745 | // t_toxav_receive_audio_frame_cb(AliceAV, 0, PCM, count, af_info.channels, af_info.samplerate, NULL); |
714 | // TOXAV_ERR_SEND_FRAME rc; | 746 | TOXAV_ERR_SEND_FRAME rc; |
715 | // if (toxav_send_audio_frame(AliceAV, 0, PCM, count, af_info.channels, af_info.samplerate, &rc) == false) { | 747 | if (toxav_send_audio_frame(AliceAV, 0, PCM, count, af_info.channels, af_info.samplerate, &rc) == false) { |
716 | // printf("Error sending frame of size %ld: %d\n", count, rc); | 748 | printf("Error sending frame of size %ld: %d\n", count, rc); |
717 | // exit(1); | 749 | exit(1); |
718 | // } | 750 | } |
719 | } | 751 | } |
720 | c_sleep(frame_duration); | 752 | iterate_tox(bootstrap, AliceAV, BobAV); |
721 | // iterate_tox(bootstrap, AliceAV, BobAV); | 753 | // c_sleep(frame_duration); |
722 | } | 754 | } |
723 | 755 | ||
724 | 756 | ||
@@ -744,6 +776,36 @@ int main (int argc, char** argv) | |||
744 | } | 776 | } |
745 | 777 | ||
746 | if (TEST_TRANSFER_V) { | 778 | if (TEST_TRANSFER_V) { |
779 | printf("\nTrying video enc/dec...\n"); | ||
780 | |||
781 | memset(&AliceCC, 0, sizeof(CallControl)); | ||
782 | memset(&BobCC, 0, sizeof(CallControl)); | ||
783 | |||
784 | { /* Call */ | ||
785 | TOXAV_ERR_CALL rc; | ||
786 | toxav_call(AliceAV, 0, 0, 500000, &rc); | ||
787 | |||
788 | if (rc != TOXAV_ERR_CALL_OK) { | ||
789 | printf("toxav_call failed: %d\n", rc); | ||
790 | exit(1); | ||
791 | } | ||
792 | } | ||
793 | |||
794 | while (!BobCC.incoming) | ||
795 | iterate_tox(bootstrap, AliceAV, BobAV); | ||
796 | |||
797 | { /* Answer */ | ||
798 | TOXAV_ERR_ANSWER rc; | ||
799 | toxav_answer(BobAV, 0, 0, 500000, &rc); | ||
800 | |||
801 | if (rc != TOXAV_ERR_ANSWER_OK) { | ||
802 | printf("toxav_answer failed: %d\n", rc); | ||
803 | exit(1); | ||
804 | } | ||
805 | } | ||
806 | |||
807 | iterate_tox(bootstrap, AliceAV, BobAV); | ||
808 | |||
747 | cvNamedWindow(vdout, CV_WINDOW_AUTOSIZE); | 809 | cvNamedWindow(vdout, CV_WINDOW_AUTOSIZE); |
748 | 810 | ||
749 | CvCapture* capture = cvCreateFileCapture(vf_name); | 811 | CvCapture* capture = cvCreateFileCapture(vf_name); |
@@ -755,15 +817,35 @@ int main (int argc, char** argv) | |||
755 | IplImage* frame; | 817 | IplImage* frame; |
756 | time_t start_time = time(NULL); | 818 | time_t start_time = time(NULL); |
757 | 819 | ||
820 | int frame_rate = cvGetCaptureProperty(capture, CV_CAP_PROP_FPS); | ||
758 | while(start_time + 10 > time(NULL)) { | 821 | while(start_time + 10 > time(NULL)) { |
759 | frame = cvQueryFrame( capture ); | 822 | frame = cvQueryFrame( capture ); |
760 | if (!frame) | 823 | if (!frame) |
761 | break; | 824 | break; |
762 | 825 | ||
826 | // cvShowImage(vdout, frame); | ||
827 | // cvWaitKey(frame_rate); | ||
828 | send_opencv_img(AliceAV, 0, frame); | ||
829 | iterate_tox(bootstrap, AliceAV, BobAV); | ||
763 | } | 830 | } |
764 | 831 | ||
765 | cvReleaseCapture(&capture); | 832 | cvReleaseCapture(&capture); |
766 | cvDestroyWindow(vdout); | 833 | cvDestroyWindow(vdout); |
834 | |||
835 | { /* Hangup */ | ||
836 | TOXAV_ERR_CALL_CONTROL rc; | ||
837 | toxav_call_control(AliceAV, 0, TOXAV_CALL_CONTROL_CANCEL, &rc); | ||
838 | |||
839 | if (rc != TOXAV_ERR_CALL_CONTROL_OK) { | ||
840 | printf("toxav_call_control failed: %d\n", rc); | ||
841 | exit(1); | ||
842 | } | ||
843 | } | ||
844 | |||
845 | iterate_tox(bootstrap, AliceAV, BobAV); | ||
846 | assert(BobCC.state == TOXAV_CALL_STATE_END); | ||
847 | |||
848 | printf("Success!"); | ||
767 | } | 849 | } |
768 | 850 | ||
769 | 851 | ||