00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "libavutil/avstring.h"
00023 #include "libavutil/dict.h"
00024 #include "avformat.h"
00025 #include <stdlib.h>
00026
00027 #define RPL_SIGNATURE "ARMovie\x0A"
00028 #define RPL_SIGNATURE_SIZE 8
00029
00031 #define RPL_LINE_LENGTH 256
00032
00033 static int rpl_probe(AVProbeData *p)
00034 {
00035 if (memcmp(p->buf, RPL_SIGNATURE, RPL_SIGNATURE_SIZE))
00036 return 0;
00037
00038 return AVPROBE_SCORE_MAX;
00039 }
00040
00041 typedef struct RPLContext {
00042
00043 int32_t frames_per_chunk;
00044
00045
00046 uint32_t chunk_number;
00047 uint32_t chunk_part;
00048 uint32_t frame_in_part;
00049 } RPLContext;
00050
00051 static int read_line(AVIOContext * pb, char* line, int bufsize)
00052 {
00053 int i;
00054 for (i = 0; i < bufsize - 1; i++) {
00055 int b = avio_r8(pb);
00056 if (b == 0)
00057 break;
00058 if (b == '\n') {
00059 line[i] = '\0';
00060 return 0;
00061 }
00062 line[i] = b;
00063 }
00064 line[i] = '\0';
00065 return -1;
00066 }
00067
00068 static int32_t read_int(const char* line, const char** endptr, int* error)
00069 {
00070 unsigned long result = 0;
00071 for (; *line>='0' && *line<='9'; line++) {
00072 if (result > (0x7FFFFFFF - 9) / 10)
00073 *error = -1;
00074 result = 10 * result + *line - '0';
00075 }
00076 *endptr = line;
00077 return result;
00078 }
00079
00080 static int32_t read_line_and_int(AVIOContext * pb, int* error)
00081 {
00082 char line[RPL_LINE_LENGTH];
00083 const char *endptr;
00084 *error |= read_line(pb, line, sizeof(line));
00085 return read_int(line, &endptr, error);
00086 }
00087
00092 static AVRational read_fps(const char* line, int* error)
00093 {
00094 int64_t num, den = 1;
00095 AVRational result;
00096 num = read_int(line, &line, error);
00097 if (*line == '.')
00098 line++;
00099 for (; *line>='0' && *line<='9'; line++) {
00100
00101 if (num > (INT64_MAX - 9) / 10 || den > INT64_MAX / 10)
00102 break;
00103 num = 10 * num + *line - '0';
00104 den *= 10;
00105 }
00106 if (!num)
00107 *error = -1;
00108 av_reduce(&result.num, &result.den, num, den, 0x7FFFFFFF);
00109 return result;
00110 }
00111
00112 static int rpl_read_header(AVFormatContext *s, AVFormatParameters *ap)
00113 {
00114 AVIOContext *pb = s->pb;
00115 RPLContext *rpl = s->priv_data;
00116 AVStream *vst = NULL, *ast = NULL;
00117 int total_audio_size;
00118 int error = 0;
00119
00120 uint32_t i;
00121
00122 int32_t audio_format, chunk_catalog_offset, number_of_chunks;
00123 AVRational fps;
00124
00125 char line[RPL_LINE_LENGTH];
00126
00127
00128
00129
00130
00131
00132
00133 error |= read_line(pb, line, sizeof(line));
00134 error |= read_line(pb, line, sizeof(line));
00135 av_dict_set(&s->metadata, "title" , line, 0);
00136 error |= read_line(pb, line, sizeof(line));
00137 av_dict_set(&s->metadata, "copyright", line, 0);
00138 error |= read_line(pb, line, sizeof(line));
00139 av_dict_set(&s->metadata, "author" , line, 0);
00140
00141
00142 vst = av_new_stream(s, 0);
00143 if (!vst)
00144 return AVERROR(ENOMEM);
00145 vst->codec->codec_type = AVMEDIA_TYPE_VIDEO;
00146 vst->codec->codec_tag = read_line_and_int(pb, &error);
00147 vst->codec->width = read_line_and_int(pb, &error);
00148 vst->codec->height = read_line_and_int(pb, &error);
00149 vst->codec->bits_per_coded_sample = read_line_and_int(pb, &error);
00150 error |= read_line(pb, line, sizeof(line));
00151 fps = read_fps(line, &error);
00152 av_set_pts_info(vst, 32, fps.den, fps.num);
00153
00154
00155 switch (vst->codec->codec_tag) {
00156 #if 0
00157 case 122:
00158 vst->codec->codec_id = CODEC_ID_ESCAPE122;
00159 break;
00160 #endif
00161 case 124:
00162 vst->codec->codec_id = CODEC_ID_ESCAPE124;
00163
00164 vst->codec->bits_per_coded_sample = 16;
00165 break;
00166 #if 0
00167 case 130:
00168 vst->codec->codec_id = CODEC_ID_ESCAPE130;
00169 break;
00170 #endif
00171 default:
00172 av_log(s, AV_LOG_WARNING,
00173 "RPL video format %i not supported yet!\n",
00174 vst->codec->codec_tag);
00175 vst->codec->codec_id = CODEC_ID_NONE;
00176 }
00177
00178
00179
00180
00181
00182 audio_format = read_line_and_int(pb, &error);
00183 if (audio_format) {
00184 ast = av_new_stream(s, 0);
00185 if (!ast)
00186 return AVERROR(ENOMEM);
00187 ast->codec->codec_type = AVMEDIA_TYPE_AUDIO;
00188 ast->codec->codec_tag = audio_format;
00189 ast->codec->sample_rate = read_line_and_int(pb, &error);
00190 ast->codec->channels = read_line_and_int(pb, &error);
00191 ast->codec->bits_per_coded_sample = read_line_and_int(pb, &error);
00192
00193
00194 if (ast->codec->bits_per_coded_sample == 0)
00195 ast->codec->bits_per_coded_sample = 4;
00196
00197 ast->codec->bit_rate = ast->codec->sample_rate *
00198 ast->codec->bits_per_coded_sample *
00199 ast->codec->channels;
00200
00201 ast->codec->codec_id = CODEC_ID_NONE;
00202 switch (audio_format) {
00203 case 1:
00204 if (ast->codec->bits_per_coded_sample == 16) {
00205
00206 ast->codec->codec_id = CODEC_ID_PCM_S16LE;
00207 break;
00208 }
00209
00210
00211 break;
00212 case 101:
00213 if (ast->codec->bits_per_coded_sample == 8) {
00214
00215
00216 ast->codec->codec_id = CODEC_ID_PCM_U8;
00217 break;
00218 } else if (ast->codec->bits_per_coded_sample == 4) {
00219 ast->codec->codec_id = CODEC_ID_ADPCM_IMA_EA_SEAD;
00220 break;
00221 }
00222 break;
00223 }
00224 if (ast->codec->codec_id == CODEC_ID_NONE) {
00225 av_log(s, AV_LOG_WARNING,
00226 "RPL audio format %i not supported yet!\n",
00227 audio_format);
00228 }
00229 av_set_pts_info(ast, 32, 1, ast->codec->bit_rate);
00230 } else {
00231 for (i = 0; i < 3; i++)
00232 error |= read_line(pb, line, sizeof(line));
00233 }
00234
00235 rpl->frames_per_chunk = read_line_and_int(pb, &error);
00236 if (rpl->frames_per_chunk > 1 && vst->codec->codec_tag != 124)
00237 av_log(s, AV_LOG_WARNING,
00238 "Don't know how to split frames for video format %i. "
00239 "Video stream will be broken!\n", vst->codec->codec_tag);
00240
00241 number_of_chunks = read_line_and_int(pb, &error);
00242
00243 number_of_chunks++;
00244
00245 error |= read_line(pb, line, sizeof(line));
00246 error |= read_line(pb, line, sizeof(line));
00247 chunk_catalog_offset =
00248 read_line_and_int(pb, &error);
00249 error |= read_line(pb, line, sizeof(line));
00250 error |= read_line(pb, line, sizeof(line));
00251 error |= read_line(pb, line, sizeof(line));
00252
00253
00254 avio_seek(pb, chunk_catalog_offset, SEEK_SET);
00255 total_audio_size = 0;
00256 for (i = 0; i < number_of_chunks; i++) {
00257 int64_t offset, video_size, audio_size;
00258 error |= read_line(pb, line, sizeof(line));
00259 if (3 != sscanf(line, "%"PRId64" , %"PRId64" ; %"PRId64,
00260 &offset, &video_size, &audio_size))
00261 error = -1;
00262 av_add_index_entry(vst, offset, i * rpl->frames_per_chunk,
00263 video_size, rpl->frames_per_chunk, 0);
00264 if (ast)
00265 av_add_index_entry(ast, offset + video_size, total_audio_size,
00266 audio_size, audio_size * 8, 0);
00267 total_audio_size += audio_size * 8;
00268 }
00269
00270 if (error) return AVERROR(EIO);
00271
00272 return 0;
00273 }
00274
00275 static int rpl_read_packet(AVFormatContext *s, AVPacket *pkt)
00276 {
00277 RPLContext *rpl = s->priv_data;
00278 AVIOContext *pb = s->pb;
00279 AVStream* stream;
00280 AVIndexEntry* index_entry;
00281 uint32_t ret;
00282
00283 if (rpl->chunk_part == s->nb_streams) {
00284 rpl->chunk_number++;
00285 rpl->chunk_part = 0;
00286 }
00287
00288 stream = s->streams[rpl->chunk_part];
00289
00290 if (rpl->chunk_number >= stream->nb_index_entries)
00291 return -1;
00292
00293 index_entry = &stream->index_entries[rpl->chunk_number];
00294
00295 if (rpl->frame_in_part == 0)
00296 if (avio_seek(pb, index_entry->pos, SEEK_SET) < 0)
00297 return AVERROR(EIO);
00298
00299 if (stream->codec->codec_type == AVMEDIA_TYPE_VIDEO &&
00300 stream->codec->codec_tag == 124) {
00301
00302
00303 uint32_t frame_size;
00304
00305 avio_skip(pb, 4);
00306 frame_size = avio_rl32(pb);
00307 if (avio_seek(pb, -8, SEEK_CUR) < 0)
00308 return AVERROR(EIO);
00309
00310 ret = av_get_packet(pb, pkt, frame_size);
00311 if (ret != frame_size) {
00312 av_free_packet(pkt);
00313 return AVERROR(EIO);
00314 }
00315 pkt->duration = 1;
00316 pkt->pts = index_entry->timestamp + rpl->frame_in_part;
00317 pkt->stream_index = rpl->chunk_part;
00318
00319 rpl->frame_in_part++;
00320 if (rpl->frame_in_part == rpl->frames_per_chunk) {
00321 rpl->frame_in_part = 0;
00322 rpl->chunk_part++;
00323 }
00324 } else {
00325 ret = av_get_packet(pb, pkt, index_entry->size);
00326 if (ret != index_entry->size) {
00327 av_free_packet(pkt);
00328 return AVERROR(EIO);
00329 }
00330
00331 if (stream->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
00332
00333
00334 pkt->duration = rpl->frames_per_chunk;
00335 } else {
00336
00337
00338 pkt->duration = ret * 8;
00339 }
00340 pkt->pts = index_entry->timestamp;
00341 pkt->stream_index = rpl->chunk_part;
00342 rpl->chunk_part++;
00343 }
00344
00345
00346
00347 if (rpl->chunk_number == 0 && rpl->frame_in_part == 0)
00348 pkt->flags |= AV_PKT_FLAG_KEY;
00349
00350 return ret;
00351 }
00352
00353 AVInputFormat ff_rpl_demuxer = {
00354 "rpl",
00355 NULL_IF_CONFIG_SMALL("RPL/ARMovie format"),
00356 sizeof(RPLContext),
00357 rpl_probe,
00358 rpl_read_header,
00359 rpl_read_packet,
00360 };