Coverage Report

Created: 2026-06-25 06:46

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/mpv/audio/aframe.c
Line
Count
Source
1
/*
2
 * This file is part of mpv.
3
 *
4
 * mpv is free software; you can redistribute it and/or
5
 * modify it under the terms of the GNU Lesser General Public
6
 * License as published by the Free Software Foundation; either
7
 * version 2.1 of the License, or (at your option) any later version.
8
 *
9
 * mpv is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 * GNU Lesser General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU Lesser General Public
15
 * License along with mpv.  If not, see <http://www.gnu.org/licenses/>.
16
 */
17
18
#include <libavutil/frame.h>
19
#include <libavutil/mem.h>
20
21
#include "config.h"
22
23
#include "common/common.h"
24
25
#include "chmap.h"
26
#include "chmap_avchannel.h"
27
#include "fmt-conversion.h"
28
#include "format.h"
29
#include "aframe.h"
30
31
struct mp_aframe {
32
    AVFrame *av_frame;
33
    // We support channel layouts different from AVFrame channel masks
34
    struct mp_chmap chmap;
35
    // We support spdif formats, which are allocated as AV_SAMPLE_FMT_S16.
36
    int format;
37
    double pts;
38
    double speed;
39
};
40
41
struct avframe_opaque {
42
    double speed;
43
};
44
45
static void free_frame(void *ptr)
46
5.41M
{
47
5.41M
    struct mp_aframe *frame = ptr;
48
5.41M
    av_frame_free(&frame->av_frame);
49
5.41M
}
50
51
struct mp_aframe *mp_aframe_create(void)
52
5.41M
{
53
5.41M
    struct mp_aframe *frame = talloc_zero(NULL, struct mp_aframe);
54
5.41M
    frame->av_frame = av_frame_alloc();
55
5.41M
    MP_HANDLE_OOM(frame->av_frame);
56
5.41M
    talloc_set_destructor(frame, free_frame);
57
5.41M
    mp_aframe_reset(frame);
58
5.41M
    return frame;
59
5.41M
}
60
61
struct mp_aframe *mp_aframe_new_ref(struct mp_aframe *frame)
62
588k
{
63
588k
    if (!frame)
64
0
        return NULL;
65
66
588k
    struct mp_aframe *dst = mp_aframe_create();
67
68
588k
    dst->chmap = frame->chmap;
69
588k
    dst->format = frame->format;
70
588k
    dst->pts = frame->pts;
71
588k
    dst->speed = frame->speed;
72
73
588k
    if (mp_aframe_is_allocated(frame)) {
74
5.88k
        if (av_frame_ref(dst->av_frame, frame->av_frame) < 0)
75
0
            abort();
76
582k
    } else {
77
        // av_frame_ref() would fail.
78
582k
        mp_aframe_config_copy(dst, frame);
79
582k
    }
80
81
588k
    return dst;
82
588k
}
83
84
// Revert to state after mp_aframe_create().
85
void mp_aframe_reset(struct mp_aframe *frame)
86
7.47M
{
87
7.47M
    av_frame_unref(frame->av_frame);
88
7.47M
    frame->chmap.num = 0;
89
7.47M
    frame->format = 0;
90
7.47M
    frame->pts = MP_NOPTS_VALUE;
91
7.47M
    frame->speed = 1.0;
92
7.47M
}
93
94
// Remove all actual audio data and leave only the metadata.
95
void mp_aframe_unref_data(struct mp_aframe *frame)
96
0
{
97
    // In a fucked up way, this is less complex than just unreffing the data.
98
0
    struct mp_aframe *tmp = mp_aframe_create();
99
0
    MPSWAP(struct mp_aframe, *tmp, *frame);
100
0
    mp_aframe_reset(frame);
101
0
    mp_aframe_config_copy(frame, tmp);
102
0
    talloc_free(tmp);
103
0
}
104
105
// Allocate this much data. Returns false for failure (data already allocated,
106
// invalid sample count or format, allocation failures).
107
// Normally you're supposed to use a frame pool and mp_aframe_pool_allocate().
108
bool mp_aframe_alloc_data(struct mp_aframe *frame, int samples)
109
27.9k
{
110
27.9k
    if (mp_aframe_is_allocated(frame))
111
0
        return false;
112
27.9k
    struct mp_aframe_pool *p = mp_aframe_pool_create(NULL);
113
27.9k
    int r = mp_aframe_pool_allocate(p, frame, samples);
114
27.9k
    talloc_free(p);
115
27.9k
    return r >= 0;
116
27.9k
}
117
118
// Return a new reference to the data in av_frame. av_frame itself is not
119
// touched. Returns NULL if not representable, or if input is NULL.
120
// Does not copy the timestamps.
121
struct mp_aframe *mp_aframe_from_avframe(struct AVFrame *av_frame)
122
2.85M
{
123
2.85M
    if (!av_frame || av_frame->width > 0 || av_frame->height > 0)
124
0
        return NULL;
125
126
2.85M
    if (!av_channel_layout_check(&av_frame->ch_layout))
127
0
        return NULL;
128
129
2.85M
    struct mp_chmap converted_map = { 0 };
130
2.85M
    if (!mp_chmap_from_av_layout(&converted_map, &av_frame->ch_layout)) {
131
8.17k
        return NULL;
132
8.17k
    }
133
134
2.84M
    int format = af_from_avformat(av_frame->format);
135
2.84M
    if (!format && av_frame->format != AV_SAMPLE_FMT_NONE)
136
0
        return NULL;
137
138
2.84M
    struct mp_aframe *frame = mp_aframe_create();
139
140
    // This also takes care of forcing refcounting.
141
2.84M
    if (av_frame_ref(frame->av_frame, av_frame) < 0)
142
0
        abort();
143
144
2.84M
    frame->format = format;
145
2.84M
    frame->chmap = converted_map;
146
147
2.84M
    if (av_frame->opaque_ref) {
148
0
        struct avframe_opaque *op = (void *)av_frame->opaque_ref->data;
149
0
        frame->speed = op->speed;
150
0
    }
151
152
2.84M
    return frame;
153
2.84M
}
154
155
// Return a new reference to the data in frame. Returns NULL is not
156
// representable (), or if input is NULL.
157
// Does not copy the timestamps.
158
struct AVFrame *mp_aframe_to_avframe(struct mp_aframe *frame)
159
0
{
160
0
    if (!frame)
161
0
        return NULL;
162
163
0
    if (af_to_avformat(frame->format) != frame->av_frame->format)
164
0
        return NULL;
165
166
0
    if (!mp_chmap_is_lavc(&frame->chmap))
167
0
        return NULL;
168
169
0
    if (!frame->av_frame->opaque_ref && frame->speed != 1.0) {
170
0
        frame->av_frame->opaque_ref =
171
0
            av_buffer_alloc(sizeof(struct avframe_opaque));
172
0
        if (!frame->av_frame->opaque_ref)
173
0
            return NULL;
174
175
0
        struct avframe_opaque *op = (void *)frame->av_frame->opaque_ref->data;
176
0
        op->speed = frame->speed;
177
0
    }
178
179
0
    return av_frame_clone(frame->av_frame);
180
0
}
181
182
struct AVFrame *mp_aframe_to_avframe_and_unref(struct mp_aframe *frame)
183
0
{
184
0
    AVFrame *av = mp_aframe_to_avframe(frame);
185
0
    talloc_free(frame);
186
0
    return av;
187
0
}
188
189
// You must not use this.
190
struct AVFrame *mp_aframe_get_raw_avframe(struct mp_aframe *frame)
191
2.41M
{
192
2.41M
    return frame->av_frame;
193
2.41M
}
194
195
// Return whether it has associated audio data. (If not, metadata only.)
196
bool mp_aframe_is_allocated(struct mp_aframe *frame)
197
23.4M
{
198
23.4M
    return frame->av_frame->buf[0] || frame->av_frame->extended_data[0];
199
23.4M
}
200
201
// Clear dst, and then copy the configuration to it.
202
void mp_aframe_config_copy(struct mp_aframe *dst, struct mp_aframe *src)
203
2.03M
{
204
2.03M
    mp_aframe_reset(dst);
205
206
2.03M
    dst->chmap = src->chmap;
207
2.03M
    dst->format = src->format;
208
209
2.03M
    mp_aframe_copy_attributes(dst, src);
210
211
2.03M
    dst->av_frame->sample_rate = src->av_frame->sample_rate;
212
2.03M
    dst->av_frame->format = src->av_frame->format;
213
214
2.03M
    if (av_channel_layout_copy(&dst->av_frame->ch_layout, &src->av_frame->ch_layout) < 0)
215
0
        abort();
216
2.03M
}
217
218
// Copy "soft" attributes from src to dst, excluding things which affect
219
// frame allocation and organization.
220
void mp_aframe_copy_attributes(struct mp_aframe *dst, struct mp_aframe *src)
221
3.25M
{
222
3.25M
    dst->pts = src->pts;
223
3.25M
    dst->speed = src->speed;
224
225
3.25M
    int rate = dst->av_frame->sample_rate;
226
227
3.25M
    if (av_frame_copy_props(dst->av_frame, src->av_frame) < 0)
228
0
        abort();
229
230
3.25M
    dst->av_frame->sample_rate = rate;
231
3.25M
}
232
233
// Return whether a and b use the same physical audio format. Extra metadata
234
// such as PTS, per-frame signalling, and AVFrame side data is not compared.
235
bool mp_aframe_config_equals(struct mp_aframe *a, struct mp_aframe *b)
236
14.3M
{
237
14.3M
    struct mp_chmap ca = {0}, cb = {0};
238
14.3M
    mp_aframe_get_chmap(a, &ca);
239
14.3M
    mp_aframe_get_chmap(b, &cb);
240
14.3M
    return mp_chmap_equals(&ca, &cb) &&
241
13.7M
           mp_aframe_get_rate(a) == mp_aframe_get_rate(b) &&
242
13.7M
           mp_aframe_get_format(a) == mp_aframe_get_format(b);
243
14.3M
}
244
245
// Return whether all required format fields have been set.
246
bool mp_aframe_config_is_valid(struct mp_aframe *frame)
247
30.4k
{
248
30.4k
    return frame->format && frame->chmap.num && frame->av_frame->sample_rate;
249
30.4k
}
250
251
// Return the pointer to the first sample for each plane. The pointers stay
252
// valid until the next call that mutates frame somehow. You must not write to
253
// the audio data. Returns NULL if no frame allocated.
254
uint8_t **mp_aframe_get_data_ro(struct mp_aframe *frame)
255
5.31M
{
256
5.31M
    return mp_aframe_is_allocated(frame) ? frame->av_frame->extended_data : NULL;
257
5.31M
}
258
259
// Like mp_aframe_get_data_ro(), but you can write to the audio data.
260
// Additionally, it will return NULL if copy-on-write fails.
261
uint8_t **mp_aframe_get_data_rw(struct mp_aframe *frame)
262
13.7M
{
263
13.7M
    if (!mp_aframe_is_allocated(frame))
264
0
        return NULL;
265
13.7M
    if (av_frame_make_writable(frame->av_frame) < 0)
266
0
        return NULL;
267
13.7M
    return frame->av_frame->extended_data;
268
13.7M
}
269
270
int mp_aframe_get_format(struct mp_aframe *frame)
271
68.8M
{
272
68.8M
    return frame->format;
273
68.8M
}
274
275
bool mp_aframe_get_chmap(struct mp_aframe *frame, struct mp_chmap *out)
276
33.6M
{
277
33.6M
    if (!mp_chmap_is_valid(&frame->chmap))
278
108k
        return false;
279
33.5M
    *out = frame->chmap;
280
33.5M
    return true;
281
33.6M
}
282
283
int mp_aframe_get_channels(struct mp_aframe *frame)
284
17.4M
{
285
17.4M
    return frame->chmap.num;
286
17.4M
}
287
288
int mp_aframe_get_rate(struct mp_aframe *frame)
289
66.2M
{
290
66.2M
    return frame->av_frame->sample_rate;
291
66.2M
}
292
293
int mp_aframe_get_size(struct mp_aframe *frame)
294
52.3M
{
295
52.3M
    return frame->av_frame->nb_samples;
296
52.3M
}
297
298
double mp_aframe_get_pts(struct mp_aframe *frame)
299
33.7M
{
300
33.7M
    return frame->pts;
301
33.7M
}
302
303
bool mp_aframe_set_format(struct mp_aframe *frame, int format)
304
50.5k
{
305
50.5k
    if (mp_aframe_is_allocated(frame))
306
0
        return false;
307
50.5k
    enum AVSampleFormat av_format = af_to_avformat(format);
308
50.5k
    if (av_format == AV_SAMPLE_FMT_NONE && format) {
309
0
        if (!af_fmt_is_spdif(format))
310
0
            return false;
311
0
        av_format = AV_SAMPLE_FMT_S16;
312
0
    }
313
50.5k
    frame->format = format;
314
50.5k
    frame->av_frame->format = av_format;
315
50.5k
    return true;
316
50.5k
}
317
318
bool mp_aframe_set_chmap(struct mp_aframe *frame, struct mp_chmap *in)
319
736k
{
320
736k
    if (!mp_chmap_is_valid(in) && !mp_chmap_is_empty(in))
321
0
        return false;
322
736k
    if (mp_aframe_is_allocated(frame) && in->num != frame->chmap.num)
323
336
        return false;
324
325
736k
    frame->chmap = *in;
326
736k
    mp_chmap_to_av_layout(&frame->av_frame->ch_layout, in);
327
328
736k
    return true;
329
736k
}
330
331
bool mp_aframe_set_rate(struct mp_aframe *frame, int rate)
332
201k
{
333
201k
    if (rate < 1 || rate > 10000000)
334
481
        return false;
335
200k
    frame->av_frame->sample_rate = rate;
336
200k
    return true;
337
201k
}
338
339
bool mp_aframe_set_size(struct mp_aframe *frame, int samples)
340
1.23M
{
341
1.23M
    if (!mp_aframe_is_allocated(frame) || mp_aframe_get_size(frame) < samples)
342
0
        return false;
343
1.23M
    frame->av_frame->nb_samples = MPMAX(samples, 0);
344
1.23M
    return true;
345
1.23M
}
346
347
void mp_aframe_set_pts(struct mp_aframe *frame, double pts)
348
6.92M
{
349
6.92M
    frame->pts = pts;
350
6.92M
}
351
352
// Set a speed factor. This is multiplied with the sample rate to get the
353
// "effective" samplerate (mp_aframe_get_effective_rate()), which will be used
354
// to do PTS calculations. If speed!=1.0, the PTS values always refer to the
355
// original PTS (before changing speed), and if you want reasonably continuous
356
// PTS between frames, you need to use the effective samplerate.
357
void mp_aframe_set_speed(struct mp_aframe *frame, double factor)
358
0
{
359
0
    frame->speed = factor;
360
0
}
361
362
// Adjust current speed factor.
363
void mp_aframe_mul_speed(struct mp_aframe *frame, double factor)
364
1.23M
{
365
1.23M
    frame->speed *= factor;
366
1.23M
}
367
368
double mp_aframe_get_speed(struct mp_aframe *frame)
369
678k
{
370
678k
    return frame->speed;
371
678k
}
372
373
// Matters for speed changed frames (such as a frame which has been resampled
374
// to play at a different speed).
375
// Return the sample rate at which the frame would have to be played to result
376
// in the same duration as the original frame before the speed change.
377
// This is used for A/V sync.
378
double mp_aframe_get_effective_rate(struct mp_aframe *frame)
379
30.9M
{
380
30.9M
    return mp_aframe_get_rate(frame) / frame->speed;
381
30.9M
}
382
383
// Return number of data pointers.
384
int mp_aframe_get_planes(struct mp_aframe *frame)
385
17.6M
{
386
17.6M
    return af_fmt_is_planar(mp_aframe_get_format(frame))
387
17.6M
           ? mp_aframe_get_channels(frame) : 1;
388
17.6M
}
389
390
// Return number of bytes between 2 consecutive samples on the same plane.
391
size_t mp_aframe_get_sstride(struct mp_aframe *frame)
392
14.9M
{
393
14.9M
    int format = mp_aframe_get_format(frame);
394
14.9M
    return af_fmt_to_bytes(format) *
395
14.9M
           (af_fmt_is_planar(format) ? 1 : mp_aframe_get_channels(frame));
396
14.9M
}
397
398
// Return total number of samples on each plane.
399
int mp_aframe_get_total_plane_samples(struct mp_aframe *frame)
400
1.73M
{
401
1.73M
    return frame->av_frame->nb_samples *
402
1.73M
           (af_fmt_is_planar(mp_aframe_get_format(frame))
403
1.73M
            ? 1 : mp_aframe_get_channels(frame));
404
1.73M
}
405
406
char *mp_aframe_format_str_buf(char *buf, size_t buf_size, struct mp_aframe *fmt)
407
124k
{
408
124k
    char ch[128];
409
124k
    mp_chmap_to_str_buf(ch, sizeof(ch), &fmt->chmap);
410
124k
    char *hr_ch = mp_chmap_to_str_hr(&fmt->chmap);
411
124k
    if (strcmp(hr_ch, ch) != 0)
412
3.85k
        mp_snprintf_cat(ch, sizeof(ch), " (%s)", hr_ch);
413
124k
    snprintf(buf, buf_size, "%dHz %s %dch %s", fmt->av_frame->sample_rate,
414
124k
             ch, fmt->chmap.num, af_fmt_to_str(fmt->format));
415
124k
    return buf;
416
124k
}
417
418
// Set data to the audio after the given number of samples (i.e. slice it).
419
void mp_aframe_skip_samples(struct mp_aframe *f, int samples)
420
5.99M
{
421
5.99M
    mp_assert(samples >= 0 && samples <= mp_aframe_get_size(f));
422
423
5.99M
    if (av_frame_make_writable(f->av_frame) < 0)
424
0
        return; // go complain to ffmpeg
425
426
5.99M
    int num_planes = mp_aframe_get_planes(f);
427
5.99M
    size_t sstride = mp_aframe_get_sstride(f);
428
12.3M
    for (int n = 0; n < num_planes; n++) {
429
6.33M
        memmove(f->av_frame->extended_data[n],
430
6.33M
                f->av_frame->extended_data[n] + samples * sstride,
431
6.33M
                (f->av_frame->nb_samples - samples) * sstride);
432
6.33M
    }
433
434
5.99M
    f->av_frame->nb_samples -= samples;
435
436
5.99M
    if (f->pts != MP_NOPTS_VALUE)
437
5.99M
        f->pts += samples / mp_aframe_get_effective_rate(f);
438
5.99M
}
439
440
// sanitize a floating point sample value
441
818M
#define sanitizef(f) do {       \
442
817M
    if (!isnormal(f))           \
