00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "avformat.h"
00022 #include "riff.h"
00023
00024
00025
00026
00027 #define CHECK_SUBSEQUENT_NSVS
00028
00029
00030
00031
00032
00033 #define NSV_MAX_RESYNC (500*1024)
00034 #define NSV_MAX_RESYNC_TRIES 300
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084 #if 0
00085 struct NSVf_header {
00086 uint32_t chunk_tag;
00087 uint32_t chunk_size;
00088 uint32_t file_size;
00089 uint32_t file_length;
00090 uint32_t info_strings_size;
00091 uint32_t table_entries;
00092 uint32_t table_entries_used;
00093 };
00094
00095 struct NSVs_header {
00096 uint32_t chunk_tag;
00097 uint32_t v4cc;
00098 uint32_t a4cc;
00099 uint16_t vwidth;
00100 uint16_t vheight;
00101 uint8_t framerate;
00102 uint16_t unknown;
00103 };
00104
00105 struct nsv_avchunk_header {
00106 uint8_t vchunk_size_lsb;
00107 uint16_t vchunk_size_msb;
00108 uint16_t achunk_size;
00109 };
00110
00111 struct nsv_pcm_header {
00112 uint8_t bits_per_sample;
00113 uint8_t channel_count;
00114 uint16_t sample_rate;
00115 };
00116 #endif
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126 #define T_NSVF MKTAG('N', 'S', 'V', 'f')
00127 #define T_NSVS MKTAG('N', 'S', 'V', 's')
00128 #define T_TOC2 MKTAG('T', 'O', 'C', '2')
00129 #define T_NONE MKTAG('N', 'O', 'N', 'E')
00130 #define T_SUBT MKTAG('S', 'U', 'B', 'T')
00131 #define T_ASYN MKTAG('A', 'S', 'Y', 'N')
00132 #define T_KEYF MKTAG('K', 'E', 'Y', 'F')
00133
00134 #define TB_NSVF MKBETAG('N', 'S', 'V', 'f')
00135 #define TB_NSVS MKBETAG('N', 'S', 'V', 's')
00136
00137
00138 #define NSV_ST_VIDEO 0
00139 #define NSV_ST_AUDIO 1
00140 #define NSV_ST_SUBT 2
00141
00142 enum NSVStatus {
00143 NSV_UNSYNC,
00144 NSV_FOUND_NSVF,
00145 NSV_HAS_READ_NSVF,
00146 NSV_FOUND_NSVS,
00147 NSV_HAS_READ_NSVS,
00148 NSV_FOUND_BEEF,
00149 NSV_GOT_VIDEO,
00150 NSV_GOT_AUDIO,
00151 };
00152
00153 typedef struct NSVStream {
00154 int frame_offset;
00155
00156 int scale;
00157 int rate;
00158 int sample_size;
00159 int start;
00160
00161 int new_frame_offset;
00162 int cum_len;
00163 } NSVStream;
00164
00165 typedef struct {
00166 int base_offset;
00167 int NSVf_end;
00168 uint32_t *nsvs_file_offset;
00169 int index_entries;
00170 enum NSVStatus state;
00171 AVPacket ahead[2];
00172
00173 int64_t duration;
00174 uint32_t vtag, atag;
00175 uint16_t vwidth, vheight;
00176 int16_t avsync;
00177 AVRational framerate;
00178 uint32_t *nsvs_timestamps;
00179
00180 } NSVContext;
00181
00182 static const AVCodecTag nsv_codec_video_tags[] = {
00183 { CODEC_ID_VP3, MKTAG('V', 'P', '3', ' ') },
00184 { CODEC_ID_VP3, MKTAG('V', 'P', '3', '0') },
00185 { CODEC_ID_VP3, MKTAG('V', 'P', '3', '1') },
00186 { CODEC_ID_VP5, MKTAG('V', 'P', '5', ' ') },
00187 { CODEC_ID_VP5, MKTAG('V', 'P', '5', '0') },
00188 { CODEC_ID_VP6, MKTAG('V', 'P', '6', ' ') },
00189 { CODEC_ID_VP6, MKTAG('V', 'P', '6', '0') },
00190 { CODEC_ID_VP6, MKTAG('V', 'P', '6', '1') },
00191 { CODEC_ID_VP6, MKTAG('V', 'P', '6', '2') },
00192
00193
00194
00195
00196 { CODEC_ID_MPEG4, MKTAG('X', 'V', 'I', 'D') },
00197 { CODEC_ID_RAWVIDEO, MKTAG('R', 'G', 'B', '3') },
00198 { CODEC_ID_NONE, 0 },
00199 };
00200
00201 static const AVCodecTag nsv_codec_audio_tags[] = {
00202 { CODEC_ID_MP3, MKTAG('M', 'P', '3', ' ') },
00203 { CODEC_ID_AAC, MKTAG('A', 'A', 'C', ' ') },
00204 { CODEC_ID_AAC, MKTAG('A', 'A', 'C', 'P') },
00205 { CODEC_ID_SPEEX, MKTAG('S', 'P', 'X', ' ') },
00206 { CODEC_ID_PCM_U16LE, MKTAG('P', 'C', 'M', ' ') },
00207 { CODEC_ID_NONE, 0 },
00208 };
00209
00210
00211 static int nsv_read_chunk(AVFormatContext *s, int fill_header);
00212
00213 #define print_tag(str, tag, size) \
00214 av_dlog(NULL, "%s: tag=%c%c%c%c\n", \
00215 str, tag & 0xff, \
00216 (tag >> 8) & 0xff, \
00217 (tag >> 16) & 0xff, \
00218 (tag >> 24) & 0xff);
00219
00220
00221 static int nsv_resync(AVFormatContext *s)
00222 {
00223 NSVContext *nsv = s->priv_data;
00224 AVIOContext *pb = s->pb;
00225 uint32_t v = 0;
00226 int i;
00227
00228 av_dlog(s, "%s(), offset = %"PRId64", state = %d\n", __FUNCTION__, avio_tell(pb), nsv->state);
00229
00230
00231
00232 for (i = 0; i < NSV_MAX_RESYNC; i++) {
00233 if (url_feof(pb)) {
00234 av_dlog(s, "NSV EOF\n");
00235 nsv->state = NSV_UNSYNC;
00236 return -1;
00237 }
00238 v <<= 8;
00239 v |= avio_r8(pb);
00240 if (i < 8) {
00241 av_dlog(s, "NSV resync: [%d] = %02x\n", i, v & 0x0FF);
00242 }
00243
00244 if ((v & 0x0000ffff) == 0xefbe) {
00245 av_dlog(s, "NSV resynced on BEEF after %d bytes\n", i+1);
00246 nsv->state = NSV_FOUND_BEEF;
00247 return 0;
00248 }
00249
00250 if (v == TB_NSVF) {
00251 av_dlog(s, "NSV resynced on NSVf after %d bytes\n", i+1);
00252 nsv->state = NSV_FOUND_NSVF;
00253 return 0;
00254 }
00255 if (v == MKBETAG('N', 'S', 'V', 's')) {
00256 av_dlog(s, "NSV resynced on NSVs after %d bytes\n", i+1);
00257 nsv->state = NSV_FOUND_NSVS;
00258 return 0;
00259 }
00260
00261 }
00262 av_dlog(s, "NSV sync lost\n");
00263 return -1;
00264 }
00265
00266 static int nsv_parse_NSVf_header(AVFormatContext *s, AVFormatParameters *ap)
00267 {
00268 NSVContext *nsv = s->priv_data;
00269 AVIOContext *pb = s->pb;
00270 unsigned int file_size, size;
00271 int64_t duration;
00272 int strings_size;
00273 int table_entries;
00274 int table_entries_used;
00275
00276 av_dlog(s, "%s()\n", __FUNCTION__);
00277
00278 nsv->state = NSV_UNSYNC;
00279
00280 size = avio_rl32(pb);
00281 if (size < 28)
00282 return -1;
00283 nsv->NSVf_end = size;
00284
00285
00286 file_size = (uint32_t)avio_rl32(pb);
00287 av_dlog(s, "NSV NSVf chunk_size %u\n", size);
00288 av_dlog(s, "NSV NSVf file_size %u\n", file_size);
00289
00290 nsv->duration = duration = avio_rl32(pb);
00291 av_dlog(s, "NSV NSVf duration %"PRId64" ms\n", duration);
00292
00293
00294 strings_size = avio_rl32(pb);
00295 table_entries = avio_rl32(pb);
00296 table_entries_used = avio_rl32(pb);
00297 av_dlog(s, "NSV NSVf info-strings size: %d, table entries: %d, bis %d\n",
00298 strings_size, table_entries, table_entries_used);
00299 if (url_feof(pb))
00300 return -1;
00301
00302 av_dlog(s, "NSV got header; filepos %"PRId64"\n", avio_tell(pb));
00303
00304 if (strings_size > 0) {
00305 char *strings;
00306 char *p, *endp;
00307 char *token, *value;
00308 char quote;
00309
00310 p = strings = av_mallocz(strings_size + 1);
00311 endp = strings + strings_size;
00312 avio_read(pb, strings, strings_size);
00313 while (p < endp) {
00314 while (*p == ' ')
00315 p++;
00316 if (p >= endp-2)
00317 break;
00318 token = p;
00319 p = strchr(p, '=');
00320 if (!p || p >= endp-2)
00321 break;
00322 *p++ = '\0';
00323 quote = *p++;
00324 value = p;
00325 p = strchr(p, quote);
00326 if (!p || p >= endp)
00327 break;
00328 *p++ = '\0';
00329 av_dlog(s, "NSV NSVf INFO: %s='%s'\n", token, value);
00330 av_metadata_set2(&s->metadata, token, value, 0);
00331 }
00332 av_free(strings);
00333 }
00334 if (url_feof(pb))
00335 return -1;
00336
00337 av_dlog(s, "NSV got infos; filepos %"PRId64"\n", avio_tell(pb));
00338
00339 if (table_entries_used > 0) {
00340 int i;
00341 nsv->index_entries = table_entries_used;
00342 if((unsigned)table_entries_used >= UINT_MAX / sizeof(uint32_t))
00343 return -1;
00344 nsv->nsvs_file_offset = av_malloc((unsigned)table_entries_used * sizeof(uint32_t));
00345
00346 for(i=0;i<table_entries_used;i++)
00347 nsv->nsvs_file_offset[i] = avio_rl32(pb) + size;
00348
00349 if(table_entries > table_entries_used &&
00350 avio_rl32(pb) == MKTAG('T','O','C','2')) {
00351 nsv->nsvs_timestamps = av_malloc((unsigned)table_entries_used*sizeof(uint32_t));
00352 for(i=0;i<table_entries_used;i++) {
00353 nsv->nsvs_timestamps[i] = avio_rl32(pb);
00354 }
00355 }
00356 }
00357
00358 av_dlog(s, "NSV got index; filepos %"PRId64"\n", avio_tell(pb));
00359
00360 #ifdef DEBUG_DUMP_INDEX
00361 #define V(v) ((v<0x20 || v > 127)?'.':v)
00362
00363 av_dlog(s, "NSV %d INDEX ENTRIES:\n", table_entries);
00364 av_dlog(s, "NSV [dataoffset][fileoffset]\n", table_entries);
00365 for (i = 0; i < table_entries; i++) {
00366 unsigned char b[8];
00367 avio_seek(pb, size + nsv->nsvs_file_offset[i], SEEK_SET);
00368 avio_read(pb, b, 8);
00369 av_dlog(s, "NSV [0x%08lx][0x%08lx]: %02x %02x %02x %02x %02x %02x %02x %02x"
00370 "%c%c%c%c%c%c%c%c\n",
00371 nsv->nsvs_file_offset[i], size + nsv->nsvs_file_offset[i],
00372 b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7],
00373 V(b[0]), V(b[1]), V(b[2]), V(b[3]), V(b[4]), V(b[5]), V(b[6]), V(b[7]) );
00374 }
00375
00376 #undef V
00377 #endif
00378
00379 avio_seek(pb, nsv->base_offset + size, SEEK_SET);
00380
00381 if (url_feof(pb))
00382 return -1;
00383 nsv->state = NSV_HAS_READ_NSVF;
00384 return 0;
00385 }
00386
00387 static int nsv_parse_NSVs_header(AVFormatContext *s, AVFormatParameters *ap)
00388 {
00389 NSVContext *nsv = s->priv_data;
00390 AVIOContext *pb = s->pb;
00391 uint32_t vtag, atag;
00392 uint16_t vwidth, vheight;
00393 AVRational framerate;
00394 int i;
00395 AVStream *st;
00396 NSVStream *nst;
00397 av_dlog(s, "%s()\n", __FUNCTION__);
00398
00399 vtag = avio_rl32(pb);
00400 atag = avio_rl32(pb);
00401 vwidth = avio_rl16(pb);
00402 vheight = avio_rl16(pb);
00403 i = avio_r8(pb);
00404
00405 av_dlog(s, "NSV NSVs framerate code %2x\n", i);
00406 if(i&0x80) {
00407 int t=(i & 0x7F)>>2;
00408 if(t<16) framerate = (AVRational){1, t+1};
00409 else framerate = (AVRational){t-15, 1};
00410
00411 if(i&1){
00412 framerate.num *= 1000;
00413 framerate.den *= 1001;
00414 }
00415
00416 if((i&3)==3) framerate.num *= 24;
00417 else if((i&3)==2) framerate.num *= 25;
00418 else framerate.num *= 30;
00419 }
00420 else
00421 framerate= (AVRational){i, 1};
00422
00423 nsv->avsync = avio_rl16(pb);
00424 nsv->framerate = framerate;
00425
00426 print_tag("NSV NSVs vtag", vtag, 0);
00427 print_tag("NSV NSVs atag", atag, 0);
00428 av_dlog(s, "NSV NSVs vsize %dx%d\n", vwidth, vheight);
00429
00430
00431 if (s->nb_streams == 0) {
00432 nsv->vtag = vtag;
00433 nsv->atag = atag;
00434 nsv->vwidth = vwidth;
00435 nsv->vheight = vwidth;
00436 if (vtag != T_NONE) {
00437 int i;
00438 st = av_new_stream(s, NSV_ST_VIDEO);
00439 if (!st)
00440 goto fail;
00441
00442 nst = av_mallocz(sizeof(NSVStream));
00443 if (!nst)
00444 goto fail;
00445 st->priv_data = nst;
00446 st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
00447 st->codec->codec_tag = vtag;
00448 st->codec->codec_id = ff_codec_get_id(nsv_codec_video_tags, vtag);
00449 st->codec->width = vwidth;
00450 st->codec->height = vheight;
00451 st->codec->bits_per_coded_sample = 24;
00452
00453 av_set_pts_info(st, 64, framerate.den, framerate.num);
00454 st->start_time = 0;
00455 st->duration = av_rescale(nsv->duration, framerate.num, 1000*framerate.den);
00456
00457 for(i=0;i<nsv->index_entries;i++) {
00458 if(nsv->nsvs_timestamps) {
00459 av_add_index_entry(st, nsv->nsvs_file_offset[i], nsv->nsvs_timestamps[i],
00460 0, 0, AVINDEX_KEYFRAME);
00461 } else {
00462 int64_t ts = av_rescale(i*nsv->duration/nsv->index_entries, framerate.num, 1000*framerate.den);
00463 av_add_index_entry(st, nsv->nsvs_file_offset[i], ts, 0, 0, AVINDEX_KEYFRAME);
00464 }
00465 }
00466 }
00467 if (atag != T_NONE) {
00468 #ifndef DISABLE_AUDIO
00469 st = av_new_stream(s, NSV_ST_AUDIO);
00470 if (!st)
00471 goto fail;
00472
00473 nst = av_mallocz(sizeof(NSVStream));
00474 if (!nst)
00475 goto fail;
00476 st->priv_data = nst;
00477 st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
00478 st->codec->codec_tag = atag;
00479 st->codec->codec_id = ff_codec_get_id(nsv_codec_audio_tags, atag);
00480
00481 st->need_parsing = AVSTREAM_PARSE_FULL;
00482
00483
00484 av_set_pts_info(st, 64, 1, framerate.num*1000);
00485 st->start_time = 0;
00486 st->duration = (int64_t)nsv->duration * framerate.num;
00487 #endif
00488 }
00489 #ifdef CHECK_SUBSEQUENT_NSVS
00490 } else {
00491 if (nsv->vtag != vtag || nsv->atag != atag || nsv->vwidth != vwidth || nsv->vheight != vwidth) {
00492 av_dlog(s, "NSV NSVs header values differ from the first one!!!\n");
00493
00494 }
00495 #endif
00496 }
00497
00498 nsv->state = NSV_HAS_READ_NSVS;
00499 return 0;
00500 fail:
00501
00502 nsv->state = NSV_UNSYNC;
00503 return -1;
00504 }
00505
00506 static int nsv_read_header(AVFormatContext *s, AVFormatParameters *ap)
00507 {
00508 NSVContext *nsv = s->priv_data;
00509 int i, err;
00510
00511 av_dlog(s, "%s()\n", __FUNCTION__);
00512 av_dlog(s, "filename '%s'\n", s->filename);
00513
00514 nsv->state = NSV_UNSYNC;
00515 nsv->ahead[0].data = nsv->ahead[1].data = NULL;
00516
00517 for (i = 0; i < NSV_MAX_RESYNC_TRIES; i++) {
00518 if (nsv_resync(s) < 0)
00519 return -1;
00520 if (nsv->state == NSV_FOUND_NSVF)
00521 err = nsv_parse_NSVf_header(s, ap);
00522
00523 if (nsv->state == NSV_FOUND_NSVS) {
00524 err = nsv_parse_NSVs_header(s, ap);
00525 break;
00526 }
00527 }
00528 if (s->nb_streams < 1)
00529 return -1;
00530
00531 err = nsv_read_chunk(s, 1);
00532
00533 av_dlog(s, "parsed header\n");
00534 return 0;
00535 }
00536
00537 static int nsv_read_chunk(AVFormatContext *s, int fill_header)
00538 {
00539 NSVContext *nsv = s->priv_data;
00540 AVIOContext *pb = s->pb;
00541 AVStream *st[2] = {NULL, NULL};
00542 NSVStream *nst;
00543 AVPacket *pkt;
00544 int i, err = 0;
00545 uint8_t auxcount;
00546 uint32_t vsize;
00547 uint16_t asize;
00548 uint16_t auxsize;
00549 uint32_t auxtag;
00550
00551 av_dlog(s, "%s(%d)\n", __FUNCTION__, fill_header);
00552
00553 if (nsv->ahead[0].data || nsv->ahead[1].data)
00554 return 0;
00555
00556 null_chunk_retry:
00557 if (url_feof(pb))
00558 return -1;
00559
00560 for (i = 0; i < NSV_MAX_RESYNC_TRIES && nsv->state < NSV_FOUND_NSVS && !err; i++)
00561 err = nsv_resync(s);
00562 if (err < 0)
00563 return err;
00564 if (nsv->state == NSV_FOUND_NSVS)
00565 err = nsv_parse_NSVs_header(s, NULL);
00566 if (err < 0)
00567 return err;
00568 if (nsv->state != NSV_HAS_READ_NSVS && nsv->state != NSV_FOUND_BEEF)
00569 return -1;
00570
00571 auxcount = avio_r8(pb);
00572 vsize = avio_rl16(pb);
00573 asize = avio_rl16(pb);
00574 vsize = (vsize << 4) | (auxcount >> 4);
00575 auxcount &= 0x0f;
00576 av_dlog(s, "NSV CHUNK %d aux, %u bytes video, %d bytes audio\n", auxcount, vsize, asize);
00577
00578 for (i = 0; i < auxcount; i++) {
00579 auxsize = avio_rl16(pb);
00580 auxtag = avio_rl32(pb);
00581 av_dlog(s, "NSV aux data: '%c%c%c%c', %d bytes\n",
00582 (auxtag & 0x0ff),
00583 ((auxtag >> 8) & 0x0ff),
00584 ((auxtag >> 16) & 0x0ff),
00585 ((auxtag >> 24) & 0x0ff),
00586 auxsize);
00587 avio_seek(pb, auxsize, SEEK_CUR);
00588 vsize -= auxsize + sizeof(uint16_t) + sizeof(uint32_t);
00589 }
00590
00591 if (url_feof(pb))
00592 return -1;
00593 if (!vsize && !asize) {
00594 nsv->state = NSV_UNSYNC;
00595 goto null_chunk_retry;
00596 }
00597
00598
00599 if (s->streams[0])
00600 st[s->streams[0]->id] = s->streams[0];
00601 if (s->streams[1])
00602 st[s->streams[1]->id] = s->streams[1];
00603
00604 if (vsize) {
00605 nst = st[NSV_ST_VIDEO]->priv_data;
00606 pkt = &nsv->ahead[NSV_ST_VIDEO];
00607 av_get_packet(pb, pkt, vsize);
00608 pkt->stream_index = st[NSV_ST_VIDEO]->index;
00609 pkt->dts = nst->frame_offset;
00610 pkt->flags |= nsv->state == NSV_HAS_READ_NSVS ? AV_PKT_FLAG_KEY : 0;
00611 for (i = 0; i < FFMIN(8, vsize); i++)
00612 av_dlog(s, "NSV video: [%d] = %02x\n", i, pkt->data[i]);
00613 }
00614 if(st[NSV_ST_VIDEO])
00615 ((NSVStream*)st[NSV_ST_VIDEO]->priv_data)->frame_offset++;
00616
00617 if (asize) {
00618 nst = st[NSV_ST_AUDIO]->priv_data;
00619 pkt = &nsv->ahead[NSV_ST_AUDIO];
00620
00621
00622 if (asize && st[NSV_ST_AUDIO]->codec->codec_tag == MKTAG('P', 'C', 'M', ' ')) {
00623 uint8_t bps;
00624 uint8_t channels;
00625 uint16_t samplerate;
00626 bps = avio_r8(pb);
00627 channels = avio_r8(pb);
00628 samplerate = avio_rl16(pb);
00629 asize-=4;
00630 av_dlog(s, "NSV RAWAUDIO: bps %d, nchan %d, srate %d\n", bps, channels, samplerate);
00631 if (fill_header) {
00632 st[NSV_ST_AUDIO]->need_parsing = AVSTREAM_PARSE_NONE;
00633 if (bps != 16) {
00634 av_dlog(s, "NSV AUDIO bit/sample != 16 (%d)!!!\n", bps);
00635 }
00636 bps /= channels;
00637 if (bps == 8)
00638 st[NSV_ST_AUDIO]->codec->codec_id = CODEC_ID_PCM_U8;
00639 samplerate /= 4;
00640 channels = 1;
00641 st[NSV_ST_AUDIO]->codec->channels = channels;
00642 st[NSV_ST_AUDIO]->codec->sample_rate = samplerate;
00643 av_dlog(s, "NSV RAWAUDIO: bps %d, nchan %d, srate %d\n", bps, channels, samplerate);
00644 }
00645 }
00646 av_get_packet(pb, pkt, asize);
00647 pkt->stream_index = st[NSV_ST_AUDIO]->index;
00648 pkt->flags |= nsv->state == NSV_HAS_READ_NSVS ? AV_PKT_FLAG_KEY : 0;
00649 if( nsv->state == NSV_HAS_READ_NSVS && st[NSV_ST_VIDEO] ) {
00650
00651 pkt->dts = (((NSVStream*)st[NSV_ST_VIDEO]->priv_data)->frame_offset-1);
00652 pkt->dts *= (int64_t)1000 * nsv->framerate.den;
00653 pkt->dts += (int64_t)nsv->avsync * nsv->framerate.num;
00654 av_dlog(s, "NSV AUDIO: sync:%d, dts:%"PRId64, nsv->avsync, pkt->dts);
00655 }
00656 nst->frame_offset++;
00657 }
00658
00659 nsv->state = NSV_UNSYNC;
00660 return 0;
00661 }
00662
00663
00664 static int nsv_read_packet(AVFormatContext *s, AVPacket *pkt)
00665 {
00666 NSVContext *nsv = s->priv_data;
00667 int i, err = 0;
00668
00669 av_dlog(s, "%s()\n", __FUNCTION__);
00670
00671
00672 if (nsv->ahead[0].data == NULL && nsv->ahead[1].data == NULL)
00673 err = nsv_read_chunk(s, 0);
00674 if (err < 0)
00675 return err;
00676
00677
00678 for (i = 0; i < 2; i++) {
00679 if (nsv->ahead[i].data) {
00680 av_dlog(s, "%s: using cached packet[%d]\n", __FUNCTION__, i);
00681
00682 memcpy(pkt, &nsv->ahead[i], sizeof(AVPacket));
00683 nsv->ahead[i].data = NULL;
00684 return pkt->size;
00685 }
00686 }
00687
00688
00689 return -1;
00690 }
00691
00692 static int nsv_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
00693 {
00694 NSVContext *nsv = s->priv_data;
00695 AVStream *st = s->streams[stream_index];
00696 NSVStream *nst = st->priv_data;
00697 int index;
00698
00699 index = av_index_search_timestamp(st, timestamp, flags);
00700 if(index < 0)
00701 return -1;
00702
00703 avio_seek(s->pb, st->index_entries[index].pos, SEEK_SET);
00704 nst->frame_offset = st->index_entries[index].timestamp;
00705 nsv->state = NSV_UNSYNC;
00706 return 0;
00707 }
00708
00709 static int nsv_read_close(AVFormatContext *s)
00710 {
00711
00712 NSVContext *nsv = s->priv_data;
00713
00714 av_freep(&nsv->nsvs_file_offset);
00715 av_freep(&nsv->nsvs_timestamps);
00716 if (nsv->ahead[0].data)
00717 av_free_packet(&nsv->ahead[0]);
00718 if (nsv->ahead[1].data)
00719 av_free_packet(&nsv->ahead[1]);
00720
00721 #if 0
00722
00723 for(i=0;i<s->nb_streams;i++) {
00724 AVStream *st = s->streams[i];
00725 NSVStream *ast = st->priv_data;
00726 if(ast){
00727 av_free(ast->index_entries);
00728 av_free(ast);
00729 }
00730 av_free(st->codec->palctrl);
00731 }
00732
00733 #endif
00734 return 0;
00735 }
00736
00737 static int nsv_probe(AVProbeData *p)
00738 {
00739 int i;
00740 av_dlog(NULL, "nsv_probe(), buf_size %d\n", p->buf_size);
00741
00742
00743 if (p->buf[0] == 'N' && p->buf[1] == 'S' &&
00744 p->buf[2] == 'V' && (p->buf[3] == 'f' || p->buf[3] == 's'))
00745 return AVPROBE_SCORE_MAX;
00746
00747
00748
00749
00750 for (i = 1; i < p->buf_size - 3; i++) {
00751 if (p->buf[i+0] == 'N' && p->buf[i+1] == 'S' &&
00752 p->buf[i+2] == 'V' && p->buf[i+3] == 's')
00753 return AVPROBE_SCORE_MAX-20;
00754 }
00755
00756 if (av_match_ext(p->filename, "nsv"))
00757 return AVPROBE_SCORE_MAX/2;
00758
00759 return 0;
00760 }
00761
00762 AVInputFormat ff_nsv_demuxer = {
00763 "nsv",
00764 NULL_IF_CONFIG_SMALL("Nullsoft Streaming Video"),
00765 sizeof(NSVContext),
00766 nsv_probe,
00767 nsv_read_header,
00768 nsv_read_packet,
00769 nsv_read_close,
00770 nsv_read_seek,
00771 };