diff options
Diffstat (limited to 'toxav/media.c')
-rw-r--r-- | toxav/media.c | 151 |
1 files changed, 32 insertions, 119 deletions
diff --git a/toxav/media.c b/toxav/media.c index e18c1803..a327c751 100644 --- a/toxav/media.c +++ b/toxav/media.c | |||
@@ -28,13 +28,8 @@ | |||
28 | #endif /* HAVE_CONFIG_H */ | 28 | #endif /* HAVE_CONFIG_H */ |
29 | 29 | ||
30 | #include <stdio.h> | 30 | #include <stdio.h> |
31 | #include <stdlib.h> | ||
31 | #include <math.h> | 32 | #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> | 33 | #include <assert.h> |
39 | 34 | ||
40 | #include "rtp.h" | 35 | #include "rtp.h" |
@@ -206,25 +201,11 @@ int queue(struct jitter_buffer *q, RTPMessage *pk) | |||
206 | 201 | ||
207 | int init_video_decoder(CodecState *cs) | 202 | int init_video_decoder(CodecState *cs) |
208 | { | 203 | { |
209 | cs->video_decoder = avcodec_find_decoder(VIDEO_CODEC); | 204 | if (vpx_codec_dec_init_ver(&cs->v_decoder, VIDEO_CODEC_DECODER_INTERFACE, NULL, 0, VPX_DECODER_ABI_VERSION) != VPX_CODEC_OK) { |
210 | |||
211 | if (!cs->video_decoder) { | ||
212 | fprintf(stderr, "Init video_decoder failed!\n"); | 205 | fprintf(stderr, "Init video_decoder failed!\n"); |
213 | return -1; | 206 | return -1; |
214 | } | 207 | } |
215 | 208 | ||
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; | 209 | return 0; |
229 | } | 210 | } |
230 | 211 | ||
@@ -242,97 +223,32 @@ int init_audio_decoder(CodecState *cs, uint32_t audio_channels) | |||
242 | } | 223 | } |
243 | 224 | ||
244 | 225 | ||
245 | int init_video_encoder(CodecState *cs, const char* webcam, const char* video_driver, uint32_t video_bitrate) | 226 | int init_video_encoder(CodecState *cs, uint16_t width, uint16_t height, uint32_t video_bitrate) |
246 | { | 227 | { |
247 | cs->video_input_format = av_find_input_format(video_driver); | 228 | vpx_codec_enc_cfg_t cfg; |
248 | 229 | int res = vpx_codec_enc_config_default(VIDEO_CODEC_ENCODER_INTERFACE, &cfg, 0); | |
249 | if (avformat_open_input(&cs->video_format_ctx, webcam, cs->video_input_format, NULL) != 0) { | 230 | if(res) { |
250 | fprintf(stderr, "Opening video_input_format failed!\n"); | 231 | printf("Failed to get config: %s\n", vpx_codec_err_to_string(res)); |
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; | 232 | return -1; |
282 | } | 233 | } |
283 | 234 | ||
284 | cs->video_encoder = avcodec_find_encoder(VIDEO_CODEC); | 235 | cfg.rc_target_bitrate = video_bitrate; |
285 | 236 | cfg.g_w = width; | |
286 | if (!cs->video_encoder) { | 237 | cfg.g_h = height; |
287 | fprintf(stderr, "Init video_encoder failed!\n"); | 238 | if(vpx_codec_enc_init_ver(&cs->v_encoder, VIDEO_CODEC_ENCODER_INTERFACE, &cfg, 0, VPX_ENCODER_ABI_VERSION) != VPX_CODEC_OK) { |
288 | return -1; | 239 | fprintf(stderr, "Failed to initialize encoder\n"); |
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; | 240 | return -1; |
319 | } | 241 | } |
320 | |||
321 | return 0; | 242 | return 0; |
322 | } | 243 | } |
323 | 244 | ||
324 | int init_audio_encoder(CodecState *cs) | 245 | int init_audio_encoder(CodecState *cs, uint32_t audio_channels) |
325 | { | 246 | { |
326 | int err = OPUS_OK; | 247 | int err = OPUS_OK; |
327 | cs->audio_encoder = opus_encoder_create(cs->audio_sample_rate, 1, OPUS_APPLICATION_VOIP, &err); | 248 | cs->audio_encoder = opus_encoder_create(cs->audio_sample_rate, audio_channels, OPUS_APPLICATION_AUDIO, &err); |
328 | |||
329 | err = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_BITRATE(cs->audio_bitrate)); | 249 | 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)); | 250 | 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)); | 251 | |
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 | 252 | ||
337 | return err == OPUS_OK ? 0 : -1; | 253 | return err == OPUS_OK ? 0 : -1; |
338 | } | 254 | } |
@@ -342,30 +258,26 @@ CodecState* codec_init_session ( uint32_t audio_bitrate, | |||
342 | uint16_t audio_frame_duration, | 258 | uint16_t audio_frame_duration, |
343 | uint32_t audio_sample_rate, | 259 | uint32_t audio_sample_rate, |
344 | uint32_t audio_channels, | 260 | uint32_t audio_channels, |
345 | uint32_t video_bitrate, | 261 | uint16_t video_width, |
346 | const char* webcam, | 262 | uint16_t video_height, |
347 | const char* webcam_driver ) | 263 | uint32_t video_bitrate ) |
348 | { | 264 | { |
349 | CodecState* _retu = av_calloc(sizeof(CodecState), 1); | 265 | CodecState* _retu = calloc(sizeof(CodecState), 1); |
350 | assert(_retu); | 266 | assert(_retu); |
351 | 267 | ||
352 | |||
353 | avdevice_register_all(); | ||
354 | avcodec_register_all(); | ||
355 | av_register_all(); | ||
356 | |||
357 | |||
358 | _retu->audio_bitrate = audio_bitrate; | 268 | _retu->audio_bitrate = audio_bitrate; |
359 | _retu->audio_sample_rate = audio_sample_rate; | 269 | _retu->audio_sample_rate = audio_sample_rate; |
360 | 270 | ||
361 | pthread_mutex_init(&_retu->ctrl_mutex, NULL); | ||
362 | |||
363 | |||
364 | /* Encoders */ | 271 | /* Encoders */ |
365 | if ( 0 == init_video_encoder(_retu, webcam, webcam_driver, video_bitrate) ) | 272 | if (!video_width || !video_height) { |
273 | video_width = 320; | ||
274 | video_height = 240; | ||
275 | } | ||
276 | |||
277 | if ( 0 == init_video_encoder(_retu, video_width, video_height, video_bitrate) ) | ||
366 | printf("Video encoder initialized!\n"); | 278 | printf("Video encoder initialized!\n"); |
367 | 279 | ||
368 | if ( 0 == init_audio_encoder(_retu) ) | 280 | if ( 0 == init_audio_encoder(_retu, audio_channels) ) |
369 | printf("Audio encoder initialized!\n"); | 281 | printf("Audio encoder initialized!\n"); |
370 | 282 | ||
371 | 283 | ||
@@ -391,7 +303,8 @@ void codec_terminate_session ( CodecState* cs ) | |||
391 | opus_decoder_destroy(cs->audio_decoder); | 303 | opus_decoder_destroy(cs->audio_decoder); |
392 | printf("Terminated decoder!\n"); | 304 | printf("Terminated decoder!\n"); |
393 | } | 305 | } |
394 | 306 | ||
395 | /* TODO: Terminate video */ | 307 | /* TODO: Terminate video */ |
396 | 308 | vpx_codec_destroy(&cs->v_decoder); | |
309 | vpx_codec_destroy(&cs->v_encoder); | ||
397 | } | 310 | } |