Filters can use min_samples/max_samples if the number is constant or activate and ff_inlink_consume_samples().
Unified · Split
| @@ -490,14 +490,6 @@ struct AVFilterLink { · 489 unmodified lines | |||
| 490 | struct AVFilterChannelLayouts *in_channel_layouts; | 490 | struct AVFilterChannelLayouts *in_channel_layouts; |
| 491 | struct AVFilterChannelLayouts *out_channel_layouts; | 491 | struct AVFilterChannelLayouts *out_channel_layouts; |
| 492 | 492 | ||
| 493 | /** | ||
| 494 | * Audio only, the destination filter sets this to a non-zero value to | ||
| 495 | * request that buffers with the given number of samples should be sent to | ||
| 496 | * it. | ||
| 497 | * Last buffer before EOF will be padded with silence. | ||
| 498 | */ | ||
| 499 | int request_samples; | ||
| 500 | |||
| 501 | /** stage of the initialization of the link properties (dimensions, etc) */ | 493 | /** stage of the initialization of the link properties (dimensions, etc) */ |
| 502 | enum { | 494 | enum { |
| 503 | AVLINK_UNINIT = 0, ///< not started | 495 | AVLINK_UNINIT = 0, ///< not started |
| @@ -143,112 +143,19 @@ static int calc_ptr_alignment(AVFrame *frame) · 142 unmodified lines | |||
| 143 | return min_align; | 143 | return min_align; |
| 144 | } | 144 | } |
| 145 | 145 | ||
| 146 | static int return_audio_frame(AVFilterContext *ctx) | ||
| 147 | { | ||
| 148 | AVFilterLink *link = ctx->outputs[0]; | ||
| 149 | FifoContext *s = ctx->priv; | ||
| 150 | AVFrame *head = s->root.next ? s->root.next->frame : NULL; | ||
| 151 | AVFrame *out; | ||
| 152 | int ret; | ||
| 153 | |||
| 154 | /* if head is NULL then we're flushing the remaining samples in out */ | ||
| 155 | if (!head && !s->out) | ||
| 156 | return AVERROR_EOF; | ||
| 157 | |||
| 158 | if (!s->out && | ||
| 159 | head->nb_samples >= link->request_samples && | ||
| 160 | calc_ptr_alignment(head) >= 32) { | ||
| 161 | if (head->nb_samples == link->request_samples) { | ||
| 162 | out = head; | ||
| 163 | queue_pop(s); | ||
| 164 | } else { | ||
| 165 | out = av_frame_clone(head); | ||
| 166 | if (!out) | ||
| 167 | return AVERROR(ENOMEM); | ||
| 168 | |||
| 169 | out->nb_samples = link->request_samples; | ||
| 170 | buffer_offset(link, head, link->request_samples); | ||
| 171 | } | ||
| 172 | } else { | ||
| 173 | int nb_channels = link->channels; | ||
| 174 | |||
| 175 | if (!s->out) { | ||
| 176 | s->out = ff_get_audio_buffer(link, link->request_samples); | ||
| 177 | if (!s->out) | ||
| 178 | return AVERROR(ENOMEM); | ||
| 179 | |||
| 180 | s->out->nb_samples = 0; | ||
| 181 | s->out->pts = head->pts; | ||
| 182 | s->allocated_samples = link->request_samples; | ||
| 183 | } else if (link->request_samples != s->allocated_samples) { | ||
| 184 | av_log(ctx, AV_LOG_ERROR, "request_samples changed before the " | ||
| 185 | "buffer was returned.\n"); | ||
| 186 | return AVERROR(EINVAL); | ||
| 187 | } | ||
| 188 | |||
| 189 | while (s->out->nb_samples < s->allocated_samples) { | ||
| 190 | int len; | ||
| 191 | |||
| 192 | if (!s->root.next) { | ||
| 193 | ret = ff_request_frame(ctx->inputs[0]); | ||
| 194 | if (ret == AVERROR_EOF) { | ||
| 195 | av_samples_set_silence(s->out->extended_data, | ||
| 196 | s->out->nb_samples, | ||
| 197 | s->allocated_samples - | ||
| 198 | s->out->nb_samples, | ||
| 199 | nb_channels, link->format); | ||
| 200 | s->out->nb_samples = s->allocated_samples; | ||
| 201 | break; | ||
| 202 | } else if (ret < 0) | ||
| 203 | return ret; | ||
| 204 | if (!s->root.next) | ||
| 205 | return 0; | ||
| 206 | } | ||
| 207 | head = s->root.next->frame; | ||
| 208 | |||
| 209 | len = FFMIN(s->allocated_samples - s->out->nb_samples, | ||
| 210 | head->nb_samples); | ||
| 211 | |||
| 212 | av_samples_copy(s->out->extended_data, head->extended_data, | ||
| 213 | s->out->nb_samples, 0, len, nb_channels, | ||
| 214 | link->format); | ||
| 215 | s->out->nb_samples += len; | ||
| 216 | |||
| 217 | if (len == head->nb_samples) { | ||
| 218 | av_frame_free(&head); | ||
| 219 | queue_pop(s); | ||
| 220 | } else { | ||
| 221 | buffer_offset(link, head, len); | ||
| 222 | } | ||
| 223 | } | ||
| 224 | out = s->out; | ||
| 225 | s->out = NULL; | ||
| 226 | } | ||
| 227 | return ff_filter_frame(link, out); | ||
| 228 | } | ||
| 229 | |||
| 230 | static int request_frame(AVFilterLink *outlink) | 146 | static int request_frame(AVFilterLink *outlink) |
| 231 | { | 147 | { |
| 232 | FifoContext *s = outlink->src->priv; | 148 | FifoContext *s = outlink->src->priv; |
| 233 | int ret = 0; | 149 | int ret = 0; |
| 234 | 150 | ||
| 235 | if (!s->root.next) { | 151 | if (!s->root.next) { |
| 236 | if ((ret = ff_request_frame(outlink->src->inputs[0])) < 0) { | 152 | if ((ret = ff_request_frame(outlink->src->inputs[0])) < 0) |
| 237 | if (ret == AVERROR_EOF && outlink->request_samples) | ||
| 238 | return return_audio_frame(outlink->src); | ||
| 239 | return ret; | 153 | return ret; |
| 240 | } | ||
| 241 | if (!s->root.next) | 154 | if (!s->root.next) |
| 242 | return 0; | 155 | return 0; |
| 243 | } | 156 | } |
| 244 | 157 | ret = ff_filter_frame(outlink, s->root.next->frame); | |
| 245 | if (outlink->request_samples) { | 158 | queue_pop(s); |
| 246 | return return_audio_frame(outlink->src); | ||
| 247 | } else { | ||
| 248 | ret = ff_filter_frame(outlink, s->root.next->frame); | ||
| 249 | queue_pop(s); | ||
| 250 | } | ||
| 251 | |||
| 252 | return ret; | 159 | return ret; |
| 253 | } | 160 | } |
| 254 | 161 | ||