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 | } |