Fix continuous accumulation of audio samples for big txt inputs.
Showing the changes to libavfilter (1 of 1 file). Show all
Unified · Split
| @@ -24,6 +24,8 @@ · 23 unmodified lines | ||
| 24 | 24 | */ |
| 25 | 25 | |
| 26 | 26 | #include <flite/flite.h> |
| 27 | +#include "libavutil/audio_fifo.h" | |
| 28 | +#include "libavutil/avstring.h" | |
| 27 | 29 | #include "libavutil/channel_layout.h" |
| 28 | 30 | #include "libavutil/file.h" |
| 29 | 31 | #include "libavutil/opt.h" |
| @@ -39,11 +41,14 @@ typedef struct FliteContext { · 9 unmodified lines | ||
| 39 | 41 | char *voice_str; |
| 40 | 42 | char *textfile; |
| 41 | 43 | char *text; |
| 42 | − cst_wave *wave; | |
| 43 | − int16_t *wave_samples; | |
| 44 | − int wave_nb_samples; | |
| 44 | + char *text_p; | |
| 45 | + char *text_saveptr; | |
| 46 | + int nb_channels; | |
| 47 | + int sample_rate; | |
| 48 | + AVAudioFifo *fifo; | |
| 45 | 49 | int list_voices; |
| 46 | 50 | cst_voice *voice; |
| 51 | + cst_audio_streaming_info *asi; | |
| 47 | 52 | struct voice_entry *voice_entry; |
| 48 | 53 | int64_t pts; |
| 49 | 54 | int frame_nb_samples; ///< number of samples per frame |
| @@ -140,10 +145,30 @@ static int select_voice(struct voice_entry **entry_ret, const char *voice_name, · 90 unmodified lines | ||
| 140 | 145 | return AVERROR(EINVAL); |
| 141 | 146 | } |
| 142 | 147 | |
| 148 | +static int audio_stream_chunk_by_word(const cst_wave *wave, int start, int size, | |
| 149 | + int last, cst_audio_streaming_info *asi) | |
| 150 | +{ | |
| 151 | + FliteContext *flite = asi->userdata; | |
| 152 | + void *const ptr[8] = { &wave->samples[start] }; | |
| 153 | + | |
| 154 | + flite->nb_channels = wave->num_channels; | |
| 155 | + flite->sample_rate = wave->sample_rate; | |
| 156 | + if (!flite->fifo) { | |
| 157 | + flite->fifo = av_audio_fifo_alloc(AV_SAMPLE_FMT_S16, flite->nb_channels, size); | |
| 158 | + if (!flite->fifo) | |
| 159 | + return CST_AUDIO_STREAM_STOP; | |
| 160 | + } | |
| 161 | + | |
| 162 | + av_audio_fifo_write(flite->fifo, ptr, size); | |
| 163 | + | |
| 164 | + return CST_AUDIO_STREAM_CONT; | |
| 165 | +} | |
| 166 | + | |
| 143 | 167 | static av_cold int init(AVFilterContext *ctx) |
| 144 | 168 | { |
| 145 | 169 | FliteContext *flite = ctx->priv; |
| 146 | 170 | int ret = 0; |
| 171 | + char *text; | |
| 147 | 172 | |
| 148 | 173 | if (flite->list_voices) { |
| 149 | 174 | list_voices(ctx, "\n"); |
| @@ -197,10 +222,21 @@ static av_cold int init(AVFilterContext *ctx) · 47 unmodified lines | ||
| 197 | 222 | return AVERROR(EINVAL); |
| 198 | 223 | } |
| 199 | 224 | |
| 200 | − /* synth all the file data in block */ | |
| 201 | − flite->wave = flite_text_to_wave(flite->text, flite->voice); | |
| 202 | − flite->wave_samples = flite->wave->samples; | |
| 203 | − flite->wave_nb_samples = flite->wave->num_samples; | |
| 225 | + flite->asi = new_audio_streaming_info(); | |
| 226 | + if (!flite->asi) | |
| 227 | + return AVERROR_BUG; | |
| 228 | + | |
| 229 | + flite->asi->asc = audio_stream_chunk_by_word; | |
| 230 | + flite->asi->userdata = flite; | |
| 231 | + feat_set(flite->voice->features, "streaming_info", audio_streaming_info_val(flite->asi)); | |
| 232 | + | |
| 233 | + flite->text_p = flite->text; | |
| 234 | + if (!(text = av_strtok(flite->text_p, "\n", &flite->text_saveptr))) | |
| 235 | + return AVERROR(EINVAL); | |
| 236 | + flite->text_p = NULL; | |
| 237 | + | |
| 238 | + flite_text_to_speech(text, flite->voice, "none"); | |
| 239 | + | |
| 204 | 240 | return 0; |
| 205 | 241 | } |
| 206 | 242 | |
| @@ -216,8 +252,7 @@ static av_cold void uninit(AVFilterContext *ctx) · 9 unmodified lines | ||
| 216 | 252 | } |
| 217 | 253 | pthread_mutex_unlock(&flite_mutex); |
| 218 | 254 | } |
| 219 | − delete_wave(flite->wave); | |
| 220 | − flite->wave = NULL; | |
| 255 | + av_audio_fifo_free(flite->fifo); | |
| 221 | 256 | } |
| 222 | 257 | |
| 223 | 258 | static int query_formats(AVFilterContext *ctx) |
| @@ -230,13 +265,13 @@ static int query_formats(AVFilterContext *ctx) · 6 unmodified lines | ||
| 230 | 265 | AVFilterFormats *sample_rates = NULL; |
| 231 | 266 | AVChannelLayout chlayout = { 0 }; |
| 232 | 267 | |
| 233 | − av_channel_layout_default(&chlayout, flite->wave->num_channels); | |
| 268 | + av_channel_layout_default(&chlayout, flite->nb_channels); | |
| 234 | 269 | |
| 235 | 270 | if ((ret = ff_add_channel_layout (&chlayouts , &chlayout )) < 0 || |
| 236 | 271 | (ret = ff_set_common_channel_layouts (ctx , chlayouts )) < 0 || |
| 237 | 272 | (ret = ff_add_format (&sample_formats, AV_SAMPLE_FMT_S16 )) < 0 || |
| 238 | 273 | (ret = ff_set_common_formats (ctx , sample_formats )) < 0 || |
| 239 | − (ret = ff_add_format (&sample_rates , flite->wave->sample_rate)) < 0 || | |
| 274 | + (ret = ff_add_format (&sample_rates , flite->sample_rate )) < 0 || | |
| 240 | 275 | (ret = ff_set_common_samplerates (ctx , sample_rates )) < 0) |
| 241 | 276 | return ret; |
| 242 | 277 | |
| @@ -248,12 +283,13 @@ static int config_props(AVFilterLink *outlink) · 5 unmodified lines | ||
| 248 | 283 | AVFilterContext *ctx = outlink->src; |
| 249 | 284 | FliteContext *flite = ctx->priv; |
| 250 | 285 | |
| 251 | − outlink->sample_rate = flite->wave->sample_rate; | |
| 252 | − outlink->time_base = (AVRational){1, flite->wave->sample_rate}; | |
| 286 | + outlink->sample_rate = flite->sample_rate; | |
| 287 | + outlink->time_base = (AVRational){1, flite->sample_rate}; | |
| 253 | 288 | |
| 254 | 289 | av_log(ctx, AV_LOG_VERBOSE, "voice:%s fmt:%s sample_rate:%d\n", |
| 255 | 290 | flite->voice_str, |
| 256 | 291 | av_get_sample_fmt_name(outlink->format), outlink->sample_rate); |
| 292 | + | |
| 257 | 293 | return 0; |
| 258 | 294 | } |
| 259 | 295 | |
| @@ -261,14 +297,23 @@ static int activate(AVFilterContext *ctx) · 1 unmodified line | ||
| 261 | 297 | { |
| 262 | 298 | AVFilterLink *outlink = ctx->outputs[0]; |
| 263 | 299 | FliteContext *flite = ctx->priv; |
| 264 | − int nb_samples = FFMIN(flite->wave_nb_samples, flite->frame_nb_samples); | |
| 265 | 300 | AVFrame *samplesref; |
| 301 | + int nb_samples; | |
| 266 | 302 | |
| 267 | 303 | if (!ff_outlink_frame_wanted(outlink)) |
| 268 | 304 | return FFERROR_NOT_READY; |
| 269 | 305 | |
| 306 | + nb_samples = FFMIN(av_audio_fifo_size(flite->fifo), flite->frame_nb_samples); | |
| 270 | 307 | if (!nb_samples) { |
| 271 | − ff_outlink_set_status(outlink, AVERROR_EOF, flite->pts); | |
| 308 | + char *text; | |
| 309 | + | |
| 310 | + if (!(text = av_strtok(flite->text_p, "\n", &flite->text_saveptr))) { | |
| 311 | + ff_outlink_set_status(outlink, AVERROR_EOF, flite->pts); | |
| 312 | + return 0; | |
| 313 | + } | |
| 314 | + | |
| 315 | + flite_text_to_speech(text, flite->voice, "none"); | |
| 316 | + ff_filter_set_ready(ctx, 100); | |
| 272 | 317 | return 0; |
| 273 | 318 | } |
| 274 | 319 | |
| @@ -276,13 +321,12 @@ static int activate(AVFilterContext *ctx) · 1 unmodified line | ||
| 276 | 321 | if (!samplesref) |
| 277 | 322 | return AVERROR(ENOMEM); |
| 278 | 323 | |
| 279 | − memcpy(samplesref->data[0], flite->wave_samples, | |
| 280 | − nb_samples * flite->wave->num_channels * 2); | |
| 324 | + av_audio_fifo_read(flite->fifo, (void **)samplesref->extended_data, | |
| 325 | + nb_samples); | |
| 326 | + | |
| 281 | 327 | samplesref->pts = flite->pts; |
| 282 | − samplesref->sample_rate = flite->wave->sample_rate; | |
| 328 | + samplesref->sample_rate = flite->sample_rate; | |
| 283 | 329 | flite->pts += nb_samples; |
| 284 | − flite->wave_samples += nb_samples * flite->wave->num_channels; | |
| 285 | − flite->wave_nb_samples -= nb_samples; | |
| 286 | 330 | |
| 287 | 331 | return ff_filter_frame(outlink, samplesref); |
| 288 | 332 | } |