443
817M
        (f) = 0;                \
444
817M
} while (0)
445
446
void mp_aframe_sanitize_float(struct mp_aframe *mpa)
447
2.84M
{
448
2.84M
    int format = af_fmt_from_planar(mp_aframe_get_format(mpa));
449
2.84M
    if (format != AF_FORMAT_FLOAT && format != AF_FORMAT_DOUBLE)
450
1.40M
        return;
451
1.44M
    int num_planes = mp_aframe_get_planes(mpa);
452
1.44M
    uint8_t **planes = mp_aframe_get_data_rw(mpa);
453
1.44M
    if (!planes)
454
0
        return;
455
3.18M
    for (int p = 0; p < num_planes; p++) {
456
1.73M
        void *ptr = planes[p];
457
1.73M
        int total = mp_aframe_get_total_plane_samples(mpa);
458
1.73M
        switch (format) {
459
1.73M
        case AF_FORMAT_FLOAT:
460
818M
            for (int s = 0; s < total; s++)
461
817M
                sanitizef(((float *)ptr)[s]);
462
1.73M
            break;
463
1
        case AF_FORMAT_DOUBLE:
464
2
            for (int s = 0; s < total; s++)
465
1
                sanitizef(((double *)ptr)[s]);
466
1
            break;
467
1.73M
        }
468
1.73M
    }
469
1.44M
}
470
471
// Return the timestamp of the sample just after the end of this frame.
472
double mp_aframe_end_pts(struct mp_aframe *f)
473
13.5M
{
474
13.5M
    double rate = mp_aframe_get_effective_rate(f);
475
13.5M
    if (f->pts == MP_NOPTS_VALUE || rate <= 0)
476
1.95k
        return MP_NOPTS_VALUE;
477
13.5M
    return f->pts + f->av_frame->nb_samples / rate;
478
13.5M
}
479
480
// Return the duration in seconds of the frame (0 if invalid).
481
double mp_aframe_duration(struct mp_aframe *f)
482
4.22M
{
483
4.22M
    double rate = mp_aframe_get_effective_rate(f);
484
4.22M
    if (rate <= 0)
485
0
        return 0;
486
4.22M
    return f->av_frame->nb_samples / rate;
487
4.22M
}
488
489
// Clip the given frame to the given timestamp range. Adjusts the frame size
490
// and timestamp.
491
// Refuses to change spdif frames.
492
void mp_aframe_clip_timestamps(struct mp_aframe *f, double start, double end)
493
6.44M
{
494
6.44M
    double f_end = mp_aframe_end_pts(f);
495
6.44M
    double rate = mp_aframe_get_effective_rate(f);
496
6.44M
    if (f_end == MP_NOPTS_VALUE)
497
978
        return;
498
6.44M
    if (end != MP_NOPTS_VALUE) {
499
111k
        if (f_end >= end) {
500
209
            if (f->pts >= end) {
501
6
                f->av_frame->nb_samples = 0;
502
203
            } else {
503
203
                if (af_fmt_is_spdif(mp_aframe_get_format(f)))
504
0
                    return;
505
203
                int new = (end - f->pts) * rate;
506
203
                f->av_frame->nb_samples = MPCLAMP(new, 0, f->av_frame->nb_samples);
507
203
            }
508
209
        }
509
111k
    }
510
6.44M
    if (start != MP_NOPTS_VALUE) {
511
519k
        if (f->pts < start) {
512
4.21k
            if (f_end <= start) {
513
3.42k
                f->av_frame->nb_samples = 0;
514
3.42k
                f->pts = f_end;
515
3.42k
            } else {
516
791
                if (af_fmt_is_spdif(mp_aframe_get_format(f)))
517
0
                    return;
518
791
                int skip = (start - f->pts) * rate;
519
791
                skip = MPCLAMP(skip, 0, f->av_frame->nb_samples);
520
791
                mp_aframe_skip_samples(f, skip);
521
791
            }
522
4.21k
        }
523
519k
    }
524
6.44M
}
525
526
bool mp_aframe_copy_samples(struct mp_aframe *dst, int dst_offset,
527
                            struct mp_aframe *src, int src_offset,
528
                            int samples)
