annotate ffmpeg/libavformat/nsvdec.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 * NSV demuxer
yading@11 3 * Copyright (c) 2004 The FFmpeg Project
yading@11 4 *
yading@11 5 * first version by Francois Revol <revol@free.fr>
yading@11 6 *
yading@11 7 * This file is part of FFmpeg.
yading@11 8 *
yading@11 9 * FFmpeg is free software; you can redistribute it and/or
yading@11 10 * modify it under the terms of the GNU Lesser General Public
yading@11 11 * License as published by the Free Software Foundation; either
yading@11 12 * version 2.1 of the License, or (at your option) any later version.
yading@11 13 *
yading@11 14 * FFmpeg is distributed in the hope that it will be useful,
yading@11 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
yading@11 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
yading@11 17 * Lesser General Public License for more details.
yading@11 18 *
yading@11 19 * You should have received a copy of the GNU Lesser General Public
yading@11 20 * License along with FFmpeg; if not, write to the Free Software
yading@11 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
yading@11 22 */
yading@11 23
yading@11 24 #include "libavutil/attributes.h"
yading@11 25 #include "libavutil/mathematics.h"
yading@11 26 #include "avformat.h"
yading@11 27 #include "internal.h"
yading@11 28 #include "libavutil/dict.h"
yading@11 29 #include "libavutil/intreadwrite.h"
yading@11 30
yading@11 31 //#define DEBUG_DUMP_INDEX // XXX dumbdriving-271.nsv breaks with it commented!!
yading@11 32 #define CHECK_SUBSEQUENT_NSVS
yading@11 33 //#define DISABLE_AUDIO
yading@11 34
yading@11 35 /* max bytes to crawl for trying to resync
yading@11 36 * stupid streaming servers don't start at chunk boundaries...
yading@11 37 */
yading@11 38 #define NSV_MAX_RESYNC (500*1024)
yading@11 39 #define NSV_MAX_RESYNC_TRIES 300
yading@11 40
yading@11 41 /*
yading@11 42 * References:
yading@11 43 * (1) http://www.multimedia.cx/nsv-format.txt
yading@11 44 * seems someone came to the same conclusions as me, and updated it:
yading@11 45 * (2) http://www.stud.ktu.lt/~vitslav/nsv/nsv-format.txt
yading@11 46 * http://www.stud.ktu.lt/~vitslav/nsv/
yading@11 47 * official docs
yading@11 48 * (3) http://ultravox.aol.com/NSVFormat.rtf
yading@11 49 * Sample files:
yading@11 50 * (S1) http://www.nullsoft.com/nsv/samples/
yading@11 51 * http://www.nullsoft.com/nsv/samples/faster.nsv
yading@11 52 * http://streamripper.sourceforge.net/openbb/read.php?TID=492&page=4
yading@11 53 */
yading@11 54
yading@11 55 /*
yading@11 56 * notes on the header (Francois Revol):
yading@11 57 *
yading@11 58 * It is followed by strings, then a table, but nothing tells
yading@11 59 * where the table begins according to (1). After checking faster.nsv,
yading@11 60 * I believe NVSf[16-19] gives the size of the strings data
yading@11 61 * (that is the offset of the data table after the header).
yading@11 62 * After checking all samples from (S1) all confirms this.
yading@11 63 *
yading@11 64 * Then, about NSVf[12-15], faster.nsf has 179700. When veiwing it in VLC,
yading@11 65 * I noticed there was about 1 NVSs chunk/s, so I ran
yading@11 66 * strings faster.nsv | grep NSVs | wc -l
yading@11 67 * which gave me 180. That leads me to think that NSVf[12-15] might be the
yading@11 68 * file length in milliseconds.
yading@11 69 * Let's try that:
yading@11 70 * for f in *.nsv; do HTIME="$(od -t x4 "$f" | head -1 | sed 's/.* //')"; echo "'$f' $((0x$HTIME))s = $((0x$HTIME/1000/60)):$((0x$HTIME/1000%60))"; done
yading@11 71 * except for nstrailer (which doesn't have an NSVf header), it repports correct time.
yading@11 72 *
yading@11 73 * nsvtrailer.nsv (S1) does not have any NSVf header, only NSVs chunks,
yading@11 74 * so the header seems to not be mandatory. (for streaming).
yading@11 75 *
yading@11 76 * index slice duration check (excepts nsvtrailer.nsv):
yading@11 77 * for f in [^n]*.nsv; do DUR="$(ffmpeg -i "$f" 2>/dev/null | grep 'NSVf duration' | cut -d ' ' -f 4)"; IC="$(ffmpeg -i "$f" 2>/dev/null | grep 'INDEX ENTRIES' | cut -d ' ' -f 2)"; echo "duration $DUR, slite time $(($DUR/$IC))"; done
yading@11 78 */
yading@11 79
yading@11 80 /*
yading@11 81 * TODO:
yading@11 82 * - handle timestamps !!!
yading@11 83 * - use index
yading@11 84 * - mime-type in probe()
yading@11 85 * - seek
yading@11 86 */
yading@11 87
yading@11 88 #if 0
yading@11 89 struct NSVf_header {
yading@11 90 uint32_t chunk_tag; /* 'NSVf' */
yading@11 91 uint32_t chunk_size;
yading@11 92 uint32_t file_size; /* max 4GB ??? no one learns anything it seems :^) */
yading@11 93 uint32_t file_length; //unknown1; /* what about MSB of file_size ? */
yading@11 94 uint32_t info_strings_size; /* size of the info strings */ //unknown2;
yading@11 95 uint32_t table_entries;
yading@11 96 uint32_t table_entries_used; /* the left ones should be -1 */
yading@11 97 };
yading@11 98
yading@11 99 struct NSVs_header {
yading@11 100 uint32_t chunk_tag; /* 'NSVs' */
yading@11 101 uint32_t v4cc; /* or 'NONE' */
yading@11 102 uint32_t a4cc; /* or 'NONE' */
yading@11 103 uint16_t vwidth; /* av_assert(vwidth%16==0) */
yading@11 104 uint16_t vheight; /* av_assert(vheight%16==0) */
yading@11 105 uint8_t framerate; /* value = (framerate&0x80)?frtable[frameratex0x7f]:framerate */
yading@11 106 uint16_t unknown;
yading@11 107 };
yading@11 108
yading@11 109 struct nsv_avchunk_header {
yading@11 110 uint8_t vchunk_size_lsb;
yading@11 111 uint16_t vchunk_size_msb; /* value = (vchunk_size_msb << 4) | (vchunk_size_lsb >> 4) */
yading@11 112 uint16_t achunk_size;
yading@11 113 };
yading@11 114
yading@11 115 struct nsv_pcm_header {
yading@11 116 uint8_t bits_per_sample;
yading@11 117 uint8_t channel_count;
yading@11 118 uint16_t sample_rate;
yading@11 119 };
yading@11 120 #endif
yading@11 121
yading@11 122 /* variation from avi.h */
yading@11 123 /*typedef struct CodecTag {
yading@11 124 int id;
yading@11 125 unsigned int tag;
yading@11 126 } CodecTag;*/
yading@11 127
yading@11 128 /* tags */
yading@11 129
yading@11 130 #define T_NSVF MKTAG('N', 'S', 'V', 'f') /* file header */
yading@11 131 #define T_NSVS MKTAG('N', 'S', 'V', 's') /* chunk header */
yading@11 132 #define T_TOC2 MKTAG('T', 'O', 'C', '2') /* extra index marker */
yading@11 133 #define T_NONE MKTAG('N', 'O', 'N', 'E') /* null a/v 4CC */
yading@11 134 #define T_SUBT MKTAG('S', 'U', 'B', 'T') /* subtitle aux data */
yading@11 135 #define T_ASYN MKTAG('A', 'S', 'Y', 'N') /* async a/v aux marker */
yading@11 136 #define T_KEYF MKTAG('K', 'E', 'Y', 'F') /* video keyframe aux marker (addition) */
yading@11 137
yading@11 138 #define TB_NSVF MKBETAG('N', 'S', 'V', 'f')
yading@11 139 #define TB_NSVS MKBETAG('N', 'S', 'V', 's')
yading@11 140
yading@11 141 /* hardcoded stream indexes */
yading@11 142 #define NSV_ST_VIDEO 0
yading@11 143 #define NSV_ST_AUDIO 1
yading@11 144 #define NSV_ST_SUBT 2
yading@11 145
yading@11 146 enum NSVStatus {
yading@11 147 NSV_UNSYNC,
yading@11 148 NSV_FOUND_NSVF,
yading@11 149 NSV_HAS_READ_NSVF,
yading@11 150 NSV_FOUND_NSVS,
yading@11 151 NSV_HAS_READ_NSVS,
yading@11 152 NSV_FOUND_BEEF,
yading@11 153 NSV_GOT_VIDEO,
yading@11 154 NSV_GOT_AUDIO,
yading@11 155 };
yading@11 156
yading@11 157 typedef struct NSVStream {
yading@11 158 int frame_offset; /* current frame (video) or byte (audio) counter
yading@11 159 (used to compute the pts) */
yading@11 160 int scale;
yading@11 161 int rate;
yading@11 162 int sample_size; /* audio only data */
yading@11 163 int start;
yading@11 164
yading@11 165 int new_frame_offset; /* temporary storage (used during seek) */
yading@11 166 int cum_len; /* temporary storage (used during seek) */
yading@11 167 } NSVStream;
yading@11 168
yading@11 169 typedef struct {
yading@11 170 int base_offset;
yading@11 171 int NSVf_end;
yading@11 172 uint32_t *nsvs_file_offset;
yading@11 173 int index_entries;
yading@11 174 enum NSVStatus state;
yading@11 175 AVPacket ahead[2]; /* [v, a] if .data is !NULL there is something */
yading@11 176 /* cached */
yading@11 177 int64_t duration;
yading@11 178 uint32_t vtag, atag;
yading@11 179 uint16_t vwidth, vheight;
yading@11 180 int16_t avsync;
yading@11 181 AVRational framerate;
yading@11 182 uint32_t *nsvs_timestamps;
yading@11 183 //DVDemuxContext* dv_demux;
yading@11 184 } NSVContext;
yading@11 185
yading@11 186 static const AVCodecTag nsv_codec_video_tags[] = {
yading@11 187 { AV_CODEC_ID_VP3, MKTAG('V', 'P', '3', ' ') },
yading@11 188 { AV_CODEC_ID_VP3, MKTAG('V', 'P', '3', '0') },
yading@11 189 { AV_CODEC_ID_VP3, MKTAG('V', 'P', '3', '1') },
yading@11 190 { AV_CODEC_ID_VP5, MKTAG('V', 'P', '5', ' ') },
yading@11 191 { AV_CODEC_ID_VP5, MKTAG('V', 'P', '5', '0') },
yading@11 192 { AV_CODEC_ID_VP6, MKTAG('V', 'P', '6', ' ') },
yading@11 193 { AV_CODEC_ID_VP6, MKTAG('V', 'P', '6', '0') },
yading@11 194 { AV_CODEC_ID_VP6, MKTAG('V', 'P', '6', '1') },
yading@11 195 { AV_CODEC_ID_VP6, MKTAG('V', 'P', '6', '2') },
yading@11 196 { AV_CODEC_ID_VP8, MKTAG('V', 'P', '8', '0') },
yading@11 197 /*
yading@11 198 { AV_CODEC_ID_VP4, MKTAG('V', 'P', '4', ' ') },
yading@11 199 { AV_CODEC_ID_VP4, MKTAG('V', 'P', '4', '0') },
yading@11 200 */
yading@11 201 { AV_CODEC_ID_MPEG4, MKTAG('X', 'V', 'I', 'D') }, /* cf sample xvid decoder from nsv_codec_sdk.zip */
yading@11 202 { AV_CODEC_ID_RAWVIDEO, MKTAG('R', 'G', 'B', '3') },
yading@11 203 { AV_CODEC_ID_NONE, 0 },
yading@11 204 };
yading@11 205
yading@11 206 static const AVCodecTag nsv_codec_audio_tags[] = {
yading@11 207 { AV_CODEC_ID_MP3, MKTAG('M', 'P', '3', ' ') },
yading@11 208 { AV_CODEC_ID_AAC, MKTAG('A', 'A', 'C', ' ') },
yading@11 209 { AV_CODEC_ID_AAC, MKTAG('A', 'A', 'C', 'P') },
yading@11 210 { AV_CODEC_ID_AAC, MKTAG('V', 'L', 'B', ' ') },
yading@11 211 { AV_CODEC_ID_SPEEX, MKTAG('S', 'P', 'X', ' ') },
yading@11 212 { AV_CODEC_ID_PCM_U16LE, MKTAG('P', 'C', 'M', ' ') },
yading@11 213 { AV_CODEC_ID_NONE, 0 },
yading@11 214 };
yading@11 215
yading@11 216 //static int nsv_load_index(AVFormatContext *s);
yading@11 217 static int nsv_read_chunk(AVFormatContext *s, int fill_header);
yading@11 218
yading@11 219 #define print_tag(str, tag, size) \
yading@11 220 av_dlog(NULL, "%s: tag=%c%c%c%c\n", \
yading@11 221 str, tag & 0xff, \
yading@11 222 (tag >> 8) & 0xff, \
yading@11 223 (tag >> 16) & 0xff, \
yading@11 224 (tag >> 24) & 0xff);
yading@11 225
yading@11 226 /* try to find something we recognize, and set the state accordingly */
yading@11 227 static int nsv_resync(AVFormatContext *s)
yading@11 228 {
yading@11 229 NSVContext *nsv = s->priv_data;
yading@11 230 AVIOContext *pb = s->pb;
yading@11 231 uint32_t v = 0;
yading@11 232 int i;
yading@11 233
yading@11 234 av_dlog(s, "%s(), offset = %"PRId64", state = %d\n", __FUNCTION__, avio_tell(pb), nsv->state);
yading@11 235
yading@11 236 //nsv->state = NSV_UNSYNC;
yading@11 237
yading@11 238 for (i = 0; i < NSV_MAX_RESYNC; i++) {
yading@11 239 if (url_feof(pb)) {
yading@11 240 av_dlog(s, "NSV EOF\n");
yading@11 241 nsv->state = NSV_UNSYNC;
yading@11 242 return -1;
yading@11 243 }
yading@11 244 v <<= 8;
yading@11 245 v |= avio_r8(pb);
yading@11 246 if (i < 8) {
yading@11 247 av_dlog(s, "NSV resync: [%d] = %02x\n", i, v & 0x0FF);
yading@11 248 }
yading@11 249
yading@11 250 if ((v & 0x0000ffff) == 0xefbe) { /* BEEF */
yading@11 251 av_dlog(s, "NSV resynced on BEEF after %d bytes\n", i+1);
yading@11 252 nsv->state = NSV_FOUND_BEEF;
yading@11 253 return 0;
yading@11 254 }
yading@11 255 /* we read as big-endian, thus the MK*BE* */
yading@11 256 if (v == TB_NSVF) { /* NSVf */
yading@11 257 av_dlog(s, "NSV resynced on NSVf after %d bytes\n", i+1);
yading@11 258 nsv->state = NSV_FOUND_NSVF;
yading@11 259 return 0;
yading@11 260 }
yading@11 261 if (v == MKBETAG('N', 'S', 'V', 's')) { /* NSVs */
yading@11 262 av_dlog(s, "NSV resynced on NSVs after %d bytes\n", i+1);
yading@11 263 nsv->state = NSV_FOUND_NSVS;
yading@11 264 return 0;
yading@11 265 }
yading@11 266
yading@11 267 }
yading@11 268 av_dlog(s, "NSV sync lost\n");
yading@11 269 return -1;
yading@11 270 }
yading@11 271
yading@11 272 static int nsv_parse_NSVf_header(AVFormatContext *s)
yading@11 273 {
yading@11 274 NSVContext *nsv = s->priv_data;
yading@11 275 AVIOContext *pb = s->pb;
yading@11 276 unsigned int av_unused file_size;
yading@11 277 unsigned int size;
yading@11 278 int64_t duration;
yading@11 279 int strings_size;
yading@11 280 int table_entries;
yading@11 281 int table_entries_used;
yading@11 282
yading@11 283 av_dlog(s, "%s()\n", __FUNCTION__);
yading@11 284
yading@11 285 nsv->state = NSV_UNSYNC; /* in case we fail */
yading@11 286
yading@11 287 size = avio_rl32(pb);
yading@11 288 if (size < 28)
yading@11 289 return -1;
yading@11 290 nsv->NSVf_end = size;
yading@11 291
yading@11 292 //s->file_size = (uint32_t)avio_rl32(pb);
yading@11 293 file_size = (uint32_t)avio_rl32(pb);
yading@11 294 av_dlog(s, "NSV NSVf chunk_size %u\n", size);
yading@11 295 av_dlog(s, "NSV NSVf file_size %u\n", file_size);
yading@11 296
yading@11 297 nsv->duration = duration = avio_rl32(pb); /* in ms */
yading@11 298 av_dlog(s, "NSV NSVf duration %"PRId64" ms\n", duration);
yading@11 299 // XXX: store it in AVStreams
yading@11 300
yading@11 301 strings_size = avio_rl32(pb);
yading@11 302 table_entries = avio_rl32(pb);
yading@11 303 table_entries_used = avio_rl32(pb);
yading@11 304 av_dlog(s, "NSV NSVf info-strings size: %d, table entries: %d, bis %d\n",
yading@11 305 strings_size, table_entries, table_entries_used);
yading@11 306 if (url_feof(pb))
yading@11 307 return -1;
yading@11 308
yading@11 309 av_dlog(s, "NSV got header; filepos %"PRId64"\n", avio_tell(pb));
yading@11 310
yading@11 311 if (strings_size > 0) {
yading@11 312 char *strings; /* last byte will be '\0' to play safe with str*() */
yading@11 313 char *p, *endp;
yading@11 314 char *token, *value;
yading@11 315 char quote;
yading@11 316
yading@11 317 p = strings = av_mallocz((size_t)strings_size + 1);
yading@11 318 if (!p)
yading@11 319 return AVERROR(ENOMEM);
yading@11 320 endp = strings + strings_size;
yading@11 321 avio_read(pb, strings, strings_size);
yading@11 322 while (p < endp) {
yading@11 323 while (*p == ' ')
yading@11 324 p++; /* strip out spaces */
yading@11 325 if (p >= endp-2)
yading@11 326 break;
yading@11 327 token = p;
yading@11 328 p = strchr(p, '=');
yading@11 329 if (!p || p >= endp-2)
yading@11 330 break;
yading@11 331 *p++ = '\0';
yading@11 332 quote = *p++;
yading@11 333 value = p;
yading@11 334 p = strchr(p, quote);
yading@11 335 if (!p || p >= endp)
yading@11 336 break;
yading@11 337 *p++ = '\0';
yading@11 338 av_dlog(s, "NSV NSVf INFO: %s='%s'\n", token, value);
yading@11 339 av_dict_set(&s->metadata, token, value, 0);
yading@11 340 }
yading@11 341 av_free(strings);
yading@11 342 }
yading@11 343 if (url_feof(pb))
yading@11 344 return -1;
yading@11 345
yading@11 346 av_dlog(s, "NSV got infos; filepos %"PRId64"\n", avio_tell(pb));
yading@11 347
yading@11 348 if (table_entries_used > 0) {
yading@11 349 int i;
yading@11 350 nsv->index_entries = table_entries_used;
yading@11 351 if((unsigned)table_entries_used >= UINT_MAX / sizeof(uint32_t))
yading@11 352 return -1;
yading@11 353 nsv->nsvs_file_offset = av_malloc((unsigned)table_entries_used * sizeof(uint32_t));
yading@11 354 if (!nsv->nsvs_file_offset)
yading@11 355 return AVERROR(ENOMEM);
yading@11 356
yading@11 357 for(i=0;i<table_entries_used;i++)
yading@11 358 nsv->nsvs_file_offset[i] = avio_rl32(pb) + size;
yading@11 359
yading@11 360 if(table_entries > table_entries_used &&
yading@11 361 avio_rl32(pb) == MKTAG('T','O','C','2')) {
yading@11 362 nsv->nsvs_timestamps = av_malloc((unsigned)table_entries_used*sizeof(uint32_t));
yading@11 363 if (!nsv->nsvs_timestamps)
yading@11 364 return AVERROR(ENOMEM);
yading@11 365 for(i=0;i<table_entries_used;i++) {
yading@11 366 nsv->nsvs_timestamps[i] = avio_rl32(pb);
yading@11 367 }
yading@11 368 }
yading@11 369 }
yading@11 370
yading@11 371 av_dlog(s, "NSV got index; filepos %"PRId64"\n", avio_tell(pb));
yading@11 372
yading@11 373 #ifdef DEBUG_DUMP_INDEX
yading@11 374 #define V(v) ((v<0x20 || v > 127)?'.':v)
yading@11 375 /* dump index */
yading@11 376 av_dlog(s, "NSV %d INDEX ENTRIES:\n", table_entries);
yading@11 377 av_dlog(s, "NSV [dataoffset][fileoffset]\n", table_entries);
yading@11 378 for (i = 0; i < table_entries; i++) {
yading@11 379 unsigned char b[8];
yading@11 380 avio_seek(pb, size + nsv->nsvs_file_offset[i], SEEK_SET);
yading@11 381 avio_read(pb, b, 8);
yading@11 382 av_dlog(s, "NSV [0x%08lx][0x%08lx]: %02x %02x %02x %02x %02x %02x %02x %02x"
yading@11 383 "%c%c%c%c%c%c%c%c\n",
yading@11 384 nsv->nsvs_file_offset[i], size + nsv->nsvs_file_offset[i],
yading@11 385 b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7],
yading@11 386 V(b[0]), V(b[1]), V(b[2]), V(b[3]), V(b[4]), V(b[5]), V(b[6]), V(b[7]) );
yading@11 387 }
yading@11 388 //avio_seek(pb, size, SEEK_SET); /* go back to end of header */
yading@11 389 #undef V
yading@11 390 #endif
yading@11 391
yading@11 392 avio_seek(pb, nsv->base_offset + size, SEEK_SET); /* required for dumbdriving-271.nsv (2 extra bytes) */
yading@11 393
yading@11 394 if (url_feof(pb))
yading@11 395 return -1;
yading@11 396 nsv->state = NSV_HAS_READ_NSVF;
yading@11 397 return 0;
yading@11 398 }
yading@11 399
yading@11 400 static int nsv_parse_NSVs_header(AVFormatContext *s)
yading@11 401 {
yading@11 402 NSVContext *nsv = s->priv_data;
yading@11 403 AVIOContext *pb = s->pb;
yading@11 404 uint32_t vtag, atag;
yading@11 405 uint16_t vwidth, vheight;
yading@11 406 AVRational framerate;
yading@11 407 int i;
yading@11 408 AVStream *st;
yading@11 409 NSVStream *nst;
yading@11 410 av_dlog(s, "%s()\n", __FUNCTION__);
yading@11 411
yading@11 412 vtag = avio_rl32(pb);
yading@11 413 atag = avio_rl32(pb);
yading@11 414 vwidth = avio_rl16(pb);
yading@11 415 vheight = avio_rl16(pb);
yading@11 416 i = avio_r8(pb);
yading@11 417
yading@11 418 av_dlog(s, "NSV NSVs framerate code %2x\n", i);
yading@11 419 if(i&0x80) { /* odd way of giving native framerates from docs */
yading@11 420 int t=(i & 0x7F)>>2;
yading@11 421 if(t<16) framerate = (AVRational){1, t+1};
yading@11 422 else framerate = (AVRational){t-15, 1};
yading@11 423
yading@11 424 if(i&1){
yading@11 425 framerate.num *= 1000;
yading@11 426 framerate.den *= 1001;
yading@11 427 }
yading@11 428
yading@11 429 if((i&3)==3) framerate.num *= 24;
yading@11 430 else if((i&3)==2) framerate.num *= 25;
yading@11 431 else framerate.num *= 30;
yading@11 432 }
yading@11 433 else
yading@11 434 framerate= (AVRational){i, 1};
yading@11 435
yading@11 436 nsv->avsync = avio_rl16(pb);
yading@11 437 nsv->framerate = framerate;
yading@11 438
yading@11 439 print_tag("NSV NSVs vtag", vtag, 0);
yading@11 440 print_tag("NSV NSVs atag", atag, 0);
yading@11 441 av_dlog(s, "NSV NSVs vsize %dx%d\n", vwidth, vheight);
yading@11 442
yading@11 443 /* XXX change to ap != NULL ? */
yading@11 444 if (s->nb_streams == 0) { /* streams not yet published, let's do that */
yading@11 445 nsv->vtag = vtag;
yading@11 446 nsv->atag = atag;
yading@11 447 nsv->vwidth = vwidth;
yading@11 448 nsv->vheight = vwidth;
yading@11 449 if (vtag != T_NONE) {
yading@11 450 int i;
yading@11 451 st = avformat_new_stream(s, NULL);
yading@11 452 if (!st)
yading@11 453 goto fail;
yading@11 454
yading@11 455 st->id = NSV_ST_VIDEO;
yading@11 456 nst = av_mallocz(sizeof(NSVStream));
yading@11 457 if (!nst)
yading@11 458 goto fail;
yading@11 459 st->priv_data = nst;
yading@11 460 st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
yading@11 461 st->codec->codec_tag = vtag;
yading@11 462 st->codec->codec_id = ff_codec_get_id(nsv_codec_video_tags, vtag);
yading@11 463 st->codec->width = vwidth;
yading@11 464 st->codec->height = vheight;
yading@11 465 st->codec->bits_per_coded_sample = 24; /* depth XXX */
yading@11 466
yading@11 467 avpriv_set_pts_info(st, 64, framerate.den, framerate.num);
yading@11 468 st->start_time = 0;
yading@11 469 st->duration = av_rescale(nsv->duration, framerate.num, 1000*framerate.den);
yading@11 470
yading@11 471 for(i=0;i<nsv->index_entries;i++) {
yading@11 472 if(nsv->nsvs_timestamps) {
yading@11 473 av_add_index_entry(st, nsv->nsvs_file_offset[i], nsv->nsvs_timestamps[i],
yading@11 474 0, 0, AVINDEX_KEYFRAME);
yading@11 475 } else {
yading@11 476 int64_t ts = av_rescale(i*nsv->duration/nsv->index_entries, framerate.num, 1000*framerate.den);
yading@11 477 av_add_index_entry(st, nsv->nsvs_file_offset[i], ts, 0, 0, AVINDEX_KEYFRAME);
yading@11 478 }
yading@11 479 }
yading@11 480 }
yading@11 481 if (atag != T_NONE) {
yading@11 482 #ifndef DISABLE_AUDIO
yading@11 483 st = avformat_new_stream(s, NULL);
yading@11 484 if (!st)
yading@11 485 goto fail;
yading@11 486
yading@11 487 st->id = NSV_ST_AUDIO;
yading@11 488 nst = av_mallocz(sizeof(NSVStream));
yading@11 489 if (!nst)
yading@11 490 goto fail;
yading@11 491 st->priv_data = nst;
yading@11 492 st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
yading@11 493 st->codec->codec_tag = atag;
yading@11 494 st->codec->codec_id = ff_codec_get_id(nsv_codec_audio_tags, atag);
yading@11 495
yading@11 496 st->need_parsing = AVSTREAM_PARSE_FULL; /* for PCM we will read a chunk later and put correct info */
yading@11 497
yading@11 498 /* set timebase to common denominator of ms and framerate */
yading@11 499 avpriv_set_pts_info(st, 64, 1, framerate.num*1000);
yading@11 500 st->start_time = 0;
yading@11 501 st->duration = (int64_t)nsv->duration * framerate.num;
yading@11 502 #endif
yading@11 503 }
yading@11 504 #ifdef CHECK_SUBSEQUENT_NSVS
yading@11 505 } else {
yading@11 506 if (nsv->vtag != vtag || nsv->atag != atag || nsv->vwidth != vwidth || nsv->vheight != vwidth) {
yading@11 507 av_dlog(s, "NSV NSVs header values differ from the first one!!!\n");
yading@11 508 //return -1;
yading@11 509 }
yading@11 510 #endif /* CHECK_SUBSEQUENT_NSVS */
yading@11 511 }
yading@11 512
yading@11 513 nsv->state = NSV_HAS_READ_NSVS;
yading@11 514 return 0;
yading@11 515 fail:
yading@11 516 /* XXX */
yading@11 517 nsv->state = NSV_UNSYNC;
yading@11 518 return -1;
yading@11 519 }
yading@11 520
yading@11 521 static int nsv_read_header(AVFormatContext *s)
yading@11 522 {
yading@11 523 NSVContext *nsv = s->priv_data;
yading@11 524 int i, err;
yading@11 525
yading@11 526 av_dlog(s, "%s()\n", __FUNCTION__);
yading@11 527 av_dlog(s, "filename '%s'\n", s->filename);
yading@11 528
yading@11 529 nsv->state = NSV_UNSYNC;
yading@11 530 nsv->ahead[0].data = nsv->ahead[1].data = NULL;
yading@11 531
yading@11 532 for (i = 0; i < NSV_MAX_RESYNC_TRIES; i++) {
yading@11 533 if (nsv_resync(s) < 0)
yading@11 534 return -1;
yading@11 535 if (nsv->state == NSV_FOUND_NSVF) {
yading@11 536 err = nsv_parse_NSVf_header(s);
yading@11 537 if (err < 0)
yading@11 538 return err;
yading@11 539 }
yading@11 540 /* we need the first NSVs also... */
yading@11 541 if (nsv->state == NSV_FOUND_NSVS) {
yading@11 542 err = nsv_parse_NSVs_header(s);
yading@11 543 if (err < 0)
yading@11 544 return err;
yading@11 545 break; /* we just want the first one */
yading@11 546 }
yading@11 547 }
yading@11 548 if (s->nb_streams < 1) /* no luck so far */
yading@11 549 return -1;
yading@11 550 /* now read the first chunk, so we can attempt to decode more info */
yading@11 551 err = nsv_read_chunk(s, 1);
yading@11 552
yading@11 553 av_dlog(s, "parsed header\n");
yading@11 554 return err;
yading@11 555 }
yading@11 556
yading@11 557 static int nsv_read_chunk(AVFormatContext *s, int fill_header)
yading@11 558 {
yading@11 559 NSVContext *nsv = s->priv_data;
yading@11 560 AVIOContext *pb = s->pb;
yading@11 561 AVStream *st[2] = {NULL, NULL};
yading@11 562 NSVStream *nst;
yading@11 563 AVPacket *pkt;
yading@11 564 int i, err = 0;
yading@11 565 uint8_t auxcount; /* number of aux metadata, also 4 bits of vsize */
yading@11 566 uint32_t vsize;
yading@11 567 uint16_t asize;
yading@11 568 uint16_t auxsize;
yading@11 569
yading@11 570 av_dlog(s, "%s(%d)\n", __FUNCTION__, fill_header);
yading@11 571
yading@11 572 if (nsv->ahead[0].data || nsv->ahead[1].data)
yading@11 573 return 0; //-1; /* hey! eat what you've in your plate first! */
yading@11 574
yading@11 575 null_chunk_retry:
yading@11 576 if (url_feof(pb))
yading@11 577 return -1;
yading@11 578
yading@11 579 for (i = 0; i < NSV_MAX_RESYNC_TRIES && nsv->state < NSV_FOUND_NSVS && !err; i++)
yading@11 580 err = nsv_resync(s);
yading@11 581 if (err < 0)
yading@11 582 return err;
yading@11 583 if (nsv->state == NSV_FOUND_NSVS)
yading@11 584 err = nsv_parse_NSVs_header(s);
yading@11 585 if (err < 0)
yading@11 586 return err;
yading@11 587 if (nsv->state != NSV_HAS_READ_NSVS && nsv->state != NSV_FOUND_BEEF)
yading@11 588 return -1;
yading@11 589
yading@11 590 auxcount = avio_r8(pb);
yading@11 591 vsize = avio_rl16(pb);
yading@11 592 asize = avio_rl16(pb);
yading@11 593 vsize = (vsize << 4) | (auxcount >> 4);
yading@11 594 auxcount &= 0x0f;
yading@11 595 av_dlog(s, "NSV CHUNK %d aux, %u bytes video, %d bytes audio\n", auxcount, vsize, asize);
yading@11 596 /* skip aux stuff */
yading@11 597 for (i = 0; i < auxcount; i++) {
yading@11 598 uint32_t av_unused auxtag;
yading@11 599 auxsize = avio_rl16(pb);
yading@11 600 auxtag = avio_rl32(pb);
yading@11 601 av_dlog(s, "NSV aux data: '%c%c%c%c', %d bytes\n",
yading@11 602 (auxtag & 0x0ff),
yading@11 603 ((auxtag >> 8) & 0x0ff),
yading@11 604 ((auxtag >> 16) & 0x0ff),
yading@11 605 ((auxtag >> 24) & 0x0ff),
yading@11 606 auxsize);
yading@11 607 avio_skip(pb, auxsize);
yading@11 608 vsize -= auxsize + sizeof(uint16_t) + sizeof(uint32_t); /* that's becoming braindead */
yading@11 609 }
yading@11 610
yading@11 611 if (url_feof(pb))
yading@11 612 return -1;
yading@11 613 if (!vsize && !asize) {
yading@11 614 nsv->state = NSV_UNSYNC;
yading@11 615 goto null_chunk_retry;
yading@11 616 }
yading@11 617
yading@11 618 /* map back streams to v,a */
yading@11 619 if (s->nb_streams > 0)
yading@11 620 st[s->streams[0]->id] = s->streams[0];
yading@11 621 if (s->nb_streams > 1)
yading@11 622 st[s->streams[1]->id] = s->streams[1];
yading@11 623
yading@11 624 if (vsize && st[NSV_ST_VIDEO]) {
yading@11 625 nst = st[NSV_ST_VIDEO]->priv_data;
yading@11 626 pkt = &nsv->ahead[NSV_ST_VIDEO];
yading@11 627 av_get_packet(pb, pkt, vsize);
yading@11 628 pkt->stream_index = st[NSV_ST_VIDEO]->index;//NSV_ST_VIDEO;
yading@11 629 pkt->dts = nst->frame_offset;
yading@11 630 pkt->flags |= nsv->state == NSV_HAS_READ_NSVS ? AV_PKT_FLAG_KEY : 0; /* keyframe only likely on a sync frame */
yading@11 631 for (i = 0; i < FFMIN(8, vsize); i++)
yading@11 632 av_dlog(s, "NSV video: [%d] = %02x\n", i, pkt->data[i]);
yading@11 633 }
yading@11 634 if(st[NSV_ST_VIDEO])
yading@11 635 ((NSVStream*)st[NSV_ST_VIDEO]->priv_data)->frame_offset++;
yading@11 636
yading@11 637 if (asize && st[NSV_ST_AUDIO]) {
yading@11 638 nst = st[NSV_ST_AUDIO]->priv_data;
yading@11 639 pkt = &nsv->ahead[NSV_ST_AUDIO];
yading@11 640 /* read raw audio specific header on the first audio chunk... */
yading@11 641 /* on ALL audio chunks ?? seems so! */
yading@11 642 if (asize && st[NSV_ST_AUDIO]->codec->codec_tag == MKTAG('P', 'C', 'M', ' ')/* && fill_header*/) {
yading@11 643 uint8_t bps;
yading@11 644 uint8_t channels;
yading@11 645 uint16_t samplerate;
yading@11 646 bps = avio_r8(pb);
yading@11 647 channels = avio_r8(pb);
yading@11 648 samplerate = avio_rl16(pb);
yading@11 649 asize-=4;
yading@11 650 av_dlog(s, "NSV RAWAUDIO: bps %d, nchan %d, srate %d\n", bps, channels, samplerate);
yading@11 651 if (fill_header) {
yading@11 652 st[NSV_ST_AUDIO]->need_parsing = AVSTREAM_PARSE_NONE; /* we know everything */
yading@11 653 if (bps != 16) {
yading@11 654 av_dlog(s, "NSV AUDIO bit/sample != 16 (%d)!!!\n", bps);
yading@11 655 }
yading@11 656 if(channels)
yading@11 657 bps /= channels; // ???
yading@11 658 else
yading@11 659 av_log(s, AV_LOG_WARNING, "Channels is 0\n");
yading@11 660 if (bps == 8)
yading@11 661 st[NSV_ST_AUDIO]->codec->codec_id = AV_CODEC_ID_PCM_U8;
yading@11 662 samplerate /= 4;/* UGH ??? XXX */
yading@11 663 channels = 1;
yading@11 664 st[NSV_ST_AUDIO]->codec->channels = channels;
yading@11 665 st[NSV_ST_AUDIO]->codec->sample_rate = samplerate;
yading@11 666 av_dlog(s, "NSV RAWAUDIO: bps %d, nchan %d, srate %d\n", bps, channels, samplerate);
yading@11 667 }
yading@11 668 }
yading@11 669 av_get_packet(pb, pkt, asize);
yading@11 670 pkt->stream_index = st[NSV_ST_AUDIO]->index;//NSV_ST_AUDIO;
yading@11 671 pkt->flags |= nsv->state == NSV_HAS_READ_NSVS ? AV_PKT_FLAG_KEY : 0; /* keyframe only likely on a sync frame */
yading@11 672 if( nsv->state == NSV_HAS_READ_NSVS && st[NSV_ST_VIDEO] ) {
yading@11 673 /* on a nsvs frame we have new information on a/v sync */
yading@11 674 pkt->dts = (((NSVStream*)st[NSV_ST_VIDEO]->priv_data)->frame_offset-1);
yading@11 675 pkt->dts *= (int64_t)1000 * nsv->framerate.den;
yading@11 676 pkt->dts += (int64_t)nsv->avsync * nsv->framerate.num;
yading@11 677 av_dlog(s, "NSV AUDIO: sync:%d, dts:%"PRId64, nsv->avsync, pkt->dts);
yading@11 678 }
yading@11 679 nst->frame_offset++;
yading@11 680 }
yading@11 681
yading@11 682 nsv->state = NSV_UNSYNC;
yading@11 683 return 0;
yading@11 684 }
yading@11 685
yading@11 686
yading@11 687 static int nsv_read_packet(AVFormatContext *s, AVPacket *pkt)
yading@11 688 {
yading@11 689 NSVContext *nsv = s->priv_data;
yading@11 690 int i, err = 0;
yading@11 691
yading@11 692 av_dlog(s, "%s()\n", __FUNCTION__);
yading@11 693
yading@11 694 /* in case we don't already have something to eat ... */
yading@11 695 if (nsv->ahead[0].data == NULL && nsv->ahead[1].data == NULL)
yading@11 696 err = nsv_read_chunk(s, 0);
yading@11 697 if (err < 0)
yading@11 698 return err;
yading@11 699
yading@11 700 /* now pick one of the plates */
yading@11 701 for (i = 0; i < 2; i++) {
yading@11 702 if (nsv->ahead[i].data) {
yading@11 703 av_dlog(s, "%s: using cached packet[%d]\n", __FUNCTION__, i);
yading@11 704 /* avoid the cost of new_packet + memcpy(->data) */
yading@11 705 memcpy(pkt, &nsv->ahead[i], sizeof(AVPacket));
yading@11 706 nsv->ahead[i].data = NULL; /* we ate that one */
yading@11 707 return pkt->size;
yading@11 708 }
yading@11 709 }
yading@11 710
yading@11 711 /* this restaurant is not approvisionned :^] */
yading@11 712 return -1;
yading@11 713 }
yading@11 714
yading@11 715 static int nsv_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
yading@11 716 {
yading@11 717 NSVContext *nsv = s->priv_data;
yading@11 718 AVStream *st = s->streams[stream_index];
yading@11 719 NSVStream *nst = st->priv_data;
yading@11 720 int index;
yading@11 721
yading@11 722 index = av_index_search_timestamp(st, timestamp, flags);
yading@11 723 if(index < 0)
yading@11 724 return -1;
yading@11 725
yading@11 726 if (avio_seek(s->pb, st->index_entries[index].pos, SEEK_SET) < 0)
yading@11 727 return -1;
yading@11 728
yading@11 729 nst->frame_offset = st->index_entries[index].timestamp;
yading@11 730 nsv->state = NSV_UNSYNC;
yading@11 731 return 0;
yading@11 732 }
yading@11 733
yading@11 734 static int nsv_read_close(AVFormatContext *s)
yading@11 735 {
yading@11 736 /* int i; */
yading@11 737 NSVContext *nsv = s->priv_data;
yading@11 738
yading@11 739 av_freep(&nsv->nsvs_file_offset);
yading@11 740 av_freep(&nsv->nsvs_timestamps);
yading@11 741 if (nsv->ahead[0].data)
yading@11 742 av_free_packet(&nsv->ahead[0]);
yading@11 743 if (nsv->ahead[1].data)
yading@11 744 av_free_packet(&nsv->ahead[1]);
yading@11 745
yading@11 746 #if 0
yading@11 747
yading@11 748 for(i=0;i<s->nb_streams;i++) {
yading@11 749 AVStream *st = s->streams[i];
yading@11 750 NSVStream *ast = st->priv_data;
yading@11 751 if(ast){
yading@11 752 av_free(ast->index_entries);
yading@11 753 av_free(ast);
yading@11 754 }
yading@11 755 av_free(st->codec->palctrl);
yading@11 756 }
yading@11 757
yading@11 758 #endif
yading@11 759 return 0;
yading@11 760 }
yading@11 761
yading@11 762 static int nsv_probe(AVProbeData *p)
yading@11 763 {
yading@11 764 int i, score = 0;
yading@11 765
yading@11 766 av_dlog(NULL, "nsv_probe(), buf_size %d\n", p->buf_size);
yading@11 767 /* check file header */
yading@11 768 /* streamed files might not have any header */
yading@11 769 if (p->buf[0] == 'N' && p->buf[1] == 'S' &&
yading@11 770 p->buf[2] == 'V' && (p->buf[3] == 'f' || p->buf[3] == 's'))
yading@11 771 return AVPROBE_SCORE_MAX;
yading@11 772 /* XXX: do streamed files always start at chunk boundary ?? */
yading@11 773 /* or do we need to search NSVs in the byte stream ? */
yading@11 774 /* seems the servers don't bother starting clean chunks... */
yading@11 775 /* sometimes even the first header is at 9KB or something :^) */
yading@11 776 for (i = 1; i < p->buf_size - 3; i++) {
yading@11 777 if (AV_RL32(p->buf + i) == AV_RL32("NSVs")) {
yading@11 778 /* Get the chunk size and check if at the end we are getting 0xBEEF */
yading@11 779 int vsize = AV_RL24(p->buf+i+19) >> 4;
yading@11 780 int asize = AV_RL16(p->buf+i+22);
yading@11 781 int offset = i + 23 + asize + vsize + 1;
yading@11 782 if (offset <= p->buf_size - 2 && AV_RL16(p->buf + offset) == 0xBEEF)
yading@11 783 return 4*AVPROBE_SCORE_MAX/5;
yading@11 784 score = AVPROBE_SCORE_MAX/5;
yading@11 785 }
yading@11 786 }
yading@11 787 /* so we'll have more luck on extension... */
yading@11 788 if (av_match_ext(p->filename, "nsv"))
yading@11 789 return AVPROBE_SCORE_MAX/2;
yading@11 790 /* FIXME: add mime-type check */
yading@11 791 return score;
yading@11 792 }
yading@11 793
yading@11 794 AVInputFormat ff_nsv_demuxer = {
yading@11 795 .name = "nsv",
yading@11 796 .long_name = NULL_IF_CONFIG_SMALL("Nullsoft Streaming Video"),
yading@11 797 .priv_data_size = sizeof(NSVContext),
yading@11 798 .read_probe = nsv_probe,
yading@11 799 .read_header = nsv_read_header,
yading@11 800 .read_packet = nsv_read_packet,
yading@11 801 .read_close = nsv_read_close,
yading@11 802 .read_seek = nsv_read_seek,
yading@11 803 };