X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Fsmacker.c;h=a96093b191dd0cb692e16ef4554291e9c99e168b;hb=4be1714b12b6c311a99a64888ea5f279c3ed9885;hp=0138af3d1405ef6415458b5fbeb0a3b64280df19;hpb=6e5dbd62681c2059bb7047f0b42d33fdf5a9d40d;p=ffmpeg diff --git a/libavformat/smacker.c b/libavformat/smacker.c index 0138af3d140..a96093b191d 100644 --- a/libavformat/smacker.c +++ b/libavformat/smacker.c @@ -50,14 +50,15 @@ typedef struct SmackerContext { /* 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; int64_t aud_pts[7]; } SmackerContext; @@ -104,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; } @@ -197,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); } @@ -205,34 +208,27 @@ 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; @@ -249,7 +245,7 @@ static int smacker_read_packet(AVFormatContext *s, AVPacket *pkt) 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]; @@ -264,12 +260,12 @@ static int smacker_read_packet(AVFormatContext *s, AVPacket *pkt) 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) { @@ -280,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]; @@ -301,53 +297,61 @@ static int smacker_read_packet(AVFormatContext *s, AVPacket *pkt) for (int i = smk->next_audio_index; i < 7; i++) { if (smk->flags & (1 << i)) { - uint32_t size; + uint32_t size; - size = avio_rl32(s->pb); - if ((int)size < 8 || size > smk->frame_size) { - av_log(s, AV_LOG_ERROR, "Invalid audio part size\n"); - ret = AVERROR_INVALIDDATA; - goto next_frame; - } + 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; + } smk->frame_size -= size; - size -= 4; + size -= 4; - if (smk->indexes[i] < 0) { - avio_skip(s->pb, size); + 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; - } + goto next_frame; + } pkt->stream_index = smk->indexes[i]; pkt->pts = smk->aud_pts[i]; - smk->aud_pts[i] += AV_RL32(pkt->data); + 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 (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; - } + ret = AVERROR_INVALIDDATA; + goto next_frame; + } if ((ret = av_new_packet(pkt, smk->frame_size + 769)) < 0) - goto next_frame; + goto next_frame; flags = smk->new_palette; - if(smk->frm_size[smk->cur_frame] & 1) + if (smk->frm_size[smk->cur_frame] & 1) flags |= 2; pkt->data[0] = flags; - memcpy(pkt->data + 1, smk->pal, 768); + 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; - pkt->size = ret + 769; + 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++; + smk->cur_frame++; return 0; next_frame: @@ -357,22 +361,37 @@ next_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; + int64_t ret; - av_freep(&smk->frm_size); - av_freep(&smk->frm_flags); + /* 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; + + 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; } -AVInputFormat ff_smacker_demuxer = { +const AVInputFormat ff_smacker_demuxer = { .name = "smk", .long_name = NULL_IF_CONFIG_SMALL("Smacker"), .priv_data_size = sizeof(SmackerContext), .read_probe = smacker_probe, .read_header = smacker_read_header, .read_packet = smacker_read_packet, - .read_close = smacker_read_close, + .read_seek = smacker_read_seek, };