2 * Packed Animation File demuxer
3 * Copyright (c) 2012 Paul B Mahol
5 * This file is part of FFmpeg.
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 #include "libavutil/channel_layout.h"
23 #include "libavcodec/paf.h"
27 #define MAGIC "Packed Animation File V1.0\n(c) 1992-96 Amazing Studio\x0a\x1a"
33 uint32_t start_offset
;
34 uint32_t preload_count
;
35 uint32_t max_video_blks
;
36 uint32_t max_audio_blks
;
38 uint32_t current_frame
;
39 uint32_t current_frame_count
;
40 uint32_t current_frame_block
;
42 uint32_t *blocks_count_table
;
43 uint32_t *frames_offset_table
;
44 uint32_t *blocks_offset_table
;
50 uint8_t *temp_audio_frame
;
56 static int read_probe(AVProbeData
*p
)
58 if ((p
->buf_size
>= strlen(MAGIC
)) &&
59 !memcmp(p
->buf
, MAGIC
, strlen(MAGIC
)))
60 return AVPROBE_SCORE_MAX
;
64 static int read_close(AVFormatContext
*s
)
66 PAFDemuxContext
*p
= s
->priv_data
;
68 av_freep(&p
->blocks_count_table
);
69 av_freep(&p
->frames_offset_table
);
70 av_freep(&p
->blocks_offset_table
);
71 av_freep(&p
->video_frame
);
72 av_freep(&p
->audio_frame
);
73 av_freep(&p
->temp_audio_frame
);
78 static void read_table(AVFormatContext
*s
, uint32_t *table
, uint32_t count
)
82 for (i
= 0; i
< count
; i
++)
83 table
[i
] = avio_rl32(s
->pb
);
85 avio_skip(s
->pb
, 4 * (FFALIGN(count
, 512) - count
));
88 static int read_header(AVFormatContext
*s
)
90 PAFDemuxContext
*p
= s
->priv_data
;
91 AVIOContext
*pb
= s
->pb
;
97 vst
= avformat_new_stream(s
, 0);
99 return AVERROR(ENOMEM
);
104 p
->nb_frames
= avio_rl32(pb
);
107 vst
->codec
->width
= avio_rl32(pb
);
108 vst
->codec
->height
= avio_rl32(pb
);
111 vst
->codec
->codec_type
= AVMEDIA_TYPE_VIDEO
;
112 vst
->codec
->codec_tag
= 0;
113 vst
->codec
->codec_id
= AV_CODEC_ID_PAF_VIDEO
;
114 avpriv_set_pts_info(vst
, 64, 1, 10);
116 ast
= avformat_new_stream(s
, 0);
118 return AVERROR(ENOMEM
);
121 ast
->codec
->codec_type
= AVMEDIA_TYPE_AUDIO
;
122 ast
->codec
->codec_tag
= 0;
123 ast
->codec
->codec_id
= AV_CODEC_ID_PAF_AUDIO
;
124 ast
->codec
->channels
= 2;
125 ast
->codec
->channel_layout
= AV_CH_LAYOUT_STEREO
;
126 ast
->codec
->sample_rate
= 22050;
127 avpriv_set_pts_info(ast
, 64, 1, 22050);
129 p
->buffer_size
= avio_rl32(pb
);
130 p
->preload_count
= avio_rl32(pb
);
131 p
->frame_blks
= avio_rl32(pb
);
132 p
->start_offset
= avio_rl32(pb
);
133 p
->max_video_blks
= avio_rl32(pb
);
134 p
->max_audio_blks
= avio_rl32(pb
);
135 if (p
->buffer_size
< 175 ||
136 p
->max_audio_blks
< 2 ||
137 p
->max_video_blks
< 1 ||
140 p
->preload_count
< 1 ||
141 p
->buffer_size
> 2048 ||
142 p
->max_video_blks
> 2048 ||
143 p
->max_audio_blks
> 2048 ||
144 p
->nb_frames
> INT_MAX
/ sizeof(uint32_t) ||
145 p
->frame_blks
> INT_MAX
/ sizeof(uint32_t))
146 return AVERROR_INVALIDDATA
;
148 p
->blocks_count_table
= av_mallocz(p
->nb_frames
*
149 sizeof(*p
->blocks_count_table
));
150 p
->frames_offset_table
= av_mallocz(p
->nb_frames
*
151 sizeof(*p
->frames_offset_table
));
152 p
->blocks_offset_table
= av_mallocz(p
->frame_blks
*
153 sizeof(*p
->blocks_offset_table
));
155 p
->video_size
= p
->max_video_blks
* p
->buffer_size
;
156 p
->video_frame
= av_mallocz(p
->video_size
);
158 p
->audio_size
= p
->max_audio_blks
* p
->buffer_size
;
159 p
->audio_frame
= av_mallocz(p
->audio_size
);
160 p
->temp_audio_frame
= av_mallocz(p
->audio_size
);
162 if (!p
->blocks_count_table
||
163 !p
->frames_offset_table
||
164 !p
->blocks_offset_table
||
167 !p
->temp_audio_frame
) {
168 ret
= AVERROR(ENOMEM
);
172 avio_seek(pb
, p
->buffer_size
, SEEK_SET
);
174 read_table(s
, p
->blocks_count_table
, p
->nb_frames
);
175 read_table(s
, p
->frames_offset_table
, p
->nb_frames
);
176 read_table(s
, p
->blocks_offset_table
, p
->frame_blks
);
179 p
->current_frame
= 0;
180 p
->current_frame_block
= 0;
182 avio_seek(pb
, p
->start_offset
, SEEK_SET
);
192 static int read_packet(AVFormatContext
*s
, AVPacket
*pkt
)
194 PAFDemuxContext
*p
= s
->priv_data
;
195 AVIOContext
*pb
= s
->pb
;
196 uint32_t count
, offset
;
199 if (p
->current_frame
>= p
->nb_frames
)
206 if (av_new_packet(pkt
, p
->audio_size
) < 0)
207 return AVERROR(ENOMEM
);
209 memcpy(pkt
->data
, p
->temp_audio_frame
, p
->audio_size
);
210 pkt
->duration
= PAF_SOUND_SAMPLES
* (p
->audio_size
/ PAF_SOUND_FRAME_SIZE
);
211 pkt
->flags
|= AV_PKT_FLAG_KEY
;
212 pkt
->stream_index
= 1;
217 count
= (p
->current_frame
== 0) ? p
->preload_count
218 : p
->blocks_count_table
[p
->current_frame
- 1];
219 for (i
= 0; i
< count
; i
++) {
220 if (p
->current_frame_block
>= p
->frame_blks
)
221 return AVERROR_INVALIDDATA
;
223 offset
= p
->blocks_offset_table
[p
->current_frame_block
] & ~(1U << 31);
224 if (p
->blocks_offset_table
[p
->current_frame_block
] & (1U << 31)) {
225 if (offset
> p
->audio_size
- p
->buffer_size
)
226 return AVERROR_INVALIDDATA
;
228 avio_read(pb
, p
->audio_frame
+ offset
, p
->buffer_size
);
229 if (offset
== (p
->max_audio_blks
- 2) * p
->buffer_size
) {
230 memcpy(p
->temp_audio_frame
, p
->audio_frame
, p
->audio_size
);
234 if (offset
> p
->video_size
- p
->buffer_size
)
235 return AVERROR_INVALIDDATA
;
237 avio_read(pb
, p
->video_frame
+ offset
, p
->buffer_size
);
239 p
->current_frame_block
++;
242 if (p
->frames_offset_table
[p
->current_frame
] >= p
->video_size
)
243 return AVERROR_INVALIDDATA
;
245 size
= p
->video_size
- p
->frames_offset_table
[p
->current_frame
];
247 if (av_new_packet(pkt
, size
) < 0)
248 return AVERROR(ENOMEM
);
250 pkt
->stream_index
= 0;
252 memcpy(pkt
->data
, p
->video_frame
+ p
->frames_offset_table
[p
->current_frame
], size
);
253 if (pkt
->data
[0] & 0x20)
254 pkt
->flags
|= AV_PKT_FLAG_KEY
;
260 AVInputFormat ff_paf_demuxer
= {
262 .long_name
= NULL_IF_CONFIG_SMALL("Amazing Studio Packed Animation File"),
263 .priv_data_size
= sizeof(PAFDemuxContext
),
264 .read_probe
= read_probe
,
265 .read_header
= read_header
,
266 .read_packet
= read_packet
,
267 .read_close
= read_close
,