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 #include "libavutil/dict.h"
00024 #include "libavutil/intreadwrite.h"
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 av_unused file_size;
00271 unsigned int size;
00272 int64_t duration;
00273 int strings_size;
00274 int table_entries;
00275 int table_entries_used;
00276
00277 av_dlog(s, "%s()\n", __FUNCTION__);
00278
00279 nsv->state = NSV_UNSYNC;
00280
00281 size = avio_rl32(pb);
00282 if (size < 28)
00283 return -1;
00284 nsv->NSVf_end = size;
00285
00286
00287 file_size = (uint32_t)avio_rl32(pb);
00288 av_dlog(s, "NSV NSVf chunk_size %u\n", size);
00289 av_dlog(s, "NSV NSVf file_size %u\n", file_size);
00290
00291 nsv->duration = duration = avio_rl32(pb);
00292 av_dlog(s, "NSV NSVf duration %"PRId64" ms\n", duration);
00293
00294
00295 strings_size = avio_rl32(pb);
00296 table_entries = avio_rl32(pb);
00297 table_entries_used = avio_rl32(pb);
00298 av_dlog(s, "NSV NSVf info-strings size: %d, table entries: %d, bis %d\n",
00299 strings_size, table_entries, table_entries_used);
00300 if (url_feof(pb))
00301 return -1;
00302
00303 av_dlog(s, "NSV got header; filepos %"PRId64"\n", avio_tell(pb));
00304
00305 if (strings_size > 0) {
00306 char *strings;
00307 char *p, *endp;
00308 char *token, *value;
00309 char quote;
00310
00311 p = strings = av_mallocz((size_t)strings_size + 1);
00312 if (!p)
00313 return AVERROR(ENOMEM);
00314 endp = strings + strings_size;
00315 avio_read(pb, strings, strings_size);
00316 while (p < endp) {
00317 while (*p == ' ')
00318 p++;
00319 if (p >= endp-2)
00320 break;
00321 token = p;
00322 p = strchr(p, '=');
00323 if (!p || p >= endp-2)
00324 break;
00325 *p++ = '\0';
00326 quote = *p++;
00327 value = p;
00328 p = strchr(p, quote);
00329 if (!p || p >= endp)
00330 break;
00331 *p++ = '\0';
00332 av_dlog(s, "NSV NSVf INFO: %s='%s'\n", token, value);
00333 av_dict_set(&s->metadata, token, value, 0);
00334 }
00335 av_free(strings);
00336 }
00337 if (url_feof(pb))
00338 return -1;
00339
00340 av_dlog(s, "NSV got infos; filepos %"PRId64"\n", avio_tell(pb));
00341
00342 if (table_entries_used > 0) {
00343 int i;
00344 nsv->index_entries = table_entries_used;
00345 if((unsigned)table_entries_used >= UINT_MAX / sizeof(uint32_t))
00346 return -1;
00347 nsv->nsvs_file_offset = av_malloc((unsigned)table_entries_used * sizeof(uint32_t));
00348 if (!nsv->nsvs_file_offset)
00349 return AVERROR(ENOMEM);
00350
00351 for(i=0;i<table_entries_used;i++)
00352 nsv->nsvs_file_offset[i] = avio_rl32(pb) + size;
00353
00354 if(table_entries > table_entries_used &&
00355 avio_rl32(pb) == MKTAG('T','O','C','2')) {
00356 nsv->nsvs_timestamps = av_malloc((unsigned)table_entries_used*sizeof(uint32_t));
00357 if (!nsv->nsvs_timestamps)
00358 return AVERROR(ENOMEM);
00359 for(i=0;i<table_entries_used;i++) {
00360 nsv->nsvs_timestamps[i] = avio_rl32(pb);
00361 }
00362 }
00363 }
00364
00365 av_dlog(s, "NSV got index; filepos %"PRId64"\n", avio_tell(pb));
00366
00367 #ifdef DEBUG_DUMP_INDEX
00368 #define V(v) ((v<0x20 || v > 127)?'.':v)
00369
00370 av_dlog(s, "NSV %d INDEX ENTRIES:\n", table_entries);
00371 av_dlog(s, "NSV [dataoffset][fileoffset]\n", table_entries);
00372 for (i = 0; i < table_entries; i++) {
00373 unsigned char b[8];
00374 avio_seek(pb, size + nsv->nsvs_file_offset[i], SEEK_SET);
00375 avio_read(pb, b, 8);
00376 av_dlog(s, "NSV [0x%08lx][0x%08lx]: %02x %02x %02x %02x %02x %02x %02x %02x"
00377 "%c%c%c%c%c%c%c%c\n",
00378 nsv->nsvs_file_offset[i], size + nsv->nsvs_file_offset[i],
00379 b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7],
00380 V(b[0]), V(b[1]), V(b[2]), V(b[3]), V(b[4]), V(b[5]), V(b[6]), V(b[7]) );
00381 }
00382
00383 #undef V
00384 #endif
00385
00386 avio_seek(pb, nsv->base_offset + size, SEEK_SET);
00387
00388 if (url_feof(pb))
00389 return -1;
00390 nsv->state = NSV_HAS_READ_NSVF;
00391 return 0;
00392 }
00393
00394 static int nsv_parse_NSVs_header(AVFormatContext *s, AVFormatParameters *ap)
00395 {
00396 NSVContext *nsv = s->priv_data;
00397 AVIOContext *pb = s->pb;
00398 uint32_t vtag, atag;
00399 uint16_t vwidth, vheight;
00400 AVRational framerate;
00401 int i;
00402 AVStream *st;
00403 NSVStream *nst;
00404 av_dlog(s, "%s()\n", __FUNCTION__);
00405
00406 vtag = avio_rl32(pb);
00407 atag = avio_rl32(pb);
00408 vwidth = avio_rl16(pb);
00409 vheight = avio_rl16(pb);
00410 i = avio_r8(pb);
00411
00412 av_dlog(s, "NSV NSVs framerate code %2x\n", i);
00413 if(i&0x80) {
00414 int t=(i & 0x7F)>>2;
00415 if(t<16) framerate = (AVRational){1, t+1};
00416 else framerate = (AVRational){t-15, 1};
00417
00418 if(i&1){
00419 framerate.num *= 1000;
00420 framerate.den *= 1001;
00421 }
00422
00423 if((i&3)==3) framerate.num *= 24;
00424 else if((i&3)==2) framerate.num *= 25;
00425 else framerate.num *= 30;
00426 }
00427 else
00428 framerate= (AVRational){i, 1};
00429
00430 nsv->avsync = avio_rl16(pb);
00431 nsv->framerate = framerate;
00432
00433 print_tag("NSV NSVs vtag", vtag, 0);
00434 print_tag("NSV NSVs atag", atag, 0);
00435 av_dlog(s, "NSV NSVs vsize %dx%d\n", vwidth, vheight);
00436
00437
00438 if (s->nb_streams == 0) {
00439 nsv->vtag = vtag;
00440 nsv->atag = atag;
00441 nsv->vwidth = vwidth;
00442 nsv->vheight = vwidth;
00443 if (vtag != T_NONE) {
00444 int i;
00445 st = av_new_stream(s, NSV_ST_VIDEO);
00446 if (!st)
00447 goto fail;
00448
00449 nst = av_mallocz(sizeof(NSVStream));
00450 if (!nst)
00451 goto fail;
00452 st->priv_data = nst;
00453 st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
00454 st->codec->codec_tag = vtag;
00455 st->codec->codec_id = ff_codec_get_id(nsv_codec_video_tags, vtag);
00456 st->codec->width = vwidth;
00457 st->codec->height = vheight;
00458 st->codec->bits_per_coded_sample = 24;
00459
00460 av_set_pts_info(st, 64, framerate.den, framerate.num);
00461 st->start_time = 0;
00462 st->duration = av_rescale(nsv->duration, framerate.num, 1000*framerate.den);
00463
00464 for(i=0;i<nsv->index_entries;i++) {
00465 if(nsv->nsvs_timestamps) {
00466 av_add_index_entry(st, nsv->nsvs_file_offset[i], nsv->nsvs_timestamps[i],
00467 0, 0, AVINDEX_KEYFRAME);
00468 } else {
00469 int64_t ts = av_rescale(i*nsv->duration/nsv->index_entries, framerate.num, 1000*framerate.den);
00470 av_add_index_entry(st, nsv->nsvs_file_offset[i], ts, 0, 0, AVINDEX_KEYFRAME);
00471 }
00472 }
00473 }
00474 if (atag != T_NONE) {
00475 #ifndef DISABLE_AUDIO
00476 st = av_new_stream(s, NSV_ST_AUDIO);
00477 if (!st)
00478 goto fail;
00479
00480 nst = av_mallocz(sizeof(NSVStream));
00481 if (!nst)
00482 goto fail;
00483 st->priv_data = nst;
00484 st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
00485 st->codec->codec_tag = atag;
00486 st->codec->codec_id = ff_codec_get_id(nsv_codec_audio_tags, atag);
00487
00488 st->need_parsing = AVSTREAM_PARSE_FULL;
00489
00490
00491 av_set_pts_info(st, 64, 1, framerate.num*1000);
00492 st->start_time = 0;
00493 st->duration = (int64_t)nsv->duration * framerate.num;
00494 #endif
00495 }
00496 #ifdef CHECK_SUBSEQUENT_NSVS
00497 } else {
00498 if (nsv->vtag != vtag || nsv->atag != atag || nsv->vwidth != vwidth || nsv->vheight != vwidth) {
00499 av_dlog(s, "NSV NSVs header values differ from the first one!!!\n");
00500
00501 }
00502 #endif
00503 }
00504
00505 nsv->state = NSV_HAS_READ_NSVS;
00506 return 0;
00507 fail:
00508
00509 nsv->state = NSV_UNSYNC;
00510 return -1;
00511 }
00512
00513 static int nsv_read_header(AVFormatContext *s, AVFormatParameters *ap)
00514 {
00515 NSVContext *nsv = s->priv_data;
00516 int i, err;
00517
00518 av_dlog(s, "%s()\n", __FUNCTION__);
00519 av_dlog(s, "filename '%s'\n", s->filename);
00520
00521 nsv->state = NSV_UNSYNC;
00522 nsv->ahead[0].data = nsv->ahead[1].data = NULL;
00523
00524 for (i = 0; i < NSV_MAX_RESYNC_TRIES; i++) {
00525 if (nsv_resync(s) < 0)
00526 return -1;
00527 if (nsv->state == NSV_FOUND_NSVF) {
00528 err = nsv_parse_NSVf_header(s, ap);
00529 if (err < 0)
00530 return err;
00531 }
00532
00533 if (nsv->state == NSV_FOUND_NSVS) {
00534 err = nsv_parse_NSVs_header(s, ap);
00535 if (err < 0)
00536 return err;
00537 break;
00538 }
00539 }
00540 if (s->nb_streams < 1)
00541 return -1;
00542
00543 err = nsv_read_chunk(s, 1);
00544
00545 av_dlog(s, "parsed header\n");
00546 return err;
00547 }
00548
00549 static int nsv_read_chunk(AVFormatContext *s, int fill_header)
00550 {
00551 NSVContext *nsv = s->priv_data;
00552 AVIOContext *pb = s->pb;
00553 AVStream *st[2] = {NULL, NULL};
00554 NSVStream *nst;
00555 AVPacket *pkt;
00556 int i, err = 0;
00557 uint8_t auxcount;
00558 uint32_t vsize;
00559 uint16_t asize;
00560 uint16_t auxsize;
00561 uint32_t av_unused auxtag;
00562
00563 av_dlog(s, "%s(%d)\n", __FUNCTION__, fill_header);
00564
00565 if (nsv->ahead[0].data || nsv->ahead[1].data)
00566 return 0;
00567
00568 null_chunk_retry:
00569 if (url_feof(pb))
00570 return -1;
00571
00572 for (i = 0; i < NSV_MAX_RESYNC_TRIES && nsv->state < NSV_FOUND_NSVS && !err; i++)
00573 err = nsv_resync(s);
00574 if (err < 0)
00575 return err;
00576 if (nsv->state == NSV_FOUND_NSVS)
00577 err = nsv_parse_NSVs_header(s, NULL);
00578 if (err < 0)
00579 return err;
00580 if (nsv->state != NSV_HAS_READ_NSVS && nsv->state != NSV_FOUND_BEEF)
00581 return -1;
00582
00583 auxcount = avio_r8(pb);
00584 vsize = avio_rl16(pb);
00585 asize = avio_rl16(pb);
00586 vsize = (vsize << 4) | (auxcount >> 4);
00587 auxcount &= 0x0f;
00588 av_dlog(s, "NSV CHUNK %d aux, %u bytes video, %d bytes audio\n", auxcount, vsize, asize);
00589
00590 for (i = 0; i < auxcount; i++) {
00591 auxsize = avio_rl16(pb);
00592 auxtag = avio_rl32(pb);
00593 av_dlog(s, "NSV aux data: '%c%c%c%c', %d bytes\n",
00594 (auxtag & 0x0ff),
00595 ((auxtag >> 8) & 0x0ff),
00596 ((auxtag >> 16) & 0x0ff),
00597 ((auxtag >> 24) & 0x0ff),
00598 auxsize);
00599 avio_skip(pb, auxsize);
00600 vsize -= auxsize + sizeof(uint16_t) + sizeof(uint32_t);
00601 }
00602
00603 if (url_feof(pb))
00604 return -1;
00605 if (!vsize && !asize) {
00606 nsv->state = NSV_UNSYNC;
00607 goto null_chunk_retry;
00608 }
00609
00610
00611 if (s->nb_streams > 0)
00612 st[s->streams[0]->id] = s->streams[0];
00613 if (s->nb_streams > 1)
00614 st[s->streams[1]->id] = s->streams[1];
00615
00616 if (vsize && st[NSV_ST_VIDEO]) {
00617 nst = st[NSV_ST_VIDEO]->priv_data;
00618 pkt = &nsv->ahead[NSV_ST_VIDEO];
00619 av_get_packet(pb, pkt, vsize);
00620 pkt->stream_index = st[NSV_ST_VIDEO]->index;
00621 pkt->dts = nst->frame_offset;
00622 pkt->flags |= nsv->state == NSV_HAS_READ_NSVS ? AV_PKT_FLAG_KEY : 0;
00623 for (i = 0; i < FFMIN(8, vsize); i++)
00624 av_dlog(s, "NSV video: [%d] = %02x\n", i, pkt->data[i]);
00625 }
00626 if(st[NSV_ST_VIDEO])
00627 ((NSVStream*)st[NSV_ST_VIDEO]->priv_data)->frame_offset++;
00628
00629 if (asize && st[NSV_ST_AUDIO]) {
00630 nst = st[NSV_ST_AUDIO]->priv_data;
00631 pkt = &nsv->ahead[NSV_ST_AUDIO];
00632
00633
00634 if (asize && st[NSV_ST_AUDIO]->codec->codec_tag == MKTAG('P', 'C', 'M', ' ')) {
00635 uint8_t bps;
00636 uint8_t channels;
00637 uint16_t samplerate;
00638 bps = avio_r8(pb);
00639 channels = avio_r8(pb);
00640 samplerate = avio_rl16(pb);
00641 asize-=4;
00642 av_dlog(s, "NSV RAWAUDIO: bps %d, nchan %d, srate %d\n", bps, channels, samplerate);
00643 if (fill_header) {
00644 st[NSV_ST_AUDIO]->need_parsing = AVSTREAM_PARSE_NONE;
00645 if (bps != 16) {
00646 av_dlog(s, "NSV AUDIO bit/sample != 16 (%d)!!!\n", bps);
00647 }
00648 bps /= channels;
00649 if (bps == 8)
00650 st[NSV_ST_AUDIO]->codec->codec_id = CODEC_ID_PCM_U8;
00651 samplerate /= 4;
00652 channels = 1;
00653 st[NSV_ST_AUDIO]->codec->channels = channels;
00654 st[NSV_ST_AUDIO]->codec->sample_rate = samplerate;
00655 av_dlog(s, "NSV RAWAUDIO: bps %d, nchan %d, srate %d\n", bps, channels, samplerate);
00656 }
00657 }
00658 av_get_packet(pb, pkt, asize);
00659 pkt->stream_index = st[NSV_ST_AUDIO]->index;
00660 pkt->flags |= nsv->state == NSV_HAS_READ_NSVS ? AV_PKT_FLAG_KEY : 0;
00661 if( nsv->state == NSV_HAS_READ_NSVS && st[NSV_ST_VIDEO] ) {
00662
00663 pkt->dts = (((NSVStream*)st[NSV_ST_VIDEO]->priv_data)->frame_offset-1);
00664 pkt->dts *= (int64_t)1000 * nsv->framerate.den;
00665 pkt->dts += (int64_t)nsv->avsync * nsv->framerate.num;
00666 av_dlog(s, "NSV AUDIO: sync:%d, dts:%"PRId64, nsv->avsync, pkt->dts);
00667 }
00668 nst->frame_offset++;
00669 }
00670
00671 nsv->state = NSV_UNSYNC;
00672 return 0;
00673 }
00674
00675
00676 static int nsv_read_packet(AVFormatContext *s, AVPacket *pkt)
00677 {
00678 NSVContext *nsv = s->priv_data;
00679 int i, err = 0;
00680
00681 av_dlog(s, "%s()\n", __FUNCTION__);
00682
00683
00684 if (nsv->ahead[0].data == NULL && nsv->ahead[1].data == NULL)
00685 err = nsv_read_chunk(s, 0);
00686 if (err < 0)
00687 return err;
00688
00689
00690 for (i = 0; i < 2; i++) {
00691 if (nsv->ahead[i].data) {
00692 av_dlog(s, "%s: using cached packet[%d]\n", __FUNCTION__, i);
00693
00694 memcpy(pkt, &nsv->ahead[i], sizeof(AVPacket));
00695 nsv->ahead[i].data = NULL;
00696 return pkt->size;
00697 }
00698 }
00699
00700
00701 return -1;
00702 }
00703
00704 static int nsv_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
00705 {
00706 NSVContext *nsv = s->priv_data;
00707 AVStream *st = s->streams[stream_index];
00708 NSVStream *nst = st->priv_data;
00709 int index;
00710
00711 index = av_index_search_timestamp(st, timestamp, flags);
00712 if(index < 0)
00713 return -1;
00714
00715 avio_seek(s->pb, st->index_entries[index].pos, SEEK_SET);
00716 nst->frame_offset = st->index_entries[index].timestamp;
00717 nsv->state = NSV_UNSYNC;
00718 return 0;
00719 }
00720
00721 static int nsv_read_close(AVFormatContext *s)
00722 {
00723
00724 NSVContext *nsv = s->priv_data;
00725
00726 av_freep(&nsv->nsvs_file_offset);
00727 av_freep(&nsv->nsvs_timestamps);
00728 if (nsv->ahead[0].data)
00729 av_free_packet(&nsv->ahead[0]);
00730 if (nsv->ahead[1].data)
00731 av_free_packet(&nsv->ahead[1]);
00732
00733 #if 0
00734
00735 for(i=0;i<s->nb_streams;i++) {
00736 AVStream *st = s->streams[i];
00737 NSVStream *ast = st->priv_data;
00738 if(ast){
00739 av_free(ast->index_entries);
00740 av_free(ast);
00741 }
00742 av_free(st->codec->palctrl);
00743 }
00744
00745 #endif
00746 return 0;
00747 }
00748
00749 static int nsv_probe(AVProbeData *p)
00750 {
00751 int i, score = 0;
00752
00753 av_dlog(NULL, "nsv_probe(), buf_size %d\n", p->buf_size);
00754
00755
00756 if (p->buf[0] == 'N' && p->buf[1] == 'S' &&
00757 p->buf[2] == 'V' && (p->buf[3] == 'f' || p->buf[3] == 's'))
00758 return AVPROBE_SCORE_MAX;
00759
00760
00761
00762
00763 for (i = 1; i < p->buf_size - 3; i++) {
00764 if (AV_RL32(p->buf + i) == AV_RL32("NSVs")) {
00765
00766 int vsize = AV_RL24(p->buf+i+19) >> 4;
00767 int asize = AV_RL16(p->buf+i+22);
00768 int offset = i + 23 + asize + vsize + 1;
00769 if (offset <= p->buf_size - 2 && AV_RL16(p->buf + offset) == 0xBEEF)
00770 return 4*AVPROBE_SCORE_MAX/5;
00771 score = AVPROBE_SCORE_MAX/5;
00772 }
00773 }
00774
00775 if (av_match_ext(p->filename, "nsv"))
00776 return AVPROBE_SCORE_MAX/2;
00777
00778 return score;
00779 }
00780
00781 AVInputFormat ff_nsv_demuxer = {
00782 "nsv",
00783 NULL_IF_CONFIG_SMALL("Nullsoft Streaming Video"),
00784 sizeof(NSVContext),
00785 nsv_probe,
00786 nsv_read_header,
00787 nsv_read_packet,
00788 nsv_read_close,
00789 nsv_read_seek,
00790 };