Commit 8270a949 authored by Stefan Westerfeld's avatar Stefan Westerfeld

avfilter/asubprocess: update state after reading to fail on invalid input

Signed-off-by: Stefan Westerfeld's avatarStefan Westerfeld <stefan@space.twc.de>
parent 1a737e87
......@@ -42,6 +42,15 @@ typedef struct SP
bool done;
} SP;
enum {
STATE_EXPECT_RIFF,
STATE_EXPECT_CHUNK,
STATE_SKIP_CHUNK,
STATE_IN_DATA_CHUNK,
STATE_IN_FMT_CHUNK,
STATE_ERROR
};
typedef struct AndioWMarkContext {
const AVClass *class;
......@@ -172,6 +181,77 @@ sp_read(SP *sp, char *buffer, int count)
}
}
static int update_state(AVFilterContext *ctx)
{
AVFilterLink *outlink = ctx->outputs[0];
ASubProcessContext *s = ctx->priv;
if (s->state == STATE_EXPECT_RIFF && sp_can_read(s->sp) >= 12) {
char buffer[12];
sp_read(s->sp, buffer, 12);
if ((memcmp (buffer, "RIFF", 4) && memcmp (buffer, "RF64", 4)) || memcmp (buffer + 8, "WAVE", 4)) {
av_log(ctx, AV_LOG_ERROR, "Subprocess output is not a valid wav file.\n");
return AVERROR_INVALIDDATA;
}
s->state = STATE_EXPECT_CHUNK;
}
if (s->state == STATE_EXPECT_CHUNK && sp_can_read(s->sp) >= 8) {
unsigned char x[8];
sp_read(s->sp, x, 8);
s->chunk_size = AV_RL32 (x + 4);
if (!memcmp (x, "data", 4))
s->state = STATE_IN_DATA_CHUNK;
else if (!memcmp (x, "fmt ", 4) && s->chunk_size >= 16)
s->state = STATE_IN_FMT_CHUNK;
else
s->state = STATE_SKIP_CHUNK;
}
if (s->state == STATE_IN_FMT_CHUNK && sp_can_read(s->sp) >= 16) {
unsigned char data[16];
int format, nb_channels, sample_rate;
sp_read(s->sp, data, 16);
format = AV_RL16(data);
nb_channels = AV_RL16(data + 2);
sample_rate = AV_RL32(data + 4);
s->out_bit_depth = AV_RL16(data + 14);
if (format != 1 && format != 0xFFFE) { // TODO: check extensible wav format: should be PCM
av_log(ctx, AV_LOG_ERROR,
"Unsupported wav format (%d) from subprocess (expected PCM).\n", format);
return AVERROR_INVALIDDATA;
}
if (nb_channels != outlink->ch_layout.nb_channels) {
av_log(ctx, AV_LOG_ERROR,
"Number of output channels (%d) from subprocess doesn't match input channels (%d).\n",
nb_channels, outlink->ch_layout.nb_channels);
return AVERROR_INVALIDDATA;
}
if (sample_rate != outlink->sample_rate) {
av_log(ctx, AV_LOG_ERROR,
"Sample rate (%d) from subprocess doesn't match input sample rate (%d).\n",
sample_rate, outlink->sample_rate);
return AVERROR_INVALIDDATA;
}
if (s->out_bit_depth != 8 && s->out_bit_depth != 16 && s->out_bit_depth != 24 && s->out_bit_depth != 32) {
av_log(ctx, AV_LOG_ERROR, "Unsupported output wav bit depth (%d) from subprocess.\n", s->out_bit_depth);
return AVERROR_INVALIDDATA;
}
s->chunk_size -= 16;
s->state = STATE_SKIP_CHUNK;
}
if (s->state == STATE_SKIP_CHUNK && sp_can_read(s->sp) >= s->chunk_size) {
while (s->chunk_size) {
char buffer[1024];
unsigned int n = FFMIN(sizeof(buffer), s->chunk_size);
sp_read (s->sp, buffer, n);
s->chunk_size -= n;
}
s->state = STATE_EXPECT_CHUNK;
}
return 0;
}
static int
sp_write(AVFilterContext *ctx, SP *sp, char *buffer, int count)
{
......@@ -204,7 +284,7 @@ sp_write(AVFilterContext *ctx, SP *sp, char *buffer, int count)
}
if (fds[1].revents & (POLLIN | POLLHUP)) {
SPB *last;
int rc;
int rc, ret;
if (!sp->out_buffers)
sp->out_buffers = spb_new();
......@@ -220,6 +300,9 @@ sp_write(AVFilterContext *ctx, SP *sp, char *buffer, int count)
rc = read(sp->output_pipe, last->data + last->count, sizeof(last->data) - last->count);
if (rc > 0) {
last->count += rc;
ret = update_state(ctx);
if (ret != 0)
return ret;
}
else if (rc == 0) {
int status, exit_status;
......@@ -238,7 +321,7 @@ sp_write(AVFilterContext *ctx, SP *sp, char *buffer, int count)
return 0;
}
else if (errno != EAGAIN && errno != EINTR) {
int ret = AVERROR(errno);
ret = AVERROR(errno);
av_log(ctx, AV_LOG_ERROR, "Read from subprocess failed: %s.\n", strerror(errno));
return ret;
}
......@@ -254,15 +337,6 @@ sp_done (SP *sp)
}
// =============================================
enum {
STATE_EXPECT_RIFF,
STATE_EXPECT_CHUNK,
STATE_SKIP_CHUNK,
STATE_IN_DATA_CHUNK,
STATE_IN_FMT_CHUNK,
STATE_ERROR
};
#define OFFSET(x) offsetof(ASubProcessContext, x)
#define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
......@@ -457,69 +531,6 @@ static int try_read_frame(AVFilterContext *ctx)
ASubProcessContext *s = ctx->priv;
int ret;
if (s->state == STATE_EXPECT_RIFF && sp_can_read(s->sp) >= 12) {
char buffer[12];
sp_read(s->sp, buffer, 12);
if ((memcmp (buffer, "RIFF", 4) && memcmp (buffer, "RF64", 4)) || memcmp (buffer + 8, "WAVE", 4)) {
av_log(ctx, AV_LOG_ERROR, "Subprocess output is not a valid wav file.\n");
return AVERROR_INVALIDDATA;
}
s->state = STATE_EXPECT_CHUNK;
}
if (s->state == STATE_EXPECT_CHUNK && sp_can_read(s->sp) >= 8) {
unsigned char x[8];
sp_read(s->sp, x, 8);
s->chunk_size = AV_RL32 (x + 4);
if (!memcmp (x, "data", 4))
s->state = STATE_IN_DATA_CHUNK;
else if (!memcmp (x, "fmt ", 4) && s->chunk_size >= 16)
s->state = STATE_IN_FMT_CHUNK;
else
s->state = STATE_SKIP_CHUNK;
}
if (s->state == STATE_IN_FMT_CHUNK && sp_can_read(s->sp) >= 16) {
unsigned char data[16];
int format, nb_channels, sample_rate;
sp_read(s->sp, data, 16);
format = AV_RL16(data);
nb_channels = AV_RL16(data + 2);
sample_rate = AV_RL32(data + 4);
s->out_bit_depth = AV_RL16(data + 14);
if (format != 1 && format != 0xFFFE) { // TODO: check extensible wav format: should be PCM
av_log(ctx, AV_LOG_ERROR,
"Unsupported wav format (%d) from subprocess (expected PCM).\n", format);
return AVERROR_INVALIDDATA;
}
if (nb_channels != outlink->ch_layout.nb_channels) {
av_log(ctx, AV_LOG_ERROR,
"Number of output channels (%d) from subprocess doesn't match input channels (%d).\n",
nb_channels, outlink->ch_layout.nb_channels);
return AVERROR_INVALIDDATA;
}
if (sample_rate != outlink->sample_rate) {
av_log(ctx, AV_LOG_ERROR,
"Sample rate (%d) from subprocess doesn't match input sample rate (%d).\n",
sample_rate, outlink->sample_rate);
return AVERROR_INVALIDDATA;
}
if (s->out_bit_depth != 8 && s->out_bit_depth != 16 && s->out_bit_depth != 24 && s->out_bit_depth != 32) {
av_log(ctx, AV_LOG_ERROR, "Unsupported output wav bit depth (%d) from subprocess.\n", s->out_bit_depth);
return AVERROR_INVALIDDATA;
}
s->chunk_size -= 16;
s->state = STATE_SKIP_CHUNK;
}
if (s->state == STATE_SKIP_CHUNK && sp_can_read(s->sp) >= s->chunk_size) {
while (s->chunk_size) {
char buffer[1024];
unsigned int n = FFMIN(sizeof(buffer), s->chunk_size);
sp_read (s->sp, buffer, n);
s->chunk_size -= n;
}
s->state = STATE_EXPECT_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;
......
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