Commit 0f45b898 authored by Stefan Westerfeld's avatar Stefan Westerfeld

avfilter/asubprocess: improved error handling

Signed-off-by: Stefan Westerfeld's avatarStefan Westerfeld <stefan@space.twc.de>
parent b7bbc07e
...@@ -10,14 +10,9 @@ ...@@ -10,14 +10,9 @@
#include "filters.h" #include "filters.h"
#include "internal.h" #include "internal.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
// =============================================
#include <sys/types.h> #include <sys/types.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <sys/stat.h>
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
...@@ -46,6 +41,20 @@ typedef struct SP ...@@ -46,6 +41,20 @@ typedef struct SP
bool done; bool done;
} SP; } SP;
typedef struct AndioWMarkContext {
const AVClass *class;
const char *command;
int state;
unsigned int chunk_size;
int in_bit_depth;
int out_bit_depth;
SP *sp;
void *sample_buffer;
int eof;
} ASubProcessContext;
// =============================================
static SPB *spb_new(void) static SPB *spb_new(void)
{ {
SPB *spb = malloc (sizeof (SPB)); SPB *spb = malloc (sizeof (SPB));
...@@ -56,9 +65,10 @@ static SPB *spb_new(void) ...@@ -56,9 +65,10 @@ static SPB *spb_new(void)
return spb; return spb;
} }
static SP * static int
sp_new (const char *command) sp_new(AVFilterContext *ctx)
{ {
ASubProcessContext *s = ctx->priv;
SP *sp = calloc (1, sizeof (SP)); SP *sp = calloc (1, sizeof (SP));
int output_pipe[2]; int output_pipe[2];
int input_pipe[2]; int input_pipe[2];
...@@ -67,44 +77,80 @@ sp_new (const char *command) ...@@ -67,44 +77,80 @@ sp_new (const char *command)
pok = pipe (output_pipe); pok = pipe (output_pipe);
if (pok != 0) if (pok != 0)
printf ("pipe() failed\n"); {
int ret = AVERROR(errno);
av_log(ctx, AV_LOG_ERROR, "Failed create subprocess output pipe: %s.\n", strerror(errno));
return ret;
}
pok = pipe (input_pipe); pok = pipe (input_pipe);
if (pok != 0) if (pok != 0)
printf ("pipe() failed\n"); {
int ret = AVERROR(errno);
av_log(ctx, AV_LOG_ERROR, "Failed create subprocess input pipe: %s.\n", strerror(errno));
return ret;
}
pid = fork(); pid = fork();
if (pid < 0) if (pid < 0)
printf ("fork() failed\n"); {
int ret = AVERROR(errno);
av_log(ctx, AV_LOG_ERROR, "Failed to fork() subprocess: %s.\n", strerror(errno));
return ret;
}
if (pid == 0) if (pid == 0)
{ {
if (dup2 (input_pipe[0], 0) < 0) if (dup2 (input_pipe[0], 0) < 0)
printf ("dup2() failed\n"); {
perror("asubprocess dup2() for stdin failed");
exit(EXIT_FAILURE);
}
if (dup2 (output_pipe[1], 1) < 0) if (dup2 (output_pipe[1], 1) < 0)
printf ("dup2() failed\n"); {
perror("asubprocess dup2() for stdout failed");
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", command, NULL); execl ("/bin/sh", "/bin/sh", "-c", s->command, NULL);
} perror("asubprocess execl() failed");
exit(EXIT_FAILURE);
}
sp->pid = pid; sp->pid = pid;
close (input_pipe[0]); close (input_pipe[0]);
close (output_pipe[1]); close (output_pipe[1]);
/* make output pipe non blocking */
i = fcntl(output_pipe[0], F_GETFL); i = fcntl(output_pipe[0], F_GETFL);
av_assert0(i != -1); if (i < 0)
{
int ret = AVERROR(errno);
av_log(ctx, AV_LOG_ERROR, "Failed to get output pipe flags: %s.\n", strerror(errno));
return ret;
}
i |= O_NONBLOCK; i |= O_NONBLOCK;
/* make input pipe non blocking */
fcntl(output_pipe[0], F_SETFL, i); fcntl(output_pipe[0], F_SETFL, i);
i = fcntl(input_pipe[1], F_GETFL); i = fcntl(input_pipe[1], F_GETFL);
av_assert0(i != -1); if (i < 0)
{
int ret = AVERROR(errno);
av_log(ctx, AV_LOG_ERROR, "Failed to get input pipe flags: %s.\n", strerror(errno));
return ret;
}
i |= O_NONBLOCK; i |= O_NONBLOCK;
fcntl(input_pipe[1], F_SETFL, i); fcntl(input_pipe[1], F_SETFL, i);
sp->input_pipe = input_pipe[1]; sp->input_pipe = input_pipe[1];
sp->output_pipe = output_pipe[0]; sp->output_pipe = output_pipe[0];
return (sp); s->sp = sp;
return 0;
} }
static int static int
sp_can_read (SP *sp) sp_can_read(SP *sp)
{ {
int can_read = 0; int can_read = 0;
for (SPB *spb = sp->out_buffers; spb; spb = spb->next) for (SPB *spb = sp->out_buffers; spb; spb = spb->next)
...@@ -114,16 +160,14 @@ sp_can_read (SP *sp) ...@@ -114,16 +160,14 @@ sp_can_read (SP *sp)
} }
static void static void
sp_read (SP *sp, char *buffer, int count) sp_read(SP *sp, char *buffer, int count)
{ {
SPB *spb = sp->out_buffers; SPB *spb = sp->out_buffers;
while (spb) while (spb)
{ {
int n = spb->count - spb->offset; int n = FFMIN(spb->count - spb->offset, count);
if (n > count)
n = count;
memcpy (buffer, spb->data + spb->offset, n); memcpy(buffer, spb->data + spb->offset, n);
spb->offset += n; spb->offset += n;
count -= n; count -= n;
buffer += n; buffer += n;
...@@ -131,7 +175,7 @@ sp_read (SP *sp, char *buffer, int count) ...@@ -131,7 +175,7 @@ sp_read (SP *sp, char *buffer, int count)
return; return;
sp->out_buffers = spb->next; sp->out_buffers = spb->next;
free (spb); free(spb);
spb = sp->out_buffers; spb = sp->out_buffers;
} }
} }
...@@ -146,7 +190,10 @@ sp_write(AVFilterContext *ctx, SP *sp, char *buffer, int count) ...@@ -146,7 +190,10 @@ sp_write(AVFilterContext *ctx, SP *sp, char *buffer, int count)
sp->input_pipe = -1; sp->input_pipe = -1;
} }
if (count && sp->done) 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_EXTERNAL;
}
do do
{ {
struct pollfd fds[2] = { struct pollfd fds[2] = {
...@@ -193,12 +240,21 @@ sp_write(AVFilterContext *ctx, SP *sp, char *buffer, int count) ...@@ -193,12 +240,21 @@ sp_write(AVFilterContext *ctx, SP *sp, char *buffer, int count)
} }
else if (rc == 0) else if (rc == 0)
{ {
int status; int status, exit_status;
waitpid(sp->pid, &status, 0); waitpid(sp->pid, &status, 0);
printf("wstatus=%d\n", WEXITSTATUS (status)); exit_status = WEXITSTATUS(status);
sp->done = true; sp->done = true;
if (exit_status != 0)
{
av_log(ctx, AV_LOG_ERROR, "Subprocess failed with non-zero exit code (%d).\n", exit_status);
return AVERROR_EXTERNAL;
}
if (count) if (count)
{
av_log(ctx, AV_LOG_ERROR, "Subprocess terminated before all input data could be written.\n");
return AVERROR_EXTERNAL; return AVERROR_EXTERNAL;
}
return 0; return 0;
} }
else if (errno != EAGAIN && errno != EINTR) else if (errno != EAGAIN && errno != EINTR)
...@@ -228,21 +284,6 @@ enum { ...@@ -228,21 +284,6 @@ enum {
STATE_ERROR STATE_ERROR
}; };
typedef struct AndioWMarkContext {
const AVClass *class;
const char *command;
int fd;
int state;
unsigned int chunk_size;
int in_bit_depth;
int out_bit_depth;
SP *sp;
void *sample_buffer;
int eof;
} ASubProcessContext;
#define OFFSET(x) offsetof(ASubProcessContext, x) #define OFFSET(x) offsetof(ASubProcessContext, x)
#define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM #define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
...@@ -316,21 +357,23 @@ static int config_input(AVFilterLink *inlink) ...@@ -316,21 +357,23 @@ static int config_input(AVFilterLink *inlink)
{ {
AVFilterContext *ctx = inlink->dst; AVFilterContext *ctx = inlink->dst;
ASubProcessContext *s = ctx->priv; ASubProcessContext *s = ctx->priv;
s->sp = sp_new (s->command); int ret;
write_wav_header(ctx, s, inlink->ch_layout.nb_channels, inlink->sample_rate);
#if 0 ret = sp_new(ctx);
int opts = s->transients|s->detector|s->phase|s->window| if (ret != 0)
s->smoothing|s->formant|s->opitch|s->channels| return ret;
RubberBandOptionProcessRealTime;
ret = write_wav_header(ctx, s, inlink->ch_layout.nb_channels, inlink->sample_rate);
if (ret != 0)
return ret;
#if 0
if (s->rbs) if (s->rbs)
rubberband_delete(s->rbs); rubberband_delete(s->rbs);
s->rbs = rubberband_new(inlink->sample_rate, inlink->ch_layout.nb_channels, opts, 1. / s->tempo, s->pitch); s->rbs = rubberband_new(inlink->sample_rate, inlink->ch_layout.nb_channels, opts, 1. / s->tempo, s->pitch);
if (!s->rbs) if (!s->rbs)
return AVERROR(ENOMEM); return AVERROR(ENOMEM);
s->nb_samples = rubberband_get_samples_required(s->rbs);
s->first_pts = AV_NOPTS_VALUE; s->first_pts = AV_NOPTS_VALUE;
#endif #endif
s->state = STATE_EXPECT_RIFF; s->state = STATE_EXPECT_RIFF;
...@@ -521,11 +564,14 @@ static int activate(AVFilterContext *ctx) ...@@ -521,11 +564,14 @@ static int activate(AVFilterContext *ctx)
if (ret != 0) if (ret != 0)
return ret; return ret;
} }
if (s->eof && !sp_done (s->sp)) if (s->eof && !sp_done(s->sp))
{ {
while (!sp_done (s->sp)) while (!sp_done(s->sp))
sp_write (ctx, s->sp, 0, 0); {
printf ("eof\n"); int ret = sp_write(ctx, s->sp, 0, 0);
if (ret != 0)
return ret;
}
} }
ret = try_read_frame(s, outlink); ret = try_read_frame(s, outlink);
if (ret != 0) if (ret != 0)
......
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