summaryrefslogtreecommitdiff
path: root/toxav/media.c
diff options
context:
space:
mode:
Diffstat (limited to 'toxav/media.c')
-rw-r--r--toxav/media.c397
1 files changed, 397 insertions, 0 deletions
diff --git a/toxav/media.c b/toxav/media.c
new file mode 100644
index 00000000..e18c1803
--- /dev/null
+++ b/toxav/media.c
@@ -0,0 +1,397 @@
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 <opus/opus.h>
38#include <assert.h>
39
40#include "rtp.h"
41#include "media.h"
42
43struct jitter_buffer {
44 RTPMessage **queue;
45 uint16_t capacity;
46 uint16_t size;
47 uint16_t front;
48 uint16_t rear;
49 uint8_t queue_ready;
50 uint16_t current_id;
51 uint32_t current_ts;
52 uint8_t id_set;
53};
54
55
56struct jitter_buffer *create_queue(int capacity)
57{
58 struct jitter_buffer *q;
59 q = (struct jitter_buffer *)calloc(sizeof(struct jitter_buffer),1);
60 q->queue = (RTPMessage **)calloc(sizeof(RTPMessage*), capacity);
61 int i = 0;
62
63 for (i = 0; i < capacity; ++i) {
64 q->queue[i] = NULL;
65 }
66
67 q->size = 0;
68 q->capacity = capacity;
69 q->front = 0;
70 q->rear = -1;
71 q->queue_ready = 0;
72 q->current_id = 0;
73 q->current_ts = 0;
74 q->id_set = 0;
75 return q;
76}
77
78/* returns 1 if 'a' has a higher sequence number than 'b' */
79uint8_t sequence_number_older(uint16_t sn_a, uint16_t sn_b, uint32_t ts_a, uint32_t ts_b)
80{
81 /* TODO: There is already this kind of function in toxrtp.c.
82 * Maybe merge?
83 */
84 return (sn_a > sn_b || ts_a > ts_b);
85}
86
87/* success is 0 when there is nothing to dequeue, 1 when there's a good packet, 2 when there's a lost packet */
88RTPMessage *dequeue(struct jitter_buffer *q, int *success)
89{
90 if (q->size == 0 || q->queue_ready == 0) {
91 q->queue_ready = 0;
92 *success = 0;
93 return NULL;
94 }
95
96 int front = q->front;
97
98 if (q->id_set == 0) {
99 q->current_id = q->queue[front]->header->sequnum;
100 q->current_ts = q->queue[front]->header->timestamp;
101 q->id_set = 1;
102 } else {
103 int next_id = q->queue[front]->header->sequnum;
104 int next_ts = q->queue[front]->header->timestamp;
105
106 /* if this packet is indeed the expected packet */
107 if (next_id == (q->current_id + 1) % MAX_SEQU_NUM) {
108 q->current_id = next_id;
109 q->current_ts = next_ts;
110 } else {
111 if (sequence_number_older(next_id, q->current_id, next_ts, q->current_ts)) {
112 printf("nextid: %d current: %d\n", next_id, q->current_id);
113 q->current_id = (q->current_id + 1) % MAX_SEQU_NUM;
114 *success = 2; /* tell the decoder the packet is lost */
115 return NULL;
116 } else {
117 /* packet too old */
118 printf("packet too old\n");
119 *success = 0;
120 return NULL;
121 }
122 }
123 }
124
125 q->size--;
126 q->front++;
127
128 if (q->front == q->capacity)
129 q->front = 0;
130
131 *success = 1;
132 q->current_id = q->queue[front]->header->sequnum;
133 q->current_ts = q->queue[front]->header->timestamp;
134 return q->queue[front];
135}
136
137int empty_queue(struct jitter_buffer *q)
138{
139 while (q->size > 0) {
140 q->size--;
141 rtp_free_msg(NULL, q->queue[q->front]);
142 q->front++;
143
144 if (q->front == q->capacity)
145 q->front = 0;
146 }
147
148 q->id_set = 0;
149 q->queue_ready = 0;
150 return 0;
151}
152
153int queue(struct jitter_buffer *q, RTPMessage *pk)
154{
155 if (q->size == q->capacity) {
156 printf("buffer full, emptying buffer...\n");
157 empty_queue(q);
158 return 0;
159 }
160
161 if (q->size > 8)
162 q->queue_ready = 1;
163
164 ++q->size;
165 ++q->rear;
166
167 if (q->rear == q->capacity)
168 q->rear = 0;
169
170 q->queue[q->rear] = pk;
171
172 int a;
173 int b;
174 int j;
175 a = q->rear;
176
177 for (j = 0; j < q->size - 1; ++j) {
178 b = a - 1;
179
180 if (b < 0)
181 b += q->capacity;
182
183 if (sequence_number_older(q->queue[b]->header->sequnum, q->queue[a]->header->sequnum,
184 q->queue[b]->header->timestamp, q->queue[a]->header->timestamp)) {
185 RTPMessage *temp;
186 temp = q->queue[a];
187 q->queue[a] = q->queue[b];
188 q->queue[b] = temp;
189 printf("had to swap\n");
190 } else {
191 break;
192 }
193
194 a -= 1;
195
196 if (a < 0)
197 a += q->capacity;
198 }
199
200 if (pk)
201 return 1;
202
203 return 0;
204}
205
206
207int init_video_decoder(CodecState *cs)
208{
209 cs->video_decoder = avcodec_find_decoder(VIDEO_CODEC);
210
211 if (!cs->video_decoder) {
212 fprintf(stderr, "Init video_decoder failed!\n");
213 return -1;
214 }
215
216 cs->video_decoder_ctx = avcodec_alloc_context3(cs->video_decoder);
217
218 if (!cs->video_decoder_ctx) {
219 fprintf(stderr, "Init video_decoder_ctx failed!\n");
220 return -1;
221 }
222
223 if (avcodec_open2(cs->video_decoder_ctx, cs->video_decoder, NULL) < 0) {
224 fprintf(stderr, "Opening video decoder failed!\n");
225 return -1;
226 }
227
228 return 0;
229}
230
231int init_audio_decoder(CodecState *cs, uint32_t audio_channels)
232{
233 int rc;
234 cs->audio_decoder = opus_decoder_create(cs->audio_sample_rate, audio_channels, &rc );
235
236 if ( rc != OPUS_OK ){
237 fprintf(stderr, "Error while starting audio decoder!\n");
238 return -1;
239 }
240
241 return 0;
242}
243
244
245int init_video_encoder(CodecState *cs, const char* webcam, const char* video_driver, uint32_t video_bitrate)
246{
247 cs->video_input_format = av_find_input_format(video_driver);
248
249 if (avformat_open_input(&cs->video_format_ctx, webcam, cs->video_input_format, NULL) != 0) {
250 fprintf(stderr, "Opening video_input_format failed!\n");
251 return -1;
252 }
253
254 avformat_find_stream_info(cs->video_format_ctx, NULL);
255 av_dump_format(cs->video_format_ctx, 0, webcam, 0);
256
257 int i;
258
259 for (i = 0; i < cs->video_format_ctx->nb_streams; ++i) {
260 if (cs->video_format_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
261 cs->video_stream = i;
262 break;
263 }
264 }
265
266 cs->webcam_decoder_ctx = cs->video_format_ctx->streams[cs->video_stream]->codec;
267 cs->webcam_decoder = avcodec_find_decoder(cs->webcam_decoder_ctx->codec_id);
268
269 if (cs->webcam_decoder == NULL) {
270 fprintf(stderr, "Unsupported codec!\n");
271 return -1;
272 }
273
274 if (cs->webcam_decoder_ctx == NULL) {
275 fprintf(stderr, "Init webcam_decoder_ctx failed!\n");
276 return -1;
277 }
278
279 if (avcodec_open2(cs->webcam_decoder_ctx, cs->webcam_decoder, NULL) < 0) {
280 fprintf(stderr, "Opening webcam decoder failed!\n");
281 return -1;
282 }
283
284 cs->video_encoder = avcodec_find_encoder(VIDEO_CODEC);
285
286 if (!cs->video_encoder) {
287 fprintf(stderr, "Init video_encoder failed!\n");
288 return -1;
289 }
290
291 cs->video_encoder_ctx = avcodec_alloc_context3(cs->video_encoder);
292
293 if (!cs->video_encoder_ctx) {
294 fprintf(stderr, "Init video_encoder_ctx failed!\n");
295 return -1;
296 }
297
298 cs->video_encoder_ctx->bit_rate = video_bitrate;
299 cs->video_encoder_ctx->rc_min_rate = cs->video_encoder_ctx->rc_max_rate = cs->video_encoder_ctx->bit_rate;
300 av_opt_set_double(cs->video_encoder_ctx->priv_data, "max-intra-rate", 90, 0);
301 av_opt_set(cs->video_encoder_ctx->priv_data, "quality", "realtime", 0);
302
303 cs->video_encoder_ctx->thread_count = 4;
304 cs->video_encoder_ctx->rc_buffer_aggressivity = 0.95;
305 cs->video_encoder_ctx->rc_buffer_size = video_bitrate * 6;
306 cs->video_encoder_ctx->profile = 3;
307 cs->video_encoder_ctx->qmax = 54;
308 cs->video_encoder_ctx->qmin = 4;
309 AVRational myrational = {1, 25};
310 cs->video_encoder_ctx->time_base = myrational;
311 cs->video_encoder_ctx->gop_size = 99999;
312 cs->video_encoder_ctx->pix_fmt = PIX_FMT_YUV420P;
313 cs->video_encoder_ctx->width = cs->webcam_decoder_ctx->width;
314 cs->video_encoder_ctx->height = cs->webcam_decoder_ctx->height;
315
316 if (avcodec_open2(cs->video_encoder_ctx, cs->video_encoder, NULL) < 0) {
317 fprintf(stderr, "Opening video encoder failed!\n");
318 return -1;
319 }
320
321 return 0;
322}
323
324int init_audio_encoder(CodecState *cs)
325{
326 int err = OPUS_OK;
327 cs->audio_encoder = opus_encoder_create(cs->audio_sample_rate, 1, OPUS_APPLICATION_VOIP, &err);
328
329 err = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_BITRATE(cs->audio_bitrate));
330 err = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_COMPLEXITY(10));
331 err = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_SIGNAL(OPUS_SIGNAL_VOICE));
332
333 /* NOTE: What do we do with this? */
334 int nfo;
335 err = opus_encoder_ctl(cs->audio_encoder, OPUS_GET_LOOKAHEAD(&nfo));
336
337 return err == OPUS_OK ? 0 : -1;
338}
339
340
341CodecState* codec_init_session ( uint32_t audio_bitrate,
342 uint16_t audio_frame_duration,
343 uint32_t audio_sample_rate,
344 uint32_t audio_channels,
345 uint32_t video_bitrate,
346 const char* webcam,
347 const char* webcam_driver )
348{
349 CodecState* _retu = av_calloc(sizeof(CodecState), 1);
350 assert(_retu);
351
352
353 avdevice_register_all();
354 avcodec_register_all();
355 av_register_all();
356
357
358 _retu->audio_bitrate = audio_bitrate;
359 _retu->audio_sample_rate = audio_sample_rate;
360
361 pthread_mutex_init(&_retu->ctrl_mutex, NULL);
362
363
364 /* Encoders */
365 if ( 0 == init_video_encoder(_retu, webcam, webcam_driver, video_bitrate) )
366 printf("Video encoder initialized!\n");
367
368 if ( 0 == init_audio_encoder(_retu) )
369 printf("Audio encoder initialized!\n");
370
371
372 /* Decoders */
373 if ( 0 == init_video_decoder(_retu) )
374 printf("Video decoder initialized!\n");
375
376 if ( 0 == init_audio_decoder(_retu, audio_channels) )
377 printf("Audio decoder initialized!\n");
378
379
380 return _retu;
381}
382
383void codec_terminate_session ( CodecState* cs )
384{
385 if ( cs->audio_encoder ) {
386 opus_encoder_destroy(cs->audio_encoder);
387 printf("Terminated encoder!\n");
388 }
389
390 if ( cs->audio_decoder ) {
391 opus_decoder_destroy(cs->audio_decoder);
392 printf("Terminated decoder!\n");
393 }
394
395 /* TODO: Terminate video */
396
397}