mirror of
https://gitee.com/openharmony/third_party_libsnd
synced 2024-11-23 09:59:54 +00:00
src/ : Reimplement handling of broadcast extention chunk in WAV/WAVEX files.
This commit is contained in:
parent
62e45b55ae
commit
ba76501702
201
src/broadcast.c
201
src/broadcast.c
@ -18,11 +18,12 @@
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
static void strncpy_crlf (char *dest, const char *src, size_t n) ;
|
||||
static void strncpy_crlf (char *dest, const char *src, size_t destmax, size_t srcmax) ;
|
||||
|
||||
/*
|
||||
** Allocate and initialize a broadcast info structure.
|
||||
@ -43,7 +44,7 @@ broadcast_info_copy (SF_BROADCAST_INFO* dst, const SF_BROADCAST_INFO* src)
|
||||
{ memcpy (dst, src, sizeof (SF_BROADCAST_INFO)) ;
|
||||
|
||||
/* In case the src has the wrong line endings. */
|
||||
strncpy_crlf (dst->coding_history, src->coding_history, sizeof (dst->coding_history)) ;
|
||||
strncpy_crlf (dst->coding_history, src->coding_history, sizeof (dst->coding_history), src->coding_history_size) ;
|
||||
|
||||
/* Currently writing this version. */
|
||||
dst->version = 1 ;
|
||||
@ -127,7 +128,7 @@ broadcast_add_coding_history (SF_BROADCAST_INFO* bext, unsigned int channels, un
|
||||
/* Note newlines in Coding History should be '\r\n' as per the URL above. */
|
||||
|
||||
if (bext->coding_history_size > 0)
|
||||
strncpy_crlf (history, bext->coding_history, sizeof (history)) ;
|
||||
strncpy_crlf (history, bext->coding_history, sizeof (history), bext->coding_history_size) ;
|
||||
else
|
||||
history [0] = 0 ;
|
||||
|
||||
@ -169,15 +170,203 @@ broadcast_add_coding_history (SF_BROADCAST_INFO* bext, unsigned int channels, un
|
||||
return SF_TRUE ;
|
||||
} /* broadcast_add_coding_history */
|
||||
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
*/
|
||||
|
||||
#if 1
|
||||
|
||||
static int
|
||||
gen_coding_history (char * added_history, size_t added_history_max, const SF_INFO * psfinfo)
|
||||
{ char chnstr [16] ;
|
||||
int count, width ;
|
||||
|
||||
/*
|
||||
** From : http://www.sr.se/utveckling/tu/bwf/docs/codhist2.htm
|
||||
**
|
||||
** Parameter Variable string <allowed option> Unit
|
||||
** ==========================================================================================
|
||||
** Coding Algorithm A=<ANALOGUE, PCM, MPEG1L1, MPEG1L2, MPEG1L3,
|
||||
** MPEG2L1, MPEG2L2, MPEG2L3>
|
||||
** Sampling frequency F=<11000,22050,24000,32000,44100,48000> [Hz]
|
||||
** Bit-rate B=<any bit-rate allowed in MPEG 2 (ISO/IEC [kbit/s per channel]
|
||||
** 13818-3)>
|
||||
** Word Length W=<8, 12, 14, 16, 18, 20, 22, 24> [bits]
|
||||
** Mode M=<mono, stereo, dual-mono, joint-stereo>
|
||||
** Text, free string T=<a free ASCII-text string for in house use.
|
||||
** This string should contain no commas (ASCII
|
||||
** 2Chex). Examples of the contents: ID-No; codec
|
||||
** type; A/D type>
|
||||
*/
|
||||
|
||||
switch (psfinfo->channels)
|
||||
{ case 0 :
|
||||
return SF_FALSE ;
|
||||
|
||||
case 1 :
|
||||
strncpy (chnstr, "mono", sizeof (chnstr)) ;
|
||||
break ;
|
||||
|
||||
case 2 :
|
||||
strncpy (chnstr, "stereo", sizeof (chnstr)) ;
|
||||
break ;
|
||||
|
||||
default :
|
||||
LSF_SNPRINTF (chnstr, sizeof (chnstr), "%uchn", psfinfo->channels) ;
|
||||
break ;
|
||||
} ;
|
||||
|
||||
switch (SF_CODEC (psfinfo->format))
|
||||
{ case SF_FORMAT_PCM_U8 :
|
||||
case SF_FORMAT_PCM_S8 :
|
||||
width = 8 ;
|
||||
break ;
|
||||
case SF_FORMAT_PCM_16 :
|
||||
width = 16 ;
|
||||
break ;
|
||||
case SF_FORMAT_PCM_24 :
|
||||
width = 24 ;
|
||||
break ;
|
||||
case SF_FORMAT_PCM_32 :
|
||||
width = 32 ;
|
||||
break ;
|
||||
case SF_FORMAT_FLOAT :
|
||||
width = 24 ; /* Bits in the mantissa + 1 */
|
||||
break ;
|
||||
case SF_FORMAT_DOUBLE :
|
||||
width = 53 ; /* Bits in the mantissa + 1 */
|
||||
break ;
|
||||
case SF_FORMAT_ULAW :
|
||||
case SF_FORMAT_ALAW :
|
||||
width = 12 ;
|
||||
break ;
|
||||
default :
|
||||
width = 42 ;
|
||||
break ;
|
||||
} ;
|
||||
|
||||
count = LSF_SNPRINTF (added_history, added_history_max,
|
||||
"A=PCM,F=%u,W=%hu,M=%s,T=%s-%s\r\n",
|
||||
psfinfo->samplerate, width, chnstr, PACKAGE, VERSION) ;
|
||||
|
||||
if (count >= SIGNED_SIZEOF (added_history))
|
||||
return 0 ;
|
||||
|
||||
return count ;
|
||||
} /* gen_coding_history */
|
||||
|
||||
static inline size_t
|
||||
bc_min_size (const SF_BROADCAST_INFO* info)
|
||||
{ if (info == NULL)
|
||||
return 0 ;
|
||||
|
||||
return offsetof (SF_BROADCAST_INFO, coding_history) + info->coding_history_size ;
|
||||
} /* broadcast_size */
|
||||
|
||||
|
||||
static inline size_t
|
||||
bc_var_coding_hist_size (const SF_BROADCAST_VAR* var)
|
||||
{ return var->size - offsetof (SF_BROADCAST_VAR, binfo.coding_history) ;
|
||||
} /* broadcast_size */
|
||||
|
||||
SF_BROADCAST_VAR*
|
||||
broadcast_var_alloc (size_t datasize)
|
||||
{ SF_BROADCAST_VAR * data ;
|
||||
|
||||
if ((data = calloc (1, datasize)) != NULL)
|
||||
data->size = datasize ;
|
||||
|
||||
return data ;
|
||||
} /* broadcast_var_alloc */
|
||||
|
||||
|
||||
int
|
||||
broadcast_var_set (SF_PRIVATE *psf, const SF_BROADCAST_INFO * info, size_t datasize)
|
||||
{ char added_history [256] ;
|
||||
int added_history_len, total_history_len ;
|
||||
|
||||
if (info == NULL)
|
||||
return SF_FALSE ;
|
||||
|
||||
if (bc_min_size (info) > datasize)
|
||||
{ psf->error = SFE_BAD_BROADCAST_INFO_SIZE ;
|
||||
return SF_FALSE ;
|
||||
} ;
|
||||
|
||||
added_history_len = gen_coding_history (added_history, sizeof (added_history), &(psf->sf)) ;
|
||||
|
||||
if (psf->broadcast_var != NULL
|
||||
&& psf->broadcast_var->binfo.coding_history_size + added_history_len < datasize)
|
||||
{ free (psf->broadcast_var) ;
|
||||
psf->broadcast_var = NULL ;
|
||||
} ;
|
||||
|
||||
if (psf->broadcast_var == NULL)
|
||||
{ int size = datasize + added_history_len + 512 ;
|
||||
|
||||
psf->broadcast_var = calloc (1, size) ;
|
||||
psf->broadcast_var->size = size ;
|
||||
} ;
|
||||
|
||||
memcpy (&(psf->broadcast_var->binfo), info, offsetof (SF_BROADCAST_INFO, coding_history)) ;
|
||||
|
||||
strncpy_crlf (psf->broadcast_var->binfo.coding_history, info->coding_history, bc_var_coding_hist_size (psf->broadcast_var), info->coding_history_size) ;
|
||||
total_history_len = strlen (psf->broadcast_var->binfo.coding_history) + added_history_len ;
|
||||
|
||||
if (psf->mode == SFM_WRITE)
|
||||
strncat (psf->broadcast_var->binfo.coding_history, added_history, strlen (added_history)) ;
|
||||
|
||||
psf->broadcast_var->binfo.coding_history_size = strlen (psf->broadcast_var->binfo.coding_history) ;
|
||||
|
||||
/* Fore coding_history_size to be even. */
|
||||
psf->broadcast_var->binfo.coding_history_size += (psf->broadcast_var->binfo.coding_history_size & 1) ? 1 : 0 ;
|
||||
|
||||
/* Currently writing this version. */
|
||||
psf->broadcast_var->binfo.version = 1 ;
|
||||
|
||||
return SF_TRUE ;
|
||||
} /* broadcast_var_set */
|
||||
|
||||
|
||||
int
|
||||
broadcast_var_get (SF_PRIVATE *psf, SF_BROADCAST_INFO * data, size_t datasize)
|
||||
{ size_t size ;
|
||||
|
||||
broadcast_info_to_var (psf) ;
|
||||
|
||||
if (psf->broadcast_var == NULL)
|
||||
return SF_FALSE ;
|
||||
|
||||
size = SF_MIN (datasize, bc_min_size (&(psf->broadcast_var->binfo))) ;
|
||||
|
||||
memcpy (data, &(psf->broadcast_var->binfo), size) ;
|
||||
|
||||
return SF_TRUE ;
|
||||
} /* broadcast_var_set */
|
||||
|
||||
void
|
||||
broadcast_info_to_var (SF_PRIVATE *psf)
|
||||
{
|
||||
if (psf->broadcast_info != NULL)
|
||||
{ broadcast_var_set (psf, psf->broadcast_info, sizeof (SF_BROADCAST_INFO)) ;
|
||||
free (psf->broadcast_info) ;
|
||||
psf->broadcast_info = NULL ;
|
||||
} ;
|
||||
} /* broadcast_info_to_var */
|
||||
|
||||
#endif
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
** Strncpy which converts all line endings to CR/LF.
|
||||
*/
|
||||
|
||||
static void
|
||||
strncpy_crlf (char *dest, const char *src, size_t max)
|
||||
{ char * end = dest + max - 1 ;
|
||||
strncpy_crlf (char *dest, const char *src, size_t destmax, size_t srcmax)
|
||||
{ char * destend = dest + destmax - 1 ;
|
||||
const char * srcend = src + srcmax - 1 ;
|
||||
|
||||
while (dest < end && src [0])
|
||||
while (dest < destend && src < srcend)
|
||||
{ if ((src [0] == '\r' && src [1] == '\n') || (src [0] == '\n' && src [1] == '\r'))
|
||||
{ *dest++ = '\r' ;
|
||||
*dest++ = '\n' ;
|
||||
|
13
src/common.h
13
src/common.h
@ -220,6 +220,12 @@ make_size_t (int x)
|
||||
** contents.
|
||||
*/
|
||||
|
||||
|
||||
typedef struct
|
||||
{ int size ;
|
||||
SF_BROADCAST_INFO binfo ;
|
||||
} SF_BROADCAST_VAR ;
|
||||
|
||||
typedef struct sf_private_tag
|
||||
{
|
||||
/* Canary in a coal mine. */
|
||||
@ -318,6 +324,7 @@ typedef struct sf_private_tag
|
||||
|
||||
/* Broadcast (EBU) Info */
|
||||
SF_BROADCAST_INFO *broadcast_info ;
|
||||
SF_BROADCAST_VAR *broadcast_var ;
|
||||
|
||||
/* Channel map data (if present) : an array of ints. */
|
||||
int *channel_map ;
|
||||
@ -787,6 +794,12 @@ SF_BROADCAST_INFO* broadcast_info_alloc (void) ;
|
||||
int broadcast_info_copy (SF_BROADCAST_INFO* dst, const SF_BROADCAST_INFO* src) ;
|
||||
int broadcast_add_coding_history (SF_BROADCAST_INFO* bext, unsigned int channels, unsigned int samplerate, int format) ;
|
||||
|
||||
SF_BROADCAST_VAR* broadcast_var_alloc (size_t datasize) ;
|
||||
int broadcast_var_set (SF_PRIVATE *psf, const SF_BROADCAST_INFO * data, size_t datasize) ;
|
||||
int broadcast_var_get (SF_PRIVATE *psf, SF_BROADCAST_INFO * data, size_t datasize) ;
|
||||
void broadcast_info_to_var (SF_PRIVATE *psf) ;
|
||||
|
||||
|
||||
typedef struct
|
||||
{ int channels ;
|
||||
int endianness ;
|
||||
|
@ -1116,29 +1116,37 @@ sf_command (SNDFILE *sndfile, int command, void *data, int datasize)
|
||||
if ((psf->mode != SFM_WRITE) && (psf->mode != SFM_RDWR))
|
||||
return SF_FALSE ;
|
||||
/* If data has already been written this must fail. */
|
||||
if (psf->broadcast_info == NULL && psf->have_written)
|
||||
if (psf->broadcast_var == NULL && psf->have_written)
|
||||
{ psf->error = SFE_CMD_HAS_DATA ;
|
||||
return SF_FALSE ;
|
||||
} ;
|
||||
|
||||
#if 0
|
||||
if (psf->broadcast_info == NULL)
|
||||
psf->broadcast_info = broadcast_info_alloc () ;
|
||||
|
||||
broadcast_info_copy (psf->broadcast_info, data) ;
|
||||
broadcast_add_coding_history (psf->broadcast_info, psf->sf.channels, psf->sf.samplerate, psf->sf.format) ;
|
||||
#else
|
||||
broadcast_var_set (psf, data, datasize) ;
|
||||
#endif
|
||||
|
||||
if (psf->write_header)
|
||||
psf->write_header (psf, SF_TRUE) ;
|
||||
return SF_TRUE ;
|
||||
|
||||
case SFC_GET_BROADCAST_INFO :
|
||||
if (datasize != sizeof (SF_BROADCAST_INFO) || data == NULL)
|
||||
if (data == NULL)
|
||||
{ psf->error = SFE_BAD_COMMAND_PARAM ;
|
||||
return SF_FALSE ;
|
||||
} ;
|
||||
#if 0
|
||||
if (psf->broadcast_info == NULL)
|
||||
return SF_FALSE ;
|
||||
return broadcast_info_copy (data, psf->broadcast_info) ;
|
||||
#else
|
||||
return broadcast_var_get (psf, data, datasize) ;
|
||||
#endif
|
||||
|
||||
case SFC_GET_INSTRUMENT :
|
||||
if (datasize != sizeof (SF_INSTRUMENT) || data == NULL)
|
||||
@ -2423,6 +2431,9 @@ psf_close (SF_PRIVATE *psf)
|
||||
if (psf->broadcast_info)
|
||||
free (psf->broadcast_info) ;
|
||||
|
||||
if (psf->broadcast_var)
|
||||
free (psf->broadcast_var) ;
|
||||
|
||||
if (psf->loop_info)
|
||||
free (psf->loop_info) ;
|
||||
|
||||
|
@ -427,20 +427,27 @@ typedef struct
|
||||
/* Struct used to retrieve broadcast (EBU) information from a file.
|
||||
** Strongly (!) based on EBU "bext" chunk format used in Broadcast WAVE.
|
||||
*/
|
||||
typedef struct
|
||||
{ char description [256] ;
|
||||
char originator [32] ;
|
||||
char originator_reference [32] ;
|
||||
char origination_date [10] ;
|
||||
char origination_time [8] ;
|
||||
unsigned int time_reference_low ;
|
||||
unsigned int time_reference_high ;
|
||||
short version ;
|
||||
char umid [64] ;
|
||||
char reserved [190] ;
|
||||
unsigned int coding_history_size ;
|
||||
char coding_history [256] ;
|
||||
} SF_BROADCAST_INFO ;
|
||||
#define SF_BROADCAST_INFO_VAR(coding_hist_size) \
|
||||
struct \
|
||||
{ char description [256] ; \
|
||||
char originator [32] ; \
|
||||
char originator_reference [32] ; \
|
||||
char origination_date [10] ; \
|
||||
char origination_time [8] ; \
|
||||
unsigned int time_reference_low ; \
|
||||
unsigned int time_reference_high ; \
|
||||
short version ; \
|
||||
char umid [64] ; \
|
||||
char reserved [190] ; \
|
||||
unsigned int coding_history_size ; \
|
||||
char coding_history [coding_hist_size] ; \
|
||||
}
|
||||
|
||||
/* SF_BROADCAST_INFO is the above struct with coding_history field of 256 bytes. */
|
||||
typedef SF_BROADCAST_INFO_VAR (256) SF_BROADCAST_INFO ;
|
||||
|
||||
|
||||
/* Virtual I/O functionality. */
|
||||
|
||||
typedef sf_count_t (*sf_vio_get_filelen) (void *user_data) ;
|
||||
typedef sf_count_t (*sf_vio_seek) (sf_count_t offset, int whence, void *user_data) ;
|
||||
|
11
src/wav.c
11
src/wav.c
@ -575,6 +575,7 @@ wav_read_header (SF_PRIVATE *psf, int *blockalign, int *framesperblock)
|
||||
|
||||
if ((error = wav_read_bext_chunk (psf, dword)))
|
||||
return error ;
|
||||
broadcast_info_to_var (psf) ;
|
||||
break ;
|
||||
|
||||
case PAD_MARKER :
|
||||
@ -1073,7 +1074,7 @@ wav_write_header (SF_PRIVATE *psf, int calc_length)
|
||||
psf_binheader_writef (psf, "ft8", (float) psf->peak_info->peaks [k].value, psf->peak_info->peaks [k].position) ;
|
||||
} ;
|
||||
|
||||
if (psf->broadcast_info != NULL)
|
||||
if (psf->broadcast_var != NULL)
|
||||
wav_write_bext_chunk (psf) ;
|
||||
|
||||
if (psf->instrument != NULL)
|
||||
@ -1621,12 +1622,12 @@ wav_read_bext_chunk (SF_PRIVATE *psf, unsigned int chunksize)
|
||||
SF_BROADCAST_INFO* b ;
|
||||
unsigned int bytes = 0 ;
|
||||
|
||||
if ((psf->broadcast_info = calloc (1, sizeof (SF_BROADCAST_INFO))) == NULL)
|
||||
if ((psf->broadcast_var = broadcast_var_alloc (chunksize + 128)) == NULL)
|
||||
{ psf->error = SFE_MALLOC_FAILED ;
|
||||
return psf->error ;
|
||||
} ;
|
||||
|
||||
b = psf->broadcast_info ;
|
||||
b = & psf->broadcast_var->binfo ;
|
||||
|
||||
bytes += psf_binheader_readf (psf, "b", b->description, sizeof (b->description)) ;
|
||||
bytes += psf_binheader_readf (psf, "b", b->originator, sizeof (b->originator)) ;
|
||||
@ -1659,9 +1660,11 @@ static int
|
||||
wav_write_bext_chunk (SF_PRIVATE *psf)
|
||||
{ SF_BROADCAST_INFO *b ;
|
||||
|
||||
if ((b = psf->broadcast_info) == NULL)
|
||||
if (psf->broadcast_var == NULL)
|
||||
return -1 ;
|
||||
|
||||
b = & psf->broadcast_var->binfo ;
|
||||
|
||||
psf_binheader_writef (psf, "m4", bext_MARKER, WAV_BEXT_CHUNK_SIZE + b->coding_history_size) ;
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user