winamp/Src/nsv/nsvlib.h

365 lines
12 KiB
C
Raw Permalink Normal View History

2024-09-24 13:54:57 +01:00
/*
** 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_