Implement skeleton JSON code

This commit is contained in:
Christopher Snowhill 2020-09-27 18:07:10 -07:00
parent 3d8e559d3d
commit 6c9de061f3
3 changed files with 183 additions and 4 deletions

View File

@ -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);
#ifdef HAVE_JSON
static void print_json_version();
#endif
static void usage(const char* name, int is_full) {
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"
" -b: decode and print batch variable commands\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);
if (!is_full)
return;
@ -81,6 +88,9 @@ typedef struct {
int play_sdtout;
int play_wreckless;
int print_metaonly;
#ifdef HAVE_JSON
int print_metajson;
#endif
int print_adxencd;
int print_oggenc;
int print_batchvar;
@ -124,7 +134,11 @@ static int parse_config(cli_config* cfg, int argc, char** argv) {
opterr = 0;
/* 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) {
case 'o':
cfg->outfilename = optarg;
@ -208,6 +222,15 @@ static int parse_config(cli_config* cfg, int argc, char** argv) {
case 'h':
usage(argv[0], 1);
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 '?':
fprintf(stderr, "Unknown option -%c found\n", optopt);
goto fail;
@ -367,6 +390,33 @@ static void print_title(VGMSTREAM* vgmstream, cli_config* cfg) {
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) {
int i;
for (i = 0; i < strlen(dst); i++) {
@ -582,9 +632,18 @@ int main(int argc, char** argv) {
/* prints */
print_info(vgmstream, &cfg);
print_tags(&cfg);
print_title(vgmstream, &cfg);
#ifdef HAVE_JSON
if (!cfg.print_metajson) {
#endif
print_info(vgmstream, &cfg);
print_tags(&cfg);
print_title(vgmstream, &cfg);
#ifdef HAVE_JSON
}
else {
print_json_info(vgmstream, &cfg);
}
#endif
/* prints done */
if (cfg.print_metaonly) {

View File

@ -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.
* If a suitable file is found, open it and change opened_vgmstream to a stereo vgmstream. */

View File

@ -1094,6 +1094,36 @@ typedef struct {
#endif
#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 */
@ -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.
* Will always be null-terminated if length > 0 */
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. */
int get_vgmstream_average_bitrate(VGMSTREAM* vgmstream);