2012-09-14 15:51:26 +00:00
|
|
|
/*
|
|
|
|
* audio encoding using libavformat
|
2017-06-13 18:22:15 +00:00
|
|
|
*
|
2012-12-28 10:41:30 +00:00
|
|
|
* Copyright (C) 2011-2012 Rudolf Polzer <divVerent@xonotic.org>
|
2012-09-14 15:51:26 +00:00
|
|
|
* NOTE: this file is partially based on ao_pcm.c by Atmosfear
|
|
|
|
*
|
2012-12-28 10:41:30 +00:00
|
|
|
* This file is part of mpv.
|
2012-09-14 15:51:26 +00:00
|
|
|
*
|
2017-06-13 18:22:15 +00:00
|
|
|
* mpv is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
2012-09-14 15:51:26 +00:00
|
|
|
*
|
2015-04-13 07:36:54 +00:00
|
|
|
* mpv is distributed in the hope that it will be useful,
|
2012-09-14 15:51:26 +00:00
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
2017-06-13 18:22:15 +00:00
|
|
|
* GNU Lesser General Public License for more details.
|
2012-09-14 15:51:26 +00:00
|
|
|
*
|
2017-06-13 18:22:15 +00:00
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with mpv. If not, see <http://www.gnu.org/licenses/>.
|
2012-09-14 15:51:26 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
2013-11-13 18:19:57 +00:00
|
|
|
#include <assert.h>
|
2013-11-16 19:20:11 +00:00
|
|
|
#include <limits.h>
|
2012-09-14 15:51:26 +00:00
|
|
|
|
|
|
|
#include <libavutil/common.h>
|
|
|
|
|
|
|
|
#include "config.h"
|
2013-12-17 01:02:25 +00:00
|
|
|
#include "options/options.h"
|
2013-12-17 01:39:45 +00:00
|
|
|
#include "common/common.h"
|
audio: refactor how data is passed to AO
This replaces the two buffers (ao_chain.ao_buffer in the core, and
buffer_state.buffers in the AO) with a single queue. Instead of having a
byte based buffer, the queue is simply a list of audio frames, as output
by the decoder. This should make dataflow simpler and reduce copying.
It also attempts to simplify fill_audio_out_buffers(), the function I
always hated most, because it's full of subtle and buggy logic.
Unfortunately, I got assaulted by corner cases, dumb features (attempt
at seamless looping, really?), and other crap, so it got pretty
complicated again. fill_audio_out_buffers() is still full of subtle and
buggy logic. Maybe it got worse. On the other hand, maybe there really
is some progress. Who knows.
Originally, the data flow parts was meant to be in f_output_chain, but
due to tricky interactions with the playloop code, it's now in the dummy
filter in audio.c.
At least this improves the way the audio PTS is passed to the encoder in
encoding mode. Now it attempts to pass frames directly, along with the
pts, which should minimize timestamp problems. But to be honest, encoder
mode is one big kludge that shouldn't exist in this way.
This commit should be considered pre-alpha code. There are lots of bugs
still hiding.
2020-08-28 18:23:54 +00:00
|
|
|
#include "audio/aframe.h"
|
2022-05-22 19:58:15 +00:00
|
|
|
#include "audio/chmap_avchannel.h"
|
2012-11-09 00:06:43 +00:00
|
|
|
#include "audio/format.h"
|
2013-11-13 18:19:57 +00:00
|
|
|
#include "audio/fmt-conversion.h"
|
audio: refactor how data is passed to AO
This replaces the two buffers (ao_chain.ao_buffer in the core, and
buffer_state.buffers in the AO) with a single queue. Instead of having a
byte based buffer, the queue is simply a list of audio frames, as output
by the decoder. This should make dataflow simpler and reduce copying.
It also attempts to simplify fill_audio_out_buffers(), the function I
always hated most, because it's full of subtle and buggy logic.
Unfortunately, I got assaulted by corner cases, dumb features (attempt
at seamless looping, really?), and other crap, so it got pretty
complicated again. fill_audio_out_buffers() is still full of subtle and
buggy logic. Maybe it got worse. On the other hand, maybe there really
is some progress. Who knows.
Originally, the data flow parts was meant to be in f_output_chain, but
due to tricky interactions with the playloop code, it's now in the dummy
filter in audio.c.
At least this improves the way the audio PTS is passed to the encoder in
encoding mode. Now it attempts to pass frames directly, along with the
pts, which should minimize timestamp problems. But to be honest, encoder
mode is one big kludge that shouldn't exist in this way.
This commit should be considered pre-alpha code. There are lots of bugs
still hiding.
2020-08-28 18:23:54 +00:00
|
|
|
#include "filters/filter_internal.h"
|
|
|
|
#include "filters/f_utils.h"
|
2016-01-11 18:03:40 +00:00
|
|
|
#include "mpv_talloc.h"
|
2012-11-09 00:06:43 +00:00
|
|
|
#include "ao.h"
|
2014-03-07 14:24:32 +00:00
|
|
|
#include "internal.h"
|
2013-12-17 01:39:45 +00:00
|
|
|
#include "common/msg.h"
|
2012-09-14 15:51:26 +00:00
|
|
|
|
2013-12-17 01:39:45 +00:00
|
|
|
#include "common/encode_lavc.h"
|
2012-09-14 15:51:26 +00:00
|
|
|
|
|
|
|
struct priv {
|
2018-04-22 17:40:36 +00:00
|
|
|
struct encoder_context *enc;
|
|
|
|
|
2012-09-14 15:51:26 +00:00
|
|
|
int pcmhack;
|
|
|
|
int aframesize;
|
|
|
|
int framecount;
|
|
|
|
int64_t lastpts;
|
|
|
|
int sample_size;
|
2012-09-25 09:53:29 +00:00
|
|
|
double expected_next_pts;
|
audio: refactor how data is passed to AO
This replaces the two buffers (ao_chain.ao_buffer in the core, and
buffer_state.buffers in the AO) with a single queue. Instead of having a
byte based buffer, the queue is simply a list of audio frames, as output
by the decoder. This should make dataflow simpler and reduce copying.
It also attempts to simplify fill_audio_out_buffers(), the function I
always hated most, because it's full of subtle and buggy logic.
Unfortunately, I got assaulted by corner cases, dumb features (attempt
at seamless looping, really?), and other crap, so it got pretty
complicated again. fill_audio_out_buffers() is still full of subtle and
buggy logic. Maybe it got worse. On the other hand, maybe there really
is some progress. Who knows.
Originally, the data flow parts was meant to be in f_output_chain, but
due to tricky interactions with the playloop code, it's now in the dummy
filter in audio.c.
At least this improves the way the audio PTS is passed to the encoder in
encoding mode. Now it attempts to pass frames directly, along with the
pts, which should minimize timestamp problems. But to be honest, encoder
mode is one big kludge that shouldn't exist in this way.
This commit should be considered pre-alpha code. There are lots of bugs
still hiding.
2020-08-28 18:23:54 +00:00
|
|
|
struct mp_filter *filter_root;
|
|
|
|
struct mp_filter *fix_frame_size;
|
2012-09-14 15:51:26 +00:00
|
|
|
|
|
|
|
AVRational worst_time_base;
|
2014-11-12 11:16:07 +00:00
|
|
|
|
|
|
|
bool shutdown;
|
2012-09-14 15:51:26 +00:00
|
|
|
};
|
|
|
|
|
2020-09-03 13:39:31 +00:00
|
|
|
static bool write_frame(struct ao *ao, struct mp_frame frame);
|
2018-04-19 18:13:28 +00:00
|
|
|
|
2018-04-22 17:40:36 +00:00
|
|
|
static bool supports_format(const AVCodec *codec, int format)
|
2013-11-16 19:20:11 +00:00
|
|
|
{
|
|
|
|
for (const enum AVSampleFormat *sampleformat = codec->sample_fmts;
|
|
|
|
sampleformat && *sampleformat != AV_SAMPLE_FMT_NONE;
|
2018-04-19 18:13:28 +00:00
|
|
|
sampleformat++)
|
2013-11-16 19:20:11 +00:00
|
|
|
{
|
2015-09-11 07:01:49 +00:00
|
|
|
if (af_from_avformat(*sampleformat) == format)
|
2015-09-10 21:38:42 +00:00
|
|
|
return true;
|
2013-11-16 19:20:11 +00:00
|
|
|
}
|
2015-09-10 21:38:42 +00:00
|
|
|
return false;
|
|
|
|
}
|
2013-11-16 19:20:11 +00:00
|
|
|
|
2018-04-22 17:40:36 +00:00
|
|
|
static void select_format(struct ao *ao, const AVCodec *codec)
|
2015-09-10 21:38:42 +00:00
|
|
|
{
|
2018-01-23 23:02:13 +00:00
|
|
|
int formats[AF_FORMAT_COUNT + 1];
|
2015-09-10 21:38:42 +00:00
|
|
|
af_get_best_sample_formats(ao->format, formats);
|
|
|
|
|
2015-09-11 07:01:49 +00:00
|
|
|
for (int n = 0; formats[n]; n++) {
|
2015-09-10 21:38:42 +00:00
|
|
|
if (supports_format(codec, formats[n])) {
|
|
|
|
ao->format = formats[n];
|
|
|
|
break;
|
|
|
|
}
|
2013-11-16 19:20:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-29 17:42:18 +00:00
|
|
|
static void on_ready(void *ptr)
|
|
|
|
{
|
|
|
|
struct ao *ao = ptr;
|
2020-03-22 12:06:59 +00:00
|
|
|
struct priv *ac = ao->priv;
|
|
|
|
|
|
|
|
ac->worst_time_base = encoder_get_mux_timebase_unlocked(ac->enc);
|
2018-04-29 17:42:18 +00:00
|
|
|
|
|
|
|
ao_add_events(ao, AO_EVENT_INITIAL_UNBLOCK);
|
|
|
|
}
|
|
|
|
|
2012-09-14 15:51:26 +00:00
|
|
|
// open & setup audio device
|
2013-07-22 20:57:51 +00:00
|
|
|
static int init(struct ao *ao)
|
2012-09-14 15:51:26 +00:00
|
|
|
{
|
2018-04-22 17:40:36 +00:00
|
|
|
struct priv *ac = ao->priv;
|
2013-11-16 19:20:11 +00:00
|
|
|
|
2018-04-22 17:40:36 +00:00
|
|
|
ac->enc = encoder_context_alloc(ao->encode_lavc_ctx, STREAM_AUDIO, ao->log);
|
|
|
|
if (!ac->enc)
|
2012-09-14 15:51:26 +00:00
|
|
|
return -1;
|
2018-04-22 17:40:36 +00:00
|
|
|
talloc_steal(ac, ac->enc);
|
2012-09-14 15:51:26 +00:00
|
|
|
|
2018-04-22 17:40:36 +00:00
|
|
|
AVCodecContext *encoder = ac->enc->encoder;
|
|
|
|
const AVCodec *codec = encoder->codec;
|
2012-09-14 15:51:26 +00:00
|
|
|
|
2016-03-17 07:58:07 +00:00
|
|
|
int samplerate = af_select_best_samplerate(ao->samplerate,
|
|
|
|
codec->supported_samplerates);
|
|
|
|
if (samplerate > 0)
|
|
|
|
ao->samplerate = samplerate;
|
|
|
|
|
2018-04-22 17:40:36 +00:00
|
|
|
encoder->time_base.num = 1;
|
|
|
|
encoder->time_base.den = ao->samplerate;
|
2012-09-14 15:51:26 +00:00
|
|
|
|
2018-04-22 17:40:36 +00:00
|
|
|
encoder->sample_rate = ao->samplerate;
|
2013-04-05 21:06:22 +00:00
|
|
|
|
2013-05-09 16:06:26 +00:00
|
|
|
struct mp_chmap_sel sel = {0};
|
|
|
|
mp_chmap_sel_add_any(&sel);
|
2016-08-04 18:49:20 +00:00
|
|
|
if (!ao_chmap_sel_adjust2(ao, &sel, &ao->channels, false))
|
2014-03-08 22:38:53 +00:00
|
|
|
goto fail;
|
2013-04-05 21:06:22 +00:00
|
|
|
mp_chmap_reorder_to_lavc(&ao->channels);
|
2022-05-22 19:58:15 +00:00
|
|
|
|
|
|
|
#if !HAVE_AV_CHANNEL_LAYOUT
|
2018-04-22 17:40:36 +00:00
|
|
|
encoder->channels = ao->channels.num;
|
|
|
|
encoder->channel_layout = mp_chmap_to_lavc(&ao->channels);
|
2022-05-22 19:58:15 +00:00
|
|
|
#else
|
|
|
|
mp_chmap_to_av_layout(&encoder->ch_layout, &ao->channels);
|
|
|
|
#endif
|
2012-09-14 15:51:26 +00:00
|
|
|
|
2018-04-22 17:40:36 +00:00
|
|
|
encoder->sample_fmt = AV_SAMPLE_FMT_NONE;
|
2012-09-14 15:51:26 +00:00
|
|
|
|
2013-11-16 19:20:11 +00:00
|
|
|
select_format(ao, codec);
|
2012-12-03 19:16:17 +00:00
|
|
|
|
2015-06-26 21:06:37 +00:00
|
|
|
ac->sample_size = af_fmt_to_bytes(ao->format);
|
2018-04-22 17:40:36 +00:00
|
|
|
encoder->sample_fmt = af_to_avformat(ao->format);
|
|
|
|
encoder->bits_per_raw_sample = ac->sample_size * 8;
|
2012-09-14 15:51:26 +00:00
|
|
|
|
2018-04-29 17:42:18 +00:00
|
|
|
if (!encoder_init_codec_and_muxer(ac->enc, on_ready, ao))
|
2014-03-08 22:38:53 +00:00
|
|
|
goto fail;
|
2012-09-14 15:51:26 +00:00
|
|
|
|
|
|
|
ac->pcmhack = 0;
|
2018-04-22 17:40:36 +00:00
|
|
|
if (encoder->frame_size <= 1)
|
|
|
|
ac->pcmhack = av_get_bits_per_sample(encoder->codec_id) / 8;
|
2012-09-14 15:51:26 +00:00
|
|
|
|
2018-04-19 18:13:28 +00:00
|
|
|
if (ac->pcmhack) {
|
2012-09-14 15:51:26 +00:00
|
|
|
ac->aframesize = 16384; // "enough"
|
2018-04-19 18:13:28 +00:00
|
|
|
} else {
|
2018-04-22 17:40:36 +00:00
|
|
|
ac->aframesize = encoder->frame_size;
|
2018-04-19 18:13:28 +00:00
|
|
|
}
|
2012-09-14 15:51:26 +00:00
|
|
|
|
|
|
|
// enough frames for at least 0.25 seconds
|
|
|
|
ac->framecount = ceil(ao->samplerate * 0.25 / ac->aframesize);
|
|
|
|
// but at least one!
|
2019-10-31 10:24:20 +00:00
|
|
|
ac->framecount = MPMAX(ac->framecount, 1);
|
2012-09-14 15:51:26 +00:00
|
|
|
|
2014-05-10 08:32:23 +00:00
|
|
|
ac->lastpts = AV_NOPTS_VALUE;
|
2012-09-14 15:51:26 +00:00
|
|
|
|
|
|
|
ao->untimed = true;
|
|
|
|
|
audio: redo internal AO API
This affects "pull" AOs only: ao_alsa, ao_pulse, ao_openal, ao_pcm,
ao_lavc. There are changes to the other AOs too, but that's only about
renaming ao_driver.resume to ao_driver.start.
ao_openal is broken because I didn't manage to fix it, so it exits with
an error message. If you want it, why don't _you_ put effort into it? I
see no reason to waste my own precious lifetime over this (I realize the
irony).
ao_alsa loses the poll() mechanism, but it was mostly broken and didn't
really do what it was supposed to. There doesn't seem to be anything in
the ALSA API to watch the playback status without polling (unless you
want to use raw UNIX signals).
No idea if ao_pulse is correct, or whether it's subtly broken now. There
is no documentation, so I can't tell what is correct, without reverse
engineering the whole project. I recommend using ALSA.
This was supposed to be just a simple fix, but somehow it expanded scope
like a train wreck. Very high chance of regressions, but probably only
for the AOs listed above. The rest you can figure out from reading the
diff.
2020-05-31 13:00:35 +00:00
|
|
|
ao->device_buffer = ac->aframesize * ac->framecount;
|
2017-06-25 13:57:15 +00:00
|
|
|
|
audio: refactor how data is passed to AO
This replaces the two buffers (ao_chain.ao_buffer in the core, and
buffer_state.buffers in the AO) with a single queue. Instead of having a
byte based buffer, the queue is simply a list of audio frames, as output
by the decoder. This should make dataflow simpler and reduce copying.
It also attempts to simplify fill_audio_out_buffers(), the function I
always hated most, because it's full of subtle and buggy logic.
Unfortunately, I got assaulted by corner cases, dumb features (attempt
at seamless looping, really?), and other crap, so it got pretty
complicated again. fill_audio_out_buffers() is still full of subtle and
buggy logic. Maybe it got worse. On the other hand, maybe there really
is some progress. Who knows.
Originally, the data flow parts was meant to be in f_output_chain, but
due to tricky interactions with the playloop code, it's now in the dummy
filter in audio.c.
At least this improves the way the audio PTS is passed to the encoder in
encoding mode. Now it attempts to pass frames directly, along with the
pts, which should minimize timestamp problems. But to be honest, encoder
mode is one big kludge that shouldn't exist in this way.
This commit should be considered pre-alpha code. There are lots of bugs
still hiding.
2020-08-28 18:23:54 +00:00
|
|
|
ac->filter_root = mp_filter_create_root(ao->global);
|
|
|
|
ac->fix_frame_size = mp_fixed_aframe_size_create(ac->filter_root,
|
|
|
|
ac->aframesize, true);
|
|
|
|
MP_HANDLE_OOM(ac->fix_frame_size);
|
2015-10-26 14:54:00 +00:00
|
|
|
|
2012-09-14 15:51:26 +00:00
|
|
|
return 0;
|
2014-03-08 22:38:53 +00:00
|
|
|
|
|
|
|
fail:
|
|
|
|
pthread_mutex_unlock(&ao->encode_lavc_ctx->lock);
|
2014-11-12 11:16:07 +00:00
|
|
|
ac->shutdown = true;
|
2014-03-08 22:38:53 +00:00
|
|
|
return -1;
|
2012-09-14 15:51:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// close audio device
|
2014-03-08 23:49:39 +00:00
|
|
|
static void uninit(struct ao *ao)
|
2012-09-14 15:51:26 +00:00
|
|
|
{
|
2013-11-16 17:50:07 +00:00
|
|
|
struct priv *ac = ao->priv;
|
2012-11-01 11:25:50 +00:00
|
|
|
struct encode_lavc_context *ectx = ao->encode_lavc_ctx;
|
|
|
|
|
2018-04-22 17:40:36 +00:00
|
|
|
if (!ac->shutdown) {
|
|
|
|
double outpts = ac->expected_next_pts;
|
2014-03-08 22:38:53 +00:00
|
|
|
|
2018-04-22 17:40:36 +00:00
|
|
|
pthread_mutex_lock(&ectx->lock);
|
2018-04-29 00:55:27 +00:00
|
|
|
if (!ac->enc->options->rawts)
|
2018-04-22 17:40:36 +00:00
|
|
|
outpts += ectx->discontinuity_pts_offset;
|
2014-03-08 22:38:53 +00:00
|
|
|
pthread_mutex_unlock(&ectx->lock);
|
2012-11-01 11:25:50 +00:00
|
|
|
|
2018-04-22 17:40:36 +00:00
|
|
|
outpts += encoder_get_offset(ac->enc);
|
audio: refactor how data is passed to AO
This replaces the two buffers (ao_chain.ao_buffer in the core, and
buffer_state.buffers in the AO) with a single queue. Instead of having a
byte based buffer, the queue is simply a list of audio frames, as output
by the decoder. This should make dataflow simpler and reduce copying.
It also attempts to simplify fill_audio_out_buffers(), the function I
always hated most, because it's full of subtle and buggy logic.
Unfortunately, I got assaulted by corner cases, dumb features (attempt
at seamless looping, really?), and other crap, so it got pretty
complicated again. fill_audio_out_buffers() is still full of subtle and
buggy logic. Maybe it got worse. On the other hand, maybe there really
is some progress. Who knows.
Originally, the data flow parts was meant to be in f_output_chain, but
due to tricky interactions with the playloop code, it's now in the dummy
filter in audio.c.
At least this improves the way the audio PTS is passed to the encoder in
encoding mode. Now it attempts to pass frames directly, along with the
pts, which should minimize timestamp problems. But to be honest, encoder
mode is one big kludge that shouldn't exist in this way.
This commit should be considered pre-alpha code. There are lots of bugs
still hiding.
2020-08-28 18:23:54 +00:00
|
|
|
|
2020-09-03 13:39:31 +00:00
|
|
|
if (!write_frame(ao, MP_EOF_FRAME))
|
audio: refactor how data is passed to AO
This replaces the two buffers (ao_chain.ao_buffer in the core, and
buffer_state.buffers in the AO) with a single queue. Instead of having a
byte based buffer, the queue is simply a list of audio frames, as output
by the decoder. This should make dataflow simpler and reduce copying.
It also attempts to simplify fill_audio_out_buffers(), the function I
always hated most, because it's full of subtle and buggy logic.
Unfortunately, I got assaulted by corner cases, dumb features (attempt
at seamless looping, really?), and other crap, so it got pretty
complicated again. fill_audio_out_buffers() is still full of subtle and
buggy logic. Maybe it got worse. On the other hand, maybe there really
is some progress. Who knows.
Originally, the data flow parts was meant to be in f_output_chain, but
due to tricky interactions with the playloop code, it's now in the dummy
filter in audio.c.
At least this improves the way the audio PTS is passed to the encoder in
encoding mode. Now it attempts to pass frames directly, along with the
pts, which should minimize timestamp problems. But to be honest, encoder
mode is one big kludge that shouldn't exist in this way.
This commit should be considered pre-alpha code. There are lots of bugs
still hiding.
2020-08-28 18:23:54 +00:00
|
|
|
MP_WARN(ao, "could not flush last frame\n");
|
|
|
|
encoder_encode(ac->enc, NULL);
|
2013-11-16 17:50:07 +00:00
|
|
|
}
|
audio: refactor how data is passed to AO
This replaces the two buffers (ao_chain.ao_buffer in the core, and
buffer_state.buffers in the AO) with a single queue. Instead of having a
byte based buffer, the queue is simply a list of audio frames, as output
by the decoder. This should make dataflow simpler and reduce copying.
It also attempts to simplify fill_audio_out_buffers(), the function I
always hated most, because it's full of subtle and buggy logic.
Unfortunately, I got assaulted by corner cases, dumb features (attempt
at seamless looping, really?), and other crap, so it got pretty
complicated again. fill_audio_out_buffers() is still full of subtle and
buggy logic. Maybe it got worse. On the other hand, maybe there really
is some progress. Who knows.
Originally, the data flow parts was meant to be in f_output_chain, but
due to tricky interactions with the playloop code, it's now in the dummy
filter in audio.c.
At least this improves the way the audio PTS is passed to the encoder in
encoding mode. Now it attempts to pass frames directly, along with the
pts, which should minimize timestamp problems. But to be honest, encoder
mode is one big kludge that shouldn't exist in this way.
This commit should be considered pre-alpha code. There are lots of bugs
still hiding.
2020-08-28 18:23:54 +00:00
|
|
|
|
|
|
|
talloc_free(ac->filter_root);
|
2012-09-14 15:51:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// must get exactly ac->aframesize amount of data
|
audio: refactor how data is passed to AO
This replaces the two buffers (ao_chain.ao_buffer in the core, and
buffer_state.buffers in the AO) with a single queue. Instead of having a
byte based buffer, the queue is simply a list of audio frames, as output
by the decoder. This should make dataflow simpler and reduce copying.
It also attempts to simplify fill_audio_out_buffers(), the function I
always hated most, because it's full of subtle and buggy logic.
Unfortunately, I got assaulted by corner cases, dumb features (attempt
at seamless looping, really?), and other crap, so it got pretty
complicated again. fill_audio_out_buffers() is still full of subtle and
buggy logic. Maybe it got worse. On the other hand, maybe there really
is some progress. Who knows.
Originally, the data flow parts was meant to be in f_output_chain, but
due to tricky interactions with the playloop code, it's now in the dummy
filter in audio.c.
At least this improves the way the audio PTS is passed to the encoder in
encoding mode. Now it attempts to pass frames directly, along with the
pts, which should minimize timestamp problems. But to be honest, encoder
mode is one big kludge that shouldn't exist in this way.
This commit should be considered pre-alpha code. There are lots of bugs
still hiding.
2020-08-28 18:23:54 +00:00
|
|
|
static void encode(struct ao *ao, struct mp_aframe *af)
|
2012-09-14 15:51:26 +00:00
|
|
|
{
|
|
|
|
struct priv *ac = ao->priv;
|
2018-04-22 17:40:36 +00:00
|
|
|
AVCodecContext *encoder = ac->enc->encoder;
|
audio: refactor how data is passed to AO
This replaces the two buffers (ao_chain.ao_buffer in the core, and
buffer_state.buffers in the AO) with a single queue. Instead of having a
byte based buffer, the queue is simply a list of audio frames, as output
by the decoder. This should make dataflow simpler and reduce copying.
It also attempts to simplify fill_audio_out_buffers(), the function I
always hated most, because it's full of subtle and buggy logic.
Unfortunately, I got assaulted by corner cases, dumb features (attempt
at seamless looping, really?), and other crap, so it got pretty
complicated again. fill_audio_out_buffers() is still full of subtle and
buggy logic. Maybe it got worse. On the other hand, maybe there really
is some progress. Who knows.
Originally, the data flow parts was meant to be in f_output_chain, but
due to tricky interactions with the playloop code, it's now in the dummy
filter in audio.c.
At least this improves the way the audio PTS is passed to the encoder in
encoding mode. Now it attempts to pass frames directly, along with the
pts, which should minimize timestamp problems. But to be honest, encoder
mode is one big kludge that shouldn't exist in this way.
This commit should be considered pre-alpha code. There are lots of bugs
still hiding.
2020-08-28 18:23:54 +00:00
|
|
|
double outpts = mp_aframe_get_pts(af);
|
2012-09-14 15:51:26 +00:00
|
|
|
|
audio: refactor how data is passed to AO
This replaces the two buffers (ao_chain.ao_buffer in the core, and
buffer_state.buffers in the AO) with a single queue. Instead of having a
byte based buffer, the queue is simply a list of audio frames, as output
by the decoder. This should make dataflow simpler and reduce copying.
It also attempts to simplify fill_audio_out_buffers(), the function I
always hated most, because it's full of subtle and buggy logic.
Unfortunately, I got assaulted by corner cases, dumb features (attempt
at seamless looping, really?), and other crap, so it got pretty
complicated again. fill_audio_out_buffers() is still full of subtle and
buggy logic. Maybe it got worse. On the other hand, maybe there really
is some progress. Who knows.
Originally, the data flow parts was meant to be in f_output_chain, but
due to tricky interactions with the playloop code, it's now in the dummy
filter in audio.c.
At least this improves the way the audio PTS is passed to the encoder in
encoding mode. Now it attempts to pass frames directly, along with the
pts, which should minimize timestamp problems. But to be honest, encoder
mode is one big kludge that shouldn't exist in this way.
This commit should be considered pre-alpha code. There are lots of bugs
still hiding.
2020-08-28 18:23:54 +00:00
|
|
|
AVFrame *frame = mp_aframe_to_avframe(af);
|
|
|
|
if (!frame)
|
|
|
|
abort();
|
2012-09-14 15:51:26 +00:00
|
|
|
|
audio: refactor how data is passed to AO
This replaces the two buffers (ao_chain.ao_buffer in the core, and
buffer_state.buffers in the AO) with a single queue. Instead of having a
byte based buffer, the queue is simply a list of audio frames, as output
by the decoder. This should make dataflow simpler and reduce copying.
It also attempts to simplify fill_audio_out_buffers(), the function I
always hated most, because it's full of subtle and buggy logic.
Unfortunately, I got assaulted by corner cases, dumb features (attempt
at seamless looping, really?), and other crap, so it got pretty
complicated again. fill_audio_out_buffers() is still full of subtle and
buggy logic. Maybe it got worse. On the other hand, maybe there really
is some progress. Who knows.
Originally, the data flow parts was meant to be in f_output_chain, but
due to tricky interactions with the playloop code, it's now in the dummy
filter in audio.c.
At least this improves the way the audio PTS is passed to the encoder in
encoding mode. Now it attempts to pass frames directly, along with the
pts, which should minimize timestamp problems. But to be honest, encoder
mode is one big kludge that shouldn't exist in this way.
This commit should be considered pre-alpha code. There are lots of bugs
still hiding.
2020-08-28 18:23:54 +00:00
|
|
|
frame->pts = rint(outpts * av_q2d(av_inv_q(encoder->time_base)));
|
2012-09-14 15:51:26 +00:00
|
|
|
|
audio: refactor how data is passed to AO
This replaces the two buffers (ao_chain.ao_buffer in the core, and
buffer_state.buffers in the AO) with a single queue. Instead of having a
byte based buffer, the queue is simply a list of audio frames, as output
by the decoder. This should make dataflow simpler and reduce copying.
It also attempts to simplify fill_audio_out_buffers(), the function I
always hated most, because it's full of subtle and buggy logic.
Unfortunately, I got assaulted by corner cases, dumb features (attempt
at seamless looping, really?), and other crap, so it got pretty
complicated again. fill_audio_out_buffers() is still full of subtle and
buggy logic. Maybe it got worse. On the other hand, maybe there really
is some progress. Who knows.
Originally, the data flow parts was meant to be in f_output_chain, but
due to tricky interactions with the playloop code, it's now in the dummy
filter in audio.c.
At least this improves the way the audio PTS is passed to the encoder in
encoding mode. Now it attempts to pass frames directly, along with the
pts, which should minimize timestamp problems. But to be honest, encoder
mode is one big kludge that shouldn't exist in this way.
This commit should be considered pre-alpha code. There are lots of bugs
still hiding.
2020-08-28 18:23:54 +00:00
|
|
|
int64_t frame_pts = av_rescale_q(frame->pts, encoder->time_base,
|
2020-03-22 12:07:24 +00:00
|
|
|
ac->worst_time_base);
|
audio: refactor how data is passed to AO
This replaces the two buffers (ao_chain.ao_buffer in the core, and
buffer_state.buffers in the AO) with a single queue. Instead of having a
byte based buffer, the queue is simply a list of audio frames, as output
by the decoder. This should make dataflow simpler and reduce copying.
It also attempts to simplify fill_audio_out_buffers(), the function I
always hated most, because it's full of subtle and buggy logic.
Unfortunately, I got assaulted by corner cases, dumb features (attempt
at seamless looping, really?), and other crap, so it got pretty
complicated again. fill_audio_out_buffers() is still full of subtle and
buggy logic. Maybe it got worse. On the other hand, maybe there really
is some progress. Who knows.
Originally, the data flow parts was meant to be in f_output_chain, but
due to tricky interactions with the playloop code, it's now in the dummy
filter in audio.c.
At least this improves the way the audio PTS is passed to the encoder in
encoding mode. Now it attempts to pass frames directly, along with the
pts, which should minimize timestamp problems. But to be honest, encoder
mode is one big kludge that shouldn't exist in this way.
This commit should be considered pre-alpha code. There are lots of bugs
still hiding.
2020-08-28 18:23:54 +00:00
|
|
|
if (ac->lastpts != AV_NOPTS_VALUE && frame_pts <= ac->lastpts) {
|
|
|
|
// whatever the fuck this code does?
|
|
|
|
MP_WARN(ao, "audio frame pts went backwards (%d <- %d), autofixed\n",
|
|
|
|
(int)frame->pts, (int)ac->lastpts);
|
|
|
|
frame_pts = ac->lastpts + 1;
|
2012-09-14 15:51:26 +00:00
|
|
|
ac->lastpts = frame_pts;
|
audio: refactor how data is passed to AO
This replaces the two buffers (ao_chain.ao_buffer in the core, and
buffer_state.buffers in the AO) with a single queue. Instead of having a
byte based buffer, the queue is simply a list of audio frames, as output
by the decoder. This should make dataflow simpler and reduce copying.
It also attempts to simplify fill_audio_out_buffers(), the function I
always hated most, because it's full of subtle and buggy logic.
Unfortunately, I got assaulted by corner cases, dumb features (attempt
at seamless looping, really?), and other crap, so it got pretty
complicated again. fill_audio_out_buffers() is still full of subtle and
buggy logic. Maybe it got worse. On the other hand, maybe there really
is some progress. Who knows.
Originally, the data flow parts was meant to be in f_output_chain, but
due to tricky interactions with the playloop code, it's now in the dummy
filter in audio.c.
At least this improves the way the audio PTS is passed to the encoder in
encoding mode. Now it attempts to pass frames directly, along with the
pts, which should minimize timestamp problems. But to be honest, encoder
mode is one big kludge that shouldn't exist in this way.
This commit should be considered pre-alpha code. There are lots of bugs
still hiding.
2020-08-28 18:23:54 +00:00
|
|
|
frame->pts = av_rescale_q(frame_pts, ac->worst_time_base,
|
|
|
|
encoder->time_base);
|
|
|
|
frame_pts = av_rescale_q(frame->pts, encoder->time_base,
|
|
|
|
ac->worst_time_base);
|
|
|
|
}
|
|
|
|
ac->lastpts = frame_pts;
|
2012-09-14 15:51:26 +00:00
|
|
|
|
audio: refactor how data is passed to AO
This replaces the two buffers (ao_chain.ao_buffer in the core, and
buffer_state.buffers in the AO) with a single queue. Instead of having a
byte based buffer, the queue is simply a list of audio frames, as output
by the decoder. This should make dataflow simpler and reduce copying.
It also attempts to simplify fill_audio_out_buffers(), the function I
always hated most, because it's full of subtle and buggy logic.
Unfortunately, I got assaulted by corner cases, dumb features (attempt
at seamless looping, really?), and other crap, so it got pretty
complicated again. fill_audio_out_buffers() is still full of subtle and
buggy logic. Maybe it got worse. On the other hand, maybe there really
is some progress. Who knows.
Originally, the data flow parts was meant to be in f_output_chain, but
due to tricky interactions with the playloop code, it's now in the dummy
filter in audio.c.
At least this improves the way the audio PTS is passed to the encoder in
encoding mode. Now it attempts to pass frames directly, along with the
pts, which should minimize timestamp problems. But to be honest, encoder
mode is one big kludge that shouldn't exist in this way.
This commit should be considered pre-alpha code. There are lots of bugs
still hiding.
2020-08-28 18:23:54 +00:00
|
|
|
frame->quality = encoder->global_quality;
|
|
|
|
encoder_encode(ac->enc, frame);
|
|
|
|
av_frame_free(&frame);
|
|
|
|
}
|
|
|
|
|
2020-09-03 13:39:31 +00:00
|
|
|
static bool write_frame(struct ao *ao, struct mp_frame frame)
|
audio: refactor how data is passed to AO
This replaces the two buffers (ao_chain.ao_buffer in the core, and
buffer_state.buffers in the AO) with a single queue. Instead of having a
byte based buffer, the queue is simply a list of audio frames, as output
by the decoder. This should make dataflow simpler and reduce copying.
It also attempts to simplify fill_audio_out_buffers(), the function I
always hated most, because it's full of subtle and buggy logic.
Unfortunately, I got assaulted by corner cases, dumb features (attempt
at seamless looping, really?), and other crap, so it got pretty
complicated again. fill_audio_out_buffers() is still full of subtle and
buggy logic. Maybe it got worse. On the other hand, maybe there really
is some progress. Who knows.
Originally, the data flow parts was meant to be in f_output_chain, but
due to tricky interactions with the playloop code, it's now in the dummy
filter in audio.c.
At least this improves the way the audio PTS is passed to the encoder in
encoding mode. Now it attempts to pass frames directly, along with the
pts, which should minimize timestamp problems. But to be honest, encoder
mode is one big kludge that shouldn't exist in this way.
This commit should be considered pre-alpha code. There are lots of bugs
still hiding.
2020-08-28 18:23:54 +00:00
|
|
|
{
|
|
|
|
struct priv *ac = ao->priv;
|
|
|
|
|
2020-09-03 13:39:31 +00:00
|
|
|
// Can't push in frame if it doesn't want it output one.
|
|
|
|
mp_pin_out_request_data(ac->fix_frame_size->pins[1]);
|
|
|
|
|
|
|
|
if (!mp_pin_in_write(ac->fix_frame_size->pins[0], frame))
|
|
|
|
return false; // shouldn't happen™
|
|
|
|
|
audio: refactor how data is passed to AO
This replaces the two buffers (ao_chain.ao_buffer in the core, and
buffer_state.buffers in the AO) with a single queue. Instead of having a
byte based buffer, the queue is simply a list of audio frames, as output
by the decoder. This should make dataflow simpler and reduce copying.
It also attempts to simplify fill_audio_out_buffers(), the function I
always hated most, because it's full of subtle and buggy logic.
Unfortunately, I got assaulted by corner cases, dumb features (attempt
at seamless looping, really?), and other crap, so it got pretty
complicated again. fill_audio_out_buffers() is still full of subtle and
buggy logic. Maybe it got worse. On the other hand, maybe there really
is some progress. Who knows.
Originally, the data flow parts was meant to be in f_output_chain, but
due to tricky interactions with the playloop code, it's now in the dummy
filter in audio.c.
At least this improves the way the audio PTS is passed to the encoder in
encoding mode. Now it attempts to pass frames directly, along with the
pts, which should minimize timestamp problems. But to be honest, encoder
mode is one big kludge that shouldn't exist in this way.
This commit should be considered pre-alpha code. There are lots of bugs
still hiding.
2020-08-28 18:23:54 +00:00
|
|
|
while (1) {
|
|
|
|
struct mp_frame fr = mp_pin_out_read(ac->fix_frame_size->pins[1]);
|
|
|
|
if (!fr.type)
|
|
|
|
break;
|
|
|
|
if (fr.type != MP_FRAME_AUDIO)
|
|
|
|
continue;
|
|
|
|
struct mp_aframe *af = fr.data;
|
|
|
|
encode(ao, af);
|
|
|
|
mp_frame_unref(&fr);
|
2018-04-19 18:13:28 +00:00
|
|
|
}
|
2020-09-03 13:39:31 +00:00
|
|
|
|
|
|
|
return true;
|
2012-09-14 15:51:26 +00:00
|
|
|
}
|
|
|
|
|
audio: redo internal AO API
This affects "pull" AOs only: ao_alsa, ao_pulse, ao_openal, ao_pcm,
ao_lavc. There are changes to the other AOs too, but that's only about
renaming ao_driver.resume to ao_driver.start.
ao_openal is broken because I didn't manage to fix it, so it exits with
an error message. If you want it, why don't _you_ put effort into it? I
see no reason to waste my own precious lifetime over this (I realize the
irony).
ao_alsa loses the poll() mechanism, but it was mostly broken and didn't
really do what it was supposed to. There doesn't seem to be anything in
the ALSA API to watch the playback status without polling (unless you
want to use raw UNIX signals).
No idea if ao_pulse is correct, or whether it's subtly broken now. There
is no documentation, so I can't tell what is correct, without reverse
engineering the whole project. I recommend using ALSA.
This was supposed to be just a simple fix, but somehow it expanded scope
like a train wreck. Very high chance of regressions, but probably only
for the AOs listed above. The rest you can figure out from reading the
diff.
2020-05-31 13:00:35 +00:00
|
|
|
static bool audio_write(struct ao *ao, void **data, int samples)
|
2012-09-14 15:51:26 +00:00
|
|
|
{
|
|
|
|
struct priv *ac = ao->priv;
|
|
|
|
struct encode_lavc_context *ectx = ao->encode_lavc_ctx;
|
audio: refactor how data is passed to AO
This replaces the two buffers (ao_chain.ao_buffer in the core, and
buffer_state.buffers in the AO) with a single queue. Instead of having a
byte based buffer, the queue is simply a list of audio frames, as output
by the decoder. This should make dataflow simpler and reduce copying.
It also attempts to simplify fill_audio_out_buffers(), the function I
always hated most, because it's full of subtle and buggy logic.
Unfortunately, I got assaulted by corner cases, dumb features (attempt
at seamless looping, really?), and other crap, so it got pretty
complicated again. fill_audio_out_buffers() is still full of subtle and
buggy logic. Maybe it got worse. On the other hand, maybe there really
is some progress. Who knows.
Originally, the data flow parts was meant to be in f_output_chain, but
due to tricky interactions with the playloop code, it's now in the dummy
filter in audio.c.
At least this improves the way the audio PTS is passed to the encoder in
encoding mode. Now it attempts to pass frames directly, along with the
pts, which should minimize timestamp problems. But to be honest, encoder
mode is one big kludge that shouldn't exist in this way.
This commit should be considered pre-alpha code. There are lots of bugs
still hiding.
2020-08-28 18:23:54 +00:00
|
|
|
|
|
|
|
// See ao_driver.write_frames.
|
|
|
|
struct mp_aframe *af = mp_aframe_new_ref(*(struct mp_aframe **)data);
|
|
|
|
|
2012-09-14 15:51:26 +00:00
|
|
|
double nextpts;
|
audio: refactor how data is passed to AO
This replaces the two buffers (ao_chain.ao_buffer in the core, and
buffer_state.buffers in the AO) with a single queue. Instead of having a
byte based buffer, the queue is simply a list of audio frames, as output
by the decoder. This should make dataflow simpler and reduce copying.
It also attempts to simplify fill_audio_out_buffers(), the function I
always hated most, because it's full of subtle and buggy logic.
Unfortunately, I got assaulted by corner cases, dumb features (attempt
at seamless looping, really?), and other crap, so it got pretty
complicated again. fill_audio_out_buffers() is still full of subtle and
buggy logic. Maybe it got worse. On the other hand, maybe there really
is some progress. Who knows.
Originally, the data flow parts was meant to be in f_output_chain, but
due to tricky interactions with the playloop code, it's now in the dummy
filter in audio.c.
At least this improves the way the audio PTS is passed to the encoder in
encoding mode. Now it attempts to pass frames directly, along with the
pts, which should minimize timestamp problems. But to be honest, encoder
mode is one big kludge that shouldn't exist in this way.
This commit should be considered pre-alpha code. There are lots of bugs
still hiding.
2020-08-28 18:23:54 +00:00
|
|
|
double pts = mp_aframe_get_pts(af);
|
|
|
|
double outpts = pts;
|
2012-09-14 15:51:26 +00:00
|
|
|
|
2018-04-22 17:40:36 +00:00
|
|
|
// for ectx PTS fields
|
2014-03-08 22:38:53 +00:00
|
|
|
pthread_mutex_lock(&ectx->lock);
|
|
|
|
|
audio: refactor how data is passed to AO
This replaces the two buffers (ao_chain.ao_buffer in the core, and
buffer_state.buffers in the AO) with a single queue. Instead of having a
byte based buffer, the queue is simply a list of audio frames, as output
by the decoder. This should make dataflow simpler and reduce copying.
It also attempts to simplify fill_audio_out_buffers(), the function I
always hated most, because it's full of subtle and buggy logic.
Unfortunately, I got assaulted by corner cases, dumb features (attempt
at seamless looping, really?), and other crap, so it got pretty
complicated again. fill_audio_out_buffers() is still full of subtle and
buggy logic. Maybe it got worse. On the other hand, maybe there really
is some progress. Who knows.
Originally, the data flow parts was meant to be in f_output_chain, but
due to tricky interactions with the playloop code, it's now in the dummy
filter in audio.c.
At least this improves the way the audio PTS is passed to the encoder in
encoding mode. Now it attempts to pass frames directly, along with the
pts, which should minimize timestamp problems. But to be honest, encoder
mode is one big kludge that shouldn't exist in this way.
This commit should be considered pre-alpha code. There are lots of bugs
still hiding.
2020-08-28 18:23:54 +00:00
|
|
|
if (!ectx->options->rawts) {
|
2018-04-29 00:55:27 +00:00
|
|
|
// Fix and apply the discontinuity pts offset.
|
2013-11-11 12:03:22 +00:00
|
|
|
nextpts = pts;
|
2012-09-25 09:53:29 +00:00
|
|
|
if (ectx->discontinuity_pts_offset == MP_NOPTS_VALUE) {
|
|
|
|
ectx->discontinuity_pts_offset = ectx->next_in_pts - nextpts;
|
2018-04-19 18:13:28 +00:00
|
|
|
} else if (fabs(nextpts + ectx->discontinuity_pts_offset -
|
|
|
|
ectx->next_in_pts) > 30)
|
|
|
|
{
|
2013-08-22 21:12:35 +00:00
|
|
|
MP_WARN(ao, "detected an unexpected discontinuity (pts jumped by "
|
2012-09-25 09:53:29 +00:00
|
|
|
"%f seconds)\n",
|
|
|
|
nextpts + ectx->discontinuity_pts_offset - ectx->next_in_pts);
|
|
|
|
ectx->discontinuity_pts_offset = ectx->next_in_pts - nextpts;
|
|
|
|
}
|
|
|
|
|
|
|
|
outpts = pts + ectx->discontinuity_pts_offset;
|
2013-11-11 12:03:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Shift pts by the pts offset first.
|
audio: refactor how data is passed to AO
This replaces the two buffers (ao_chain.ao_buffer in the core, and
buffer_state.buffers in the AO) with a single queue. Instead of having a
byte based buffer, the queue is simply a list of audio frames, as output
by the decoder. This should make dataflow simpler and reduce copying.
It also attempts to simplify fill_audio_out_buffers(), the function I
always hated most, because it's full of subtle and buggy logic.
Unfortunately, I got assaulted by corner cases, dumb features (attempt
at seamless looping, really?), and other crap, so it got pretty
complicated again. fill_audio_out_buffers() is still full of subtle and
buggy logic. Maybe it got worse. On the other hand, maybe there really
is some progress. Who knows.
Originally, the data flow parts was meant to be in f_output_chain, but
due to tricky interactions with the playloop code, it's now in the dummy
filter in audio.c.
At least this improves the way the audio PTS is passed to the encoder in
encoding mode. Now it attempts to pass frames directly, along with the
pts, which should minimize timestamp problems. But to be honest, encoder
mode is one big kludge that shouldn't exist in this way.
This commit should be considered pre-alpha code. There are lots of bugs
still hiding.
2020-08-28 18:23:54 +00:00
|
|
|
outpts += encoder_get_offset(ac->enc);
|
2012-09-14 15:51:26 +00:00
|
|
|
|
2013-11-11 12:03:22 +00:00
|
|
|
// Calculate expected pts of next audio frame (input side).
|
audio: refactor how data is passed to AO
This replaces the two buffers (ao_chain.ao_buffer in the core, and
buffer_state.buffers in the AO) with a single queue. Instead of having a
byte based buffer, the queue is simply a list of audio frames, as output
by the decoder. This should make dataflow simpler and reduce copying.
It also attempts to simplify fill_audio_out_buffers(), the function I
always hated most, because it's full of subtle and buggy logic.
Unfortunately, I got assaulted by corner cases, dumb features (attempt
at seamless looping, really?), and other crap, so it got pretty
complicated again. fill_audio_out_buffers() is still full of subtle and
buggy logic. Maybe it got worse. On the other hand, maybe there really
is some progress. Who knows.
Originally, the data flow parts was meant to be in f_output_chain, but
due to tricky interactions with the playloop code, it's now in the dummy
filter in audio.c.
At least this improves the way the audio PTS is passed to the encoder in
encoding mode. Now it attempts to pass frames directly, along with the
pts, which should minimize timestamp problems. But to be honest, encoder
mode is one big kludge that shouldn't exist in this way.
This commit should be considered pre-alpha code. There are lots of bugs
still hiding.
2020-08-28 18:23:54 +00:00
|
|
|
ac->expected_next_pts = pts + mp_aframe_get_size(af) / (double) ao->samplerate;
|
2018-04-22 17:40:36 +00:00
|
|
|
|
2013-11-11 12:03:22 +00:00
|
|
|
// Set next allowed input pts value (input side).
|
audio: refactor how data is passed to AO
This replaces the two buffers (ao_chain.ao_buffer in the core, and
buffer_state.buffers in the AO) with a single queue. Instead of having a
byte based buffer, the queue is simply a list of audio frames, as output
by the decoder. This should make dataflow simpler and reduce copying.
It also attempts to simplify fill_audio_out_buffers(), the function I
always hated most, because it's full of subtle and buggy logic.
Unfortunately, I got assaulted by corner cases, dumb features (attempt
at seamless looping, really?), and other crap, so it got pretty
complicated again. fill_audio_out_buffers() is still full of subtle and
buggy logic. Maybe it got worse. On the other hand, maybe there really
is some progress. Who knows.
Originally, the data flow parts was meant to be in f_output_chain, but
due to tricky interactions with the playloop code, it's now in the dummy
filter in audio.c.
At least this improves the way the audio PTS is passed to the encoder in
encoding mode. Now it attempts to pass frames directly, along with the
pts, which should minimize timestamp problems. But to be honest, encoder
mode is one big kludge that shouldn't exist in this way.
This commit should be considered pre-alpha code. There are lots of bugs
still hiding.
2020-08-28 18:23:54 +00:00
|
|
|
if (!ectx->options->rawts) {
|
2012-09-25 09:53:29 +00:00
|
|
|
nextpts = ac->expected_next_pts + ectx->discontinuity_pts_offset;
|
|
|
|
if (nextpts > ectx->next_in_pts)
|
|
|
|
ectx->next_in_pts = nextpts;
|
|
|
|
}
|
2012-09-14 15:51:26 +00:00
|
|
|
|
audio: refactor how data is passed to AO
This replaces the two buffers (ao_chain.ao_buffer in the core, and
buffer_state.buffers in the AO) with a single queue. Instead of having a
byte based buffer, the queue is simply a list of audio frames, as output
by the decoder. This should make dataflow simpler and reduce copying.
It also attempts to simplify fill_audio_out_buffers(), the function I
always hated most, because it's full of subtle and buggy logic.
Unfortunately, I got assaulted by corner cases, dumb features (attempt
at seamless looping, really?), and other crap, so it got pretty
complicated again. fill_audio_out_buffers() is still full of subtle and
buggy logic. Maybe it got worse. On the other hand, maybe there really
is some progress. Who knows.
Originally, the data flow parts was meant to be in f_output_chain, but
due to tricky interactions with the playloop code, it's now in the dummy
filter in audio.c.
At least this improves the way the audio PTS is passed to the encoder in
encoding mode. Now it attempts to pass frames directly, along with the
pts, which should minimize timestamp problems. But to be honest, encoder
mode is one big kludge that shouldn't exist in this way.
This commit should be considered pre-alpha code. There are lots of bugs
still hiding.
2020-08-28 18:23:54 +00:00
|
|
|
pthread_mutex_unlock(&ectx->lock);
|
2014-07-16 13:08:06 +00:00
|
|
|
|
audio: refactor how data is passed to AO
This replaces the two buffers (ao_chain.ao_buffer in the core, and
buffer_state.buffers in the AO) with a single queue. Instead of having a
byte based buffer, the queue is simply a list of audio frames, as output
by the decoder. This should make dataflow simpler and reduce copying.
It also attempts to simplify fill_audio_out_buffers(), the function I
always hated most, because it's full of subtle and buggy logic.
Unfortunately, I got assaulted by corner cases, dumb features (attempt
at seamless looping, really?), and other crap, so it got pretty
complicated again. fill_audio_out_buffers() is still full of subtle and
buggy logic. Maybe it got worse. On the other hand, maybe there really
is some progress. Who knows.
Originally, the data flow parts was meant to be in f_output_chain, but
due to tricky interactions with the playloop code, it's now in the dummy
filter in audio.c.
At least this improves the way the audio PTS is passed to the encoder in
encoding mode. Now it attempts to pass frames directly, along with the
pts, which should minimize timestamp problems. But to be honest, encoder
mode is one big kludge that shouldn't exist in this way.
This commit should be considered pre-alpha code. There are lots of bugs
still hiding.
2020-08-28 18:23:54 +00:00
|
|
|
mp_aframe_set_pts(af, outpts);
|
2014-07-16 13:08:06 +00:00
|
|
|
|
2020-09-03 13:39:31 +00:00
|
|
|
return write_frame(ao, MAKE_FRAME(MP_FRAME_AUDIO, af));
|
audio: redo internal AO API
This affects "pull" AOs only: ao_alsa, ao_pulse, ao_openal, ao_pcm,
ao_lavc. There are changes to the other AOs too, but that's only about
renaming ao_driver.resume to ao_driver.start.
ao_openal is broken because I didn't manage to fix it, so it exits with
an error message. If you want it, why don't _you_ put effort into it? I
see no reason to waste my own precious lifetime over this (I realize the
irony).
ao_alsa loses the poll() mechanism, but it was mostly broken and didn't
really do what it was supposed to. There doesn't seem to be anything in
the ALSA API to watch the playback status without polling (unless you
want to use raw UNIX signals).
No idea if ao_pulse is correct, or whether it's subtly broken now. There
is no documentation, so I can't tell what is correct, without reverse
engineering the whole project. I recommend using ALSA.
This was supposed to be just a simple fix, but somehow it expanded scope
like a train wreck. Very high chance of regressions, but probably only
for the AOs listed above. The rest you can figure out from reading the
diff.
2020-05-31 13:00:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void get_state(struct ao *ao, struct mp_pcm_state *state)
|
|
|
|
{
|
audio: refactor how data is passed to AO
This replaces the two buffers (ao_chain.ao_buffer in the core, and
buffer_state.buffers in the AO) with a single queue. Instead of having a
byte based buffer, the queue is simply a list of audio frames, as output
by the decoder. This should make dataflow simpler and reduce copying.
It also attempts to simplify fill_audio_out_buffers(), the function I
always hated most, because it's full of subtle and buggy logic.
Unfortunately, I got assaulted by corner cases, dumb features (attempt
at seamless looping, really?), and other crap, so it got pretty
complicated again. fill_audio_out_buffers() is still full of subtle and
buggy logic. Maybe it got worse. On the other hand, maybe there really
is some progress. Who knows.
Originally, the data flow parts was meant to be in f_output_chain, but
due to tricky interactions with the playloop code, it's now in the dummy
filter in audio.c.
At least this improves the way the audio PTS is passed to the encoder in
encoding mode. Now it attempts to pass frames directly, along with the
pts, which should minimize timestamp problems. But to be honest, encoder
mode is one big kludge that shouldn't exist in this way.
This commit should be considered pre-alpha code. There are lots of bugs
still hiding.
2020-08-28 18:23:54 +00:00
|
|
|
state->free_samples = 1;
|
audio: redo internal AO API
This affects "pull" AOs only: ao_alsa, ao_pulse, ao_openal, ao_pcm,
ao_lavc. There are changes to the other AOs too, but that's only about
renaming ao_driver.resume to ao_driver.start.
ao_openal is broken because I didn't manage to fix it, so it exits with
an error message. If you want it, why don't _you_ put effort into it? I
see no reason to waste my own precious lifetime over this (I realize the
irony).
ao_alsa loses the poll() mechanism, but it was mostly broken and didn't
really do what it was supposed to. There doesn't seem to be anything in
the ALSA API to watch the playback status without polling (unless you
want to use raw UNIX signals).
No idea if ao_pulse is correct, or whether it's subtly broken now. There
is no documentation, so I can't tell what is correct, without reverse
engineering the whole project. I recommend using ALSA.
This was supposed to be just a simple fix, but somehow it expanded scope
like a train wreck. Very high chance of regressions, but probably only
for the AOs listed above. The rest you can figure out from reading the
diff.
2020-05-31 13:00:35 +00:00
|
|
|
state->queued_samples = 0;
|
|
|
|
state->delay = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool set_pause(struct ao *ao, bool paused)
|
|
|
|
{
|
|
|
|
return true; // signal support so common code doesn't write silence
|
|
|
|
}
|
2014-06-12 09:42:00 +00:00
|
|
|
|
audio: redo internal AO API
This affects "pull" AOs only: ao_alsa, ao_pulse, ao_openal, ao_pcm,
ao_lavc. There are changes to the other AOs too, but that's only about
renaming ao_driver.resume to ao_driver.start.
ao_openal is broken because I didn't manage to fix it, so it exits with
an error message. If you want it, why don't _you_ put effort into it? I
see no reason to waste my own precious lifetime over this (I realize the
irony).
ao_alsa loses the poll() mechanism, but it was mostly broken and didn't
really do what it was supposed to. There doesn't seem to be anything in
the ALSA API to watch the playback status without polling (unless you
want to use raw UNIX signals).
No idea if ao_pulse is correct, or whether it's subtly broken now. There
is no documentation, so I can't tell what is correct, without reverse
engineering the whole project. I recommend using ALSA.
This was supposed to be just a simple fix, but somehow it expanded scope
like a train wreck. Very high chance of regressions, but probably only
for the AOs listed above. The rest you can figure out from reading the
diff.
2020-05-31 13:00:35 +00:00
|
|
|
static void start(struct ao *ao)
|
|
|
|
{
|
|
|
|
// we use data immediately
|
|
|
|
}
|
|
|
|
|
|
|
|
static void reset(struct ao *ao)
|
|
|
|
{
|
2012-09-14 15:51:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const struct ao_driver audio_out_lavc = {
|
2013-02-06 21:54:03 +00:00
|
|
|
.encode = true,
|
2013-10-23 17:07:27 +00:00
|
|
|
.description = "audio encoding using libavcodec",
|
|
|
|
.name = "lavc",
|
2018-04-29 17:42:18 +00:00
|
|
|
.initially_blocked = true,
|
audio: refactor how data is passed to AO
This replaces the two buffers (ao_chain.ao_buffer in the core, and
buffer_state.buffers in the AO) with a single queue. Instead of having a
byte based buffer, the queue is simply a list of audio frames, as output
by the decoder. This should make dataflow simpler and reduce copying.
It also attempts to simplify fill_audio_out_buffers(), the function I
always hated most, because it's full of subtle and buggy logic.
Unfortunately, I got assaulted by corner cases, dumb features (attempt
at seamless looping, really?), and other crap, so it got pretty
complicated again. fill_audio_out_buffers() is still full of subtle and
buggy logic. Maybe it got worse. On the other hand, maybe there really
is some progress. Who knows.
Originally, the data flow parts was meant to be in f_output_chain, but
due to tricky interactions with the playloop code, it's now in the dummy
filter in audio.c.
At least this improves the way the audio PTS is passed to the encoder in
encoding mode. Now it attempts to pass frames directly, along with the
pts, which should minimize timestamp problems. But to be honest, encoder
mode is one big kludge that shouldn't exist in this way.
This commit should be considered pre-alpha code. There are lots of bugs
still hiding.
2020-08-28 18:23:54 +00:00
|
|
|
.write_frames = true,
|
2018-04-22 17:40:36 +00:00
|
|
|
.priv_size = sizeof(struct priv),
|
2012-09-14 15:51:26 +00:00
|
|
|
.init = init,
|
|
|
|
.uninit = uninit,
|
audio: redo internal AO API
This affects "pull" AOs only: ao_alsa, ao_pulse, ao_openal, ao_pcm,
ao_lavc. There are changes to the other AOs too, but that's only about
renaming ao_driver.resume to ao_driver.start.
ao_openal is broken because I didn't manage to fix it, so it exits with
an error message. If you want it, why don't _you_ put effort into it? I
see no reason to waste my own precious lifetime over this (I realize the
irony).
ao_alsa loses the poll() mechanism, but it was mostly broken and didn't
really do what it was supposed to. There doesn't seem to be anything in
the ALSA API to watch the playback status without polling (unless you
want to use raw UNIX signals).
No idea if ao_pulse is correct, or whether it's subtly broken now. There
is no documentation, so I can't tell what is correct, without reverse
engineering the whole project. I recommend using ALSA.
This was supposed to be just a simple fix, but somehow it expanded scope
like a train wreck. Very high chance of regressions, but probably only
for the AOs listed above. The rest you can figure out from reading the
diff.
2020-05-31 13:00:35 +00:00
|
|
|
.get_state = get_state,
|
|
|
|
.set_pause = set_pause,
|
|
|
|
.write = audio_write,
|
|
|
|
.start = start,
|
|
|
|
.reset = reset,
|
2012-09-14 15:51:26 +00:00
|
|
|
};
|
2016-06-24 18:20:32 +00:00
|
|
|
|
|
|
|
// vim: sw=4 ts=4 et tw=80
|