// 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) { int error = 0; struct mp_audio config; mp_audio_buffer_get_format(da->decode_buffer, &config); while (mp_audio_buffer_samples(da->decode_buffer) < len) { int maxlen = mp_audio_buffer_get_write_available(da->decode_buffer); if (maxlen < DECODE_MAX_UNIT) break; struct mp_audio buffer; mp_audio_buffer_get_write_buffer(da->decode_buffer, maxlen, &buffer); buffer.samples = 0; error = da->ad_driver->decode_audio(da, &buffer, maxlen); if (error < 0) break; // Commit the data just read as valid data mp_audio_buffer_finish_write(da->decode_buffer, buffer.samples); // Format change if (!mp_audio_config_equals(&da->decoded, &config)) { // If there are still samples left in the buffer, let them drain // first, and don't signal a format change to the caller yet. if (mp_audio_buffer_samples(da->decode_buffer) > 0) break; error = -2; break; } } // Filter struct mp_audio filter_data; mp_audio_buffer_peek(da->decode_buffer, &filter_data); filter_data.rate = da->afilter->input.rate; // due to playback speed change len = MPMIN(filter_data.samples, len); filter_data.samples = len; bool eof = filter_data.samples == 0 && error < 0; if (af_filter(da->afilter, &filter_data, eof ? AF_FILTER_FLAG_EOF : 0) < 0) return -1; mp_audio_buffer_append(outbuf, &filter_data); if (eof && filter_data.samples > 0) error = 0; // don't end playback yet // remove processed data from decoder buffer: mp_audio_buffer_skip(da->decode_buffer, len); // Assume the filter chain is drained from old data at this point. // (If not, the remaining old data is discarded.) if (error == -2) { if (!reinit_audio_buffer(da)) error = -1; // switch to invalid format } return error; }
/* 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; }
static int init_audio_codec(struct dec_audio *d_audio, const char *decoder) { if (!d_audio->ad_driver->init(d_audio, decoder)) { MP_VERBOSE(d_audio, "Audio decoder init failed.\n"); d_audio->ad_driver = NULL; uninit_decoder(d_audio); return 0; } d_audio->decode_buffer = mp_audio_buffer_create(NULL); if (!reinit_audio_buffer(d_audio)) { uninit_decoder(d_audio); return 0; } return 1; }
static int init_audio_codec(struct dec_audio *d_audio, const char *decoder) { if (!d_audio->ad_driver->init(d_audio, decoder)) { mp_tmsg(MSGT_DECAUDIO, MSGL_V, "Audio decoder init failed.\n"); d_audio->ad_driver = NULL; uninit_decoder(d_audio); return 0; } if (!d_audio->decoded.channels.num || !d_audio->decoded.rate || !d_audio->decoded.format) { mp_tmsg(MSGT_DECAUDIO, MSGL_ERR, "Audio decoder did not specify " "audio format!\n"); uninit_decoder(d_audio); return 0; } d_audio->decode_buffer = mp_audio_buffer_create(NULL); reinit_audio_buffer(d_audio); return 1; }
// 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) { bool format_change = false; int error = 0; assert(len > 0); // would break EOF logic below while (mp_audio_buffer_samples(da->decode_buffer) < len) { // Check for a format change struct mp_audio config; mp_audio_buffer_get_format(da->decode_buffer, &config); format_change = !mp_audio_config_equals(&da->decoded, &config); if (format_change) { error = AD_EOF; // drain remaining data left in the current buffer break; } if (da->decoded.samples > 0) { int copy = MPMIN(da->decoded.samples, len); struct mp_audio append = da->decoded; append.samples = copy; mp_audio_buffer_append(da->decode_buffer, &append); mp_audio_skip_samples(&da->decoded, copy); da->pts_offset += copy; continue; } error = da->ad_driver->decode_packet(da); if (error < 0) break; } if (error == AD_WAIT) return error; // Filter struct mp_audio filter_data; mp_audio_buffer_peek(da->decode_buffer, &filter_data); filter_data.rate = da->afilter->input.rate; // due to playback speed change len = MPMIN(filter_data.samples, len); filter_data.samples = len; bool eof = error == AD_EOF && filter_data.samples == 0; if (af_filter(da->afilter, &filter_data, eof ? AF_FILTER_FLAG_EOF : 0) < 0) return AD_ERR; mp_audio_buffer_append(outbuf, &filter_data); if (error == AD_EOF && filter_data.samples > 0) error = 0; // don't end playback yet // remove processed data from decoder buffer: mp_audio_buffer_skip(da->decode_buffer, len); // if format was changed, and all data was drained, execute the format change if (format_change && eof) { error = AD_NEW_FMT; if (!reinit_audio_buffer(da)) error = AD_ERR; // switch to invalid format } return error; }