diff options
Diffstat (limited to 'toxav/toxmedia.c')
-rw-r--r-- | toxav/toxmedia.c | 819 |
1 files changed, 819 insertions, 0 deletions
diff --git a/toxav/toxmedia.c b/toxav/toxmedia.c new file mode 100644 index 00000000..aff3cf8c --- /dev/null +++ b/toxav/toxmedia.c | |||
@@ -0,0 +1,819 @@ | |||
1 | /* AV_codec.c | ||
2 | // * | ||
3 | * Audio and video codec intitialisation, encoding/decoding and playback | ||
4 | * | ||
5 | * Copyright (C) 2013 Tox project All Rights Reserved. | ||
6 | * | ||
7 | * This file is part of Tox. | ||
8 | * | ||
9 | * Tox is free software: you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation, either version 3 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * Tox is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with Tox. If not, see <http://www.gnu.org/licenses/>. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | /*----------------------------------------------------------------------------------*/ | ||
25 | |||
26 | #ifdef HAVE_CONFIG_H | ||
27 | #include "config.h" | ||
28 | #endif /* HAVE_CONFIG_H */ | ||
29 | |||
30 | #include <stdio.h> | ||
31 | #include <math.h> | ||
32 | #include <libavcodec/avcodec.h> | ||
33 | #include <libavformat/avformat.h> | ||
34 | #include <libswscale/swscale.h> | ||
35 | #include <libavdevice/avdevice.h> | ||
36 | #include <libavutil/opt.h> | ||
37 | #include <AL/al.h> | ||
38 | #include <AL/alc.h> | ||
39 | #include <SDL/SDL.h> | ||
40 | #include <SDL/SDL_thread.h> | ||
41 | #include <pthread.h> | ||
42 | #include <opus/opus.h> | ||
43 | |||
44 | #include "toxmsi.h" | ||
45 | #include "toxrtp.h" | ||
46 | #include "toxmedia.h" | ||
47 | |||
48 | SDL_Surface *screen; | ||
49 | |||
50 | int display_received_frame(codec_state *cs, AVFrame *r_video_frame) | ||
51 | { | ||
52 | AVPicture pict; | ||
53 | SDL_LockYUVOverlay(cs->video_picture.bmp); | ||
54 | |||
55 | pict.data[0] = cs->video_picture.bmp->pixels[0]; | ||
56 | pict.data[1] = cs->video_picture.bmp->pixels[2]; | ||
57 | pict.data[2] = cs->video_picture.bmp->pixels[1]; | ||
58 | pict.linesize[0] = cs->video_picture.bmp->pitches[0]; | ||
59 | pict.linesize[1] = cs->video_picture.bmp->pitches[2]; | ||
60 | pict.linesize[2] = cs->video_picture.bmp->pitches[1]; | ||
61 | |||
62 | /* Convert the image into YUV format that SDL uses */ | ||
63 | sws_scale(cs->sws_SDL_r_ctx, (uint8_t const * const *)r_video_frame->data, r_video_frame->linesize, 0, | ||
64 | cs->video_decoder_ctx->height, pict.data, pict.linesize ); | ||
65 | |||
66 | SDL_UnlockYUVOverlay(cs->video_picture.bmp); | ||
67 | SDL_Rect rect; | ||
68 | rect.x = 0; | ||
69 | rect.y = 0; | ||
70 | rect.w = cs->video_decoder_ctx->width; | ||
71 | rect.h = cs->video_decoder_ctx->height; | ||
72 | SDL_DisplayYUVOverlay(cs->video_picture.bmp, &rect); | ||
73 | return 1; | ||
74 | } | ||
75 | |||
76 | struct jitter_buffer { | ||
77 | RTPMessage **queue; | ||
78 | uint16_t capacity; | ||
79 | uint16_t size; | ||
80 | uint16_t front; | ||
81 | uint16_t rear; | ||
82 | uint8_t queue_ready; | ||
83 | uint16_t current_id; | ||
84 | uint32_t current_ts; | ||
85 | uint8_t id_set; | ||
86 | }; | ||
87 | |||
88 | struct jitter_buffer *create_queue(int capacity) | ||
89 | { | ||
90 | struct jitter_buffer *q; | ||
91 | q = (struct jitter_buffer *)calloc(sizeof(struct jitter_buffer),1); | ||
92 | q->queue = (RTPMessage **)calloc((sizeof(RTPMessage) * capacity),1); | ||
93 | int i = 0; | ||
94 | |||
95 | for (i = 0; i < capacity; ++i) { | ||
96 | q->queue[i] = NULL; | ||
97 | } | ||
98 | |||
99 | q->size = 0; | ||
100 | q->capacity = capacity; | ||
101 | q->front = 0; | ||
102 | q->rear = -1; | ||
103 | q->queue_ready = 0; | ||
104 | q->current_id = 0; | ||
105 | q->current_ts = 0; | ||
106 | q->id_set = 0; | ||
107 | return q; | ||
108 | } | ||
109 | |||
110 | /* returns 1 if 'a' has a higher sequence number than 'b' */ | ||
111 | uint8_t sequence_number_older(uint16_t sn_a, uint16_t sn_b, uint32_t ts_a, uint32_t ts_b) | ||
112 | { | ||
113 | /* should be stable enough */ | ||
114 | |||
115 | /* TODO: There is already this kind of function in toxrtp.c. | ||
116 | * Maybe merge? | ||
117 | */ | ||
118 | return (sn_a > sn_b || ts_a > ts_b); | ||
119 | } | ||
120 | |||
121 | /* success is 0 when there is nothing to dequeue, 1 when there's a good packet, 2 when there's a lost packet */ | ||
122 | RTPMessage *dequeue(struct jitter_buffer *q, int *success) | ||
123 | { | ||
124 | if (q->size == 0 || q->queue_ready == 0) { | ||
125 | q->queue_ready = 0; | ||
126 | *success = 0; | ||
127 | return NULL; | ||
128 | } | ||
129 | |||
130 | int front = q->front; | ||
131 | |||
132 | if (q->id_set == 0) { | ||
133 | q->current_id = q->queue[front]->header->sequnum; | ||
134 | q->current_ts = q->queue[front]->header->timestamp; | ||
135 | q->id_set = 1; | ||
136 | } else { | ||
137 | int next_id = q->queue[front]->header->sequnum; | ||
138 | int next_ts = q->queue[front]->header->timestamp; | ||
139 | |||
140 | /* if this packet is indeed the expected packet */ | ||
141 | if (next_id == (q->current_id + 1) % MAX_SEQU_NUM) { | ||
142 | q->current_id = next_id; | ||
143 | q->current_ts = next_ts; | ||
144 | } else { | ||
145 | if (sequence_number_older(next_id, q->current_id, next_ts, q->current_ts)) { | ||
146 | printf("nextid: %d current: %d\n", next_id, q->current_id); | ||
147 | q->current_id = (q->current_id + 1) % MAX_SEQU_NUM; | ||
148 | *success = 2; /* tell the decoder the packet is lost */ | ||
149 | return NULL; | ||
150 | } else { | ||
151 | /* packet too old */ | ||
152 | printf("packet too old\n"); | ||
153 | *success = 0; | ||
154 | return NULL; | ||
155 | } | ||
156 | } | ||
157 | } | ||
158 | |||
159 | q->size--; | ||
160 | q->front++; | ||
161 | |||
162 | if (q->front == q->capacity) | ||
163 | q->front = 0; | ||
164 | |||
165 | *success = 1; | ||
166 | q->current_id = q->queue[front]->header->sequnum; | ||
167 | q->current_ts = q->queue[front]->header->timestamp; | ||
168 | return q->queue[front]; | ||
169 | } | ||
170 | |||
171 | int empty_queue(struct jitter_buffer *q) | ||
172 | { | ||
173 | while (q->size > 0) { | ||
174 | q->size--; | ||
175 | /* FIXME: */ | ||
176 | /* rtp_free_msg(cs->_rtp_video, q->queue[q->front]); */ | ||
177 | q->front++; | ||
178 | |||
179 | if (q->front == q->capacity) | ||
180 | q->front = 0; | ||
181 | } | ||
182 | |||
183 | q->id_set = 0; | ||
184 | q->queue_ready = 0; | ||
185 | return 0; | ||
186 | } | ||
187 | |||
188 | int queue(struct jitter_buffer *q, RTPMessage *pk) | ||
189 | { | ||
190 | if (q->size == q->capacity) { | ||
191 | printf("buffer full, emptying buffer...\n"); | ||
192 | empty_queue(q); | ||
193 | return 0; | ||
194 | } | ||
195 | |||
196 | if (q->size > 8) | ||
197 | q->queue_ready = 1; | ||
198 | |||
199 | ++q->size; | ||
200 | ++q->rear; | ||
201 | |||
202 | if (q->rear == q->capacity) | ||
203 | q->rear = 0; | ||
204 | |||
205 | q->queue[q->rear] = pk; | ||
206 | |||
207 | int a; | ||
208 | int b; | ||
209 | int j; | ||
210 | a = q->rear; | ||
211 | |||
212 | for (j = 0; j < q->size - 1; ++j) { | ||
213 | b = a - 1; | ||
214 | |||
215 | if (b < 0) | ||
216 | b += q->capacity; | ||
217 | |||
218 | if (sequence_number_older(q->queue[b]->header->sequnum, q->queue[a]->header->sequnum, | ||
219 | q->queue[b]->header->timestamp, q->queue[a]->header->timestamp)) { | ||
220 | RTPMessage *temp; | ||
221 | temp = q->queue[a]; | ||
222 | q->queue[a] = q->queue[b]; | ||
223 | q->queue[b] = temp; | ||
224 | printf("had to swap\n"); | ||
225 | } else { | ||
226 | break; | ||
227 | } | ||
228 | |||
229 | a -= 1; | ||
230 | |||
231 | if (a < 0) | ||
232 | a += q->capacity; | ||
233 | } | ||
234 | |||
235 | if (pk) | ||
236 | return 1; | ||
237 | |||
238 | return 0; | ||
239 | } | ||
240 | |||
241 | int init_receive_audio(codec_state *cs) | ||
242 | { | ||
243 | int err = OPUS_OK; | ||
244 | cs->audio_decoder = opus_decoder_create(48000, 1, &err); | ||
245 | opus_decoder_init(cs->audio_decoder, 48000, 1); | ||
246 | printf("init audio decoder successful\n"); | ||
247 | return 1; | ||
248 | } | ||
249 | |||
250 | int init_receive_video(codec_state *cs) | ||
251 | { | ||
252 | cs->video_decoder = avcodec_find_decoder(VIDEO_CODEC); | ||
253 | |||
254 | if (!cs->video_decoder) { | ||
255 | printf("init video_decoder failed\n"); | ||
256 | return 0; | ||
257 | } | ||
258 | |||
259 | cs->video_decoder_ctx = avcodec_alloc_context3(cs->video_decoder); | ||
260 | |||
261 | if (!cs->video_decoder_ctx) { | ||
262 | printf("init video_decoder_ctx failed\n"); | ||
263 | return 0; | ||
264 | } | ||
265 | |||
266 | if (avcodec_open2(cs->video_decoder_ctx, cs->video_decoder, NULL) < 0) { | ||
267 | printf("opening video decoder failed\n"); | ||
268 | return 0; | ||
269 | } | ||
270 | |||
271 | printf("init video decoder successful\n"); | ||
272 | return 1; | ||
273 | } | ||
274 | |||
275 | int init_send_video(codec_state *cs) | ||
276 | { | ||
277 | cs->video_input_format = av_find_input_format(VIDEO_DRIVER); | ||
278 | |||
279 | if (avformat_open_input(&cs->video_format_ctx, DEFAULT_WEBCAM, cs->video_input_format, NULL) != 0) { | ||
280 | printf("opening video_input_format failed\n"); | ||
281 | return 0; | ||
282 | } | ||
283 | |||
284 | avformat_find_stream_info(cs->video_format_ctx, NULL); | ||
285 | av_dump_format(cs->video_format_ctx, 0, DEFAULT_WEBCAM, 0); | ||
286 | |||
287 | int i; | ||
288 | |||
289 | for (i = 0; i < cs->video_format_ctx->nb_streams; ++i) { | ||
290 | if (cs->video_format_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) { | ||
291 | cs->video_stream = i; | ||
292 | break; | ||
293 | } | ||
294 | } | ||
295 | |||
296 | cs->webcam_decoder_ctx = cs->video_format_ctx->streams[cs->video_stream]->codec; | ||
297 | cs->webcam_decoder = avcodec_find_decoder(cs->webcam_decoder_ctx->codec_id); | ||
298 | |||
299 | if (cs->webcam_decoder == NULL) { | ||
300 | printf("Unsupported codec\n"); | ||
301 | return 0; | ||
302 | } | ||
303 | |||
304 | if (cs->webcam_decoder_ctx == NULL) { | ||
305 | printf("init webcam_decoder_ctx failed\n"); | ||
306 | return 0; | ||
307 | } | ||
308 | |||
309 | if (avcodec_open2(cs->webcam_decoder_ctx, cs->webcam_decoder, NULL) < 0) { | ||
310 | printf("opening webcam decoder failed\n"); | ||
311 | return 0; | ||
312 | } | ||
313 | |||
314 | cs->video_encoder = avcodec_find_encoder(VIDEO_CODEC); | ||
315 | |||
316 | if (!cs->video_encoder) { | ||
317 | printf("init video_encoder failed\n"); | ||
318 | return 0; | ||
319 | } | ||
320 | |||
321 | cs->video_encoder_ctx = avcodec_alloc_context3(cs->video_encoder); | ||
322 | |||
323 | if (!cs->video_encoder_ctx) { | ||
324 | printf("init video_encoder_ctx failed\n"); | ||
325 | return 0; | ||
326 | } | ||
327 | |||
328 | cs->video_encoder_ctx->bit_rate = VIDEO_BITRATE; | ||
329 | cs->video_encoder_ctx->rc_min_rate = cs->video_encoder_ctx->rc_max_rate = cs->video_encoder_ctx->bit_rate; | ||
330 | av_opt_set_double(cs->video_encoder_ctx->priv_data, "max-intra-rate", 90, 0); | ||
331 | av_opt_set(cs->video_encoder_ctx->priv_data, "quality", "realtime", 0); | ||
332 | |||
333 | cs->video_encoder_ctx->thread_count = 4; | ||
334 | cs->video_encoder_ctx->rc_buffer_aggressivity = 0.95; | ||
335 | cs->video_encoder_ctx->rc_buffer_size = VIDEO_BITRATE * 6; | ||
336 | cs->video_encoder_ctx->profile = 3; | ||
337 | cs->video_encoder_ctx->qmax = 54; | ||
338 | cs->video_encoder_ctx->qmin = 4; | ||
339 | AVRational myrational = {1, 25}; | ||
340 | cs->video_encoder_ctx->time_base = myrational; | ||
341 | cs->video_encoder_ctx->gop_size = 99999; | ||
342 | cs->video_encoder_ctx->pix_fmt = PIX_FMT_YUV420P; | ||
343 | cs->video_encoder_ctx->width = cs->webcam_decoder_ctx->width; | ||
344 | cs->video_encoder_ctx->height = cs->webcam_decoder_ctx->height; | ||
345 | |||
346 | if (avcodec_open2(cs->video_encoder_ctx, cs->video_encoder, NULL) < 0) { | ||
347 | printf("opening video encoder failed\n"); | ||
348 | return 0; | ||
349 | } | ||
350 | |||
351 | printf("init video encoder successful\n"); | ||
352 | return 1; | ||
353 | } | ||
354 | |||
355 | int init_send_audio(codec_state *cs) | ||
356 | { | ||
357 | cs->support_send_audio = 0; | ||
358 | |||
359 | const ALchar *pDeviceList = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER); | ||
360 | int i = 0; | ||
361 | const ALchar *device_names[20]; | ||
362 | |||
363 | if (pDeviceList) { | ||
364 | printf("\nAvailable Capture Devices are:\n"); | ||
365 | |||
366 | while (*pDeviceList) { | ||
367 | device_names[i] = pDeviceList; | ||
368 | printf("%d) %s\n", i, device_names[i]); | ||
369 | pDeviceList += strlen(pDeviceList) + 1; | ||
370 | ++i; | ||
371 | } | ||
372 | } | ||
373 | |||
374 | printf("enter capture device number: \n"); | ||
375 | char dev[2]; | ||
376 | fgets(dev, sizeof(dev), stdin); | ||
377 | cs->audio_capture_device = alcCaptureOpenDevice(device_names[dev[0] - 48], AUDIO_SAMPLE_RATE, AL_FORMAT_MONO16, | ||
378 | AUDIO_FRAME_SIZE * 4); | ||
379 | |||
380 | if (alcGetError(cs->audio_capture_device) != AL_NO_ERROR) { | ||
381 | printf("could not start capture device! %d\n", alcGetError(cs->audio_capture_device)); | ||
382 | return 0; | ||
383 | } | ||
384 | |||
385 | int err = OPUS_OK; | ||
386 | cs->audio_bitrate = AUDIO_BITRATE; | ||
387 | cs->audio_encoder = opus_encoder_create(AUDIO_SAMPLE_RATE, 1, OPUS_APPLICATION_VOIP, &err); | ||
388 | err = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_BITRATE(cs->audio_bitrate)); | ||
389 | err = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_COMPLEXITY(10)); | ||
390 | err = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_SIGNAL(OPUS_SIGNAL_VOICE)); | ||
391 | |||
392 | opus_encoder_init(cs->audio_encoder, AUDIO_SAMPLE_RATE, 1, OPUS_APPLICATION_VOIP); | ||
393 | |||
394 | int nfo; | ||
395 | err = opus_encoder_ctl(cs->audio_encoder, OPUS_GET_LOOKAHEAD(&nfo)); | ||
396 | /* printf("Encoder lookahead delay : %d\n", nfo); */ | ||
397 | printf("init audio encoder successful\n"); | ||
398 | |||
399 | return 1; | ||
400 | } | ||
401 | |||
402 | int init_encoder(codec_state *cs) | ||
403 | { | ||
404 | avdevice_register_all(); | ||
405 | avcodec_register_all(); | ||
406 | avdevice_register_all(); | ||
407 | av_register_all(); | ||
408 | |||
409 | pthread_mutex_init(&cs->rtp_msg_mutex_lock, NULL); | ||
410 | pthread_mutex_init(&cs->avcodec_mutex_lock, NULL); | ||
411 | |||
412 | cs->support_send_video = init_send_video(cs); | ||
413 | cs->support_send_audio = init_send_audio(cs); | ||
414 | |||
415 | cs->send_audio = 1; | ||
416 | cs->send_video = 1; | ||
417 | |||
418 | return 1; | ||
419 | } | ||
420 | |||
421 | int init_decoder(codec_state *cs) | ||
422 | { | ||
423 | avdevice_register_all(); | ||
424 | avcodec_register_all(); | ||
425 | avdevice_register_all(); | ||
426 | av_register_all(); | ||
427 | |||
428 | cs->receive_video = 0; | ||
429 | cs->receive_audio = 0; | ||
430 | |||
431 | cs->support_receive_video = init_receive_video(cs); | ||
432 | cs->support_receive_audio = init_receive_audio(cs); | ||
433 | |||
434 | cs->receive_audio = 1; | ||
435 | cs->receive_video = 1; | ||
436 | |||
437 | return 1; | ||
438 | } | ||
439 | |||
440 | int video_encoder_refresh(codec_state *cs, int bps) | ||
441 | { | ||
442 | if (cs->video_encoder_ctx) | ||
443 | avcodec_close(cs->video_encoder_ctx); | ||
444 | |||
445 | cs->video_encoder = avcodec_find_encoder(VIDEO_CODEC); | ||
446 | |||
447 | if (!cs->video_encoder) { | ||
448 | printf("init video_encoder failed\n"); | ||
449 | return -1; | ||
450 | } | ||
451 | |||
452 | cs->video_encoder_ctx = avcodec_alloc_context3(cs->video_encoder); | ||
453 | |||
454 | if (!cs->video_encoder_ctx) { | ||
455 | printf("init video_encoder_ctx failed\n"); | ||
456 | return -1; | ||
457 | } | ||
458 | |||
459 | cs->video_encoder_ctx->bit_rate = bps; | ||
460 | cs->video_encoder_ctx->rc_min_rate = cs->video_encoder_ctx->rc_max_rate = cs->video_encoder_ctx->bit_rate; | ||
461 | av_opt_set_double(cs->video_encoder_ctx->priv_data, "max-intra-rate", 90, 0); | ||
462 | av_opt_set(cs->video_encoder_ctx->priv_data, "quality", "realtime", 0); | ||
463 | |||
464 | cs->video_encoder_ctx->thread_count = 4; | ||
465 | cs->video_encoder_ctx->rc_buffer_aggressivity = 0.95; | ||
466 | cs->video_encoder_ctx->rc_buffer_size = bps * 6; | ||
467 | cs->video_encoder_ctx->profile = 0; | ||
468 | cs->video_encoder_ctx->qmax = 54; | ||
469 | cs->video_encoder_ctx->qmin = 4; | ||
470 | AVRational myrational = {1, 25}; | ||
471 | cs->video_encoder_ctx->time_base = myrational; | ||
472 | cs->video_encoder_ctx->gop_size = 99999; | ||
473 | cs->video_encoder_ctx->pix_fmt = PIX_FMT_YUV420P; | ||
474 | cs->video_encoder_ctx->width = cs->webcam_decoder_ctx->width; | ||
475 | cs->video_encoder_ctx->height = cs->webcam_decoder_ctx->height; | ||
476 | |||
477 | if (avcodec_open2(cs->video_encoder_ctx, cs->video_encoder, NULL) < 0) { | ||
478 | printf("opening video encoder failed\n"); | ||
479 | return -1; | ||
480 | } | ||
481 | return 0; | ||
482 | } | ||
483 | |||
484 | void *encode_video_thread(void *arg) | ||
485 | { | ||
486 | codec_state *cs = (codec_state *)arg; | ||
487 | AVPacket pkt1, *packet = &pkt1; | ||
488 | int p = 0; | ||
489 | int err; | ||
490 | int got_packet; | ||
491 | RTPMessage *s_video_msg; | ||
492 | int video_frame_finished; | ||
493 | AVFrame *s_video_frame; | ||
494 | AVFrame *webcam_frame; | ||
495 | s_video_frame = avcodec_alloc_frame(); | ||
496 | webcam_frame = avcodec_alloc_frame(); | ||
497 | AVPacket enc_video_packet; | ||
498 | |||
499 | uint8_t *buffer; | ||
500 | int numBytes; | ||
501 | /* Determine required buffer size and allocate buffer */ | ||
502 | numBytes = avpicture_get_size(PIX_FMT_YUV420P, cs->webcam_decoder_ctx->width, cs->webcam_decoder_ctx->height); | ||
503 | buffer = (uint8_t *)av_calloc(numBytes * sizeof(uint8_t),1); | ||
504 | avpicture_fill((AVPicture *)s_video_frame, buffer, PIX_FMT_YUV420P, cs->webcam_decoder_ctx->width, | ||
505 | cs->webcam_decoder_ctx->height); | ||
506 | cs->sws_ctx = sws_getContext(cs->webcam_decoder_ctx->width, cs->webcam_decoder_ctx->height, | ||
507 | cs->webcam_decoder_ctx->pix_fmt, cs->webcam_decoder_ctx->width, cs->webcam_decoder_ctx->height, PIX_FMT_YUV420P, | ||
508 | SWS_BILINEAR, NULL, NULL, NULL); | ||
509 | |||
510 | while (!cs->quit && cs->send_video) { | ||
511 | |||
512 | if (av_read_frame(cs->video_format_ctx, packet) < 0) { | ||
513 | printf("error reading frame\n"); | ||
514 | |||
515 | if (cs->video_format_ctx->pb->error != 0) | ||
516 | break; | ||
517 | |||
518 | continue; | ||
519 | } | ||
520 | |||
521 | if (packet->stream_index == cs->video_stream) { | ||
522 | if (avcodec_decode_video2(cs->webcam_decoder_ctx, webcam_frame, &video_frame_finished, packet) < 0) { | ||
523 | printf("couldn't decode\n"); | ||
524 | continue; | ||
525 | } | ||
526 | |||
527 | av_free_packet(packet); | ||
528 | sws_scale(cs->sws_ctx, (uint8_t const * const *)webcam_frame->data, webcam_frame->linesize, 0, | ||
529 | cs->webcam_decoder_ctx->height, s_video_frame->data, s_video_frame->linesize); | ||
530 | /* create a new I-frame every 60 frames */ | ||
531 | ++p; | ||
532 | |||
533 | if (p == 60) { | ||
534 | |||
535 | s_video_frame->pict_type = AV_PICTURE_TYPE_BI ; | ||
536 | } else if (p == 61) { | ||
537 | s_video_frame->pict_type = AV_PICTURE_TYPE_I ; | ||
538 | p = 0; | ||
539 | } else { | ||
540 | s_video_frame->pict_type = AV_PICTURE_TYPE_P ; | ||
541 | } | ||
542 | |||
543 | if (video_frame_finished) { | ||
544 | err = avcodec_encode_video2(cs->video_encoder_ctx, &enc_video_packet, s_video_frame, &got_packet); | ||
545 | |||
546 | if (err < 0) { | ||
547 | printf("could not encode video frame\n"); | ||
548 | continue; | ||
549 | } | ||
550 | |||
551 | if (!got_packet) { | ||
552 | continue; | ||
553 | } | ||
554 | |||
555 | pthread_mutex_lock(&cs->rtp_msg_mutex_lock); | ||
556 | |||
557 | if (!enc_video_packet.data) fprintf(stderr, "video packet data is NULL\n"); | ||
558 | |||
559 | if ( 0 > rtp_send_msg ( cs->_rtp_video, cs->_messenger, enc_video_packet.data, enc_video_packet.size) ) { | ||
560 | printf("invalid message\n"); | ||
561 | } | ||
562 | |||
563 | pthread_mutex_unlock(&cs->rtp_msg_mutex_lock); | ||
564 | av_free_packet(&enc_video_packet); | ||
565 | } | ||
566 | } else { | ||
567 | av_free_packet(packet); | ||
568 | } | ||
569 | } | ||
570 | |||
571 | /* clean up codecs */ | ||
572 | pthread_mutex_lock(&cs->avcodec_mutex_lock); | ||
573 | av_free(buffer); | ||
574 | av_free(webcam_frame); | ||
575 | av_free(s_video_frame); | ||
576 | sws_freeContext(cs->sws_ctx); | ||
577 | avcodec_close(cs->webcam_decoder_ctx); | ||
578 | avcodec_close(cs->video_encoder_ctx); | ||
579 | pthread_mutex_unlock(&cs->avcodec_mutex_lock); | ||
580 | pthread_exit ( NULL ); | ||
581 | } | ||
582 | |||
583 | void *encode_audio_thread(void *arg) | ||
584 | { | ||
585 | codec_state *cs = (codec_state *)arg; | ||
586 | RTPMessage *s_audio_msg; | ||
587 | unsigned char encoded_data[4096]; | ||
588 | int encoded_size = 0; | ||
589 | int16_t frame[4096]; | ||
590 | int frame_size = AUDIO_FRAME_SIZE; | ||
591 | ALint sample = 0; | ||
592 | alcCaptureStart(cs->audio_capture_device); | ||
593 | |||
594 | while (!cs->quit && cs->send_audio) { | ||
595 | alcGetIntegerv(cs->audio_capture_device, ALC_CAPTURE_SAMPLES, (ALCsizei)sizeof(ALint), &sample); | ||
596 | |||
597 | if (sample >= frame_size) { | ||
598 | alcCaptureSamples(cs->audio_capture_device, frame, frame_size); | ||
599 | encoded_size = opus_encode(cs->audio_encoder, frame, frame_size, encoded_data, 480); | ||
600 | |||
601 | if (encoded_size <= 0) { | ||
602 | printf("Could not encode audio packet\n"); | ||
603 | } else { | ||
604 | pthread_mutex_lock(&cs->rtp_msg_mutex_lock); | ||
605 | |||
606 | rtp_send_msg ( cs->_rtp_audio, cs->_messenger, encoded_data, encoded_size ); | ||
607 | |||
608 | pthread_mutex_unlock(&cs->rtp_msg_mutex_lock); | ||
609 | |||
610 | } | ||
611 | } else { | ||
612 | usleep(1000); | ||
613 | } | ||
614 | } | ||
615 | |||
616 | /* clean up codecs */ | ||
617 | pthread_mutex_lock(&cs->avcodec_mutex_lock); | ||
618 | alcCaptureStop(cs->audio_capture_device); | ||
619 | alcCaptureCloseDevice(cs->audio_capture_device); | ||
620 | |||
621 | pthread_mutex_unlock(&cs->avcodec_mutex_lock); | ||
622 | pthread_exit ( NULL ); | ||
623 | } | ||
624 | |||
625 | |||
626 | int video_decoder_refresh(codec_state *cs, int width, int height) | ||
627 | { | ||
628 | printf("need to refresh\n"); | ||
629 | screen = SDL_SetVideoMode(width, height, 0, 0); | ||
630 | |||
631 | if (cs->video_picture.bmp) | ||
632 | SDL_FreeYUVOverlay(cs->video_picture.bmp); | ||
633 | |||
634 | cs->video_picture.bmp = SDL_CreateYUVOverlay(width, height, SDL_YV12_OVERLAY, screen); | ||
635 | cs->sws_SDL_r_ctx = sws_getContext(width, height, cs->video_decoder_ctx->pix_fmt, width, height, PIX_FMT_YUV420P, | ||
636 | SWS_BILINEAR, NULL, NULL, NULL); | ||
637 | return 1; | ||
638 | } | ||
639 | |||
640 | void *decode_video_thread(void *arg) | ||
641 | { | ||
642 | codec_state *cs = (codec_state *)arg; | ||
643 | cs->video_stream = 0; | ||
644 | RTPMessage *r_msg; | ||
645 | int dec_frame_finished; | ||
646 | AVFrame *r_video_frame; | ||
647 | r_video_frame = avcodec_alloc_frame(); | ||
648 | AVPacket dec_video_packet; | ||
649 | av_new_packet (&dec_video_packet, 65536); | ||
650 | int width = 0; | ||
651 | int height = 0; | ||
652 | |||
653 | while (!cs->quit && cs->receive_video) { | ||
654 | r_msg = rtp_recv_msg ( cs->_rtp_video ); | ||
655 | |||
656 | if (r_msg) { | ||
657 | memcpy(dec_video_packet.data, r_msg->data, r_msg->length); | ||
658 | dec_video_packet.size = r_msg->length; | ||
659 | avcodec_decode_video2(cs->video_decoder_ctx, r_video_frame, &dec_frame_finished, &dec_video_packet); | ||
660 | |||
661 | if (dec_frame_finished) { | ||
662 | if (cs->video_decoder_ctx->width != width || cs->video_decoder_ctx->height != height) { | ||
663 | width = cs->video_decoder_ctx->width; | ||
664 | height = cs->video_decoder_ctx->height; | ||
665 | printf("w: %d h%d \n", width, height); | ||
666 | video_decoder_refresh(cs, width, height); | ||
667 | } | ||
668 | |||
669 | display_received_frame(cs, r_video_frame); | ||
670 | } else { | ||
671 | /* TODO: request the sender to create a new i-frame immediatly */ | ||
672 | printf("bad video packet\n"); | ||
673 | } | ||
674 | |||
675 | rtp_free_msg(cs->_rtp_video, r_msg); | ||
676 | } | ||
677 | |||
678 | usleep(1000); | ||
679 | } | ||
680 | |||
681 | printf("vend\n"); | ||
682 | /* clean up codecs */ | ||
683 | pthread_mutex_lock(&cs->avcodec_mutex_lock); | ||
684 | av_free(r_video_frame); | ||
685 | avcodec_close(cs->video_decoder_ctx); | ||
686 | pthread_mutex_unlock(&cs->avcodec_mutex_lock); | ||
687 | pthread_exit ( NULL ); | ||
688 | } | ||
689 | |||
690 | void *decode_audio_thread(void *arg) | ||
691 | { | ||
692 | codec_state *cs = (codec_state *)arg; | ||
693 | RTPMessage *r_msg; | ||
694 | |||
695 | int frame_size = AUDIO_FRAME_SIZE; | ||
696 | int data_size; | ||
697 | |||
698 | ALCdevice *dev; | ||
699 | ALCcontext *ctx; | ||
700 | ALuint source, *buffers; | ||
701 | dev = alcOpenDevice(NULL); | ||
702 | ctx = alcCreateContext(dev, NULL); | ||
703 | alcMakeContextCurrent(ctx); | ||
704 | int openal_buffers = 5; | ||
705 | |||
706 | buffers = calloc(sizeof(ALuint) * openal_buffers,1); | ||
707 | alGenBuffers(openal_buffers, buffers); | ||
708 | alGenSources((ALuint)1, &source); | ||
709 | alSourcei(source, AL_LOOPING, AL_FALSE); | ||
710 | |||
711 | ALuint buffer; | ||
712 | ALint val; | ||
713 | |||
714 | ALenum error; | ||
715 | uint16_t zeros[frame_size]; | ||
716 | int i; | ||
717 | |||
718 | for (i = 0; i < frame_size; i++) { | ||
719 | zeros[i] = 0; | ||
720 | } | ||
721 | |||
722 | for (i = 0; i < openal_buffers; ++i) { | ||
723 | alBufferData(buffers[i], AL_FORMAT_MONO16, zeros, frame_size, 48000); | ||
724 | } | ||
725 | |||
726 | alSourceQueueBuffers(source, openal_buffers, buffers); | ||
727 | alSourcePlay(source); | ||
728 | |||
729 | if (alGetError() != AL_NO_ERROR) { | ||
730 | fprintf(stderr, "Error starting audio\n"); | ||
731 | cs->quit = 1; | ||
732 | } | ||
733 | |||
734 | struct jitter_buffer *j_buf = NULL; | ||
735 | |||
736 | j_buf = create_queue(20); | ||
737 | |||
738 | int success = 0; | ||
739 | |||
740 | int dec_frame_len; | ||
741 | |||
742 | opus_int16 PCM[frame_size]; | ||
743 | |||
744 | while (!cs->quit && cs->receive_audio) { | ||
745 | |||
746 | r_msg = rtp_recv_msg ( cs->_rtp_audio ); | ||
747 | |||
748 | if (r_msg) { | ||
749 | /* push the packet into the queue */ | ||
750 | queue(j_buf, r_msg); | ||
751 | } | ||
752 | |||
753 | /* grab a packet from the queue */ | ||
754 | success = 0; | ||
755 | alGetSourcei(source, AL_BUFFERS_PROCESSED, &val); | ||
756 | |||
757 | if (val > 0) | ||
758 | r_msg = dequeue(j_buf, &success); | ||
759 | |||
760 | if (success > 0) { | ||
761 | /* good packet */ | ||
762 | if (success == 1) { | ||
763 | dec_frame_len = opus_decode(cs->audio_decoder, r_msg->data, r_msg->length, PCM, frame_size, 0); | ||
764 | rtp_free_msg(cs->_rtp_audio, r_msg); | ||
765 | } | ||
766 | |||
767 | /* lost packet */ | ||
768 | if (success == 2) { | ||
769 | printf("lost packet\n"); | ||
770 | dec_frame_len = opus_decode(cs->audio_decoder, NULL, 0, PCM, frame_size, 1); | ||
771 | } | ||
772 | |||
773 | if (dec_frame_len > 0) { | ||
774 | alGetSourcei(source, AL_BUFFERS_PROCESSED, &val); | ||
775 | |||
776 | if (val <= 0) | ||
777 | continue; | ||
778 | |||
779 | alSourceUnqueueBuffers(source, 1, &buffer); | ||
780 | data_size = av_samples_get_buffer_size(NULL, 1, dec_frame_len, AV_SAMPLE_FMT_S16, 1); | ||
781 | alBufferData(buffer, AL_FORMAT_MONO16, PCM, data_size, 48000); | ||
782 | int error = alGetError(); | ||
783 | |||
784 | if (error != AL_NO_ERROR) { | ||
785 | fprintf(stderr, "Error setting buffer %d\n", error); | ||
786 | break; | ||
787 | } | ||
788 | |||
789 | alSourceQueueBuffers(source, 1, &buffer); | ||
790 | |||
791 | if (alGetError() != AL_NO_ERROR) { | ||
792 | fprintf(stderr, "error: could not buffer audio\n"); | ||
793 | break; | ||
794 | } | ||
795 | |||
796 | alGetSourcei(source, AL_SOURCE_STATE, &val); | ||
797 | |||
798 | if (val != AL_PLAYING) | ||
799 | alSourcePlay(source); | ||
800 | |||
801 | |||
802 | } | ||
803 | } | ||
804 | |||
805 | usleep(1000); | ||
806 | } | ||
807 | |||
808 | /* clean up codecs */ | ||
809 | pthread_mutex_lock(&cs->avcodec_mutex_lock); | ||
810 | |||
811 | /* clean up openal */ | ||
812 | alDeleteSources(1, &source); | ||
813 | alDeleteBuffers(openal_buffers, buffers); | ||
814 | alcMakeContextCurrent(NULL); | ||
815 | alcDestroyContext(ctx); | ||
816 | alcCloseDevice(dev); | ||
817 | pthread_mutex_unlock(&cs->avcodec_mutex_lock); | ||
818 | pthread_exit ( NULL ); | ||
819 | } | ||