0xAA55 发表于 2014-7-14 03:37:11

【C】libFLAC的使用

1、什么是libFLAC?

libFLAC是用于操作FLAC文件的C开源工具。
libFLAC的官网:https://xiph.org/flac/

2、什么是FLAC?

FLAC是一种针对声音文件的无损压缩算法。压缩比略低于AAC,但是压缩和解压的速度很理想。使用FLAC压缩的无损音乐,体积将比没有经过压缩的无损音乐小很多(取决于音乐的平均音量。通常体积能减少到原文件的50%左右)。
相比较MP3有损压缩格式而言,FLAC能保留100%的音质。对于广大音乐爱好者而言,相对于MP3,FLAC是更好的选择。

libFLAC的源码请大家到libFLAC的官网下载。点此进入官方下载页面。
我这里有备用的下载地址。如果大家无法到官网下载libFLAC的源码,大家可以来我这里下载1.3.0版。强烈建议大家去官网下载最新版。



首先我们下载libFLAC的源码。然后用VS打开它的FLAC.sln这个文件。我用的是VS2012,因此出现了提示升级工程的对话框。我就将工程文件升级为VS2012的版本了。

看左边有很多工程。其中需要留意的是这几个工程:

C语言工程:
libFLAC_dynamic:编译它你能得到libFLAC.dll。这个DLL导出的函数可以帮你完成对FLAC文件的编码和解码的操作。
libFLAC_static:编译它,你能得到libFLAC.lib。当你既想操作FLAC文件,又不想让自己的程序依赖libFLAC.dll的时候,你可以使用它。
C++工程:
libFLAC++_dynamic:C++版的libFLAC.dll。功能和C语言版的一样,但是它是C++风格的,适合C++使用。
libFLAC++_static:C++版的libFLAC.lib。

这些是libFLAC的核心部分。当你展开它你会发现以下的文件:


这些文件是用NASM语法编写的汇编代码,用NASM编译,然后和C语言程序配合进行FLAC的编码和解码的。注意这是PC平台上的x86汇编。32位的。
我编译这个工程的时候NASM产生了“nasm.h:83: warning: COFF section names limited to 8 characters: truncating”这样的警告。意思是nasm.h第83行给段起名的时候超过了8个字符的长度,超出部分被截去。
这样的警告一般不会导致什么严重的错误,除非你为了编这个程序定义了各种奇怪的段,然后一不小心就冲突了。而这样的错误一般会被链接器发现,从而提示你进行修正。所以目前可以无视。

libFLAC的源码出现了NASM汇编代码,而且在很多地方出现了_asm内联汇编的语句,看似影响了移植性,其实这只是libFLAC用于优化代码运行效率的手段。
我们只需把C语言的预定义部分加上FLAC__NO_ASM,就能使其把原本用_asm内联汇编语句实现的部分用C代替了,从而保证了移植性。

本来libFLAC的源码里面附带的工程文件的配置是只有Win32平台编译的配置的。经过我的一系列处理(去掉NASM的部分使其不参与编译,然后通过调整预处理来使其不使用内联汇编)之后我编译出了64位的libFLAC.lib(静态链接库)。大家可以在这里下载。
x86:
x64:

要使用libFLAC进行C语言编程进行FLAC文件编码和解码,我们首先需要两样东西:编译时用到的头文件(.H)和链接时用到的库文件(.LIB,无论是动态DLL还是静态LIB)。
库文件请下载上面的。头文件,则在你刚下载的libFLAC的源码的include文件夹的FLAC文件夹内。
为了便于大家学习,我将头文件打包上传了。点此下载->

头文件都是放在FLAC文件夹里面的。首先你把FLAC文件夹拷到你的工程文件夹。然后配置好你的工程,让它链接你的库文件。键人在此就不赘述了。

0x1:解码程序怎么写?

首先你需要包含一个头文件:#include"FLAC/stream_decoder.h"

FLAC的使用是围绕一个结构体进行的:FLAC__StreamDecoder *pDecoder;//FLAC解码器对象

FLAC是面向对象编程的思路。FLAC__StreamDecoder就是它所指的对象。首先我们需要调用FLAC__stream_decoder_new()来取得这个对象。

pDecoder=FLAC__stream_decoder_new();
if(!pDecoder)
{
    fprintf(stderr,"初始化FLAC解码器失败!\n");
    return;
}

取得的pDecoder就是我们所说的FLAC解码器对象了。切记在用完了pDecoder之后要记得把它删掉,否则就会占用内存。调用FLAC__stream_decoder_delete(pDecoder);就可以把它占用的部分删掉了。

