[FFmpeg-devel] [PATCH] PAF demuxer and decoder
Paul B Mahol
onemda at gmail.com
Wed Jul 4 00:57:10 CEST 2012
On 7/3/12, Michael Niedermayer <michaelni at gmx.at> wrote:
> On Mon, Jul 02, 2012 at 02:28:32AM +0000, Paul B Mahol wrote:
>> Signed-off-by: Paul B Mahol <onemda at gmail.com>
> [...]
>> +static int decode_0(AVCodecContext *avctx, uint8_t code, uint8_t *pkt)
>> +{
>> + PAFVideoDecContext *c = avctx->priv_data;
>> + uint32_t opcode_size, offset;
>> + uint8_t *dst, *dend, mask = 0, color = 0, a, b, p;
>> + const uint8_t *src, *send, *opcodes;
>> + int cnt, i, j, x = 0;
>> +
>> + cnt = bytestream2_get_byte(&c->gb);
>> + if (cnt) {
>> + if (code & 0x10) {
>> + int align;
>> +
>> + align = bytestream2_tell(&c->gb) & 3;
>> + if (align)
>> + bytestream2_skip(&c->gb, 4 - align);
>> + }
>> + do {
>> + uint32_t cnt;
>> +
>> + a = bytestream2_get_byte(&c->gb);
>> + b = bytestream2_get_byte(&c->gb);
>> + p = (a & 0xC0) >> 6;
>> + dst = c->frame[p] + get_video_page_offset(avctx, a, b);
>> + dend = c->frame[p] + c->frame_size;
>> + offset = (b & 0x7F) * 2;
>> + cnt = bytestream2_get_le16(&c->gb) + offset;
>> +
>> + do {
>> + offset++;
>> + if (dst + 3 * avctx->width + 4 > dend)
>> + return AVERROR_INVALIDDATA;
>> + copy4h(avctx, dst);
>> + if ((offset & 0x3F) == 0)
>> + dst += avctx->width * 3;
>> + dst += 4;
>> + } while (offset < cnt);
>> + } while (--cnt);
>> + }
>> +
>> + dst = c->frame[c->current_frame];
>> + do {
>> + a = bytestream2_get_byte(&c->gb);
>> + b = bytestream2_get_byte(&c->gb);
>> + p = (a & 0xC0) >> 6;
>> + src = c->frame[p] + get_video_page_offset(avctx, a, b);
>> + send = c->frame[p] + c->frame_size;
>> + if (src + 3 * avctx->width + 4 > send)
>> + return AVERROR_INVALIDDATA;
>> + copy_block4(dst, src, avctx->width, avctx->width, 4);
>> + cnt++;
>> + if ((cnt & 0x3F) == 0)
>> + dst += avctx->width * 3;
>> + dst += 4;
>> + } while (cnt < c->video_size / 16);
>> +
>> + opcode_size = bytestream2_get_le16(&c->gb);
>> + bytestream2_skip(&c->gb, 2);
>> +
>> + if (bytestream2_get_bytes_left(&c->gb) < opcode_size)
>> + return AVERROR_INVALIDDATA;
>> +
>> + opcodes = pkt + bytestream2_tell(&c->gb);
>> + bytestream2_skipu(&c->gb, opcode_size);
>> +
>> + dst = c->frame[c->current_frame];
>> +
>> + for (i = 0; i < avctx->height; i += 4, dst += avctx->width * 3) {
>> + for (j = 0; j < avctx->width; j += 4, dst += 4) {
>
> this seems to assume dimensions are a multiple of 4, paf_vid_init
> should check this so not too much is written
Agreed, fixed.
>
>
> [...]
>> +AVCodec ff_paf_video_decoder = {
>> + .name = "paf_video",
>> + .type = AVMEDIA_TYPE_VIDEO,
>> + .id = CODEC_ID_PAF_VIDEO,
>> + .priv_data_size = sizeof(PAFVideoDecContext),
>> + .init = paf_vid_init,
>> + .close = paf_vid_close,
>> + .decode = paf_vid_decode,
>> + .long_name = NULL_IF_CONFIG_SMALL("Amazing Studio Packed
>> Animation File Video"),
>> +};
>> +
>> +AVCodec ff_paf_audio_decoder = {
>> + .name = "paf_audio",
>> + .type = AVMEDIA_TYPE_AUDIO,
>> + .id = CODEC_ID_PAF_AUDIO,
>> + .priv_data_size = sizeof(PAFAudioDecContext),
>> + .init = paf_aud_init,
>> + .decode = paf_aud_decode,
>> + .capabilities = CODEC_CAP_DR1,
>> + .long_name = NULL_IF_CONFIG_SMALL("Amazing Studio Packed
>> Animation File Audio"),
>> +};
>
> the audio decoder could be split into a seperate file
I prefer to keep game video and audio decoders in same file
(like how it is done with bmv). paf audio decoder is so trivail that it
does not deserve separate file.
>
>
> [...]
>> +static int read_header(AVFormatContext *s)
>> +{
>> + PAFDemuxContext *p = s->priv_data;
>> + AVIOContext *pb = s->pb;
>> + AVStream *ast, *vst;
>> + int ret = 0;
>> +
>> + avio_skip(pb, 132);
>> +
>> + vst = avformat_new_stream(s, 0);
>> + if (!vst)
>> + return AVERROR(ENOMEM);
>> +
>> + vst->start_time = 0;
>> + vst->nb_frames =
>> + vst->duration =
>> + p->nb_frames = avio_rl32(pb);
>> + avio_skip(pb, 4);
>> + vst->codec->width = avio_rl32(pb);
>> + vst->codec->height = avio_rl32(pb);
>> + avio_skip(pb, 4);
>> + vst->codec->codec_type = AVMEDIA_TYPE_VIDEO;
>> + vst->codec->codec_tag = 0;
>> + vst->codec->codec_id = CODEC_ID_PAF_VIDEO;
>> + avpriv_set_pts_info(vst, 64, 1, 10);
>> +
>> + ast = avformat_new_stream(s, 0);
>> + if (!ast)
>> + return AVERROR(ENOMEM);
>> +
>> + ast->start_time = 0;
>> + ast->codec->codec_type = AVMEDIA_TYPE_AUDIO;
>> + ast->codec->codec_tag = 0;
>> + ast->codec->codec_id = CODEC_ID_PAF_AUDIO;
>> + ast->codec->channels = 2;
>> + ast->codec->sample_rate = 22050;
>> + avpriv_set_pts_info(ast, 64, 1, 22050);
>> +
>> + p->buffer_size = avio_rl32(pb);
>> + if (p->buffer_size < 175 || p->buffer_size > 2048)
>> + return AVERROR_INVALIDDATA;
>> +
>> + p->preload_count = avio_rl32(pb);
>> + p->frame_blks = avio_rl32(pb);
>> + p->start_offset = avio_rl32(pb);
>> + p->max_video_blks = avio_rl32(pb);
>> + p->max_audio_blks = avio_rl32(pb);
>> + if (p->max_audio_blks < 1 ||
>> + p->max_video_blks < 1 ||
>> + p->frame_blks < 1 ||
>> + p->nb_frames < 1 ||
>> + p->preload_count < 1)
>> + return AVERROR_INVALIDDATA;
>> +
>
>> + p->blocks_count_table = av_mallocz(p->nb_frames *
>> sizeof(uint32_t));
>> + p->frames_offset_table = av_mallocz(p->nb_frames *
>> sizeof(uint32_t));
>> + p->blocks_offset_table = av_mallocz(p->frame_blks *
>> sizeof(uint32_t));
>
> possibke interger overflows in the multiplication can lead to out of
> array writes later
>
Fixed.
>
> [...]
>> + size = p->video_size - p->frames_offset_table[p->current_frame];
>> + if (size < 0)
>> + return AVERROR_INVALIDDATA;
>> +
>> + if (av_new_packet(pkt, size) < 0)
>> + return AVERROR(ENOMEM);
>> +
>> + pkt->stream_index = 0;
>> + pkt->duration = 1;
>> + memcpy(pkt->data, p->video_frame +
>> p->frames_offset_table[p->current_frame], size);
>
> this creates video frames that are much larger than needed
Unfortunately using next video frame offset does not works always beacuse
it eats frame data (type 4 compression) and decoded output is black for
couple of first frames.
Also clearing video_frame/audio_frame after demuxing each packet
will break decoding too, so no trivial implementation of seeking is possible.
>
> rest looks ok
More information about the ffmpeg-devel
mailing list