529
0
{
530
0
    if (!mp_aframe_config_equals(dst, src))
531
0
        return false;
532
533
0
    if (mp_aframe_get_size(dst) < dst_offset + samples ||
534
0
        mp_aframe_get_size(src) < src_offset + samples)
535
0
        return false;
536
537
0
    uint8_t **s = mp_aframe_get_data_ro(src);
538
0
    uint8_t **d = mp_aframe_get_data_rw(dst);
539
0
    if (!s || !d)
540
0
        return false;
541
542
0
    int planes = mp_aframe_get_planes(dst);
543
0
    size_t sstride = mp_aframe_get_sstride(dst);
544
545
0
    for (int n = 0; n < planes; n++) {
546
0
        memcpy(d[n] + dst_offset * sstride, s[n] + src_offset * sstride,
547
0
               samples * sstride);
548
0
    }
549
550
0
    return true;
551
0
}
552
553
bool mp_aframe_set_silence(struct mp_aframe *f, int offset, int samples)
554
0
{
555
0
    if (mp_aframe_get_size(f) < offset + samples)
556
0
        return false;
557
558
0
    int format = mp_aframe_get_format(f);
559
0
    uint8_t **d = mp_aframe_get_data_rw(f);
560
0
    if (!d)
561
0
        return false;
562
563
0
    int planes = mp_aframe_get_planes(f);
564
0
    size_t sstride = mp_aframe_get_sstride(f);
565
566
0
    for (int n = 0; n < planes; n++)
567
0
        af_fill_silence(d[n] + offset * sstride, samples * sstride, format);
568
569
0
    return true;
570
0
}
571
572
bool mp_aframe_reverse(struct mp_aframe *f)
573
1
{
574
1
    int format = mp_aframe_get_format(f);
575
1
    int bps = af_fmt_to_bytes(format);
576
1
    if (!af_fmt_is_pcm(format) || bps > 16)
577
0
        return false;
578
579
1
    uint8_t **d = mp_aframe_get_data_rw(f);
580
1
    if (!d)
581
0
        return false;
582
583
1
    int planes = mp_aframe_get_planes(f);
584
1
    int samples = mp_aframe_get_size(f);
585
1
    int channels = mp_aframe_get_channels(f);
586
1
    size_t sstride = mp_aframe_get_sstride(f);
587
588
1
    int plane_samples = channels;
589
1
    if (af_fmt_is_planar(format))
590
0
        plane_samples = 1;
591
592
2
    for (int p = 0; p < planes; p++) {
593
513
        for (int n = 0; n < samples / 2; n++) {
594
512
            int s1_offset = n * sstride;
595
512
            int s2_offset = (samples - 1 - n) * sstride;
596
1.02k
            for (int c = 0; c < plane_samples; c++) {
597
                // Nobody said it'd be fast.
598
512
                char tmp[16];
599
512
                uint8_t *s1 = d[p] + s1_offset + c * bps;
600
512
                uint8_t *s2 = d[p] + s2_offset + c * bps;
601
512
                memcpy(tmp, s2, bps);
602
512
                memcpy(s2, s1, bps);
603
512
                memcpy(s1, tmp, bps);
604
512
            }
605
512
        }
606
1
    }
607
608
1
    return true;
609
1
}
610
611
int mp_aframe_approx_byte_size(struct mp_aframe *frame)
612
7.18M
{
613
    // God damn, AVFrame is too fucking annoying. Just go with the size that
614
    // allocating a new frame would use.
615
7.18M
    int planes = mp_aframe_get_planes(frame);
616
7.18M
    size_t sstride = mp_aframe_get_sstride(frame);
617
7.18M
    int samples = frame->av_frame->nb_samples;
618
7.18M
    int plane_size = MP_ALIGN_UP(sstride * MPMAX(samples, 1), 32);
619
7.18M
    return plane_size * planes + sizeof(*frame);
620
7.18M
}
621
622
struct mp_aframe_pool {
623
    AVBufferPool *avpool;
624
    int element_size;
625
};
626
627
struct mp_aframe_pool *mp_aframe_pool_create(void *ta_parent)
628
45.8k
{
629
45.8k
    return talloc_zero(ta_parent, struct mp_aframe_pool);
630
45.8k
}
631
632
static void mp_aframe_pool_destructor(void *p)
633
41.6k
{
634
41.6k
    struct mp_aframe_pool *pool = p;
635
41.6k
    av_buffer_pool_uninit(&pool->avpool);
636
41.6k
}
637
638
// Like mp_aframe_allocate(), but use the pool to allocate data.
639
int mp_aframe_pool_allocate(struct mp_aframe_pool *pool, struct mp_aframe *frame,
640
                            int samples)