然后就是它的初始化工作了。有以下几种初始化的函数可供选择:
FLAC__stream_decoder_init_stream:由用户自行将FLAC文件的内容输入,然后取得解码得到的波形数据。
FLAC__stream_decoder_init_ogg_stream:由用户自行将ogg FLAC文件的内容输入,然后取得解码得到的波形数据。
FLAC__stream_decoder_init_FILE:用户提供打开了FLAC文件的FILE*,然后FLAC解码器会自动从文件流读入数据,再解码。
FLAC__stream_decoder_init_ogg_FILE:用户提供打开了ogg FLAC文件的FILE*,然后FLAC解码器会自动从文件流读入数据,再解码。
FLAC__stream_decoder_init_file:用户只需提供FLAC文件的路径,FLAC解码器自动打开文件进行解码。
FLAC__stream_decoder_init_ogg_file:用户只需提供ogg FLAC文件的路径,FLAC解码器自动打开文件进行解码。
(PS.什么是ogg FLAC?)

这些函数都是以回调函数的方式运作的。用户只需提供回调函数,然后让它解码,最后等它调用你的回调函数就能取得解码的数据了。
我这里把这几个函数的原型贴出来。/** Initialize the decoder instance to decode native FLAC streams.
*
*This flavor of initialization sets up the decoder to decode from a
*native FLAC stream. I/O is performed via callbacks to the client.
*For decoding from a plain file via filename or open FILE*,
*FLAC__stream_decoder_init_file() and FLAC__stream_decoder_init_FILE()
*provide a simpler interface.
*
*This function should be called after FLAC__stream_decoder_new() and
*FLAC__stream_decoder_set_*() but before any of the
*FLAC__stream_decoder_process_*() functions.Will set and return the
*decoder state, which will be FLAC__STREAM_DECODER_SEARCH_FOR_METADATA
*if initialization succeeded.
*
* \paramdecoder            An uninitialized decoder instance.
* \paramread_callback      See FLAC__StreamDecoderReadCallback.This
*                            pointer must not be \c NULL.
* \paramseek_callback      See FLAC__StreamDecoderSeekCallback.This
*                            pointer may be \c NULL if seeking is not
*                            supported.If \a seek_callback is not \c NULL then a
*                            \a tell_callback, \a length_callback, and \a eof_callback must also be supplied.
*                            Alternatively, a dummy seek callback that just
*                            returns \c FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED
*                            may also be supplied, all though this is slightly
*                            less efficient for the decoder.
* \paramtell_callback      See FLAC__StreamDecoderTellCallback.This
*                            pointer may be \c NULL if not supported by the client.If
*                            \a seek_callback is not \c NULL then a
*                            \a tell_callback must also be supplied.
*                            Alternatively, a dummy tell callback that just
*                            returns \c FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED
*                            may also be supplied, all though this is slightly
*                            less efficient for the decoder.
* \paramlength_callback    See FLAC__StreamDecoderLengthCallback.This
*                            pointer may be \c NULL if not supported by the client.If
*                            \a seek_callback is not \c NULL then a
*                            \a length_callback must also be supplied.
*                            Alternatively, a dummy length callback that just
*                            returns \c FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED
*                            may also be supplied, all though this is slightly
*                            less efficient for the decoder.
* \parameof_callback       See FLAC__StreamDecoderEofCallback.This
*                            pointer may be \c NULL if not supported by the client.If
*                            \a seek_callback is not \c NULL then a
*                            \a eof_callback must also be supplied.
*                            Alternatively, a dummy length callback that just
*                            returns \c false
*                            may also be supplied, all though this is slightly
*                            less efficient for the decoder.
* \paramwrite_callback   See FLAC__StreamDecoderWriteCallback.This
*                            pointer must not be \c NULL.
* \parammetadata_callbackSee FLAC__StreamDecoderMetadataCallback.This
*                            pointer may be \c NULL if the callback is not
*                            desired.
* \paramerror_callback   See FLAC__StreamDecoderErrorCallback.This
*                            pointer must not be \c NULL.
* \paramclient_data      This value will be supplied to callbacks in their
*                            \a client_data argument.
* \assert
*    \code decoder != NULL \endcode
* \retval FLAC__StreamDecoderInitStatus
*    \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful;
*    see FLAC__StreamDecoderInitStatus for the meanings of other return values.
*/
FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_stream(
        FLAC__StreamDecoder *decoder,
        FLAC__StreamDecoderReadCallback read_callback,
        FLAC__StreamDecoderSeekCallback seek_callback,
        FLAC__StreamDecoderTellCallback tell_callback,
        FLAC__StreamDecoderLengthCallback length_callback,
        FLAC__StreamDecoderEofCallback eof_callback,
        FLAC__StreamDecoderWriteCallback write_callback,
        FLAC__StreamDecoderMetadataCallback metadata_callback,
        FLAC__StreamDecoderErrorCallback error_callback,
        void *client_data
);

