1/* 2 * Silicon Graphics Movie demuxer 3 * Copyright (c) 2012 Peter Ross 4 * 5 * This file is part of FFmpeg. 6 * 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. 11 * 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. 16 * 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 20 */ 21 22/** 23 * @file 24 * Silicon Graphics Movie demuxer 25 */ 26 27#include "libavutil/channel_layout.h" 28#include "libavutil/eval.h" 29#include "libavutil/intreadwrite.h" 30#include "libavutil/rational.h" 31 32#include "avformat.h" 33#include "internal.h" 34 35typedef struct MvContext { 36 int nb_video_tracks; 37 int nb_audio_tracks; 38 39 int eof_count; ///< number of streams that have finished 40 int stream_index; ///< current stream index 41 int frame[2]; ///< frame nb for current stream 42 43 int acompression; ///< compression level for audio stream 44 int aformat; ///< audio format 45} MvContext; 46 47#define AUDIO_FORMAT_SIGNED 401 48 49static int mv_probe(AVProbeData *p) 50{ 51 if (AV_RB32(p->buf) == MKBETAG('M', 'O', 'V', 'I') && 52 AV_RB16(p->buf + 4) < 3) 53 return AVPROBE_SCORE_MAX; 54 return 0; 55} 56 57static char *var_read_string(AVIOContext *pb, int size) 58{ 59 int n; 60 char *str = av_malloc(size + 1); 61 if (!str) 62 return NULL; 63 n = avio_get_str(pb, size, str, size + 1); 64 if (n < size) 65 avio_skip(pb, size - n); 66 return str; 67} 68 69static int var_read_int(AVIOContext *pb, int size) 70{ 71 int v; 72 char *s = var_read_string(pb, size); 73 if (!s) 74 return 0; 75 v = strtol(s, NULL, 10); 76 av_free(s); 77 return v; 78} 79 80static AVRational var_read_float(AVIOContext *pb, int size) 81{ 82 AVRational v; 83 char *s = var_read_string(pb, size); 84 if (!s) 85 return (AVRational) { 0, 0 }; 86 v = av_d2q(av_strtod(s, NULL), INT_MAX); 87 av_free(s); 88 return v; 89} 90 91static void var_read_metadata(AVFormatContext *avctx, const char *tag, int size) 92{ 93 char *value = var_read_string(avctx->pb, size); 94 if (value) 95 av_dict_set(&avctx->metadata, tag, value, AV_DICT_DONT_STRDUP_VAL); 96} 97 98static int set_channels(AVFormatContext *avctx, AVStream *st, int channels) 99{ 100 if (channels <= 0) { 101 av_log(avctx, AV_LOG_ERROR, "Channel count %d invalid.\n", channels); 102 return AVERROR_INVALIDDATA; 103 } 104 st->codec->channels = channels; 105 st->codec->channel_layout = (st->codec->channels == 1) ? AV_CH_LAYOUT_MONO 106 : AV_CH_LAYOUT_STEREO; 107 return 0; 108} 109 110/** 111 * Parse global variable 112 * @return < 0 if unknown 113 */ 114static int parse_global_var(AVFormatContext *avctx, AVStream *st, 115 const char *name, int size) 116{ 117 MvContext *mv = avctx->priv_data; 118 AVIOContext *pb = avctx->pb; 119 if (!strcmp(name, "__NUM_I_TRACKS")) { 120 mv->nb_video_tracks = var_read_int(pb, size); 121 } else if (!strcmp(name, "__NUM_A_TRACKS")) { 122 mv->nb_audio_tracks = var_read_int(pb, size); 123 } else if (!strcmp(name, "COMMENT") || !strcmp(name, "TITLE")) { 124 var_read_metadata(avctx, name, size); 125 } else if (!strcmp(name, "LOOP_MODE") || !strcmp(name, "NUM_LOOPS") || 126 !strcmp(name, "OPTIMIZED")) { 127 avio_skip(pb, size); // ignore 128 } else 129 return AVERROR_INVALIDDATA; 130 131 return 0; 132} 133 134/** 135 * Parse audio variable 136 * @return < 0 if unknown 137 */ 138static int parse_audio_var(AVFormatContext *avctx, AVStream *st, 139 const char *name, int size) 140{ 141 MvContext *mv = avctx->priv_data; 142 AVIOContext *pb = avctx->pb; 143 if (!strcmp(name, "__DIR_COUNT")) { 144 st->nb_frames = var_read_int(pb, size); 145 } else if (!strcmp(name, "AUDIO_FORMAT")) { 146 mv->aformat = var_read_int(pb, size); 147 } else if (!strcmp(name, "COMPRESSION")) { 148 mv->acompression = var_read_int(pb, size); 149 } else if (!strcmp(name, "DEFAULT_VOL")) { 150 var_read_metadata(avctx, name, size); 151 } else if (!strcmp(name, "NUM_CHANNELS")) { 152 return set_channels(avctx, st, var_read_int(pb, size)); 153 } else if (!strcmp(name, "SAMPLE_RATE")) { 154 st->codec->sample_rate = var_read_int(pb, size); 155 avpriv_set_pts_info(st, 33, 1, st->codec->sample_rate); 156 } else if (!strcmp(name, "SAMPLE_WIDTH")) { 157 st->codec->bits_per_coded_sample = var_read_int(pb, size) * 8; 158 } else 159 return AVERROR_INVALIDDATA; 160 161 return 0; 162} 163 164/** 165 * Parse video variable 166 * @return < 0 if unknown 167 */ 168static int parse_video_var(AVFormatContext *avctx, AVStream *st, 169 const char *name, int size) 170{ 171 AVIOContext *pb = avctx->pb; 172 if (!strcmp(name, "__DIR_COUNT")) { 173 st->nb_frames = st->duration = var_read_int(pb, size); 174 } else if (!strcmp(name, "COMPRESSION")) { 175 char *str = var_read_string(pb, size); 176 if (!str) 177 return AVERROR_INVALIDDATA; 178 if (!strcmp(str, "1")) { 179 st->codec->codec_id = AV_CODEC_ID_MVC1; 180 } else if (!strcmp(str, "2")) { 181 st->codec->pix_fmt = AV_PIX_FMT_ABGR; 182 st->codec->codec_id = AV_CODEC_ID_RAWVIDEO; 183 } else if (!strcmp(str, "3")) { 184 st->codec->codec_id = AV_CODEC_ID_SGIRLE; 185 } else if (!strcmp(str, "10")) { 186 st->codec->codec_id = AV_CODEC_ID_MJPEG; 187 } else if (!strcmp(str, "MVC2")) { 188 st->codec->codec_id = AV_CODEC_ID_MVC2; 189 } else { 190 avpriv_request_sample(avctx, "Video compression %s", str); 191 } 192 av_free(str); 193 } else if (!strcmp(name, "FPS")) { 194 AVRational fps = var_read_float(pb, size); 195 avpriv_set_pts_info(st, 64, fps.den, fps.num); 196 st->avg_frame_rate = fps; 197 } else if (!strcmp(name, "HEIGHT")) { 198 st->codec->height = var_read_int(pb, size); 199 } else if (!strcmp(name, "PIXEL_ASPECT")) { 200 st->sample_aspect_ratio = var_read_float(pb, size); 201 av_reduce(&st->sample_aspect_ratio.num, &st->sample_aspect_ratio.den, 202 st->sample_aspect_ratio.num, st->sample_aspect_ratio.den, 203 INT_MAX); 204 } else if (!strcmp(name, "WIDTH")) { 205 st->codec->width = var_read_int(pb, size); 206 } else if (!strcmp(name, "ORIENTATION")) { 207 if (var_read_int(pb, size) == 1101) { 208 st->codec->extradata = av_strdup("BottomUp"); 209 st->codec->extradata_size = 9; 210 } 211 } else if (!strcmp(name, "Q_SPATIAL") || !strcmp(name, "Q_TEMPORAL")) { 212 var_read_metadata(avctx, name, size); 213 } else if (!strcmp(name, "INTERLACING") || !strcmp(name, "PACKING")) { 214 avio_skip(pb, size); // ignore 215 } else 216 return AVERROR_INVALIDDATA; 217 218 return 0; 219} 220 221static void read_table(AVFormatContext *avctx, AVStream *st, 222 int (*parse)(AVFormatContext *avctx, AVStream *st, 223 const char *name, int size)) 224{ 225 int count, i; 226 AVIOContext *pb = avctx->pb; 227 avio_skip(pb, 4); 228 count = avio_rb32(pb); 229 avio_skip(pb, 4); 230 for (i = 0; i < count; i++) { 231 char name[17]; 232 int size; 233 avio_read(pb, name, 16); 234 name[sizeof(name) - 1] = 0; 235 size = avio_rb32(pb); 236 if (parse(avctx, st, name, size) < 0) { 237 avpriv_request_sample(avctx, "Variable %s", name); 238 avio_skip(pb, size); 239 } 240 } 241} 242 243static void read_index(AVIOContext *pb, AVStream *st) 244{ 245 uint64_t timestamp = 0; 246 int i; 247 for (i = 0; i < st->nb_frames; i++) { 248 uint32_t pos = avio_rb32(pb); 249 uint32_t size = avio_rb32(pb); 250 avio_skip(pb, 8); 251 av_add_index_entry(st, pos, timestamp, size, 0, AVINDEX_KEYFRAME); 252 if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) { 253 timestamp += size / (st->codec->channels * 2); 254 } else { 255 timestamp++; 256 } 257 } 258} 259 260static int mv_read_header(AVFormatContext *avctx) 261{ 262 MvContext *mv = avctx->priv_data; 263 AVIOContext *pb = avctx->pb; 264 AVStream *ast = NULL, *vst = NULL; //initialization to suppress warning 265 int version, i; 266 267 avio_skip(pb, 4); 268 269 version = avio_rb16(pb); 270 if (version == 2) { 271 uint64_t timestamp; 272 int v; 273 avio_skip(pb, 22); 274 275 /* allocate audio track first to prevent unnecessary seeking 276 * (audio packet always precede video packet for a given frame) */ 277 ast = avformat_new_stream(avctx, NULL); 278 if (!ast) 279 return AVERROR(ENOMEM); 280 281 vst = avformat_new_stream(avctx, NULL); 282 if (!vst) 283 return AVERROR(ENOMEM); 284 avpriv_set_pts_info(vst, 64, 1, 15); 285 vst->codec->codec_type = AVMEDIA_TYPE_VIDEO; 286 vst->avg_frame_rate = av_inv_q(vst->time_base); 287 vst->nb_frames = avio_rb32(pb); 288 v = avio_rb32(pb); 289 switch (v) { 290 case 1: 291 vst->codec->codec_id = AV_CODEC_ID_MVC1; 292 break; 293 case 2: 294 vst->codec->pix_fmt = AV_PIX_FMT_ARGB; 295 vst->codec->codec_id = AV_CODEC_ID_RAWVIDEO; 296 break; 297 default: 298 avpriv_request_sample(avctx, "Video compression %i", v); 299 break; 300 } 301 vst->codec->codec_tag = 0; 302 vst->codec->width = avio_rb32(pb); 303 vst->codec->height = avio_rb32(pb); 304 avio_skip(pb, 12); 305 306 ast->codec->codec_type = AVMEDIA_TYPE_AUDIO; 307 ast->nb_frames = vst->nb_frames; 308 ast->codec->sample_rate = avio_rb32(pb); 309 avpriv_set_pts_info(ast, 33, 1, ast->codec->sample_rate); 310 if (set_channels(avctx, ast, avio_rb32(pb)) < 0) 311 return AVERROR_INVALIDDATA; 312 313 v = avio_rb32(pb); 314 if (v == AUDIO_FORMAT_SIGNED) { 315 ast->codec->codec_id = AV_CODEC_ID_PCM_S16BE; 316 } else { 317 avpriv_request_sample(avctx, "Audio compression (format %i)", v); 318 } 319 320 avio_skip(pb, 12); 321 var_read_metadata(avctx, "title", 0x80); 322 var_read_metadata(avctx, "comment", 0x100); 323 avio_skip(pb, 0x80); 324 325 timestamp = 0; 326 for (i = 0; i < vst->nb_frames; i++) { 327 uint32_t pos = avio_rb32(pb); 328 uint32_t asize = avio_rb32(pb); 329 uint32_t vsize = avio_rb32(pb); 330 avio_skip(pb, 8); 331 av_add_index_entry(ast, pos, timestamp, asize, 0, AVINDEX_KEYFRAME); 332 av_add_index_entry(vst, pos + asize, i, vsize, 0, AVINDEX_KEYFRAME); 333 timestamp += asize / (ast->codec->channels * 2); 334 } 335 } else if (!version && avio_rb16(pb) == 3) { 336 avio_skip(pb, 4); 337 338 read_table(avctx, NULL, parse_global_var); 339 340 if (mv->nb_audio_tracks > 1) { 341 avpriv_request_sample(avctx, "Multiple audio streams support"); 342 return AVERROR_PATCHWELCOME; 343 } else if (mv->nb_audio_tracks) { 344 ast = avformat_new_stream(avctx, NULL); 345 if (!ast) 346 return AVERROR(ENOMEM); 347 ast->codec->codec_type = AVMEDIA_TYPE_AUDIO; 348 read_table(avctx, ast, parse_audio_var); 349 if (mv->acompression == 100 && 350 mv->aformat == AUDIO_FORMAT_SIGNED && 351 ast->codec->bits_per_coded_sample == 16) { 352 ast->codec->codec_id = AV_CODEC_ID_PCM_S16BE; 353 } else { 354 avpriv_request_sample(avctx, 355 "Audio compression %i (format %i, sr %i)", 356 mv->acompression, mv->aformat, 357 ast->codec->bits_per_coded_sample); 358 ast->codec->codec_id = AV_CODEC_ID_NONE; 359 } 360 if (ast->codec->channels <= 0) { 361 av_log(avctx, AV_LOG_ERROR, "No valid channel count found.\n"); 362 return AVERROR_INVALIDDATA; 363 } 364 } 365 366 if (mv->nb_video_tracks > 1) { 367 avpriv_request_sample(avctx, "Multiple video streams support"); 368 return AVERROR_PATCHWELCOME; 369 } else if (mv->nb_video_tracks) { 370 vst = avformat_new_stream(avctx, NULL); 371 if (!vst) 372 return AVERROR(ENOMEM); 373 vst->codec->codec_type = AVMEDIA_TYPE_VIDEO; 374 read_table(avctx, vst, parse_video_var); 375 } 376 377 if (mv->nb_audio_tracks) 378 read_index(pb, ast); 379 380 if (mv->nb_video_tracks) 381 read_index(pb, vst); 382 } else { 383 avpriv_request_sample(avctx, "Version %i", version); 384 return AVERROR_PATCHWELCOME; 385 } 386 387 return 0; 388} 389 390static int mv_read_packet(AVFormatContext *avctx, AVPacket *pkt) 391{ 392 MvContext *mv = avctx->priv_data; 393 AVIOContext *pb = avctx->pb; 394 AVStream *st = avctx->streams[mv->stream_index]; 395 const AVIndexEntry *index; 396 int frame = mv->frame[mv->stream_index]; 397 int ret; 398 uint64_t pos; 399 400 if (frame < st->nb_index_entries) { 401 index = &st->index_entries[frame]; 402 pos = avio_tell(pb); 403 if (index->pos > pos) 404 avio_skip(pb, index->pos - pos); 405 else if (index->pos < pos) { 406 if (!pb->seekable) 407 return AVERROR(EIO); 408 ret = avio_seek(pb, index->pos, SEEK_SET); 409 if (ret < 0) 410 return ret; 411 } 412 ret = av_get_packet(pb, pkt, index->size); 413 if (ret < 0) 414 return ret; 415 416 pkt->stream_index = mv->stream_index; 417 pkt->pts = index->timestamp; 418 pkt->flags |= AV_PKT_FLAG_KEY; 419 420 mv->frame[mv->stream_index]++; 421 mv->eof_count = 0; 422 } else { 423 mv->eof_count++; 424 if (mv->eof_count >= avctx->nb_streams) 425 return AVERROR_EOF; 426 427 // avoid returning 0 without a packet 428 return AVERROR(EAGAIN); 429 } 430 431 mv->stream_index++; 432 if (mv->stream_index >= avctx->nb_streams) 433 mv->stream_index = 0; 434 435 return 0; 436} 437 438static int mv_read_seek(AVFormatContext *avctx, int stream_index, 439 int64_t timestamp, int flags) 440{ 441 MvContext *mv = avctx->priv_data; 442 AVStream *st = avctx->streams[stream_index]; 443 int frame, i; 444 445 if ((flags & AVSEEK_FLAG_FRAME) || (flags & AVSEEK_FLAG_BYTE)) 446 return AVERROR(ENOSYS); 447 448 if (!avctx->pb->seekable) 449 return AVERROR(EIO); 450 451 frame = av_index_search_timestamp(st, timestamp, flags); 452 if (frame < 0) 453 return AVERROR_INVALIDDATA; 454 455 for (i = 0; i < avctx->nb_streams; i++) 456 mv->frame[i] = frame; 457 return 0; 458} 459 460AVInputFormat ff_mv_demuxer = { 461 .name = "mv", 462 .long_name = NULL_IF_CONFIG_SMALL("Silicon Graphics Movie"), 463 .priv_data_size = sizeof(MvContext), 464 .read_probe = mv_probe, 465 .read_header = mv_read_header, 466 .read_packet = mv_read_packet, 467 .read_seek = mv_read_seek, 468}; 469