/src/mpv/audio/out/ao_lavc.c
Line | Count | Source |
1 | | /* |
2 | | * audio encoding using libavformat |
3 | | * |
4 | | * Copyright (C) 2011-2012 Rudolf Polzer <divVerent@xonotic.org> |
5 | | * NOTE: this file is partially based on ao_pcm.c by Atmosfear |
6 | | * |
7 | | * This file is part of mpv. |
8 | | * |
9 | | * mpv is free software; you can redistribute it and/or |
10 | | * modify it under the terms of the GNU Lesser General Public |
11 | | * License as published by the Free Software Foundation; either |
12 | | * version 2.1 of the License, or (at your option) any later version. |
13 | | * |
14 | | * mpv 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 Lesser General Public License for more details. |
18 | | * |
19 | | * You should have received a copy of the GNU Lesser General Public |
20 | | * License along with mpv. If not, see <http://www.gnu.org/licenses/>. |
21 | | */ |
22 | | |
23 | | #include <stdio.h> |
24 | | #include <stdlib.h> |
25 | | #include <assert.h> |
26 | | #include <limits.h> |
27 | | |
28 | | #include <libavutil/common.h> |
29 | | #include <libavutil/samplefmt.h> |
30 | | |
31 | | #include "config.h" |
32 | | #include "options/options.h" |
33 | | #include "common/common.h" |
34 | | #include "audio/aframe.h" |
35 | | #include "audio/chmap_avchannel.h" |
36 | | #include "audio/format.h" |
37 | | #include "audio/fmt-conversion.h" |
38 | | #include "filters/filter_internal.h" |
39 | | #include "filters/f_utils.h" |
40 | | #include "misc/lavc_compat.h" |
41 | | #include "mpv_talloc.h" |
42 | | #include "ao.h" |
43 | | #include "internal.h" |
44 | | #include "common/msg.h" |
45 | | |
46 | | #include "common/encode_lavc.h" |
47 | | |
48 | | struct priv { |
49 | | struct encoder_context *enc; |
50 | | |
51 | | int pcmhack; |
52 | | int aframesize; |
53 | | int framecount; |
54 | | int64_t lastpts; |
55 | | int sample_size; |
56 | | double expected_next_pts; |
57 | | struct mp_filter *filter_root; |
58 | | struct mp_filter *fix_frame_size; |
59 | | |
60 | | AVRational worst_time_base; |
61 | | |
62 | | bool shutdown; |
63 | | }; |
64 | | |
65 | | static bool write_frame(struct ao *ao, struct mp_frame frame); |
66 | | |
67 | | static bool supports_format(const AVCodec *codec, int format) |
68 | 0 | { |
69 | 0 | const enum AVSampleFormat *sampleformat; |
70 | 0 | int ret = mp_avcodec_get_supported_config(NULL, codec, |
71 | 0 | AV_CODEC_CONFIG_SAMPLE_FORMAT, |
72 | 0 | (const void **)&sampleformat); |
73 | 0 | if (ret >= 0 && !sampleformat) |
74 | 0 | return true; |
75 | 0 | for (; ret >= 0 && *sampleformat != AV_SAMPLE_FMT_NONE; sampleformat++) |
76 | 0 | { |
77 | 0 | if (af_from_avformat(*sampleformat) == format) |
78 | 0 | return true; |
79 | 0 | } |
80 | 0 | return false; |
81 | 0 | } |
82 | | |
83 | | static void select_format(struct ao *ao, const AVCodec *codec) |
84 | 0 | { |
85 | 0 | int formats[AF_FORMAT_COUNT + 1]; |
86 | 0 | af_get_best_sample_formats(ao->format, formats); |
87 | |
|
88 | 0 | for (int n = 0; formats[n]; n++) { |
89 | 0 | if (supports_format(codec, formats[n])) { |
90 | 0 | ao->format = formats[n]; |
91 | 0 | break; |
92 | 0 | } |
93 | 0 | } |
94 | 0 | } |
95 | | |
96 | | // open & setup audio device |
97 | | static int init(struct ao *ao) |
98 | 0 | { |
99 | 0 | struct priv *ac = ao->priv; |
100 | |
|
101 | 0 | ac->enc = encoder_context_alloc(ao->encode_lavc_ctx, STREAM_AUDIO, ao->log); |
102 | 0 | if (!ac->enc) |
103 | 0 | return -1; |
104 | 0 | talloc_steal(ac, ac->enc); |
105 | |
|
106 | 0 | AVCodecContext *encoder = ac->enc->encoder; |
107 | 0 | const AVCodec *codec = encoder->codec; |
108 | |
|
109 | 0 | const int *samplerates; |
110 | 0 | int ret = mp_avcodec_get_supported_config(NULL, codec, |
111 | 0 | AV_CODEC_CONFIG_SAMPLE_RATE, |
112 | 0 | (const void **)&samplerates); |
113 | |
|
114 | 0 | int samplerate = 0; |
115 | 0 | if (ret >= 0) |
116 | 0 | samplerate = af_select_best_samplerate(ao->samplerate, samplerates); |
117 | 0 | if (samplerate > 0) |
118 | 0 | ao->samplerate = samplerate; |
119 | |
|
120 | 0 | encoder->time_base.num = 1; |
121 | 0 | encoder->time_base.den = ao->samplerate; |
122 | |
|
123 | 0 | encoder->sample_rate = ao->samplerate; |
124 | |
|
125 | 0 | struct mp_chmap_sel sel = {0}; |
126 | 0 | mp_chmap_sel_add_any(&sel); |
127 | 0 | if (!ao_chmap_sel_adjust2(ao, &sel, &ao->channels, false)) |
128 | 0 | goto fail; |
129 | 0 | mp_chmap_reorder_to_lavc(&ao->channels); |
130 | 0 | mp_chmap_to_av_layout(&encoder->ch_layout, &ao->channels); |
131 | |
|
132 | 0 | encoder->sample_fmt = AV_SAMPLE_FMT_NONE; |
133 | |
|
134 | 0 | select_format(ao, codec); |
135 | |
|
136 | 0 | ac->sample_size = af_fmt_to_bytes(ao->format); |
137 | 0 | encoder->sample_fmt = af_to_avformat(ao->format); |
138 | 0 | encoder->bits_per_raw_sample = ac->sample_size * 8; |
139 | |
|
140 | 0 | if (!encoder_init_codec_and_muxer(ac->enc)) |
141 | 0 | goto fail; |
142 | | |
143 | 0 | ac->worst_time_base = encoder_get_mux_timebase_unlocked(ac->enc); |
144 | 0 | ac->pcmhack = 0; |
145 | 0 | if (encoder->frame_size <= 1) |
146 | 0 | ac->pcmhack = av_get_bits_per_sample(encoder->codec_id) / 8; |
147 | |
|
148 | 0 | if (ac->pcmhack) { |
149 | 0 | ac->aframesize = 16384; // "enough" |
150 | 0 | } else { |
151 | 0 | ac->aframesize = encoder->frame_size; |
152 | 0 | } |
153 | | |
154 | | // enough frames for at least 0.25 seconds |
155 | 0 | ac->framecount = ceil(ao->samplerate * 0.25 / ac->aframesize); |
156 | | // but at least one! |
157 | 0 | ac->framecount = MPMAX(ac->framecount, 1); |
158 | |
|
159 | 0 | ac->lastpts = AV_NOPTS_VALUE; |
160 | |
|
161 | 0 | ao->untimed = true; |
162 | |
|
163 | 0 | ao->device_buffer = ac->aframesize * ac->framecount; |
164 | |
|
165 | 0 | ac->filter_root = mp_filter_create_root(ao->global); |
166 | 0 | ac->fix_frame_size = mp_fixed_aframe_size_create(ac->filter_root, |
167 | 0 | ac->aframesize, true); |
168 | 0 | MP_HANDLE_OOM(ac->fix_frame_size); |
169 | | |
170 | 0 | return 0; |
171 | | |
172 | 0 | fail: |
173 | 0 | mp_mutex_unlock(&ao->encode_lavc_ctx->lock); |
174 | 0 | ac->shutdown = true; |
175 | 0 | return -1; |
176 | 0 | } |
177 | | |
178 | | // close audio device |
179 | | static void uninit(struct ao *ao) |
180 | 0 | { |
181 | 0 | struct priv *ac = ao->priv; |
182 | |
|
183 | 0 | if (!ac->shutdown) { |
184 | 0 | if (!write_frame(ao, MP_EOF_FRAME)) |
185 | 0 | MP_WARN(ao, "could not flush last frame\n"); |
186 | 0 | encoder_encode(ac->enc, NULL); |
187 | 0 | } |
188 | |
|
189 | 0 | talloc_free(ac->filter_root); |
190 | 0 | } |
191 | | |
192 | | // must get exactly ac->aframesize amount of data |
193 | | static void encode(struct ao *ao, struct mp_aframe *af) |
194 | 0 | { |
195 | 0 | struct priv *ac = ao->priv; |
196 | 0 | AVCodecContext *encoder = ac->enc->encoder; |
197 | 0 | double outpts = mp_aframe_get_pts(af); |
198 | |
|
199 | 0 | AVFrame *frame = mp_aframe_to_avframe(af); |
200 | 0 | MP_HANDLE_OOM(frame); |
201 | | |
202 | 0 | frame->pts = rint(outpts * av_q2d(av_inv_q(encoder->time_base))); |
203 | |
|
204 | 0 | int64_t frame_pts = av_rescale_q(frame->pts, encoder->time_base, |
205 | 0 | ac->worst_time_base); |
206 | 0 | if (ac->lastpts != AV_NOPTS_VALUE && frame_pts <= ac->lastpts) { |
207 | | // whatever the fuck this code does? |
208 | 0 | MP_WARN(ao, "audio frame pts went backwards (%d <- %d), autofixed\n", |
209 | 0 | (int)frame->pts, (int)ac->lastpts); |
210 | 0 | frame_pts = ac->lastpts + 1; |
211 | 0 | ac->lastpts = frame_pts; |
212 | 0 | frame->pts = av_rescale_q(frame_pts, ac->worst_time_base, |
213 | 0 | encoder->time_base); |
214 | 0 | frame_pts = av_rescale_q(frame->pts, encoder->time_base, |
215 | 0 | ac->worst_time_base); |
216 | 0 | } |
217 | 0 | ac->lastpts = frame_pts; |
218 | |
|
219 | 0 | frame->quality = encoder->global_quality; |
220 | 0 | encoder_encode(ac->enc, frame); |
221 | 0 | av_frame_free(&frame); |
222 | 0 | } |
223 | | |
224 | | static bool write_frame(struct ao *ao, struct mp_frame frame) |
225 | 0 | { |
226 | 0 | struct priv *ac = ao->priv; |
227 | | |
228 | | // Can't push in frame if it doesn't want it output one. |
229 | 0 | mp_pin_out_request_data(ac->fix_frame_size->pins[1]); |
230 | |
|
231 | 0 | if (!mp_pin_in_write(ac->fix_frame_size->pins[0], frame)) |
232 | 0 | return false; // shouldn't happen™ |
233 | | |
234 | 0 | while (1) { |
235 | 0 | struct mp_frame fr = mp_pin_out_read(ac->fix_frame_size->pins[1]); |
236 | 0 | if (!fr.type) |
237 | 0 | break; |
238 | 0 | if (fr.type != MP_FRAME_AUDIO) |
239 | 0 | continue; |
240 | 0 | struct mp_aframe *af = fr.data; |
241 | 0 | encode(ao, af); |
242 | 0 | mp_frame_unref(&fr); |
243 | 0 | } |
244 | |
|
245 | 0 | return true; |
246 | 0 | } |
247 | | |
248 | | static bool audio_write(struct ao *ao, void **data, int samples) |
249 | 0 | { |
250 | 0 | struct priv *ac = ao->priv; |
251 | 0 | struct encode_lavc_context *ectx = ao->encode_lavc_ctx; |
252 | | |
253 | | // See ao_driver.write_frames. |
254 | 0 | struct mp_aframe *af = mp_aframe_new_ref(*(struct mp_aframe **)data); |
255 | |
|
256 | 0 | double nextpts; |
257 | 0 | double pts = mp_aframe_get_pts(af); |
258 | 0 | double outpts = pts; |
259 | | |
260 | | // for ectx PTS fields |
261 | 0 | mp_mutex_lock(&ectx->lock); |
262 | |
|
263 | 0 | if (!ectx->options->rawts) { |
264 | | // Fix and apply the discontinuity pts offset. |
265 | 0 | nextpts = pts; |
266 | 0 | if (ectx->discontinuity_pts_offset == MP_NOPTS_VALUE) { |
267 | 0 | ectx->discontinuity_pts_offset = ectx->next_in_pts - nextpts; |
268 | 0 | } else if (fabs(nextpts + ectx->discontinuity_pts_offset - |
269 | 0 | ectx->next_in_pts) > 30) |
270 | 0 | { |
271 | 0 | MP_WARN(ao, "detected an unexpected discontinuity (pts jumped by " |
272 | 0 | "%f seconds)\n", |
273 | 0 | nextpts + ectx->discontinuity_pts_offset - ectx->next_in_pts); |
274 | 0 | ectx->discontinuity_pts_offset = ectx->next_in_pts - nextpts; |
275 | 0 | } |
276 | |
|
277 | 0 | outpts = pts + ectx->discontinuity_pts_offset; |
278 | 0 | } |
279 | | |
280 | | // Calculate expected pts of next audio frame (input side). |
281 | 0 | ac->expected_next_pts = pts + mp_aframe_get_size(af) / (double) ao->samplerate; |
282 | | |
283 | | // Set next allowed input pts value (input side). |
284 | 0 | if (!ectx->options->rawts) { |
285 | 0 | nextpts = ac->expected_next_pts + ectx->discontinuity_pts_offset; |
286 | 0 | if (nextpts > ectx->next_in_pts) |
287 | 0 | ectx->next_in_pts = nextpts; |
288 | 0 | } |
289 | |
|
290 | 0 | mp_mutex_unlock(&ectx->lock); |
291 | |
|
292 | 0 | mp_aframe_set_pts(af, outpts); |
293 | |
|
294 | 0 | return write_frame(ao, MAKE_FRAME(MP_FRAME_AUDIO, af)); |
295 | 0 | } |
296 | | |
297 | | static void get_state(struct ao *ao, struct mp_pcm_state *state) |
298 | 0 | { |
299 | 0 | state->free_samples = 1; |
300 | 0 | state->queued_samples = 0; |
301 | 0 | state->delay = 0; |
302 | 0 | } |
303 | | |
304 | | static bool set_pause(struct ao *ao, bool paused) |
305 | 0 | { |
306 | 0 | return true; // signal support so common code doesn't write silence |
307 | 0 | } |
308 | | |
309 | | static void start(struct ao *ao) |
310 | 0 | { |
311 | | // we use data immediately |
312 | 0 | } |
313 | | |
314 | | static void reset(struct ao *ao) |
315 | 0 | { |
316 | 0 | } |
317 | | |
318 | | const struct ao_driver audio_out_lavc = { |
319 | | .encode = true, |
320 | | .description = "audio encoding using libavcodec", |
321 | | .name = "lavc", |
322 | | .write_frames = true, |
323 | | .priv_size = sizeof(struct priv), |
324 | | .init = init, |
325 | | .uninit = uninit, |
326 | | .get_state = get_state, |
327 | | .set_pause = set_pause, |
328 | | .write = audio_write, |
329 | | .start = start, |
330 | | .reset = reset, |
331 | | }; |
332 | | |
333 | | // vim: sw=4 ts=4 et tw=80 |