/** Initialize the decoder instance to decode Ogg FLAC streams.
*
*This flavor of initialization sets up the decoder to decode from a
*FLAC stream in an Ogg container. I/O is performed via callbacks to the
*client.For decoding from a plain file via filename or open FILE*,
*FLAC__stream_decoder_init_ogg_file() and FLAC__stream_decoder_init_ogg_FILE()
*provide a simpler interface.
*
*This function should be called after FLAC__stream_decoder_new() and
*FLAC__stream_decoder_set_*() but before any of the
*FLAC__stream_decoder_process_*() functions.Will set and return the
*decoder state, which will be FLAC__STREAM_DECODER_SEARCH_FOR_METADATA
*if initialization succeeded.
*
*\note Support for Ogg FLAC in the library is optional.If this
*library has been built without support for Ogg FLAC, this function
*will return \c FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER.
*
* \paramdecoder            An uninitialized decoder instance.
* \paramread_callback      See FLAC__StreamDecoderReadCallback.This
*                            pointer must not be \c NULL.
* \paramseek_callback      See FLAC__StreamDecoderSeekCallback.This
*                            pointer may be \c NULL if seeking is not
*                            supported.If \a seek_callback is not \c NULL then a
*                            \a tell_callback, \a length_callback, and \a eof_callback must also be supplied.
*                            Alternatively, a dummy seek callback that just
*                            returns \c FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED
*                            may also be supplied, all though this is slightly
*                            less efficient for the decoder.
* \paramtell_callback      See FLAC__StreamDecoderTellCallback.This
*                            pointer may be \c NULL if not supported by the client.If
*                            \a seek_callback is not \c NULL then a
*                            \a tell_callback must also be supplied.
*                            Alternatively, a dummy tell callback that just
*                            returns \c FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED
*                            may also be supplied, all though this is slightly
*                            less efficient for the decoder.
* \paramlength_callback    See FLAC__StreamDecoderLengthCallback.This
*                            pointer may be \c NULL if not supported by the client.If
*                            \a seek_callback is not \c NULL then a
*                            \a length_callback must also be supplied.
*                            Alternatively, a dummy length callback that just
*                            returns \c FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED
*                            may also be supplied, all though this is slightly
*                            less efficient for the decoder.
* \parameof_callback       See FLAC__StreamDecoderEofCallback.This
*                            pointer may be \c NULL if not supported by the client.If
*                            \a seek_callback is not \c NULL then a
*                            \a eof_callback must also be supplied.
*                            Alternatively, a dummy length callback that just
*                            returns \c false
*                            may also be supplied, all though this is slightly
*                            less efficient for the decoder.
* \paramwrite_callback   See FLAC__StreamDecoderWriteCallback.This
*                            pointer must not be \c NULL.
* \parammetadata_callbackSee FLAC__StreamDecoderMetadataCallback.This
*                            pointer may be \c NULL if the callback is not
*                            desired.
* \paramerror_callback   See FLAC__StreamDecoderErrorCallback.This
*                            pointer must not be \c NULL.
* \paramclient_data      This value will be supplied to callbacks in their
*                            \a client_data argument.
* \assert
*    \code decoder != NULL \endcode
* \retval FLAC__StreamDecoderInitStatus
*    \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful;
*    see FLAC__StreamDecoderInitStatus for the meanings of other return values.
*/
FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_stream(
        FLAC__StreamDecoder *decoder,
        FLAC__StreamDecoderReadCallback read_callback,
        FLAC__StreamDecoderSeekCallback seek_callback,
        FLAC__StreamDecoderTellCallback tell_callback,
        FLAC__StreamDecoderLengthCallback length_callback,
        FLAC__StreamDecoderEofCallback eof_callback,
        FLAC__StreamDecoderWriteCallback write_callback,
        FLAC__StreamDecoderMetadataCallback metadata_callback,
        FLAC__StreamDecoderErrorCallback error_callback,
        void *client_data
);

/** Initialize the decoder instance to decode native FLAC files.
*
*This flavor of initialization sets up the decoder to decode from a
*plain native FLAC file.For non-stdio streams, you must use
*FLAC__stream_decoder_init_stream() and provide callbacks for the I/O.
*
*This function should be called after FLAC__stream_decoder_new() and
*FLAC__stream_decoder_set_*() but before any of the
*FLAC__stream_decoder_process_*() functions.Will set and return the
*decoder state, which will be FLAC__STREAM_DECODER_SEARCH_FOR_METADATA
*if initialization succeeded.
*
* \paramdecoder            An uninitialized decoder instance.
* \paramfile               An open FLAC file.The file should have been
*                            opened with mode \c "rb" and rewound.The file
*                            becomes owned by the decoder and should not be
*                            manipulated by the client while decoding.
*                            Unless \a file is \c stdin, it will be closed
*                            when FLAC__stream_decoder_finish() is called.
*                            Note however that seeking will not work when
*                            decoding from \c stdout since it is not seekable.
* \paramwrite_callback   See FLAC__StreamDecoderWriteCallback.This
*                            pointer must not be \c NULL.
* \parammetadata_callbackSee FLAC__StreamDecoderMetadataCallback.This
*                            pointer may be \c NULL if the callback is not
*                            desired.
* \paramerror_callback   See FLAC__StreamDecoderErrorCallback.This
*                            pointer must not be \c NULL.
* \paramclient_data      This value will be supplied to callbacks in their
*                            \a client_data argument.
* \assert
*    \code decoder != NULL \endcode
*    \code file != NULL \endcode
* \retval FLAC__StreamDecoderInitStatus
*    \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful;
*    see FLAC__StreamDecoderInitStatus for the meanings of other return values.
*/
FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_FILE(
        FLAC__StreamDecoder *decoder,
        FILE *file,
        FLAC__StreamDecoderWriteCallback write_callback,
        FLAC__StreamDecoderMetadataCallback metadata_callback,
        FLAC__StreamDecoderErrorCallback error_callback,
        void *client_data
);

