Created
March 26, 2025 07:17
-
-
Save nu774/d82ffd0b0c637b34fb3369cdc779e1cb to your computer and use it in GitHub Desktop.
scan chained oggflac file with libFLAC 1.5+
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <FLAC/stream_decoder.h> | |
#include <FLAC/format.h> | |
typedef struct context_t { | |
FLAC__StreamMetadata_StreamInfo si; | |
FLAC__StreamDecoderErrorStatus err; | |
char **vc; | |
} context_t; | |
FLAC__StreamDecoderWriteStatus | |
write_callback(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, | |
const FLAC__int32 *const buffer[], void *client_data) { | |
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; | |
} | |
void error_callback(const FLAC__StreamDecoder *decoder, | |
FLAC__StreamDecoderErrorStatus status, void *client_data) { | |
((context_t *)client_data)->err = status; | |
} | |
void metadata_callback(const FLAC__StreamDecoder *decoder, | |
const FLAC__StreamMetadata *metadata, | |
void *client_data) { | |
context_t *ctx = (context_t *)client_data; | |
switch (metadata->type) { | |
case FLAC__METADATA_TYPE_STREAMINFO: { | |
ctx->si = metadata->data.stream_info; | |
break; | |
} | |
case FLAC__METADATA_TYPE_VORBIS_COMMENT: { | |
FLAC__StreamMetadata_VorbisComment vc = metadata->data.vorbis_comment; | |
unsigned ptr_area_size = (vc.num_comments + 1)* sizeof(char*); | |
int all_len = 0; | |
for (int i = 0; i < vc.num_comments; ++i) { | |
all_len += vc.comments[i].length + 1; | |
} | |
void *buffer = malloc(ptr_area_size + all_len); | |
ctx->vc = buffer; | |
char *bp = (char*)buffer + ptr_area_size; | |
for (int i = 0; i < vc.num_comments; ++i) { | |
memcpy(bp, vc.comments[i].entry, vc.comments[i].length); | |
bp[vc.comments[i].length] = 0; | |
ctx->vc[i] = bp; | |
bp += vc.comments[i].length + 1; | |
} | |
ctx->vc[vc.num_comments] = 0; | |
break; | |
} | |
default: | |
break; | |
} | |
} | |
int main(int argc, char **argv) { | |
if (argc == 1) { | |
fprintf(stderr, "usage: %s FILE\n", argv[0]); | |
return 1; | |
} | |
FLAC__StreamDecoder *decoder = FLAC__stream_decoder_new(); | |
context_t ctx; | |
memset(&ctx, 0, sizeof ctx); | |
FLAC__StreamDecoderInitStatus res = FLAC__stream_decoder_init_ogg_file( | |
decoder, argv[1], write_callback, metadata_callback, error_callback, | |
&ctx); | |
if (res != FLAC__STREAM_DECODER_INIT_STATUS_OK) { | |
fprintf(stderr, "ERROR: cannot open %s: error=%d", argv[1], res); | |
FLAC__stream_decoder_delete(decoder); | |
return 2; | |
} | |
FLAC__stream_decoder_set_decode_chained_stream(decoder, 1); | |
FLAC__stream_decoder_set_metadata_respond(decoder, | |
FLAC__METADATA_TYPE_STREAMINFO); | |
FLAC__stream_decoder_set_metadata_respond(decoder, | |
FLAC__METADATA_TYPE_VORBIS_COMMENT); | |
for (int track = 1;; ++track) { | |
memset(&ctx, 0, sizeof ctx); | |
if (!FLAC__stream_decoder_process_until_end_of_metadata(decoder) || ctx.err) | |
break; | |
printf("stream #%d sample rate: %d, channels: %d, bits: %d, duration: %g\n", | |
track, | |
ctx.si.sample_rate, ctx.si.channels, ctx.si.bits_per_sample, | |
(double)ctx.si.total_samples / ctx.si.sample_rate); | |
if (ctx.vc) { | |
for (int i = 0; ctx.vc[i] != NULL; i++) { | |
printf("%s\n", ctx.vc[i]); | |
} | |
free(ctx.vc); | |
} | |
if (!FLAC__stream_decoder_skip_single_link(decoder)) | |
break; | |
if (FLAC__stream_decoder_get_state(decoder) == FLAC__STREAM_DECODER_END_OF_STREAM) | |
break; | |
putchar('\n'); | |
} | |
FLAC__stream_decoder_delete(decoder); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment