Browse code

lavr: temporarily store custom matrix in AVAudioResampleContext

This allows AudioMix to be treated the same way as other conversion contexts
and removes the requirement to allocate it at the same time as the
AVAudioResampleContext.

The current matrix get/set functions are split between the public interface
and AudioMix private functions.

Justin Ruggles authored on 2012/11/30 04:53:04
Showing 6 changed files
... ...
@@ -302,27 +302,37 @@ static int mix_function_init(AudioMix *am)
302 302
     return 0;
303 303
 }
304 304
 
305
-int ff_audio_mix_init(AVAudioResampleContext *avr)
305
+AudioMix *ff_audio_mix_alloc(AVAudioResampleContext *avr)
306 306
 {
307
+    AudioMix *am;
307 308
     int ret;
308 309
 
310
+    am = av_mallocz(sizeof(*am));
311
+    if (!am)
312
+        return NULL;
313
+    am->avr = avr;
314
+
309 315
     if (avr->internal_sample_fmt != AV_SAMPLE_FMT_S16P &&
310 316
         avr->internal_sample_fmt != AV_SAMPLE_FMT_FLTP) {
311 317
         av_log(avr, AV_LOG_ERROR, "Unsupported internal format for "
312 318
                "mixing: %s\n",
313 319
                av_get_sample_fmt_name(avr->internal_sample_fmt));
314
-        return AVERROR(EINVAL);
320
+        goto error;
315 321
     }
316 322
 
323
+    am->fmt          = avr->internal_sample_fmt;
324
+    am->coeff_type   = avr->mix_coeff_type;
325
+    am->in_layout    = avr->in_channel_layout;
326
+    am->out_layout   = avr->out_channel_layout;
327
+    am->in_channels  = avr->in_channels;
328
+    am->out_channels = avr->out_channels;
329
+
317 330
     /* build matrix if the user did not already set one */
318
-    if (avr->am->matrix) {
319
-        if (avr->am->coeff_type != avr->mix_coeff_type      ||
320
-            avr->am->in_layout  != avr->in_channel_layout   ||
321
-            avr->am->out_layout != avr->out_channel_layout) {
322
-            av_log(avr, AV_LOG_ERROR,
323
-                   "Custom matrix does not match current parameters\n");
324
-            return AVERROR(EINVAL);
325
-        }
331
+    if (avr->mix_matrix) {
332
+        ret = ff_audio_mix_set_matrix(am, avr->mix_matrix, avr->in_channels);
333
+        if (ret < 0)
334
+            goto error;
335
+        av_freep(&avr->mix_matrix);
326 336
     } else {
327 337
         int i, j;
328 338
         char in_layout_name[128];
... ...
@@ -330,7 +340,7 @@ int ff_audio_mix_init(AVAudioResampleContext *avr)
330 330
         double *matrix_dbl = av_mallocz(avr->out_channels * avr->in_channels *
331 331
                                         sizeof(*matrix_dbl));
332 332
         if (!matrix_dbl)
333
-            return AVERROR(ENOMEM);
333
+            goto error;
334 334
 
335 335
         ret = avresample_build_matrix(avr->in_channel_layout,
336 336
                                       avr->out_channel_layout,
... ...
@@ -343,7 +353,7 @@ int ff_audio_mix_init(AVAudioResampleContext *avr)
343 343
                                       avr->matrix_encoding);
344 344
         if (ret < 0) {
345 345
             av_free(matrix_dbl);
346
-            return ret;
346
+            goto error;
347 347
         }
348 348
 
349 349
         av_get_channel_layout_string(in_layout_name, sizeof(in_layout_name),
... ...
@@ -360,32 +370,33 @@ int ff_audio_mix_init(AVAudioResampleContext *avr)
360 360
             av_log(avr, AV_LOG_DEBUG, "\n");
361 361
         }
362 362
 
363
-        ret = avresample_set_matrix(avr, matrix_dbl, avr->in_channels);
363
+        ret = ff_audio_mix_set_matrix(am, matrix_dbl, avr->in_channels);
364 364
         if (ret < 0) {
365 365
             av_free(matrix_dbl);
366
-            return ret;
366
+            goto error;
367 367
         }
368 368
         av_free(matrix_dbl);
369 369
     }
370 370
 
371
-    avr->am->fmt          = avr->internal_sample_fmt;
372
-    avr->am->coeff_type   = avr->mix_coeff_type;
373
-    avr->am->in_layout    = avr->in_channel_layout;
374
-    avr->am->out_layout   = avr->out_channel_layout;
375
-    avr->am->in_channels  = avr->in_channels;
376
-    avr->am->out_channels = avr->out_channels;
377
-
378
-    ret = mix_function_init(avr->am);
371
+    ret = mix_function_init(am);
379 372
     if (ret < 0)
380
-        return ret;
373
+        goto error;
381 374
 
382
-    return 0;
375
+    return am;
376
+
377
+error:
378
+    av_free(am);
379
+    return NULL;
383 380
 }
384 381
 
385
-void ff_audio_mix_close(AudioMix *am)
382
+void ff_audio_mix_free(AudioMix **am_p)
386 383
 {
387
-    if (!am)
384
+    AudioMix *am;
385
+
386
+    if (!*am_p)
388 387
         return;
388
+    am = *am_p;
389
+
389 390
     if (am->matrix) {
390 391
         av_free(am->matrix[0]);
391 392
         am->matrix = NULL;
... ...
@@ -393,6 +404,8 @@ void ff_audio_mix_close(AudioMix *am)
393 393
     memset(am->matrix_q8,  0, sizeof(am->matrix_q8 ));
394 394
     memset(am->matrix_q15, 0, sizeof(am->matrix_q15));
395 395
     memset(am->matrix_flt, 0, sizeof(am->matrix_flt));
396
+
397
+    av_freep(am_p);
396 398
 }
397 399
 
398 400
 int ff_audio_mix(AudioMix *am, AudioData *src)
... ...
@@ -424,3 +437,92 @@ int ff_audio_mix(AudioMix *am, AudioData *src)
424 424
 
425 425
     return 0;
426 426
 }
427
+
428
+int ff_audio_mix_get_matrix(AudioMix *am, double *matrix, int stride)
429
+{
430
+    int i, o;
431
+
432
+    if ( am->in_channels <= 0 ||  am->in_channels > AVRESAMPLE_MAX_CHANNELS ||
433
+        am->out_channels <= 0 || am->out_channels > AVRESAMPLE_MAX_CHANNELS) {
434
+        av_log(am, AV_LOG_ERROR, "Invalid channel counts\n");
435
+        return AVERROR(EINVAL);
436
+    }
437
+
438
+#define GET_MATRIX_CONVERT(suffix, scale)                                   \
439
+    if (!am->matrix_ ## suffix[0]) {                                        \
440
+        av_log(am, AV_LOG_ERROR, "matrix is not set\n");                    \
441
+        return AVERROR(EINVAL);                                             \
442
+    }                                                                       \
443
+    for (o = 0; o < am->out_channels; o++)                                  \
444
+        for (i = 0; i < am->in_channels; i++)                               \
445
+            matrix[o * stride + i] = am->matrix_ ## suffix[o][i] * (scale);
446
+
447
+    switch (am->coeff_type) {
448
+    case AV_MIX_COEFF_TYPE_Q8:
449
+        GET_MATRIX_CONVERT(q8, 1.0 / 256.0);
450
+        break;
451
+    case AV_MIX_COEFF_TYPE_Q15:
452
+        GET_MATRIX_CONVERT(q15, 1.0 / 32768.0);
453
+        break;
454
+    case AV_MIX_COEFF_TYPE_FLT:
455
+        GET_MATRIX_CONVERT(flt, 1.0);
456
+        break;
457
+    default:
458
+        av_log(am, AV_LOG_ERROR, "Invalid mix coeff type\n");
459
+        return AVERROR(EINVAL);
460
+    }
461
+
462
+    return 0;
463
+}
464
+
465
+int ff_audio_mix_set_matrix(AudioMix *am, const double *matrix, int stride)
466
+{
467
+    int i, o;
468
+
469
+    if ( am->in_channels <= 0 ||  am->in_channels > AVRESAMPLE_MAX_CHANNELS ||
470
+        am->out_channels <= 0 || am->out_channels > AVRESAMPLE_MAX_CHANNELS) {
471
+        av_log(am, AV_LOG_ERROR, "Invalid channel counts\n");
472
+        return AVERROR(EINVAL);
473
+    }
474
+
475
+    if (am->matrix) {
476
+        av_free(am->matrix[0]);
477
+        am->matrix = NULL;
478
+    }
479
+
480
+#define CONVERT_MATRIX(type, expr)                                          \
481
+    am->matrix_## type[0] = av_mallocz(am->out_channels * am->in_channels * \
482
+                                       sizeof(*am->matrix_## type[0]));     \
483
+    if (!am->matrix_## type[0])                                             \
484
+        return AVERROR(ENOMEM);                                             \
485
+    for (o = 0; o < am->out_channels; o++) {                                \
486
+        if (o > 0)                                                          \
487
+            am->matrix_## type[o] = am->matrix_## type[o - 1] +             \
488
+                                    am->in_channels;                        \
489
+        for (i = 0; i < am->in_channels; i++) {                             \
490
+            double v = matrix[o * stride + i];                              \
491
+            am->matrix_## type[o][i] = expr;                                \
492
+        }                                                                   \
493
+    }                                                                       \
494
+    am->matrix = (void **)am->matrix_## type;
495
+
496
+    switch (am->coeff_type) {
497
+    case AV_MIX_COEFF_TYPE_Q8:
498
+        CONVERT_MATRIX(q8, av_clip_int16(lrint(256.0 * v)))
499
+        break;
500
+    case AV_MIX_COEFF_TYPE_Q15:
501
+        CONVERT_MATRIX(q15, av_clipl_int32(llrint(32768.0 * v)))
502
+        break;
503
+    case AV_MIX_COEFF_TYPE_FLT:
504
+        CONVERT_MATRIX(flt, v)
505
+        break;
506
+    default:
507
+        av_log(am, AV_LOG_ERROR, "Invalid mix coeff type\n");
508
+        return AVERROR(EINVAL);
509
+    }
510
+
511
+    /* TODO: detect situations where we can just swap around pointers
512
+             instead of doing matrix multiplications with 0.0 and 1.0 */
513
+
514
+    return 0;
515
+}
... ...
@@ -79,28 +79,36 @@ void ff_audio_mix_set_func(AudioMix *am, enum AVSampleFormat fmt,
79 79
                            const char *descr, void *mix_func);
80 80
 
81 81
 /**
82
- * Initialize the AudioMix context in the AVAudioResampleContext.
82
+ * Allocate and initialize an AudioMix context.
83 83
  *
84 84
  * The parameters in the AVAudioResampleContext are used to initialize the
85
- * AudioMix context and set the mixing matrix.
85
+ * AudioMix context.
86 86
  *
87 87
  * @param avr  AVAudioResampleContext
88
- * @return     0 on success, negative AVERROR code on failure
88
+ * @return     newly-allocated AudioMix context.
89 89
  */
90
-int ff_audio_mix_init(AVAudioResampleContext *avr);
90
+AudioMix *ff_audio_mix_alloc(AVAudioResampleContext *avr);
91 91
 
92 92
 /**
93
- * Close an AudioMix context.
94
- *
95
- * This clears and frees the mixing matrix arrays.
93
+ * Free an AudioMix context.
96 94
  */
97
-void ff_audio_mix_close(AudioMix *am);
95
+void ff_audio_mix_free(AudioMix **am);
98 96
 
99 97
 /**
100 98
  * Apply channel mixing to audio data using the current mixing matrix.
101 99
  */
102 100
 int ff_audio_mix(AudioMix *am, AudioData *src);
103 101
 
102
+/**
103
+ * Get the current mixing matrix.
104
+ */
105
+int ff_audio_mix_get_matrix(AudioMix *am, double *matrix, int stride);
106
+
107
+/**
108
+ * Set the current mixing matrix.
109
+ */
110
+int ff_audio_mix_set_matrix(AudioMix *am, const double *matrix, int stride);
111
+
104 112
 /* arch-specific initialization functions */
105 113
 
106 114
 void ff_audio_mix_init_x86(AudioMix *am);
... ...
@@ -287,115 +287,3 @@ int avresample_build_matrix(uint64_t in_layout, uint64_t out_layout,
287 287
 
288 288
     return 0;
289 289
 }
290
-
291
-int avresample_get_matrix(AVAudioResampleContext *avr, double *matrix,
292
-                          int stride)
293
-{
294
-    int in_channels, out_channels, i, o;
295
-
296
-    in_channels  = av_get_channel_layout_nb_channels(avr->in_channel_layout);
297
-    out_channels = av_get_channel_layout_nb_channels(avr->out_channel_layout);
298
-
299
-    if ( in_channels <= 0 ||  in_channels > AVRESAMPLE_MAX_CHANNELS ||
300
-        out_channels <= 0 || out_channels > AVRESAMPLE_MAX_CHANNELS) {
301
-        av_log(avr, AV_LOG_ERROR, "Invalid channel layouts\n");
302
-        return AVERROR(EINVAL);
303
-    }
304
-
305
-    switch (avr->mix_coeff_type) {
306
-    case AV_MIX_COEFF_TYPE_Q8:
307
-        if (!avr->am->matrix_q8[0]) {
308
-            av_log(avr, AV_LOG_ERROR, "matrix is not set\n");
309
-            return AVERROR(EINVAL);
310
-        }
311
-        for (o = 0; o < out_channels; o++)
312
-            for (i = 0; i < in_channels; i++)
313
-                matrix[o * stride + i] = avr->am->matrix_q8[o][i] / 256.0;
314
-        break;
315
-    case AV_MIX_COEFF_TYPE_Q15:
316
-        if (!avr->am->matrix_q15[0]) {
317
-            av_log(avr, AV_LOG_ERROR, "matrix is not set\n");
318
-            return AVERROR(EINVAL);
319
-        }
320
-        for (o = 0; o < out_channels; o++)
321
-            for (i = 0; i < in_channels; i++)
322
-                matrix[o * stride + i] = avr->am->matrix_q15[o][i] / 32768.0;
323
-        break;
324
-    case AV_MIX_COEFF_TYPE_FLT:
325
-        if (!avr->am->matrix_flt[0]) {
326
-            av_log(avr, AV_LOG_ERROR, "matrix is not set\n");
327
-            return AVERROR(EINVAL);
328
-        }
329
-        for (o = 0; o < out_channels; o++)
330
-            for (i = 0; i < in_channels; i++)
331
-                matrix[o * stride + i] = avr->am->matrix_flt[o][i];
332
-        break;
333
-    default:
334
-        av_log(avr, AV_LOG_ERROR, "Invalid mix coeff type\n");
335
-        return AVERROR(EINVAL);
336
-    }
337
-
338
-    return 0;
339
-}
340
-
341
-int avresample_set_matrix(AVAudioResampleContext *avr, const double *matrix,
342
-                          int stride)
343
-{
344
-    int in_channels, out_channels, i, o;
345
-
346
-    in_channels  = av_get_channel_layout_nb_channels(avr->in_channel_layout);
347
-    out_channels = av_get_channel_layout_nb_channels(avr->out_channel_layout);
348
-
349
-    if ( in_channels <= 0 ||  in_channels > AVRESAMPLE_MAX_CHANNELS ||
350
-        out_channels <= 0 || out_channels > AVRESAMPLE_MAX_CHANNELS) {
351
-        av_log(avr, AV_LOG_ERROR, "Invalid channel layouts\n");
352
-        return AVERROR(EINVAL);
353
-    }
354
-
355
-    if (avr->am->matrix) {
356
-        av_free(avr->am->matrix[0]);
357
-        avr->am->matrix = NULL;
358
-    }
359
-
360
-#define CONVERT_MATRIX(type, expr)                                          \
361
-    avr->am->matrix_## type[0] = av_mallocz(out_channels * in_channels *    \
362
-                                            sizeof(*avr->am->matrix_## type[0])); \
363
-    if (!avr->am->matrix_## type[0])                                        \
364
-        return AVERROR(ENOMEM);                                             \
365
-    for (o = 0; o < out_channels; o++) {                                    \
366
-        if (o > 0)                                                          \
367
-            avr->am->matrix_## type[o] = avr->am->matrix_## type[o - 1] +   \
368
-                                         in_channels;                       \
369
-        for (i = 0; i < in_channels; i++) {                                 \
370
-            double v = matrix[o * stride + i];                              \
371
-            avr->am->matrix_## type[o][i] = expr;                           \
372
-        }                                                                   \
373
-    }                                                                       \
374
-    avr->am->matrix = (void **)avr->am->matrix_## type;
375
-
376
-    switch (avr->mix_coeff_type) {
377
-    case AV_MIX_COEFF_TYPE_Q8:
378
-        CONVERT_MATRIX(q8, av_clip_int16(lrint(256.0 * v)))
379
-        break;
380
-    case AV_MIX_COEFF_TYPE_Q15:
381
-        CONVERT_MATRIX(q15, av_clipl_int32(llrint(32768.0 * v)))
382
-        break;
383
-    case AV_MIX_COEFF_TYPE_FLT:
384
-        CONVERT_MATRIX(flt, v)
385
-        break;
386
-    default:
387
-        av_log(avr, AV_LOG_ERROR, "Invalid mix coeff type\n");
388
-        return AVERROR(EINVAL);
389
-    }
390
-
391
-    /* TODO: detect situations where we can just swap around pointers
392
-             instead of doing matrix multiplications with 0.0 and 1.0 */
393
-
394
-    /* set AudioMix params */
395
-    avr->am->in_layout    = avr->in_channel_layout;
396
-    avr->am->out_layout   = avr->out_channel_layout;
397
-    avr->am->in_channels  = in_channels;
398
-    avr->am->out_channels = out_channels;
399
-
400
-    return 0;
401
-}
... ...
@@ -74,6 +74,12 @@ struct AVAudioResampleContext {
74 74
     ResampleContext *resample;  /**< resampling context                      */
75 75
     AudioMix *am;               /**< channel mixing context                  */
76 76
     enum AVMatrixEncoding matrix_encoding;      /**< matrixed stereo encoding */
77
+
78
+    /**
79
+     * mix matrix
80
+     * only used if avresample_set_matrix() is called before avresample_open()
81
+     */
82
+    double *mix_matrix;
77 83
 };
78 84
 
79 85
 #endif /* AVRESAMPLE_INTERNAL_H */
... ...
@@ -84,13 +84,6 @@ AVAudioResampleContext *avresample_alloc_context(void)
84 84
     avr->av_class = &av_resample_context_class;
85 85
     av_opt_set_defaults(avr);
86 86
 
87
-    avr->am = av_mallocz(sizeof(*avr->am));
88
-    if (!avr->am) {
89
-        av_free(avr);
90
-        return NULL;
91
-    }
92
-    avr->am->avr = avr;
93
-
94 87
     return avr;
95 88
 }
96 89
 
... ...
@@ -169,9 +169,11 @@ int avresample_open(AVAudioResampleContext *avr)
169 169
         }
170 170
     }
171 171
     if (avr->mixing_needed) {
172
-        ret = ff_audio_mix_init(avr);
173
-        if (ret < 0)
172
+        avr->am = ff_audio_mix_alloc(avr);
173
+        if (!avr->am) {
174
+            ret = AVERROR(ENOMEM);
174 175
             goto error;
176
+        }
175 177
     }
176 178
 
177 179
     return 0;
... ...
@@ -191,8 +193,8 @@ void avresample_close(AVAudioResampleContext *avr)
191 191
     av_freep(&avr->ac_in);
192 192
     av_freep(&avr->ac_out);
193 193
     ff_audio_resample_free(&avr->resample);
194
-    ff_audio_mix_close(avr->am);
195
-    return;
194
+    ff_audio_mix_free(&avr->am);
195
+    av_freep(&avr->mix_matrix);
196 196
 }
197 197
 
198 198
 void avresample_free(AVAudioResampleContext **avr)
... ...
@@ -200,7 +202,6 @@ void avresample_free(AVAudioResampleContext **avr)
200 200
     if (!*avr)
201 201
         return;
202 202
     avresample_close(*avr);
203
-    av_freep(&(*avr)->am);
204 203
     av_opt_free(*avr);
205 204
     av_freep(avr);
206 205
 }
