#ifndef FFMPEG_AUDIO_H #define FFMPEG_AUDIO_H #include #ifdef _WIN32 #ifdef LIB_COMPILE #define FFMPEG_EXTERN __declspec(dllexport) #else #define FFMPEG_EXTERN __declspec(dllimport) #endif #else #define FFMPEG_EXTERN #endif #ifdef __cplusplus extern "C" { #endif /* * Audio-only FFmpeg wrapper. * * The implementation is C++, but this header is plain C-compatible. All * public object types are opaque. The caller never sees FFmpeg's AVFormatContext, * AVCodecContext, AVPacket, stream_index, or std::string objects. * * Output audio format is deliberately fixed: * * signed 32-bit integer PCM * interleaved / packed * native endian * * This makes the API easy to bind from Racket and straightforward to feed into * libao. Source formats such as MP3 float/planar output are converted internally. */ typedef struct __fmpg_instance__ fmpg_instance; typedef struct __fmpg_decoder__ fmpg_decoder; typedef struct __fmpg_package__ fmpg_package; /* ------------------------------------------------------------------------- */ /* Lifecycle */ /* ------------------------------------------------------------------------- */ /* * Create an empty decoder instance. * * Return: * instance pointer, or NULL on allocation failure. */ 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); /* * Open a media file and select the best audio stream. * * The selected stream index is kept inside the instance. The public API does * not expose FFmpeg stream indices. After this function succeeds, metadata, * duration, sample rate and channel count are available through the getters * below. * * Return: * 1 on success * 0 on failure or if no usable audio stream was found */ FFMPEG_EXTERN int fmpg_open_file(fmpg_instance *instance, const char *filename); /* Close the current file, if any, and reset instance-owned information. */ 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); /* ------------------------------------------------------------------------- */ /* 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); /* Output sample rate in Hz, for example 44100 or 48000. */ 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); /* Always 32: samples are signed 32-bit integer PCM. */ 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); /* * 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); /* * 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); /* ------------------------------------------------------------------------- */ /* 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_author(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_comment(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_track(fmpg_instance *instance); /* Container-level bitrate in bits/second, or -1 if unknown. */ FFMPEG_EXTERN int fmpg_file_bitrate(fmpg_instance *instance); /* ------------------------------------------------------------------------- */ /* Packet reading */ /* ------------------------------------------------------------------------- */ /* * Read the next compressed packet from the selected audio stream. * * Non-audio packets and packets from non-selected streams are skipped * internally. The caller therefore no longer has to inspect stream_index. * * Return: * package pointer, or NULL at EOF or on read error. */ FFMPEG_EXTERN fmpg_package *fmpg_read_package(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. * * The compressed decoder buffer, decoded output buffer and resampler state are * reset. After seeking, continue reading packages and decoding as usual. * * Return: * 1 on success * 0 on failure */ FFMPEG_EXTERN int fmpg_seek_ms(fmpg_decoder *decoder, int64_t target_pos_ms); /* ------------------------------------------------------------------------- */ /* Decoder output */ /* ------------------------------------------------------------------------- */ /* * Pointer to the current decoded PCM buffer. * * 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. */ FFMPEG_EXTERN int fmpg_decoder_buffer_size(fmpg_decoder *decoder); /* * Approximate timecode of the current decoded block in seconds. * * This is based on packet timestamps. It is useful for progress indication, * but exact sample counting should use ac_decoder_sample_position(). */ FFMPEG_EXTERN double fmpg_decoder_timecode(fmpg_decoder *decoder); /* * Number of output sample frames produced by the last decode/flush call. * * 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 } #endif #endif