mirror of
https://github.com/mpv-player/mpv.git
synced 2025-12-28 05:33:14 +00:00
audio: change playback restart and resyncing
This commit makes audio decoding non-blocking. If e.g. the network is
too slow the playloop will just go to sleep, instead of blocking until
enough data is available.
For video, this was already done with commit 7083f88c. For audio, it's
unfortunately much more complicated, because the audio decoder was used
in a blocking manner. Large changes are required to get around this.
The whole playback restart mechanism must be turned into a statemachine,
especially since it has close interactions with video restart. Lots of
video code is thus also changed.
(For the record, I don't think switching this code to threads would
make this conceptually easier: the code would still have to deal with
external input while blocked, so these in-between states do get visible
[and thus need to be handled] anyway. On the other hand, it certainly
should be possible to modularize this code a bit better.)
This will probably cause a bunch of regressions.
This commit is contained in:
@@ -309,8 +309,10 @@ static int decode_packet(struct dec_audio *da)
|
||||
mp_audio_set_null_data(&da->decoded);
|
||||
|
||||
struct demux_packet *mpkt = priv->packet;
|
||||
if (!mpkt)
|
||||
mpkt = demux_read_packet(da->header);
|
||||
if (!mpkt) {
|
||||
if (demux_read_packet_async(da->header, &mpkt) == 0)
|
||||
return AD_WAIT;
|
||||
}
|
||||
|
||||
priv->packet = talloc_steal(priv, mpkt);
|
||||
|
||||
@@ -343,7 +345,7 @@ static int decode_packet(struct dec_audio *da)
|
||||
}
|
||||
// LATM may need many packets to find mux info
|
||||
if (ret == AVERROR(EAGAIN))
|
||||
return 0;
|
||||
return AD_OK;
|
||||
}
|
||||
if (ret < 0) {
|
||||
MP_ERR(da, "Error decoding audio.\n");
|
||||
|
||||
@@ -218,7 +218,9 @@ static int decode_packet(struct dec_audio *da)
|
||||
|
||||
mp_audio_set_null_data(&da->decoded);
|
||||
|
||||
struct demux_packet *pkt = demux_read_packet(da->header);
|
||||
struct demux_packet *pkt;
|
||||
if (demux_read_packet_async(da->header, &pkt) == 0)
|
||||
return AD_WAIT;
|
||||
if (!pkt)
|
||||
return AD_EOF;
|
||||
|
||||
|
||||
@@ -191,7 +191,10 @@ static int decode_packet(struct dec_audio *da)
|
||||
|
||||
spdif_ctx->out_buffer_len = 0;
|
||||
|
||||
struct demux_packet *mpkt = demux_read_packet(da->header);
|
||||
struct demux_packet *mpkt;
|
||||
if (demux_read_packet_async(da->header, &mpkt) == 0)
|
||||
return AD_WAIT;
|
||||
|
||||
if (!mpkt)
|
||||
return AD_EOF;
|
||||
|
||||
|
||||
@@ -89,27 +89,7 @@ static int init_audio_codec(struct dec_audio *d_audio, const char *decoder)
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Decode enough until we know the audio format.
|
||||
for (int tries = 1; ; tries++) {
|
||||
if (mp_audio_config_valid(&d_audio->decoded)) {
|
||||
MP_VERBOSE(d_audio, "Initial decode succeeded after %d packets.\n",
|
||||
tries);
|
||||
break;
|
||||
}
|
||||
if (tries >= 50) {
|
||||
MP_ERR(d_audio, "initial decode failed\n");
|
||||
uninit_decoder(d_audio);
|
||||
return 0;
|
||||
}
|
||||
d_audio->ad_driver->decode_packet(d_audio);
|
||||
}
|
||||
|
||||
d_audio->decode_buffer = mp_audio_buffer_create(NULL);
|
||||
if (!reinit_audio_buffer(d_audio)) {
|
||||
uninit_decoder(d_audio);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -171,9 +151,6 @@ int audio_init_best_codec(struct dec_audio *d_audio, char *audio_decoders)
|
||||
talloc_asprintf(d_audio, "%s [%s:%s]", decoder->desc, decoder->family,
|
||||
decoder->decoder);
|
||||
MP_VERBOSE(d_audio, "Selected audio codec: %s\n", d_audio->decoder_desc);
|
||||
MP_VERBOSE(d_audio, "AUDIO: %d Hz, %d ch, %s\n",
|
||||
d_audio->decoded.rate, d_audio->decoded.channels.num,
|
||||
af_fmt_to_str(d_audio->decoded.format));
|
||||
} else {
|
||||
MP_ERR(d_audio, "Failed to initialize an audio decoder for codec '%s'.\n",
|
||||
d_audio->header->codec ? d_audio->header->codec : "<unknown>");
|
||||
@@ -238,6 +215,24 @@ int audio_init_filters(struct dec_audio *d_audio, int in_samplerate,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Decode packets until we know the audio format. Then reinit the buffer.
|
||||
* Returns AD_OK on success, negative AD_* code otherwise.
|
||||
* Also returns AD_OK if already initialized (and does nothing).
|
||||
*/
|
||||
int initial_audio_decode(struct dec_audio *da)
|
||||
{
|
||||
while (!mp_audio_config_valid(&da->decoded)) {
|
||||
if (da->decoded.samples > 0)
|
||||
return AD_ERR; // invalid format, rather than uninitialized
|
||||
int ret = da->ad_driver->decode_packet(da);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
if (mp_audio_buffer_samples(da->decode_buffer) > 0) // avoid accidental flush
|
||||
return AD_OK;
|
||||
return reinit_audio_buffer(da) ? AD_OK : AD_ERR;
|
||||
}
|
||||
|
||||
// Filter len bytes of input, put result into outbuf.
|
||||
static int filter_n_bytes(struct dec_audio *da, struct mp_audio_buffer *outbuf,
|
||||
int len)
|
||||
@@ -270,6 +265,9 @@ static int filter_n_bytes(struct dec_audio *da, struct mp_audio_buffer *outbuf,
|
||||
break;
|
||||
}
|
||||
|
||||
if (error == AD_WAIT)
|
||||
return error;
|
||||
|
||||
// Filter
|
||||
struct mp_audio filter_data;
|
||||
mp_audio_buffer_peek(da->decode_buffer, &filter_data);
|
||||
@@ -306,6 +304,9 @@ static int filter_n_bytes(struct dec_audio *da, struct mp_audio_buffer *outbuf,
|
||||
int audio_decode(struct dec_audio *d_audio, struct mp_audio_buffer *outbuf,
|
||||
int minsamples)
|
||||
{
|
||||
if (!d_audio->afilter)
|
||||
return AD_ERR;
|
||||
|
||||
// Indicates that a filter seems to be buffering large amounts of data
|
||||
int huge_filter_buffer = 0;
|
||||
|
||||
|
||||
@@ -51,15 +51,16 @@ struct dec_audio {
|
||||
enum {
|
||||
AD_OK = 0,
|
||||
AD_ERR = -1,
|
||||
AD_NEW_FMT = -2,
|
||||
AD_ASYNC_PLAY_DONE = -3,
|
||||
AD_EOF = -4,
|
||||
AD_EOF = -2,
|
||||
AD_NEW_FMT = -3,
|
||||
AD_WAIT = -4,
|
||||
};
|
||||
|
||||
struct mp_decoder_list *audio_decoder_list(void);
|
||||
int audio_init_best_codec(struct dec_audio *d_audio, char *audio_decoders);
|
||||
int audio_decode(struct dec_audio *d_audio, struct mp_audio_buffer *outbuf,
|
||||
int minsamples);
|
||||
int initial_audio_decode(struct dec_audio *d_audio);
|
||||
void audio_reset_decoding(struct dec_audio *d_audio);
|
||||
void audio_uninit(struct dec_audio *d_audio);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user