mirror of
https://github.com/WinampDesktop/winamp.git
synced 2024-09-24 15:54:12 +00:00
365 lines
12 KiB
C
365 lines
12 KiB
C
|
/*
|
||
|
** 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_
|