Working Wavpack filter for compressing WAV filies.
Improved error handling of filter routines. Improved verbose logging.
This commit is contained in:
parent
fd087a8949
commit
af39994a59
9 changed files with 382 additions and 57 deletions
|
@ -64,15 +64,17 @@ ssize_t packpnm_filter(struct filter_info *fi, void *filter_private);
|
||||||
|
|
||||||
#ifdef _ENABLE_WAVPACK_
|
#ifdef _ENABLE_WAVPACK_
|
||||||
extern size_t wavpack_filter_encode(uchar_t *in_buf, size_t len, uchar_t **out_buf);
|
extern size_t wavpack_filter_encode(uchar_t *in_buf, size_t len, uchar_t **out_buf);
|
||||||
|
extern size_t wavpack_filter_decode(uchar_t *in_buf, size_t len, uchar_t **out_buf,
|
||||||
|
ssize_t out_len);
|
||||||
ssize_t wavpack_filter(struct filter_info *fi, void *filter_private);
|
ssize_t wavpack_filter(struct filter_info *fi, void *filter_private);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void
|
void
|
||||||
add_filters_by_type(struct type_data *typetab, struct filter_flags *ff)
|
add_filters_by_type(struct type_data *typetab, struct filter_flags *ff)
|
||||||
{
|
{
|
||||||
#ifndef _MPLV2_LICENSE_
|
struct scratch_buffer *sdat = NULL;
|
||||||
struct scratch_buffer *sdat;
|
|
||||||
int slot;
|
int slot;
|
||||||
|
#ifndef _MPLV2_LICENSE_
|
||||||
|
|
||||||
if (ff->enable_packjpg) {
|
if (ff->enable_packjpg) {
|
||||||
sdat = (struct scratch_buffer *)malloc(sizeof (struct scratch_buffer));
|
sdat = (struct scratch_buffer *)malloc(sizeof (struct scratch_buffer));
|
||||||
|
@ -95,6 +97,21 @@ add_filters_by_type(struct type_data *typetab, struct filter_flags *ff)
|
||||||
typetab[slot].filter_name = "packPNM";
|
typetab[slot].filter_name = "packPNM";
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef _ENABLE_WAVPACK_
|
||||||
|
if (ff->enable_wavpack) {
|
||||||
|
if (!sdat) {
|
||||||
|
sdat = (struct scratch_buffer *)malloc(sizeof (struct scratch_buffer));
|
||||||
|
sdat->in_buff = NULL;
|
||||||
|
sdat->in_bufflen = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
slot = TYPE_WAV >> 3;
|
||||||
|
typetab[slot].filter_private = sdat;
|
||||||
|
typetab[slot].filter_func = wavpack_filter;
|
||||||
|
typetab[slot].filter_name = "WavPack";
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -279,13 +296,13 @@ packjpg_filter(struct filter_info *fi, void *filter_private)
|
||||||
out = NULL;
|
out = NULL;
|
||||||
if ((len = packjpg_filter_process(mapbuf, in_size, &out)) == 0) {
|
if ((len = packjpg_filter_process(mapbuf, in_size, &out)) == 0) {
|
||||||
/*
|
/*
|
||||||
* If filter failed we write out the original data and indicate skip
|
* If filter failed we write out the original data and indicate a
|
||||||
* to continue the archive extraction.
|
* soft error to continue the archive extraction.
|
||||||
*/
|
*/
|
||||||
free(out);
|
free(out);
|
||||||
if (write_archive_data(fi->target_arc, mapbuf, len1, fi->block_size) < len1)
|
if (write_archive_data(fi->target_arc, mapbuf, len1, fi->block_size) < len1)
|
||||||
return (FILTER_RETURN_ERROR);
|
return (FILTER_RETURN_ERROR);
|
||||||
return (FILTER_RETURN_SKIP);
|
return (FILTER_RETURN_SOFT_ERROR);
|
||||||
}
|
}
|
||||||
rv = write_archive_data(fi->target_arc, out, len, fi->block_size);
|
rv = write_archive_data(fi->target_arc, out, len, fi->block_size);
|
||||||
free(out);
|
free(out);
|
||||||
|
@ -382,13 +399,13 @@ packpnm_filter(struct filter_info *fi, void *filter_private)
|
||||||
out = NULL;
|
out = NULL;
|
||||||
if ((len = packpnm_filter_process(mapbuf, in_size, &out)) == 0) {
|
if ((len = packpnm_filter_process(mapbuf, in_size, &out)) == 0) {
|
||||||
/*
|
/*
|
||||||
* If filter failed we write out the original data and indicate skip
|
* If filter failed we write out the original data and indicate a
|
||||||
* to continue the archive extraction.
|
* soft error to continue the archive extraction.
|
||||||
*/
|
*/
|
||||||
free(out);
|
free(out);
|
||||||
if (write_archive_data(fi->target_arc, mapbuf, len1, fi->block_size) < len1)
|
if (write_archive_data(fi->target_arc, mapbuf, len1, fi->block_size) < len1)
|
||||||
return (FILTER_RETURN_ERROR);
|
return (FILTER_RETURN_ERROR);
|
||||||
return (FILTER_RETURN_SKIP);
|
return (FILTER_RETURN_SOFT_ERROR);
|
||||||
}
|
}
|
||||||
rv = write_archive_data(fi->target_arc, out, len, fi->block_size);
|
rv = write_archive_data(fi->target_arc, out, len, fi->block_size);
|
||||||
free(out);
|
free(out);
|
||||||
|
@ -413,7 +430,7 @@ wavpack_filter(struct filter_info *fi, void *filter_private)
|
||||||
if (fi->compressing) {
|
if (fi->compressing) {
|
||||||
mapbuf = mmap(NULL, len, PROT_READ, MAP_SHARED, fi->fd, 0);
|
mapbuf = mmap(NULL, len, PROT_READ, MAP_SHARED, fi->fd, 0);
|
||||||
if (mapbuf == NULL) {
|
if (mapbuf == NULL) {
|
||||||
log_msg(LOG_ERR, 1, "Mmap failed in packPNM filter.");
|
log_msg(LOG_ERR, 1, "Mmap failed in WavPack filter.");
|
||||||
return (FILTER_RETURN_ERROR);
|
return (FILTER_RETURN_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -475,7 +492,7 @@ wavpack_filter(struct filter_info *fi, void *filter_private)
|
||||||
}
|
}
|
||||||
munmap(mapbuf, len1);
|
munmap(mapbuf, len1);
|
||||||
|
|
||||||
in_size = LE64(len);
|
in_size = LE64(len1);
|
||||||
rv = archive_write_data(fi->target_arc, &in_size, 8);
|
rv = archive_write_data(fi->target_arc, &in_size, 8);
|
||||||
if (rv != 8)
|
if (rv != 8)
|
||||||
return (rv);
|
return (rv);
|
||||||
|
@ -488,15 +505,15 @@ wavpack_filter(struct filter_info *fi, void *filter_private)
|
||||||
* Decompression case.
|
* Decompression case.
|
||||||
*/
|
*/
|
||||||
out = NULL;
|
out = NULL;
|
||||||
if ((len = wavpack_filter_encode(mapbuf, in_size, &out)) == 0) {
|
if ((len = wavpack_filter_decode(mapbuf, len, &out, in_size)) == 0) {
|
||||||
/*
|
/*
|
||||||
* If filter failed we write out the original data and indicate skip
|
* If filter failed we write out the original data and indicate a
|
||||||
* to continue the archive extraction.
|
* soft error to continue the archive extraction.
|
||||||
*/
|
*/
|
||||||
free(out);
|
free(out);
|
||||||
if (write_archive_data(fi->target_arc, mapbuf, len1, fi->block_size) < len1)
|
if (write_archive_data(fi->target_arc, mapbuf, len1, fi->block_size) < len1)
|
||||||
return (FILTER_RETURN_ERROR);
|
return (FILTER_RETURN_ERROR);
|
||||||
return (FILTER_RETURN_SKIP);
|
return (FILTER_RETURN_SOFT_ERROR);
|
||||||
}
|
}
|
||||||
rv = write_archive_data(fi->target_arc, out, len, fi->block_size);
|
rv = write_archive_data(fi->target_arc, out, len, fi->block_size);
|
||||||
free(out);
|
free(out);
|
||||||
|
|
|
@ -39,6 +39,7 @@ extern "C" {
|
||||||
|
|
||||||
#define FILTER_RETURN_SKIP (1)
|
#define FILTER_RETURN_SKIP (1)
|
||||||
#define FILTER_RETURN_ERROR (-1)
|
#define FILTER_RETURN_ERROR (-1)
|
||||||
|
#define FILTER_RETURN_SOFT_ERROR (-2)
|
||||||
#define FILTER_XATTR_ENTRY "_._pc_filter_xattr"
|
#define FILTER_XATTR_ENTRY "_._pc_filter_xattr"
|
||||||
|
|
||||||
struct filter_info {
|
struct filter_info {
|
||||||
|
@ -52,6 +53,7 @@ struct filter_info {
|
||||||
|
|
||||||
struct filter_flags {
|
struct filter_flags {
|
||||||
int enable_packjpg;
|
int enable_packjpg;
|
||||||
|
int enable_wavpack;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef ssize_t (*filter_func_ptr)(struct filter_info *fi, void *filter_private);
|
typedef ssize_t (*filter_func_ptr)(struct filter_info *fi, void *filter_private);
|
||||||
|
|
|
@ -1156,9 +1156,8 @@ archiver_thread_func(void *dat) {
|
||||||
} else {
|
} else {
|
||||||
archive_entry_set_size(entry, archive_entry_size(entry));
|
archive_entry_set_size(entry, archive_entry_size(entry));
|
||||||
}
|
}
|
||||||
if (pctx->verbose)
|
log_msg(LOG_VERBOSE, 0, "%5d/%5d %8" PRIu64 " %s", ctr, pctx->archive_members_count,
|
||||||
log_msg(LOG_INFO, 0, "%5d/%5d %8" PRIu64 " %s", ctr, pctx->archive_members_count,
|
archive_entry_size(entry), name);
|
||||||
archive_entry_size(entry), name);
|
|
||||||
|
|
||||||
archive_entry_linkify(resolver, &entry, &spare_entry);
|
archive_entry_linkify(resolver, &entry, &spare_entry);
|
||||||
ent = entry;
|
ent = entry;
|
||||||
|
@ -1201,7 +1200,7 @@ start_archiver(pc_ctx_t *pctx) {
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
copy_data_out(struct archive *ar, struct archive *aw, struct archive_entry *entry,
|
copy_data_out(struct archive *ar, struct archive *aw, struct archive_entry *entry,
|
||||||
int typ)
|
int typ, pc_ctx_t *pctx)
|
||||||
{
|
{
|
||||||
int64_t offset;
|
int64_t offset;
|
||||||
const void *buff;
|
const void *buff;
|
||||||
|
@ -1219,7 +1218,18 @@ copy_data_out(struct archive *ar, struct archive *aw, struct archive_entry *entr
|
||||||
return (ARCHIVE_FATAL);
|
return (ARCHIVE_FATAL);
|
||||||
|
|
||||||
} else if (rv == FILTER_RETURN_SKIP) {
|
} else if (rv == FILTER_RETURN_SKIP) {
|
||||||
log_msg(LOG_WARN, 0, "Filter function failed for entry.");
|
log_msg(LOG_WARN, 0, "Filter function skipped.");
|
||||||
|
return (ARCHIVE_WARN);
|
||||||
|
|
||||||
|
} else if (rv == FILTER_RETURN_SOFT_ERROR) {
|
||||||
|
log_msg(LOG_WARN, 0, "Filter function failed for entry: %s.",
|
||||||
|
archive_entry_pathname(entry));
|
||||||
|
pctx->errored_count++;
|
||||||
|
if (pctx->err_paths_fd) {
|
||||||
|
fprintf(pctx->err_paths_fd, "%s,%s",
|
||||||
|
archive_entry_pathname(entry),
|
||||||
|
typetab[(typ >> 3)].filter_name);
|
||||||
|
}
|
||||||
return (ARCHIVE_WARN);
|
return (ARCHIVE_WARN);
|
||||||
} else {
|
} else {
|
||||||
return (ARCHIVE_OK);
|
return (ARCHIVE_OK);
|
||||||
|
@ -1247,7 +1257,7 @@ copy_data_out(struct archive *ar, struct archive *aw, struct archive_entry *entr
|
||||||
|
|
||||||
static int
|
static int
|
||||||
archive_extract_entry(struct archive *a, struct archive_entry *entry,
|
archive_extract_entry(struct archive *a, struct archive_entry *entry,
|
||||||
struct archive *ad, int typ)
|
struct archive *ad, int typ, pc_ctx_t *pctx)
|
||||||
{
|
{
|
||||||
int r, r2;
|
int r, r2;
|
||||||
char *filter_name;
|
char *filter_name;
|
||||||
|
@ -1271,7 +1281,7 @@ archive_extract_entry(struct archive *a, struct archive_entry *entry,
|
||||||
archive_copy_error(a, ad);
|
archive_copy_error(a, ad);
|
||||||
} else if (!archive_entry_size_is_set(entry) || archive_entry_size(entry) > 0) {
|
} else if (!archive_entry_size_is_set(entry) || archive_entry_size(entry) > 0) {
|
||||||
/* Otherwise, pour data into the entry. */
|
/* Otherwise, pour data into the entry. */
|
||||||
r = copy_data_out(a, ad, entry, typ);
|
r = copy_data_out(a, ad, entry, typ, pctx);
|
||||||
}
|
}
|
||||||
r2 = archive_write_finish_entry(ad);
|
r2 = archive_write_finish_entry(ad);
|
||||||
if (r2 < ARCHIVE_WARN)
|
if (r2 < ARCHIVE_WARN)
|
||||||
|
@ -1375,6 +1385,11 @@ extractor_thread_func(void *dat) {
|
||||||
log_msg(LOG_ERR, 1, "Cannot change to dir: %s", pctx->to_filename);
|
log_msg(LOG_ERR, 1, "Cannot change to dir: %s", pctx->to_filename);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Open list file for pathnames that had filter errors (if any).
|
||||||
|
*/
|
||||||
|
pctx->err_paths_fd = fopen("filter_failures.txt", "w");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1431,7 +1446,7 @@ extractor_thread_func(void *dat) {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!pctx->list_mode) {
|
if (!pctx->list_mode) {
|
||||||
rv = archive_extract_entry(arc, entry, awd, typ);
|
rv = archive_extract_entry(arc, entry, awd, typ, pctx);
|
||||||
} else {
|
} else {
|
||||||
rv = archive_list_entry(arc, entry, typ);
|
rv = archive_list_entry(arc, entry, typ);
|
||||||
}
|
}
|
||||||
|
@ -1439,8 +1454,8 @@ extractor_thread_func(void *dat) {
|
||||||
log_msg(LOG_WARN, 0, "%s: %s", archive_entry_pathname(entry),
|
log_msg(LOG_WARN, 0, "%s: %s", archive_entry_pathname(entry),
|
||||||
archive_error_string(arc));
|
archive_error_string(arc));
|
||||||
|
|
||||||
} else if (pctx->verbose) {
|
} else {
|
||||||
log_msg(LOG_INFO, 0, "%5d %8" PRIu64 " %s", ctr, archive_entry_size(entry),
|
log_msg(LOG_VERBOSE, 0, "%5d %8" PRIu64 " %s", ctr, archive_entry_size(entry),
|
||||||
archive_entry_pathname(entry));
|
archive_entry_pathname(entry));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1452,12 +1467,26 @@ extractor_thread_func(void *dat) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pctx->list_mode) {
|
if (!pctx->list_mode) {
|
||||||
|
if (pctx->errored_count > 0) {
|
||||||
|
log_msg(LOG_WARN, 0, "WARN: %d pathnames failed filter decoding.");
|
||||||
|
if (pctx->err_paths_fd) {
|
||||||
|
fclose(pctx->err_paths_fd);
|
||||||
|
log_msg(LOG_WARN, 0, "Please see file filter_failures.txt.");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (pctx->err_paths_fd) {
|
||||||
|
fclose(pctx->err_paths_fd);
|
||||||
|
(void) unlink("filter_failures.txt");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (got_cwd) {
|
if (got_cwd) {
|
||||||
rv = chdir(cwd);
|
rv = chdir(cwd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
archive_read_free(arc);
|
archive_read_free(arc);
|
||||||
archive_write_free(awd);
|
archive_write_free(awd);
|
||||||
|
|
||||||
done:
|
done:
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,11 +93,11 @@ read_block(read_data *rdat, uchar_t *tgt, uint32_t len, uint32_t *numread)
|
||||||
numcopy = rdat->bufsize - rdat->bytes_read;
|
numcopy = rdat->bufsize - rdat->bytes_read;
|
||||||
|
|
||||||
if (numcopy == 0)
|
if (numcopy == 0)
|
||||||
return (1);
|
return (FALSE);
|
||||||
memcpy(tgt, rdat->buf + rdat->bytes_read, numcopy);
|
memcpy(tgt, rdat->buf + rdat->bytes_read, numcopy);
|
||||||
rdat->bytes_read += numcopy;
|
rdat->bytes_read += numcopy;
|
||||||
*numread = numcopy;
|
*numread = numcopy;
|
||||||
return (0);
|
return (TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -116,13 +116,106 @@ read_block_ref(read_data *rdat, uchar_t **ref, uint32_t len, uint32_t *numread)
|
||||||
numcopy = rdat->bufsize - rdat->bytes_read;
|
numcopy = rdat->bufsize - rdat->bytes_read;
|
||||||
|
|
||||||
if (numcopy == 0)
|
if (numcopy == 0)
|
||||||
return (1);
|
return (FALSE);
|
||||||
*ref = rdat->buf + rdat->bytes_read;
|
*ref = rdat->buf + rdat->bytes_read;
|
||||||
rdat->bytes_read += numcopy;
|
rdat->bytes_read += numcopy;
|
||||||
*numread = numcopy;
|
*numread = numcopy;
|
||||||
|
return (TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Memory buffer I/O functions mirroring semantics of stdio, for Wavpack
|
||||||
|
* I/O ops structure.
|
||||||
|
*/
|
||||||
|
static int32_t
|
||||||
|
read_bytes(void *id, void *data, int32_t bcount)
|
||||||
|
{
|
||||||
|
read_data *rdat = (read_data *)id;
|
||||||
|
uint32_t numread;
|
||||||
|
|
||||||
|
if (!read_block(rdat, (uchar_t *)data, bcount, &numread)) {
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
return (numread);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t
|
||||||
|
get_pos(void *id)
|
||||||
|
{
|
||||||
|
read_data *rdat = (read_data *)id;
|
||||||
|
return (rdat->bytes_read);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
set_pos_abs(void *id, uint32_t pos)
|
||||||
|
{
|
||||||
|
read_data *rdat = (read_data *)id;
|
||||||
|
|
||||||
|
if (pos > rdat->bufsize)
|
||||||
|
pos = rdat->bufsize;
|
||||||
|
rdat->bytes_read = pos;
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
set_pos_rel(void *id, int32_t delta, int mode)
|
||||||
|
{
|
||||||
|
read_data *rdat = (read_data *)id;
|
||||||
|
int64_t br;
|
||||||
|
|
||||||
|
br = rdat->bytes_read;
|
||||||
|
if (mode == SEEK_SET) {
|
||||||
|
br = delta;
|
||||||
|
} else if (mode == SEEK_CUR) {
|
||||||
|
br += delta;
|
||||||
|
} else if (mode == SEEK_END) {
|
||||||
|
br = rdat->bufsize - delta;
|
||||||
|
} else {
|
||||||
|
errno = EINVAL;
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
if (br < 0) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
if (br > rdat->bufsize)
|
||||||
|
br = rdat->bufsize;
|
||||||
|
rdat->bytes_read = br;
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
push_back_byte(void *id, int c)
|
||||||
|
{
|
||||||
|
read_data *rdat = (read_data *)id;
|
||||||
|
|
||||||
|
if (rdat->bytes_read > 0) {
|
||||||
|
rdat->bytes_read--;
|
||||||
|
rdat->buf[rdat->bytes_read] = c;
|
||||||
|
return (c);
|
||||||
|
} else {
|
||||||
|
return (EOF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t
|
||||||
|
get_length(void *id)
|
||||||
|
{
|
||||||
|
read_data *rdat = (read_data *)id;
|
||||||
|
return (rdat->bufsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
can_seek(void *id)
|
||||||
|
{
|
||||||
|
return (TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static WavpackStreamReader memreader = {
|
||||||
|
read_bytes, get_pos, set_pos_abs, set_pos_rel, push_back_byte,
|
||||||
|
get_length, can_seek, write_block
|
||||||
|
};
|
||||||
|
|
||||||
#define INPUT_SAMPLES 65536
|
#define INPUT_SAMPLES 65536
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -140,7 +233,6 @@ pack_audio(WavpackContext *wpc, read_data *rdat)
|
||||||
|
|
||||||
WavpackPackInit(wpc);
|
WavpackPackInit(wpc);
|
||||||
bytes_per_sample = WavpackGetBytesPerSample (wpc) * WavpackGetNumChannels (wpc);
|
bytes_per_sample = WavpackGetBytesPerSample (wpc) * WavpackGetNumChannels (wpc);
|
||||||
//input_buffer = malloc(input_samples * bytes_per_sample);
|
|
||||||
sample_buffer = malloc(input_samples * sizeof (int32_t) * WavpackGetNumChannels (wpc));
|
sample_buffer = malloc(input_samples * sizeof (int32_t) * WavpackGetNumChannels (wpc));
|
||||||
samples_remaining = WavpackGetNumSamples (wpc);
|
samples_remaining = WavpackGetNumSamples (wpc);
|
||||||
|
|
||||||
|
@ -212,7 +304,7 @@ pack_audio(WavpackContext *wpc, read_data *rdat)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Helper routine for wavpack. Higher level encoding interface adapted from
|
* Helper routine for wavpack. Higher level encoding interface adapted from
|
||||||
* pack_file() in cli/wavpack.c
|
* pack_file() in cli/wavpack.c and unpack_file() in cli/wvunpack.c
|
||||||
*/
|
*/
|
||||||
size_t
|
size_t
|
||||||
wavpack_filter_encode(uchar_t *in_buf, size_t len, uchar_t **out_buf)
|
wavpack_filter_encode(uchar_t *in_buf, size_t len, uchar_t **out_buf)
|
||||||
|
@ -233,27 +325,29 @@ wavpack_filter_encode(uchar_t *in_buf, size_t len, uchar_t **out_buf)
|
||||||
memset(&loc_config, 0, sizeof (loc_config));
|
memset(&loc_config, 0, sizeof (loc_config));
|
||||||
adobe_mode = 0;
|
adobe_mode = 0;
|
||||||
|
|
||||||
/*
|
|
||||||
* Default WavPack config.
|
|
||||||
*/
|
|
||||||
loc_config.flags |= CONFIG_FAST_FLAG;
|
|
||||||
|
|
||||||
*out_buf = (uchar_t *)malloc(len);
|
*out_buf = (uchar_t *)malloc(len);
|
||||||
if (*out_buf == NULL)
|
if (*out_buf == NULL) {
|
||||||
|
log_msg(LOG_ERR, 1, "malloc failed.");
|
||||||
return (0);
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
wv_dat.buf = *out_buf;
|
wv_dat.buf = *out_buf;
|
||||||
wv_dat.bufsize = len;
|
wv_dat.bufsize = len;
|
||||||
wpc = WavpackOpenFileOutput (write_block, &wv_dat, NULL);
|
wpc = WavpackOpenFileOutput(write_block, &wv_dat, NULL);
|
||||||
|
|
||||||
rd_dat.buf = in_buf;
|
rd_dat.buf = in_buf;
|
||||||
rd_dat.bufsize = len;
|
rd_dat.bufsize = len;
|
||||||
|
|
||||||
// read (and copy to output) initial RIFF form header
|
// Read (and copy to output) initial RIFF form header
|
||||||
if (read_block(&rd_dat, (uchar_t *)&riff_chunk_header, sizeof (RiffChunkHeader), &bcount) ||
|
if (!read_block(&rd_dat, (uchar_t *)&riff_chunk_header, sizeof (RiffChunkHeader), &bcount) ||
|
||||||
bcount != sizeof (RiffChunkHeader) || strncmp (riff_chunk_header.ckID, "RIFF", 4) ||
|
bcount != sizeof (RiffChunkHeader) || strncmp(riff_chunk_header.ckID, "RIFF", 4) ||
|
||||||
strncmp (riff_chunk_header.formType, "WAVE", 4)) {
|
strncmp(riff_chunk_header.formType, "WAVE", 4)) {
|
||||||
WavpackCloseFile (wpc);
|
WavpackCloseFile(wpc);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!WavpackAddWrapper(wpc, &riff_chunk_header, sizeof (RiffChunkHeader))) {
|
||||||
|
WavpackCloseFile(wpc);
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -261,9 +355,14 @@ wavpack_filter_encode(uchar_t *in_buf, size_t len, uchar_t **out_buf)
|
||||||
// (until the data chunk) and copy them to the output
|
// (until the data chunk) and copy them to the output
|
||||||
//
|
//
|
||||||
while (1) {
|
while (1) {
|
||||||
if (read_block(&rd_dat, (uchar_t *)&chunk_header, sizeof (ChunkHeader), &bcount) ||
|
if (!read_block(&rd_dat, (uchar_t *)&chunk_header, sizeof (ChunkHeader), &bcount) ||
|
||||||
bcount != sizeof (ChunkHeader)) {
|
bcount != sizeof (ChunkHeader)) {
|
||||||
WavpackCloseFile (wpc);
|
WavpackCloseFile(wpc);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!WavpackAddWrapper(wpc, &chunk_header, sizeof (ChunkHeader))) {
|
||||||
|
WavpackCloseFile(wpc);
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -278,9 +377,14 @@ wavpack_filter_encode(uchar_t *in_buf, size_t len, uchar_t **out_buf)
|
||||||
if (chunk_header.ckSize < 16 || chunk_header.ckSize > sizeof (WaveHeader) ||
|
if (chunk_header.ckSize < 16 || chunk_header.ckSize > sizeof (WaveHeader) ||
|
||||||
!read_block(&rd_dat, (uchar_t *)&WaveHeader, chunk_header.ckSize, &bcount) ||
|
!read_block(&rd_dat, (uchar_t *)&WaveHeader, chunk_header.ckSize, &bcount) ||
|
||||||
bcount != chunk_header.ckSize) {
|
bcount != chunk_header.ckSize) {
|
||||||
WavpackCloseFile (wpc);
|
WavpackCloseFile(wpc);
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
if (!WavpackAddWrapper(wpc, &WaveHeader, chunk_header.ckSize)) {
|
||||||
|
WavpackCloseFile(wpc);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
WavpackLittleEndianToNative (&WaveHeader, WaveHeaderFormat);
|
WavpackLittleEndianToNative (&WaveHeader, WaveHeaderFormat);
|
||||||
|
|
||||||
if (chunk_header.ckSize > 16 && WaveHeader.cbSize == 2)
|
if (chunk_header.ckSize > 16 && WaveHeader.cbSize == 2)
|
||||||
|
@ -306,7 +410,7 @@ wavpack_filter_encode(uchar_t *in_buf, size_t len, uchar_t **out_buf)
|
||||||
supported = FALSE;
|
supported = FALSE;
|
||||||
|
|
||||||
if (!supported) {
|
if (!supported) {
|
||||||
WavpackCloseFile (wpc);
|
WavpackCloseFile(wpc);
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -367,7 +471,7 @@ wavpack_filter_encode(uchar_t *in_buf, size_t len, uchar_t **out_buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!WavpackSetConfiguration(wpc, &loc_config, total_samples)) {
|
if (!WavpackSetConfiguration(wpc, &loc_config, total_samples)) {
|
||||||
WavpackCloseFile (wpc);
|
WavpackCloseFile(wpc);
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -401,6 +505,167 @@ wavpack_filter_encode(uchar_t *in_buf, size_t len, uchar_t **out_buf)
|
||||||
return (wv_dat.bytes_written);
|
return (wv_dat.bytes_written);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reformat samples from longs in processor's native endian mode to
|
||||||
|
* little-endian data with (possibly) less than 4 bytes / sample.
|
||||||
|
*/
|
||||||
|
static unsigned char *
|
||||||
|
format_samples(int bps, unsigned char *dst, int32_t *src, uint32_t samcnt)
|
||||||
|
{
|
||||||
|
int32_t temp;
|
||||||
|
|
||||||
|
switch (bps) {
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
while (samcnt--)
|
||||||
|
*dst++ = *src++ + 128;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
while (samcnt--) {
|
||||||
|
*dst++ = (unsigned char) (temp = *src++);
|
||||||
|
*dst++ = (unsigned char) (temp >> 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
while (samcnt--) {
|
||||||
|
*dst++ = (unsigned char) (temp = *src++);
|
||||||
|
*dst++ = (unsigned char) (temp >> 8);
|
||||||
|
*dst++ = (unsigned char) (temp >> 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 4:
|
||||||
|
while (samcnt--) {
|
||||||
|
*dst++ = (unsigned char) (temp = *src++);
|
||||||
|
*dst++ = (unsigned char) (temp >> 8);
|
||||||
|
*dst++ = (unsigned char) (temp >> 16);
|
||||||
|
*dst++ = (unsigned char) (temp >> 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
wavpack_filter_decode(uchar_t *in_buf, size_t len, uchar_t **out_buf, ssize_t out_len)
|
||||||
|
{
|
||||||
|
write_data wr_dat;
|
||||||
|
read_data rd_dat;
|
||||||
|
WavpackContext *wpc;
|
||||||
|
int bytes_per_sample, num_channels, bps, result;
|
||||||
|
int32_t *temp_buffer;
|
||||||
|
uchar_t *output_ptr = NULL, *output_buffer = NULL;
|
||||||
|
uint32_t total_unpacked_samples = 0, output_buffer_size = 0;
|
||||||
|
char error[80];
|
||||||
|
|
||||||
|
rd_dat.buf = in_buf;
|
||||||
|
rd_dat.bufsize = len;
|
||||||
|
rd_dat.bytes_read = 0;
|
||||||
|
wpc = WavpackOpenFileInputEx(&memreader, &rd_dat, NULL, error, OPEN_WRAPPER, 0);
|
||||||
|
if (!wpc) {
|
||||||
|
log_msg(LOG_ERR, 0, error);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
num_channels = WavpackGetNumChannels(wpc);
|
||||||
|
bps = WavpackGetBytesPerSample(wpc);
|
||||||
|
bytes_per_sample = num_channels * bps;
|
||||||
|
|
||||||
|
*out_buf = (uchar_t *)malloc(out_len);
|
||||||
|
if (*out_buf == NULL) {
|
||||||
|
log_msg(LOG_ERR, 1, "malloc failed.");
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Must start with a wrapper.
|
||||||
|
*/
|
||||||
|
wr_dat.buf = *out_buf;
|
||||||
|
wr_dat.bufsize = len;
|
||||||
|
wr_dat.bytes_written = 0;
|
||||||
|
wr_dat.first_block_size = 0;
|
||||||
|
wr_dat.error = 0;
|
||||||
|
if (WavpackGetWrapperBytes(wpc)) {
|
||||||
|
if (!write_block(&wr_dat, WavpackGetWrapperData(wpc),
|
||||||
|
WavpackGetWrapperBytes(wpc))) {
|
||||||
|
WavpackFreeWrapper(wpc);
|
||||||
|
WavpackCloseFile(wpc);
|
||||||
|
log_msg(LOG_ERR, 0, "Wavpack: Header write failed.");
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
WavpackFreeWrapper(wpc);
|
||||||
|
} else {
|
||||||
|
log_msg(LOG_ERR, 0, "Wavpack: RIFF wrapper size if zero. File corrupt?");
|
||||||
|
WavpackCloseFile(wpc);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = TRUE;
|
||||||
|
temp_buffer = malloc (4096L * num_channels * 4);
|
||||||
|
output_buffer_size = 1024 * 256;
|
||||||
|
output_buffer = malloc(output_buffer_size);
|
||||||
|
output_ptr = output_buffer;
|
||||||
|
|
||||||
|
while (result) {
|
||||||
|
uint32_t samples_to_unpack, samples_unpacked;
|
||||||
|
|
||||||
|
samples_to_unpack = (output_buffer_size -
|
||||||
|
(uint32_t)(output_ptr - output_buffer)) / bytes_per_sample;
|
||||||
|
if (samples_to_unpack > 4096)
|
||||||
|
samples_to_unpack = 4096;
|
||||||
|
|
||||||
|
samples_unpacked = WavpackUnpackSamples(wpc, temp_buffer, samples_to_unpack);
|
||||||
|
total_unpacked_samples += samples_unpacked;
|
||||||
|
|
||||||
|
if (samples_unpacked) {
|
||||||
|
output_ptr = format_samples(bps, output_ptr, temp_buffer,
|
||||||
|
samples_unpacked * num_channels);
|
||||||
|
}
|
||||||
|
if (!samples_unpacked || (output_buffer_size -
|
||||||
|
(output_ptr - output_buffer)) < (uint32_t)bytes_per_sample) {
|
||||||
|
if (!write_block(&wr_dat, output_buffer,
|
||||||
|
(uint32_t)(output_ptr - output_buffer))) {
|
||||||
|
if (temp_buffer)
|
||||||
|
free(temp_buffer);
|
||||||
|
WavpackCloseFile(wpc);
|
||||||
|
log_msg(LOG_ERR, 0, "Wavpack: Writing samples failed.");
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
output_ptr = output_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!samples_unpacked)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (output_buffer)
|
||||||
|
free(output_buffer);
|
||||||
|
|
||||||
|
while (WavpackGetWrapperBytes(wpc)) {
|
||||||
|
if (!write_block(&wr_dat, WavpackGetWrapperData(wpc),
|
||||||
|
WavpackGetWrapperBytes(wpc))) {
|
||||||
|
if (temp_buffer)
|
||||||
|
free(temp_buffer);
|
||||||
|
WavpackCloseFile(wpc);
|
||||||
|
log_msg(LOG_ERR, 0, "Wavpack: Writing trailing data failed.");
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
WavpackFreeWrapper(wpc);
|
||||||
|
WavpackUnpackSamples(wpc, temp_buffer, 1); // perhaps there's more RIFF info...
|
||||||
|
}
|
||||||
|
|
||||||
|
free(temp_buffer);
|
||||||
|
WavpackCloseFile(wpc);
|
||||||
|
|
||||||
|
return (wr_dat.bytes_written);
|
||||||
|
}
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
17
pcompress.c
17
pcompress.c
|
@ -2854,6 +2854,7 @@ init_pc_context(pc_ctx_t *pctx, int argc, char *argv[])
|
||||||
strcpy(pctx->exec_name, pos);
|
strcpy(pctx->exec_name, pos);
|
||||||
pctx->advanced_opts = 0;
|
pctx->advanced_opts = 0;
|
||||||
ff.enable_packjpg = 0;
|
ff.enable_packjpg = 0;
|
||||||
|
ff.enable_wavpack = 0;
|
||||||
|
|
||||||
pthread_mutex_lock(&opt_parse);
|
pthread_mutex_lock(&opt_parse);
|
||||||
while ((opt = getopt(argc, argv, "dc:s:l:pt:MCDGEe:w:LPS:B:Fk:avmKjxi")) != -1) {
|
while ((opt = getopt(argc, argv, "dc:s:l:pt:MCDGEe:w:LPS:B:Fk:avmKjxi")) != -1) {
|
||||||
|
@ -3010,7 +3011,7 @@ init_pc_context(pc_ctx_t *pctx, int argc, char *argv[])
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'v':
|
case 'v':
|
||||||
pctx->verbose = 1;
|
set_log_level(LOG_VERBOSE);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'm':
|
case 'm':
|
||||||
|
@ -3024,6 +3025,7 @@ init_pc_context(pc_ctx_t *pctx, int argc, char *argv[])
|
||||||
case 'j':
|
case 'j':
|
||||||
pctx->advanced_opts = 1;
|
pctx->advanced_opts = 1;
|
||||||
ff.enable_packjpg = 1;
|
ff.enable_packjpg = 1;
|
||||||
|
ff.enable_wavpack = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'x':
|
case 'x':
|
||||||
|
@ -3142,9 +3144,10 @@ init_pc_context(pc_ctx_t *pctx, int argc, char *argv[])
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Dispack and PackJPG are only valid when archiving files.
|
* Dispack, PackJPG and WavPack are only valid when archiving files.
|
||||||
*/
|
*/
|
||||||
if ((pctx->dispack_preprocess || ff.enable_packjpg) && !pctx->archive_mode) {
|
if ((pctx->dispack_preprocess || ff.enable_packjpg || ff.enable_wavpack)
|
||||||
|
&& !pctx->archive_mode) {
|
||||||
log_msg(LOG_ERR, 0, "Dispack Executable Preprocessor and PackJPG are only valid when archiving.");
|
log_msg(LOG_ERR, 0, "Dispack Executable Preprocessor and PackJPG are only valid when archiving.");
|
||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
|
@ -3305,9 +3308,13 @@ init_pc_context(pc_ctx_t *pctx, int argc, char *argv[])
|
||||||
* Selectively enable filters while archiving, depending on compression level.
|
* Selectively enable filters while archiving, depending on compression level.
|
||||||
*/
|
*/
|
||||||
if (pctx->archive_mode) {
|
if (pctx->archive_mode) {
|
||||||
if (pctx->level > 10) ff.enable_packjpg = 1;
|
if (pctx->level > 10) {
|
||||||
|
ff.enable_packjpg = 1;
|
||||||
|
ff.enable_wavpack = 1;
|
||||||
|
}
|
||||||
init_filters(&ff);
|
init_filters(&ff);
|
||||||
pctx->enable_packjpg = ff.enable_packjpg;
|
pctx->enable_packjpg = ff.enable_packjpg;
|
||||||
|
pctx->enable_wavpack = ff.enable_wavpack;
|
||||||
if (pctx->level > 8) pctx->dispack_preprocess = 1;
|
if (pctx->level > 8) pctx->dispack_preprocess = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3345,7 +3352,9 @@ init_pc_context(pc_ctx_t *pctx, int argc, char *argv[])
|
||||||
* Enable all filters while decompressing. Obviously!
|
* Enable all filters while decompressing. Obviously!
|
||||||
*/
|
*/
|
||||||
ff.enable_packjpg = 1;
|
ff.enable_packjpg = 1;
|
||||||
|
ff.enable_wavpack = 1;
|
||||||
pctx->enable_packjpg = 1;
|
pctx->enable_packjpg = 1;
|
||||||
|
pctx->enable_wavpack = 1;
|
||||||
init_filters(&ff);
|
init_filters(&ff);
|
||||||
}
|
}
|
||||||
pctx->inited = 1;
|
pctx->inited = 1;
|
||||||
|
|
|
@ -217,7 +217,6 @@ typedef struct pc_ctx {
|
||||||
int dispack_preprocess;
|
int dispack_preprocess;
|
||||||
int encrypt_type;
|
int encrypt_type;
|
||||||
int archive_mode;
|
int archive_mode;
|
||||||
int verbose;
|
|
||||||
int enable_archive_sort;
|
int enable_archive_sort;
|
||||||
int pagesize;
|
int pagesize;
|
||||||
int force_archive_perms;
|
int force_archive_perms;
|
||||||
|
@ -246,7 +245,10 @@ typedef struct pc_ctx {
|
||||||
int btype, ctype;
|
int btype, ctype;
|
||||||
int min_chunk;
|
int min_chunk;
|
||||||
int enable_packjpg;
|
int enable_packjpg;
|
||||||
|
int enable_wavpack;
|
||||||
int list_mode;
|
int list_mode;
|
||||||
|
FILE *err_paths_fd;
|
||||||
|
uint32_t errored_count;
|
||||||
|
|
||||||
unsigned int chunk_num;
|
unsigned int chunk_num;
|
||||||
uint64_t largest_chunk, smallest_chunk, avg_chunk;
|
uint64_t largest_chunk, smallest_chunk, avg_chunk;
|
||||||
|
|
|
@ -61,7 +61,7 @@ static mach_timebase_info_data_t sTimebaseInfo;
|
||||||
|
|
||||||
processor_cap_t proc_info;
|
processor_cap_t proc_info;
|
||||||
pthread_mutex_t f_mutex = PTHREAD_MUTEX_INITIALIZER;
|
pthread_mutex_t f_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||||
static int cur_log_level = 2;
|
static int cur_log_level = LOG_INFO;
|
||||||
static log_dest_t ldest = {LOG_OUTPUT, LOG_INFO, NULL};
|
static log_dest_t ldest = {LOG_OUTPUT, LOG_INFO, NULL};
|
||||||
static char *f_name_list[512];
|
static char *f_name_list[512];
|
||||||
static int f_count = 512, f_inited = 0;
|
static int f_count = 512, f_inited = 0;
|
||||||
|
|
|
@ -277,7 +277,7 @@ typedef enum {
|
||||||
/*
|
/*
|
||||||
* Sub-types.
|
* Sub-types.
|
||||||
*/
|
*/
|
||||||
#define NUM_SUB_TYPES 32
|
#define NUM_SUB_TYPES 33
|
||||||
TYPE_EXE32 = 8,
|
TYPE_EXE32 = 8,
|
||||||
TYPE_JPEG = 16,
|
TYPE_JPEG = 16,
|
||||||
TYPE_MARKUP = 24,
|
TYPE_MARKUP = 24,
|
||||||
|
@ -386,7 +386,8 @@ typedef enum {
|
||||||
typedef enum {
|
typedef enum {
|
||||||
LOG_ERR,
|
LOG_ERR,
|
||||||
LOG_WARN,
|
LOG_WARN,
|
||||||
LOG_INFO
|
LOG_INFO,
|
||||||
|
LOG_VERBOSE
|
||||||
} log_level_t;
|
} log_level_t;
|
||||||
|
|
||||||
typedef void (*log_callback_ptr)(char *msg);
|
typedef void (*log_callback_ptr)(char *msg);
|
||||||
|
|
Loading…
Reference in a new issue