Commit c82196d6 authored by Stefan Westerfeld's avatar Stefan Westerfeld

avfilter/asubprocess: code cleanup, minor error handling improvements

Signed-off-by: Stefan Westerfeld's avatarStefan Westerfeld <stefan@space.twc.de>
parent bc24058b
......@@ -40,7 +40,7 @@ typedef struct SP
int output_pipe;
SPB *out_buffers;
SPB *unused_buffers;
int pid;
pid_t pid;
size_t input_count;
size_t can_read;
bool done;
......@@ -74,6 +74,17 @@ typedef struct ASubProcessContext {
FFFrameQueue frame_queue;
} ASubProcessContext;
#define OFFSET(x) offsetof(ASubProcessContext, x)
#define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
static const AVOption asubprocess_options[] = {
{ "command", "set command to run as subprocess", OFFSET(command), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, A},
{ "bits", "set wav bit depth for subprocess input", OFFSET(in_bit_depth), AV_OPT_TYPE_INT, {.i64=32}, 0, 32, A},
{ NULL },
};
AVFILTER_DEFINE_CLASS(asubprocess);
static SPB *spb_new(AVFilterContext *ctx)
{
ASubProcessContext *s = ctx->priv;
......@@ -115,9 +126,9 @@ static void
sp_cleanup(SP *sp)
{
if (sp->input_pipe >= 0)
close (sp->input_pipe);
close(sp->input_pipe);
if (sp->output_pipe >= 0)
close (sp->output_pipe);
close(sp->output_pipe);
if (!sp->done) {
int status;
......@@ -238,7 +249,7 @@ sp_read(SP *sp, char *buffer, size_t count)
static int try_read_frame(AVFilterContext *ctx);
static int update_state(AVFilterContext *ctx)
static int process_input(AVFilterContext *ctx)
{
AVFilterLink *outlink = ctx->outputs[0];
ASubProcessContext *s = ctx->priv;
......@@ -300,7 +311,7 @@ static int update_state(AVFilterContext *ctx)
s->chunk_size -= 16;
s->state = STATE_SKIP_CHUNK;
}
else if (s->state == STATE_SKIP_CHUNK && can_read > 0) {
else if (s->state == STATE_SKIP_CHUNK) {
unsigned int to_skip = FFMIN(s->chunk_size, can_read);
s->chunk_size -= to_skip;
if (!s->chunk_size)
......@@ -309,14 +320,14 @@ static int update_state(AVFilterContext *ctx)
while (to_skip) {
char buffer[1024];
unsigned int n = FFMIN(sizeof(buffer), to_skip);
sp_read (s->sp, buffer, n);
sp_read(s->sp, buffer, n);
to_skip -= n;
}
}
else {
if (s->sp->input_count > MAX_INPUT_BEFORE_DATA) {
av_log(ctx, AV_LOG_ERROR, "Subprocess output is not a valid wav file: no 'data' chunk found.\n");
return AVERROR_INVALIDDATA;
av_log(ctx, AV_LOG_ERROR, "Subprocess output is not a valid wav file: no 'data' chunk found.\n");
return AVERROR_INVALIDDATA;
}
break;
}
......@@ -352,16 +363,22 @@ sp_write(AVFilterContext *ctx, char *buffer, int count)
}
if (count && sp->done) {
av_log(ctx, AV_LOG_ERROR, "Subprocess terminated before all input data could be written.\n");
return AVERROR_EXTERNAL;
return AVERROR(EIO);
}
do {
int rc;
struct pollfd fds[2] = {
{ .fd = sp->input_pipe, .events = POLLOUT, .revents = 0 },
{ .fd = sp->output_pipe, .events = POLLIN, .revents = 0 },
};
poll(fds, 2, -1);
errno = 0;
rc = poll(fds, 2, -1);
if ((rc <= 0 && errno != EAGAIN && errno != EINTR) || (fds[0].revents & POLLNVAL) || (fds[1].revents & (POLLERR | POLLNVAL))) {
av_log(ctx, AV_LOG_ERROR, "Poll for subprocess failed.\n");
return AVERROR(errno ? errno : EIO);
}
if (fds[0].revents & (POLLOUT | POLLHUP)) {
int rc = write(sp->input_pipe, &buffer[offset], count);
rc = write(sp->input_pipe, &buffer[offset], count);
if (rc > 0) {
offset += rc;
count -= rc;
......@@ -374,7 +391,7 @@ sp_write(AVFilterContext *ctx, char *buffer, int count)
}
if (fds[1].revents & (POLLIN | POLLHUP)) {
SPB *last;
int rc, ret;
int ret;
if (!sp->out_buffers) {
sp->out_buffers = spb_new(ctx);
......@@ -397,7 +414,7 @@ sp_write(AVFilterContext *ctx, char *buffer, int count)
last->count += rc;
sp->input_count += rc;
sp->can_read += rc;
ret = update_state(ctx);
ret = process_input(ctx);
if (ret != 0)
return ret;
}
......@@ -409,11 +426,11 @@ sp_write(AVFilterContext *ctx, char *buffer, int count)
if (exit_status != 0) {
av_log(ctx, AV_LOG_ERROR, "Subprocess failed with non-zero exit code (%d).\n", exit_status);
return AVERROR_EXTERNAL;
return AVERROR(EIO);
}
if (count) {
av_log(ctx, AV_LOG_ERROR, "Subprocess terminated before all input data could be written.\n");
return AVERROR_EXTERNAL;
return AVERROR(EIO);
}
return 0;
}
......@@ -432,18 +449,6 @@ sp_done (SP *sp)
{
return sp->done;
}
// =============================================
#define OFFSET(x) offsetof(ASubProcessContext, x)
#define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
static const AVOption asubprocess_options[] = {
{ "command", "set command to run as subprocess", OFFSET(command), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, A},
{ "bits", "set wav bit depth for subprocess input", OFFSET(in_bit_depth), AV_OPT_TYPE_INT, {.i64=32}, 0, 32, A},
{ NULL },
};
AVFILTER_DEFINE_CLASS(asubprocess);
static av_cold int init(AVFilterContext *ctx)
{
......@@ -474,8 +479,9 @@ static av_cold void uninit(AVFilterContext *ctx)
av_freep(&s->sample_buffer);
}
static int write_wav_header(AVFilterContext *ctx, ASubProcessContext *s, int nb_channels, int sample_rate)
static int write_wav_header(AVFilterContext *ctx, int nb_channels, int sample_rate)
{
ASubProcessContext *s = ctx->priv;
int bit_depth = s->in_bit_depth;
AVIOContext *wav_header = NULL;
uint8_t *buffer = NULL;
......@@ -541,8 +547,9 @@ 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, int32_t *data, int count)
{
ASubProcessContext *s = ctx->priv;
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) {
......@@ -578,13 +585,14 @@ static int write_samples(AVFilterContext *ctx, ASubProcessContext *s, int32_t *d
return sp_write(ctx, s->sample_buffer, sample_size * count);
}
static int write_frame(AVFilterContext *ctx, ASubProcessContext *s, AVFilterLink *inlink, AVFrame *in)
static int write_frame(AVFilterContext *ctx, AVFilterLink *inlink, AVFrame *in)
{
ASubProcessContext *s = ctx->priv;
AVFrame *out;
int ret;
s->nb_input_samples += in->nb_samples;
ret = write_samples(ctx, s, (int32_t *)in->data[0], in->nb_samples * inlink->ch_layout.nb_channels);
ret = write_samples(ctx, (int32_t *)in->data[0], in->nb_samples * inlink->ch_layout.nb_channels);
if (ret < 0) {
av_frame_free(&in);
return ret;
......@@ -651,7 +659,7 @@ static int activate(AVFilterContext *ctx)
s->state = STATE_EXPECT_RIFF;
ret = write_wav_header(ctx, s, inlink->ch_layout.nb_channels, inlink->sample_rate);
ret = write_wav_header(ctx, inlink->ch_layout.nb_channels, inlink->sample_rate);
if (ret != 0)
return ret;
}
......@@ -662,7 +670,7 @@ static int activate(AVFilterContext *ctx)
if (ret < 0)
return ret;
if (ret > 0) {
ret = write_frame(ctx, s, inlink, in);
ret = write_frame(ctx, inlink, in);
if (ff_inlink_queued_samples(inlink) >= 0)
ff_filter_set_ready(ctx, 100);
......
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