X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Fsmacker.c;h=61209e7038481b35d2e8359b44153eda31af42f4;hb=337f777f378cfcc0d6f0d01fb7125905e8b0da55;hp=787c5d8972f66667ff2101c14ee4eaa9ad6e3865;hpb=02bbb3700670cc0bcf2c267ae48b21b0a9d7b599;p=ffmpeg diff --git a/libavformat/smacker.c b/libavformat/smacker.c index 787c5d8972f..61209e70384 100644 --- a/libavformat/smacker.c +++ b/libavformat/smacker.c @@ -48,15 +48,17 @@ typedef struct SmackerContext { uint32_t *frm_size; uint8_t *frm_flags; /* internal variables */ + int64_t next_frame_pos; int cur_frame; + int videoindex; + int indexes[7]; + int duration_size[7]; /* current frame for demuxing */ + uint32_t frame_size; + int flags; + int next_audio_index; + int new_palette; uint8_t pal[768]; - int indexes[7]; - int videoindex; - uint8_t *bufs[7]; - int buf_sizes[7]; - int stream_id[7]; - int curstream; int64_t aud_pts[7]; } SmackerContext; @@ -103,8 +105,8 @@ static int smacker_read_header(AVFormatContext *s) height = avio_rl32(pb); smk->frames = avio_rl32(pb); pts_inc = avio_rl32(pb); - if (pts_inc > INT_MAX / 100) { - av_log(s, AV_LOG_ERROR, "pts_inc %d is too large\n", pts_inc); + if (pts_inc > INT_MAX / 100 || pts_inc == INT_MIN) { + av_log(s, AV_LOG_ERROR, "pts_inc %d is invalid\n", pts_inc); return AVERROR_INVALIDDATA; } @@ -196,6 +198,8 @@ static int smacker_read_header(AVFormatContext *s) if (par->bits_per_coded_sample == 16 && par->codec_id == AV_CODEC_ID_PCM_U8) par->codec_id = AV_CODEC_ID_PCM_S16LE; + else + smk->duration_size[i] = 4; avpriv_set_pts_info(ast, 64, 1, par->sample_rate * par->channels * par->bits_per_coded_sample / 8); } @@ -204,75 +208,64 @@ static int smacker_read_header(AVFormatContext *s) avio_rl32(pb); /* padding */ /* setup data */ - smk->frm_size = av_malloc_array(smk->frames, sizeof(*smk->frm_size)); - smk->frm_flags = av_malloc(smk->frames); - if (!smk->frm_size || !smk->frm_flags) { - av_freep(&smk->frm_size); - av_freep(&smk->frm_flags); + st->priv_data = av_malloc_array(smk->frames, sizeof(*smk->frm_size) + + sizeof(*smk->frm_flags)); + if (!st->priv_data) return AVERROR(ENOMEM); - } + smk->frm_size = st->priv_data; + smk->frm_flags = (void*)(smk->frm_size + smk->frames); /* read frame info */ for (i = 0; i < smk->frames; i++) { smk->frm_size[i] = avio_rl32(pb); } - for (i = 0; i < smk->frames; i++) { - smk->frm_flags[i] = avio_r8(pb); - } - - /* load trees to extradata, they will be unpacked by decoder */ - ret = avio_read(pb, par->extradata + 16, par->extradata_size - 16); - if (ret != par->extradata_size - 16) { - av_freep(&smk->frm_size); - av_freep(&smk->frm_flags); - return AVERROR(EIO); + if ((ret = ffio_read_size(pb, smk->frm_flags, smk->frames)) < 0 || + /* load trees to extradata, they will be unpacked by decoder */ + (ret = ffio_read_size(pb, par->extradata + 16, + par->extradata_size - 16)) < 0) { + return ret; } return 0; } - static int smacker_read_packet(AVFormatContext *s, AVPacket *pkt) { SmackerContext *smk = s->priv_data; - int64_t next_frame_pos; int flags; int ret; - int i; - int frame_size = 0; - int palchange = 0; if (avio_feof(s->pb) || smk->cur_frame >= smk->frames) return AVERROR_EOF; /* if we demuxed all streams, pass another frame */ - if (smk->curstream <= 0) { - frame_size = smk->frm_size[smk->cur_frame] & (~3); - next_frame_pos = avio_tell(s->pb) + (unsigned)frame_size; + if (!smk->next_audio_index) { + smk->frame_size = smk->frm_size[smk->cur_frame] & (~3); + smk->next_frame_pos = avio_tell(s->pb) + smk->frame_size; flags = smk->frm_flags[smk->cur_frame]; + smk->flags = flags >> 1; /* handle palette change event */ - if(flags & SMACKER_PAL){ + if (flags & SMACKER_PAL) { int size, sz, t, off, j, pos; uint8_t *pal = smk->pal; uint8_t oldpal[768]; memcpy(oldpal, pal, 768); size = avio_r8(s->pb); - size = size * 4 - 1; - if (size + 1 > frame_size) { + size = size * 4; + if (size > smk->frame_size) { ret = AVERROR_INVALIDDATA; goto next_frame; } - frame_size -= size; - frame_size--; + smk->frame_size -= size--; sz = 0; pos = avio_tell(s->pb) + size; - while(sz < 256){ + while (sz < 256) { t = avio_r8(s->pb); - if(t & 0x80){ /* skip palette entries */ - sz += (t & 0x7F) + 1; + if (t & 0x80) { /* skip palette entries */ + sz += (t & 0x7F) + 1; pal += ((t & 0x7F) + 1) * 3; - } else if(t & 0x40){ /* copy with offset */ + } else if (t & 0x40) { /* copy with offset */ off = avio_r8(s->pb); j = (t & 0x3F) + 1; if (off + j > 0x100) { @@ -283,7 +276,7 @@ static int smacker_read_packet(AVFormatContext *s, AVPacket *pkt) goto next_frame; } off *= 3; - while(j-- && sz < 256) { + while (j-- && sz < 256) { *pal++ = oldpal[off + 0]; *pal++ = oldpal[off + 1]; *pal++ = oldpal[off + 2]; @@ -298,82 +291,97 @@ static int smacker_read_packet(AVFormatContext *s, AVPacket *pkt) } } avio_seek(s->pb, pos, 0); - palchange |= 1; + smk->new_palette = 1; } - flags >>= 1; - smk->curstream = 0; - /* if audio chunks are present, put them to stack and retrieve later */ - for(i = 0; i < 7; i++) { - if(flags & 1) { - uint32_t size; - - size = avio_rl32(s->pb) - 4; - if (!size || size + 4LL > frame_size) { - av_log(s, AV_LOG_ERROR, "Invalid audio part size\n"); - ret = AVERROR_INVALIDDATA; - goto next_frame; - } - frame_size -= size; - frame_size -= 4; - if ((ret = av_reallocp(&smk->bufs[smk->curstream], size)) < 0) { - smk->buf_sizes[smk->curstream] = 0; - goto next_frame; - } - smk->buf_sizes[smk->curstream] = size; - ret = ffio_read_size(s->pb, smk->bufs[smk->curstream], size); - if (ret < 0) - goto next_frame; - smk->stream_id[smk->curstream] = smk->indexes[i]; - smk->curstream++; + } + + for (int i = smk->next_audio_index; i < 7; i++) { + if (smk->flags & (1 << i)) { + uint32_t size; + + size = avio_rl32(s->pb); + if ((int)size < 4 + smk->duration_size[i] || size > smk->frame_size) { + av_log(s, AV_LOG_ERROR, "Invalid audio part size\n"); + ret = AVERROR_INVALIDDATA; + goto next_frame; } - flags >>= 1; - } - if (frame_size < 0 || frame_size >= INT_MAX/2) { - ret = AVERROR_INVALIDDATA; - goto next_frame; + smk->frame_size -= size; + size -= 4; + + if (smk->indexes[i] < 0 || + s->streams[smk->indexes[i]]->discard >= AVDISCARD_ALL) { + smk->aud_pts[i] += smk->duration_size[i] ? avio_rl32(s->pb) + : size; + avio_skip(s->pb, size - smk->duration_size[i]); + continue; + } + if ((ret = av_get_packet(s->pb, pkt, size)) != size) { + ret = ret < 0 ? ret : AVERROR_INVALIDDATA; + goto next_frame; + } + pkt->stream_index = smk->indexes[i]; + pkt->pts = smk->aud_pts[i]; + pkt->duration = smk->duration_size[i] ? AV_RL32(pkt->data) + : size; + smk->aud_pts[i] += pkt->duration; + smk->next_audio_index = i + 1; + return 0; } - if ((ret = av_new_packet(pkt, frame_size + 769)) < 0) - goto next_frame; - if(smk->frm_size[smk->cur_frame] & 1) - palchange |= 2; - pkt->data[0] = palchange; - memcpy(pkt->data + 1, smk->pal, 768); - ret = ffio_read_size(s->pb, pkt->data + 769, frame_size); - if (ret < 0) - goto next_frame; - pkt->stream_index = smk->videoindex; - pkt->pts = smk->cur_frame; - pkt->size = ret + 769; - smk->cur_frame++; - } else { - smk->curstream--; - if (smk->stream_id[smk->curstream] < 0 || !smk->bufs[smk->curstream]) - return AVERROR_INVALIDDATA; - if ((ret = av_new_packet(pkt, smk->buf_sizes[smk->curstream])) < 0) - return ret; - memcpy(pkt->data, smk->bufs[smk->curstream], smk->buf_sizes[smk->curstream]); - pkt->size = smk->buf_sizes[smk->curstream]; - pkt->stream_index = smk->stream_id[smk->curstream]; - pkt->pts = smk->aud_pts[smk->curstream]; - smk->aud_pts[smk->curstream] += AV_RL32(pkt->data); } + if (s->streams[smk->videoindex]->discard >= AVDISCARD_ALL) { + ret = FFERROR_REDO; + goto next_frame; + } + if (smk->frame_size >= INT_MAX/2) { + ret = AVERROR_INVALIDDATA; + goto next_frame; + } + if ((ret = av_new_packet(pkt, smk->frame_size + 769)) < 0) + goto next_frame; + flags = smk->new_palette; + if (smk->frm_size[smk->cur_frame] & 1) + flags |= 2; + pkt->data[0] = flags; + memcpy(pkt->data + 1, smk->pal, 768); + ret = ffio_read_size(s->pb, pkt->data + 769, smk->frame_size); + if (ret < 0) + goto next_frame; + pkt->stream_index = smk->videoindex; + pkt->pts = smk->cur_frame; + smk->next_audio_index = 0; + smk->new_palette = 0; + smk->cur_frame++; + return 0; next_frame: - avio_seek(s->pb, next_frame_pos, SEEK_SET); + avio_seek(s->pb, smk->next_frame_pos, SEEK_SET); + smk->next_audio_index = 0; smk->cur_frame++; return ret; } -static int smacker_read_close(AVFormatContext *s) +static int smacker_read_seek(AVFormatContext *s, int stream_index, + int64_t timestamp, int flags) { SmackerContext *smk = s->priv_data; - int i; + int64_t ret; + + /* only rewinding to start is supported */ + if (timestamp != 0) { + av_log(s, AV_LOG_ERROR, + "Random seeks are not supported (can only seek to start).\n"); + return AVERROR(EINVAL); + } + + if ((ret = avio_seek(s->pb, s->internal->data_offset, SEEK_SET)) < 0) + return ret; - for(i = 0; i < 7; i++) - av_freep(&smk->bufs[i]); - av_freep(&smk->frm_size); - av_freep(&smk->frm_flags); + smk->cur_frame = 0; + smk->next_audio_index = 0; + smk->new_palette = 0; + memset(smk->pal, 0, sizeof(smk->pal)); + memset(smk->aud_pts, 0, sizeof(smk->aud_pts)); return 0; } @@ -385,5 +393,5 @@ AVInputFormat ff_smacker_demuxer = { .read_probe = smacker_probe, .read_header = smacker_read_header, .read_packet = smacker_read_packet, - .read_close = smacker_read_close, + .read_seek = smacker_read_seek, };