FFmpeg - 音频解码
来源:互联网 发布:淘宝模特拍摄动作 编辑:程序博客网 时间:2024/05/21 22:45
因公司项目需求。简单学习了FFMPEG。在这里做个记录。
音频解码的流程如下:
先介绍一下AVFormatContext里面的几个成员:
/**
* Maximum size of the data read from input for determining
* the input container format.
* Demuxing only, set by the caller before avformat_open_input().
*/
int64_t probesize;
/**
* Maximum duration (in AV_TIME_BASE units) of the data read
* from input in avformat_find_stream_info().
* Demuxing only, set by the caller before avformat_find_stream_info().
* Can be set to 0 to let avformat choose using a heuristic.
*/
int64_t max_analyze_duration;
/**
* Custom interrupt callbacks for the I/O layer.
*
* demuxing: set by the user before avformat_open_input().
* muxing: set by the user before avformat_write_header()
* (mainly useful for AVFMT_NOFILE formats). The callback
* should also be passed to avio_open2() if it's used to
* open the file.
*/
AVIOInterruptCB interrupt_callback;
/**
* I/O context.
*
* - demuxing: either set by the user before avformat_open_input() (then
* the user must close it manually) or set by avformat_open_input().
* - muxing: set by the user before avformat_write_header(). The caller must
* take care of closing / freeing the IO context.
*
* Do NOT set this field if AVFMT_NOFILE flag is set in
* iformat/oformat.flags. In such a case, the (de)muxer will handle
* I/O in some other way and this field will be NULL.
*/
AVIOContext *pb;
输入为内存的时候,我们需要设置一个AVIOContext。
而直接用于拉流时,可以直接调用avformat_open_input。第二个参数传url。
ffmpeg也提供了停止拉流的方法。设置AVFormatContext的interrupt_callback。自己写一个回调。当它返回1时,拉流停止。
这里还有一个延迟的问题。ffmpeg解码时,会先猜测解码的数据格式。通过设置AVFormatContext的probeSize和max_analyze_duration。可以明显的降低延迟。
直接上代码:
#ifndef _IDECODE_H_#define _IDECODE_H_#include "util.h"extern "C" {#include <libavcodec/avcodec.h>#include <libavformat/avformat.h>};//中断int decode_interrupt_cb(void *obj);class IDecode{public:int init();int run();//数据输出回调void setWritePacketFuncCB(write_packetFunc func);//回调输出对象void setOutputObj(void *outObj);//设置猜测缓存,ff默认为32KB,太小可能导致无法解码void setProbeSize(int64_t probeSize);//设置猜测时间,ff默认为5s,太小可能导致无法解码void setMaxAnalyzeDuration(int64_t maxAnalyzeDuration);//暂停void pause();//继续解码void play();//停止,用于销毁之前void stop();//用于获取编码器信息void setGetSampleRateCB(getParamsCallBack cb);void setGetBitRateCB(getParamsCallBack cb);void setGetSampleFmtCB(getParamsCallBack cb);void setGetCodecidCB(getParamsCallBack cb);virtual ~IDecode();protected:virtual int constructAVIO() = 0;int constructCodec();virtual void release() = 0;bool isStop;bool isPause;void* outPutObj;AVFormatContext *fmt_ctx;AVCodecContext *pInCodecCtx;int64_t probeSize;int64_t maxAnalyzeDuration;getParamsCallBack getSampleRateCB;getParamsCallBack getBitRateCB;getParamsCallBack getSampleFmtCB;getParamsCallBack getCodecidCB;write_packetFunc writePacket;explicit IDecode();int writeFrame(AVFrame *decoded_frame, AVPacket &pkt, AVCodecContext *pInCodecCtx);public://用于中断bool getStop()const;};#endif // _IDECODE_H_
#ifndef _IDECODE_MEM_H_#define _IDECODE_MEM_H_#include "IDecode.h"class IDecode_mem : public IDecode{const int AV_IO_BUFF_SIZE = 1024;public:typedef int(*read_packetFunc)(void *opaque, uint8_t *buf, int buf_size);public:explicit IDecode_mem();void setInputObj(void* obj);void setReadPacketFuncCallback(read_packetFunc func);~IDecode_mem();private:void release();int constructAVIO() override;AVIOContext *avio_ctx;read_packetFunc readPacket;void* inputObj;};#endif // _IDECODE_MEM_H_
#ifndef _IDECODE_URL_H_#define _IDECODE_URL_H_#include "IDecode.h"#include <string>class IDecode_url : public IDecode{public:explicit IDecode_url();//设置拉流URLvoid setUrl(const std::string& url);~IDecode_url();private:int constructAVIO() override;void release() override;std::string url;};#endif // !_IDECODE_MEM_H_
#include "IDecode.h"#include "error.h"IDecode::IDecode():writePacket(nullptr), outPutObj(nullptr),isStop(false), getSampleRateCB(nullptr),getBitRateCB(nullptr), getSampleFmtCB(nullptr),getCodecidCB(nullptr), fmt_ctx(nullptr),pInCodecCtx(nullptr), isPause(false){av_register_all();}IDecode::~IDecode(){}void IDecode::setWritePacketFuncCB(write_packetFunc func){this->writePacket = func;}void IDecode::setOutputObj(void *outObj){this->outPutObj = outObj;}void IDecode::setGetSampleRateCB(getParamsCallBack cb){this->getSampleFmtCB = cb;}void IDecode::setGetBitRateCB(getParamsCallBack cb){this->getBitRateCB = cb;}void IDecode::setGetSampleFmtCB(getParamsCallBack cb){this->getSampleFmtCB = cb;}void IDecode::setGetCodecidCB(getParamsCallBack cb){this->getCodecidCB = cb;}void IDecode::stop(){this->isStop = true;}bool IDecode::getStop()const{return isStop;}void IDecode::pause(){isPause = true;}void IDecode::play(){isPause = false;}void IDecode::setProbeSize(int64_t probeSize){this->probeSize = probeSize;}void IDecode::setMaxAnalyzeDuration(int64_t maxAnalyzeDuration){this->maxAnalyzeDuration = maxAnalyzeDuration;}int IDecode::run(){Error error;AVPacket pkt;int got_frame = 0;AVFrame *decoded_frame = nullptr;while (av_read_frame(fmt_ctx, &pkt) >= 0){if (!isPause) {av_init_packet(&pkt);error = (Error)writeFrame(decoded_frame, pkt, pInCodecCtx);if (Error::ERROR_NONE != error){av_packet_unref(&pkt);if (decoded_frame)av_frame_free(&decoded_frame);release();return error;}av_packet_unref(&pkt);}}if (decoded_frame)av_frame_free(&decoded_frame);avformat_close_input(&fmt_ctx);return Error::ERROR_NONE;}int IDecode::writeFrame(AVFrame *decoded_frame, AVPacket &pkt, AVCodecContext *pInCodecCtx){int got_frame = 0;int len = 0;while (pkt.size > 0){if (!decoded_frame){if (!(decoded_frame = av_frame_alloc())){decoded_frame = nullptr;return Error::ERROR_FRAME_ALLOCATE;}}int got_frame = 0;len = avcodec_decode_audio4(pInCodecCtx, decoded_frame, &got_frame, &pkt);if (len < 0) {return Error::ERROR_DECODING;}if (got_frame){int data_size = av_get_bytes_per_sample(pInCodecCtx->sample_fmt);if (data_size < 0){return Error::ERROR_CALCULATE_DATA_SIZE;}int frame_buf_size = decoded_frame->nb_samples * data_size * pInCodecCtx->channels;uint8_t* frame_buf = new uint8_t[frame_buf_size];for (int i = 0; i < decoded_frame->nb_samples; i++){for (int ch = 0; ch < pInCodecCtx->channels; ch++){memcpy(frame_buf + i*data_size*(ch + 1), decoded_frame->data[ch] + data_size*i, data_size);}}if (writePacket) {writePacket(outPutObj, frame_buf, frame_buf_size);}delete []frame_buf;}pkt.size -= len;pkt.data += len;pkt.dts = pkt.pts = AV_NOPTS_VALUE;}return Error::ERROR_NONE;}int IDecode::constructCodec(){int ret = 0;ret = avformat_find_stream_info(fmt_ctx, nullptr);if (ret < 0){release();return Error::ERROR_FORMAT_FIND_STREAM_INFO;}int audio_index = -1;for (size_t i = 0; i < fmt_ctx->nb_streams; i++){if (fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {audio_index = i;}}if (-1 == audio_index){release();return Error::ERROR_NONE_AUDIO;}AVCodec *codec = avcodec_find_decoder(fmt_ctx->streams[audio_index]->codecpar->codec_id);if (!codec){release();return Error::ERROR_NO_CODEC_SUPPORT;}pInCodecCtx = fmt_ctx->streams[audio_index]->codec;if (getSampleRateCB)getSampleRateCB(pInCodecCtx->sample_rate);if (getBitRateCB)getBitRateCB(pInCodecCtx->bit_rate);if (getSampleFmtCB)getSampleFmtCB(pInCodecCtx->sample_fmt);if (getCodecidCB)getCodecidCB(pInCodecCtx->codec_id);if ((ret = avcodec_open2(pInCodecCtx, codec, nullptr)) < 0){release();return Error::ERROR_AVCODEC_OPEN2;}return Error::ERROR_NONE;}int IDecode::init(){Error error;error = (Error)constructAVIO();if (Error::ERROR_NONE != error){return error;}error = (Error)constructCodec();return error;}int decode_interrupt_cb(void *obj){//线程不安全if (obj != nullptr){IDecode *decode = (IDecode *)obj;if (decode->getStop()){return 1;}}return 0;}
#include "IDecode_mem.h"#include "error.h"IDecode_mem::IDecode_mem() :inputObj(nullptr), readPacket(nullptr), avio_ctx(nullptr){}IDecode_mem::~IDecode_mem(){}void IDecode_mem::setReadPacketFuncCallback(read_packetFunc func){this->readPacket = func;}int IDecode_mem::constructAVIO(){uint8_t *avio_ctx_buffer = nullptr;int ret = 0;avio_ctx_buffer = (uint8_t*)av_malloc(AV_IO_BUFF_SIZE);if (!avio_ctx_buffer){return Error::ERROR_ALLOC;}avio_ctx = avio_alloc_context(avio_ctx_buffer,AV_IO_BUFF_SIZE,0,inputObj, readPacket,nullptr,nullptr);if (!avio_ctx){avio_ctx = nullptr;return Error::ERROR_AVIO_ALLOC_CONTEXT;}if (!(fmt_ctx = avformat_alloc_context())){release();return Error::ERROR_ALLOC_CONTEXT;}const AVIOInterruptCB int_cb = { decode_interrupt_cb, this };if (-1 != probeSize)fmt_ctx->probesize = probeSize;if (-1 != maxAnalyzeDuration)fmt_ctx->max_analyze_duration = maxAnalyzeDuration;fmt_ctx->interrupt_callback = int_cb;fmt_ctx->pb = avio_ctx;ret = avformat_open_input(&fmt_ctx, nullptr, nullptr, nullptr);if (ret < 0) {release();return Error::ERROR_FORMAT_OPEN_INPUT;}return Error::ERROR_NONE;}void IDecode_mem::setInputObj(void* obj){this->inputObj = obj;}void IDecode_mem::release(){if (avio_ctx){av_freep(&avio_ctx->buffer);av_freep(&avio_ctx);}avformat_close_input(&fmt_ctx);}
#include "IDecode_url.h"#include "error.h"IDecode_url::IDecode_url() : url(""){avformat_network_init();}IDecode_url::~IDecode_url(){}void IDecode_url::setUrl(const std::string& url){this->url = url;}int IDecode_url::constructAVIO(){int ret = 0;if (!(fmt_ctx = avformat_alloc_context())){return Error::ERROR_ALLOC_CONTEXT;}const AVIOInterruptCB int_cb = { decode_interrupt_cb, this };if (-1 != probeSize)fmt_ctx->probesize = probeSize;if (-1 != maxAnalyzeDuration)fmt_ctx->max_analyze_duration = maxAnalyzeDuration;fmt_ctx->interrupt_callback = int_cb;ret = avformat_open_input(&fmt_ctx, url.c_str(), nullptr, nullptr);if (ret < 0){release();return Error::ERROR_FORMAT_OPEN_INPUT;}return Error::ERROR_NONE;}void IDecode_url::release(){if(fmt_ctx)avformat_close_input(&fmt_ctx);}
使用方法:
FILE *f2 = fopen(outFileName, "wb");int writeData(void*p, uint8_t* data, int size) {cout << "asdasd" << endl;fwrite(data, 1, size, f2);return 1;}void thread_run(IDecode_url *decode,int &ret){decode->init();ret = decode->run();}void testDecoder_url(){int ret = -1;IDecode_url *decode = new IDecode_url;decode->setUrl("http://XXXXX:XXXX/1_1.mp3");decode->setOutputObj(nullptr);decode->setProbeSize(1024);decode->setMaxAnalyzeDuration(2000);decode->setWritePacketFuncCB(writeData);thread _thread(thread_run, decode, std::ref(ret));_thread.detach();_sleep(3000);decode->stop();_sleep(10000);delete decode;decode = nullptr;fclose(f2);}
- ffmpeg音频解码
- FFMPEG音频解码浅析
- FFmpeg - 音频解码过程
- FFmpeg - 音频解码
- FFMPEG 解码音频
- FFMPEG音频解码浅析
- ffmpeg 开源视、音频解码
- FFmpeg解码音频
- ffmpeg库音频解码示例
- ffmpeg 解码音频的方法
- ffmpeg库音频解码示例
- ffmpeg库音频解码示例
- ffmpeg库音频解码示例
- ffmpeg库音频解码示例
- ffmpeg 解码音频的方法
- ffmpeg库音频解码示例
- ffmpeg库音频解码示例
- ffmpeg的音频解码部分
- js 字符串与数值相互转换,以及时间戳转换成日期形式字符串方法
- SSM框架的详细解说
- Handler内存泄漏
- datagrid getselected/getselections/getData之间的用法差异
- Java foreach(加强for循环)
- FFmpeg - 音频解码
- 欢迎使用CSDN-markdown编辑器
- SpringMVC+Hibernate+Spring整合实例
- 正则表达式时间复杂度O(n)
- Linux 每天自动备份mysql数据库的方法
- UI层自动化测试框架(三):基础层
- 【龙印】3D打印固件Marlin中限位开关相关代码解读
- 知乎爬虫
- centos 7 lamp+lnmp环境