diff options
Diffstat (limited to 'Src/nsv/nsvlib.h')
-rw-r--r-- | Src/nsv/nsvlib.h | 364 |
1 files changed, 364 insertions, 0 deletions
diff --git a/Src/nsv/nsvlib.h b/Src/nsv/nsvlib.h new file mode 100644 index 00000000..b773d996 --- /dev/null +++ b/Src/nsv/nsvlib.h @@ -0,0 +1,364 @@ +/* +** nsvlib.h - NSV file/bitstream reading/writing interface +** +** Copyright (C) 2001-2002 Nullsoft, Inc. +** +** Confidential Subject to NDA +*/ + +#ifndef _NSVLIB_H_ +#define _NSVLIB_H_ + +/********************************************************************* +** bitstream classes +*/ + +#include "nsvbs.h" + + +/********************************************************************* +** NSV packeting limits +*/ +#define NSV_MAX_AUDIO_LEN 0x8000 // 32kb +#define NSV_MAX_VIDEO_LEN 0x80000 // 512kb +#define NSV_MAX_AUX_LEN 0x8000 // 32kb for each aux stream +#define NSV_MAX_AUXSTREAMS 15 // 15 aux streams maximum + + +/********************************************************************* +** Constants for setting certain metadata items using addHdrMetaData() +*/ +#define METADATANAME_AUTHOR "Author" +#define METADATANAME_TITLE "Title" +#define METADATANAME_COPYRIGHT "Copyright" +#define METADATANAME_COMMENT "Comment" +#define METADATANAME_PROFILE "Profile" +#define METADATANAME_FILEID "File ID" + +/********************************************************************* +** NSV type utility functions/macros +*/ + +/* +** Use NSV_MAKETYPE() to quickly make NSV audio/video/aux types. +** ex: NSV_MAKETYPE('R','G','B','A') +*/ +#define NSV_MAKETYPE(A,B,C,D) ((A) | ((B)<<8) | ((C)<<16) | ((D)<<24)) + +/* +** These functions convert types to and from strings. +*/ + +/* nsv_type_to_string() converts an NSV type to a string. + * out must be at least 5 bytes long. If 't' is not a valid type, + * then out will be set to an empty string + * ex: + * char out[5]; + * nsv_type_to_string(NSV_MAKETYPE('R','G','B','A'),out); + * strcmp(out,"RGBA") == 0 + */ +void nsv_type_to_string(unsigned int t, char *out); + +/* nsv_string_to_type() converts a string to an NSV type. + * Returns 0 if the type is not valid. + * ex: nsv_string_to_type("RGBA") == NSV_MAKETYPE('R','G','B','A') + */ +unsigned int nsv_string_to_type(char *in); + + +/********************************************************************* +** NSV bitstream packeting/unpacketing classes +*/ + + +/* nsv_Packeter is used to packet audio/video/auxiliary data into + * a bitstream. + * + * ex: + * nsv_Packeter p; + * nsv_OutBS bs; + * p.setVidFmt(NSV_MAKETYPE('R','G','B','A'),320,240,30.0); + * p.setAudFmt(NSV_MAKETYPE('P','C','M',' ')); + * for (;;) { + * doEncodeAudioAndVideo(); + * p.setSyncFrame(is_keyframe); + * p.setSyncOffset(av_sync_offset); + * p.setAudio(audio_data,audio_len); + * p.setVideo(video_data,video_len); + * p.clearAuxChannels(); // you can add aux channels if you want + * if (p.packet(bs)) error(); + * int outbuflen; + * void *outbuf=bs.get(&outbuflen); + * fwrite(outbuf,outbuflen,1,fp); // write output + * bs.clear(); // clear bitstream + * } + * + */ + +class nsv_Packeter { + public: + nsv_Packeter(); + ~nsv_Packeter(); + + // init (per file) calls + void setVidFmt(unsigned int vfmt, unsigned int w, unsigned int h, double frt); + void setAudFmt(unsigned int afmt) { audfmt=afmt; } + + // per frame calls + void setSyncFrame(int is_syncframe) { is_sync_frame=is_syncframe; } + void setSyncOffset(int syncoffs) { syncoffset_cur=syncoffs; } + void setAudio(void *a, int a_len) { audio=a; audio_len=a_len; } + void setVideo(void *v, int v_len) { video=v; video_len=v_len; } + int addAuxChannel(unsigned int fmt, void *data, int data_len) // 0 on success + { + if (aux_used >= NSV_MAX_AUXSTREAMS) return -1; + aux[aux_used]=data; + aux_len[aux_used]=data_len; + aux_types[aux_used]=fmt; + aux_used++; + return 0; + } + void clearAuxChannels() { aux_used=0; } + + int packet(nsv_OutBS &bs); // returns 0 on success + + // some utility getting functions + unsigned int getAudFmt() { return audfmt; } + unsigned int getVidFmt() { return vidfmt; } + unsigned int getWidth() { return width; } + unsigned int getHeight() { return height; } + double getFrameRate() { return framerate; } + + private: + unsigned char framerate_idx; + unsigned int vidfmt; + unsigned int audfmt; + unsigned int width; + unsigned int height; + double framerate; + int syncoffset_cur; + + int aux_used; + void *aux[NSV_MAX_AUXSTREAMS]; + int aux_len[NSV_MAX_AUXSTREAMS]; + unsigned int aux_types[NSV_MAX_AUXSTREAMS]; + int is_sync_frame; + void *audio; + int audio_len; + void *video; + int video_len; +}; + + +/* nsv_Unpacketer is used to unpacket a bitstream into audio/video/auxiliary data + * to decode, use an nsv_InBS object with data, and call unpacket(). + * ex: + * nsv_Unpacketer up; + * nsv_InBS in; + * nsv_InBS videoout, audioout; + * up.setVideoOut(&videoout); + * up.setAudioOut(&audioout); + * for (;;) { + * int ret=up.unpacket(in); + * if (ret < 0) break; // eof + * if (ret > 0) add_data_to_bitstream(&in,ret); + * if (!ret) { // got frame + * int vl=videoout.getbits(32); + * int al=videoout.getbits(32); + * char *vd=(char*)videoout.getcurbyteptr(); + * char *ad=(char*)audioout.getcurbyteptr(); + * doDecode(vd,vl,ad,al); + * videoout.seek(vl*8); + * audioout.seek(al*8); + * videoout.compact(); // free memory up + * audioout.compact(); // free memory up + * in.compact(); // free memory up + * } + * } + */ + +class nsv_Unpacketer { + public: + nsv_Unpacketer() { reset(); } + ~nsv_Unpacketer() { } + + void reset(int full=1); // if full, full reset is done. + // if not, then it is a partial reset (ie for seeking) + + // when EOF is set, the unpacketer will fail instead of requesting more data at the + // end; it will also not require that the next frame be available for sync + // (normally it looks ahead to verify data) + void setEof(int eof=1) { m_eof=eof; } + int getEof() { return m_eof; } + + // use these to set where the unpacketer writes the output of each stream + // set to NULL to ignore output of that stream + + void setAudioOut(nsv_InBS *output=NULL) { m_audiobs=output; } + // the format of the audio data written to the output is: + // 32 bits: length of frame + // ? bytes: audio data + // (to read): + // int l=output->getbits(32); + // decode_audio(output->getcurbyteptr(),l); + // output->seek(l*8); + + + void setVideoOut(nsv_InBS *output=NULL) { m_videobs=output; } + // the format of the video data written to the output is: + // 32 bits: length of frame + // ? bytes: video data + // (to read): + // int l=output->getbits(32); + // decode_video(output->getcurbyteptr(),l); + // output->seek(l*8); + + void setAuxOut(nsv_InBS *output=NULL) { m_auxbs=output; } + // the format of the aux data written to the output is: + // 32 bits: length of frame + // 32 bits: type of aux data + // ? bytes: aux data + // (to read): + // int l=output->getbits(32); + // int type=output->getbits(32); + // decode_aux(output->getcurbyteptr(),l); + // output->seek(l*8); + // aux is different than audio/video in that it includes a 32 bit + // type value that is not included in the length. + + + // returns 0 on success, >0 on needs (at least X bytes) more data, + // -1 on error (eof and no header found) + int unpacket(nsv_InBS &bs); + + + // do we have enough sync to determine formats/widths/heights/framerates + int isValid() { return valid; } + + // are we fully synched? + int isSynched() { return synched; } + + // get sync offset from when we first synched up + signed int getSyncOffset() { return (signed int) syncoffset; } + + // get sync offset from current frame (not usually used) + signed int getCurSyncOffset() { return (signed int) syncoffset_cur; } + + // get video, audio, width, height, framerate formats. + unsigned int getVidFmt() { return vidfmt; } + unsigned int getAudFmt() { return audfmt; } + unsigned int getWidth() { return width; } + unsigned int getHeight() { return height; } + double getFrameRate() { return framerate; } + unsigned char getFrameRateIdx() { return framerate_idx; } + + // is current frame a sync frame? + int isSynchFrame() { return is_sync_frame; } + + private: + nsv_InBS *m_audiobs, *m_videobs, *m_auxbs; + int valid; // contents of stream info are valid for syncing + int synched; // turns off anal packet checking + unsigned int vidfmt; + unsigned int audfmt; + unsigned int width; + unsigned int height; + double framerate; + int is_sync_frame; + unsigned char framerate_idx; + int syncoffset; + int syncoffset_cur; + + int m_eof; +}; + + +/********************************************************************* +** NSV file header reading/writing functions +*/ + + +typedef struct { + // header_size is the size of NSV header. nsv_writeheader() and nsv_readheader() + // will set this automatically + unsigned int header_size; + + // file_lenbytes is the size of the NSV bitstream (not including the header size) + // this can be 0xFFFFFFFF to signify unknown length + unsigned int file_lenbytes; + + // file_lenms is the length of the NSV bitstream in milliseconds. + // this can be 0xFFFFFFFF to signify unknown length + unsigned int file_lenms; + + // metadata_len describes the length of the metadata. + unsigned int metadata_len; + + // toc_alloc describes the allocated length of the TOC (in entries). + // set this to zero to use toc_size (recommended). + unsigned int toc_alloc; + + // toc_size describes the used size of the TOC (in entries) + // set this to zero to disable the TOC. When using toc_ex, + // this must be < toc_alloc/2 (if using nsv_writeheader, and + // toc_size is too big, toc_alloc will be grown automatically. + unsigned int toc_size; + + // buffer which contains the TOC. this will be automatically + // allocated when using nsv_readheader(), but you should allocate + // this yourself when using nsv_writeheader() + unsigned int *toc; + + // if used, contains time pairs (in frames) for the offset. this will be + // automatically allocated when using nsv_readheader(), but you should allocate + // this yourself when using nsv_writeheader() + // DO NOT FREE THIS VALUE IF IT WAS ALLOCATED FROM NSV_READHEADER. :) + // (it is just an extension of toc, which should be freed with free()) + unsigned int *toc_ex; + + // buffer which contains metadata. allocated when using nsv_readheader(), + // but you should allocate this yourself when using nsv_writeheader() + // note that nsv_readheader() will NULL terminate this buffer. + void *metadata; + +} nsv_fileHeader; + +// nsv_writeheader() writes the NSV file header to the bitstream bs. +// the NSV file header will be at LEAST padto bytes long (usually +// you will leave padto to 0) +void nsv_writeheader(nsv_OutBS &bs, nsv_fileHeader *hdr, unsigned int padto); + +// nsv_readheader() reads an NSV file header from a bitstream bs. +// if the return value is less than zero, then there is no NSV +// file header in bs. if the return value is zero, the NSV file +// header was succesfully read. if the return value is positive, +// then at least that many more bytes are needed to decode the +// header. +// ex: +// nsv_InBS bs; +// nsv_fileHeader hdr; +// for (;;) { +// int ret=nsv_readheader(bs,&hdr); +// if (ret<=0) break; +// addBytesToBs(bs,ret); +// } +// if (hdr.header_size) { we_got_valid_header(&hdr); } +// + +int nsv_readheader(nsv_InBS &bs, nsv_fileHeader *hdr); + + +// nsv_getmetadata() retrieves a metadata item from the metadata +// block. if that item is not found, NULL is returned. +// Note that the value returned by nsv_getmetadata() has been +// malloc()'d, and you must free() it when you are done. +// ex: +// char *v=nsv_getmetadata(hdr.metadata,"TITLE"); +// if (v) printf("title=%s\n",v); +// free(v); +// + +char *nsv_getmetadata(void *metadata, char *name); + + +#endif//_NSVLIB_H_ |