Commit dbed10fb authored by Stefan Westerfeld's avatar Stefan Westerfeld

avfilter/asubprocess: fail if wav 'data' chunk could not be found

Signed-off-by: Stefan Westerfeld's avatarStefan Westerfeld <stefan@space.twc.de>
parent 8270a949
......@@ -23,7 +23,8 @@
#include <stdbool.h>
#include <string.h>
#define BUFFER_SIZE 1024 * 128
#define BUFFER_SIZE 1024 * 128
#define MAX_INPUT_BEFORE_DATA 16 * 1024 * 1024 /* max number of bytes before data chunk */
typedef struct SPB
{
......@@ -35,11 +36,12 @@ typedef struct SPB
typedef struct SP
{
int input_pipe;
int output_pipe;
SPB *out_buffers;
int pid;
bool done;
int input_pipe;
int output_pipe;
SPB *out_buffers;
int pid;
size_t input_count;
bool done;
} SP;
enum {
......@@ -186,75 +188,92 @@ 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;
while (s->state != STATE_IN_DATA_CHUNK) {
unsigned int can_read = sp_can_read(s->sp);
if (s->state == STATE_EXPECT_RIFF && can_read >= 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 (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;
else if (s->state == STATE_EXPECT_CHUNK && can_read >= 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 (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;
else if (s->state == STATE_IN_FMT_CHUNK && can_read >= 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->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;
else if (s->state == STATE_SKIP_CHUNK && can_read > 0) {
unsigned int to_skip = FFMIN(s->chunk_size, can_read);
s->chunk_size -= to_skip;
if (!s->chunk_size)
s->state = STATE_EXPECT_CHUNK;
while (to_skip) {
char buffer[1024];
unsigned int n = FFMIN(sizeof(buffer), to_skip);
sp_read (s->sp, buffer, n);
to_skip -= n;
}
}
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;
else {
if (s->state != STATE_IN_DATA_CHUNK && s->sp->input_count > MAX_INPUT_BEFORE_DATA) {
av_log(ctx, AV_LOG_ERROR, "Input is not a valid wav file: no 'data' chunk found.\n");
return AVERROR_INVALIDDATA;
}
break;
}
s->state = STATE_EXPECT_CHUNK;
}
return 0;
}
static int
sp_write(AVFilterContext *ctx, SP *sp, char *buffer, int count)
sp_write(AVFilterContext *ctx, char *buffer, int count)
{
ASubProcessContext *s = ctx->priv;
SP *sp = s->sp;
int offset = 0;
if (count == 0 && sp->input_pipe >= 0) { // eof
close(sp->input_pipe);
......@@ -300,6 +319,7 @@ 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;
sp->input_count += rc;
ret = update_state(ctx);
if (ret != 0)
return ret;
......@@ -400,7 +420,7 @@ static int write_wav_header(AVFilterContext *ctx, ASubProcessContext *s, int nb_
ffio_wfourcc(wav_header, "data");
avio_wl32(wav_header, -1);
size = avio_close_dyn_buf(wav_header, &buffer);
ret = sp_write(ctx, s->sp, buffer, size);
ret = sp_write(ctx,buffer, size);
av_free(buffer);
return ret;
}
......@@ -482,7 +502,7 @@ static int write_samples(AVFilterContext *ctx, ASubProcessContext *s, int32_t *d
#if !HAVE_BIGENDIAN
if (s->in_bit_depth == 32) {
/* optimized case: on little endian systems we don't need any conversion */
return sp_write(ctx, s->sp, (char *)data, sample_size * count);
return sp_write(ctx, (char *)data, sample_size * count);
}
#endif
if (s->in_bit_depth == 16) {
......@@ -502,7 +522,7 @@ static int write_samples(AVFilterContext *ctx, ASubProcessContext *s, int32_t *d
for (int k = 0; k < count; k++)
AV_WL32(out + k, data[k]);
}
return sp_write(ctx, s->sp, s->sample_buffer, sample_size * count);
return sp_write(ctx, s->sample_buffer, sample_size * count);
}
static int write_frame(AVFilterContext *ctx, ASubProcessContext *s, AVFilterLink *inlink, AVFrame *in)
......@@ -583,7 +603,7 @@ static int activate(AVFilterContext *ctx)
}
if (s->eof && !sp_done(s->sp)) {
while (!sp_done(s->sp)) {
int ret = sp_write(ctx, s->sp, 0, 0);
int ret = sp_write(ctx, 0, 0);
if (ret != 0)
return ret;
}
......
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