... ...
@@ -404,6 +405,66 @@ int attribute_align_arg avresample_convert(AVAudioResampleContext *avr,
404 404
                                   current_buffer);
405 405
 }
406 406
 
407
+int avresample_get_matrix(AVAudioResampleContext *avr, double *matrix,
408
+                          int stride)
409
+{
410
+    int in_channels, out_channels, i, o;
411
+
412
+    if (avr->am)
413
+        return ff_audio_mix_get_matrix(avr->am, matrix, stride);
414
+
415
+    in_channels  = av_get_channel_layout_nb_channels(avr->in_channel_layout);
416
+    out_channels = av_get_channel_layout_nb_channels(avr->out_channel_layout);
417
+
418
+    if ( in_channels <= 0 ||  in_channels > AVRESAMPLE_MAX_CHANNELS ||
419
+        out_channels <= 0 || out_channels > AVRESAMPLE_MAX_CHANNELS) {
420
+        av_log(avr, AV_LOG_ERROR, "Invalid channel layouts\n");
421
+        return AVERROR(EINVAL);
422
+    }
423
+
424
+    if (!avr->mix_matrix) {
425
+        av_log(avr, AV_LOG_ERROR, "matrix is not set\n");
426
+        return AVERROR(EINVAL);
427
+    }
428
+
429
+    for (o = 0; o < out_channels; o++)
430
+        for (i = 0; i < in_channels; i++)
431
+            matrix[o * stride + i] = avr->mix_matrix[o * in_channels + i];
432
+
433
+    return 0;
434
+}
435
+
436
+int avresample_set_matrix(AVAudioResampleContext *avr, const double *matrix,
437
+                          int stride)
438
+{
439
+    int in_channels, out_channels, i, o;
440
+
441
+    if (avr->am)
442
+        return ff_audio_mix_set_matrix(avr->am, matrix, stride);
443
+
444
+    in_channels  = av_get_channel_layout_nb_channels(avr->in_channel_layout);
445
+    out_channels = av_get_channel_layout_nb_channels(avr->out_channel_layout);
446
+
447
+    if ( in_channels <= 0 ||  in_channels > AVRESAMPLE_MAX_CHANNELS ||
448
+        out_channels <= 0 || out_channels > AVRESAMPLE_MAX_CHANNELS) {
449
+        av_log(avr, AV_LOG_ERROR, "Invalid channel layouts\n");
450
+        return AVERROR(EINVAL);
451
+    }
452
+
453
+    if (avr->mix_matrix)
454
+        av_freep(&avr->mix_matrix);
455
+    avr->mix_matrix = av_malloc(in_channels * out_channels *
456
+                                sizeof(*avr->mix_matrix));
457
+    if (!avr->mix_matrix)
458
+        return AVERROR(ENOMEM);
459
+
460
+    for (o = 0; o < out_channels; o++)
461
+        for (i = 0; i < in_channels; i++)
462
+            avr->mix_matrix[o * in_channels + i] = matrix[o * stride + i];
463
+
464
+    return 0;
465
+}
466
+
407 467
 int avresample_available(AVAudioResampleContext *avr)
408 468
 {
409 469
     return av_audio_fifo_size(avr->out_fifo);