00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "libavutil/intreadwrite.h"
00023 #include "avformat.h"
00024 #include "internal.h"
00025 #include "avio.h"
00026
00027 typedef struct {
00028 int version;
00029 int audio_stream_index;
00030 int video_stream_index;
00031 } SMUSHContext;
00032
00033 static int smush_read_probe(AVProbeData *p)
00034 {
00035 if (((AV_RL32(p->buf) == MKTAG('S', 'A', 'N', 'M') &&
00036 AV_RL32(p->buf + 8) == MKTAG('S', 'H', 'D', 'R')) ||
00037 (AV_RL32(p->buf) == MKTAG('A', 'N', 'I', 'M') &&
00038 AV_RL32(p->buf + 8) == MKTAG('A', 'H', 'D', 'R')))) {
00039 return AVPROBE_SCORE_MAX;
00040 }
00041
00042 return 0;
00043 }
00044
00045 static int smush_read_header(AVFormatContext *ctx)
00046 {
00047 SMUSHContext *smush = ctx->priv_data;
00048 AVIOContext *pb = ctx->pb;
00049 AVStream *vst, *ast;
00050 uint32_t magic, nframes, size, subversion, i;
00051 uint32_t width = 0, height = 0, got_audio = 0, read = 0;
00052 uint32_t sample_rate, channels, palette[256];
00053
00054 magic = avio_rb32(pb);
00055 avio_skip(pb, 4);
00056
00057 if (magic == MKBETAG('A', 'N', 'I', 'M')) {
00058 if (avio_rb32(pb) != MKBETAG('A', 'H', 'D', 'R'))
00059 return AVERROR_INVALIDDATA;
00060
00061 size = avio_rb32(pb);
00062 if (size < 3 * 256 + 6)
00063 return AVERROR_INVALIDDATA;
00064
00065 smush->version = 0;
00066 subversion = avio_rl16(pb);
00067 nframes = avio_rl16(pb);
00068
00069 avio_skip(pb, 2);
00070
00071 for (i = 0; i < 256; i++)
00072 palette[i] = avio_rb24(pb);
00073
00074 avio_skip(pb, size - (3 * 256 + 6));
00075 } else if (magic == MKBETAG('S', 'A', 'N', 'M') ) {
00076 if (avio_rb32(pb) != MKBETAG('S', 'H', 'D', 'R'))
00077 return AVERROR_INVALIDDATA;
00078
00079 size = avio_rb32(pb);
00080 if (size < 14)
00081 return AVERROR_INVALIDDATA;
00082
00083 smush->version = 1;
00084 subversion = avio_rl16(pb);
00085 nframes = avio_rl32(pb);
00086 avio_skip(pb, 2);
00087 width = avio_rl16(pb);
00088 height = avio_rl16(pb);
00089 avio_skip(pb, 2);
00090 avio_skip(pb, size - 14);
00091
00092 if (avio_rb32(pb) != MKBETAG('F', 'L', 'H', 'D'))
00093 return AVERROR_INVALIDDATA;
00094
00095 size = avio_rb32(pb);
00096 while (!got_audio && ((read + 8) < size)) {
00097 uint32_t sig, chunk_size;
00098
00099 if (url_feof(pb))
00100 return AVERROR_EOF;
00101
00102 sig = avio_rb32(pb);
00103 chunk_size = avio_rb32(pb);
00104 read += 8;
00105 switch (sig) {
00106 case MKBETAG('W', 'a', 'v', 'e'):
00107 got_audio = 1;
00108 sample_rate = avio_rl32(pb);
00109 channels = avio_rl32(pb);
00110 avio_skip(pb, chunk_size - 8);
00111 read += chunk_size;
00112 break;
00113 case MKBETAG('B', 'l', '1', '6'):
00114 case MKBETAG('A', 'N', 'N', 'O'):
00115 avio_skip(pb, chunk_size);
00116 read += chunk_size;
00117 break;
00118 default:
00119 return AVERROR_INVALIDDATA;
00120 break;
00121 }
00122 }
00123
00124 avio_skip(pb, size - read);
00125 } else {
00126 av_log(ctx, AV_LOG_ERROR, "Wrong magic\n");
00127 return AVERROR_INVALIDDATA;
00128 }
00129
00130 vst = avformat_new_stream(ctx, 0);
00131 if (!vst)
00132 return AVERROR(ENOMEM);
00133
00134 smush->video_stream_index = vst->index;
00135
00136 vst->start_time = 0;
00137 vst->duration =
00138 vst->nb_frames = nframes;
00139 vst->codec->codec_type = AVMEDIA_TYPE_VIDEO;
00140 vst->codec->codec_id = AV_CODEC_ID_SANM;
00141 vst->codec->codec_tag = 0;
00142 vst->codec->width = width;
00143 vst->codec->height = height;
00144
00145 avpriv_set_pts_info(vst, 64, 66667, 1000000);
00146
00147 if (!smush->version) {
00148 vst->codec->extradata = av_malloc(1024 + 2 + FF_INPUT_BUFFER_PADDING_SIZE);
00149 if (!vst->codec->extradata)
00150 return AVERROR(ENOMEM);
00151
00152 vst->codec->extradata_size = 1024 + 2;
00153 AV_WL16(vst->codec->extradata, subversion);
00154 for (i = 0; i < 256; i++)
00155 AV_WL32(vst->codec->extradata + 2 + i * 4, palette[i]);
00156 }
00157
00158 if (got_audio) {
00159 ast = avformat_new_stream(ctx, 0);
00160 if (!ast)
00161 return AVERROR(ENOMEM);
00162
00163 smush->audio_stream_index = ast->index;
00164
00165 ast->start_time = 0;
00166 ast->codec->codec_type = AVMEDIA_TYPE_AUDIO;
00167 ast->codec->codec_id = AV_CODEC_ID_VIMA;
00168 ast->codec->codec_tag = 0;
00169 ast->codec->sample_rate = sample_rate;
00170 ast->codec->channels = channels;
00171
00172 avpriv_set_pts_info(ast, 64, 1, ast->codec->sample_rate);
00173 }
00174
00175 return 0;
00176 }
00177
00178 static int smush_read_packet(AVFormatContext *ctx, AVPacket *pkt)
00179 {
00180 SMUSHContext *smush = ctx->priv_data;
00181 AVIOContext *pb = ctx->pb;
00182 int done = 0;
00183
00184 while (!done) {
00185 uint32_t sig, size;
00186
00187 if (url_feof(pb))
00188 return AVERROR_EOF;
00189
00190 sig = avio_rb32(pb);
00191 size = avio_rb32(pb);
00192
00193 switch (sig) {
00194 case MKBETAG('F', 'R', 'M', 'E'):
00195 if (smush->version)
00196 break;
00197 if (av_get_packet(pb, pkt, size) < 0)
00198 return AVERROR(EIO);
00199
00200 pkt->stream_index = smush->video_stream_index;
00201 done = 1;
00202 break;
00203 case MKBETAG('B', 'l', '1', '6'):
00204 if (av_get_packet(pb, pkt, size) < 0)
00205 return AVERROR(EIO);
00206
00207 pkt->stream_index = smush->video_stream_index;
00208 pkt->duration = 1;
00209 done = 1;
00210 break;
00211 case MKBETAG('W', 'a', 'v', 'e'):
00212 if (size < 13)
00213 return AVERROR_INVALIDDATA;
00214 if (av_get_packet(pb, pkt, size) < 13)
00215 return AVERROR(EIO);
00216
00217 pkt->stream_index = smush->audio_stream_index;
00218 pkt->flags |= AV_PKT_FLAG_KEY;
00219 pkt->duration = AV_RB32(pkt->data);
00220 if (pkt->duration == 0xFFFFFFFFu)
00221 pkt->duration = AV_RB32(pkt->data + 8);
00222 done = 1;
00223 break;
00224 default:
00225 avio_skip(pb, size);
00226 break;
00227 }
00228 }
00229
00230 return 0;
00231 }
00232
00233 AVInputFormat ff_smush_demuxer = {
00234 .name = "smush",
00235 .long_name = NULL_IF_CONFIG_SMALL("LucasArts Smush"),
00236 .priv_data_size = sizeof(SMUSHContext),
00237 .read_probe = smush_read_probe,
00238 .read_header = smush_read_header,
00239 .read_packet = smush_read_packet,
00240 };