/** Initialize the decoder instance to decode Ogg FLAC files.
*
*This flavor of initialization sets up the decoder to decode from a
*plain Ogg FLAC file.For non-stdio streams, you must use
*FLAC__stream_decoder_init_ogg_stream() and provide callbacks for the I/O.
*
*This function should be called after FLAC__stream_decoder_new() and
*FLAC__stream_decoder_set_*() but before any of the
*FLAC__stream_decoder_process_*() functions.Will set and return the
*decoder state, which will be FLAC__STREAM_DECODER_SEARCH_FOR_METADATA
*if initialization succeeded.
*
*\note Support for Ogg FLAC in the library is optional.If this
*library has been built without support for Ogg FLAC, this function
*will return \c FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER.
*
* \paramdecoder            An uninitialized decoder instance.
* \paramfile               An open FLAC file.The file should have been
*                            opened with mode \c "rb" and rewound.The file
*                            becomes owned by the decoder and should not be
*                            manipulated by the client while decoding.
*                            Unless \a file is \c stdin, it will be closed
*                            when FLAC__stream_decoder_finish() is called.
*                            Note however that seeking will not work when
*                            decoding from \c stdout since it is not seekable.
* \paramwrite_callback   See FLAC__StreamDecoderWriteCallback.This
*                            pointer must not be \c NULL.
* \parammetadata_callbackSee FLAC__StreamDecoderMetadataCallback.This
*                            pointer may be \c NULL if the callback is not
*                            desired.
* \paramerror_callback   See FLAC__StreamDecoderErrorCallback.This
*                            pointer must not be \c NULL.
* \paramclient_data      This value will be supplied to callbacks in their
*                            \a client_data argument.
* \assert
*    \code decoder != NULL \endcode
*    \code file != NULL \endcode
* \retval FLAC__StreamDecoderInitStatus
*    \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful;
*    see FLAC__StreamDecoderInitStatus for the meanings of other return values.
*/
FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_FILE(
        FLAC__StreamDecoder *decoder,
        FILE *file,
        FLAC__StreamDecoderWriteCallback write_callback,
        FLAC__StreamDecoderMetadataCallback metadata_callback,
        FLAC__StreamDecoderErrorCallback error_callback,
        void *client_data
);

/** Initialize the decoder instance to decode native FLAC files.
*
*This flavor of initialization sets up the decoder to decode from a plain
*native FLAC file.If POSIX fopen() semantics are not sufficient, (for
*example, with Unicode filenames on Windows), you must use
*FLAC__stream_decoder_init_FILE(), or FLAC__stream_decoder_init_stream()
*and provide callbacks for the I/O.
*
*This function should be called after FLAC__stream_decoder_new() and
*FLAC__stream_decoder_set_*() but before any of the
*FLAC__stream_decoder_process_*() functions.Will set and return the
*decoder state, which will be FLAC__STREAM_DECODER_SEARCH_FOR_METADATA
*if initialization succeeded.
*
* \paramdecoder            An uninitialized decoder instance.
* \paramfilename         The name of the file to decode from.The file will
*                            be opened with fopen().Use \c NULL to decode from
*                            \c stdin.Note that \c stdin is not seekable.
* \paramwrite_callback   See FLAC__StreamDecoderWriteCallback.This
*                            pointer must not be \c NULL.
* \parammetadata_callbackSee FLAC__StreamDecoderMetadataCallback.This
*                            pointer may be \c NULL if the callback is not
*                            desired.
* \paramerror_callback   See FLAC__StreamDecoderErrorCallback.This
*                            pointer must not be \c NULL.
* \paramclient_data      This value will be supplied to callbacks in their
*                            \a client_data argument.
* \assert
*    \code decoder != NULL \endcode
* \retval FLAC__StreamDecoderInitStatus
*    \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful;
*    see FLAC__StreamDecoderInitStatus for the meanings of other return values.
*/
FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_file(
        FLAC__StreamDecoder *decoder,
        const char *filename,
        FLAC__StreamDecoderWriteCallback write_callback,
        FLAC__StreamDecoderMetadataCallback metadata_callback,
        FLAC__StreamDecoderErrorCallback error_callback,
        void *client_data
);

