annotate ffmpeg/libavformat/rpl.c @ 13:844d341cf643 tip

Back up before ISMIR
author Yading Song <yading.song@eecs.qmul.ac.uk>
date Thu, 31 Oct 2013 13:17:06 +0000
parents f445c3017523
children
rev   line source
yading@11 1 /*
yading@11 2 * ARMovie/RPL demuxer
yading@11 3 * Copyright (c) 2007 Christian Ohm, 2008 Eli Friedman
yading@11 4 *
yading@11 5 * This file is part of FFmpeg.
yading@11 6 *
yading@11 7 * FFmpeg is free software; you can redistribute it and/or
yading@11 8 * modify it under the terms of the GNU Lesser General Public
yading@11 9 * License as published by the Free Software Foundation; either
yading@11 10 * version 2.1 of the License, or (at your option) any later version.
yading@11 11 *
yading@11 12 * FFmpeg is distributed in the hope that it will be useful,
yading@11 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
yading@11 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
yading@11 15 * Lesser General Public License for more details.
yading@11 16 *
yading@11 17 * You should have received a copy of the GNU Lesser General Public
yading@11 18 * License along with FFmpeg; if not, write to the Free Software
yading@11 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
yading@11 20 */
yading@11 21
yading@11 22 #include "libavutil/avstring.h"
yading@11 23 #include "libavutil/dict.h"
yading@11 24 #include "avformat.h"
yading@11 25 #include "internal.h"
yading@11 26 #include <stdlib.h>
yading@11 27
yading@11 28 #define RPL_SIGNATURE "ARMovie\x0A"
yading@11 29 #define RPL_SIGNATURE_SIZE 8
yading@11 30
yading@11 31 /** 256 is arbitrary, but should be big enough for any reasonable file. */
yading@11 32 #define RPL_LINE_LENGTH 256
yading@11 33
yading@11 34 static int rpl_probe(AVProbeData *p)
yading@11 35 {
yading@11 36 if (memcmp(p->buf, RPL_SIGNATURE, RPL_SIGNATURE_SIZE))
yading@11 37 return 0;
yading@11 38
yading@11 39 return AVPROBE_SCORE_MAX;
yading@11 40 }
yading@11 41
yading@11 42 typedef struct RPLContext {
yading@11 43 // RPL header data
yading@11 44 int32_t frames_per_chunk;
yading@11 45
yading@11 46 // Stream position data
yading@11 47 uint32_t chunk_number;
yading@11 48 uint32_t chunk_part;
yading@11 49 uint32_t frame_in_part;
yading@11 50 } RPLContext;
yading@11 51
yading@11 52 static int read_line(AVIOContext * pb, char* line, int bufsize)
yading@11 53 {
yading@11 54 int i;
yading@11 55 for (i = 0; i < bufsize - 1; i++) {
yading@11 56 int b = avio_r8(pb);
yading@11 57 if (b == 0)
yading@11 58 break;
yading@11 59 if (b == '\n') {
yading@11 60 line[i] = '\0';
yading@11 61 return url_feof(pb) ? -1 : 0;
yading@11 62 }
yading@11 63 line[i] = b;
yading@11 64 }
yading@11 65 line[i] = '\0';
yading@11 66 return -1;
yading@11 67 }
yading@11 68
yading@11 69 static int32_t read_int(const char* line, const char** endptr, int* error)
yading@11 70 {
yading@11 71 unsigned long result = 0;
yading@11 72 for (; *line>='0' && *line<='9'; line++) {
yading@11 73 if (result > (0x7FFFFFFF - 9) / 10)
yading@11 74 *error = -1;
yading@11 75 result = 10 * result + *line - '0';
yading@11 76 }
yading@11 77 *endptr = line;
yading@11 78 return result;
yading@11 79 }
yading@11 80
yading@11 81 static int32_t read_line_and_int(AVIOContext * pb, int* error)
yading@11 82 {
yading@11 83 char line[RPL_LINE_LENGTH];
yading@11 84 const char *endptr;
yading@11 85 *error |= read_line(pb, line, sizeof(line));
yading@11 86 return read_int(line, &endptr, error);
yading@11 87 }
yading@11 88
yading@11 89 /** Parsing for fps, which can be a fraction. Unfortunately,
yading@11 90 * the spec for the header leaves out a lot of details,
yading@11 91 * so this is mostly guessing.
yading@11 92 */
yading@11 93 static AVRational read_fps(const char* line, int* error)
yading@11 94 {
yading@11 95 int64_t num, den = 1;
yading@11 96 AVRational result;
yading@11 97 num = read_int(line, &line, error);
yading@11 98 if (*line == '.')
yading@11 99 line++;
yading@11 100 for (; *line>='0' && *line<='9'; line++) {
yading@11 101 // Truncate any numerator too large to fit into an int64_t
yading@11 102 if (num > (INT64_MAX - 9) / 10 || den > INT64_MAX / 10)
yading@11 103 break;
yading@11 104 num = 10 * num + *line - '0';
yading@11 105 den *= 10;
yading@11 106 }
yading@11 107 if (!num)
yading@11 108 *error = -1;
yading@11 109 av_reduce(&result.num, &result.den, num, den, 0x7FFFFFFF);
yading@11 110 return result;
yading@11 111 }
yading@11 112
yading@11 113 static int rpl_read_header(AVFormatContext *s)
yading@11 114 {
yading@11 115 AVIOContext *pb = s->pb;
yading@11 116 RPLContext *rpl = s->priv_data;
yading@11 117 AVStream *vst = NULL, *ast = NULL;
yading@11 118 int total_audio_size;
yading@11 119 int error = 0;
yading@11 120
yading@11 121 uint32_t i;
yading@11 122
yading@11 123 int32_t audio_format, chunk_catalog_offset, number_of_chunks;
yading@11 124 AVRational fps;
yading@11 125
yading@11 126 char line[RPL_LINE_LENGTH];
yading@11 127
yading@11 128 // The header for RPL/ARMovie files is 21 lines of text
yading@11 129 // containing the various header fields. The fields are always
yading@11 130 // in the same order, and other text besides the first
yading@11 131 // number usually isn't important.
yading@11 132 // (The spec says that there exists some significance
yading@11 133 // for the text in a few cases; samples needed.)
yading@11 134 error |= read_line(pb, line, sizeof(line)); // ARMovie
yading@11 135 error |= read_line(pb, line, sizeof(line)); // movie name
yading@11 136 av_dict_set(&s->metadata, "title" , line, 0);
yading@11 137 error |= read_line(pb, line, sizeof(line)); // date/copyright
yading@11 138 av_dict_set(&s->metadata, "copyright", line, 0);
yading@11 139 error |= read_line(pb, line, sizeof(line)); // author and other
yading@11 140 av_dict_set(&s->metadata, "author" , line, 0);
yading@11 141
yading@11 142 // video headers
yading@11 143 vst = avformat_new_stream(s, NULL);
yading@11 144 if (!vst)
yading@11 145 return AVERROR(ENOMEM);
yading@11 146 vst->codec->codec_type = AVMEDIA_TYPE_VIDEO;
yading@11 147 vst->codec->codec_tag = read_line_and_int(pb, &error); // video format
yading@11 148 vst->codec->width = read_line_and_int(pb, &error); // video width
yading@11 149 vst->codec->height = read_line_and_int(pb, &error); // video height
yading@11 150 vst->codec->bits_per_coded_sample = read_line_and_int(pb, &error); // video bits per sample
yading@11 151 error |= read_line(pb, line, sizeof(line)); // video frames per second
yading@11 152 fps = read_fps(line, &error);
yading@11 153 avpriv_set_pts_info(vst, 32, fps.den, fps.num);
yading@11 154
yading@11 155 // Figure out the video codec
yading@11 156 switch (vst->codec->codec_tag) {
yading@11 157 #if 0
yading@11 158 case 122:
yading@11 159 vst->codec->codec_id = AV_CODEC_ID_ESCAPE122;
yading@11 160 break;
yading@11 161 #endif
yading@11 162 case 124:
yading@11 163 vst->codec->codec_id = AV_CODEC_ID_ESCAPE124;
yading@11 164 // The header is wrong here, at least sometimes
yading@11 165 vst->codec->bits_per_coded_sample = 16;
yading@11 166 break;
yading@11 167 case 130:
yading@11 168 vst->codec->codec_id = AV_CODEC_ID_ESCAPE130;
yading@11 169 break;
yading@11 170 default:
yading@11 171 av_log(s, AV_LOG_WARNING,
yading@11 172 "RPL video format %i not supported yet!\n",
yading@11 173 vst->codec->codec_tag);
yading@11 174 vst->codec->codec_id = AV_CODEC_ID_NONE;
yading@11 175 }
yading@11 176
yading@11 177 // Audio headers
yading@11 178
yading@11 179 // ARMovie supports multiple audio tracks; I don't have any
yading@11 180 // samples, though. This code will ignore additional tracks.
yading@11 181 audio_format = read_line_and_int(pb, &error); // audio format ID
yading@11 182 if (audio_format) {
yading@11 183 ast = avformat_new_stream(s, NULL);
yading@11 184 if (!ast)
yading@11 185 return AVERROR(ENOMEM);
yading@11 186 ast->codec->codec_type = AVMEDIA_TYPE_AUDIO;
yading@11 187 ast->codec->codec_tag = audio_format;
yading@11 188 ast->codec->sample_rate = read_line_and_int(pb, &error); // audio bitrate
yading@11 189 ast->codec->channels = read_line_and_int(pb, &error); // number of audio channels
yading@11 190 ast->codec->bits_per_coded_sample = read_line_and_int(pb, &error); // audio bits per sample
yading@11 191 // At least one sample uses 0 for ADPCM, which is really 4 bits
yading@11 192 // per sample.
yading@11 193 if (ast->codec->bits_per_coded_sample == 0)
yading@11 194 ast->codec->bits_per_coded_sample = 4;
yading@11 195
yading@11 196 ast->codec->bit_rate = ast->codec->sample_rate *
yading@11 197 ast->codec->bits_per_coded_sample *
yading@11 198 ast->codec->channels;
yading@11 199
yading@11 200 ast->codec->codec_id = AV_CODEC_ID_NONE;
yading@11 201 switch (audio_format) {
yading@11 202 case 1:
yading@11 203 if (ast->codec->bits_per_coded_sample == 16) {
yading@11 204 // 16-bit audio is always signed
yading@11 205 ast->codec->codec_id = AV_CODEC_ID_PCM_S16LE;
yading@11 206 break;
yading@11 207 }
yading@11 208 // There are some other formats listed as legal per the spec;
yading@11 209 // samples needed.
yading@11 210 break;
yading@11 211 case 101:
yading@11 212 if (ast->codec->bits_per_coded_sample == 8) {
yading@11 213 // The samples with this kind of audio that I have
yading@11 214 // are all unsigned.
yading@11 215 ast->codec->codec_id = AV_CODEC_ID_PCM_U8;
yading@11 216 break;
yading@11 217 } else if (ast->codec->bits_per_coded_sample == 4) {
yading@11 218 ast->codec->codec_id = AV_CODEC_ID_ADPCM_IMA_EA_SEAD;
yading@11 219 break;
yading@11 220 }
yading@11 221 break;
yading@11 222 }
yading@11 223 if (ast->codec->codec_id == AV_CODEC_ID_NONE) {
yading@11 224 av_log(s, AV_LOG_WARNING,
yading@11 225 "RPL audio format %i not supported yet!\n",
yading@11 226 audio_format);
yading@11 227 }
yading@11 228 avpriv_set_pts_info(ast, 32, 1, ast->codec->bit_rate);
yading@11 229 } else {
yading@11 230 for (i = 0; i < 3; i++)
yading@11 231 error |= read_line(pb, line, sizeof(line));
yading@11 232 }
yading@11 233
yading@11 234 rpl->frames_per_chunk = read_line_and_int(pb, &error); // video frames per chunk
yading@11 235 if (rpl->frames_per_chunk > 1 && vst->codec->codec_tag != 124)
yading@11 236 av_log(s, AV_LOG_WARNING,
yading@11 237 "Don't know how to split frames for video format %i. "
yading@11 238 "Video stream will be broken!\n", vst->codec->codec_tag);
yading@11 239
yading@11 240 number_of_chunks = read_line_and_int(pb, &error); // number of chunks in the file
yading@11 241 // The number in the header is actually the index of the last chunk.
yading@11 242 number_of_chunks++;
yading@11 243
yading@11 244 error |= read_line(pb, line, sizeof(line)); // "even" chunk size in bytes
yading@11 245 error |= read_line(pb, line, sizeof(line)); // "odd" chunk size in bytes
yading@11 246 chunk_catalog_offset = // offset of the "chunk catalog"
yading@11 247 read_line_and_int(pb, &error); // (file index)
yading@11 248 error |= read_line(pb, line, sizeof(line)); // offset to "helpful" sprite
yading@11 249 error |= read_line(pb, line, sizeof(line)); // size of "helpful" sprite
yading@11 250 error |= read_line(pb, line, sizeof(line)); // offset to key frame list
yading@11 251
yading@11 252 // Read the index
yading@11 253 avio_seek(pb, chunk_catalog_offset, SEEK_SET);
yading@11 254 total_audio_size = 0;
yading@11 255 for (i = 0; !error && i < number_of_chunks; i++) {
yading@11 256 int64_t offset, video_size, audio_size;
yading@11 257 error |= read_line(pb, line, sizeof(line));
yading@11 258 if (3 != sscanf(line, "%"SCNd64" , %"SCNd64" ; %"SCNd64,
yading@11 259 &offset, &video_size, &audio_size))
yading@11 260 error = -1;
yading@11 261 av_add_index_entry(vst, offset, i * rpl->frames_per_chunk,
yading@11 262 video_size, rpl->frames_per_chunk, 0);
yading@11 263 if (ast)
yading@11 264 av_add_index_entry(ast, offset + video_size, total_audio_size,
yading@11 265 audio_size, audio_size * 8, 0);
yading@11 266 total_audio_size += audio_size * 8;
yading@11 267 }
yading@11 268
yading@11 269 if (error) return AVERROR(EIO);
yading@11 270
yading@11 271 return 0;
yading@11 272 }
yading@11 273
yading@11 274 static int rpl_read_packet(AVFormatContext *s, AVPacket *pkt)
yading@11 275 {
yading@11 276 RPLContext *rpl = s->priv_data;
yading@11 277 AVIOContext *pb = s->pb;
yading@11 278 AVStream* stream;
yading@11 279 AVIndexEntry* index_entry;
yading@11 280 uint32_t ret;
yading@11 281
yading@11 282 if (rpl->chunk_part == s->nb_streams) {
yading@11 283 rpl->chunk_number++;
yading@11 284 rpl->chunk_part = 0;
yading@11 285 }
yading@11 286
yading@11 287 stream = s->streams[rpl->chunk_part];
yading@11 288
yading@11 289 if (rpl->chunk_number >= stream->nb_index_entries)
yading@11 290 return AVERROR_EOF;
yading@11 291
yading@11 292 index_entry = &stream->index_entries[rpl->chunk_number];
yading@11 293
yading@11 294 if (rpl->frame_in_part == 0)
yading@11 295 if (avio_seek(pb, index_entry->pos, SEEK_SET) < 0)
yading@11 296 return AVERROR(EIO);
yading@11 297
yading@11 298 if (stream->codec->codec_type == AVMEDIA_TYPE_VIDEO &&
yading@11 299 stream->codec->codec_tag == 124) {
yading@11 300 // We have to split Escape 124 frames because there are
yading@11 301 // multiple frames per chunk in Escape 124 samples.
yading@11 302 uint32_t frame_size;
yading@11 303
yading@11 304 avio_skip(pb, 4); /* flags */
yading@11 305 frame_size = avio_rl32(pb);
yading@11 306 if (avio_seek(pb, -8, SEEK_CUR) < 0)
yading@11 307 return AVERROR(EIO);
yading@11 308
yading@11 309 ret = av_get_packet(pb, pkt, frame_size);
yading@11 310 if (ret != frame_size) {
yading@11 311 av_free_packet(pkt);
yading@11 312 return AVERROR(EIO);
yading@11 313 }
yading@11 314 pkt->duration = 1;
yading@11 315 pkt->pts = index_entry->timestamp + rpl->frame_in_part;
yading@11 316 pkt->stream_index = rpl->chunk_part;
yading@11 317
yading@11 318 rpl->frame_in_part++;
yading@11 319 if (rpl->frame_in_part == rpl->frames_per_chunk) {
yading@11 320 rpl->frame_in_part = 0;
yading@11 321 rpl->chunk_part++;
yading@11 322 }
yading@11 323 } else {
yading@11 324 ret = av_get_packet(pb, pkt, index_entry->size);
yading@11 325 if (ret != index_entry->size) {
yading@11 326 av_free_packet(pkt);
yading@11 327 return AVERROR(EIO);
yading@11 328 }
yading@11 329
yading@11 330 if (stream->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
yading@11 331 // frames_per_chunk should always be one here; the header
yading@11 332 // parsing will warn if it isn't.
yading@11 333 pkt->duration = rpl->frames_per_chunk;
yading@11 334 } else {
yading@11 335 // All the audio codecs supported in this container
yading@11 336 // (at least so far) are constant-bitrate.
yading@11 337 pkt->duration = ret * 8;
yading@11 338 }
yading@11 339 pkt->pts = index_entry->timestamp;
yading@11 340 pkt->stream_index = rpl->chunk_part;
yading@11 341 rpl->chunk_part++;
yading@11 342 }
yading@11 343
yading@11 344 // None of the Escape formats have keyframes, and the ADPCM
yading@11 345 // format used doesn't have keyframes.
yading@11 346 if (rpl->chunk_number == 0 && rpl->frame_in_part == 0)
yading@11 347 pkt->flags |= AV_PKT_FLAG_KEY;
yading@11 348
yading@11 349 return ret;
yading@11 350 }
yading@11 351
yading@11 352 AVInputFormat ff_rpl_demuxer = {
yading@11 353 .name = "rpl",
yading@11 354 .long_name = NULL_IF_CONFIG_SMALL("RPL / ARMovie"),
yading@11 355 .priv_data_size = sizeof(RPLContext),
yading@11 356 .read_probe = rpl_probe,
yading@11 357 .read_header = rpl_read_header,
yading@11 358 .read_packet = rpl_read_packet,
yading@11 359 };