266 lines
9.1 KiB
C++
266 lines
9.1 KiB
C++
#ifndef FFMPEG_AUDIO_H
|
|
#define FFMPEG_AUDIO_H
|
|
|
|
#include <stdint.h>
|
|
|
|
#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
|