/** Initialize the decoder instance to decode Ogg FLAC files.
*
*This flavor of initialization sets up the decoder to decode from a plain
*Ogg FLAC file.If POSIX fopen() semantics are not sufficient, (for
*example, with Unicode filenames on Windows), you must use
*FLAC__stream_decoder_init_ogg_FILE(), or FLAC__stream_decoder_init_ogg_stream()
*and provide callbacks for the I/O.
*
*This function should be called after FLAC__stream_decoder_new() and
*FLAC__stream_decoder_set_*() but before any of the
*FLAC__stream_decoder_process_*() functions.Will set and return the
*decoder state, which will be FLAC__STREAM_DECODER_SEARCH_FOR_METADATA
*if initialization succeeded.
*
*\note Support for Ogg FLAC in the library is optional.If this
*library has been built without support for Ogg FLAC, this function
*will return \c FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER.
*
* \paramdecoder            An uninitialized decoder instance.
* \paramfilename         The name of the file to decode from.The file will
*                            be opened with fopen().Use \c NULL to decode from
*                            \c stdin.Note that \c stdin is not seekable.
* \paramwrite_callback   See FLAC__StreamDecoderWriteCallback.This
*                            pointer must not be \c NULL.
* \parammetadata_callbackSee FLAC__StreamDecoderMetadataCallback.This
*                            pointer may be \c NULL if the callback is not
*                            desired.
* \paramerror_callback   See FLAC__StreamDecoderErrorCallback.This
*                            pointer must not be \c NULL.
* \paramclient_data      This value will be supplied to callbacks in their
*                            \a client_data argument.
* \assert
*    \code decoder != NULL \endcode
* \retval FLAC__StreamDecoderInitStatus
*    \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful;
*    see FLAC__StreamDecoderInitStatus for the meanings of other return values.
*/
FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_file(
        FLAC__StreamDecoder *decoder,
        const char *filename,
        FLAC__StreamDecoderWriteCallback write_callback,
        FLAC__StreamDecoderMetadataCallback metadata_callback,
        FLAC__StreamDecoderErrorCallback error_callback,
        void *client_data
);大家可以通过看注释来了解它们的使用方式。

刚才只是初始化的设定而已。设置好初始化的操作以后,你要做的就是让libFLAC帮你解码。
有以下几种方式可以启动它的解码过程:
FLAC__stream_decoder_process_single:解码一个块,得到一个块的数据。
FLAC__stream_decoder_process_until_end_of_metadata:一直解码,直到元数据(metadata)的结尾。
FLAC__stream_decoder_process_until_end_of_stream:一直解码,直到流的结尾(整个文件解码完)
当你调用上面三个函数中的一个的时候,libFLAC就会开始帮你解码,调用你提供的回调函数,把解码得到的数据提供给你。

其中可以用于辅助解码的函数如下:
FLAC__stream_decoder_skip_single_frame:跳过一个块。
FLAC__stream_decoder_seek_absolute:定位到某一个样本处。

详细的来自头文件的信息:/** Decode one metadata block or audio frame.
*This version instructs the decoder to decode a either a single metadata
*block or a single frame and stop, unless the callbacks return a fatal
*error or the read callback returns
*\c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM.
*
*As the decoder needs more input it will call the read callback.
*Depending on what was decoded, the metadata or write callback will be
*called with the decoded metadata block or audio frame.
*
*Unless there is a fatal read error or end of stream, this function
*will return once one whole frame is decoded.In other words, if the
*stream is not synchronized or points to a corrupt frame header, the
*decoder will continue to try and resync until it gets to a valid
*frame, then decode one frame, then return.If the decoder points to
*a frame whose frame CRC in the frame footer does not match the
*computed frame CRC, this function will issue a
*FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH error to the
*error callback, and return, having decoded one complete, although
*corrupt, frame.(Such corrupted frames are sent as silence of the
*correct length to the write callback.)
*
* \paramdecoderAn initialized decoder instance.
* \assert
*    \code decoder != NULL \endcode
* \retval FLAC__bool
*    \c false if any fatal read, write, or memory allocation error
*    occurred (meaning decoding must stop), else \c true; for more
*    information about the decoder, check the decoder state with
*    FLAC__stream_decoder_get_state().
*/
FLAC_API FLAC__bool FLAC__stream_decoder_process_single(FLAC__StreamDecoder *decoder);

/** Decode until the end of the metadata.
*This version instructs the decoder to decode from the current position
*and continue until all the metadata has been read, or until the
*callbacks return a fatal error or the read callback returns
*\c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM.
*
*As the decoder needs more input it will call the read callback.
*As each metadata block is decoded, the metadata callback will be called
*with the decoded metadata.
*
* \paramdecoderAn initialized decoder instance.
* \assert
*    \code decoder != NULL \endcode
* \retval FLAC__bool
*    \c false if any fatal read, write, or memory allocation error
*    occurred (meaning decoding must stop), else \c true; for more
*    information about the decoder, check the decoder state with
*    FLAC__stream_decoder_get_state().
*/
FLAC_API FLAC__bool FLAC__stream_decoder_process_until_end_of_metadata(FLAC__StreamDecoder *decoder);

