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