decoding to 32 bit
This commit is contained in:
@@ -8,12 +8,14 @@
|
|||||||
#define fprintf fprintf_s
|
#define fprintf fprintf_s
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void write_u16_le(FILE *f, uint16_t v) {
|
static void write_u16_le(FILE *f, uint16_t v)
|
||||||
|
{
|
||||||
fputc((int)(v & 0xff), f);
|
fputc((int)(v & 0xff), f);
|
||||||
fputc((int)((v >> 8) & 0xff), f);
|
fputc((int)((v >> 8) & 0xff), f);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void write_u32_le(FILE *f, uint32_t v) {
|
static void write_u32_le(FILE *f, uint32_t v)
|
||||||
|
{
|
||||||
fputc((int)(v & 0xff), f);
|
fputc((int)(v & 0xff), f);
|
||||||
fputc((int)((v >> 8) & 0xff), f);
|
fputc((int)((v >> 8) & 0xff), f);
|
||||||
fputc((int)((v >> 16) & 0xff), f);
|
fputc((int)((v >> 16) & 0xff), f);
|
||||||
@@ -24,7 +26,8 @@ static int write_wav_header(FILE *f,
|
|||||||
int sample_rate,
|
int sample_rate,
|
||||||
int channels,
|
int channels,
|
||||||
int bits_per_sample,
|
int bits_per_sample,
|
||||||
uint32_t data_size) {
|
uint32_t data_size)
|
||||||
|
{
|
||||||
const uint32_t byte_rate =
|
const uint32_t byte_rate =
|
||||||
(uint32_t)(sample_rate * channels * bits_per_sample / 8);
|
(uint32_t)(sample_rate * channels * bits_per_sample / 8);
|
||||||
const uint16_t block_align =
|
const uint16_t block_align =
|
||||||
@@ -36,7 +39,7 @@ static int write_wav_header(FILE *f,
|
|||||||
|
|
||||||
fwrite("fmt ", 1, 4, f);
|
fwrite("fmt ", 1, 4, f);
|
||||||
write_u32_le(f, 16); /* fmt chunk size */
|
write_u32_le(f, 16); /* fmt chunk size */
|
||||||
write_u16_le(f, 1); /* 1 = integer PCM */
|
write_u16_le(f, 1); /* PCM */
|
||||||
write_u16_le(f, (uint16_t)channels);
|
write_u16_le(f, (uint16_t)channels);
|
||||||
write_u32_le(f, (uint32_t)sample_rate);
|
write_u32_le(f, (uint32_t)sample_rate);
|
||||||
write_u32_le(f, byte_rate);
|
write_u32_le(f, byte_rate);
|
||||||
@@ -53,7 +56,8 @@ static int rewrite_wav_header(FILE *f,
|
|||||||
int sample_rate,
|
int sample_rate,
|
||||||
int channels,
|
int channels,
|
||||||
int bits_per_sample,
|
int bits_per_sample,
|
||||||
uint32_t data_size) {
|
uint32_t data_size)
|
||||||
|
{
|
||||||
if (fseek(f, 0, SEEK_SET) != 0) {
|
if (fseek(f, 0, SEEK_SET) != 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -65,37 +69,24 @@ static int rewrite_wav_header(FILE *f,
|
|||||||
data_size);
|
data_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int write_decoder_buffer(FILE *out,
|
static void print_if_present(const char *label, const char *value)
|
||||||
fmpg_decoder *dec,
|
{
|
||||||
uint64_t *total_written) {
|
if (value && value[0]) {
|
||||||
const uint8_t *buf = fmpg_decoder_buffer(dec);
|
printf("%s: %s\n", label, value);
|
||||||
const int size = fmpg_decoder_buffer_size(dec);
|
|
||||||
|
|
||||||
if (!buf || size <= 0) {
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fwrite(buf, 1, (size_t)size, out) != (size_t)size) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
*total_written += (uint64_t)size;
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
const char *infile;
|
const char *infile;
|
||||||
const char *outfile;
|
const char *outfile;
|
||||||
|
|
||||||
fmpg_instance *ac = NULL;
|
fmpg_instance *fmpg = NULL;
|
||||||
fmpg_decoder *dec = NULL;
|
|
||||||
FILE *out = NULL;
|
FILE *out = NULL;
|
||||||
|
|
||||||
int sample_rate;
|
int sample_rate;
|
||||||
int channels;
|
int channels;
|
||||||
int bits_per_sample;
|
int bits_per_sample;
|
||||||
int64_t duration_ms;
|
|
||||||
int64_t duration_samples;
|
|
||||||
uint64_t total_written = 0;
|
uint64_t total_written = 0;
|
||||||
|
|
||||||
if (argc != 3) {
|
if (argc != 3) {
|
||||||
@@ -106,48 +97,38 @@ int main(int argc, char **argv) {
|
|||||||
infile = argv[1];
|
infile = argv[1];
|
||||||
outfile = argv[2];
|
outfile = argv[2];
|
||||||
|
|
||||||
ac = fmpg_init();
|
fmpg = fmpg_init();
|
||||||
if (!ac) {
|
if (!fmpg) {
|
||||||
fprintf(stderr, "ac_init failed\n");
|
fprintf(stderr, "fmpg_init failed\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fmpg_open_file(ac, infile)) {
|
if (!fmpg_open_file(fmpg, infile)) {
|
||||||
fprintf(stderr, "could not open input file: %s\n", infile);
|
fprintf(stderr, "could not open input file: %s\n", infile);
|
||||||
fmpg_free(ac);
|
fmpg_free(fmpg);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
sample_rate = fmpg_audio_sample_rate(ac);
|
sample_rate = fmpg_audio_sample_rate(fmpg);
|
||||||
channels = fmpg_audio_channels(ac);
|
channels = fmpg_audio_channels(fmpg);
|
||||||
bits_per_sample = fmpg_audio_bits_per_sample(ac);
|
bits_per_sample = fmpg_audio_bits_per_sample(fmpg);
|
||||||
duration_ms = fmpg_duration_ms(ac);
|
|
||||||
duration_samples = fmpg_duration_samples(ac);
|
|
||||||
|
|
||||||
if (sample_rate <= 0 || channels <= 0 || bits_per_sample != 32) {
|
if (sample_rate <= 0 || channels <= 0 || bits_per_sample != 32) {
|
||||||
fprintf(stderr, "invalid audio parameters\n");
|
fprintf(stderr, "unexpected audio format reported by decoder\n");
|
||||||
fmpg_free(ac);
|
fmpg_free(fmpg);
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
dec = fmpg_create_decoder(ac);
|
|
||||||
if (!dec) {
|
|
||||||
fprintf(stderr, "could not create decoder\n");
|
|
||||||
fmpg_free(ac);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
out = fopen(outfile, "wb");
|
out = fopen(outfile, "wb");
|
||||||
if (!out) {
|
if (!out) {
|
||||||
fprintf(stderr, "could not open output file: %s\n", outfile);
|
fprintf(stderr, "could not open output file: %s\n", outfile);
|
||||||
fmpg_free_decoder(dec);
|
fmpg_free(fmpg);
|
||||||
fmpg_free(ac);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We do not know the final WAV data size yet.
|
* The final WAV data size is only known after decoding. Write a temporary
|
||||||
* Write a placeholder header first and patch it at the end.
|
* header now and patch it after the decode loop.
|
||||||
*/
|
*/
|
||||||
if (!write_wav_header(out,
|
if (!write_wav_header(out,
|
||||||
sample_rate,
|
sample_rate,
|
||||||
@@ -156,44 +137,22 @@ int main(int argc, char **argv) {
|
|||||||
0)) {
|
0)) {
|
||||||
fprintf(stderr, "could not write WAV header\n");
|
fprintf(stderr, "could not write WAV header\n");
|
||||||
fclose(out);
|
fclose(out);
|
||||||
fmpg_free_decoder(dec);
|
fmpg_free(fmpg);
|
||||||
fmpg_free(ac);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (;;) {
|
while (fmpg_decode_next(fmpg)) {
|
||||||
fmpg_package *pkg = fmpg_read_package(ac);
|
const uint8_t *buf = fmpg_buffer(fmpg);
|
||||||
|
const int size = fmpg_buffer_size(fmpg);
|
||||||
|
|
||||||
if (!pkg) {
|
if (buf && size > 0) {
|
||||||
break;
|
if (fwrite(buf, 1, (size_t)size, out) != (size_t)size) {
|
||||||
}
|
fprintf(stderr, "write error\n");
|
||||||
|
|
||||||
/*
|
|
||||||
* ac_read_package() now returns only packets from the internally
|
|
||||||
* selected audio stream. No stream_index test is needed anymore.
|
|
||||||
*/
|
|
||||||
if (fmpg_decode_package(pkg, dec)) {
|
|
||||||
if (!write_decoder_buffer(out, dec, &total_written)) {
|
|
||||||
fprintf(stderr, "could not write PCM data\n");
|
|
||||||
fmpg_free_package(pkg);
|
|
||||||
fclose(out);
|
fclose(out);
|
||||||
fmpg_free_decoder(dec);
|
fmpg_free(fmpg);
|
||||||
fmpg_free(ac);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
total_written += (uint64_t)size;
|
||||||
|
|
||||||
fmpg_free_package(pkg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Drain delayed samples from the decoder and resampler. */
|
|
||||||
while (fmpg_flush_decoder(dec)) {
|
|
||||||
if (!write_decoder_buffer(out, dec, &total_written)) {
|
|
||||||
fprintf(stderr, "could not write flushed PCM data\n");
|
|
||||||
fclose(out);
|
|
||||||
fmpg_free_decoder(dec);
|
|
||||||
fmpg_free(ac);
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -209,24 +168,31 @@ int main(int argc, char **argv) {
|
|||||||
bits_per_sample,
|
bits_per_sample,
|
||||||
(uint32_t)total_written)) {
|
(uint32_t)total_written)) {
|
||||||
fprintf(stderr, "could not rewrite WAV header\n");
|
fprintf(stderr, "could not rewrite WAV header\n");
|
||||||
|
fclose(out);
|
||||||
|
fmpg_free(fmpg);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(out);
|
fclose(out);
|
||||||
|
|
||||||
printf("wrote %s\n", outfile);
|
printf("wrote: %s\n", outfile);
|
||||||
printf("title: %s\n", fmpg_file_title(ac));
|
|
||||||
printf("album: %s\n", fmpg_file_album(ac));
|
|
||||||
printf("sample rate: %d\n", sample_rate);
|
printf("sample rate: %d\n", sample_rate);
|
||||||
printf("channels: %d\n", channels);
|
printf("channels: %d\n", channels);
|
||||||
printf("sample bits: %d\n", bits_per_sample);
|
printf("sample bits: %d\n", bits_per_sample);
|
||||||
printf("duration ms: %lld\n", (long long)duration_ms);
|
printf("data bytes: %llu\n", (unsigned long long)total_written);
|
||||||
printf("duration smp:%lld\n", (long long)duration_samples);
|
printf("samples out: %lld\n", (long long)fmpg_sample_position(fmpg));
|
||||||
printf("decoded smp: %lld\n", (long long)fmpg_decoder_sample_position(dec));
|
|
||||||
printf("data bytes: %llu\n",
|
|
||||||
(unsigned long long)total_written);
|
|
||||||
|
|
||||||
fmpg_free_decoder(dec);
|
if (fmpg_duration_ms(fmpg) >= 0) {
|
||||||
fmpg_free(ac);
|
printf("duration ms: %lld\n", (long long)fmpg_duration_ms(fmpg));
|
||||||
|
}
|
||||||
|
if (fmpg_duration_samples(fmpg) >= 0) {
|
||||||
|
printf("duration smp:%lld\n", (long long)fmpg_duration_samples(fmpg));
|
||||||
|
}
|
||||||
|
|
||||||
|
print_if_present("title", fmpg_file_title(fmpg));
|
||||||
|
print_if_present("artist", fmpg_file_author(fmpg));
|
||||||
|
print_if_present("album", fmpg_file_album(fmpg));
|
||||||
|
|
||||||
|
fmpg_free(fmpg);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
+426
-325
File diff suppressed because it is too large
Load Diff
+51
-159
@@ -20,243 +20,135 @@ extern "C" {
|
|||||||
/*
|
/*
|
||||||
* Audio-only FFmpeg wrapper.
|
* Audio-only FFmpeg wrapper.
|
||||||
*
|
*
|
||||||
* The implementation is C++, but this header is plain C-compatible. All
|
* The implementation is C++, but the exported API is plain C. The caller never
|
||||||
* public object types are opaque. The caller never sees FFmpeg's AVFormatContext,
|
* sees FFmpeg objects, stream indices, packets, decoders, or C++ objects.
|
||||||
* AVCodecContext, AVPacket, stream_index, or std::string objects.
|
|
||||||
*
|
*
|
||||||
* Output audio format is deliberately fixed:
|
* Output audio format is fixed:
|
||||||
*
|
*
|
||||||
* signed 32-bit integer PCM
|
* signed 32-bit integer PCM
|
||||||
* interleaved / packed
|
* interleaved / packed
|
||||||
* native endian
|
* native endian
|
||||||
*
|
*
|
||||||
* This makes the API easy to bind from Racket and straightforward to feed into
|
* A sample frame means one sample moment across all channels. For stereo S32,
|
||||||
* libao. Source formats such as MP3 float/planar output are converted internally.
|
* one sample frame is two int32_t values, therefore 8 bytes.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
typedef struct __fmpg_instance__ fmpg_instance;
|
typedef struct __fmpg_instance__ fmpg_instance;
|
||||||
typedef struct __fmpg_decoder__ fmpg_decoder;
|
|
||||||
typedef struct __fmpg_package__ fmpg_package;
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------- */
|
||||||
/* Lifecycle */
|
/* Lifecycle */
|
||||||
/* ------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------- */
|
||||||
|
|
||||||
/*
|
|
||||||
* Create an empty decoder instance.
|
|
||||||
*
|
|
||||||
* Return:
|
|
||||||
* instance pointer, or NULL on allocation failure.
|
|
||||||
*/
|
|
||||||
FFMPEG_EXTERN fmpg_instance *fmpg_init(void);
|
FFMPEG_EXTERN fmpg_instance *fmpg_init(void);
|
||||||
|
|
||||||
/*
|
|
||||||
* Close any open file and free the instance.
|
|
||||||
*
|
|
||||||
* It is safe to pass NULL.
|
|
||||||
*/
|
|
||||||
FFMPEG_EXTERN void fmpg_free(fmpg_instance *instance);
|
FFMPEG_EXTERN void fmpg_free(fmpg_instance *instance);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Open a media file and select the best audio stream.
|
* Open a media file, select the best audio stream, and create the internal
|
||||||
|
* decoder/resampler for that stream.
|
||||||
*
|
*
|
||||||
* The selected stream index is kept inside the instance. The public API does
|
* After success, metadata, duration, sample rate and channel count are
|
||||||
* not expose FFmpeg stream indices. After this function succeeds, metadata,
|
* available through the getters below.
|
||||||
* duration, sample rate and channel count are available through the getters
|
|
||||||
* below.
|
|
||||||
*
|
*
|
||||||
* Return:
|
* Return: 1 on success, 0 on failure.
|
||||||
* 1 on success
|
|
||||||
* 0 on failure or if no usable audio stream was found
|
|
||||||
*/
|
*/
|
||||||
FFMPEG_EXTERN int fmpg_open_file(fmpg_instance *instance,
|
FFMPEG_EXTERN int fmpg_open_file(fmpg_instance *instance, const char *filename);
|
||||||
const char *filename);
|
|
||||||
|
|
||||||
/* Close the current file, if any, and reset instance-owned information. */
|
|
||||||
FFMPEG_EXTERN void fmpg_close(fmpg_instance *instance);
|
FFMPEG_EXTERN void fmpg_close(fmpg_instance *instance);
|
||||||
|
|
||||||
/* Return 1 if a file is open, 0 otherwise. */
|
|
||||||
FFMPEG_EXTERN int fmpg_is_open(fmpg_instance *instance);
|
FFMPEG_EXTERN int fmpg_is_open(fmpg_instance *instance);
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------- */
|
||||||
/* Audio information */
|
/* Audio information */
|
||||||
/* ------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------- */
|
||||||
|
|
||||||
/*
|
|
||||||
* The number of audio streams found in the container.
|
|
||||||
*
|
|
||||||
* The decoder currently uses the best stream selected by FFmpeg. This count is
|
|
||||||
* informational; stream selection is intentionally not part of the public API.
|
|
||||||
*/
|
|
||||||
FFMPEG_EXTERN int fmpg_audio_stream_count(fmpg_instance *instance);
|
FFMPEG_EXTERN int fmpg_audio_stream_count(fmpg_instance *instance);
|
||||||
|
|
||||||
/* Output sample rate in Hz, for example 44100 or 48000. */
|
|
||||||
FFMPEG_EXTERN int fmpg_audio_sample_rate(fmpg_instance *instance);
|
FFMPEG_EXTERN int fmpg_audio_sample_rate(fmpg_instance *instance);
|
||||||
|
|
||||||
/* Number of output channels, for example 1 or 2. */
|
|
||||||
FFMPEG_EXTERN int fmpg_audio_channels(fmpg_instance *instance);
|
FFMPEG_EXTERN int fmpg_audio_channels(fmpg_instance *instance);
|
||||||
|
|
||||||
/* Always 32: samples are signed 32-bit integer PCM. */
|
|
||||||
FFMPEG_EXTERN int fmpg_audio_bits_per_sample(fmpg_instance *instance);
|
FFMPEG_EXTERN int fmpg_audio_bits_per_sample(fmpg_instance *instance);
|
||||||
|
|
||||||
/* Always 4: one output sample occupies four bytes. */
|
|
||||||
FFMPEG_EXTERN int fmpg_audio_bytes_per_sample(fmpg_instance *instance);
|
FFMPEG_EXTERN int fmpg_audio_bytes_per_sample(fmpg_instance *instance);
|
||||||
|
|
||||||
/*
|
/* Duration in milliseconds, or -1 if unknown. */
|
||||||
* Duration in milliseconds, or -1 if unknown.
|
|
||||||
*
|
|
||||||
* This value is known after ac_open_file() succeeds, as far as FFmpeg can know
|
|
||||||
* it from the container/stream metadata. Some streams do not contain exact
|
|
||||||
* duration information; in that case this getter returns -1.
|
|
||||||
*/
|
|
||||||
FFMPEG_EXTERN int64_t fmpg_duration_ms(fmpg_instance *instance);
|
FFMPEG_EXTERN int64_t fmpg_duration_ms(fmpg_instance *instance);
|
||||||
|
|
||||||
/*
|
/* Duration in output sample frames, or -1 if unknown. */
|
||||||
* Duration expressed as output sample frames, or -1 if unknown.
|
|
||||||
*
|
|
||||||
* A sample frame means one sample moment across all channels. For stereo, one
|
|
||||||
* sample frame contains two int32_t values: left and right. This is usually the
|
|
||||||
* most useful duration unit for playback and progress calculations.
|
|
||||||
*
|
|
||||||
* PCM int32_t values in the whole output would be:
|
|
||||||
*
|
|
||||||
* ac_duration_samples(instance) * ac_audio_channels(instance)
|
|
||||||
*/
|
|
||||||
FFMPEG_EXTERN int64_t fmpg_duration_samples(fmpg_instance *instance);
|
FFMPEG_EXTERN int64_t fmpg_duration_samples(fmpg_instance *instance);
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------- */
|
||||||
/* Metadata */
|
/* Metadata */
|
||||||
/* ------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------- */
|
||||||
|
|
||||||
/*
|
|
||||||
* Metadata is owned by the instance and available after ac_open_file().
|
|
||||||
* Returned strings are never NULL. Missing metadata is returned as "".
|
|
||||||
*
|
|
||||||
* Pointers remain valid until ac_close() or ac_free() is called for the
|
|
||||||
* instance. Do not free the returned strings.
|
|
||||||
*/
|
|
||||||
FFMPEG_EXTERN const char *fmpg_file_title(fmpg_instance *instance);
|
FFMPEG_EXTERN const char *fmpg_file_title(fmpg_instance *instance);
|
||||||
FFMPEG_EXTERN const char *fmpg_file_author(fmpg_instance *instance);
|
FFMPEG_EXTERN const char *fmpg_file_author(fmpg_instance *instance);
|
||||||
FFMPEG_EXTERN const char *fmpg_file_album(fmpg_instance *instance);
|
FFMPEG_EXTERN const char *fmpg_file_album(fmpg_instance *instance);
|
||||||
FFMPEG_EXTERN const char *fmpg_file_genre(fmpg_instance *instance);
|
FFMPEG_EXTERN const char *fmpg_file_genre(fmpg_instance *instance);
|
||||||
FFMPEG_EXTERN const char *fmpg_file_comment(fmpg_instance *instance);
|
FFMPEG_EXTERN const char *fmpg_file_comment(fmpg_instance *instance);
|
||||||
FFMPEG_EXTERN const char *fmpg_file_copyright(fmpg_instance *instance);
|
FFMPEG_EXTERN const char *fmpg_file_copyright(fmpg_instance *instance);
|
||||||
|
|
||||||
/* Return -1 if the field is unknown. */
|
|
||||||
FFMPEG_EXTERN int fmpg_file_year(fmpg_instance *instance);
|
FFMPEG_EXTERN int fmpg_file_year(fmpg_instance *instance);
|
||||||
FFMPEG_EXTERN int fmpg_file_track(fmpg_instance *instance);
|
FFMPEG_EXTERN int fmpg_file_track(fmpg_instance *instance);
|
||||||
|
|
||||||
/* Container-level bitrate in bits/second, or -1 if unknown. */
|
|
||||||
FFMPEG_EXTERN int fmpg_file_bitrate(fmpg_instance *instance);
|
FFMPEG_EXTERN int fmpg_file_bitrate(fmpg_instance *instance);
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------- */
|
||||||
/* Packet reading */
|
/* Decoding */
|
||||||
/* ------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------- */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read the next compressed packet from the selected audio stream.
|
* Decode the next block of audio.
|
||||||
*
|
*
|
||||||
* Non-audio packets and packets from non-selected streams are skipped
|
* Internally this reads compressed packets from the selected audio stream,
|
||||||
* internally. The caller therefore no longer has to inspect stream_index.
|
* feeds them to the FFmpeg decoder, receives all available decoded frames,
|
||||||
|
* converts them to signed 32-bit interleaved PCM, and concatenates them in the
|
||||||
|
* instance output buffer.
|
||||||
|
*
|
||||||
|
* Non-selected streams are skipped internally. The caller does not handle
|
||||||
|
* stream_index, packets, or decoder objects.
|
||||||
*
|
*
|
||||||
* Return:
|
* Return:
|
||||||
* package pointer, or NULL at EOF or on read error.
|
* 1 if PCM data is available through fmpg_buffer()/fmpg_buffer_size()
|
||||||
|
* 0 at EOF or on error
|
||||||
*/
|
*/
|
||||||
FFMPEG_EXTERN fmpg_package *fmpg_read_package(fmpg_instance *instance);
|
FFMPEG_EXTERN int fmpg_decode_next(fmpg_instance *instance);
|
||||||
|
|
||||||
/* Free a package returned by ac_read_package(). Safe to pass NULL. */
|
|
||||||
FFMPEG_EXTERN void fmpg_free_package(fmpg_package *package);
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------- */
|
|
||||||
/* Decoder */
|
|
||||||
/* ------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Create a decoder for the selected audio stream.
|
|
||||||
*
|
|
||||||
* The stream is the one selected during ac_open_file(). The caller does not
|
|
||||||
* pass a stream index.
|
|
||||||
*/
|
|
||||||
FFMPEG_EXTERN fmpg_decoder *fmpg_create_decoder(fmpg_instance *instance);
|
|
||||||
|
|
||||||
/* Free decoder and all FFmpeg decoder/resampler state. Safe to pass NULL. */
|
|
||||||
FFMPEG_EXTERN void fmpg_free_decoder(fmpg_decoder *decoder);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Decode one compressed audio package.
|
|
||||||
*
|
|
||||||
* Modern FFmpeg decoding is packet-in, frame-out. One compressed packet can
|
|
||||||
* produce zero, one, or multiple decoded frames. This function receives all
|
|
||||||
* available frames, converts them to signed 32-bit interleaved PCM, and
|
|
||||||
* concatenates them into the decoder output buffer.
|
|
||||||
*
|
|
||||||
* Return:
|
|
||||||
* 1 if PCM data was produced
|
|
||||||
* 0 if no PCM data was produced or an error occurred
|
|
||||||
*/
|
|
||||||
FFMPEG_EXTERN int fmpg_decode_package(fmpg_package *package, fmpg_decoder *decoder);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Flush delayed decoder/resampler samples after EOF.
|
|
||||||
*
|
|
||||||
* Call this repeatedly after ac_read_package() returns NULL, until this
|
|
||||||
* function returns 0.
|
|
||||||
*/
|
|
||||||
FFMPEG_EXTERN int fmpg_flush_decoder(fmpg_decoder *decoder);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Seek to an absolute position in milliseconds.
|
* Seek to an absolute position in milliseconds.
|
||||||
*
|
*
|
||||||
* The compressed decoder buffer, decoded output buffer and resampler state are
|
* FFmpeg may seek to a packet before the requested timestamp. This wrapper
|
||||||
* reset. After seeking, continue reading packages and decoding as usual.
|
* decodes and discards pre-roll samples until the requested output sample is
|
||||||
|
* reached, when timestamps are available. That makes the exposed sample
|
||||||
|
* position match the music position as closely as FFmpeg's timestamps allow.
|
||||||
*
|
*
|
||||||
* Return:
|
* Return: 1 on success, 0 on failure.
|
||||||
* 1 on success
|
|
||||||
* 0 on failure
|
|
||||||
*/
|
*/
|
||||||
FFMPEG_EXTERN int fmpg_seek_ms(fmpg_decoder *decoder, int64_t target_pos_ms);
|
FFMPEG_EXTERN int fmpg_seek_ms(fmpg_instance *instance, int64_t target_pos_ms);
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------- */
|
||||||
/* Decoder output */
|
/* Output buffer and sample positions */
|
||||||
/* ------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------- */
|
||||||
|
|
||||||
/*
|
/* Pointer to the current decoded PCM buffer. Valid until next API call that
|
||||||
* Pointer to the current decoded PCM buffer.
|
* decodes, seeks, closes, or frees the instance. */
|
||||||
*
|
FFMPEG_EXTERN const uint8_t *fmpg_buffer(fmpg_instance *instance);
|
||||||
* Format:
|
|
||||||
* int32_t samples
|
|
||||||
* interleaved by channel
|
|
||||||
* native endian
|
|
||||||
*
|
|
||||||
* The pointer remains valid until the next ac_decode_package(),
|
|
||||||
* ac_flush_decoder(), ac_seek_ms(), or ac_free_decoder() call for this decoder.
|
|
||||||
*/
|
|
||||||
FFMPEG_EXTERN const uint8_t *fmpg_decoder_buffer(fmpg_decoder *decoder);
|
|
||||||
|
|
||||||
/* Size of the current decoded PCM buffer in bytes. */
|
/* Size of the current decoded PCM buffer in bytes. */
|
||||||
FFMPEG_EXTERN int fmpg_decoder_buffer_size(fmpg_decoder *decoder);
|
FFMPEG_EXTERN int fmpg_buffer_size(fmpg_instance *instance);
|
||||||
|
|
||||||
|
/* Number of sample frames in the current decoded PCM buffer. */
|
||||||
|
FFMPEG_EXTERN int64_t fmpg_buffer_samples(fmpg_instance *instance);
|
||||||
|
|
||||||
|
/* Absolute sample-frame index of the first sample frame in the current buffer. */
|
||||||
|
FFMPEG_EXTERN int64_t fmpg_buffer_start_sample(fmpg_instance *instance);
|
||||||
|
|
||||||
|
/* Absolute sample-frame index just after the current buffer. */
|
||||||
|
FFMPEG_EXTERN int64_t fmpg_buffer_end_sample(fmpg_instance *instance);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Approximate timecode of the current decoded block in seconds.
|
* Current absolute sample position in the music stream.
|
||||||
*
|
*
|
||||||
* This is based on packet timestamps. It is useful for progress indication,
|
* This is the same as fmpg_buffer_end_sample() after a successful
|
||||||
* but exact sample counting should use ac_decoder_sample_position().
|
* fmpg_decode_next(): it points just after the last produced sample frame.
|
||||||
*/
|
*/
|
||||||
FFMPEG_EXTERN double fmpg_decoder_timecode(fmpg_decoder *decoder);
|
FFMPEG_EXTERN int64_t fmpg_sample_position(fmpg_instance *instance);
|
||||||
|
|
||||||
/*
|
/* Approximate start time of the current decoded block in seconds. */
|
||||||
* Number of output sample frames produced by the last decode/flush call.
|
FFMPEG_EXTERN double fmpg_timecode(fmpg_instance *instance);
|
||||||
*
|
|
||||||
* A sample frame contains one sample for each channel. For stereo S32, one
|
|
||||||
* sample frame is 8 bytes.
|
|
||||||
*/
|
|
||||||
FFMPEG_EXTERN int64_t fmpg_decoder_last_samples(fmpg_decoder *decoder);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Running count of output sample frames produced since decoder creation or
|
|
||||||
* the most recent successful seek.
|
|
||||||
*/
|
|
||||||
FFMPEG_EXTERN int64_t fmpg_decoder_sample_position(fmpg_decoder *decoder);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user