/** Decode until the end of the stream.
*This version instructs the decoder to decode from the current position
*and continue until the end of stream (the read callback returns
*\c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM), or until the
*callbacks return a fatal error.
*
*As the decoder needs more input it will call the read callback.
*As each metadata block and frame is decoded, the metadata or write
*callback will be called with the decoded metadata or frame.
*
* \paramdecoderAn initialized decoder instance.
* \assert
*    \code decoder != NULL \endcode
* \retval FLAC__bool
*    \c false if any fatal read, write, or memory allocation error
*    occurred (meaning decoding must stop), else \c true; for more
*    information about the decoder, check the decoder state with
*    FLAC__stream_decoder_get_state().
*/
FLAC_API FLAC__bool FLAC__stream_decoder_process_until_end_of_stream(FLAC__StreamDecoder *decoder);

/** Skip one audio frame.
*This version instructs the decoder to 'skip' a single frame and stop,
*unless the callbacks return a fatal error or the read callback returns
*\c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM.
*
*The decoding flow is the same as what occurs when
*FLAC__stream_decoder_process_single() is called to process an audio
*frame, except that this function does not decode the parsed data into
*PCM or call the write callback.The integrity of the frame is still
*checked the same way as in the other process functions.
*
*This function will return once one whole frame is skipped, in the
*same way that FLAC__stream_decoder_process_single() will return once
*one whole frame is decoded.
*
*This function can be used in more quickly determining FLAC frame
*boundaries when decoding of the actual data is not needed, for
*example when an application is separating a FLAC stream into frames
*for editing or storing in a container.To do this, the application
*can use FLAC__stream_decoder_skip_single_frame() to quickly advance
*to the next frame, then use
*FLAC__stream_decoder_get_decode_position() to find the new frame
*boundary.
*
*This function should only be called when the stream has advanced
*past all the metadata, otherwise it will return \c false.
*
* \paramdecoderAn initialized decoder instance not in a metadata
*                  state.
* \assert
*    \code decoder != NULL \endcode
* \retval FLAC__bool
*    \c false if any fatal read, write, or memory allocation error
*    occurred (meaning decoding must stop), or if the decoder
*    is in the FLAC__STREAM_DECODER_SEARCH_FOR_METADATA or
*    FLAC__STREAM_DECODER_READ_METADATA state, else \c true; for more
*    information about the decoder, check the decoder state with
*    FLAC__stream_decoder_get_state().
*/
FLAC_API FLAC__bool FLAC__stream_decoder_skip_single_frame(FLAC__StreamDecoder *decoder);

/** Flush the input and seek to an absolute sample.
*Decoding will resume at the given sample.Note that because of
*this, the next write callback may contain a partial block.The
*client must support seeking the input or this function will fail
*and return \c false.Furthermore, if the decoder state is
*\c FLAC__STREAM_DECODER_SEEK_ERROR, then the decoder must be flushed
*with FLAC__stream_decoder_flush() or reset with
*FLAC__stream_decoder_reset() before decoding can continue.
*
* \paramdecoderA decoder instance.
* \paramsample   The target sample number to seek to.
* \assert
*    \code decoder != NULL \endcode
* \retval FLAC__bool
*    \c true if successful, else \c false.
*/
FLAC_API FLAC__bool FLAC__stream_decoder_seek_absolute(FLAC__StreamDecoder *decoder, FLAC__uint64 sample);回调函数的原型详见libFLAC的头文件。里面有非常详细的介绍。你只需在VS里把光标放到这些函数类型上然后按下F12就能看到所有的信息。
不过为了便于理解,我把这些回调函数的原型也复制了过来。这样大家就不用亲自去按F12看信息了。直接看我的帖子就行。/** Signature for the read callback.
*
*A function pointer matching this signature must be passed to
*FLAC__stream_decoder_init*_stream(). The supplied function will be
*called when the decoder needs more input data.The address of the
*buffer to be filled is supplied, along with the number of bytes the
*buffer can hold.The callback may choose to supply less data and
*modify the byte count but must be careful not to overflow the buffer.
*The callback then returns a status code chosen from
*FLAC__StreamDecoderReadStatus.
*
* Here is an example of a read callback for stdio streams:
* \code
* FLAC__StreamDecoderReadStatus read_cb(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
* {
*   FILE *file = ((MyClientData*)client_data)->file;
*   if(*bytes > 0) {
*   *bytes = fread(buffer, sizeof(FLAC__byte), *bytes, file);
*   if(ferror(file))
*       return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
*   else if(*bytes == 0)
*       return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
*   else
*       return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
*   }
*   else
*   return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
* }
* \endcode
*
* \note In general, FLAC__StreamDecoder functions which change the
* state should not be called on the \a decoder while in the callback.
*
* \paramdecoderThe decoder instance calling the callback.
* \parambuffer   A pointer to a location for the callee to store
*                  data to be decoded.
* \parambytes    A pointer to the size of the buffer.On entry
*                  to the callback, it contains the maximum number
*                  of bytes that may be stored in \a buffer.The
*                  callee must set it to the actual number of bytes
*                  stored (0 in case of error or end-of-stream) before
*                  returning.
* \paramclient_dataThe callee's client data set through
*                      FLAC__stream_decoder_init_*().
* \retval FLAC__StreamDecoderReadStatus
*    The callee's return status.Note that the callback should return
*    \c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM if and only if
*    zero bytes were read and there is no more data to be read.
*/
typedef FLAC__StreamDecoderReadStatus (*FLAC__StreamDecoderReadCallback)(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data);

