Merge commit '5c54fc6195e52c329b88cf5a56d18628f0ee0029' into release/1.1

* commit '5c54fc6195e52c329b88cf5a56d18628f0ee0029':
  Prepare for 9.8 RELEASE
  update Changelog
  smacker: check frame size validity
  smacker: pad the extradata allocation
  smacker: check the return value of smacker_decode_tree
  smacker: fix an off by one in huff.length computation
  4xm: do not overread the prestream buffer
  4xm: validate the buffer size before parsing it
  4xm: reject frames not compatible with the declared version
  4xm: drop pointless assert
  4xm: forward errors from decode_p_block
  4xm: fold last_picture lazy allocation in decode_p_frame
  4xm: do not overread while parsing header
  4xm: refactor fourxm_read_header
  4xm: K&R formatting cosmetics
  4xm: use the correct logging context

Conflicts:
	Changelog
	RELEASE
	libavcodec/4xm.c
	libavcodec/smacker.c
	libavformat/4xm.c
	libavformat/smacker.c

Merged-by: Michael Niedermayer <michaelni@gmx.at>
This commit is contained in:
Michael Niedermayer
2013-08-27 15:37:41 +02:00
5 changed files with 242 additions and 175 deletions

View File

@@ -2,6 +2,27 @@ Entries are sorted chronologically from oldest to youngest within each release,
releases are sorted from youngest to oldest. releases are sorted from youngest to oldest.
version <next>: version <next>:
Most of the following fixes resulted from test samples that the Google
Security Team has kindly made available to us:
- 4xm: fix several programming errors to avoid crashes, etc.
- apetag: use int64_t for filesize
- jpegls: Fix invalid writes to memory
- ljpeg: use the correct number of components in YUV
- mjpeg: Validate sampling factors
- mjpegdec: properly report unsupported disabled features
- mjpegdec: validate parameters in mjpeg_decode_scan_progressive_ac
- mpegvideo: allocate sufficiently large scratch buffer for interlaced vid
- pixdesc: mark gray8 as pseudopal
- smacker: fix several programming errors to avoid crashes, etc.
- tiff: do not overread the source buffer
- vmd: drop incomplete chunks and spurious samples
- vmdav: convert to bytestream2 to avoid invalid reads and writes
- wavpack: check packet size early
- wavpack: use bytestream2 in wavpack_decode_block
- wavpack: validate samples size parsed in wavpack_decode_block
- aac: check the maximum number of channels to avoid invalid writes - aac: check the maximum number of channels to avoid invalid writes
- indeo3: fix off by one in MV validity check - indeo3: fix off by one in MV validity check
- id3v2: check for end of file while unescaping tags to avoid invalid - id3v2: check for end of file while unescaping tags to avoid invalid

View File

@@ -328,12 +328,12 @@ static inline void mcdc(uint16_t *dst, const uint16_t *src, int log2w,
} }
break; break;
default: default:
av_assert2(0); av_assert0(0);
} }
} }
static void decode_p_block(FourXContext *f, uint16_t *dst, uint16_t *src, static int decode_p_block(FourXContext *f, uint16_t *dst, uint16_t *src,
int log2w, int log2h, int stride) int log2w, int log2h, int stride)
{ {
const int index = size2index[log2h][log2w]; const int index = size2index[log2h][log2w];
const int h = 1 << log2h; const int h = 1 << log2h;
@@ -342,57 +342,64 @@ static void decode_p_block(FourXContext *f, uint16_t *dst, uint16_t *src,
BLOCK_TYPE_VLC_BITS, 1); BLOCK_TYPE_VLC_BITS, 1);
uint16_t *start = (uint16_t *)f->last_picture.data[0]; uint16_t *start = (uint16_t *)f->last_picture.data[0];
uint16_t *end = start + stride * (f->avctx->height - h + 1) - (1 << log2w); uint16_t *end = start + stride * (f->avctx->height - h + 1) - (1 << log2w);
int ret;
av_assert2(code >= 0 && code <= 6); av_assert0(code >= 0 && code <= 6 && log2w >= 0);
if (code == 0) { if (code == 0) {
if (bytestream2_get_bytes_left(&f->g) < 1) { if (bytestream2_get_bytes_left(&f->g) < 1) {
av_log(f->avctx, AV_LOG_ERROR, "bytestream overread\n"); av_log(f->avctx, AV_LOG_ERROR, "bytestream overread\n");
return; return AVERROR_INVALIDDATA;
} }
src += f->mv[bytestream2_get_byteu(&f->g)]; src += f->mv[bytestream2_get_byteu(&f->g)];
if (start > src || src > end) { if (start > src || src > end) {
av_log(f->avctx, AV_LOG_ERROR, "mv out of pic\n"); av_log(f->avctx, AV_LOG_ERROR, "mv out of pic\n");
return; return AVERROR_INVALIDDATA;
} }
mcdc(dst, src, log2w, h, stride, 1, 0); mcdc(dst, src, log2w, h, stride, 1, 0);
} else if (code == 1) { } else if (code == 1) {
log2h--; log2h--;
decode_p_block(f, dst, src, log2w, log2h, stride); if ((ret = decode_p_block(f, dst, src, log2w, log2h, stride)) < 0)
decode_p_block(f, dst + (stride << log2h), return ret;
src + (stride << log2h), log2w, log2h, stride); if ((ret = decode_p_block(f, dst + (stride << log2h),
src + (stride << log2h),
log2w, log2h, stride)) < 0)
return ret;
} else if (code == 2) { } else if (code == 2) {
log2w--; log2w--;
decode_p_block(f, dst , src, log2w, log2h, stride); if ((ret = decode_p_block(f, dst , src, log2w, log2h, stride)) < 0)
decode_p_block(f, dst + (1 << log2w), return ret;
src + (1 << log2w), log2w, log2h, stride); if ((ret = decode_p_block(f, dst + (1 << log2w),
src + (1 << log2w),
log2w, log2h, stride)) < 0)
return ret;
} else if (code == 3 && f->version < 2) { } else if (code == 3 && f->version < 2) {
mcdc(dst, src, log2w, h, stride, 1, 0); mcdc(dst, src, log2w, h, stride, 1, 0);
} else if (code == 4) { } else if (code == 4) {
if (bytestream2_get_bytes_left(&f->g) < 1) { if (bytestream2_get_bytes_left(&f->g) < 1) {
av_log(f->avctx, AV_LOG_ERROR, "bytestream overread\n"); av_log(f->avctx, AV_LOG_ERROR, "bytestream overread\n");
return; return AVERROR_INVALIDDATA;
} }
src += f->mv[bytestream2_get_byteu(&f->g)]; src += f->mv[bytestream2_get_byteu(&f->g)];
if (start > src || src > end) { if (start > src || src > end) {
av_log(f->avctx, AV_LOG_ERROR, "mv out of pic\n"); av_log(f->avctx, AV_LOG_ERROR, "mv out of pic\n");
return; return AVERROR_INVALIDDATA;
} }
if (bytestream2_get_bytes_left(&f->g2) < 2){ if (bytestream2_get_bytes_left(&f->g2) < 2){
av_log(f->avctx, AV_LOG_ERROR, "wordstream overread\n"); av_log(f->avctx, AV_LOG_ERROR, "wordstream overread\n");
return; return AVERROR_INVALIDDATA;
} }
mcdc(dst, src, log2w, h, stride, 1, bytestream2_get_le16u(&f->g2)); mcdc(dst, src, log2w, h, stride, 1, bytestream2_get_le16u(&f->g2));
} else if (code == 5) { } else if (code == 5) {
if (bytestream2_get_bytes_left(&f->g2) < 2) { if (bytestream2_get_bytes_left(&f->g2) < 2) {
av_log(f->avctx, AV_LOG_ERROR, "wordstream overread\n"); av_log(f->avctx, AV_LOG_ERROR, "wordstream overread\n");
return; return AVERROR_INVALIDDATA;
} }
mcdc(dst, src, log2w, h, stride, 0, bytestream2_get_le16u(&f->g2)); mcdc(dst, src, log2w, h, stride, 0, bytestream2_get_le16u(&f->g2));
} else if (code == 6) { } else if (code == 6) {
if (bytestream2_get_bytes_left(&f->g2) < 4) { if (bytestream2_get_bytes_left(&f->g2) < 4) {
av_log(f->avctx, AV_LOG_ERROR, "wordstream overread\n"); av_log(f->avctx, AV_LOG_ERROR, "wordstream overread\n");
return; return AVERROR_INVALIDDATA;
} }
if (log2w) { if (log2w) {
dst[0] = bytestream2_get_le16u(&f->g2); dst[0] = bytestream2_get_le16u(&f->g2);
@@ -402,6 +409,7 @@ static void decode_p_block(FourXContext *f, uint16_t *dst, uint16_t *src,
dst[stride] = bytestream2_get_le16u(&f->g2); dst[stride] = bytestream2_get_le16u(&f->g2);
} }
} }
return 0;
} }
static int decode_p_frame(FourXContext *f, const uint8_t *buf, int length) static int decode_p_frame(FourXContext *f, const uint8_t *buf, int length)
@@ -414,8 +422,20 @@ static int decode_p_frame(FourXContext *f, const uint8_t *buf, int length)
const int stride = f->current_picture.linesize[0] >> 1; const int stride = f->current_picture.linesize[0] >> 1;
unsigned int bitstream_size, bytestream_size, wordstream_size, extra, unsigned int bitstream_size, bytestream_size, wordstream_size, extra,
bytestream_offset, wordstream_offset; bytestream_offset, wordstream_offset;
int ret;
if (!f->last_picture.data[0]) {
if ((ret = ff_get_buffer(f->avctx, &f->last_picture)) < 0) {
av_log(f->avctx, AV_LOG_ERROR, "get_buffer() failed\n");
return ret;
}
for (y=0; y<f->avctx->height; y++)
memset(f->last_picture.data[0] + y*f->last_picture.linesize[0], 0, 2*f->avctx->width);
}
if (f->version > 1) { if (f->version > 1) {
if (length < 20)
return AVERROR_INVALIDDATA;
extra = 20; extra = 20;
if (length < extra) if (length < extra)
return -1; return -1;
@@ -459,7 +479,8 @@ static int decode_p_frame(FourXContext *f, const uint8_t *buf, int length)
for (y = 0; y < height; y += 8) { for (y = 0; y < height; y += 8) {
for (x = 0; x < width; x += 8) for (x = 0; x < width; x += 8)
decode_p_block(f, dst + x, src + x, 3, 3, stride); if ((ret = decode_p_block(f, dst + x, src + x, 3, 3, stride)) < 0)
return ret;
src += 8 * stride; src += 8 * stride;
dst += 8 * stride; dst += 8 * stride;
} }
@@ -579,7 +600,8 @@ static int decode_i_mb(FourXContext *f)
} }
static const uint8_t *read_huffman_tables(FourXContext *f, static const uint8_t *read_huffman_tables(FourXContext *f,
const uint8_t * const buf, int buf_size) const uint8_t * const buf,
int buf_size)
{ {
int frequency[512] = { 0 }; int frequency[512] = { 0 };
uint8_t flag[512]; uint8_t flag[512];
@@ -598,8 +620,11 @@ static const uint8_t *read_huffman_tables(FourXContext *f,
for (;;) { for (;;) {
int i; int i;
if (start <= end && ptr_end - ptr < end - start + 1 + 1) if (ptr_end - ptr < FFMAX(end - start + 1, 0) + 1) {
av_log(f->avctx, AV_LOG_ERROR, "invalid data in read_huffman_tables\n");
return NULL; return NULL;
}
for (i = start; i <= end; i++) for (i = start; i <= end; i++)
frequency[i] = *ptr++; frequency[i] = *ptr++;
start = *ptr++; start = *ptr++;
@@ -701,9 +726,9 @@ static int decode_i2_frame(FourXContext *f, const uint8_t *buf, int length)
color[1] = bytestream2_get_le16u(&g3); color[1] = bytestream2_get_le16u(&g3);
if (color[0] & 0x8000) if (color[0] & 0x8000)
av_log(NULL, AV_LOG_ERROR, "unk bit 1\n"); av_log(f->avctx, AV_LOG_ERROR, "unk bit 1\n");
if (color[1] & 0x8000) if (color[1] & 0x8000)
av_log(NULL, AV_LOG_ERROR, "unk bit 2\n"); av_log(f->avctx, AV_LOG_ERROR, "unk bit 2\n");
color[2] = mix(color[0], color[1]); color[2] = mix(color[0], color[1]);
color[3] = mix(color[1], color[0]); color[3] = mix(color[1], color[0]);
@@ -748,7 +773,7 @@ static int decode_i_frame(FourXContext *f, const uint8_t *buf, int length)
return -1; return -1;
} }
prestream = read_huffman_tables(f, prestream, buf + length - prestream); prestream = read_huffman_tables(f, prestream, prestream_size);
if (!prestream) { if (!prestream) {
av_log(f->avctx, AV_LOG_ERROR, "Error reading Huffman tables.\n"); av_log(f->avctx, AV_LOG_ERROR, "Error reading Huffman tables.\n");
return AVERROR_INVALIDDATA; return AVERROR_INVALIDDATA;
@@ -795,30 +820,38 @@ static int decode_frame(AVCodecContext *avctx, void *data,
AVFrame *p, temp; AVFrame *p, temp;
int i, frame_4cc, frame_size; int i, frame_4cc, frame_size;
if (buf_size < 12) if (buf_size < 20)
return AVERROR_INVALIDDATA; return AVERROR_INVALIDDATA;
frame_4cc = AV_RL32(buf);
if (buf_size != AV_RL32(buf + 4) + 8 || buf_size < 20) av_assert0(avctx->width % 16 == 0 && avctx->height % 16 == 0);
if (buf_size < AV_RL32(buf + 4) + 8) {
av_log(f->avctx, AV_LOG_ERROR, "size mismatch %d %d\n", av_log(f->avctx, AV_LOG_ERROR, "size mismatch %d %d\n",
buf_size, AV_RL32(buf + 4)); buf_size, AV_RL32(buf + 4));
return AVERROR_INVALIDDATA;
}
frame_4cc = AV_RL32(buf);
if (frame_4cc == AV_RL32("cfrm")) { if (frame_4cc == AV_RL32("cfrm")) {
int free_index = -1; int free_index = -1;
int id, whole_size;
const int data_size = buf_size - 20; const int data_size = buf_size - 20;
const int id = AV_RL32(buf + 12);
const int whole_size = AV_RL32(buf + 16);
CFrameBuffer *cfrm; CFrameBuffer *cfrm;
if (data_size < 0 || whole_size < 0) {
av_log(f->avctx, AV_LOG_ERROR, "sizes invalid\n");
return AVERROR_INVALIDDATA;
}
if (f->version <= 1) { if (f->version <= 1) {
av_log(f->avctx, AV_LOG_ERROR, "cfrm in version %d\n", f->version); av_log(f->avctx, AV_LOG_ERROR, "cfrm in version %d\n", f->version);
return AVERROR_INVALIDDATA; return AVERROR_INVALIDDATA;
} }
id = AV_RL32(buf + 12);
whole_size = AV_RL32(buf + 16);
if (data_size < 0 || whole_size < 0) {
av_log(f->avctx, AV_LOG_ERROR, "sizes invalid\n");
return AVERROR_INVALIDDATA;
}
for (i = 0; i < CFRAME_BUFFER_COUNT; i++) for (i = 0; i < CFRAME_BUFFER_COUNT; i++)
if (f->cfrm[i].id && f->cfrm[i].id < avctx->frame_number) if (f->cfrm[i].id && f->cfrm[i].id < avctx->frame_number)
av_log(f->avctx, AV_LOG_ERROR, "lost c frame %d\n", av_log(f->avctx, AV_LOG_ERROR, "lost c frame %d\n",
@@ -859,6 +892,9 @@ static int decode_frame(AVCodecContext *avctx, void *data,
av_log(f->avctx, AV_LOG_ERROR, "cframe id mismatch %d %d\n", av_log(f->avctx, AV_LOG_ERROR, "cframe id mismatch %d %d\n",
id, avctx->frame_number); id, avctx->frame_number);
if (f->version <= 1)
return AVERROR_INVALIDDATA;
cfrm->size = cfrm->id = 0; cfrm->size = cfrm->id = 0;
frame_4cc = AV_RL32("pfrm"); frame_4cc = AV_RL32("pfrm");
} else } else
@@ -897,16 +933,6 @@ static int decode_frame(AVCodecContext *avctx, void *data,
return -1; return -1;
} }
} else if (frame_4cc == AV_RL32("pfrm") || frame_4cc == AV_RL32("pfr2")) { } else if (frame_4cc == AV_RL32("pfrm") || frame_4cc == AV_RL32("pfr2")) {
if (!f->last_picture.data[0]) {
f->last_picture.reference = 3;
if (ff_get_buffer(avctx, &f->last_picture) < 0) {
av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
return -1;
}
for (i=0; i<avctx->height; i++)
memset(f->last_picture.data[0] + i*f->last_picture.linesize[0], 0, 2*avctx->width);
}
p->pict_type = AV_PICTURE_TYPE_P; p->pict_type = AV_PICTURE_TYPE_P;
if (decode_p_frame(f, buf, frame_size) < 0) { if (decode_p_frame(f, buf, frame_size) < 0) {
av_log(f->avctx, AV_LOG_ERROR, "decode p frame failed\n"); av_log(f->avctx, AV_LOG_ERROR, "decode p frame failed\n");

View File

@@ -257,7 +257,7 @@ static int smacker_decode_header_tree(SmackVContext *smk, GetBitContext *gb, int
ctx.recode2 = tmp2.values; ctx.recode2 = tmp2.values;
ctx.last = last; ctx.last = last;
huff.length = ((size + 3) >> 2) + 3; huff.length = ((size + 3) >> 2) + 4;
huff.maxlength = 0; huff.maxlength = 0;
huff.current = 0; huff.current = 0;
huff.values = av_mallocz(huff.length * sizeof(int)); huff.values = av_mallocz(huff.length * sizeof(int));
@@ -661,9 +661,16 @@ static int smka_decode_frame(AVCodecContext *avctx, void *data,
h[i].lengths = av_mallocz(256 * sizeof(int)); h[i].lengths = av_mallocz(256 * sizeof(int));
h[i].values = av_mallocz(256 * sizeof(int)); h[i].values = av_mallocz(256 * sizeof(int));
skip_bits1(&gb); skip_bits1(&gb);
res = smacker_decode_tree(&gb, &h[i], 0, 0); if (smacker_decode_tree(&gb, &h[i], 0, 0) < 0) {
if (res < 0) for (; i >= 0; i--) {
return res; if (vlc[i].table)
ff_free_vlc(&vlc[i]);
av_free(h[i].bits);
av_free(h[i].lengths);
av_free(h[i].values);
}
return AVERROR_INVALIDDATA;
}
skip_bits1(&gb); skip_bits1(&gb);
if(h[i].current > 1) { if(h[i].current > 1) {
res = init_vlc(&vlc[i], SMKTREE_BITS, h[i].length, res = init_vlc(&vlc[i], SMKTREE_BITS, h[i].length,

View File

@@ -57,7 +57,7 @@
#define GET_LIST_HEADER() \ #define GET_LIST_HEADER() \
fourcc_tag = avio_rl32(pb); \ fourcc_tag = avio_rl32(pb); \
size = avio_rl32(pb); \ size = avio_rl32(pb); \
if (fourcc_tag != LIST_TAG) \ if (fourcc_tag != LIST_TAG) \
return AVERROR_INVALIDDATA; \ return AVERROR_INVALIDDATA; \
fourcc_tag = avio_rl32(pb); fourcc_tag = avio_rl32(pb);
@@ -72,8 +72,6 @@ typedef struct AudioTrack {
} AudioTrack; } AudioTrack;
typedef struct FourxmDemuxContext { typedef struct FourxmDemuxContext {
int width;
int height;
int video_stream_index; int video_stream_index;
int track_count; int track_count;
AudioTrack *tracks; AudioTrack *tracks;
@@ -91,6 +89,108 @@ static int fourxm_probe(AVProbeData *p)
return AVPROBE_SCORE_MAX; return AVPROBE_SCORE_MAX;
} }
static int parse_vtrk(AVFormatContext *s,
FourxmDemuxContext *fourxm, uint8_t *buf, int size,
int left)
{
AVStream *st;
/* check that there is enough data */
if (size != vtrk_SIZE || left < size + 8) {
return AVERROR_INVALIDDATA;
}
/* allocate a new AVStream */
st = avformat_new_stream(s, NULL);
if (!st)
return AVERROR(ENOMEM);
avpriv_set_pts_info(st, 60, 1, fourxm->fps);
fourxm->video_stream_index = st->index;
st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
st->codec->codec_id = AV_CODEC_ID_4XM;
st->codec->extradata_size = 4;
st->codec->extradata = av_malloc(4);
AV_WL32(st->codec->extradata, AV_RL32(buf + 16));
st->codec->width = AV_RL32(buf + 36);
st->codec->height = AV_RL32(buf + 40);
return 0;
}
static int parse_strk(AVFormatContext *s,
FourxmDemuxContext *fourxm, uint8_t *buf, int size,
int left)
{
AVStream *st;
int track;
/* check that there is enough data */
if (size != strk_SIZE || left < size + 8)
return AVERROR_INVALIDDATA;
track = AV_RL32(buf + 8);
if ((unsigned)track >= UINT_MAX / sizeof(AudioTrack) - 1) {
av_log(s, AV_LOG_ERROR, "current_track too large\n");
return AVERROR_INVALIDDATA;
}
if (track + 1 > fourxm->track_count) {
fourxm->tracks = av_realloc_f(fourxm->tracks, track + 1, sizeof(AudioTrack));
if (!fourxm->tracks)
return AVERROR(ENOMEM);
memset(&fourxm->tracks[fourxm->track_count], 0,
sizeof(AudioTrack) * (track + 1 - fourxm->track_count));
fourxm->track_count = track + 1;
}
fourxm->tracks[track].adpcm = AV_RL32(buf + 12);
fourxm->tracks[track].channels = AV_RL32(buf + 36);
fourxm->tracks[track].sample_rate = AV_RL32(buf + 40);
fourxm->tracks[track].bits = AV_RL32(buf + 44);
fourxm->tracks[track].audio_pts = 0;
if (fourxm->tracks[track].channels <= 0 ||
fourxm->tracks[track].sample_rate <= 0 ||
fourxm->tracks[track].bits < 0) {
av_log(s, AV_LOG_ERROR, "audio header invalid\n");
return AVERROR_INVALIDDATA;
}
if (!fourxm->tracks[track].adpcm && fourxm->tracks[track].bits<8) {
av_log(s, AV_LOG_ERROR, "bits unspecified for non ADPCM\n");
return AVERROR_INVALIDDATA;
}
/* allocate a new AVStream */
st = avformat_new_stream(s, NULL);
if (!st)
return AVERROR(ENOMEM);
st->id = track;
avpriv_set_pts_info(st, 60, 1, fourxm->tracks[track].sample_rate);
fourxm->tracks[track].stream_index = st->index;
st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
st->codec->codec_tag = 0;
st->codec->channels = fourxm->tracks[track].channels;
st->codec->sample_rate = fourxm->tracks[track].sample_rate;
st->codec->bits_per_coded_sample = fourxm->tracks[track].bits;
st->codec->bit_rate = st->codec->channels *
st->codec->sample_rate *
st->codec->bits_per_coded_sample;
st->codec->block_align = st->codec->channels *
st->codec->bits_per_coded_sample;
if (fourxm->tracks[track].adpcm){
st->codec->codec_id = AV_CODEC_ID_ADPCM_4XM;
} else if (st->codec->bits_per_coded_sample == 8) {
st->codec->codec_id = AV_CODEC_ID_PCM_U8;
} else
st->codec->codec_id = AV_CODEC_ID_PCM_S16LE;
return 0;
}
static int fourxm_read_header(AVFormatContext *s) static int fourxm_read_header(AVFormatContext *s)
{ {
AVIOContext *pb = s->pb; AVIOContext *pb = s->pb;
@@ -100,11 +200,10 @@ static int fourxm_read_header(AVFormatContext *s)
FourxmDemuxContext *fourxm = s->priv_data; FourxmDemuxContext *fourxm = s->priv_data;
unsigned char *header; unsigned char *header;
int i, ret; int i, ret;
AVStream *st;
fourxm->track_count = 0; fourxm->track_count = 0;
fourxm->tracks = NULL; fourxm->tracks = NULL;
fourxm->fps = 1.0; fourxm->fps = 1.0;
/* skip the first 3 32-bit numbers */ /* skip the first 3 32-bit numbers */
avio_skip(pb, 12); avio_skip(pb, 12);
@@ -119,7 +218,7 @@ static int fourxm_read_header(AVFormatContext *s)
header = av_malloc(header_size); header = av_malloc(header_size);
if (!header) if (!header)
return AVERROR(ENOMEM); return AVERROR(ENOMEM);
if (avio_read(pb, header, header_size) != header_size){ if (avio_read(pb, header, header_size) != header_size) {
av_free(header); av_free(header);
return AVERROR(EIO); return AVERROR(EIO);
} }
@@ -127,123 +226,38 @@ static int fourxm_read_header(AVFormatContext *s)
/* take the lazy approach and search for any and all vtrk and strk chunks */ /* take the lazy approach and search for any and all vtrk and strk chunks */
for (i = 0; i < header_size - 8; i++) { for (i = 0; i < header_size - 8; i++) {
fourcc_tag = AV_RL32(&header[i]); fourcc_tag = AV_RL32(&header[i]);
size = AV_RL32(&header[i + 4]); size = AV_RL32(&header[i + 4]);
if (size > header_size - i - 8 && (fourcc_tag == vtrk_TAG || fourcc_tag == strk_TAG)) { if (size > header_size - i - 8 && (fourcc_tag == vtrk_TAG || fourcc_tag == strk_TAG)) {
av_log(s, AV_LOG_ERROR, "chunk larger than array %d>%d\n", size, header_size - i - 8); av_log(s, AV_LOG_ERROR, "chunk larger than array %d>%d\n", size, header_size - i - 8);
return AVERROR_INVALIDDATA; return AVERROR_INVALIDDATA;
} }
if (fourcc_tag == std__TAG) { if (fourcc_tag == std__TAG) {
if (header_size < i + 16) { if (header_size - i < 16) {
av_log(s, AV_LOG_ERROR, "std TAG truncated\n"); av_log(s, AV_LOG_ERROR, "std TAG truncated\n");
return AVERROR_INVALIDDATA; ret = AVERROR_INVALIDDATA;
goto fail;
} }
fourxm->fps = av_int2float(AV_RL32(&header[i + 12])); fourxm->fps = av_int2float(AV_RL32(&header[i + 12]));
} else if (fourcc_tag == vtrk_TAG) { } else if (fourcc_tag == vtrk_TAG) {
/* check that there is enough data */ if ((ret = parse_vtrk(s, fourxm, header + i, size,
if (size != vtrk_SIZE) { header_size - i)) < 0)
ret= AVERROR_INVALIDDATA;
goto fail; goto fail;
}
fourxm->width = AV_RL32(&header[i + 36]);
fourxm->height = AV_RL32(&header[i + 40]);
/* allocate a new AVStream */
st = avformat_new_stream(s, NULL);
if (!st){
ret= AVERROR(ENOMEM);
goto fail;
}
avpriv_set_pts_info(st, 60, 1, fourxm->fps);
fourxm->video_stream_index = st->index;
st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
st->codec->codec_id = AV_CODEC_ID_4XM;
st->codec->extradata_size = 4;
st->codec->extradata = av_malloc(4);
AV_WL32(st->codec->extradata, AV_RL32(&header[i + 16]));
st->codec->width = fourxm->width;
st->codec->height = fourxm->height;
i += 8 + size; i += 8 + size;
} else if (fourcc_tag == strk_TAG) { } else if (fourcc_tag == strk_TAG) {
int current_track; if ((ret = parse_strk(s, fourxm, header + i, size,
/* check that there is enough data */ header_size - i)) < 0)
if (size != strk_SIZE) {
ret= AVERROR_INVALIDDATA;
goto fail; goto fail;
}
current_track = AV_RL32(&header[i + 8]);
if((unsigned)current_track >= UINT_MAX / sizeof(AudioTrack) - 1){
av_log(s, AV_LOG_ERROR, "current_track too large\n");
ret = AVERROR_INVALIDDATA;
goto fail;
}
if (current_track + 1 > fourxm->track_count) {
fourxm->tracks = av_realloc_f(fourxm->tracks,
sizeof(AudioTrack),
current_track + 1);
if (!fourxm->tracks) {
ret = AVERROR(ENOMEM);
goto fail;
}
memset(&fourxm->tracks[fourxm->track_count], 0,
sizeof(AudioTrack) * (current_track + 1 - fourxm->track_count));
fourxm->track_count = current_track + 1;
}
fourxm->tracks[current_track].adpcm = AV_RL32(&header[i + 12]);
fourxm->tracks[current_track].channels = AV_RL32(&header[i + 36]);
fourxm->tracks[current_track].sample_rate = AV_RL32(&header[i + 40]);
fourxm->tracks[current_track].bits = AV_RL32(&header[i + 44]);
fourxm->tracks[current_track].audio_pts = 0;
if( fourxm->tracks[current_track].channels <= 0
|| fourxm->tracks[current_track].sample_rate <= 0
|| fourxm->tracks[current_track].bits < 0){
av_log(s, AV_LOG_ERROR, "audio header invalid\n");
ret = AVERROR_INVALIDDATA;
goto fail;
}
if(!fourxm->tracks[current_track].adpcm && fourxm->tracks[current_track].bits<8){
av_log(s, AV_LOG_ERROR, "bits unspecified for non ADPCM\n");
ret = AVERROR_INVALIDDATA;
goto fail;
}
i += 8 + size; i += 8 + size;
/* allocate a new AVStream */
st = avformat_new_stream(s, NULL);
if (!st){
ret= AVERROR(ENOMEM);
goto fail;
}
st->id = current_track;
avpriv_set_pts_info(st, 60, 1, fourxm->tracks[current_track].sample_rate);
fourxm->tracks[current_track].stream_index = st->index;
st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
st->codec->codec_tag = 0;
st->codec->channels = fourxm->tracks[current_track].channels;
st->codec->sample_rate = fourxm->tracks[current_track].sample_rate;
st->codec->bits_per_coded_sample = fourxm->tracks[current_track].bits;
st->codec->bit_rate = st->codec->channels * st->codec->sample_rate *
st->codec->bits_per_coded_sample;
st->codec->block_align = st->codec->channels * st->codec->bits_per_coded_sample;
if (fourxm->tracks[current_track].adpcm){
st->codec->codec_id = AV_CODEC_ID_ADPCM_4XM;
}else if (st->codec->bits_per_coded_sample == 8){
st->codec->codec_id = AV_CODEC_ID_PCM_U8;
}else
st->codec->codec_id = AV_CODEC_ID_PCM_S16LE;
} }
} }
/* skip over the LIST-MOVI chunk (which is where the stream should be */ /* skip over the LIST-MOVI chunk (which is where the stream should be */
GET_LIST_HEADER(); GET_LIST_HEADER();
if (fourcc_tag != MOVI_TAG){ if (fourcc_tag != MOVI_TAG) {
ret= AVERROR_INVALIDDATA; ret = AVERROR_INVALIDDATA;
goto fail; goto fail;
} }
@@ -262,7 +276,7 @@ static int fourxm_read_packet(AVFormatContext *s,
AVPacket *pkt) AVPacket *pkt)
{ {
FourxmDemuxContext *fourxm = s->priv_data; FourxmDemuxContext *fourxm = s->priv_data;
AVIOContext *pb = s->pb; AVIOContext *pb = s->pb;
unsigned int fourcc_tag; unsigned int fourcc_tag;
unsigned int size; unsigned int size;
int ret = 0; int ret = 0;
@@ -272,18 +286,16 @@ static int fourxm_read_packet(AVFormatContext *s,
int audio_frame_count; int audio_frame_count;
while (!packet_read) { while (!packet_read) {
if ((ret = avio_read(s->pb, header, 8)) < 0) if ((ret = avio_read(s->pb, header, 8)) < 0)
return ret; return ret;
fourcc_tag = AV_RL32(&header[0]); fourcc_tag = AV_RL32(&header[0]);
size = AV_RL32(&header[4]); size = AV_RL32(&header[4]);
if (url_feof(pb)) if (url_feof(pb))
return AVERROR(EIO); return AVERROR(EIO);
switch (fourcc_tag) { switch (fourcc_tag) {
case LIST_TAG: case LIST_TAG:
/* this is a good time to bump the video pts */ /* this is a good time to bump the video pts */
fourxm->video_pts ++; fourxm->video_pts++;
/* skip the LIST-* tag and move on to the next fourcc */ /* skip the LIST-* tag and move on to the next fourcc */
avio_rl32(pb); avio_rl32(pb);
@@ -300,45 +312,43 @@ static int fourxm_read_packet(AVFormatContext *s,
if (size + 8 < size || av_new_packet(pkt, size + 8)) if (size + 8 < size || av_new_packet(pkt, size + 8))
return AVERROR(EIO); return AVERROR(EIO);
pkt->stream_index = fourxm->video_stream_index; pkt->stream_index = fourxm->video_stream_index;
pkt->pts = fourxm->video_pts; pkt->pts = fourxm->video_pts;
pkt->pos = avio_tell(s->pb); pkt->pos = avio_tell(s->pb);
memcpy(pkt->data, header, 8); memcpy(pkt->data, header, 8);
ret = avio_read(s->pb, &pkt->data[8], size); ret = avio_read(s->pb, &pkt->data[8], size);
if (ret < 0){ if (ret < 0) {
av_free_packet(pkt); av_free_packet(pkt);
}else } else
packet_read = 1; packet_read = 1;
break; break;
case snd__TAG: case snd__TAG:
track_number = avio_rl32(pb); track_number = avio_rl32(pb);
avio_skip(pb, 4); avio_skip(pb, 4);
size-=8; size -= 8;
if (track_number < fourxm->track_count && fourxm->tracks[track_number].channels>0) { if (track_number < fourxm->track_count &&
ret= av_get_packet(s->pb, pkt, size); fourxm->tracks[track_number].channels > 0) {
if(ret<0) ret = av_get_packet(s->pb, pkt, size);
if (ret < 0)
return AVERROR(EIO); return AVERROR(EIO);
pkt->stream_index = pkt->stream_index =
fourxm->tracks[track_number].stream_index; fourxm->tracks[track_number].stream_index;
pkt->pts = fourxm->tracks[track_number].audio_pts; pkt->pts = fourxm->tracks[track_number].audio_pts;
packet_read = 1; packet_read = 1;
/* pts accounting */ /* pts accounting */
audio_frame_count = size; audio_frame_count = size;
if (fourxm->tracks[track_number].adpcm) if (fourxm->tracks[track_number].adpcm)
audio_frame_count -= audio_frame_count -= 2 * (fourxm->tracks[track_number].channels);
2 * (fourxm->tracks[track_number].channels); audio_frame_count /= fourxm->tracks[track_number].channels;
audio_frame_count /= if (fourxm->tracks[track_number].adpcm) {
fourxm->tracks[track_number].channels;
if (fourxm->tracks[track_number].adpcm){
audio_frame_count *= 2; audio_frame_count *= 2;
}else } else
audio_frame_count /= audio_frame_count /=
(fourxm->tracks[track_number].bits / 8); (fourxm->tracks[track_number].bits / 8);
fourxm->tracks[track_number].audio_pts += audio_frame_count; fourxm->tracks[track_number].audio_pts += audio_frame_count;
} else { } else {
avio_skip(pb, size); avio_skip(pb, size);
} }

View File

@@ -210,7 +210,8 @@ static int smacker_read_header(AVFormatContext *s)
/* load trees to extradata, they will be unpacked by decoder */ /* load trees to extradata, they will be unpacked by decoder */
st->codec->extradata = av_malloc(smk->treesize + 16 + FF_INPUT_BUFFER_PADDING_SIZE); st->codec->extradata = av_mallocz(smk->treesize + 16 +
FF_INPUT_BUFFER_PADDING_SIZE);
st->codec->extradata_size = smk->treesize + 16; st->codec->extradata_size = smk->treesize + 16;
if(!st->codec->extradata){ if(!st->codec->extradata){
av_log(s, AV_LOG_ERROR, "Cannot allocate %i bytes of extradata\n", smk->treesize + 16); av_log(s, AV_LOG_ERROR, "Cannot allocate %i bytes of extradata\n", smk->treesize + 16);
@@ -305,12 +306,14 @@ static int smacker_read_packet(AVFormatContext *s, AVPacket *pkt)
/* if audio chunks are present, put them to stack and retrieve later */ /* if audio chunks are present, put them to stack and retrieve later */
for(i = 0; i < 7; i++) { for(i = 0; i < 7; i++) {
if(flags & 1) { if(flags & 1) {
unsigned int size; uint32_t size;
uint8_t *tmpbuf; uint8_t *tmpbuf;
size = avio_rl32(s->pb) - 4; size = avio_rl32(s->pb) - 4;
if(size + 4L > frame_size) if (!size || size + 4L > frame_size) {
av_log(s, AV_LOG_ERROR, "Invalid audio part size\n");
return AVERROR_INVALIDDATA; return AVERROR_INVALIDDATA;
}
frame_size -= size; frame_size -= size;
frame_size -= 4; frame_size -= 4;
smk->curstream++; smk->curstream++;