音频采集
今天我們來談論下如何在進行音頻采集。
系統多種多樣?電腦上的系統有mac,windows,linux。手機系統有android,ios等。如果我們使用每種系統的音視頻函數進行采集,成本會很大。ffmpeg已經為我們封裝了相應的api。
今天我們講一下,音頻的采集流程和相應的api。最后我們通過一個例子來實現音頻的采集。
音頻采集的流程簡單來說如下圖
用ffmepg描述上面的流程
可以下面流程圖描述
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
ffmpeg流程講解
1、要想對設備操作我們就要對設備進行注冊
/*** Initialize libavdevice and register all the input and output devices.*/ void avdevice_register_all(void);2、設置采集方式
/*** Find AVInputFormat based on the short name of the input format.*/ ff_const59 AVInputFormat *av_find_input_format(const char *short_name);av_find_input_format?傳入的參數avfoundataion/dshow/alsa
avfoundataion mac
dshow? windows
alsa? linux
AVInputFormat是ffmpeg的解復用器對象,
一種文件格式對應一個AVInputFormat結構,在程序運行時候有多個實例。
next變量用于把支持的所有輸入文件容器格式連接成鏈表,便于遍歷查找。
priv_data_size標識具體的文件容器格式對應的Context大小。
我們看下AVInputFormat?的結構體都有什么內容
typedef struct AVInputFormat {/*格式的短名稱*/const char *name;/*格式的長名稱*/const char *long_name;/*** Can use flags: AVFMT_NOFILE, AVFMT_NEEDNUMBER, AVFMT_SHOW_IDS,* AVFMT_NOTIMESTAMPS, AVFMT_GENERIC_INDEX, AVFMT_TS_DISCONT, AVFMT_NOBINSEARCH,* AVFMT_NOGENSEARCH, AVFMT_NO_BYTE_SEEK, AVFMT_SEEK_TO_PTS.*/int flags;/*定義了擴展,如果不進行格式探測通常不用擴展*/const char *extensions;/*codec 的tag*/const struct AVCodecTag * const *codec_tag;/*AvClass 用戶內部的context*/const AVClass *priv_class; ///< AVClass for the private context/*** Comma-separated list of mime types.* It is used check for matching mime types while probing.* @see av_probe_input_format2*//*mime類型,當probing的時候需檢測是否是需要的mime類型*/const char *mime_type;/****************************************************************** No fields below this line are part of the public API. They* may not be used outside of libavformat and can be changed and* removed at will.* New public fields should be added right above.******************************************************************//*用于把支持的所有輸入文件容器格式連接成鏈表*/ #if FF_API_NEXTff_const59 struct AVInputFormat *next; #endif/*** 原始解封裝存儲的id*/int raw_codec_id;/*** 格式文件的大小*/int priv_data_size;/*** 判斷給定的文件是否有機會被解析為這種格式。* 提供的緩沖區保證為AVPROBE_PADDING_SIZE字節大小,因此除非您需要更多,否則不必檢查該緩沖區。.*/int (*read_probe)(const AVProbeData *);/**讀取格式頭并初始化AVFormatContext結構。 如果正確,則返回0。 應該調用“ avformat_new_stream”來創建新的流。*/int (*read_header)(struct AVFormatContext *);/*讀取一個包,并放在pkt當中。pts和flags常常被設置。加入當前flag = AVFMTCTX_NOHEADER,就會調用avformat_new_stream,這個方法必須在可見線程調用0為成功,<0錯誤調用后,不管成功與否,必須釋放AVPacket*/int (*read_packet)(struct AVFormatContext *, AVPacket *pkt);/*關閉流。AVFormatContext和AVStreams沒有被釋放*/int (*read_close)(struct AVFormatContext *);/*讀取給定的時間錯*/int (*read_seek)(struct AVFormatContext *,int stream_index, int64_t timestamp, int flags);/*** Get the next timestamp in stream[stream_index].time_base units.* @return the timestamp or AV_NOPTS_VALUE if an error occurred*//*讀取stream[stream_index]中的下一個時間戳, 如果錯誤發生返回AV_NOPTS_VALUE*/int64_t (*read_timestamp)(struct AVFormatContext *s, int stream_index,int64_t *pos, int64_t pos_limit);/*恢復播放,只在RTSP格式下有意義*/int (*read_play)(struct AVFormatContext *);/*暫停播放,只在RTSP格式下有意義*/int (*read_pause)(struct AVFormatContext *);/*快進快退到指定時間戳*/int (*read_seek2)(struct AVFormatContext *s, int stream_index, int64_t min_ts, int64_t ts, int64_t max_ts, int flags);/*返回設備列表及其屬性*/int (*get_device_list)(struct AVFormatContext *s, struct AVDeviceInfoList *device_list);/*初始化設備能力子模塊*/int (*create_device_capabilities)(struct AVFormatContext *s, struct AVDeviceCapabilitiesQuery *caps);/*釋放設備能力子模塊*/int (*free_device_capabilities)(struct AVFormatContext *s, struct AVDeviceCapabilitiesQuery *caps); } AVInputFormat;3、打開設備
/*** Open an input stream and read the header. The codecs are not opened.* The stream must be closed with avformat_close_input().** @param ps Pointer to user-supplied AVFormatContext (allocated by avformat_alloc_context).* May be a pointer to NULL, in which case an AVFormatContext is allocated by this* function and written into ps.* Note that a user-supplied AVFormatContext will be freed on failure.* @param url URL of the stream to open.* @param fmt If non-NULL, this parameter forces a specific input format.* Otherwise the format is autodetected.* @param options A dictionary filled with AVFormatContext and demuxer-private options.* On return this parameter will be destroyed and replaced with a dict containing* options that were not found. May be NULL.** @return 0 on success, a negative AVERROR on failure.** @note If you want to use custom IO, preallocate the format context and set its pb field.*/ int avformat_open_input(AVFormatContext **ps, const char *url, ff_const59 AVInputFormat *fmt, AVDictionary **options);4、從音頻設備獲取數據放在AVPacket
/*** Return the next frame of a stream.* This function returns what is stored in the file, and does not validate* that what is there are valid frames for the decoder. It will split what is* stored in the file into frames and return one for each call. It will not* omit invalid data between valid frames so as to give the decoder the maximum* information possible for decoding.** On success, the returned packet is reference-counted (pkt->buf is set) and* valid indefinitely. The packet must be freed with av_packet_unref() when* it is no longer needed. For video, the packet contains exactly one frame.* For audio, it contains an integer number of frames if each frame has* a known fixed size (e.g. PCM or ADPCM data). If the audio frames have* a variable size (e.g. MPEG audio), then it contains one frame.** pkt->pts, pkt->dts and pkt->duration are always set to correct* values in AVStream.time_base units (and guessed if the format cannot* provide them). pkt->pts can be AV_NOPTS_VALUE if the video format* has B-frames, so it is better to rely on pkt->dts if you do not* decompress the payload.** @return 0 if OK, < 0 on error or end of file. On error, pkt will be blank* (as if it came from av_packet_alloc()).** @note pkt will be initialized, so it may be uninitialized, but it must not* contain data that needs to be freed.*/ int av_read_frame(AVFormatContext *s, AVPacket *pkt);5、AVPacket使用完要進行釋放
涉及到四個函數
av_init_packet(<AVPacket *pkt)
av_packet_unref(AVPacket *pkt)
?
av_packet_alloc()
先分配空間,再進行初始化
av_packet_free(AVPacket **pkt)
先av_packet_unref,再釋放空間
av_init_packet和av_packet_unref是一對
av_packet_alloc和av_packet_free是一對。
要成對出現要不會內存泄漏
6關閉輸入設備
/*** Close an opened input AVFormatContext. Free it and all its contents* and set *s to NULL.*/ void avformat_close_input(AVFormatContext **s);?
下一篇文章我們來進行下實戰,在mac寫一個demo能夠進行音頻采集。
總結
- 上一篇: asp毕业设计——基于asp+sqlse
- 下一篇: 狂雨小说带自动采集规则加俩套小说模板