/** Signature for the seek callback.
*
*A function pointer matching this signature may be passed to
*FLAC__stream_decoder_init*_stream().The supplied function will be
*called when the decoder needs to seek the input stream.The decoder
*will pass the absolute byte offset to seek to, 0 meaning the
*beginning of the stream.
*
* Here is an example of a seek callback for stdio streams:
* \code
* FLAC__StreamDecoderSeekStatus seek_cb(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data)
* {
*   FILE *file = ((MyClientData*)client_data)->file;
*   if(file == stdin)
*   return FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED;
*   else if(fseeko(file, (off_t)absolute_byte_offset, SEEK_SET) < 0)
*   return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
*   else
*   return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
* }
* \endcode
*
* \note In general, FLAC__StreamDecoder functions which change the
* state should not be called on the \a decoder while in the callback.
*
* \paramdecoderThe decoder instance calling the callback.
* \paramabsolute_byte_offsetThe offset from the beginning of the stream
*                               to seek to.
* \paramclient_dataThe callee's client data set through
*                      FLAC__stream_decoder_init_*().
* \retval FLAC__StreamDecoderSeekStatus
*    The callee's return status.
*/
typedef FLAC__StreamDecoderSeekStatus (*FLAC__StreamDecoderSeekCallback)(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data);

/** Signature for the tell callback.
*
*A function pointer matching this signature may be passed to
*FLAC__stream_decoder_init*_stream().The supplied function will be
*called when the decoder wants to know the current position of the
*stream.The callback should return the byte offset from the
*beginning of the stream.
*
* Here is an example of a tell callback for stdio streams:
* \code
* FLAC__StreamDecoderTellStatus tell_cb(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data)
* {
*   FILE *file = ((MyClientData*)client_data)->file;
*   off_t pos;
*   if(file == stdin)
*   return FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED;
*   else if((pos = ftello(file)) < 0)
*   return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
*   else {
*   *absolute_byte_offset = (FLAC__uint64)pos;
*   return FLAC__STREAM_DECODER_TELL_STATUS_OK;
*   }
* }
* \endcode
*
* \note In general, FLAC__StreamDecoder functions which change the
* state should not be called on the \a decoder while in the callback.
*
* \paramdecoderThe decoder instance calling the callback.
* \paramabsolute_byte_offsetA pointer to storage for the current offset
*                               from the beginning of the stream.
* \paramclient_dataThe callee's client data set through
*                      FLAC__stream_decoder_init_*().
* \retval FLAC__StreamDecoderTellStatus
*    The callee's return status.
*/
typedef FLAC__StreamDecoderTellStatus (*FLAC__StreamDecoderTellCallback)(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data);

/** Signature for the length callback.
*
*A function pointer matching this signature may be passed to
*FLAC__stream_decoder_init*_stream().The supplied function will be
*called when the decoder wants to know the total length of the stream
*in bytes.
*
* Here is an example of a length callback for stdio streams:
* \code
* FLAC__StreamDecoderLengthStatus length_cb(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data)
* {
*   FILE *file = ((MyClientData*)client_data)->file;
*   struct stat filestats;
*
*   if(file == stdin)
*   return FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED;
*   else if(fstat(fileno(file), &filestats) != 0)
*   return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
*   else {
*   *stream_length = (FLAC__uint64)filestats.st_size;
*   return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
*   }
* }
* \endcode
*
* \note In general, FLAC__StreamDecoder functions which change the
* state should not be called on the \a decoder while in the callback.
*
* \paramdecoderThe decoder instance calling the callback.
* \paramstream_lengthA pointer to storage for the length of the stream
*                        in bytes.
* \paramclient_dataThe callee's client data set through
*                      FLAC__stream_decoder_init_*().
* \retval FLAC__StreamDecoderLengthStatus
*    The callee's return status.
*/
typedef FLAC__StreamDecoderLengthStatus (*FLAC__StreamDecoderLengthCallback)(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data);

/** Signature for the EOF callback.
*
*A function pointer matching this signature may be passed to
*FLAC__stream_decoder_init*_stream().The supplied function will be
*called when the decoder needs to know if the end of the stream has
*been reached.
*
* Here is an example of a EOF callback for stdio streams:
* FLAC__bool eof_cb(const FLAC__StreamDecoder *decoder, void *client_data)
* \code
* {
*   FILE *file = ((MyClientData*)client_data)->file;
*   return feof(file)? true : false;
* }
* \endcode
*
* \note In general, FLAC__StreamDecoder functions which change the
* state should not be called on the \a decoder while in the callback.
*
* \paramdecoderThe decoder instance calling the callback.
* \paramclient_dataThe callee's client data set through
*                      FLAC__stream_decoder_init_*().
* \retval FLAC__bool
*    \c true if the currently at the end of the stream, else \c false.
*/
typedef FLAC__bool (*FLAC__StreamDecoderEofCallback)(const FLAC__StreamDecoder *decoder, void *client_data);

/** Signature for the write callback.
*
*A function pointer matching this signature must be passed to one of
*the FLAC__stream_decoder_init_*() functions.
*The supplied function will be called when the decoder has decoded a
*single audio frame.The decoder will pass the frame metadata as well
*as an array of pointers (one for each channel) pointing to the
*decoded audio.
*
* \note In general, FLAC__StreamDecoder functions which change the
* state should not be called on the \a decoder while in the callback.
*
* \paramdecoderThe decoder instance calling the callback.
* \paramframe    The description of the decoded frame.See
*                  FLAC__Frame.
* \parambuffer   An array of pointers to decoded channels of data.
*                  Each pointer will point to an array of signed
*                  samples of length \a frame->header.blocksize.
*                  Channels will be ordered according to the FLAC
*                  specification; see the documentation for the
*                  <A HREF="../format.html#frame_header">frame header</A>.
* \paramclient_dataThe callee's client data set through
*                      FLAC__stream_decoder_init_*().
* \retval FLAC__StreamDecoderWriteStatus
*    The callee's return status.
*/
typedef FLAC__StreamDecoderWriteStatus (*FLAC__StreamDecoderWriteCallback)(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data);

/** Signature for the metadata callback.
*
*A function pointer matching this signature must be passed to one of
*the FLAC__stream_decoder_init_*() functions.
*The supplied function will be called when the decoder has decoded a
*metadata block.In a valid FLAC file there will always be one
*\c STREAMINFO block, followed by zero or more other metadata blocks.
*These will be supplied by the decoder in the same order as they
*appear in the stream and always before the first audio frame (i.e.
*write callback).The metadata block that is passed in must not be
*modified, and it doesn't live beyond the callback, so you should make
*a copy of it with FLAC__metadata_object_clone() if you will need it
*elsewhere.Since metadata blocks can potentially be large, by
*default the decoder only calls the metadata callback for the
*\c STREAMINFO block; you can instruct the decoder to pass or filter
*other blocks with FLAC__stream_decoder_set_metadata_*() calls.
*
* \note In general, FLAC__StreamDecoder functions which change the
* state should not be called on the \a decoder while in the callback.
*
* \paramdecoderThe decoder instance calling the callback.
* \parammetadata The decoded metadata block.
* \paramclient_dataThe callee's client data set through
*                      FLAC__stream_decoder_init_*().
*/
typedef void (*FLAC__StreamDecoderMetadataCallback)(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data);

/** Signature for the error callback.
*
*A function pointer matching this signature must be passed to one of
*the FLAC__stream_decoder_init_*() functions.
*The supplied function will be called whenever an error occurs during
*decoding.
*
* \note In general, FLAC__StreamDecoder functions which change the
* state should not be called on the \a decoder while in the callback.
*
* \paramdecoderThe decoder instance calling the callback.
* \paramstatus   The error encountered by the decoder.
* \paramclient_dataThe callee's client data set through
*                      FLAC__stream_decoder_init_*().
*/
typedef void (*FLAC__StreamDecoderErrorCallback)(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);那么到最后,我来总结一下解码器的写法:

1、取得解码器对象。FLAC__StreamDecoder *pDecoder=FLAC__stream_decoder_new();
2、初始化解码器。用以下的几个函数中的一个来完成。其实就是告诉libFLAC,要解码的数据的来源,以及解码得到的数据的去向。
FLAC__stream_decoder_init_stream
FLAC__stream_decoder_init_ogg_stream
FLAC__stream_decoder_init_FILE
FLAC__stream_decoder_init_ogg_FILE
FLAC__stream_decoder_init_file
FLAC__stream_decoder_init_ogg_file

3、开始解码过程。调用以下的函数来实现。
FLAC__stream_decoder_process_single:解码一个块。
FLAC__stream_decoder_process_until_end_of_metadata:解码全部metadata块。
FLAC__stream_decoder_process_until_end_of_stream:解码全部块。

4、完成解码后清理用过的内存。
FLAC__stream_decoder_delete(pDecoder);

就这些。

界限突破 发表于 2015-4-13 18:18:34

求大神编译一个1.3.1版本的,这玩意编译真是太蛋疼了

界限突破 发表于 2015-4-13 18:26:43

我试了下,不知为什么链接错误一大堆,我在国外网站找的也一样

0xAA55 发表于 2015-4-13 19:20:37

界限突破 发表于 2015-4-13 18:26
我试了下,不知为什么链接错误一大堆,我在国外网站找的也一样

你用的是libFLAC的C艹库。你需要自己构建这个子类,然后完成那些接口,否则无法链接。

界限突破 发表于 2015-4-13 22:46:42

0xAA55 发表于 2015-4-13 19:20
你用的是libFLAC的C艹库。你需要自己构建这个子类,然后完成那些接口,否则无法链接。 ...

soga,多谢指点
页: [1]
查看完整版本: 【C】libFLAC的使用