641
1.79M
{
642
1.79M
    int planes = mp_aframe_get_planes(frame);
643
1.79M
    size_t sstride = mp_aframe_get_sstride(frame);
644
    // FFmpeg hardcodes similar hidden possibly-requirements in a number of
645
    // places: av_frame_get_buffer(), libavcodec's get_buffer(), mem.c,
646
    // probably more.
647
1.79M
    int align_samples = MP_ALIGN_UP(MPMAX(samples, 1), 32);
648
1.79M
    int plane_size = MP_ALIGN_UP(sstride * align_samples, 64);
649
1.79M
    int size = plane_size * planes;
650
651
1.79M
    if (size <= 0 || mp_aframe_is_allocated(frame))
652
0
        return -1;
653
654
1.79M
    if (!pool->avpool || size > pool->element_size) {
655
42.0k
        size_t alloc = ta_calc_prealloc_elems(size);
656
42.0k
        if (alloc >= INT_MAX)
657
0
            return -1;
658
42.0k
        av_buffer_pool_uninit(&pool->avpool);
659
42.0k
        pool->element_size = alloc;
660
42.0k
        pool->avpool = av_buffer_pool_init(pool->element_size, NULL);
661
42.0k
        if (!pool->avpool)
662
0
            return -1;
663
42.0k
        talloc_set_destructor(pool, mp_aframe_pool_destructor);
664
42.0k
    }
665
666
    // Yes, you have to do all this shit manually.
667
    // At least it's less stupid than av_frame_get_buffer(), which just wipes
668
    // the entire frame struct on error for no reason.
669
1.79M
    AVFrame *av_frame = frame->av_frame;
670
1.79M
    if (av_frame->extended_data != av_frame->data)
671
0
        av_freep(&av_frame->extended_data); // sigh
672
1.79M
    if (planes > AV_NUM_DATA_POINTERS) {
673
73.2k
        av_frame->extended_data =
674
73.2k
            av_calloc(planes, sizeof(av_frame->extended_data[0]));
675
73.2k
        MP_HANDLE_OOM(av_frame->extended_data);
676
1.72M
    } else {
677
1.72M
        av_frame->extended_data = av_frame->data;
678
1.72M
    }
679
1.79M
    av_frame->buf[0] = av_buffer_pool_get(pool->avpool);
680
1.79M
    if (!av_frame->buf[0])
681
0
        return -1;
682
1.79M
    av_frame->linesize[0] = samples * sstride;
683
5.08M
    for (int n = 0; n < planes; n++)
684
3.28M
        av_frame->extended_data[n] = av_frame->buf[0]->data + n * plane_size;
685
1.79M
    if (planes > AV_NUM_DATA_POINTERS) {
686
659k
        for (int n = 0; n < AV_NUM_DATA_POINTERS; n++)
687
585k
            av_frame->data[n] = av_frame->extended_data[n];
688
73.2k
    }
689
1.79M
    av_frame->nb_samples = samples;
690
691
1.79M
    return 0;
692
1.79M
}