Commit 58bad47d authored by Stefan Westerfeld's avatar Stefan Westerfeld

avfilter/asubprocess: queue and reuse input frames if possible

Signed-off-by: Stefan Westerfeld's avatarStefan Westerfeld <stefan@space.twc.de>
parent 0f45b898
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "avfilter.h" #include "avfilter.h"
#include "filters.h" #include "filters.h"
#include "internal.h" #include "internal.h"
#include "framequeue.h"
#include <sys/types.h> #include <sys/types.h>
#include <sys/wait.h> #include <sys/wait.h>
...@@ -51,7 +52,9 @@ typedef struct AndioWMarkContext { ...@@ -51,7 +52,9 @@ typedef struct AndioWMarkContext {
int out_bit_depth; int out_bit_depth;
SP *sp; SP *sp;
void *sample_buffer; void *sample_buffer;
size_t sample_buffer_size;
int eof; int eof;
FFFrameQueue frame_queue;
} ASubProcessContext; } ASubProcessContext;
// ============================================= // =============================================
...@@ -98,21 +101,21 @@ sp_new(AVFilterContext *ctx) ...@@ -98,21 +101,21 @@ sp_new(AVFilterContext *ctx)
} }
if (pid == 0) if (pid == 0)
{ {
if (dup2 (input_pipe[0], 0) < 0) if (dup2(input_pipe[0], 0) < 0)
{ {
perror("asubprocess dup2() for stdin failed"); perror("asubprocess dup2() for stdin failed");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if (dup2 (output_pipe[1], 1) < 0) if (dup2(output_pipe[1], 1) < 0)
{ {
perror("asubprocess dup2() for stdout failed"); perror("asubprocess dup2() for stdout failed");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
close (output_pipe[1]); close(output_pipe[1]);
close (output_pipe[0]); close(output_pipe[0]);
close (input_pipe[1]); close(input_pipe[1]);
close (input_pipe[0]); close(input_pipe[0]);
execl ("/bin/sh", "/bin/sh", "-c", s->command, NULL); execl("/bin/sh", "/bin/sh", "-c", s->command, NULL);
perror("asubprocess execl() failed"); perror("asubprocess execl() failed");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
...@@ -298,6 +301,8 @@ AVFILTER_DEFINE_CLASS(asubprocess); ...@@ -298,6 +301,8 @@ AVFILTER_DEFINE_CLASS(asubprocess);
static av_cold int init(AVFilterContext *ctx) static av_cold int init(AVFilterContext *ctx)
{ {
ASubProcessContext *s = ctx->priv; ASubProcessContext *s = ctx->priv;
FFFrameQueueGlobal fqg;
if (!s->command) { if (!s->command) {
av_log(ctx, AV_LOG_ERROR, "No command provided\n"); av_log(ctx, AV_LOG_ERROR, "No command provided\n");
return AVERROR(EINVAL); return AVERROR(EINVAL);
...@@ -306,22 +311,19 @@ static av_cold int init(AVFilterContext *ctx) ...@@ -306,22 +311,19 @@ static av_cold int init(AVFilterContext *ctx)
av_log(ctx, AV_LOG_ERROR, "Only 16, 24 and 32 input bit depth supported\n"); av_log(ctx, AV_LOG_ERROR, "Only 16, 24 and 32 input bit depth supported\n");
return AVERROR(EINVAL); return AVERROR(EINVAL);
} }
ff_framequeue_global_init(&fqg);
ff_framequeue_init(&s->frame_queue, &fqg);
return 0; return 0;
} }
static av_cold void uninit(AVFilterContext *ctx) static av_cold void uninit(AVFilterContext *ctx)
{ {
printf ("TODO: uninit\n");
#if 0
ASubProcessContext *s = ctx->priv; ASubProcessContext *s = ctx->priv;
if (s->rbs) ff_framequeue_free(&s->frame_queue);
rubberband_delete(s->rbs); av_freep(&s->sample_buffer);
#endif
} }
#define NB_BUFFER_SAMPLES 4096
static int write_wav_header(AVFilterContext *ctx, ASubProcessContext *s, int nb_channels, int sample_rate) static int write_wav_header(AVFilterContext *ctx, ASubProcessContext *s, int nb_channels, int sample_rate)
{ {
int bit_depth = s->in_bit_depth; int bit_depth = s->in_bit_depth;
...@@ -377,7 +379,6 @@ static int config_input(AVFilterLink *inlink) ...@@ -377,7 +379,6 @@ static int config_input(AVFilterLink *inlink)
s->first_pts = AV_NOPTS_VALUE; s->first_pts = AV_NOPTS_VALUE;
#endif #endif
s->state = STATE_EXPECT_RIFF; s->state = STATE_EXPECT_RIFF;
s->sample_buffer = av_malloc (NB_BUFFER_SAMPLES * inlink->ch_layout.nb_channels * 4 /* max 32 bit */); // TODO: leak
return 0; return 0;
} }
...@@ -425,6 +426,14 @@ static void read_samples(ASubProcessContext *s, int32_t *data, int count) ...@@ -425,6 +426,14 @@ static void read_samples(ASubProcessContext *s, int32_t *data, int count)
static int write_samples(AVFilterContext *ctx, ASubProcessContext *s, int32_t *data, int count) static int write_samples(AVFilterContext *ctx, ASubProcessContext *s, int32_t *data, int count)
{ {
int sample_size = s->in_bit_depth / 8; int sample_size = s->in_bit_depth / 8;
int bsize = count * 4; /* allocate sample buffer for 32 bit per sample (required for conversions of input/output) */
if (s->sample_buffer_size < bsize)
{
s->sample_buffer = av_realloc(s->sample_buffer, bsize);
if (!s->sample_buffer)
return AVERROR(ENOMEM);
s->sample_buffer_size = bsize;
}
#if !HAVE_BIGENDIAN #if !HAVE_BIGENDIAN
if (s->in_bit_depth == 32) if (s->in_bit_depth == 32)
...@@ -459,17 +468,26 @@ static int write_samples(AVFilterContext *ctx, ASubProcessContext *s, int32_t *d ...@@ -459,17 +468,26 @@ static int write_samples(AVFilterContext *ctx, ASubProcessContext *s, int32_t *d
static int write_frame(AVFilterContext *ctx, ASubProcessContext *s, AVFilterLink *inlink, AVFrame *in) static int write_frame(AVFilterContext *ctx, ASubProcessContext *s, AVFilterLink *inlink, AVFrame *in)
{ {
AVFrame *out;
int ret = 0; int ret = 0;
av_assert0(in->nb_samples <= NB_BUFFER_SAMPLES);
ret = write_samples(ctx, s, (int32_t *)in->data[0], in->nb_samples * inlink->ch_layout.nb_channels); ret = write_samples(ctx, s, (int32_t *)in->data[0], in->nb_samples * inlink->ch_layout.nb_channels);
av_frame_free(&in); if (av_frame_is_writable(in)) {
out = in;
} else {
out = ff_get_audio_buffer(ctx->outputs[0], in->nb_samples);
if (!out) {
av_frame_free(&in);
return AVERROR(ENOMEM);
}
av_frame_copy_props(out, in);
}
ff_framequeue_add(&s->frame_queue, out);
return ret; return ret;
} }
static int try_read_frame(ASubProcessContext *s, AVFilterLink *outlink) static int try_read_frame(ASubProcessContext *s, AVFilterLink *outlink)
{ {
AVFrame *out;
int ret; int ret;
if (s->state == STATE_EXPECT_RIFF && sp_can_read(s->sp) >= 12) if (s->state == STATE_EXPECT_RIFF && sp_can_read(s->sp) >= 12)
...@@ -509,19 +527,17 @@ static int try_read_frame(ASubProcessContext *s, AVFilterLink *outlink) ...@@ -509,19 +527,17 @@ static int try_read_frame(ASubProcessContext *s, AVFilterLink *outlink)
} }
s->state = STATE_EXPECT_CHUNK; s->state = STATE_EXPECT_CHUNK;
} }
if (s->state == STATE_IN_DATA_CHUNK) if (s->state == STATE_IN_DATA_CHUNK && ff_framequeue_queued_frames(&s->frame_queue))
{ {
AVFrame *out = ff_framequeue_peek(&s->frame_queue, 0);
int sample_size = s->out_bit_depth / 8; int sample_size = s->out_bit_depth / 8;
int avail = sp_can_read(s->sp) / sample_size / outlink->ch_layout.nb_channels; int avail = sp_can_read(s->sp) / sample_size / outlink->ch_layout.nb_channels;
if (avail > NB_BUFFER_SAMPLES)
avail = NB_BUFFER_SAMPLES; if (avail >= out->nb_samples || (s->eof && avail > 0)) // TODO: eof handling correct?
if (avail == NB_BUFFER_SAMPLES || (s->eof && avail > 0))
{ {
out = ff_get_audio_buffer(outlink, avail); avail = FFMIN(avail, out->nb_samples);
if (!out) { out = ff_framequeue_take(&s->frame_queue);
return AVERROR(ENOMEM); av_assert0(avail <= s->sample_buffer_size);
}
av_assert0(avail <= NB_BUFFER_SAMPLES);
read_samples(s, (int32_t *)out->data[0], avail * outlink->ch_layout.nb_channels); read_samples(s, (int32_t *)out->data[0], avail * outlink->ch_layout.nb_channels);
ret = ff_filter_frame(outlink, out); ret = ff_filter_frame(outlink, out);
if (ret < 0) if (ret < 0)
...@@ -547,8 +563,7 @@ static int activate(AVFilterContext *ctx) ...@@ -547,8 +563,7 @@ static int activate(AVFilterContext *ctx)
ret = try_read_frame(s, outlink); ret = try_read_frame(s, outlink);
if (ret != 0) if (ret != 0)
return ret; return ret;
ret = ff_inlink_consume_samples(inlink, NB_BUFFER_SAMPLES, NB_BUFFER_SAMPLES, &in); ret = ff_inlink_consume_frame(inlink, &in);
//ret = ff_inlink_consume_frame(inlink, &in);
if (ff_inlink_acknowledge_status(inlink, &status, &pts)) if (ff_inlink_acknowledge_status(inlink, &status, &pts))
s->eof |= status == AVERROR_EOF; s->eof |= status == AVERROR_EOF;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment