mirror of
https://github.com/DrBeef/ioq3quest.git
synced 2024-11-26 22:11:18 +00:00
Merge branch 'features/upgrade-opusfile-0.5' of https://github.com/xhairball/ioq3 into opus_update
This commit is contained in:
commit
166f5ab90c
12 changed files with 2841 additions and 1013 deletions
5
Makefile
5
Makefile
|
@ -242,7 +242,7 @@ JPDIR=$(MOUNT_DIR)/jpeg-8c
|
|||
SPEEXDIR=$(MOUNT_DIR)/libspeex
|
||||
OGGDIR=$(MOUNT_DIR)/libogg-1.3.1
|
||||
OPUSDIR=$(MOUNT_DIR)/opus-1.0.2
|
||||
OPUSFILEDIR=$(MOUNT_DIR)/opusfile-0.2
|
||||
OPUSFILEDIR=$(MOUNT_DIR)/opusfile-0.5
|
||||
ZDIR=$(MOUNT_DIR)/zlib
|
||||
Q3ASMDIR=$(MOUNT_DIR)/tools/asm
|
||||
LBURGDIR=$(MOUNT_DIR)/tools/lcc/lburg
|
||||
|
@ -1955,7 +1955,8 @@ Q3OBJ += \
|
|||
$(B)/client/info.o \
|
||||
$(B)/client/internal.o \
|
||||
$(B)/client/opusfile.o \
|
||||
$(B)/client/stream.o
|
||||
$(B)/client/stream.o \
|
||||
$(B)/client/wincerts.o
|
||||
endif
|
||||
endif
|
||||
|
||||
|
|
|
@ -1,286 +0,0 @@
|
|||
/********************************************************************
|
||||
* *
|
||||
* THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. *
|
||||
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||
* *
|
||||
* THE libopusfile SOURCE CODE IS (C) COPYRIGHT 2012 *
|
||||
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************/
|
||||
#include "internal.h"
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
|
||||
static unsigned op_parse_uint16le(const unsigned char *_data){
|
||||
return _data[0]|_data[1]<<8;
|
||||
}
|
||||
|
||||
static int op_parse_int16le(const unsigned char *_data){
|
||||
int ret;
|
||||
ret=_data[0]|_data[1]<<8;
|
||||
return (ret^0x8000)-0x8000;
|
||||
}
|
||||
|
||||
static opus_uint32 op_parse_uint32le(const unsigned char *_data){
|
||||
return _data[0]|_data[1]<<8|_data[2]<<16|_data[3]<<24;
|
||||
}
|
||||
|
||||
int opus_head_parse(OpusHead *_head,const unsigned char *_data,size_t _len){
|
||||
OpusHead head;
|
||||
if(_len<8)return OP_ENOTFORMAT;
|
||||
if(memcmp(_data,"OpusHead",8)!=0)return OP_ENOTFORMAT;
|
||||
if(_len<9)return OP_EBADHEADER;
|
||||
head.version=_data[8];
|
||||
if(head.version>15)return OP_EVERSION;
|
||||
if(_len<19)return OP_EBADHEADER;
|
||||
head.channel_count=_data[9];
|
||||
head.pre_skip=op_parse_uint16le(_data+10);
|
||||
head.input_sample_rate=op_parse_uint32le(_data+12);
|
||||
head.output_gain=op_parse_int16le(_data+16);
|
||||
head.mapping_family=_data[18];
|
||||
if(head.mapping_family==0){
|
||||
if(head.channel_count<1||head.channel_count>2)return OP_EBADHEADER;
|
||||
if(head.version<=1&&_len>19)return OP_EBADHEADER;
|
||||
head.stream_count=1;
|
||||
head.coupled_count=head.channel_count-1;
|
||||
if(_head!=NULL){
|
||||
_head->mapping[0]=0;
|
||||
_head->mapping[1]=1;
|
||||
}
|
||||
}
|
||||
else if(head.mapping_family==1){
|
||||
size_t size;
|
||||
int ci;
|
||||
if(head.channel_count<1||head.channel_count>8)return OP_EBADHEADER;
|
||||
size=21+head.channel_count;
|
||||
if(_len<size||head.version<=1&&_len>size)return OP_EBADHEADER;
|
||||
head.stream_count=_data[19];
|
||||
if(head.stream_count<1)return OP_EBADHEADER;
|
||||
head.coupled_count=_data[20];
|
||||
if(head.coupled_count>head.stream_count)return OP_EBADHEADER;
|
||||
for(ci=0;ci<head.channel_count;ci++){
|
||||
if(_data[21+ci]>=head.stream_count+head.coupled_count
|
||||
&&_data[21+ci]!=255){
|
||||
return OP_EBADHEADER;
|
||||
}
|
||||
}
|
||||
if(_head!=NULL)memcpy(_head->mapping,_data+21,head.channel_count);
|
||||
}
|
||||
/*General purpose players should not attempt to play back content with
|
||||
channel mapping family 255.*/
|
||||
else if(head.mapping_family==255)return OP_EIMPL;
|
||||
/*No other channel mapping families are currently defined.*/
|
||||
else return OP_EBADHEADER;
|
||||
if(_head!=NULL)memcpy(_head,&head,head.mapping-(unsigned char *)&head);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void opus_tags_init(OpusTags *_tags){
|
||||
memset(_tags,0,sizeof(*_tags));
|
||||
}
|
||||
|
||||
void opus_tags_clear(OpusTags *_tags){
|
||||
int i;
|
||||
for(i=_tags->comments;i-->0;)_ogg_free(_tags->user_comments[i]);
|
||||
_ogg_free(_tags->user_comments);
|
||||
_ogg_free(_tags->comment_lengths);
|
||||
_ogg_free(_tags->vendor);
|
||||
}
|
||||
|
||||
/*The actual implementation of opus_tags_parse().
|
||||
Unlike the public API, this function requires _tags to already be
|
||||
initialized, modifies its contents before success is guaranteed, and assumes
|
||||
the caller will clear it on error.*/
|
||||
int opus_tags_parse_impl(OpusTags *_tags,
|
||||
const unsigned char *_data,size_t _len){
|
||||
opus_uint32 count;
|
||||
size_t size;
|
||||
size_t len;
|
||||
int ncomments;
|
||||
int i;
|
||||
len=_len;
|
||||
if(len<8)return OP_ENOTFORMAT;
|
||||
if(memcmp(_data,"OpusTags",8)!=0)return OP_ENOTFORMAT;
|
||||
if(len<16)return OP_EBADHEADER;
|
||||
_data+=8;
|
||||
len-=8;
|
||||
count=op_parse_uint32le(_data);
|
||||
_data+=4;
|
||||
len-=4;
|
||||
if(count>len)return OP_EBADHEADER;
|
||||
if(_tags!=NULL){
|
||||
char *vendor;
|
||||
size=count+1;
|
||||
if(size<count)return OP_EFAULT;
|
||||
vendor=(char *)_ogg_malloc(size);
|
||||
if(vendor==NULL)return OP_EFAULT;
|
||||
memcpy(vendor,_data,count);
|
||||
vendor[count]='\0';
|
||||
_tags->vendor=vendor;
|
||||
}
|
||||
_data+=count;
|
||||
len-=count;
|
||||
if(len<4)return OP_EBADHEADER;
|
||||
count=op_parse_uint32le(_data);
|
||||
_data+=4;
|
||||
len-=4;
|
||||
/*Check to make sure there's minimally sufficient data left in the packet.*/
|
||||
if(count>len>>2)return OP_EBADHEADER;
|
||||
/*Check for overflow (the API limits this to an int).*/
|
||||
if(count>(opus_uint32)INT_MAX-1)return OP_EFAULT;
|
||||
if(_tags!=NULL){
|
||||
size=sizeof(*_tags->comment_lengths)*(count+1);
|
||||
if(size/sizeof(*_tags->comment_lengths)!=count+1)return OP_EFAULT;
|
||||
_tags->comment_lengths=(int *)_ogg_malloc(size);
|
||||
size=sizeof(*_tags->user_comments)*(count+1);
|
||||
if(size/sizeof(*_tags->user_comments)!=count+1)return OP_EFAULT;
|
||||
_tags->user_comments=(char **)_ogg_malloc(size);
|
||||
if(_tags->comment_lengths==NULL||_tags->user_comments==NULL){
|
||||
return OP_EFAULT;
|
||||
}
|
||||
}
|
||||
ncomments=(int)count;
|
||||
for(i=0;i<ncomments;i++){
|
||||
/*Check to make sure there's minimally sufficient data left in the packet.*/
|
||||
if((size_t)(ncomments-i)>len>>2)return OP_EBADHEADER;
|
||||
count=op_parse_uint32le(_data);
|
||||
_data+=4;
|
||||
len-=4;
|
||||
if(count>len)return OP_EBADHEADER;
|
||||
/*Check for overflow (the API limits this to an int).*/
|
||||
if(count>(opus_uint32)INT_MAX)return OP_EFAULT;
|
||||
if(_tags!=NULL){
|
||||
_tags->comment_lengths[i]=(int)count;
|
||||
size=count+1;
|
||||
if(size<count)return OP_EFAULT;
|
||||
_tags->user_comments[i]=(char *)_ogg_malloc(size);
|
||||
if(_tags->user_comments[i]==NULL)return OP_EFAULT;
|
||||
_tags->comments=i+1;
|
||||
memcpy(_tags->user_comments[i],_data,count);
|
||||
_tags->user_comments[i][count]='\0';
|
||||
}
|
||||
_data+=count;
|
||||
len-=count;
|
||||
}
|
||||
if(_tags!=NULL){
|
||||
_tags->user_comments[ncomments]=NULL;
|
||||
_tags->comment_lengths[ncomments]=0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int opus_tags_parse(OpusTags *_tags,const unsigned char *_data,size_t _len){
|
||||
if(_tags!=NULL){
|
||||
OpusTags tags;
|
||||
int ret;
|
||||
opus_tags_init(&tags);
|
||||
ret=opus_tags_parse_impl(&tags,_data,_len);
|
||||
if(ret<0)opus_tags_clear(&tags);
|
||||
else *_tags=*&tags;
|
||||
return ret;
|
||||
}
|
||||
else return opus_tags_parse_impl(NULL,_data,_len);
|
||||
}
|
||||
|
||||
/*Add room for a new comment.*/
|
||||
static int op_tags_add_prepare(OpusTags *_tags){
|
||||
char **user_comments;
|
||||
int *comment_lengths;
|
||||
int ncomments;
|
||||
ncomments=_tags->comments;
|
||||
user_comments=_ogg_realloc(_tags->user_comments,
|
||||
sizeof(*_tags->user_comments)*(ncomments+2));
|
||||
if(OP_UNLIKELY(user_comments==NULL))return OP_EFAULT;
|
||||
_tags->user_comments=user_comments;
|
||||
comment_lengths=_ogg_realloc(_tags->comment_lengths,
|
||||
sizeof(*_tags->comment_lengths)*(ncomments+2));
|
||||
if(OP_UNLIKELY(comment_lengths==NULL))return OP_EFAULT;
|
||||
_tags->comment_lengths=comment_lengths;
|
||||
comment_lengths[ncomments]=comment_lengths[ncomments+1]=0;
|
||||
/*Our caller will always set user_comments[ncomments].*/
|
||||
user_comments[ncomments+1]=NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int opus_tags_add(OpusTags *_tags,const char *_tag,const char *_value){
|
||||
char *comment;
|
||||
int tag_len;
|
||||
int value_len;
|
||||
int ncomments;
|
||||
int ret;
|
||||
ret=op_tags_add_prepare(_tags);
|
||||
if(OP_UNLIKELY(ret<0))return ret;
|
||||
tag_len=strlen(_tag);
|
||||
value_len=strlen(_value);
|
||||
ncomments=_tags->comments;
|
||||
/*+2 for '=' and '\0'.*/
|
||||
_tags->user_comments[ncomments]=comment=
|
||||
(char *)_ogg_malloc(sizeof(*comment)*(tag_len+value_len+2));
|
||||
if(OP_UNLIKELY(comment==NULL))return OP_EFAULT;
|
||||
_tags->comment_lengths[ncomments]=tag_len+value_len+1;
|
||||
memcpy(comment,_tag,sizeof(*comment)*tag_len);
|
||||
comment[tag_len]='=';
|
||||
memcpy(comment+tag_len+1,_value,sizeof(*comment)*(value_len+1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int opus_tags_add_comment(OpusTags *_tags,const char *_comment){
|
||||
char *comment;
|
||||
int ncomments;
|
||||
int comment_len;
|
||||
int ret;
|
||||
ret=op_tags_add_prepare(_tags);
|
||||
if(OP_UNLIKELY(ret<0))return ret;
|
||||
comment_len=strlen(_comment);
|
||||
ncomments=_tags->comments;
|
||||
_tags->user_comments[ncomments]=comment=(char *)
|
||||
_ogg_malloc(sizeof(*_tags->user_comments[ncomments])*(comment_len+1));
|
||||
if(OP_UNLIKELY(comment==NULL))return OP_EFAULT;
|
||||
_tags->comment_lengths[ncomments]=comment_len;
|
||||
memcpy(comment,_comment,sizeof(*comment)*(comment_len+1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*Is _a a "tag=value" comment whose tag matches _b?
|
||||
0 if it is, a non-zero value otherwise.*/
|
||||
static int op_tagcompare(const char *_a,const char *_b,int _n){
|
||||
return op_strncasecmp(_a,_b,_n)||_a[_n]!='=';
|
||||
}
|
||||
|
||||
const char *opus_tags_query(const OpusTags *_tags,const char *_tag,int _count){
|
||||
char **user_comments;
|
||||
int tag_len;
|
||||
int found;
|
||||
int ncomments;
|
||||
int ci;
|
||||
tag_len=strlen(_tag);
|
||||
ncomments=_tags->comments;
|
||||
user_comments=_tags->user_comments;
|
||||
found=0;
|
||||
for(ci=0;ci<ncomments;ci++){
|
||||
if(!op_tagcompare(user_comments[ci],_tag,tag_len)){
|
||||
/*We return a pointer to the data, not a copy.*/
|
||||
if(_count==found++)return user_comments[ci]+tag_len+1;
|
||||
}
|
||||
}
|
||||
/*Didn't find anything.*/
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int opus_tags_query_count(const OpusTags *_tags,const char *_tag){
|
||||
char **user_comments;
|
||||
int tag_len;
|
||||
int found;
|
||||
int ncomments;
|
||||
int ci;
|
||||
tag_len=strlen(_tag);
|
||||
ncomments=_tags->comments;
|
||||
user_comments=_tags->user_comments;
|
||||
found=0;
|
||||
for(ci=0;ci<ncomments;ci++){
|
||||
if(!op_tagcompare(user_comments[ci],_tag,tag_len))found++;
|
||||
}
|
||||
return found;
|
||||
}
|
|
@ -1,184 +0,0 @@
|
|||
/********************************************************************
|
||||
* *
|
||||
* THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. *
|
||||
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||
* *
|
||||
* THE libopusfile SOURCE CODE IS (C) COPYRIGHT 1994-2012 *
|
||||
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************
|
||||
|
||||
function: stdio-based convenience library for opening/seeking/decoding
|
||||
last mod: $Id: vorbisfile.c 17573 2010-10-27 14:53:59Z xiphmont $
|
||||
|
||||
********************************************************************/
|
||||
#include "internal.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef struct OpusMemStream OpusMemStream;
|
||||
|
||||
#define OP_MEM_SIZE_MAX (~(size_t)0>>1)
|
||||
#define OP_MEM_DIFF_MAX ((ptrdiff_t)OP_MEM_SIZE_MAX)
|
||||
|
||||
/*The context information needed to read from a block of memory as if it were a
|
||||
file.*/
|
||||
struct OpusMemStream{
|
||||
/*The block of memory to read from.*/
|
||||
const unsigned char *data;
|
||||
/*The total size of the block.
|
||||
This must be at most OP_MEM_SIZE_MAX to prevent signed overflow while
|
||||
seeking.*/
|
||||
ptrdiff_t size;
|
||||
/*The current file position.
|
||||
This is allowed to be set arbitrarily greater than size (i.e., past the end
|
||||
of the block, though we will not read data past the end of the block), but
|
||||
is not allowed to be negative (i.e., before the beginning of the block).*/
|
||||
ptrdiff_t pos;
|
||||
};
|
||||
|
||||
static int op_fread(void *_stream,unsigned char *_ptr,int _buf_size){
|
||||
FILE *stream;
|
||||
size_t ret;
|
||||
/*Check for empty read.*/
|
||||
if(_buf_size<=0)return 0;
|
||||
stream=(FILE *)_stream;
|
||||
ret=fread(_ptr,1,_buf_size,stream);
|
||||
OP_ASSERT(ret<=(size_t)_buf_size);
|
||||
/*If ret==0 and !feof(stream), there was a read error.*/
|
||||
return ret>0||feof(stream)?(int)ret:OP_EREAD;
|
||||
}
|
||||
|
||||
static int op_fseek(void *_stream,opus_int64 _offset,int _whence){
|
||||
#if defined(__MINGW32__)
|
||||
return fseeko64((FILE *)_stream,_offset,_whence);
|
||||
#elif defined(_MSC_VER)
|
||||
return _fseeki64((FILE *)_stream,_offset,_whence);
|
||||
#else
|
||||
return fseeko((FILE *)_stream,(off_t)_offset,_whence);
|
||||
#endif
|
||||
}
|
||||
|
||||
static opus_int64 op_ftell(void *_stream){
|
||||
#if defined(__MINGW32__)
|
||||
return ftello64((FILE *)_stream);
|
||||
#elif defined(_MSC_VER)
|
||||
return _ftelli64((FILE *)_stream);
|
||||
#else
|
||||
return ftello((FILE *)_stream);
|
||||
#endif
|
||||
}
|
||||
|
||||
static const OpusFileCallbacks OP_FILE_CALLBACKS={
|
||||
op_fread,
|
||||
op_fseek,
|
||||
op_ftell,
|
||||
(op_close_func)fclose
|
||||
};
|
||||
|
||||
void *op_fopen(OpusFileCallbacks *_cb,const char *_path,const char *_mode){
|
||||
FILE *fp;
|
||||
fp=fopen(_path,_mode);
|
||||
if(fp!=NULL)*_cb=*&OP_FILE_CALLBACKS;
|
||||
return fp;
|
||||
}
|
||||
|
||||
void *op_fdopen(OpusFileCallbacks *_cb,int _fd,const char *_mode){
|
||||
FILE *fp;
|
||||
fp=fdopen(_fd,_mode);
|
||||
if(fp!=NULL)*_cb=*&OP_FILE_CALLBACKS;
|
||||
return fp;
|
||||
}
|
||||
|
||||
void *op_freopen(OpusFileCallbacks *_cb,const char *_path,const char *_mode,
|
||||
void *_stream){
|
||||
FILE *fp;
|
||||
fp=freopen(_path,_mode,(FILE *)_stream);
|
||||
if(fp!=NULL)*_cb=*&OP_FILE_CALLBACKS;
|
||||
return fp;
|
||||
}
|
||||
|
||||
static int op_mem_read(void *_stream,unsigned char *_ptr,int _buf_size){
|
||||
OpusMemStream *stream;
|
||||
ptrdiff_t size;
|
||||
ptrdiff_t pos;
|
||||
stream=(OpusMemStream *)_stream;
|
||||
/*Check for empty read.*/
|
||||
if(_buf_size<=0)return 0;
|
||||
size=stream->size;
|
||||
pos=stream->pos;
|
||||
/*Check for EOF.*/
|
||||
if(pos>=size)return 0;
|
||||
/*Check for a short read.*/
|
||||
_buf_size=(int)OP_MAX(size-pos,_buf_size);
|
||||
memcpy(_ptr,stream->data+pos,_buf_size);
|
||||
pos+=_buf_size;
|
||||
stream->pos=pos;
|
||||
return _buf_size;
|
||||
}
|
||||
|
||||
static int op_mem_seek(void *_stream,opus_int64 _offset,int _whence){
|
||||
OpusMemStream *stream;
|
||||
ptrdiff_t pos;
|
||||
stream=(OpusMemStream *)_stream;
|
||||
pos=stream->pos;
|
||||
switch(_whence){
|
||||
case SEEK_SET:{
|
||||
/*Check for overflow:*/
|
||||
if(_offset<0||_offset>OP_MEM_DIFF_MAX)return -1;
|
||||
pos=(ptrdiff_t)_offset;
|
||||
}break;
|
||||
case SEEK_CUR:{
|
||||
/*Check for overflow:*/
|
||||
if(_offset<-pos||_offset>OP_MEM_DIFF_MAX-pos)return -1;
|
||||
pos=(ptrdiff_t)(pos+_offset);
|
||||
}break;
|
||||
case SEEK_END:{
|
||||
ptrdiff_t size;
|
||||
size=stream->size;
|
||||
OP_ASSERT(size>=0);
|
||||
/*Check for overflow:*/
|
||||
if(_offset>size||_offset<size-OP_MEM_DIFF_MAX)return -1;
|
||||
pos=(ptrdiff_t)(size-_offset);
|
||||
}break;
|
||||
default:return -1;
|
||||
}
|
||||
stream->pos=pos;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static opus_int64 op_mem_tell(void *_stream){
|
||||
OpusMemStream *stream;
|
||||
stream=(OpusMemStream *)_stream;
|
||||
return (ogg_int64_t)stream->pos;
|
||||
}
|
||||
|
||||
static int op_mem_close(void *_stream){
|
||||
_ogg_free(_stream);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const OpusFileCallbacks OP_MEM_CALLBACKS={
|
||||
op_mem_read,
|
||||
op_mem_seek,
|
||||
op_mem_tell,
|
||||
op_mem_close
|
||||
};
|
||||
|
||||
void *op_mem_stream_create(OpusFileCallbacks *_cb,
|
||||
const unsigned char *_data,size_t _size){
|
||||
OpusMemStream *stream;
|
||||
if(_size>OP_MEM_SIZE_MAX)return NULL;
|
||||
stream=(OpusMemStream *)_ogg_malloc(sizeof(*stream));
|
||||
if(stream!=NULL){
|
||||
*_cb=*&OP_MEM_CALLBACKS;
|
||||
stream->data=_data;
|
||||
stream->size=_size;
|
||||
stream->pos=0;
|
||||
}
|
||||
return stream;
|
||||
}
|
|
@ -16,7 +16,6 @@
|
|||
********************************************************************/
|
||||
#if !defined(_opusfile_h)
|
||||
# define _opusfile_h (1)
|
||||
# include <stdarg.h>
|
||||
|
||||
/**\mainpage
|
||||
\section Introduction
|
||||
|
@ -50,17 +49,68 @@
|
|||
Several additional sections are not tied to the main API.
|
||||
- \ref stream_callbacks
|
||||
- \ref header_info
|
||||
- \ref error_codes*/
|
||||
- \ref error_codes
|
||||
|
||||
\section Overview
|
||||
|
||||
The <tt>libopusfile</tt> API always decodes files to 48 kHz.
|
||||
The original sample rate is not preserved by the lossy compression, though
|
||||
it is stored in the header to allow you to resample to it after decoding
|
||||
(the <tt>libopusfile</tt> API does not currently provide a resampler,
|
||||
but the
|
||||
<a href="http://www.speex.org/docs/manual/speex-manual/node7.html#SECTION00760000000000000000">the
|
||||
Speex resampler</a> is a good choice if you need one).
|
||||
In general, if you are playing back the audio, you should leave it at
|
||||
48 kHz, provided your audio hardware supports it.
|
||||
When decoding to a file, it may be worth resampling back to the original
|
||||
sample rate, so as not to surprise users who might not expect the sample
|
||||
rate to change after encoding to Opus and decoding.
|
||||
|
||||
Opus files can contain anywhere from 1 to 255 channels of audio.
|
||||
The channel mappings for up to 8 channels are the same as the
|
||||
<a href="http://www.xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-800004.3.9">Vorbis
|
||||
mappings</a>.
|
||||
A special stereo API can convert everything to 2 channels, making it simple
|
||||
to support multichannel files in an application which only has stereo
|
||||
output.
|
||||
Although the <tt>libopusfile</tt> ABI provides support for the theoretical
|
||||
maximum number of channels, the current implementation does not support
|
||||
files with more than 8 channels, as they do not have well-defined channel
|
||||
mappings.
|
||||
|
||||
Like all Ogg files, Opus files may be "chained".
|
||||
That is, multiple Opus files may be combined into a single, longer file just
|
||||
by concatenating the original files.
|
||||
This is commonly done in internet radio streaming, as it allows the title
|
||||
and artist to be updated each time the song changes, since each link in the
|
||||
chain includes its own set of metadata.
|
||||
|
||||
<tt>libopusfile</tt> fully supports chained files.
|
||||
It will decode the first Opus stream found in each link of a chained file
|
||||
(ignoring any other streams that might be concurrently multiplexed with it,
|
||||
such as a video stream).
|
||||
|
||||
The channel count can also change between links.
|
||||
If your application is not prepared to deal with this, it can use the stereo
|
||||
API to ensure the audio from all links will always get decoded into a
|
||||
common format.
|
||||
Since <tt>libopusfile</tt> always decodes to 48 kHz, you do not have to
|
||||
worry about the sample rate changing between links (as was possible with
|
||||
Vorbis).
|
||||
This makes application support for chained files with <tt>libopusfile</tt>
|
||||
very easy.*/
|
||||
|
||||
# if defined(__cplusplus)
|
||||
extern "C" {
|
||||
# endif
|
||||
|
||||
# include <stdarg.h>
|
||||
# include <stdio.h>
|
||||
# include <ogg/ogg.h>
|
||||
# include <opus_multistream.h>
|
||||
|
||||
/**@cond PRIVATE*/
|
||||
|
||||
/*Enable special features for gcc and gcc-compatible compilers.*/
|
||||
# if !defined(OP_GNUC_PREREQ)
|
||||
# if defined(__GNUC__)&&defined(__GNUC_MINOR__)
|
||||
|
@ -75,9 +125,12 @@ extern "C" {
|
|||
# pragma GCC visibility push(default)
|
||||
# endif
|
||||
|
||||
typedef struct OpusHead OpusHead;
|
||||
typedef struct OpusTags OpusTags;
|
||||
typedef struct OggOpusFile OggOpusFile;
|
||||
typedef struct OpusHead OpusHead;
|
||||
typedef struct OpusTags OpusTags;
|
||||
typedef struct OpusPictureTag OpusPictureTag;
|
||||
typedef struct OpusServerInfo OpusServerInfo;
|
||||
typedef struct OpusFileCallbacks OpusFileCallbacks;
|
||||
typedef struct OggOpusFile OggOpusFile;
|
||||
|
||||
/*Warning attributes for libopusfile functions.*/
|
||||
# if OP_GNUC_PREREQ(3,4)
|
||||
|
@ -91,6 +144,8 @@ typedef struct OggOpusFile OggOpusFile;
|
|||
# define OP_ARG_NONNULL(_x)
|
||||
# endif
|
||||
|
||||
/**@endcond*/
|
||||
|
||||
/**\defgroup error_codes Error Codes*/
|
||||
/*@{*/
|
||||
/**\name List of possible error codes
|
||||
|
@ -182,8 +237,9 @@ struct OpusHead{
|
|||
opus_uint32 input_sample_rate;
|
||||
/**The gain to apply to the decoded output, in dB, as a Q8 value in the range
|
||||
-32768...32767.
|
||||
The decoder will automatically scale the output by
|
||||
pow(10,output_gain/(20.0*256)).*/
|
||||
The <tt>libopusfile</tt> API will automatically apply this gain to the
|
||||
decoded output before returning it, scaling it by
|
||||
<code>pow(10,output_gain/(20.0*256))</code>.*/
|
||||
int output_gain;
|
||||
/**The channel mapping family, in the range 0...255.
|
||||
Channel mapping family 0 covers mono or stereo in a single stream.
|
||||
|
@ -253,6 +309,87 @@ struct OpusTags{
|
|||
char *vendor;
|
||||
};
|
||||
|
||||
/**\name Picture tag image formats*/
|
||||
/*@{*/
|
||||
|
||||
/**The MIME type was not recognized, or the image data did not match the
|
||||
declared MIME type.*/
|
||||
#define OP_PIC_FORMAT_UNKNOWN (-1)
|
||||
/**The MIME type indicates the image data is really a URL.*/
|
||||
#define OP_PIC_FORMAT_URL (0)
|
||||
/**The image is a JPEG.*/
|
||||
#define OP_PIC_FORMAT_JPEG (1)
|
||||
/**The image is a PNG.*/
|
||||
#define OP_PIC_FORMAT_PNG (2)
|
||||
/**The image is a GIF.*/
|
||||
#define OP_PIC_FORMAT_GIF (3)
|
||||
|
||||
/*@}*/
|
||||
|
||||
/**The contents of a METADATA_BLOCK_PICTURE tag.*/
|
||||
struct OpusPictureTag{
|
||||
/**The picture type according to the ID3v2 APIC frame:
|
||||
<ol start="0">
|
||||
<li>Other</li>
|
||||
<li>32x32 pixels 'file icon' (PNG only)</li>
|
||||
<li>Other file icon</li>
|
||||
<li>Cover (front)</li>
|
||||
<li>Cover (back)</li>
|
||||
<li>Leaflet page</li>
|
||||
<li>Media (e.g. label side of CD)</li>
|
||||
<li>Lead artist/lead performer/soloist</li>
|
||||
<li>Artist/performer</li>
|
||||
<li>Conductor</li>
|
||||
<li>Band/Orchestra</li>
|
||||
<li>Composer</li>
|
||||
<li>Lyricist/text writer</li>
|
||||
<li>Recording Location</li>
|
||||
<li>During recording</li>
|
||||
<li>During performance</li>
|
||||
<li>Movie/video screen capture</li>
|
||||
<li>A bright colored fish</li>
|
||||
<li>Illustration</li>
|
||||
<li>Band/artist logotype</li>
|
||||
<li>Publisher/Studio logotype</li>
|
||||
</ol>
|
||||
Others are reserved and should not be used.
|
||||
There may only be one each of picture type 1 and 2 in a file.*/
|
||||
opus_int32 type;
|
||||
/**The MIME type of the picture, in printable ASCII characters 0x20-0x7E.
|
||||
The MIME type may also be <code>"-->"</code> to signify that the data part
|
||||
is a URL pointing to the picture instead of the picture data itself.
|
||||
In this case, a terminating NUL is appended to the URL string in #data,
|
||||
but #data_length is set to the length of the string excluding that
|
||||
terminating NUL.*/
|
||||
char *mime_type;
|
||||
/**The description of the picture, in UTF-8.*/
|
||||
char *description;
|
||||
/**The width of the picture in pixels.*/
|
||||
opus_uint32 width;
|
||||
/**The height of the picture in pixels.*/
|
||||
opus_uint32 height;
|
||||
/**The color depth of the picture in bits-per-pixel (<em>not</em>
|
||||
bits-per-channel).*/
|
||||
opus_uint32 depth;
|
||||
/**For indexed-color pictures (e.g., GIF), the number of colors used, or 0
|
||||
for non-indexed pictures.*/
|
||||
opus_uint32 colors;
|
||||
/**The length of the picture data in bytes.*/
|
||||
opus_uint32 data_length;
|
||||
/**The binary picture data.*/
|
||||
unsigned char *data;
|
||||
/**The format of the picture data, if known.
|
||||
One of
|
||||
<ul>
|
||||
<li>#OP_PIC_FORMAT_UNKNOWN,</li>
|
||||
<li>#OP_PIC_FORMAT_URL,</li>
|
||||
<li>#OP_PIC_FORMAT_JPEG,</li>
|
||||
<li>#OP_PIC_FORMAT_PNG, or</li>
|
||||
<li>#OP_PIC_FORMAT_GIF.</li>
|
||||
</ul>*/
|
||||
int format;
|
||||
};
|
||||
|
||||
/**\name Functions for manipulating header data
|
||||
|
||||
These functions manipulate the #OpusHead and #OpusTags structures,
|
||||
|
@ -315,7 +452,7 @@ ogg_int64_t opus_granule_sample(const OpusHead *_head,ogg_int64_t _gp)
|
|||
for validity.
|
||||
\param[in] _data The contents of the 'comment' header packet.
|
||||
\param _len The number of bytes of data in the 'info' header packet.
|
||||
\retval 0 Success.
|
||||
\retval 0 Success.
|
||||
\retval #OP_ENOTFORMAT If the data does not start with the "OpusTags"
|
||||
string.
|
||||
\retval #OP_EBADHEADER If the contents of the packet otherwise violate the
|
||||
|
@ -324,6 +461,15 @@ ogg_int64_t opus_granule_sample(const OpusHead *_head,ogg_int64_t _gp)
|
|||
OP_WARN_UNUSED_RESULT int opus_tags_parse(OpusTags *_tags,
|
||||
const unsigned char *_data,size_t _len) OP_ARG_NONNULL(2);
|
||||
|
||||
/**Performs a deep copy of an #OpusTags structure.
|
||||
\param _dst The #OpusTags structure to copy into.
|
||||
If this function fails, the contents of this structure remain
|
||||
untouched.
|
||||
\param _src The #OpusTags structure to copy from.
|
||||
\retval 0 Success.
|
||||
\retval #OP_EFAULT If there wasn't enough memory to copy the tags.*/
|
||||
int opus_tags_copy(OpusTags *_dst,const OpusTags *_src) OP_ARG_NONNULL(1);
|
||||
|
||||
/**Initializes an #OpusTags structure.
|
||||
This should be called on a freshly allocated #OpusTags structure before
|
||||
attempting to use it.
|
||||
|
@ -385,6 +531,24 @@ const char *opus_tags_query(const OpusTags *_tags,const char *_tag,int _count)
|
|||
int opus_tags_query_count(const OpusTags *_tags,const char *_tag)
|
||||
OP_ARG_NONNULL(1) OP_ARG_NONNULL(2);
|
||||
|
||||
/**Get the track gain from an R128_TRACK_GAIN tag, if one was specified.
|
||||
This searches for the first R128_TRACK_GAIN tag with a valid signed,
|
||||
16-bit decimal integer value and returns the value.
|
||||
This routine is exposed merely for convenience for applications which wish
|
||||
to do something special with the track gain (i.e., display it).
|
||||
If you simply wish to apply the track gain instead of the header gain, you
|
||||
can use op_set_gain_offset() with an #OP_TRACK_GAIN type and no offset.
|
||||
\param _tags An initialized #OpusTags structure.
|
||||
\param[out] _gain_q8 The track gain, in 1/256ths of a dB.
|
||||
This will lie in the range [-32768,32767], and should
|
||||
be applied in <em>addition</em> to the header gain.
|
||||
On error, no value is returned, and the previous
|
||||
contents remain unchanged.
|
||||
\return 0 on success, or a negative value on error.
|
||||
\retval #OP_FALSE There was no track gain available in the given tags.*/
|
||||
int opus_tags_get_track_gain(const OpusTags *_tags,int *_gain_q8)
|
||||
OP_ARG_NONNULL(1) OP_ARG_NONNULL(2);
|
||||
|
||||
/**Clears the #OpusTags structure.
|
||||
This should be called on an #OpusTags structure after it is no longer
|
||||
needed.
|
||||
|
@ -392,6 +556,78 @@ int opus_tags_query_count(const OpusTags *_tags,const char *_tag)
|
|||
\param _tags The #OpusTags structure to clear.*/
|
||||
void opus_tags_clear(OpusTags *_tags) OP_ARG_NONNULL(1);
|
||||
|
||||
/**Check if \a _comment is an instance of a \a _tag_name tag.
|
||||
\see opus_tagncompare
|
||||
\param _tag_name A NUL-terminated, case-insensitive, ASCII string containing
|
||||
the name of the tag to check for (without the terminating
|
||||
'=' character).
|
||||
\param _comment The comment string to check.
|
||||
\return An integer less than, equal to, or greater than zero if \a _comment
|
||||
is found respectively, to be less than, to match, or be greater
|
||||
than a "tag=value" string whose tag matches \a _tag_name.*/
|
||||
int opus_tagcompare(const char *_tag_name,const char *_comment);
|
||||
|
||||
/**Check if \a _comment is an instance of a \a _tag_name tag.
|
||||
This version is slightly more efficient than opus_tagcompare() if the length
|
||||
of the tag name is already known (e.g., because it is a constant).
|
||||
\see opus_tagcompare
|
||||
\param _tag_name A case-insensitive ASCII string containing the name of the
|
||||
tag to check for (without the terminating '=' character).
|
||||
\param _tag_len The number of characters in the tag name.
|
||||
This must be non-negative.
|
||||
\param _comment The comment string to check.
|
||||
\return An integer less than, equal to, or greater than zero if \a _comment
|
||||
is found respectively, to be less than, to match, or be greater
|
||||
than a "tag=value" string whose tag matches the first \a _tag_len
|
||||
characters of \a _tag_name.*/
|
||||
int opus_tagncompare(const char *_tag_name,int _tag_len,const char *_comment);
|
||||
|
||||
/**Parse a single METADATA_BLOCK_PICTURE tag.
|
||||
This decodes the BASE64-encoded content of the tag and returns a structure
|
||||
with the MIME type, description, image parameters (if known), and the
|
||||
compressed image data.
|
||||
If the MIME type indicates the presence of an image format we recognize
|
||||
(JPEG, PNG, or GIF) and the actual image data contains the magic signature
|
||||
associated with that format, then the OpusPictureTag::format field will be
|
||||
set to the corresponding format.
|
||||
This is provided as a convenience to avoid requiring applications to parse
|
||||
the MIME type and/or do their own format detection for the commonly used
|
||||
formats.
|
||||
In this case, we also attempt to extract the image parameters directly from
|
||||
the image data (overriding any that were present in the tag, which the
|
||||
specification says applications are not meant to rely on).
|
||||
The application must still provide its own support for actually decoding the
|
||||
image data and, if applicable, retrieving that data from URLs.
|
||||
\param[out] _pic Returns the parsed picture data.
|
||||
No sanitation is done on the type, MIME type, or
|
||||
description fields, so these might return invalid values.
|
||||
The contents of this structure are left unmodified on
|
||||
failure.
|
||||
\param _tag The METADATA_BLOCK_PICTURE tag contents.
|
||||
The leading "METADATA_BLOCK_PICTURE=" portion is optional,
|
||||
to allow the function to be used on either directly on the
|
||||
values in OpusTags::user_comments or on the return value
|
||||
of opus_tags_query().
|
||||
\return 0 on success or a negative value on error.
|
||||
\retval #OP_ENOTFORMAT The METADATA_BLOCK_PICTURE contents were not valid.
|
||||
\retval #OP_EFAULT There was not enough memory to store the picture tag
|
||||
contents.*/
|
||||
OP_WARN_UNUSED_RESULT int opus_picture_tag_parse(OpusPictureTag *_pic,
|
||||
const char *_tag) OP_ARG_NONNULL(1) OP_ARG_NONNULL(2);
|
||||
|
||||
/**Initializes an #OpusPictureTag structure.
|
||||
This should be called on a freshly allocated #OpusPictureTag structure
|
||||
before attempting to use it.
|
||||
\param _pic The #OpusPictureTag structure to initialize.*/
|
||||
void opus_picture_tag_init(OpusPictureTag *_pic) OP_ARG_NONNULL(1);
|
||||
|
||||
/**Clears the #OpusPictureTag structure.
|
||||
This should be called on an #OpusPictureTag structure after it is no longer
|
||||
needed.
|
||||
It will free all memory used by the structure members.
|
||||
\param _pic The #OpusPictureTag structure to clear.*/
|
||||
void opus_picture_tag_clear(OpusPictureTag *_pic) OP_ARG_NONNULL(1);
|
||||
|
||||
/*@}*/
|
||||
|
||||
/*@}*/
|
||||
|
@ -408,6 +644,8 @@ void opus_tags_clear(OpusTags *_tags) OP_ARG_NONNULL(1);
|
|||
They may be expanded in the future.*/
|
||||
/*@{*/
|
||||
|
||||
/**@cond PRIVATE*/
|
||||
|
||||
/*These are the raw numbers used to define the request codes.
|
||||
They should not be used directly.*/
|
||||
#define OP_SSL_SKIP_CERTIFICATE_CHECK_REQUEST (6464)
|
||||
|
@ -415,6 +653,7 @@ void opus_tags_clear(OpusTags *_tags) OP_ARG_NONNULL(1);
|
|||
#define OP_HTTP_PROXY_PORT_REQUEST (6592)
|
||||
#define OP_HTTP_PROXY_USER_REQUEST (6656)
|
||||
#define OP_HTTP_PROXY_PASS_REQUEST (6720)
|
||||
#define OP_GET_SERVER_INFO_REQUEST (6784)
|
||||
|
||||
#define OP_URL_OPT(_request) ((_request)+(char *)0)
|
||||
|
||||
|
@ -422,6 +661,64 @@ void opus_tags_clear(OpusTags *_tags) OP_ARG_NONNULL(1);
|
|||
provided to one of the URL options.*/
|
||||
#define OP_CHECK_INT(_x) ((void)((_x)==(opus_int32)0),(opus_int32)(_x))
|
||||
#define OP_CHECK_CONST_CHAR_PTR(_x) ((_x)+((_x)-(const char *)(_x)))
|
||||
#define OP_CHECK_SERVER_INFO_PTR(_x) ((_x)+((_x)-(OpusServerInfo *)(_x)))
|
||||
|
||||
/**@endcond*/
|
||||
|
||||
/**HTTP/Shoutcast/Icecast server information associated with a URL.*/
|
||||
struct OpusServerInfo{
|
||||
/**The name of the server (icy-name/ice-name).
|
||||
This is <code>NULL</code> if there was no <code>icy-name</code> or
|
||||
<code>ice-name</code> header.*/
|
||||
char *name;
|
||||
/**A short description of the server (icy-description/ice-description).
|
||||
This is <code>NULL</code> if there was no <code>icy-description</code> or
|
||||
<code>ice-description</code> header.*/
|
||||
char *description;
|
||||
/**The genre the server falls under (icy-genre/ice-genre).
|
||||
This is <code>NULL</code> if there was no <code>icy-genre</code> or
|
||||
<code>ice-genre</code> header.*/
|
||||
char *genre;
|
||||
/**The homepage for the server (icy-url/ice-url).
|
||||
This is <code>NULL</code> if there was no <code>icy-url</code> or
|
||||
<code>ice-url</code> header.*/
|
||||
char *url;
|
||||
/**The software used by the origin server (Server).
|
||||
This is <code>NULL</code> if there was no <code>Server</code> header.*/
|
||||
char *server;
|
||||
/**The media type of the entity sent to the recepient (Content-Type).
|
||||
This is <code>NULL</code> if there was no <code>Content-Type</code>
|
||||
header.*/
|
||||
char *content_type;
|
||||
/**The nominal stream bitrate in kbps (icy-br/ice-bitrate).
|
||||
This is <code>-1</code> if there was no <code>icy-br</code> or
|
||||
<code>ice-bitrate</code> header.*/
|
||||
opus_int32 bitrate_kbps;
|
||||
/**Flag indicating whether the server is public (<code>1</code>) or not
|
||||
(<code>0</code>) (icy-pub/ice-public).
|
||||
This is <code>-1</code> if there was no <code>icy-pub</code> or
|
||||
<code>ice-public</code> header.*/
|
||||
int is_public;
|
||||
/**Flag indicating whether the server is using HTTPS instead of HTTP.
|
||||
This is <code>0</code> unless HTTPS is being used.
|
||||
This may not match the protocol used in the original URL if there were
|
||||
redirections.*/
|
||||
int is_ssl;
|
||||
};
|
||||
|
||||
/**Initializes an #OpusServerInfo structure.
|
||||
All fields are set as if the corresponding header was not available.
|
||||
\param _info The #OpusServerInfo structure to initialize.
|
||||
\note If you use this function, you must link against <tt>libopusurl</tt>.*/
|
||||
void opus_server_info_init(OpusServerInfo *_info) OP_ARG_NONNULL(1);
|
||||
|
||||
/**Clears the #OpusServerInfo structure.
|
||||
This should be called on an #OpusServerInfo structure after it is no longer
|
||||
needed.
|
||||
It will free all memory used by the structure members.
|
||||
\param _info The #OpusServerInfo structure to clear.
|
||||
\note If you use this function, you must link against <tt>libopusurl</tt>.*/
|
||||
void opus_server_info_clear(OpusServerInfo *_info) OP_ARG_NONNULL(1);
|
||||
|
||||
/**Skip the certificate check when connecting via TLS/SSL (https).
|
||||
\param _b <code>opus_int32</code>: Whether or not to skip the certificate
|
||||
|
@ -467,7 +764,7 @@ void opus_tags_clear(OpusTags *_tags) OP_ARG_NONNULL(1);
|
|||
arguments.
|
||||
\hideinitializer*/
|
||||
#define OP_HTTP_PROXY_USER(_user) \
|
||||
OP_URL_OPT(OP_HTTP_PROXY_USER_REQUEST),OP_CHECK_CONST_CHAR_PTR(_host)
|
||||
OP_URL_OPT(OP_HTTP_PROXY_USER_REQUEST),OP_CHECK_CONST_CHAR_PTR(_user)
|
||||
|
||||
/**Use the given password for authentication when proxying connections.
|
||||
All proxy parameters are ignored for non-http and non-https URLs.
|
||||
|
@ -480,7 +777,28 @@ void opus_tags_clear(OpusTags *_tags) OP_ARG_NONNULL(1);
|
|||
arguments.
|
||||
\hideinitializer*/
|
||||
#define OP_HTTP_PROXY_PASS(_pass) \
|
||||
OP_URL_OPT(OP_HTTP_PROXY_PASS_REQUEST),OP_CHECK_CONST_CHAR_PTR(_host)
|
||||
OP_URL_OPT(OP_HTTP_PROXY_PASS_REQUEST),OP_CHECK_CONST_CHAR_PTR(_pass)
|
||||
|
||||
/**Parse information about the streaming server (if any) and return it.
|
||||
Very little validation is done.
|
||||
In particular, OpusServerInfo::url may not be a valid URL,
|
||||
OpusServerInfo::bitrate_kbps may not really be in kbps, and
|
||||
OpusServerInfo::content_type may not be a valid MIME type.
|
||||
The character set of the string fields is not specified anywhere, and should
|
||||
not be assumed to be valid UTF-8.
|
||||
\param _info OpusServerInfo *: Returns information about the server.
|
||||
If there is any error opening the stream, the
|
||||
contents of this structure remain
|
||||
unmodified.
|
||||
On success, fills in the structure with the
|
||||
server information that was available, if
|
||||
any.
|
||||
After a successful return, the contents of
|
||||
this structure should be freed by calling
|
||||
opus_server_info_clear().
|
||||
\hideinitializer*/
|
||||
#define OP_GET_SERVER_INFO(_info) \
|
||||
OP_URL_OPT(OP_GET_SERVER_INFO_REQUEST),OP_CHECK_SERVER_INFO_PTR(_info)
|
||||
|
||||
/*@}*/
|
||||
/*@}*/
|
||||
|
@ -497,8 +815,6 @@ void opus_tags_clear(OpusTags *_tags) OP_ARG_NONNULL(1);
|
|||
block of memory, or URLs.*/
|
||||
/*@{*/
|
||||
|
||||
typedef struct OpusFileCallbacks OpusFileCallbacks;
|
||||
|
||||
/**Reads up to \a _nbytes bytes of data from \a _stream.
|
||||
\param _stream The stream to read from.
|
||||
\param[out] _ptr The buffer to store the data in.
|
||||
|
@ -564,6 +880,10 @@ struct OpusFileCallbacks{
|
|||
If there is an error opening the file, nothing will be
|
||||
filled in here.
|
||||
\param _path The path to the file to open.
|
||||
On Windows, this string must be UTF-8 (to allow access to
|
||||
files whose names cannot be represented in the current
|
||||
MBCS code page).
|
||||
All other systems use the native character encoding.
|
||||
\param _mode The mode to open the file in.
|
||||
\return A stream handle to use with the callbacks, or <code>NULL</code> on
|
||||
error.*/
|
||||
|
@ -597,6 +917,10 @@ OP_WARN_UNUSED_RESULT void *op_fdopen(OpusFileCallbacks *_cb,
|
|||
If there is an error opening the file, nothing will be
|
||||
filled in here.
|
||||
\param _path The path to the file to open.
|
||||
On Windows, this string must be UTF-8 (to allow access
|
||||
to files whose names cannot be represented in the
|
||||
current MBCS code page).
|
||||
All other systems use the native character encoding.
|
||||
\param _mode The mode to open the file in.
|
||||
\param _stream A stream previously returned by op_fopen(), op_fdopen(),
|
||||
or op_freopen().
|
||||
|
@ -624,6 +948,7 @@ OP_WARN_UNUSED_RESULT void *op_mem_stream_create(OpusFileCallbacks *_cb,
|
|||
takes a va_list instead of a variable number of arguments.
|
||||
It does not call the <code>va_end</code> macro, and because it invokes the
|
||||
<code>va_arg</code> macro, the value of \a _ap is undefined after the call.
|
||||
\note If you use this function, you must link against <tt>libopusurl</tt>.
|
||||
\param[out] _cb The callbacks to use for this stream.
|
||||
If there is an error creating the stream, nothing will
|
||||
be filled in here.
|
||||
|
@ -632,6 +957,10 @@ OP_WARN_UNUSED_RESULT void *op_mem_stream_create(OpusFileCallbacks *_cb,
|
|||
schemes are supported.
|
||||
Both <http:> and <https:> may be disabled at compile
|
||||
time, in which case opening such URLs will always fail.
|
||||
Currently this only supports URIs.
|
||||
IRIs should be converted to UTF-8 and URL-escaped, with
|
||||
internationalized domain names encoded in punycode,
|
||||
before passing them to this function.
|
||||
\param[in,out] _ap A list of the \ref url_options "optional flags" to use.
|
||||
This is a variable-length list of options terminated
|
||||
with <code>NULL</code>.
|
||||
|
@ -640,7 +969,8 @@ OP_WARN_UNUSED_RESULT void *op_mem_stream_create(OpusFileCallbacks *_cb,
|
|||
OP_WARN_UNUSED_RESULT void *op_url_stream_vcreate(OpusFileCallbacks *_cb,
|
||||
const char *_url,va_list _ap) OP_ARG_NONNULL(1) OP_ARG_NONNULL(2);
|
||||
|
||||
/**Creates a stream that reads from the given URL using the specified proxy.
|
||||
/**Creates a stream that reads from the given URL.
|
||||
\note If you use this function, you must link against <tt>libopusurl</tt>.
|
||||
\param[out] _cb The callbacks to use for this stream.
|
||||
If there is an error creating the stream, nothing will be
|
||||
filled in here.
|
||||
|
@ -649,6 +979,10 @@ OP_WARN_UNUSED_RESULT void *op_url_stream_vcreate(OpusFileCallbacks *_cb,
|
|||
are supported.
|
||||
Both <http:> and <https:> may be disabled at compile time,
|
||||
in which case opening such URLs will always fail.
|
||||
Currently this only supports URIs.
|
||||
IRIs should be converted to UTF-8 and URL-escaped, with
|
||||
internationalized domain names encoded in punycode, before
|
||||
passing them to this function.
|
||||
\param ... The \ref url_options "optional flags" to use.
|
||||
This is a variable-length list of options terminated with
|
||||
<code>NULL</code>.
|
||||
|
@ -731,12 +1065,17 @@ OP_WARN_UNUSED_RESULT OggOpusFile *op_open_memory(const unsigned char *_data,
|
|||
takes a va_list instead of a variable number of arguments.
|
||||
It does not call the <code>va_end</code> macro, and because it invokes the
|
||||
<code>va_arg</code> macro, the value of \a _ap is undefined after the call.
|
||||
\note If you use this function, you must link against <tt>libopusurl</tt>.
|
||||
\param _url The URL to open.
|
||||
Currently only the <file:>, <http:>, and <https:>
|
||||
schemes are supported.
|
||||
Both <http:> and <https:> may be disabled at compile
|
||||
time, in which case opening such URLs will always
|
||||
fail.
|
||||
Currently this only supports URIs.
|
||||
IRIs should be converted to UTF-8 and URL-escaped,
|
||||
with internationalized domain names encoded in
|
||||
punycode, before passing them to this function.
|
||||
\param[out] _error Returns 0 on success, or a failure code on error.
|
||||
You may pass in <code>NULL</code> if you don't want
|
||||
the failure code.
|
||||
|
@ -751,13 +1090,16 @@ OP_WARN_UNUSED_RESULT OggOpusFile *op_vopen_url(const char *_url,
|
|||
int *_error,va_list _ap) OP_ARG_NONNULL(1);
|
||||
|
||||
/**Open a stream from a URL.
|
||||
However, this approach will not work for live streams or HTTP/1.0 servers
|
||||
(which do not support Range requets).
|
||||
\note If you use this function, you must link against <tt>libopusurl</tt>.
|
||||
\param _url The URL to open.
|
||||
Currently only the <file:>, <http:>, and <https:> schemes
|
||||
are supported.
|
||||
Both <http:> and <https:> may be disabled at compile
|
||||
time, in which case opening such URLs will always fail.
|
||||
Currently this only supports URIs.
|
||||
IRIs should be converted to UTF-8 and URL-escaped, with
|
||||
internationalized domain names encoded in punycode,
|
||||
before passing them to this function.
|
||||
\param[out] _error Returns 0 on success, or a failure code on error.
|
||||
You may pass in <code>NULL</code> if you don't want the
|
||||
failure code.
|
||||
|
@ -841,7 +1183,11 @@ OP_WARN_UNUSED_RESULT OggOpusFile *op_open_url(const char *_url,
|
|||
<dd>The first or last timestamp in a link failed
|
||||
basic validity checks.</dd>
|
||||
</dl>
|
||||
\return A freshly opened \c OggOpusFile, or <code>NULL</code> on error.*/
|
||||
\return A freshly opened \c OggOpusFile, or <code>NULL</code> on error.
|
||||
<tt>libopusfile</tt> does <em>not</em> take ownership of the source
|
||||
if the call fails.
|
||||
The calling application is responsible for closing the source if
|
||||
this call returns an error.*/
|
||||
OP_WARN_UNUSED_RESULT OggOpusFile *op_open_callbacks(void *_source,
|
||||
const OpusFileCallbacks *_cb,const unsigned char *_initial_data,
|
||||
size_t _initial_bytes,int *_error) OP_ARG_NONNULL(2);
|
||||
|
@ -876,6 +1222,7 @@ OP_WARN_UNUSED_RESULT OggOpusFile *op_test_memory(const unsigned char *_data,
|
|||
takes a va_list instead of a variable number of arguments.
|
||||
It does not call the <code>va_end</code> macro, and because it invokes the
|
||||
<code>va_arg</code> macro, the value of \a _ap is undefined after the call.
|
||||
\note If you use this function, you must link against <tt>libopusurl</tt>.
|
||||
\see op_test_url
|
||||
\see op_test_callbacks
|
||||
\param _url The URL to open.
|
||||
|
@ -884,6 +1231,10 @@ OP_WARN_UNUSED_RESULT OggOpusFile *op_test_memory(const unsigned char *_data,
|
|||
Both <http:> and <https:> may be disabled at compile
|
||||
time, in which case opening such URLs will always
|
||||
fail.
|
||||
Currently this only supports URIs.
|
||||
IRIs should be converted to UTF-8 and URL-escaped,
|
||||
with internationalized domain names encoded in
|
||||
punycode, before passing them to this function.
|
||||
\param[out] _error Returns 0 on success, or a failure code on error.
|
||||
You may pass in <code>NULL</code> if you don't want
|
||||
the failure code.
|
||||
|
@ -898,12 +1249,17 @@ OP_WARN_UNUSED_RESULT OggOpusFile *op_vtest_url(const char *_url,
|
|||
int *_error,va_list _ap) OP_ARG_NONNULL(1);
|
||||
|
||||
/**Partially open a stream from a URL.
|
||||
\note If you use this function, you must link against <tt>libopusurl</tt>.
|
||||
\see op_test_callbacks
|
||||
\param _url The URL to open.
|
||||
Currently only the <file:>, <http:>, and <https:>
|
||||
schemes are supported.
|
||||
Both <http:> and <https:> may be disabled at compile
|
||||
time, in which case opening such URLs will always fail.
|
||||
Currently this only supports URIs.
|
||||
IRIs should be converted to UTF-8 and URL-escaped, with
|
||||
internationalized domain names encoded in punycode,
|
||||
before passing them to this function.
|
||||
\param[out] _error Returns 0 on success, or a failure code on error.
|
||||
You may pass in <code>NULL</code> if you don't want the
|
||||
failure code.
|
||||
|
@ -974,7 +1330,11 @@ OP_WARN_UNUSED_RESULT OggOpusFile *op_test_url(const char *_url,
|
|||
the failure code.
|
||||
See op_open_callbacks() for a full list of failure
|
||||
codes.
|
||||
\return A partially opened \c OggOpusFile, or <code>NULL</code> on error.*/
|
||||
\return A partially opened \c OggOpusFile, or <code>NULL</code> on error.
|
||||
<tt>libopusfile</tt> does <em>not</em> take ownership of the source
|
||||
if the call fails.
|
||||
The calling application is responsible for closing the source if
|
||||
this call returns an error.*/
|
||||
OP_WARN_UNUSED_RESULT OggOpusFile *op_test_callbacks(void *_source,
|
||||
const OpusFileCallbacks *_cb,const unsigned char *_initial_data,
|
||||
size_t _initial_bytes,int *_error) OP_ARG_NONNULL(2);
|
||||
|
@ -1046,7 +1406,7 @@ void op_free(OggOpusFile *_of);
|
|||
This function may be called on partially-opened streams.
|
||||
\param _of The \c OggOpusFile whose seekable status is to be returned.
|
||||
\return A non-zero value if seekable, and 0 if unseekable.*/
|
||||
int op_seekable(OggOpusFile *_of) OP_ARG_NONNULL(1);
|
||||
int op_seekable(const OggOpusFile *_of) OP_ARG_NONNULL(1);
|
||||
|
||||
/**Returns the number of links in this chained stream.
|
||||
This function may be called on partially-opened streams, but it will always
|
||||
|
@ -1054,9 +1414,9 @@ int op_seekable(OggOpusFile *_of) OP_ARG_NONNULL(1);
|
|||
The actual number of links is not known until the stream is fully opened.
|
||||
\param _of The \c OggOpusFile from which to retrieve the link count.
|
||||
\return For fully-open seekable sources, this returns the total number of
|
||||
links in the whole stream.
|
||||
links in the whole stream, which will be at least 1.
|
||||
For partially-open or unseekable sources, this always returns 1.*/
|
||||
int op_link_count(OggOpusFile *_of) OP_ARG_NONNULL(1);
|
||||
int op_link_count(const OggOpusFile *_of) OP_ARG_NONNULL(1);
|
||||
|
||||
/**Get the serial number of the given link in a (possibly-chained) Ogg Opus
|
||||
stream.
|
||||
|
@ -1071,7 +1431,7 @@ int op_link_count(OggOpusFile *_of) OP_ARG_NONNULL(1);
|
|||
the serial number of the last link.
|
||||
If the source is not seekable, this always returns the serial number
|
||||
of the current link.*/
|
||||
opus_uint32 op_serialno(OggOpusFile *_of,int _li) OP_ARG_NONNULL(1);
|
||||
opus_uint32 op_serialno(const OggOpusFile *_of,int _li) OP_ARG_NONNULL(1);
|
||||
|
||||
/**Get the channel count of the given link in a (possibly-chained) Ogg Opus
|
||||
stream.
|
||||
|
@ -1088,7 +1448,7 @@ opus_uint32 op_serialno(OggOpusFile *_of,int _li) OP_ARG_NONNULL(1);
|
|||
the channel count of the last link.
|
||||
If the source is not seekable, this always returns the channel count
|
||||
of the current link.*/
|
||||
int op_channel_count(OggOpusFile *_of,int _li) OP_ARG_NONNULL(1);
|
||||
int op_channel_count(const OggOpusFile *_of,int _li) OP_ARG_NONNULL(1);
|
||||
|
||||
/**Get the total (compressed) size of the stream, or of an individual link in
|
||||
a (possibly-chained) Ogg Opus stream, including all headers and Ogg muxing
|
||||
|
@ -1106,7 +1466,7 @@ int op_channel_count(OggOpusFile *_of,int _li) OP_ARG_NONNULL(1);
|
|||
\retval #OP_EINVAL The source is not seekable (so we can't know the length),
|
||||
\a _li wasn't less than the total number of links in
|
||||
the stream, or the stream was only partially open.*/
|
||||
opus_int64 op_raw_total(OggOpusFile *_of,int _li) OP_ARG_NONNULL(1);
|
||||
opus_int64 op_raw_total(const OggOpusFile *_of,int _li) OP_ARG_NONNULL(1);
|
||||
|
||||
/**Get the total PCM length (number of samples at 48 kHz) of the stream, or of
|
||||
an individual link in a (possibly-chained) Ogg Opus stream.
|
||||
|
@ -1124,7 +1484,7 @@ opus_int64 op_raw_total(OggOpusFile *_of,int _li) OP_ARG_NONNULL(1);
|
|||
\retval #OP_EINVAL The source is not seekable (so we can't know the length),
|
||||
\a _li wasn't less than the total number of links in
|
||||
the stream, or the stream was only partially open.*/
|
||||
ogg_int64_t op_pcm_total(OggOpusFile *_of,int _li) OP_ARG_NONNULL(1);
|
||||
ogg_int64_t op_pcm_total(const OggOpusFile *_of,int _li) OP_ARG_NONNULL(1);
|
||||
|
||||
/**Get the ID header information for the given link in a (possibly chained) Ogg
|
||||
Opus stream.
|
||||
|
@ -1140,7 +1500,7 @@ ogg_int64_t op_pcm_total(OggOpusFile *_of,int _li) OP_ARG_NONNULL(1);
|
|||
information for the current link is always returned, if
|
||||
available.
|
||||
\return The contents of the ID header for the given link.*/
|
||||
const OpusHead *op_head(OggOpusFile *_of,int _li) OP_ARG_NONNULL(1);
|
||||
const OpusHead *op_head(const OggOpusFile *_of,int _li) OP_ARG_NONNULL(1);
|
||||
|
||||
/**Get the comment header information for the given link in a (possibly
|
||||
chained) Ogg Opus stream.
|
||||
|
@ -1158,7 +1518,7 @@ const OpusHead *op_head(OggOpusFile *_of,int _li) OP_ARG_NONNULL(1);
|
|||
\return The contents of the comment header for the given link, or
|
||||
<code>NULL</code> if this is an unseekable stream that encountered
|
||||
an invalid link.*/
|
||||
const OpusTags *op_tags(OggOpusFile *_of,int _li) OP_ARG_NONNULL(1);
|
||||
const OpusTags *op_tags(const OggOpusFile *_of,int _li) OP_ARG_NONNULL(1);
|
||||
|
||||
/**Retrieve the index of the current link.
|
||||
This is the link that produced the data most recently read by
|
||||
|
@ -1175,7 +1535,7 @@ const OpusTags *op_tags(OggOpusFile *_of,int _li) OP_ARG_NONNULL(1);
|
|||
each time a new link is encountered (even though op_link_count()
|
||||
always returns 1).
|
||||
\retval #OP_EINVAL The stream was only partially open.*/
|
||||
int op_current_link(OggOpusFile *_of) OP_ARG_NONNULL(1);
|
||||
int op_current_link(const OggOpusFile *_of) OP_ARG_NONNULL(1);
|
||||
|
||||
/**Computes the bitrate for a given link in a (possibly chained) Ogg Opus
|
||||
stream.
|
||||
|
@ -1188,7 +1548,7 @@ int op_current_link(OggOpusFile *_of) OP_ARG_NONNULL(1);
|
|||
\retval #OP_EINVAL The stream was only partially open, the stream was not
|
||||
seekable, or \a _li was larger than the number of
|
||||
links.*/
|
||||
opus_int32 op_bitrate(OggOpusFile *_of,int _li) OP_ARG_NONNULL(1);
|
||||
opus_int32 op_bitrate(const OggOpusFile *_of,int _li) OP_ARG_NONNULL(1);
|
||||
|
||||
/**Compute the instantaneous bitrate, measured as the ratio of bits to playable
|
||||
samples decoded since a) the last call to op_bitrate_instant(), b) the last
|
||||
|
@ -1207,7 +1567,7 @@ opus_int32 op_bitrate_instant(OggOpusFile *_of) OP_ARG_NONNULL(1);
|
|||
\param _of The \c OggOpusFile from which to retrieve the position indicator.
|
||||
\return The byte position that is currently being read from.
|
||||
\retval #OP_EINVAL The stream was only partially open.*/
|
||||
opus_int64 op_raw_tell(OggOpusFile *_of) OP_ARG_NONNULL(1);
|
||||
opus_int64 op_raw_tell(const OggOpusFile *_of) OP_ARG_NONNULL(1);
|
||||
|
||||
/**Obtain the PCM offset of the next sample to be read.
|
||||
If the stream is not properly timestamped, this might not increment by the
|
||||
|
@ -1216,7 +1576,7 @@ opus_int64 op_raw_tell(OggOpusFile *_of) OP_ARG_NONNULL(1);
|
|||
\param _of The \c OggOpusFile from which to retrieve the PCM offset.
|
||||
\return The PCM offset of the next sample to be read.
|
||||
\retval #OP_EINVAL The stream was only partially open.*/
|
||||
ogg_int64_t op_pcm_tell(OggOpusFile *_of) OP_ARG_NONNULL(1);
|
||||
ogg_int64_t op_pcm_tell(const OggOpusFile *_of) OP_ARG_NONNULL(1);
|
||||
|
||||
/*@}*/
|
||||
/*@}*/
|
||||
|
@ -1303,11 +1663,12 @@ int op_pcm_seek(OggOpusFile *_of,ogg_int64_t _pcm_offset) OP_ARG_NONNULL(1);
|
|||
clipping and other issues which might be avoided entirely if, e.g., you
|
||||
scale down the volume at some other stage.
|
||||
However, if you intend to direct consume 16-bit samples, the conversion in
|
||||
<tt>libopusfile</tt> provides noise-shaping dithering API.
|
||||
<tt>libopusfile</tt> provides noise-shaping dithering and, if compiled
|
||||
against <tt>libopus</tt> 1.1 or later, soft-clipping prevention.
|
||||
|
||||
<tt>libopusfile</tt> can also be configured at compile time to use the
|
||||
fixed-point <tt>libopus</tt> API.
|
||||
If so, the floating-point API may also be disabled.
|
||||
If so, <tt>libopusfile</tt>'s floating-point API may also be disabled.
|
||||
In that configuration, nothing in <tt>libopusfile</tt> will use any
|
||||
floating-point operations, to simplify support on devices without an
|
||||
adequate FPU.
|
||||
|
@ -1316,20 +1677,125 @@ int op_pcm_seek(OggOpusFile *_of,ogg_int64_t _pcm_offset) OP_ARG_NONNULL(1);
|
|||
not check the error return code from op_read_float() or its associated
|
||||
functions.
|
||||
If the remote peer does not close the connection gracefully (with a TLS
|
||||
"close notify" message), these functions will return OP_EREAD instead of 0
|
||||
"close notify" message), these functions will return #OP_EREAD instead of 0
|
||||
when they reach the end of the file.
|
||||
If you are reading from an <https:> URL (particularly if seeking is not
|
||||
supported), you should make sure to check for this error and warn the user
|
||||
appropriately.*/
|
||||
/*@{*/
|
||||
|
||||
/**Indicates that the decoding callback should produce signed 16-bit
|
||||
native-endian output samples.*/
|
||||
#define OP_DEC_FORMAT_SHORT (7008)
|
||||
/**Indicates that the decoding callback should produce 32-bit native-endian
|
||||
float samples.*/
|
||||
#define OP_DEC_FORMAT_FLOAT (7040)
|
||||
|
||||
/**Indicates that the decoding callback did not decode anything, and that
|
||||
<tt>libopusfile</tt> should decode normally instead.*/
|
||||
#define OP_DEC_USE_DEFAULT (6720)
|
||||
|
||||
/**Called to decode an Opus packet.
|
||||
This should invoke the functional equivalent of opus_multistream_decode() or
|
||||
opus_multistream_decode_float(), except that it returns 0 on success
|
||||
instead of the number of decoded samples (which is known a priori).
|
||||
\param _ctx The application-provided callback context.
|
||||
\param _decoder The decoder to use to decode the packet.
|
||||
\param[out] _pcm The buffer to decode into.
|
||||
This will always have enough room for \a _nchannels of
|
||||
\a _nsamples samples, which should be placed into this
|
||||
buffer interleaved.
|
||||
\param _op The packet to decode.
|
||||
This will always have its granule position set to a valid
|
||||
value.
|
||||
\param _nsamples The number of samples expected from the packet.
|
||||
\param _nchannels The number of channels expected from the packet.
|
||||
\param _format The desired sample output format.
|
||||
This is either #OP_DEC_FORMAT_SHORT or
|
||||
#OP_DEC_FORMAT_FLOAT.
|
||||
\param _li The index of the link from which this packet was decoded.
|
||||
\return A non-negative value on success, or a negative value on error.
|
||||
The error codes should be the same as those returned by
|
||||
opus_multistream_decode() or opus_multistream_decode_float().
|
||||
\retval 0 Decoding was successful.
|
||||
The application has filled the buffer with
|
||||
exactly <code>\a _nsamples*\a
|
||||
_nchannels</code> samples in the requested
|
||||
format.
|
||||
\retval #OP_DEC_USE_DEFAULT No decoding was done.
|
||||
<tt>libopusfile</tt> should decode normally
|
||||
instead.*/
|
||||
typedef int (*op_decode_cb_func)(void *_ctx,OpusMSDecoder *_decoder,void *_pcm,
|
||||
const ogg_packet *_op,int _nsamples,int _nchannels,int _format,int _li);
|
||||
|
||||
/**Sets the packet decode callback function.
|
||||
This is called once for each packet that needs to be decoded.
|
||||
A call to this function is no guarantee that the audio will eventually be
|
||||
delivered to the application.
|
||||
Some or all of the data from the packet may be discarded (i.e., at the
|
||||
beginning or end of a link, or after a seek), however the callback is
|
||||
required to provide all of it.
|
||||
\param _of The \c OggOpusFile on which to set the decode callback.
|
||||
\param _decode_cb The callback function to call.
|
||||
This may be <code>NULL</code> to disable calling the
|
||||
callback.
|
||||
\param _ctx The application-provided context pointer to pass to the
|
||||
callback on each call.*/
|
||||
void op_set_decode_callback(OggOpusFile *_of,
|
||||
op_decode_cb_func _decode_cb,void *_ctx) OP_ARG_NONNULL(1);
|
||||
|
||||
/**Gain offset type that indicates that the provided offset is relative to the
|
||||
header gain.
|
||||
This is the default.*/
|
||||
#define OP_HEADER_GAIN (0)
|
||||
|
||||
/**Gain offset type that indicates that the provided offset is relative to the
|
||||
R128_TRACK_GAIN value (if any), in addition to the header gain.*/
|
||||
#define OP_TRACK_GAIN (3008)
|
||||
|
||||
/**Gain offset type that indicates that the provided offset should be used as
|
||||
the gain directly, without applying any the header or track gains.*/
|
||||
#define OP_ABSOLUTE_GAIN (3009)
|
||||
|
||||
/**Sets the gain to be used for decoded output.
|
||||
By default, the gain in the header is applied with no additional offset.
|
||||
The total gain (including header gain and/or track gain, if applicable, and
|
||||
this offset), will be clamped to [-32768,32767]/256 dB.
|
||||
This is more than enough to saturate or underflow 16-bit PCM.
|
||||
\note The new gain will not be applied to any already buffered, decoded
|
||||
output.
|
||||
This means you cannot change it sample-by-sample, as at best it will be
|
||||
updated packet-by-packet.
|
||||
It is meant for setting a target volume level, rather than applying smooth
|
||||
fades, etc.
|
||||
\param _of The \c OggOpusFile on which to set the gain offset.
|
||||
\param _gain_type One of #OP_HEADER_GAIN, #OP_TRACK_GAIN, or
|
||||
#OP_ABSOLUTE_GAIN.
|
||||
\param _gain_offset_q8 The gain offset to apply, in 1/256ths of a dB.
|
||||
\return 0 on success or a negative value on error.
|
||||
\retval #OP_EINVAL The \a _gain_type was unrecognized.*/
|
||||
int op_set_gain_offset(OggOpusFile *_of,
|
||||
int _gain_type,opus_int32 _gain_offset_q8) OP_ARG_NONNULL(1);
|
||||
|
||||
/**Sets whether or not dithering is enabled for 16-bit decoding.
|
||||
By default, when <tt>libopusfile</tt> is compiled to use floating-point
|
||||
internally, calling op_read() or op_read_stereo() will first decode to
|
||||
float, and then convert to fixed-point using noise-shaping dithering.
|
||||
This flag can be used to disable that dithering.
|
||||
When the application uses op_read_float() or op_read_float_stereo(), or when
|
||||
the library has been compiled to decode directly to fixed point, this flag
|
||||
has no effect.
|
||||
\param _of The \c OggOpusFile on which to enable or disable dithering.
|
||||
\param _enabled A non-zero value to enable dithering, or 0 to disable it.*/
|
||||
void op_set_dither_enabled(OggOpusFile *_of,int _enabled) OP_ARG_NONNULL(1);
|
||||
|
||||
/**Reads more samples from the stream.
|
||||
\note Although \a _buf_size must indicate the total number of values that
|
||||
can be stored in \a _pcm, the return value is the number of samples
|
||||
<em>per channel</em>.
|
||||
This is done because
|
||||
<ol>
|
||||
<li>The channel count cannot be known a prior (reading more samples might
|
||||
<li>The channel count cannot be known a priori (reading more samples might
|
||||
advance us into the next link, with a different channel count), so
|
||||
\a _buf_size cannot also be in units of samples per channel,</li>
|
||||
<li>Returning the samples per channel matches the <code>libopus</code> API
|
||||
|
@ -1346,14 +1812,14 @@ int op_pcm_seek(OggOpusFile *_of,ogg_int64_t _pcm_offset) OP_ARG_NONNULL(1);
|
|||
</ol>
|
||||
\param _of The \c OggOpusFile from which to read.
|
||||
\param[out] _pcm A buffer in which to store the output PCM samples, as
|
||||
signed native-endian 16-bit values with a nominal
|
||||
range of <code>[-32768,32767)</code>.
|
||||
signed native-endian 16-bit values at 48 kHz
|
||||
with a nominal range of <code>[-32768,32767)</code>.
|
||||
Multiple channels are interleaved using the
|
||||
<a href="http://www.xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-800004.3.9">Vorbis
|
||||
channel ordering</a>.
|
||||
This must have room for at least \a _buf_size values.
|
||||
\param _buf_size The number of values that can be stored in \a _pcm.
|
||||
It is reccommended that this be large enough for at
|
||||
It is recommended that this be large enough for at
|
||||
least 120 ms of data at 48 kHz per channel (5760
|
||||
values per channel).
|
||||
Smaller buffers will simply return less data, possibly
|
||||
|
@ -1411,7 +1877,7 @@ OP_WARN_UNUSED_RESULT int op_read(OggOpusFile *_of,
|
|||
can be stored in \a _pcm, the return value is the number of samples
|
||||
<em>per channel</em>.
|
||||
<ol>
|
||||
<li>The channel count cannot be known a prior (reading more samples might
|
||||
<li>The channel count cannot be known a priori (reading more samples might
|
||||
advance us into the next link, with a different channel count), so
|
||||
\a _buf_size cannot also be in units of samples per channel,</li>
|
||||
<li>Returning the samples per channel matches the <code>libopus</code> API
|
||||
|
@ -1428,14 +1894,14 @@ OP_WARN_UNUSED_RESULT int op_read(OggOpusFile *_of,
|
|||
</ol>
|
||||
\param _of The \c OggOpusFile from which to read.
|
||||
\param[out] _pcm A buffer in which to store the output PCM samples as
|
||||
signed floats with a nominal range of
|
||||
signed floats at 48 kHz with a nominal range of
|
||||
<code>[-1.0,1.0]</code>.
|
||||
Multiple channels are interleaved using the
|
||||
<a href="http://www.xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-800004.3.9">Vorbis
|
||||
channel ordering</a>.
|
||||
This must have room for at least \a _buf_size floats.
|
||||
\param _buf_size The number of floats that can be stored in \a _pcm.
|
||||
It is reccommended that this be large enough for at
|
||||
It is recommended that this be large enough for at
|
||||
least 120 ms of data at 48 kHz per channel (5760
|
||||
samples per channel).
|
||||
Smaller buffers will simply return less data, possibly
|
||||
|
@ -1497,13 +1963,13 @@ OP_WARN_UNUSED_RESULT int op_read_float(OggOpusFile *_of,
|
|||
op_read().
|
||||
\param _of The \c OggOpusFile from which to read.
|
||||
\param[out] _pcm A buffer in which to store the output PCM samples, as
|
||||
signed native-endian 16-bit values with a nominal
|
||||
range of <code>[-32768,32767)</code>.
|
||||
signed native-endian 16-bit values at 48 kHz
|
||||
with a nominal range of <code>[-32768,32767)</code>.
|
||||
The left and right channels are interleaved in the
|
||||
buffer.
|
||||
This must have room for at least \a _buf_size values.
|
||||
\param _buf_size The number of values that can be stored in \a _pcm.
|
||||
It is reccommended that this be large enough for at
|
||||
It is recommended that this be large enough for at
|
||||
least 120 ms of data at 48 kHz per channel (11520
|
||||
values total).
|
||||
Smaller buffers will simply return less data, possibly
|
||||
|
@ -1558,13 +2024,13 @@ OP_WARN_UNUSED_RESULT int op_read_stereo(OggOpusFile *_of,
|
|||
op_read_float().
|
||||
\param _of The \c OggOpusFile from which to read.
|
||||
\param[out] _pcm A buffer in which to store the output PCM samples, as
|
||||
signed floats with a nominal range of
|
||||
signed floats at 48 kHz with a nominal range of
|
||||
<code>[-1.0,1.0]</code>.
|
||||
The left and right channels are interleaved in the
|
||||
buffer.
|
||||
This must have room for at least \a _buf_size values.
|
||||
\param _buf_size The number of values that can be stored in \a _pcm.
|
||||
It is reccommended that this be large enough for at
|
||||
It is recommended that this be large enough for at
|
||||
least 120 ms of data at 48 kHz per channel (11520
|
||||
values total).
|
||||
Smaller buffers will simply return less data, possibly
|
File diff suppressed because it is too large
Load diff
683
code/opusfile-0.5/src/info.c
Normal file
683
code/opusfile-0.5/src/info.c
Normal file
|
@ -0,0 +1,683 @@
|
|||
/********************************************************************
|
||||
* *
|
||||
* THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. *
|
||||
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||
* *
|
||||
* THE libopusfile SOURCE CODE IS (C) COPYRIGHT 2012 *
|
||||
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "internal.h"
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
|
||||
static unsigned op_parse_uint16le(const unsigned char *_data){
|
||||
return _data[0]|_data[1]<<8;
|
||||
}
|
||||
|
||||
static int op_parse_int16le(const unsigned char *_data){
|
||||
int ret;
|
||||
ret=_data[0]|_data[1]<<8;
|
||||
return (ret^0x8000)-0x8000;
|
||||
}
|
||||
|
||||
static opus_uint32 op_parse_uint32le(const unsigned char *_data){
|
||||
return _data[0]|_data[1]<<8|_data[2]<<16|_data[3]<<24;
|
||||
}
|
||||
|
||||
static opus_uint32 op_parse_uint32be(const unsigned char *_data){
|
||||
return _data[3]|_data[2]<<8|_data[1]<<16|_data[0]<<24;
|
||||
}
|
||||
|
||||
int opus_head_parse(OpusHead *_head,const unsigned char *_data,size_t _len){
|
||||
OpusHead head;
|
||||
if(_len<8)return OP_ENOTFORMAT;
|
||||
if(memcmp(_data,"OpusHead",8)!=0)return OP_ENOTFORMAT;
|
||||
if(_len<9)return OP_EBADHEADER;
|
||||
head.version=_data[8];
|
||||
if(head.version>15)return OP_EVERSION;
|
||||
if(_len<19)return OP_EBADHEADER;
|
||||
head.channel_count=_data[9];
|
||||
head.pre_skip=op_parse_uint16le(_data+10);
|
||||
head.input_sample_rate=op_parse_uint32le(_data+12);
|
||||
head.output_gain=op_parse_int16le(_data+16);
|
||||
head.mapping_family=_data[18];
|
||||
if(head.mapping_family==0){
|
||||
if(head.channel_count<1||head.channel_count>2)return OP_EBADHEADER;
|
||||
if(head.version<=1&&_len>19)return OP_EBADHEADER;
|
||||
head.stream_count=1;
|
||||
head.coupled_count=head.channel_count-1;
|
||||
if(_head!=NULL){
|
||||
_head->mapping[0]=0;
|
||||
_head->mapping[1]=1;
|
||||
}
|
||||
}
|
||||
else if(head.mapping_family==1){
|
||||
size_t size;
|
||||
int ci;
|
||||
if(head.channel_count<1||head.channel_count>8)return OP_EBADHEADER;
|
||||
size=21+head.channel_count;
|
||||
if(_len<size||head.version<=1&&_len>size)return OP_EBADHEADER;
|
||||
head.stream_count=_data[19];
|
||||
if(head.stream_count<1)return OP_EBADHEADER;
|
||||
head.coupled_count=_data[20];
|
||||
if(head.coupled_count>head.stream_count)return OP_EBADHEADER;
|
||||
for(ci=0;ci<head.channel_count;ci++){
|
||||
if(_data[21+ci]>=head.stream_count+head.coupled_count
|
||||
&&_data[21+ci]!=255){
|
||||
return OP_EBADHEADER;
|
||||
}
|
||||
}
|
||||
if(_head!=NULL)memcpy(_head->mapping,_data+21,head.channel_count);
|
||||
}
|
||||
/*General purpose players should not attempt to play back content with
|
||||
channel mapping family 255.*/
|
||||
else if(head.mapping_family==255)return OP_EIMPL;
|
||||
/*No other channel mapping families are currently defined.*/
|
||||
else return OP_EBADHEADER;
|
||||
if(_head!=NULL)memcpy(_head,&head,head.mapping-(unsigned char *)&head);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void opus_tags_init(OpusTags *_tags){
|
||||
memset(_tags,0,sizeof(*_tags));
|
||||
}
|
||||
|
||||
void opus_tags_clear(OpusTags *_tags){
|
||||
int ci;
|
||||
for(ci=_tags->comments;ci-->0;)_ogg_free(_tags->user_comments[ci]);
|
||||
_ogg_free(_tags->user_comments);
|
||||
_ogg_free(_tags->comment_lengths);
|
||||
_ogg_free(_tags->vendor);
|
||||
}
|
||||
|
||||
/*Ensure there's room for up to _ncomments comments.*/
|
||||
static int op_tags_ensure_capacity(OpusTags *_tags,size_t _ncomments){
|
||||
char **user_comments;
|
||||
int *comment_lengths;
|
||||
size_t size;
|
||||
if(OP_UNLIKELY(_ncomments>=(size_t)INT_MAX))return OP_EFAULT;
|
||||
size=sizeof(*_tags->comment_lengths)*(_ncomments+1);
|
||||
if(size/sizeof(*_tags->comment_lengths)!=_ncomments+1)return OP_EFAULT;
|
||||
comment_lengths=(int *)_ogg_realloc(_tags->comment_lengths,size);
|
||||
if(OP_UNLIKELY(comment_lengths==NULL))return OP_EFAULT;
|
||||
comment_lengths[_ncomments]=0;
|
||||
_tags->comment_lengths=comment_lengths;
|
||||
size=sizeof(*_tags->user_comments)*(_ncomments+1);
|
||||
if(size/sizeof(*_tags->user_comments)!=_ncomments+1)return OP_EFAULT;
|
||||
user_comments=(char **)_ogg_realloc(_tags->user_comments,size);
|
||||
if(OP_UNLIKELY(user_comments==NULL))return OP_EFAULT;
|
||||
user_comments[_ncomments]=NULL;
|
||||
_tags->user_comments=user_comments;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*Duplicate a (possibly non-NUL terminated) string with a known length.*/
|
||||
static char *op_strdup_with_len(const char *_s,size_t _len){
|
||||
size_t size;
|
||||
char *ret;
|
||||
size=sizeof(*ret)*(_len+1);
|
||||
if(OP_UNLIKELY(size<_len))return NULL;
|
||||
ret=(char *)_ogg_malloc(size);
|
||||
if(OP_LIKELY(ret!=NULL)){
|
||||
ret=(char *)memcpy(ret,_s,sizeof(*ret)*_len);
|
||||
ret[_len]='\0';
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*The actual implementation of opus_tags_parse().
|
||||
Unlike the public API, this function requires _tags to already be
|
||||
initialized, modifies its contents before success is guaranteed, and assumes
|
||||
the caller will clear it on error.*/
|
||||
static int opus_tags_parse_impl(OpusTags *_tags,
|
||||
const unsigned char *_data,size_t _len){
|
||||
opus_uint32 count;
|
||||
size_t len;
|
||||
int ncomments;
|
||||
int ci;
|
||||
len=_len;
|
||||
if(len<8)return OP_ENOTFORMAT;
|
||||
if(memcmp(_data,"OpusTags",8)!=0)return OP_ENOTFORMAT;
|
||||
if(len<16)return OP_EBADHEADER;
|
||||
_data+=8;
|
||||
len-=8;
|
||||
count=op_parse_uint32le(_data);
|
||||
_data+=4;
|
||||
len-=4;
|
||||
if(count>len)return OP_EBADHEADER;
|
||||
if(_tags!=NULL){
|
||||
_tags->vendor=op_strdup_with_len((char *)_data,count);
|
||||
if(_tags->vendor==NULL)return OP_EFAULT;
|
||||
}
|
||||
_data+=count;
|
||||
len-=count;
|
||||
if(len<4)return OP_EBADHEADER;
|
||||
count=op_parse_uint32le(_data);
|
||||
_data+=4;
|
||||
len-=4;
|
||||
/*Check to make sure there's minimally sufficient data left in the packet.*/
|
||||
if(count>len>>2)return OP_EBADHEADER;
|
||||
/*Check for overflow (the API limits this to an int).*/
|
||||
if(count>(opus_uint32)INT_MAX-1)return OP_EFAULT;
|
||||
if(_tags!=NULL){
|
||||
int ret;
|
||||
ret=op_tags_ensure_capacity(_tags,count);
|
||||
if(ret<0)return ret;
|
||||
}
|
||||
ncomments=(int)count;
|
||||
for(ci=0;ci<ncomments;ci++){
|
||||
/*Check to make sure there's minimally sufficient data left in the packet.*/
|
||||
if((size_t)(ncomments-ci)>len>>2)return OP_EBADHEADER;
|
||||
count=op_parse_uint32le(_data);
|
||||
_data+=4;
|
||||
len-=4;
|
||||
if(count>len)return OP_EBADHEADER;
|
||||
/*Check for overflow (the API limits this to an int).*/
|
||||
if(count>(opus_uint32)INT_MAX)return OP_EFAULT;
|
||||
if(_tags!=NULL){
|
||||
_tags->user_comments[ci]=op_strdup_with_len((char *)_data,count);
|
||||
if(_tags->user_comments[ci]==NULL)return OP_EFAULT;
|
||||
_tags->comment_lengths[ci]=(int)count;
|
||||
_tags->comments=ci+1;
|
||||
}
|
||||
_data+=count;
|
||||
len-=count;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int opus_tags_parse(OpusTags *_tags,const unsigned char *_data,size_t _len){
|
||||
if(_tags!=NULL){
|
||||
OpusTags tags;
|
||||
int ret;
|
||||
opus_tags_init(&tags);
|
||||
ret=opus_tags_parse_impl(&tags,_data,_len);
|
||||
if(ret<0)opus_tags_clear(&tags);
|
||||
else *_tags=*&tags;
|
||||
return ret;
|
||||
}
|
||||
else return opus_tags_parse_impl(NULL,_data,_len);
|
||||
}
|
||||
|
||||
/*The actual implementation of opus_tags_copy().
|
||||
Unlike the public API, this function requires _dst to already be
|
||||
initialized, modifies its contents before success is guaranteed, and assumes
|
||||
the caller will clear it on error.*/
|
||||
static int opus_tags_copy_impl(OpusTags *_dst,const OpusTags *_src){
|
||||
char *vendor;
|
||||
int ncomments;
|
||||
int ret;
|
||||
int ci;
|
||||
vendor=_src->vendor;
|
||||
_dst->vendor=op_strdup_with_len(vendor,strlen(vendor));
|
||||
if(OP_UNLIKELY(_dst->vendor==NULL))return OP_EFAULT;
|
||||
ncomments=_src->comments;
|
||||
ret=op_tags_ensure_capacity(_dst,ncomments);
|
||||
if(OP_UNLIKELY(ret<0))return ret;
|
||||
for(ci=0;ci<ncomments;ci++){
|
||||
int len;
|
||||
len=_src->comment_lengths[ci];
|
||||
OP_ASSERT(len>=0);
|
||||
_dst->user_comments[ci]=op_strdup_with_len(_src->user_comments[ci],len);
|
||||
if(OP_UNLIKELY(_dst->user_comments[ci]==NULL))return OP_EFAULT;
|
||||
_dst->comment_lengths[ci]=len;
|
||||
_dst->comments=ci+1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int opus_tags_copy(OpusTags *_dst,const OpusTags *_src){
|
||||
OpusTags dst;
|
||||
int ret;
|
||||
opus_tags_init(&dst);
|
||||
ret=opus_tags_copy_impl(&dst,_src);
|
||||
if(OP_UNLIKELY(ret<0))opus_tags_clear(&dst);
|
||||
else *_dst=*&dst;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int opus_tags_add(OpusTags *_tags,const char *_tag,const char *_value){
|
||||
char *comment;
|
||||
int tag_len;
|
||||
int value_len;
|
||||
int ncomments;
|
||||
int ret;
|
||||
ncomments=_tags->comments;
|
||||
ret=op_tags_ensure_capacity(_tags,ncomments+1);
|
||||
if(OP_UNLIKELY(ret<0))return ret;
|
||||
tag_len=strlen(_tag);
|
||||
value_len=strlen(_value);
|
||||
/*+2 for '=' and '\0'.*/
|
||||
_tags->comment_lengths[ncomments]=0;
|
||||
_tags->user_comments[ncomments]=comment=
|
||||
(char *)_ogg_malloc(sizeof(*comment)*(tag_len+value_len+2));
|
||||
if(OP_UNLIKELY(comment==NULL))return OP_EFAULT;
|
||||
_tags->comment_lengths[ncomments]=tag_len+value_len+1;
|
||||
memcpy(comment,_tag,sizeof(*comment)*tag_len);
|
||||
comment[tag_len]='=';
|
||||
memcpy(comment+tag_len+1,_value,sizeof(*comment)*(value_len+1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int opus_tags_add_comment(OpusTags *_tags,const char *_comment){
|
||||
int comment_len;
|
||||
int ncomments;
|
||||
int ret;
|
||||
ncomments=_tags->comments;
|
||||
ret=op_tags_ensure_capacity(_tags,ncomments+1);
|
||||
if(OP_UNLIKELY(ret<0))return ret;
|
||||
comment_len=(int)strlen(_comment);
|
||||
_tags->comment_lengths[ncomments]=0;
|
||||
_tags->user_comments[ncomments]=op_strdup_with_len(_comment,comment_len);
|
||||
if(OP_UNLIKELY(_tags->user_comments[ncomments]==NULL))return OP_EFAULT;
|
||||
_tags->comment_lengths[ncomments]=comment_len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int opus_tagcompare(const char *_tag_name,const char *_comment){
|
||||
return opus_tagncompare(_tag_name,strlen(_tag_name),_comment);
|
||||
}
|
||||
|
||||
int opus_tagncompare(const char *_tag_name,int _tag_len,const char *_comment){
|
||||
int ret;
|
||||
OP_ASSERT(_tag_len>=0);
|
||||
ret=op_strncasecmp(_tag_name,_comment,_tag_len);
|
||||
return ret?ret:'='-_comment[_tag_len];
|
||||
}
|
||||
|
||||
const char *opus_tags_query(const OpusTags *_tags,const char *_tag,int _count){
|
||||
char **user_comments;
|
||||
int tag_len;
|
||||
int found;
|
||||
int ncomments;
|
||||
int ci;
|
||||
tag_len=strlen(_tag);
|
||||
ncomments=_tags->comments;
|
||||
user_comments=_tags->user_comments;
|
||||
found=0;
|
||||
for(ci=0;ci<ncomments;ci++){
|
||||
if(!opus_tagncompare(_tag,tag_len,user_comments[ci])){
|
||||
/*We return a pointer to the data, not a copy.*/
|
||||
if(_count==found++)return user_comments[ci]+tag_len+1;
|
||||
}
|
||||
}
|
||||
/*Didn't find anything.*/
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int opus_tags_query_count(const OpusTags *_tags,const char *_tag){
|
||||
char **user_comments;
|
||||
int tag_len;
|
||||
int found;
|
||||
int ncomments;
|
||||
int ci;
|
||||
tag_len=strlen(_tag);
|
||||
ncomments=_tags->comments;
|
||||
user_comments=_tags->user_comments;
|
||||
found=0;
|
||||
for(ci=0;ci<ncomments;ci++){
|
||||
if(!opus_tagncompare(_tag,tag_len,user_comments[ci]))found++;
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
int opus_tags_get_track_gain(const OpusTags *_tags,int *_gain_q8){
|
||||
char **comments;
|
||||
int ncomments;
|
||||
int ci;
|
||||
comments=_tags->user_comments;
|
||||
ncomments=_tags->comments;
|
||||
/*Look for the first valid R128_TRACK_GAIN tag and use that.*/
|
||||
for(ci=0;ci<ncomments;ci++){
|
||||
if(opus_tagncompare("R128_TRACK_GAIN",15,comments[ci])==0){
|
||||
char *p;
|
||||
opus_int32 gain_q8;
|
||||
int negative;
|
||||
p=comments[ci]+16;
|
||||
negative=0;
|
||||
if(*p=='-'){
|
||||
negative=-1;
|
||||
p++;
|
||||
}
|
||||
else if(*p=='+')p++;
|
||||
gain_q8=0;
|
||||
while(*p>='0'&&*p<='9'){
|
||||
gain_q8=10*gain_q8+*p-'0';
|
||||
if(gain_q8>32767-negative)break;
|
||||
p++;
|
||||
}
|
||||
/*This didn't look like a signed 16-bit decimal integer.
|
||||
Not a valid R128_TRACK_GAIN tag.*/
|
||||
if(*p!='\0')continue;
|
||||
*_gain_q8=(int)(gain_q8+negative^negative);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return OP_FALSE;
|
||||
}
|
||||
|
||||
static int op_is_jpeg(const unsigned char *_buf,size_t _buf_sz){
|
||||
return _buf_sz>=11&&memcmp(_buf,"\xFF\xD8\xFF\xE0",4)==0
|
||||
&&(_buf[4]<<8|_buf[5])>=16&&memcmp(_buf+6,"JFIF",5)==0;
|
||||
}
|
||||
|
||||
/*Tries to extract the width, height, bits per pixel, and palette size of a
|
||||
JPEG.
|
||||
On failure, simply leaves its outputs unmodified.*/
|
||||
static void op_extract_jpeg_params(const unsigned char *_buf,size_t _buf_sz,
|
||||
opus_uint32 *_width,opus_uint32 *_height,
|
||||
opus_uint32 *_depth,opus_uint32 *_colors,int *_has_palette){
|
||||
if(op_is_jpeg(_buf,_buf_sz)){
|
||||
size_t offs;
|
||||
offs=2;
|
||||
for(;;){
|
||||
size_t segment_len;
|
||||
int marker;
|
||||
while(offs<_buf_sz&&_buf[offs]!=0xFF)offs++;
|
||||
while(offs<_buf_sz&&_buf[offs]==0xFF)offs++;
|
||||
marker=_buf[offs];
|
||||
offs++;
|
||||
/*If we hit EOI* (end of image), or another SOI* (start of image),
|
||||
or SOS (start of scan), then stop now.*/
|
||||
if(offs>=_buf_sz||(marker>=0xD8&&marker<=0xDA))break;
|
||||
/*RST* (restart markers): skip (no segment length).*/
|
||||
else if(marker>=0xD0&&marker<=0xD7)continue;
|
||||
/*Read the length of the marker segment.*/
|
||||
if(_buf_sz-offs<2)break;
|
||||
segment_len=_buf[offs]<<8|_buf[offs+1];
|
||||
if(segment_len<2||_buf_sz-offs<segment_len)break;
|
||||
if(marker==0xC0||(marker>0xC0&&marker<0xD0&&(marker&3)!=0)){
|
||||
/*Found a SOFn (start of frame) marker segment:*/
|
||||
if(segment_len>=8){
|
||||
*_height=_buf[offs+3]<<8|_buf[offs+4];
|
||||
*_width=_buf[offs+5]<<8|_buf[offs+6];
|
||||
*_depth=_buf[offs+2]*_buf[offs+7];
|
||||
*_colors=0;
|
||||
*_has_palette=0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
/*Other markers: skip the whole marker segment.*/
|
||||
offs+=segment_len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int op_is_png(const unsigned char *_buf,size_t _buf_sz){
|
||||
return _buf_sz>=8&&memcmp(_buf,"\x89PNG\x0D\x0A\x1A\x0A",8)==0;
|
||||
}
|
||||
|
||||
/*Tries to extract the width, height, bits per pixel, and palette size of a
|
||||
PNG.
|
||||
On failure, simply leaves its outputs unmodified.*/
|
||||
static void op_extract_png_params(const unsigned char *_buf,size_t _buf_sz,
|
||||
opus_uint32 *_width,opus_uint32 *_height,
|
||||
opus_uint32 *_depth,opus_uint32 *_colors,int *_has_palette){
|
||||
if(op_is_png(_buf,_buf_sz)){
|
||||
size_t offs;
|
||||
offs=8;
|
||||
while(_buf_sz-offs>=12){
|
||||
ogg_uint32_t chunk_len;
|
||||
chunk_len=op_parse_uint32be(_buf+offs);
|
||||
if(chunk_len>_buf_sz-(offs+12))break;
|
||||
else if(chunk_len==13&&memcmp(_buf+offs+4,"IHDR",4)==0){
|
||||
int color_type;
|
||||
*_width=op_parse_uint32be(_buf+offs+8);
|
||||
*_height=op_parse_uint32be(_buf+offs+12);
|
||||
color_type=_buf[offs+17];
|
||||
if(color_type==3){
|
||||
*_depth=24;
|
||||
*_has_palette=1;
|
||||
}
|
||||
else{
|
||||
int sample_depth;
|
||||
sample_depth=_buf[offs+16];
|
||||
if(color_type==0)*_depth=sample_depth;
|
||||
else if(color_type==2)*_depth=sample_depth*3;
|
||||
else if(color_type==4)*_depth=sample_depth*2;
|
||||
else if(color_type==6)*_depth=sample_depth*4;
|
||||
*_colors=0;
|
||||
*_has_palette=0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if(*_has_palette>0&&memcmp(_buf+offs+4,"PLTE",4)==0){
|
||||
*_colors=chunk_len/3;
|
||||
break;
|
||||
}
|
||||
offs+=12+chunk_len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int op_is_gif(const unsigned char *_buf,size_t _buf_sz){
|
||||
return _buf_sz>=6&&(memcmp(_buf,"GIF87a",6)==0||memcmp(_buf,"GIF89a",6)==0);
|
||||
}
|
||||
|
||||
/*Tries to extract the width, height, bits per pixel, and palette size of a
|
||||
GIF.
|
||||
On failure, simply leaves its outputs unmodified.*/
|
||||
static void op_extract_gif_params(const unsigned char *_buf,size_t _buf_sz,
|
||||
opus_uint32 *_width,opus_uint32 *_height,
|
||||
opus_uint32 *_depth,opus_uint32 *_colors,int *_has_palette){
|
||||
if(op_is_gif(_buf,_buf_sz)&&_buf_sz>=14){
|
||||
*_width=_buf[6]|_buf[7]<<8;
|
||||
*_height=_buf[8]|_buf[9]<<8;
|
||||
/*libFLAC hard-codes the depth to 24.*/
|
||||
*_depth=24;
|
||||
*_colors=1<<((_buf[10]&7)+1);
|
||||
*_has_palette=1;
|
||||
}
|
||||
}
|
||||
|
||||
/*The actual implementation of opus_picture_tag_parse().
|
||||
Unlike the public API, this function requires _pic to already be
|
||||
initialized, modifies its contents before success is guaranteed, and assumes
|
||||
the caller will clear it on error.*/
|
||||
static int opus_picture_tag_parse_impl(OpusPictureTag *_pic,const char *_tag,
|
||||
unsigned char *_buf,size_t _buf_sz,size_t _base64_sz){
|
||||
opus_int32 picture_type;
|
||||
opus_uint32 mime_type_length;
|
||||
char *mime_type;
|
||||
opus_uint32 description_length;
|
||||
char *description;
|
||||
opus_uint32 width;
|
||||
opus_uint32 height;
|
||||
opus_uint32 depth;
|
||||
opus_uint32 colors;
|
||||
opus_uint32 data_length;
|
||||
opus_uint32 file_width;
|
||||
opus_uint32 file_height;
|
||||
opus_uint32 file_depth;
|
||||
opus_uint32 file_colors;
|
||||
int format;
|
||||
int has_palette;
|
||||
int colors_set;
|
||||
size_t i;
|
||||
/*Decode the BASE64 data.*/
|
||||
for(i=0;i<_base64_sz;i++){
|
||||
opus_uint32 value;
|
||||
int j;
|
||||
value=0;
|
||||
for(j=0;j<4;j++){
|
||||
unsigned c;
|
||||
unsigned d;
|
||||
c=(unsigned char)_tag[4*i+j];
|
||||
if(c=='+')d=62;
|
||||
else if(c=='/')d=63;
|
||||
else if(c>='0'&&c<='9')d=52+c-'0';
|
||||
else if(c>='a'&&c<='z')d=26+c-'a';
|
||||
else if(c>='A'&&c<='Z')d=c-'A';
|
||||
else if(c=='='&&3*i+j>_buf_sz)d=0;
|
||||
else return OP_ENOTFORMAT;
|
||||
value=value<<6|d;
|
||||
}
|
||||
_buf[3*i]=(unsigned char)(value>>16);
|
||||
if(3*i+1<_buf_sz){
|
||||
_buf[3*i+1]=(unsigned char)(value>>8);
|
||||
if(3*i+2<_buf_sz)_buf[3*i+2]=(unsigned char)value;
|
||||
}
|
||||
}
|
||||
i=0;
|
||||
picture_type=op_parse_uint32be(_buf+i);
|
||||
i+=4;
|
||||
/*Extract the MIME type.*/
|
||||
mime_type_length=op_parse_uint32be(_buf+i);
|
||||
i+=4;
|
||||
if(mime_type_length>_buf_sz-32)return OP_ENOTFORMAT;
|
||||
mime_type=(char *)_ogg_malloc(sizeof(*_pic->mime_type)*(mime_type_length+1));
|
||||
if(mime_type==NULL)return OP_EFAULT;
|
||||
memcpy(mime_type,_buf+i,sizeof(*mime_type)*mime_type_length);
|
||||
mime_type[mime_type_length]='\0';
|
||||
_pic->mime_type=mime_type;
|
||||
i+=mime_type_length;
|
||||
/*Extract the description string.*/
|
||||
description_length=op_parse_uint32be(_buf+i);
|
||||
i+=4;
|
||||
if(description_length>_buf_sz-mime_type_length-32)return OP_ENOTFORMAT;
|
||||
description=
|
||||
(char *)_ogg_malloc(sizeof(*_pic->mime_type)*(description_length+1));
|
||||
if(description==NULL)return OP_EFAULT;
|
||||
memcpy(description,_buf+i,sizeof(*description)*description_length);
|
||||
description[description_length]='\0';
|
||||
_pic->description=description;
|
||||
i+=description_length;
|
||||
/*Extract the remaining fields.*/
|
||||
width=op_parse_uint32be(_buf+i);
|
||||
i+=4;
|
||||
height=op_parse_uint32be(_buf+i);
|
||||
i+=4;
|
||||
depth=op_parse_uint32be(_buf+i);
|
||||
i+=4;
|
||||
colors=op_parse_uint32be(_buf+i);
|
||||
i+=4;
|
||||
/*If one of these is set, they all must be, but colors==0 is a valid value.*/
|
||||
colors_set=width!=0||height!=0||depth!=0||colors!=0;
|
||||
if(width==0||height==0||depth==0&&colors_set)return OP_ENOTFORMAT;
|
||||
data_length=op_parse_uint32be(_buf+i);
|
||||
i+=4;
|
||||
if(data_length>_buf_sz-i)return OP_ENOTFORMAT;
|
||||
/*Trim extraneous data so we don't copy it below.*/
|
||||
_buf_sz=i+data_length;
|
||||
/*Attempt to determine the image format.*/
|
||||
format=OP_PIC_FORMAT_UNKNOWN;
|
||||
if(mime_type_length==3&&strcmp(mime_type,"-->")==0){
|
||||
format=OP_PIC_FORMAT_URL;
|
||||
/*Picture type 1 must be a 32x32 PNG.*/
|
||||
if(picture_type==1&&(width!=0||height!=0)&&(width!=32||height!=32)){
|
||||
return OP_ENOTFORMAT;
|
||||
}
|
||||
/*Append a terminating NUL for the convenience of our callers.*/
|
||||
_buf[_buf_sz++]='\0';
|
||||
}
|
||||
else{
|
||||
if(mime_type_length==10
|
||||
&&op_strncasecmp(mime_type,"image/jpeg",mime_type_length)==0){
|
||||
if(op_is_jpeg(_buf+i,data_length))format=OP_PIC_FORMAT_JPEG;
|
||||
}
|
||||
else if(mime_type_length==9
|
||||
&&op_strncasecmp(mime_type,"image/png",mime_type_length)==0){
|
||||
if(op_is_png(_buf+i,data_length))format=OP_PIC_FORMAT_PNG;
|
||||
}
|
||||
else if(mime_type_length==9
|
||||
&&op_strncasecmp(mime_type,"image/gif",mime_type_length)==0){
|
||||
if(op_is_gif(_buf+i,data_length))format=OP_PIC_FORMAT_GIF;
|
||||
}
|
||||
else if(mime_type_length==0||(mime_type_length==6
|
||||
&&op_strncasecmp(mime_type,"image/",mime_type_length)==0)){
|
||||
if(op_is_jpeg(_buf+i,data_length))format=OP_PIC_FORMAT_JPEG;
|
||||
else if(op_is_png(_buf+i,data_length))format=OP_PIC_FORMAT_PNG;
|
||||
else if(op_is_gif(_buf+i,data_length))format=OP_PIC_FORMAT_GIF;
|
||||
}
|
||||
file_width=file_height=file_depth=file_colors=0;
|
||||
has_palette=-1;
|
||||
switch(format){
|
||||
case OP_PIC_FORMAT_JPEG:{
|
||||
op_extract_jpeg_params(_buf+i,data_length,
|
||||
&file_width,&file_height,&file_depth,&file_colors,&has_palette);
|
||||
}break;
|
||||
case OP_PIC_FORMAT_PNG:{
|
||||
op_extract_png_params(_buf+i,data_length,
|
||||
&file_width,&file_height,&file_depth,&file_colors,&has_palette);
|
||||
}break;
|
||||
case OP_PIC_FORMAT_GIF:{
|
||||
op_extract_gif_params(_buf+i,data_length,
|
||||
&file_width,&file_height,&file_depth,&file_colors,&has_palette);
|
||||
}break;
|
||||
}
|
||||
if(has_palette>=0){
|
||||
/*If we successfully extracted these parameters from the image, override
|
||||
any declared values.*/
|
||||
width=file_width;
|
||||
height=file_height;
|
||||
depth=file_depth;
|
||||
colors=file_colors;
|
||||
}
|
||||
/*Picture type 1 must be a 32x32 PNG.*/
|
||||
if(picture_type==1&&(format!=OP_PIC_FORMAT_PNG||width!=32||height!=32)){
|
||||
return OP_ENOTFORMAT;
|
||||
}
|
||||
}
|
||||
/*Adjust _buf_sz instead of using data_length to capture the terminating NUL
|
||||
for URLs.*/
|
||||
_buf_sz-=i;
|
||||
memmove(_buf,_buf+i,sizeof(*_buf)*_buf_sz);
|
||||
_buf=(unsigned char *)_ogg_realloc(_buf,_buf_sz);
|
||||
if(_buf_sz>0&&_buf==NULL)return OP_EFAULT;
|
||||
_pic->type=picture_type;
|
||||
_pic->width=width;
|
||||
_pic->height=height;
|
||||
_pic->depth=depth;
|
||||
_pic->colors=colors;
|
||||
_pic->data_length=data_length;
|
||||
_pic->data=_buf;
|
||||
_pic->format=format;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int opus_picture_tag_parse(OpusPictureTag *_pic,const char *_tag){
|
||||
OpusPictureTag pic;
|
||||
unsigned char *buf;
|
||||
size_t base64_sz;
|
||||
size_t buf_sz;
|
||||
size_t tag_length;
|
||||
int ret;
|
||||
if(opus_tagncompare("METADATA_BLOCK_PICTURE",22,_tag)==0)_tag+=23;
|
||||
/*Figure out how much BASE64-encoded data we have.*/
|
||||
tag_length=strlen(_tag);
|
||||
if(tag_length&3)return OP_ENOTFORMAT;
|
||||
base64_sz=tag_length>>2;
|
||||
buf_sz=3*base64_sz;
|
||||
if(buf_sz<32)return OP_ENOTFORMAT;
|
||||
if(_tag[tag_length-1]=='=')buf_sz--;
|
||||
if(_tag[tag_length-2]=='=')buf_sz--;
|
||||
if(buf_sz<32)return OP_ENOTFORMAT;
|
||||
/*Allocate an extra byte to allow appending a terminating NUL to URL data.*/
|
||||
buf=(unsigned char *)_ogg_malloc(sizeof(*buf)*(buf_sz+1));
|
||||
if(buf==NULL)return OP_EFAULT;
|
||||
opus_picture_tag_init(&pic);
|
||||
ret=opus_picture_tag_parse_impl(&pic,_tag,buf,buf_sz,base64_sz);
|
||||
if(ret<0){
|
||||
opus_picture_tag_clear(&pic);
|
||||
_ogg_free(buf);
|
||||
}
|
||||
else *_pic=*&pic;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void opus_picture_tag_init(OpusPictureTag *_pic){
|
||||
memset(_pic,0,sizeof(*_pic));
|
||||
}
|
||||
|
||||
void opus_picture_tag_clear(OpusPictureTag *_pic){
|
||||
_ogg_free(_pic->description);
|
||||
_ogg_free(_pic->mime_type);
|
||||
_ogg_free(_pic->data);
|
||||
}
|
|
@ -9,6 +9,10 @@
|
|||
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
#if defined(OP_ENABLE_ASSERTIONS)
|
|
@ -32,10 +32,22 @@
|
|||
# include <opusfile.h>
|
||||
|
||||
typedef struct OggOpusLink OggOpusLink;
|
||||
|
||||
# if defined(OP_FIXED_POINT)
|
||||
|
||||
typedef opus_int16 op_sample;
|
||||
|
||||
# else
|
||||
|
||||
typedef float op_sample;
|
||||
|
||||
/*We're using this define to test for libopus 1.1 or later until libopus
|
||||
provides a better mechanism.*/
|
||||
# if defined(OPUS_GET_EXPERT_FRAME_DURATION_REQUEST)
|
||||
/*Enable soft clipping prevention in 16-bit decodes.*/
|
||||
# define OP_SOFT_CLIP (1)
|
||||
# endif
|
||||
|
||||
# endif
|
||||
|
||||
# if OP_GNUC_PREREQ(4,2)
|
||||
|
@ -80,8 +92,10 @@ void op_fatal_impl(const char *_str,const char *_file,int _line);
|
|||
# define OP_ALWAYS_TRUE(_cond) ((void)(_cond))
|
||||
# endif
|
||||
|
||||
# define OP_INT64_MAX ((ogg_int64_t)0x7FFFFFFFFFFFFFFFLL)
|
||||
# define OP_INT64_MAX (2*(((ogg_int64_t)1<<62)-1)|1)
|
||||
# define OP_INT64_MIN (-OP_INT64_MAX-1)
|
||||
# define OP_INT32_MAX (2*(((ogg_int32_t)1<<30)-1)|1)
|
||||
# define OP_INT32_MIN (-OP_INT32_MAX-1)
|
||||
|
||||
# define OP_MIN(_a,_b) ((_a)<(_b)?(_a):(_b))
|
||||
# define OP_MAX(_a,_b) ((_a)>(_b)?(_a):(_b))
|
||||
|
@ -90,7 +104,7 @@ void op_fatal_impl(const char *_str,const char *_file,int _line);
|
|||
/*Advance a file offset by the given amount, clamping against OP_INT64_MAX.
|
||||
This is used to advance a known offset by things like OP_CHUNK_SIZE or
|
||||
OP_PAGE_SIZE_MAX, while making sure to avoid signed overflow.
|
||||
It assumes that both _offset and _amount are positive.*/
|
||||
It assumes that both _offset and _amount are non-negative.*/
|
||||
#define OP_ADV_OFFSET(_offset,_amount) \
|
||||
(OP_MIN(_offset,OP_INT64_MAX-(_amount))+(_amount))
|
||||
|
||||
|
@ -189,6 +203,10 @@ struct OggOpusFile{
|
|||
int op_count;
|
||||
/*Central working state for the packet-to-PCM decoder.*/
|
||||
OpusMSDecoder *od;
|
||||
/*The application-provided packet decode callback.*/
|
||||
op_decode_cb_func decode_cb;
|
||||
/*The application-provided packet decode callback context.*/
|
||||
void *decode_cb_ctx;
|
||||
/*The stream count used to initialize the decoder.*/
|
||||
int od_stream_count;
|
||||
/*The coupled stream count used to initialize the decoder.*/
|
||||
|
@ -203,12 +221,26 @@ struct OggOpusFile{
|
|||
int od_buffer_pos;
|
||||
/*The number of valid samples in the decoded buffer.*/
|
||||
int od_buffer_size;
|
||||
/*Internal state for dithering float->short output.*/
|
||||
/*The type of gain offset to apply.
|
||||
One of OP_HEADER_GAIN, OP_TRACK_GAIN, or OP_ABSOLUTE_GAIN.*/
|
||||
int gain_type;
|
||||
/*The offset to apply to the gain.*/
|
||||
opus_int32 gain_offset_q8;
|
||||
/*Internal state for soft clipping and dithering float->short output.*/
|
||||
#if !defined(OP_FIXED_POINT)
|
||||
# if defined(OP_SOFT_CLIP)
|
||||
float clip_state[OP_NCHANNELS_MAX];
|
||||
# endif
|
||||
float dither_a[OP_NCHANNELS_MAX*4];
|
||||
float dither_b[OP_NCHANNELS_MAX*4];
|
||||
int dither_mute;
|
||||
opus_uint32 dither_seed;
|
||||
int dither_mute;
|
||||
int dither_disabled;
|
||||
/*The number of channels represented by the internal state.
|
||||
This gets set to 0 whenever anything that would prevent state propagation
|
||||
occurs (switching between the float/short APIs, or between the
|
||||
stereo/multistream APIs).*/
|
||||
int state_channel_count;
|
||||
#endif
|
||||
};
|
||||
|
File diff suppressed because it is too large
Load diff
366
code/opusfile-0.5/src/stream.c
Normal file
366
code/opusfile-0.5/src/stream.c
Normal file
|
@ -0,0 +1,366 @@
|
|||
/********************************************************************
|
||||
* *
|
||||
* THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. *
|
||||
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||
* *
|
||||
* THE libopusfile SOURCE CODE IS (C) COPYRIGHT 1994-2012 *
|
||||
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************
|
||||
|
||||
function: stdio-based convenience library for opening/seeking/decoding
|
||||
last mod: $Id: vorbisfile.c 17573 2010-10-27 14:53:59Z xiphmont $
|
||||
|
||||
********************************************************************/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "internal.h"
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#if defined(_WIN32)
|
||||
# include <io.h>
|
||||
#endif
|
||||
|
||||
typedef struct OpusMemStream OpusMemStream;
|
||||
|
||||
#define OP_MEM_SIZE_MAX (~(size_t)0>>1)
|
||||
#define OP_MEM_DIFF_MAX ((ptrdiff_t)OP_MEM_SIZE_MAX)
|
||||
|
||||
/*The context information needed to read from a block of memory as if it were a
|
||||
file.*/
|
||||
struct OpusMemStream{
|
||||
/*The block of memory to read from.*/
|
||||
const unsigned char *data;
|
||||
/*The total size of the block.
|
||||
This must be at most OP_MEM_SIZE_MAX to prevent signed overflow while
|
||||
seeking.*/
|
||||
ptrdiff_t size;
|
||||
/*The current file position.
|
||||
This is allowed to be set arbitrarily greater than size (i.e., past the end
|
||||
of the block, though we will not read data past the end of the block), but
|
||||
is not allowed to be negative (i.e., before the beginning of the block).*/
|
||||
ptrdiff_t pos;
|
||||
};
|
||||
|
||||
static int op_fread(void *_stream,unsigned char *_ptr,int _buf_size){
|
||||
FILE *stream;
|
||||
size_t ret;
|
||||
/*Check for empty read.*/
|
||||
if(_buf_size<=0)return 0;
|
||||
stream=(FILE *)_stream;
|
||||
ret=fread(_ptr,1,_buf_size,stream);
|
||||
OP_ASSERT(ret<=(size_t)_buf_size);
|
||||
/*If ret==0 and !feof(stream), there was a read error.*/
|
||||
return ret>0||feof(stream)?(int)ret:OP_EREAD;
|
||||
}
|
||||
|
||||
static int op_fseek(void *_stream,opus_int64 _offset,int _whence){
|
||||
#if defined(_WIN32)
|
||||
/*_fseeki64() is not exposed until MSCVCRT80.
|
||||
This is the default starting with MSVC 2005 (_MSC_VER>=1400), but we want
|
||||
to allow linking against older MSVCRT versions for compatibility back to
|
||||
XP without installing extra runtime libraries.
|
||||
i686-pc-mingw32 does not have fseeko() and requires
|
||||
__MSVCRT_VERSION__>=0x800 for _fseeki64(), which screws up linking with
|
||||
other libraries (that don't use MSVCRT80 from MSVC 2005 by default).
|
||||
i686-w64-mingw32 does have fseeko() and respects _FILE_OFFSET_BITS, but I
|
||||
don't know how to detect that at compile time.
|
||||
We could just use fseeko64() (which is available in both), but its
|
||||
implemented using fgetpos()/fsetpos() just like this code, except without
|
||||
the overflow checking, so we prefer our version.*/
|
||||
opus_int64 pos;
|
||||
/*We don't use fpos_t directly because it might be a struct if __STDC__ is
|
||||
non-zero or _INTEGRAL_MAX_BITS < 64.
|
||||
I'm not certain when the latter is true, but someone could in theory set
|
||||
the former.
|
||||
Either way, it should be binary compatible with a normal 64-bit int (this
|
||||
assumption is not portable, but I believe it is true for MSVCRT).*/
|
||||
OP_ASSERT(sizeof(pos)==sizeof(fpos_t));
|
||||
/*Translate the seek to an absolute one.*/
|
||||
if(_whence==SEEK_CUR){
|
||||
int ret;
|
||||
ret=fgetpos((FILE *)_stream,(fpos_t *)&pos);
|
||||
if(ret)return ret;
|
||||
}
|
||||
else if(_whence==SEEK_END)pos=_filelengthi64(_fileno((FILE *)_stream));
|
||||
else if(_whence==SEEK_SET)pos=0;
|
||||
else return -1;
|
||||
/*Check for errors or overflow.*/
|
||||
if(pos<0||_offset<-pos||_offset>OP_INT64_MAX-pos)return -1;
|
||||
pos+=_offset;
|
||||
return fsetpos((FILE *)_stream,(fpos_t *)&pos);
|
||||
#else
|
||||
/*This function actually conforms to the SUSv2 and POSIX.1-2001, so we prefer
|
||||
it except on Windows.*/
|
||||
return fseeko((FILE *)_stream,(off_t)_offset,_whence);
|
||||
#endif
|
||||
}
|
||||
|
||||
static opus_int64 op_ftell(void *_stream){
|
||||
#if defined(_WIN32)
|
||||
/*_ftelli64() is not exposed until MSCVCRT80, and ftello()/ftello64() have
|
||||
the same problems as fseeko()/fseeko64() in MingW.
|
||||
See above for a more detailed explanation.*/
|
||||
opus_int64 pos;
|
||||
OP_ASSERT(sizeof(pos)==sizeof(fpos_t));
|
||||
return fgetpos((FILE *)_stream,(fpos_t *)&pos)?-1:pos;
|
||||
#else
|
||||
/*This function actually conforms to the SUSv2 and POSIX.1-2001, so we prefer
|
||||
it except on Windows.*/
|
||||
return ftello((FILE *)_stream);
|
||||
#endif
|
||||
}
|
||||
|
||||
static const OpusFileCallbacks OP_FILE_CALLBACKS={
|
||||
op_fread,
|
||||
op_fseek,
|
||||
op_ftell,
|
||||
(op_close_func)fclose
|
||||
};
|
||||
|
||||
#if defined(_WIN32)
|
||||
# include <stddef.h>
|
||||
# include <errno.h>
|
||||
|
||||
/*Windows doesn't accept UTF-8 by default, and we don't have a wchar_t API,
|
||||
so if we just pass the path to fopen(), then there'd be no way for a user
|
||||
of our API to open a Unicode filename.
|
||||
Instead, we translate from UTF-8 to UTF-16 and use Windows' wchar_t API.
|
||||
This makes this API more consistent with platforms where the character set
|
||||
used by fopen is the same as used on disk, which is generally UTF-8, and
|
||||
with our metadata API, which always uses UTF-8.*/
|
||||
static wchar_t *op_utf8_to_utf16(const char *_src){
|
||||
wchar_t *dst;
|
||||
size_t len;
|
||||
len=strlen(_src);
|
||||
/*Worst-case output is 1 wide character per 1 input character.*/
|
||||
dst=(wchar_t *)_ogg_malloc(sizeof(*dst)*(len+1));
|
||||
if(dst!=NULL){
|
||||
size_t si;
|
||||
size_t di;
|
||||
for(di=si=0;si<len;si++){
|
||||
int c0;
|
||||
c0=(unsigned char)_src[si];
|
||||
if(!(c0&0x80)){
|
||||
/*Start byte says this is a 1-byte sequence.*/
|
||||
dst[di++]=(wchar_t)c0;
|
||||
continue;
|
||||
}
|
||||
else{
|
||||
int c1;
|
||||
/*This is safe, because c0 was not 0 and _src is NUL-terminated.*/
|
||||
c1=(unsigned char)_src[si+1];
|
||||
if((c1&0xC0)==0x80){
|
||||
/*Found at least one continuation byte.*/
|
||||
if((c0&0xE0)==0xC0){
|
||||
wchar_t w;
|
||||
/*Start byte says this is a 2-byte sequence.*/
|
||||
w=(c0&0x1F)<<6|c1&0x3F;
|
||||
if(w>=0x80U){
|
||||
/*This is a 2-byte sequence that is not overlong.*/
|
||||
dst[di++]=w;
|
||||
si++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else{
|
||||
int c2;
|
||||
/*This is safe, because c1 was not 0 and _src is NUL-terminated.*/
|
||||
c2=(unsigned char)_src[si+2];
|
||||
if((c2&0xC0)==0x80){
|
||||
/*Found at least two continuation bytes.*/
|
||||
if((c0&0xF0)==0xE0){
|
||||
wchar_t w;
|
||||
/*Start byte says this is a 3-byte sequence.*/
|
||||
w=(c0&0xF)<<12|(c1&0x3F)<<6|c2&0x3F;
|
||||
if(w>=0x800U&&(w<0xD800||w>=0xE000)&&w<0xFFFE){
|
||||
/*This is a 3-byte sequence that is not overlong, not a
|
||||
UTF-16 surrogate pair value, and not a 'not a character'
|
||||
value.*/
|
||||
dst[di++]=w;
|
||||
si+=2;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else{
|
||||
int c3;
|
||||
/*This is safe, because c2 was not 0 and _src is
|
||||
NUL-terminated.*/
|
||||
c3=(unsigned char)_src[si+3];
|
||||
if((c3&0xC0)==0x80){
|
||||
/*Found at least three continuation bytes.*/
|
||||
if((c0&0xF8)==0xF0){
|
||||
opus_uint32 w;
|
||||
/*Start byte says this is a 4-byte sequence.*/
|
||||
w=(c0&7)<<18|(c1&0x3F)<<12|(c2&0x3F)<<6&(c3&0x3F);
|
||||
if(w>=0x10000U&&w<0x110000U){
|
||||
/*This is a 4-byte sequence that is not overlong and not
|
||||
greater than the largest valid Unicode code point.
|
||||
Convert it to a surrogate pair.*/
|
||||
w-=0x10000;
|
||||
dst[di++]=(wchar_t)(0xD800+(w>>10));
|
||||
dst[di++]=(wchar_t)(0xDC00+(w&0x3FF));
|
||||
si+=3;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*If we got here, we encountered an illegal UTF-8 sequence.*/
|
||||
_ogg_free(dst);
|
||||
return NULL;
|
||||
}
|
||||
OP_ASSERT(di<=len);
|
||||
dst[di]='\0';
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void *op_fopen(OpusFileCallbacks *_cb,const char *_path,const char *_mode){
|
||||
FILE *fp;
|
||||
#if !defined(_WIN32)
|
||||
fp=fopen(_path,_mode);
|
||||
#else
|
||||
fp=NULL;
|
||||
if(_path==NULL||_mode==NULL)errno=EINVAL;
|
||||
else{
|
||||
wchar_t *wpath;
|
||||
wchar_t *wmode;
|
||||
wpath=op_utf8_to_utf16(_path);
|
||||
wmode=op_utf8_to_utf16(_mode);
|
||||
if(wmode==NULL)errno=EINVAL;
|
||||
else if(wpath==NULL)errno=ENOENT;
|
||||
else fp=_wfopen(wpath,wmode);
|
||||
_ogg_free(wmode);
|
||||
_ogg_free(wpath);
|
||||
}
|
||||
#endif
|
||||
if(fp!=NULL)*_cb=*&OP_FILE_CALLBACKS;
|
||||
return fp;
|
||||
}
|
||||
|
||||
void *op_fdopen(OpusFileCallbacks *_cb,int _fd,const char *_mode){
|
||||
FILE *fp;
|
||||
fp=fdopen(_fd,_mode);
|
||||
if(fp!=NULL)*_cb=*&OP_FILE_CALLBACKS;
|
||||
return fp;
|
||||
}
|
||||
|
||||
void *op_freopen(OpusFileCallbacks *_cb,const char *_path,const char *_mode,
|
||||
void *_stream){
|
||||
FILE *fp;
|
||||
#if !defined(_WIN32)
|
||||
fp=freopen(_path,_mode,(FILE *)_stream);
|
||||
#else
|
||||
fp=NULL;
|
||||
if(_path==NULL||_mode==NULL)errno=EINVAL;
|
||||
else{
|
||||
wchar_t *wpath;
|
||||
wchar_t *wmode;
|
||||
wpath=op_utf8_to_utf16(_path);
|
||||
wmode=op_utf8_to_utf16(_mode);
|
||||
if(wmode==NULL)errno=EINVAL;
|
||||
else if(wpath==NULL)errno=ENOENT;
|
||||
else fp=_wfreopen(wpath,wmode,(FILE *)_stream);
|
||||
_ogg_free(wmode);
|
||||
_ogg_free(wpath);
|
||||
}
|
||||
#endif
|
||||
if(fp!=NULL)*_cb=*&OP_FILE_CALLBACKS;
|
||||
return fp;
|
||||
}
|
||||
|
||||
static int op_mem_read(void *_stream,unsigned char *_ptr,int _buf_size){
|
||||
OpusMemStream *stream;
|
||||
ptrdiff_t size;
|
||||
ptrdiff_t pos;
|
||||
stream=(OpusMemStream *)_stream;
|
||||
/*Check for empty read.*/
|
||||
if(_buf_size<=0)return 0;
|
||||
size=stream->size;
|
||||
pos=stream->pos;
|
||||
/*Check for EOF.*/
|
||||
if(pos>=size)return 0;
|
||||
/*Check for a short read.*/
|
||||
_buf_size=(int)OP_MIN(size-pos,_buf_size);
|
||||
memcpy(_ptr,stream->data+pos,_buf_size);
|
||||
pos+=_buf_size;
|
||||
stream->pos=pos;
|
||||
return _buf_size;
|
||||
}
|
||||
|
||||
static int op_mem_seek(void *_stream,opus_int64 _offset,int _whence){
|
||||
OpusMemStream *stream;
|
||||
ptrdiff_t pos;
|
||||
stream=(OpusMemStream *)_stream;
|
||||
pos=stream->pos;
|
||||
OP_ASSERT(pos>=0);
|
||||
switch(_whence){
|
||||
case SEEK_SET:{
|
||||
/*Check for overflow:*/
|
||||
if(_offset<0||_offset>OP_MEM_DIFF_MAX)return -1;
|
||||
pos=(ptrdiff_t)_offset;
|
||||
}break;
|
||||
case SEEK_CUR:{
|
||||
/*Check for overflow:*/
|
||||
if(_offset<-pos||_offset>OP_MEM_DIFF_MAX-pos)return -1;
|
||||
pos=(ptrdiff_t)(pos+_offset);
|
||||
}break;
|
||||
case SEEK_END:{
|
||||
ptrdiff_t size;
|
||||
size=stream->size;
|
||||
OP_ASSERT(size>=0);
|
||||
/*Check for overflow:*/
|
||||
if(_offset>size||_offset<size-OP_MEM_DIFF_MAX)return -1;
|
||||
pos=(ptrdiff_t)(size-_offset);
|
||||
}break;
|
||||
default:return -1;
|
||||
}
|
||||
stream->pos=pos;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static opus_int64 op_mem_tell(void *_stream){
|
||||
OpusMemStream *stream;
|
||||
stream=(OpusMemStream *)_stream;
|
||||
return (ogg_int64_t)stream->pos;
|
||||
}
|
||||
|
||||
static int op_mem_close(void *_stream){
|
||||
_ogg_free(_stream);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const OpusFileCallbacks OP_MEM_CALLBACKS={
|
||||
op_mem_read,
|
||||
op_mem_seek,
|
||||
op_mem_tell,
|
||||
op_mem_close
|
||||
};
|
||||
|
||||
void *op_mem_stream_create(OpusFileCallbacks *_cb,
|
||||
const unsigned char *_data,size_t _size){
|
||||
OpusMemStream *stream;
|
||||
if(_size>OP_MEM_SIZE_MAX)return NULL;
|
||||
stream=(OpusMemStream *)_ogg_malloc(sizeof(*stream));
|
||||
if(stream!=NULL){
|
||||
*_cb=*&OP_MEM_CALLBACKS;
|
||||
stream->data=_data;
|
||||
stream->size=_size;
|
||||
stream->pos=0;
|
||||
}
|
||||
return stream;
|
||||
}
|
171
code/opusfile-0.5/src/wincerts.c
Normal file
171
code/opusfile-0.5/src/wincerts.c
Normal file
|
@ -0,0 +1,171 @@
|
|||
/********************************************************************
|
||||
* *
|
||||
* THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. *
|
||||
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||
* *
|
||||
* THE libopusfile SOURCE CODE IS (C) COPYRIGHT 2013 *
|
||||
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************/
|
||||
|
||||
/*This should really be part of OpenSSL, but there's been a patch [1] sitting
|
||||
in their bugtracker for over two years that implements this, without any
|
||||
action, so I'm giving up and re-implementing it locally.
|
||||
|
||||
[1] <http://rt.openssl.org/Ticket/Display.html?id=2158>*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "internal.h"
|
||||
#if defined(OP_ENABLE_HTTP)&&defined(_WIN32)
|
||||
/*You must include windows.h before wincrypt.h and x509.h.*/
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# define WIN32_EXTRA_LEAN
|
||||
# include <windows.h>
|
||||
/*You must include wincrypt.h before x509.h, too, or X509_NAME doesn't get
|
||||
defined properly.*/
|
||||
# include <wincrypt.h>
|
||||
# include <openssl/ssl.h>
|
||||
# include <openssl/err.h>
|
||||
# include <openssl/x509.h>
|
||||
|
||||
static int op_capi_new(X509_LOOKUP *_lu){
|
||||
HCERTSTORE h_store;
|
||||
h_store=CertOpenStore(CERT_STORE_PROV_SYSTEM_A,0,0,
|
||||
CERT_STORE_OPEN_EXISTING_FLAG|CERT_STORE_READONLY_FLAG|
|
||||
CERT_SYSTEM_STORE_CURRENT_USER|CERT_STORE_SHARE_CONTEXT_FLAG,"ROOT");
|
||||
if(h_store!=NULL){
|
||||
_lu->method_data=(char *)h_store;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void op_capi_free(X509_LOOKUP *_lu){
|
||||
HCERTSTORE h_store;
|
||||
h_store=(HCERTSTORE)_lu->method_data;
|
||||
# if defined(OP_ENABLE_ASSERTIONS)
|
||||
OP_ALWAYS_TRUE(CertCloseStore(h_store,CERT_CLOSE_STORE_CHECK_FLAG));
|
||||
# else
|
||||
CertCloseStore(h_store,0);
|
||||
# endif
|
||||
}
|
||||
|
||||
static int op_capi_retrieve_by_subject(X509_LOOKUP *_lu,int _type,
|
||||
X509_NAME *_name,X509_OBJECT *_ret){
|
||||
X509_OBJECT *obj;
|
||||
CRYPTO_w_lock(CRYPTO_LOCK_X509_STORE);
|
||||
obj=X509_OBJECT_retrieve_by_subject(_lu->store_ctx->objs,_type,_name);
|
||||
CRYPTO_w_unlock(CRYPTO_LOCK_X509_STORE);
|
||||
if(obj!=NULL){
|
||||
_ret->type=obj->type;
|
||||
memcpy(&_ret->data,&obj->data,sizeof(_ret->data));
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int op_capi_get_by_subject(X509_LOOKUP *_lu,int _type,X509_NAME *_name,
|
||||
X509_OBJECT *_ret){
|
||||
HCERTSTORE h_store;
|
||||
if(_name==NULL)return 0;
|
||||
if(_name->bytes==NULL||_name->bytes->length<=0||_name->modified){
|
||||
if(i2d_X509_NAME(_name,NULL)<0)return 0;
|
||||
OP_ASSERT(_name->bytes->length>0);
|
||||
}
|
||||
h_store=(HCERTSTORE)_lu->method_data;
|
||||
switch(_type){
|
||||
case X509_LU_X509:{
|
||||
CERT_NAME_BLOB find_para;
|
||||
PCCERT_CONTEXT cert;
|
||||
X509 *x;
|
||||
int ret;
|
||||
/*Although X509_NAME contains a canon_enc field, that "canonical" [1]
|
||||
encoding was just made up by OpenSSL.
|
||||
It doesn't correspond to any actual standard, and since it drops the
|
||||
initial sequence header, won't be recognized by the Crypto API.
|
||||
The assumption here is that CertFindCertificateInStore() will allow any
|
||||
appropriate variations in the encoding when it does its comparison.
|
||||
This is, however, emphatically not true under Wine, which just compares
|
||||
the encodings with memcmp().
|
||||
Most of the time things work anyway, though, and there isn't really
|
||||
anything we can do to make the situation better.
|
||||
|
||||
[1] A "canonical form" is defined as the one where, if you locked 10
|
||||
mathematicians in a room and asked them to come up with a
|
||||
representation for something, it's the answer that 9 of them would
|
||||
give you back.
|
||||
I don't think OpenSSL's encoding qualifies.*/
|
||||
find_para.cbData=_name->bytes->length;
|
||||
find_para.pbData=(unsigned char *)_name->bytes->data;
|
||||
cert=CertFindCertificateInStore(h_store,X509_ASN_ENCODING,0,
|
||||
CERT_FIND_SUBJECT_NAME,&find_para,NULL);
|
||||
if(cert==NULL)return 0;
|
||||
x=d2i_X509(NULL,(const unsigned char **)&cert->pbCertEncoded,
|
||||
cert->cbCertEncoded);
|
||||
CertFreeCertificateContext(cert);
|
||||
if(x==NULL)return 0;
|
||||
ret=X509_STORE_add_cert(_lu->store_ctx,x);
|
||||
X509_free(x);
|
||||
if(ret)return op_capi_retrieve_by_subject(_lu,_type,_name,_ret);
|
||||
}break;
|
||||
case X509_LU_CRL:{
|
||||
CERT_INFO cert_info;
|
||||
CERT_CONTEXT find_para;
|
||||
PCCRL_CONTEXT crl;
|
||||
X509_CRL *x;
|
||||
int ret;
|
||||
ret=op_capi_retrieve_by_subject(_lu,_type,_name,_ret);
|
||||
if(ret>0)return ret;
|
||||
memset(&cert_info,0,sizeof(cert_info));
|
||||
cert_info.Issuer.cbData=_name->bytes->length;
|
||||
cert_info.Issuer.pbData=(unsigned char *)_name->bytes->data;
|
||||
memset(&find_para,0,sizeof(find_para));
|
||||
find_para.pCertInfo=&cert_info;
|
||||
crl=CertFindCRLInStore(h_store,0,0,CRL_FIND_ISSUED_BY,&find_para,NULL);
|
||||
if(crl==NULL)return 0;
|
||||
x=d2i_X509_CRL(NULL,(const unsigned char **)&crl->pbCrlEncoded,
|
||||
crl->cbCrlEncoded);
|
||||
CertFreeCRLContext(crl);
|
||||
if(x==NULL)return 0;
|
||||
ret=X509_STORE_add_crl(_lu->store_ctx,x);
|
||||
X509_CRL_free(x);
|
||||
if(ret)return op_capi_retrieve_by_subject(_lu,_type,_name,_ret);
|
||||
}break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*This is not const because OpenSSL doesn't allow it, even though it won't
|
||||
write to it.*/
|
||||
static X509_LOOKUP_METHOD X509_LOOKUP_CAPI={
|
||||
"Load Crypto API store into cache",
|
||||
op_capi_new,
|
||||
op_capi_free,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
op_capi_get_by_subject,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
int SSL_CTX_set_default_verify_paths_win32(SSL_CTX *_ssl_ctx){
|
||||
X509_STORE *store;
|
||||
X509_LOOKUP *lu;
|
||||
/*We intentionally do not add the normal default paths, as they are usually
|
||||
wrong, and are just asking to be used as an exploit vector.*/
|
||||
store=SSL_CTX_get_cert_store(_ssl_ctx);
|
||||
OP_ASSERT(store!=NULL);
|
||||
lu=X509_STORE_add_lookup(store,&X509_LOOKUP_CAPI);
|
||||
if(lu==NULL)return 0;
|
||||
ERR_clear_error();
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
90
code/opusfile-0.5/src/winerrno.h
Normal file
90
code/opusfile-0.5/src/winerrno.h
Normal file
|
@ -0,0 +1,90 @@
|
|||
/********************************************************************
|
||||
* *
|
||||
* THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. *
|
||||
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
|
||||
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
|
||||
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
|
||||
* *
|
||||
* THE libopusfile SOURCE CODE IS (C) COPYRIGHT 2012 *
|
||||
* by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
|
||||
* *
|
||||
********************************************************************/
|
||||
#if !defined(_opusfile_winerrno_h)
|
||||
# define _opusfile_winerrno_h (1)
|
||||
|
||||
# include <errno.h>
|
||||
# include <winerror.h>
|
||||
|
||||
/*These conflict with the MSVC errno.h definitions, but we don't need to use
|
||||
the original ones in any file that deals with sockets.
|
||||
We could map the WSA errors to the errno.h ones (most of which are only
|
||||
available on sufficiently new versions of MSVC), but they aren't ordered the
|
||||
same, and given how rarely we actually look at the values, I don't think
|
||||
it's worth a lookup table.*/
|
||||
# undef EWOULDBLOCK
|
||||
# undef EINPROGRESS
|
||||
# undef EALREADY
|
||||
# undef ENOTSOCK
|
||||
# undef EDESTADDRREQ
|
||||
# undef EMSGSIZE
|
||||
# undef EPROTOTYPE
|
||||
# undef ENOPROTOOPT
|
||||
# undef EPROTONOSUPPORT
|
||||
# undef EOPNOTSUPP
|
||||
# undef EAFNOSUPPORT
|
||||
# undef EADDRINUSE
|
||||
# undef EADDRNOTAVAIL
|
||||
# undef ENETDOWN
|
||||
# undef ENETUNREACH
|
||||
# undef ENETRESET
|
||||
# undef ECONNABORTED
|
||||
# undef ECONNRESET
|
||||
# undef ENOBUFS
|
||||
# undef EISCONN
|
||||
# undef ENOTCONN
|
||||
# undef ETIMEDOUT
|
||||
# undef ECONNREFUSED
|
||||
# undef ELOOP
|
||||
# undef ENAMETOOLONG
|
||||
# undef EHOSTUNREACH
|
||||
# undef ENOTEMPTY
|
||||
|
||||
# define EWOULDBLOCK (WSAEWOULDBLOCK-WSABASEERR)
|
||||
# define EINPROGRESS (WSAEINPROGRESS-WSABASEERR)
|
||||
# define EALREADY (WSAEALREADY-WSABASEERR)
|
||||
# define ENOTSOCK (WSAENOTSOCK-WSABASEERR)
|
||||
# define EDESTADDRREQ (WSAEDESTADDRREQ-WSABASEERR)
|
||||
# define EMSGSIZE (WSAEMSGSIZE-WSABASEERR)
|
||||
# define EPROTOTYPE (WSAEPROTOTYPE-WSABASEERR)
|
||||
# define ENOPROTOOPT (WSAENOPROTOOPT-WSABASEERR)
|
||||
# define EPROTONOSUPPORT (WSAEPROTONOSUPPORT-WSABASEERR)
|
||||
# define ESOCKTNOSUPPORT (WSAESOCKTNOSUPPORT-WSABASEERR)
|
||||
# define EOPNOTSUPP (WSAEOPNOTSUPP-WSABASEERR)
|
||||
# define EPFNOSUPPORT (WSAEPFNOSUPPORT-WSABASEERR)
|
||||
# define EAFNOSUPPORT (WSAEAFNOSUPPORT-WSABASEERR)
|
||||
# define EADDRINUSE (WSAEADDRINUSE-WSABASEERR)
|
||||
# define EADDRNOTAVAIL (WSAEADDRNOTAVAIL-WSABASEERR)
|
||||
# define ENETDOWN (WSAENETDOWN-WSABASEERR)
|
||||
# define ENETUNREACH (WSAENETUNREACH-WSABASEERR)
|
||||
# define ENETRESET (WSAENETRESET-WSABASEERR)
|
||||
# define ECONNABORTED (WSAECONNABORTED-WSABASEERR)
|
||||
# define ECONNRESET (WSAECONNRESET-WSABASEERR)
|
||||
# define ENOBUFS (WSAENOBUFS-WSABASEERR)
|
||||
# define EISCONN (WSAEISCONN-WSABASEERR)
|
||||
# define ENOTCONN (WSAENOTCONN-WSABASEERR)
|
||||
# define ESHUTDOWN (WSAESHUTDOWN-WSABASEERR)
|
||||
# define ETOOMANYREFS (WSAETOOMANYREFS-WSABASEERR)
|
||||
# define ETIMEDOUT (WSAETIMEDOUT-WSABASEERR)
|
||||
# define ECONNREFUSED (WSAECONNREFUSED-WSABASEERR)
|
||||
# define ELOOP (WSAELOOP-WSABASEERR)
|
||||
# define ENAMETOOLONG (WSAENAMETOOLONG-WSABASEERR)
|
||||
# define EHOSTDOWN (WSAEHOSTDOWN-WSABASEERR)
|
||||
# define EHOSTUNREACH (WSAEHOSTUNREACH-WSABASEERR)
|
||||
# define ENOTEMPTY (WSAENOTEMPTY-WSABASEERR)
|
||||
# define EPROCLIM (WSAEPROCLIM-WSABASEERR)
|
||||
# define EUSERS (WSAEUSERS-WSABASEERR)
|
||||
# define EDQUOT (WSAEDQUOT-WSABASEERR)
|
||||
# define ESTALE (WSAESTALE-WSABASEERR)
|
||||
# define EREMOTE (WSAEREMOTE-WSABASEERR)
|
||||
|
||||
#endif
|
Loading…
Reference in a new issue