Libav
|
00001 /* 00002 * ARMovie/RPL demuxer 00003 * Copyright (c) 2007 Christian Ohm, 2008 Eli Friedman 00004 * 00005 * This file is part of FFmpeg. 00006 * 00007 * FFmpeg is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2.1 of the License, or (at your option) any later version. 00011 * 00012 * FFmpeg is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with FFmpeg; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00020 */ 00021 00022 #include "libavutil/avstring.h" 00023 #include "avformat.h" 00024 #include <stdlib.h> 00025 00026 #define RPL_SIGNATURE "ARMovie\x0A" 00027 #define RPL_SIGNATURE_SIZE 8 00028 00030 #define RPL_LINE_LENGTH 256 00031 00032 static int rpl_probe(AVProbeData *p) 00033 { 00034 if (memcmp(p->buf, RPL_SIGNATURE, RPL_SIGNATURE_SIZE)) 00035 return 0; 00036 00037 return AVPROBE_SCORE_MAX; 00038 } 00039 00040 typedef struct RPLContext { 00041 // RPL header data 00042 int32_t frames_per_chunk; 00043 00044 // Stream position data 00045 uint32_t chunk_number; 00046 uint32_t chunk_part; 00047 uint32_t frame_in_part; 00048 } RPLContext; 00049 00050 static int read_line(ByteIOContext * pb, char* line, int bufsize) 00051 { 00052 int i; 00053 for (i = 0; i < bufsize - 1; i++) { 00054 int b = get_byte(pb); 00055 if (b == 0) 00056 break; 00057 if (b == '\n') { 00058 line[i] = '\0'; 00059 return 0; 00060 } 00061 line[i] = b; 00062 } 00063 line[i] = '\0'; 00064 return -1; 00065 } 00066 00067 static int32_t read_int(const char* line, const char** endptr, int* error) 00068 { 00069 unsigned long result = 0; 00070 for (; *line>='0' && *line<='9'; line++) { 00071 if (result > (0x7FFFFFFF - 9) / 10) 00072 *error = -1; 00073 result = 10 * result + *line - '0'; 00074 } 00075 *endptr = line; 00076 return result; 00077 } 00078 00079 static int32_t read_line_and_int(ByteIOContext * pb, int* error) 00080 { 00081 char line[RPL_LINE_LENGTH]; 00082 const char *endptr; 00083 *error |= read_line(pb, line, sizeof(line)); 00084 return read_int(line, &endptr, error); 00085 } 00086 00091 static AVRational read_fps(const char* line, int* error) 00092 { 00093 int64_t num, den = 1; 00094 AVRational result; 00095 num = read_int(line, &line, error); 00096 if (*line == '.') 00097 line++; 00098 for (; *line>='0' && *line<='9'; line++) { 00099 // Truncate any numerator too large to fit into an int64_t 00100 if (num > (INT64_MAX - 9) / 10 || den > INT64_MAX / 10) 00101 break; 00102 num = 10 * num + *line - '0'; 00103 den *= 10; 00104 } 00105 if (!num) 00106 *error = -1; 00107 av_reduce(&result.num, &result.den, num, den, 0x7FFFFFFF); 00108 return result; 00109 } 00110 00111 static int rpl_read_header(AVFormatContext *s, AVFormatParameters *ap) 00112 { 00113 ByteIOContext *pb = s->pb; 00114 RPLContext *rpl = s->priv_data; 00115 AVStream *vst = NULL, *ast = NULL; 00116 int total_audio_size; 00117 int error = 0; 00118 00119 uint32_t i; 00120 00121 int32_t audio_format, chunk_catalog_offset, number_of_chunks; 00122 AVRational fps; 00123 00124 char line[RPL_LINE_LENGTH]; 00125 00126 // The header for RPL/ARMovie files is 21 lines of text 00127 // containing the various header fields. The fields are always 00128 // in the same order, and other text besides the first 00129 // number usually isn't important. 00130 // (The spec says that there exists some significance 00131 // for the text in a few cases; samples needed.) 00132 error |= read_line(pb, line, sizeof(line)); // ARMovie 00133 error |= read_line(pb, line, sizeof(line)); // movie name 00134 av_metadata_set2(&s->metadata, "title" , line, 0); 00135 error |= read_line(pb, line, sizeof(line)); // date/copyright 00136 av_metadata_set2(&s->metadata, "copyright", line, 0); 00137 error |= read_line(pb, line, sizeof(line)); // author and other 00138 av_metadata_set2(&s->metadata, "author" , line, 0); 00139 00140 // video headers 00141 vst = av_new_stream(s, 0); 00142 if (!vst) 00143 return AVERROR(ENOMEM); 00144 vst->codec->codec_type = AVMEDIA_TYPE_VIDEO; 00145 vst->codec->codec_tag = read_line_and_int(pb, &error); // video format 00146 vst->codec->width = read_line_and_int(pb, &error); // video width 00147 vst->codec->height = read_line_and_int(pb, &error); // video height 00148 vst->codec->bits_per_coded_sample = read_line_and_int(pb, &error); // video bits per sample 00149 error |= read_line(pb, line, sizeof(line)); // video frames per second 00150 fps = read_fps(line, &error); 00151 av_set_pts_info(vst, 32, fps.den, fps.num); 00152 00153 // Figure out the video codec 00154 switch (vst->codec->codec_tag) { 00155 #if 0 00156 case 122: 00157 vst->codec->codec_id = CODEC_ID_ESCAPE122; 00158 break; 00159 #endif 00160 case 124: 00161 vst->codec->codec_id = CODEC_ID_ESCAPE124; 00162 // The header is wrong here, at least sometimes 00163 vst->codec->bits_per_coded_sample = 16; 00164 break; 00165 #if 0 00166 case 130: 00167 vst->codec->codec_id = CODEC_ID_ESCAPE130; 00168 break; 00169 #endif 00170 default: 00171 av_log(s, AV_LOG_WARNING, 00172 "RPL video format %i not supported yet!\n", 00173 vst->codec->codec_tag); 00174 vst->codec->codec_id = CODEC_ID_NONE; 00175 } 00176 00177 // Audio headers 00178 00179 // ARMovie supports multiple audio tracks; I don't have any 00180 // samples, though. This code will ignore additional tracks. 00181 audio_format = read_line_and_int(pb, &error); // audio format ID 00182 if (audio_format) { 00183 ast = av_new_stream(s, 0); 00184 if (!ast) 00185 return AVERROR(ENOMEM); 00186 ast->codec->codec_type = AVMEDIA_TYPE_AUDIO; 00187 ast->codec->codec_tag = audio_format; 00188 ast->codec->sample_rate = read_line_and_int(pb, &error); // audio bitrate 00189 ast->codec->channels = read_line_and_int(pb, &error); // number of audio channels 00190 ast->codec->bits_per_coded_sample = read_line_and_int(pb, &error); // audio bits per sample 00191 // At least one sample uses 0 for ADPCM, which is really 4 bits 00192 // per sample. 00193 if (ast->codec->bits_per_coded_sample == 0) 00194 ast->codec->bits_per_coded_sample = 4; 00195 00196 ast->codec->bit_rate = ast->codec->sample_rate * 00197 ast->codec->bits_per_coded_sample * 00198 ast->codec->channels; 00199 00200 ast->codec->codec_id = CODEC_ID_NONE; 00201 switch (audio_format) { 00202 case 1: 00203 if (ast->codec->bits_per_coded_sample == 16) { 00204 // 16-bit audio is always signed 00205 ast->codec->codec_id = CODEC_ID_PCM_S16LE; 00206 break; 00207 } 00208 // There are some other formats listed as legal per the spec; 00209 // samples needed. 00210 break; 00211 case 101: 00212 if (ast->codec->bits_per_coded_sample == 8) { 00213 // The samples with this kind of audio that I have 00214 // are all unsigned. 00215 ast->codec->codec_id = CODEC_ID_PCM_U8; 00216 break; 00217 } else if (ast->codec->bits_per_coded_sample == 4) { 00218 ast->codec->codec_id = CODEC_ID_ADPCM_IMA_EA_SEAD; 00219 break; 00220 } 00221 break; 00222 } 00223 if (ast->codec->codec_id == CODEC_ID_NONE) { 00224 av_log(s, AV_LOG_WARNING, 00225 "RPL audio format %i not supported yet!\n", 00226 audio_format); 00227 } 00228 av_set_pts_info(ast, 32, 1, ast->codec->bit_rate); 00229 } else { 00230 for (i = 0; i < 3; i++) 00231 error |= read_line(pb, line, sizeof(line)); 00232 } 00233 00234 rpl->frames_per_chunk = read_line_and_int(pb, &error); // video frames per chunk 00235 if (rpl->frames_per_chunk > 1 && vst->codec->codec_tag != 124) 00236 av_log(s, AV_LOG_WARNING, 00237 "Don't know how to split frames for video format %i. " 00238 "Video stream will be broken!\n", vst->codec->codec_tag); 00239 00240 number_of_chunks = read_line_and_int(pb, &error); // number of chunks in the file 00241 // The number in the header is actually the index of the last chunk. 00242 number_of_chunks++; 00243 00244 error |= read_line(pb, line, sizeof(line)); // "even" chunk size in bytes 00245 error |= read_line(pb, line, sizeof(line)); // "odd" chunk size in bytes 00246 chunk_catalog_offset = // offset of the "chunk catalog" 00247 read_line_and_int(pb, &error); // (file index) 00248 error |= read_line(pb, line, sizeof(line)); // offset to "helpful" sprite 00249 error |= read_line(pb, line, sizeof(line)); // size of "helpful" sprite 00250 error |= read_line(pb, line, sizeof(line)); // offset to key frame list 00251 00252 // Read the index 00253 url_fseek(pb, chunk_catalog_offset, SEEK_SET); 00254 total_audio_size = 0; 00255 for (i = 0; i < number_of_chunks; i++) { 00256 int64_t offset, video_size, audio_size; 00257 error |= read_line(pb, line, sizeof(line)); 00258 if (3 != sscanf(line, "%"PRId64" , %"PRId64" ; %"PRId64, 00259 &offset, &video_size, &audio_size)) 00260 error = -1; 00261 av_add_index_entry(vst, offset, i * rpl->frames_per_chunk, 00262 video_size, rpl->frames_per_chunk, 0); 00263 if (ast) 00264 av_add_index_entry(ast, offset + video_size, total_audio_size, 00265 audio_size, audio_size * 8, 0); 00266 total_audio_size += audio_size * 8; 00267 } 00268 00269 if (error) return AVERROR(EIO); 00270 00271 return 0; 00272 } 00273 00274 static int rpl_read_packet(AVFormatContext *s, AVPacket *pkt) 00275 { 00276 RPLContext *rpl = s->priv_data; 00277 ByteIOContext *pb = s->pb; 00278 AVStream* stream; 00279 AVIndexEntry* index_entry; 00280 uint32_t ret; 00281 00282 if (rpl->chunk_part == s->nb_streams) { 00283 rpl->chunk_number++; 00284 rpl->chunk_part = 0; 00285 } 00286 00287 stream = s->streams[rpl->chunk_part]; 00288 00289 if (rpl->chunk_number >= stream->nb_index_entries) 00290 return -1; 00291 00292 index_entry = &stream->index_entries[rpl->chunk_number]; 00293 00294 if (rpl->frame_in_part == 0) 00295 if (url_fseek(pb, index_entry->pos, SEEK_SET) < 0) 00296 return AVERROR(EIO); 00297 00298 if (stream->codec->codec_type == AVMEDIA_TYPE_VIDEO && 00299 stream->codec->codec_tag == 124) { 00300 // We have to split Escape 124 frames because there are 00301 // multiple frames per chunk in Escape 124 samples. 00302 uint32_t frame_size, frame_flags; 00303 00304 frame_flags = get_le32(pb); 00305 frame_size = get_le32(pb); 00306 if (url_fseek(pb, -8, SEEK_CUR) < 0) 00307 return AVERROR(EIO); 00308 00309 ret = av_get_packet(pb, pkt, frame_size); 00310 if (ret != frame_size) { 00311 av_free_packet(pkt); 00312 return AVERROR(EIO); 00313 } 00314 pkt->duration = 1; 00315 pkt->pts = index_entry->timestamp + rpl->frame_in_part; 00316 pkt->stream_index = rpl->chunk_part; 00317 00318 rpl->frame_in_part++; 00319 if (rpl->frame_in_part == rpl->frames_per_chunk) { 00320 rpl->frame_in_part = 0; 00321 rpl->chunk_part++; 00322 } 00323 } else { 00324 ret = av_get_packet(pb, pkt, index_entry->size); 00325 if (ret != index_entry->size) { 00326 av_free_packet(pkt); 00327 return AVERROR(EIO); 00328 } 00329 00330 if (stream->codec->codec_type == AVMEDIA_TYPE_VIDEO) { 00331 // frames_per_chunk should always be one here; the header 00332 // parsing will warn if it isn't. 00333 pkt->duration = rpl->frames_per_chunk; 00334 } else { 00335 // All the audio codecs supported in this container 00336 // (at least so far) are constant-bitrate. 00337 pkt->duration = ret * 8; 00338 } 00339 pkt->pts = index_entry->timestamp; 00340 pkt->stream_index = rpl->chunk_part; 00341 rpl->chunk_part++; 00342 } 00343 00344 // None of the Escape formats have keyframes, and the ADPCM 00345 // format used doesn't have keyframes. 00346 if (rpl->chunk_number == 0 && rpl->frame_in_part == 0) 00347 pkt->flags |= AV_PKT_FLAG_KEY; 00348 00349 return ret; 00350 } 00351 00352 AVInputFormat rpl_demuxer = { 00353 "rpl", 00354 NULL_IF_CONFIG_SMALL("RPL/ARMovie format"), 00355 sizeof(RPLContext), 00356 rpl_probe, 00357 rpl_read_header, 00358 rpl_read_packet, 00359 };