mirror of
https://github.com/vgmstream/vgmstream.git
synced 2025-01-19 00:04:04 +01:00
Implement skeleton JSON code
This commit is contained in:
parent
3d8e559d3d
commit
6c9de061f3
@ -31,6 +31,9 @@ extern int optind, opterr, optopt;
|
|||||||
|
|
||||||
|
|
||||||
static size_t make_wav_header(uint8_t* buf, size_t buf_size, int32_t sample_count, int32_t sample_rate, int channels, int smpl_chunk, int32_t loop_start, int32_t loop_end);
|
static size_t make_wav_header(uint8_t* buf, size_t buf_size, int32_t sample_count, int32_t sample_rate, int channels, int smpl_chunk, int32_t loop_start, int32_t loop_end);
|
||||||
|
#ifdef HAVE_JSON
|
||||||
|
static void print_json_version();
|
||||||
|
#endif
|
||||||
|
|
||||||
static void usage(const char* name, int is_full) {
|
static void usage(const char* name, int is_full) {
|
||||||
fprintf(stderr,"vgmstream CLI decoder " VERSION " " __DATE__ "\n"
|
fprintf(stderr,"vgmstream CLI decoder " VERSION " " __DATE__ "\n"
|
||||||
@ -56,6 +59,10 @@ static void usage(const char* name, int is_full) {
|
|||||||
" -g: decode and print oggenc command line to encode as OGG\n"
|
" -g: decode and print oggenc command line to encode as OGG\n"
|
||||||
" -b: decode and print batch variable commands\n"
|
" -b: decode and print batch variable commands\n"
|
||||||
" -h: print extra commands (for testing)\n"
|
" -h: print extra commands (for testing)\n"
|
||||||
|
#ifdef HAVE_JSON
|
||||||
|
" -V: print version info and supported extensions as JSON\n"
|
||||||
|
" -I: print requested file info as JSON\n"
|
||||||
|
#endif
|
||||||
, name);
|
, name);
|
||||||
if (!is_full)
|
if (!is_full)
|
||||||
return;
|
return;
|
||||||
@ -81,6 +88,9 @@ typedef struct {
|
|||||||
int play_sdtout;
|
int play_sdtout;
|
||||||
int play_wreckless;
|
int play_wreckless;
|
||||||
int print_metaonly;
|
int print_metaonly;
|
||||||
|
#ifdef HAVE_JSON
|
||||||
|
int print_metajson;
|
||||||
|
#endif
|
||||||
int print_adxencd;
|
int print_adxencd;
|
||||||
int print_oggenc;
|
int print_oggenc;
|
||||||
int print_batchvar;
|
int print_batchvar;
|
||||||
@ -124,7 +134,11 @@ static int parse_config(cli_config* cfg, int argc, char** argv) {
|
|||||||
opterr = 0;
|
opterr = 0;
|
||||||
|
|
||||||
/* read config */
|
/* read config */
|
||||||
while ((opt = getopt(argc, argv, "o:l:f:d:ipPcmxeLEFrgb2:s:t:Tk:K:hOvD:")) != -1) {
|
while ((opt = getopt(argc, argv, "o:l:f:d:ipPcmxeLEFrgb2:s:t:Tk:K:hOvD:"
|
||||||
|
#ifdef HAVE_JSON
|
||||||
|
"VI"
|
||||||
|
#endif
|
||||||
|
)) != -1) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 'o':
|
case 'o':
|
||||||
cfg->outfilename = optarg;
|
cfg->outfilename = optarg;
|
||||||
@ -208,6 +222,15 @@ static int parse_config(cli_config* cfg, int argc, char** argv) {
|
|||||||
case 'h':
|
case 'h':
|
||||||
usage(argv[0], 1);
|
usage(argv[0], 1);
|
||||||
goto fail;
|
goto fail;
|
||||||
|
#ifdef HAVE_JSON
|
||||||
|
case 'V':
|
||||||
|
print_json_version();
|
||||||
|
goto fail;
|
||||||
|
case 'I':
|
||||||
|
cfg->print_metaonly = 1;
|
||||||
|
cfg->print_metajson = 1;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
case '?':
|
case '?':
|
||||||
fprintf(stderr, "Unknown option -%c found\n", optopt);
|
fprintf(stderr, "Unknown option -%c found\n", optopt);
|
||||||
goto fail;
|
goto fail;
|
||||||
@ -367,6 +390,33 @@ static void print_title(VGMSTREAM* vgmstream, cli_config* cfg) {
|
|||||||
printf("title: %s\n", title);
|
printf("title: %s\n", title);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_JSON
|
||||||
|
void print_json_version() {
|
||||||
|
size_t extension_list_len;
|
||||||
|
const char** extension_list;
|
||||||
|
extension_list = vgmstream_get_formats(&extension_list_len);
|
||||||
|
|
||||||
|
json_t* ext_list = json_array();
|
||||||
|
|
||||||
|
for (size_t i = 0; i < extension_list_len; ++i) {
|
||||||
|
json_t* ext = json_string(extension_list[i]);
|
||||||
|
json_array_append(ext_list, ext);
|
||||||
|
json_decref(ext);
|
||||||
|
}
|
||||||
|
|
||||||
|
json_t* version_string = json_string(VERSION);
|
||||||
|
|
||||||
|
json_t* final_object = json_object();
|
||||||
|
json_object_set(final_object, "version", version_string);
|
||||||
|
json_decref(version_string);
|
||||||
|
|
||||||
|
json_object_set(final_object, "extensions", ext_list);
|
||||||
|
json_decref(ext_list);
|
||||||
|
|
||||||
|
json_dumpf(final_object, stdout, );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static void clean_filename(char* dst, int clean_paths) {
|
static void clean_filename(char* dst, int clean_paths) {
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < strlen(dst); i++) {
|
for (i = 0; i < strlen(dst); i++) {
|
||||||
@ -582,9 +632,18 @@ int main(int argc, char** argv) {
|
|||||||
|
|
||||||
|
|
||||||
/* prints */
|
/* prints */
|
||||||
print_info(vgmstream, &cfg);
|
#ifdef HAVE_JSON
|
||||||
print_tags(&cfg);
|
if (!cfg.print_metajson) {
|
||||||
print_title(vgmstream, &cfg);
|
#endif
|
||||||
|
print_info(vgmstream, &cfg);
|
||||||
|
print_tags(&cfg);
|
||||||
|
print_title(vgmstream, &cfg);
|
||||||
|
#ifdef HAVE_JSON
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
print_json_info(vgmstream, &cfg);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* prints done */
|
/* prints done */
|
||||||
if (cfg.print_metaonly) {
|
if (cfg.print_metaonly) {
|
||||||
|
@ -1042,6 +1042,95 @@ void describe_vgmstream(VGMSTREAM* vgmstream, char* desc, int length) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void describe_vgmstream_info(VGMSTREAM* vgmstream, vgmstream_info* info) {
|
||||||
|
if (!info) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(info, 0, sizeof(*info));
|
||||||
|
|
||||||
|
if (!vgmstream) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
info->sample_rate = vgmstream->sample_rate;
|
||||||
|
|
||||||
|
info->channels = vgmstream->channels;
|
||||||
|
|
||||||
|
{
|
||||||
|
int output_channels = 0;
|
||||||
|
mixing_info(vgmstream, NULL, &output_channels);
|
||||||
|
|
||||||
|
if (output_channels != vgmstream->channels) {
|
||||||
|
info->mixing_info.input_channels = vgmstream->channels;
|
||||||
|
info->mixing_info.output_channels = output_channels;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
info->channel_layout = vgmstream->channel_layout;
|
||||||
|
|
||||||
|
if (vgmstream->loop_start_sample >= 0 && vgmstream->loop_end_sample > vgmstream->loop_start_sample) {
|
||||||
|
info->loop_info.start = vgmstream->loop_start_sample;
|
||||||
|
info->loop_info.end = vgmstream->loop_end_sample;
|
||||||
|
}
|
||||||
|
|
||||||
|
info->num_samples = vgmstream->num_samples;
|
||||||
|
|
||||||
|
get_vgmstream_coding_description(vgmstream, info->encoding, sizeof(info->encoding));
|
||||||
|
|
||||||
|
get_vgmstream_layout_description(vgmstream, info->layout, sizeof(info->layout));
|
||||||
|
|
||||||
|
if (vgmstream->layout_type == layout_interleave && vgmstream->channels > 1) {
|
||||||
|
info->interleave_info.value = vgmstream->interleave_block_size;
|
||||||
|
|
||||||
|
if (vgmstream->interleave_first_block_size && vgmstream->interleave_first_block_size != vgmstream->interleave_block_size) {
|
||||||
|
info->interleave_info.first_block = vgmstream->interleave_first_block_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vgmstream->interleave_last_block_size && vgmstream->interleave_last_block_size != vgmstream->interleave_block_size) {
|
||||||
|
info->interleave_info.last_block = vgmstream->interleave_last_block_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* codecs with configurable frame size */
|
||||||
|
if (vgmstream->frame_size > 0 || vgmstream->interleave_block_size > 0) {
|
||||||
|
int32_t frame_size = vgmstream->frame_size > 0 ? vgmstream->frame_size : vgmstream->interleave_block_size;
|
||||||
|
switch (vgmstream->coding_type) {
|
||||||
|
case coding_MSADPCM:
|
||||||
|
case coding_MSADPCM_int:
|
||||||
|
case coding_MSADPCM_ck:
|
||||||
|
case coding_MS_IMA:
|
||||||
|
case coding_MC3:
|
||||||
|
case coding_WWISE_IMA:
|
||||||
|
case coding_REF_IMA:
|
||||||
|
case coding_PSX_cfg:
|
||||||
|
info->frame_size = frame_size;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get_vgmstream_meta_description(vgmstream, info->metadata, sizeof(info->metadata));
|
||||||
|
|
||||||
|
info->bitrate = get_vgmstream_average_bitrate(vgmstream);
|
||||||
|
|
||||||
|
/* only interesting if more than one */
|
||||||
|
if (vgmstream->num_streams > 1) {
|
||||||
|
info->stream_info.total = vgmstream->num_streams;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
info->stream_info.total = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vgmstream->num_streams > 1) {
|
||||||
|
info->stream_info.current = vgmstream->stream_index == 0 ? 1 : vgmstream->stream_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vgmstream->stream_name[0] != '\0') {
|
||||||
|
snprintf(info->stream_info.name, sizeof(info->stream_info.name), "%s", vgmstream->stream_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* See if there is a second file which may be the second channel, given an already opened mono vgmstream.
|
/* See if there is a second file which may be the second channel, given an already opened mono vgmstream.
|
||||||
* If a suitable file is found, open it and change opened_vgmstream to a stereo vgmstream. */
|
* If a suitable file is found, open it and change opened_vgmstream to a stereo vgmstream. */
|
||||||
|
@ -1094,6 +1094,36 @@ typedef struct {
|
|||||||
#endif
|
#endif
|
||||||
#endif //VGM_USE_MP4V2
|
#endif //VGM_USE_MP4V2
|
||||||
|
|
||||||
|
// VGMStream description in structure format
|
||||||
|
typedef struct {
|
||||||
|
int sample_rate;
|
||||||
|
int channels;
|
||||||
|
struct mixing_info {
|
||||||
|
int input_channels;
|
||||||
|
int output_channels;
|
||||||
|
} mixing_info;
|
||||||
|
int channel_layout;
|
||||||
|
struct loop_info {
|
||||||
|
int start;
|
||||||
|
int end;
|
||||||
|
} loop_info;
|
||||||
|
size_t num_samples;
|
||||||
|
char encoding[128];
|
||||||
|
char layout[128];
|
||||||
|
struct interleave_info {
|
||||||
|
int value;
|
||||||
|
int first_block;
|
||||||
|
int last_block;
|
||||||
|
} interleave_info;
|
||||||
|
int frame_size;
|
||||||
|
char metadata[128];
|
||||||
|
int bitrate;
|
||||||
|
struct stream_info {
|
||||||
|
int current;
|
||||||
|
int total;
|
||||||
|
char name[128];
|
||||||
|
} stream_info;
|
||||||
|
} vgmstream_info;
|
||||||
|
|
||||||
/* -------------------------------------------------------------------------*/
|
/* -------------------------------------------------------------------------*/
|
||||||
/* vgmstream "public" API */
|
/* vgmstream "public" API */
|
||||||
@ -1123,6 +1153,7 @@ void seek_vgmstream(VGMSTREAM* vgmstream, int32_t seek_sample);
|
|||||||
/* Write a description of the stream into array pointed by desc, which must be length bytes long.
|
/* Write a description of the stream into array pointed by desc, which must be length bytes long.
|
||||||
* Will always be null-terminated if length > 0 */
|
* Will always be null-terminated if length > 0 */
|
||||||
void describe_vgmstream(VGMSTREAM* vgmstream, char* desc, int length);
|
void describe_vgmstream(VGMSTREAM* vgmstream, char* desc, int length);
|
||||||
|
void describe_vgmstream_info(VGMSTREAM* vgmstream, vgmstream_info* desc);
|
||||||
|
|
||||||
/* Return the average bitrate in bps of all unique files contained within this stream. */
|
/* Return the average bitrate in bps of all unique files contained within this stream. */
|
||||||
int get_vgmstream_average_bitrate(VGMSTREAM* vgmstream);
|
int get_vgmstream_average_bitrate(VGMSTREAM* vgmstream);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user