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 @@
#include "avfilter.h"
#include "filters.h"
#include "internal.h"
#include "framequeue.h"
#include <sys/types.h>
#include <sys/wait.h>
......@@ -51,7 +52,9 @@ typedef struct AndioWMarkContext {
int out_bit_depth;
SP *sp;
void *sample_buffer;
size_t sample_buffer_size;
int eof;
FFFrameQueue frame_queue;
} ASubProcessContext;
// =============================================
......@@ -98,21 +101,21 @@ sp_new(AVFilterContext *ctx)
}
if (pid == 0)
{
if (dup2 (input_pipe[0], 0) < 0)
if (dup2(input_pipe[0], 0) < 0)
{
perror("asubprocess dup2() for stdin failed");
exit(EXIT_FAILURE);
}
if (dup2 (output_pipe[1], 1) < 0)
if (dup2(output_pipe[1], 1) < 0)
{
perror("asubprocess dup2() for stdout failed");
exit(EXIT_FAILURE);
}
close (output_pipe[1]);
close (output_pipe[0]);
close (input_pipe[1]);
close (input_pipe[0]);
execl ("/bin/sh", "/bin/sh", "-c", s->command, NULL);
close(output_pipe[1]);
close(output_pipe[0]);
close(input_pipe[1]);
close(input_pipe[0]);
execl("/bin/sh", "/bin/sh", "-c", s->command, NULL);
perror("asubprocess execl() failed");
exit(EXIT_FAILURE);
}
......@@ -298,6 +301,8 @@ AVFILTER_DEFINE_CLASS(asubprocess);
static av_cold int init(AVFilterContext *ctx)
{
ASubProcessContext *s = ctx->priv;
FFFrameQueueGlobal fqg;
if (!s->command) {
av_log(ctx, AV_LOG_ERROR, "No command provided\n");
return AVERROR(EINVAL);
......@@ -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");
return AVERROR(EINVAL);
}
ff_framequeue_global_init(&fqg);
ff_framequeue_init(&s->frame_queue, &fqg);
return 0;
}
static av_cold void uninit(AVFilterContext *ctx)
{
printf ("TODO: uninit\n");
#if 0
ASubProcessContext *s = ctx->priv;
if (s->rbs)
rubberband_delete(s->rbs);
#endif
ff_framequeue_free(&s->frame_queue);
av_freep(&s->sample_buffer);
}
#define NB_BUFFER_SAMPLES 4096
static int write_wav_header(AVFilterContext *ctx, ASubProcessContext *s, int nb_channels, int sample_rate)
{
int bit_depth = s->in_bit_depth;
......@@ -377,7 +379,6 @@ static int config_input(AVFilterLink *inlink)
s->first_pts = AV_NOPTS_VALUE;
#endif
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;
}
......@@ -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)
{
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 (s->in_bit_depth == 32)
......@@ -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)
{
AVFrame *out;
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);
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;
}
static int try_read_frame(ASubProcessContext *s, AVFilterLink *outlink)
{
AVFrame *out;
int ret;
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)
}
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 avail = sp_can_read(s->sp) / sample_size / outlink->ch_layout.nb_channels;
if (avail > NB_BUFFER_SAMPLES)
avail = NB_BUFFER_SAMPLES;
if (avail == NB_BUFFER_SAMPLES || (s->eof && avail > 0))
if (avail >= out->nb_samples || (s->eof && avail > 0)) // TODO: eof handling correct?
{
out = ff_get_audio_buffer(outlink, avail);
if (!out) {
return AVERROR(ENOMEM);
}
av_assert0(avail <= NB_BUFFER_SAMPLES);
avail = FFMIN(avail, out->nb_samples);
out = ff_framequeue_take(&s->frame_queue);
av_assert0(avail <= s->sample_buffer_size);
read_samples(s, (int32_t *)out->data[0], avail * outlink->ch_layout.nb_channels);
ret = ff_filter_frame(outlink, out);
if (ret < 0)
......@@ -547,8 +563,7 @@ static int activate(AVFilterContext *ctx)
ret = try_read_frame(s, outlink);
if (ret != 0)
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))
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