网上关于这个结构的介绍有很多,我在之前最初学习时查看过相关源码记录了一些笔记,由于更换固态硬盘笔记一直在原来128g的固态中,想将其改成U盘成本实在是太高,很多笔记都扔在里面了,真的好蛋疼,我直接写一些我的使用,其他的在一点一点完善
AVFormatContext* get_input_avformatcontex_f(char *input_url){
int ret = 0;
char errbuf[1024] = {0,};
AVFormatContext *fmt_ctx = NULL;
AVInputFormat *ifmt = NULL;
AVDictionary *options = NULL;
ifmt = av_find_input_format("avfoundation");
//查看设备支持什么作为输入
av_dict_set(&options,"list_devices","true",0);
char *input_stream_url = input_url; //设置输入源通常为本地文件或一些链接
//如果是使用ffmpeg进行采集则需要设置一些音频或视频的采集参数
/*
av_dict_set(&options, "video_size", w_h_c_str, 0);
av_dict_set(&options, "framerate", "30", 0);
av_dict_set(&options, "pixel_format", "nv12", 0);
{"pixel_format", "set pixel format", OFFSET(pix_fmt), AV_OPT_TYPE_PIXEL_FMT, {.i64=AV_PIX_FMT_NONE}, -1, INT_MAX, 0 },
{"video_size", "set video size", OFFSET(width), AV_OPT_TYPE_IMAGE_SIZE, {.str=NULL}, 0, INT_MAX, 0 }, {NULL}, };
*/
av_log_set_level(AV_LOG_DEBUG);
if ((ret = avformat_open_input(&fmt_ctx, input_stream_url, ifmt, &options)) < 0){
av_strerror(ret, errbuf, 1024);
fprintf(stderr, "Failed to open audio device, [%d]%s\n", ret, errbuf);
return NULL;
}
return fmt_ctx;
}
然后创建一个AVPacket用来接收封装数据
AVPacket* get_avpacket_f_input(){
AVPacket *av_packet = NULL;
av_packet = av_packet_alloc();
if (!av_packet) {
fprintf(stderr,"av_packet_alloc failed");
goto __ERROR;
}
return av_packet;
__ERROR:
if (!av_packet) {
av_packet_free(&av_packet);
}
return NULL;
}
在打开输入上下文之后可以对获取数据进行解码
-(void)decode_audio:(AVCodecContext *)input_ctx and_packet:(AVPacket *)input_avpacket{
int ret = -1;
ret = avcodec_send_packet(input_ctx, input_avpacket);
while (ret >=0 ) {
ret = avcodec_receive_frame(input_ctx,input_a_frame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
return;
else if (ret < 0) {
fprintf(stderr, "Error during decoding\n");
exit(1);
}
if (ret >= 0) {
self.callback(Collect_Data_Audio, input_a_frame);
}
av_packet_unref(input_packet);//一定要记得释放 如果不释放内存会暴涨
}
}
可以在获取数据之前查看输入流的相关信息代码如下
- (void)get_input_stream_oc:(char *)input_url and_avFormatContext:(AVFormatContext *)input_fmt{
avformat_find_stream_info(input_fmt, NULL);
av_dump_format(input_fmt, 0, input_url , 0);
for (int i = 0; i < input_fmt->nb_streams; i++) {
AVStream *stream = input_fmt->streams[i];
if (stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {//打印流信息
audio_stream_index = i;
}else if(stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO){
video_stream_index = i;
}
}
//音频
AVCodec *acodec = avcodec_find_decoder(input_fmt->streams[audio_stream_index]->codecpar->codec_id);
AVCodecContext *ac = avcodec_alloc_context3(acodec);
ac->sample_rate = input_fmt->streams[audio_stream_index]->codecpar->sample_rate;
ac->sample_fmt = input_fmt->streams[audio_stream_index]->codecpar->format;
ac->channels = input_fmt->streams[audio_stream_index]->codecpar->channels;
avcodec_open2(ac, acodec, NULL);
AVFrame *frame = av_frame_alloc();
frame->nb_samples = ac->frame_size;
frame->channel_layout = ac->channel_layout;
frame->format = ac->sample_fmt;
av_frame_get_buffer(frame, 0);
input_de_codec_a = acodec;
input_de_ctx_a = ac;
input_a_frame = frame;
//视频
AVCodecContext* vc = input_fmt->streams[video_stream_index]->codec;
AVCodec* vcodec = avcodec_find_decoder(vc->codec_id);
avcodec_open2(vc, vcodec, NULL);
AVFrame *vframe = av_frame_alloc();
av_frame_get_buffer(vframe, 0);
input_de_codec_v = vcodec;
input_de_ctx_v = vc;
input_v_frame = vframe; //c函数内无法这样给成员变量赋值 应该是语法的问题
[self config_av_inputfmt:fmt_ctx and_videoindex:video_stream_index and_audioindex:audio_stream_index];
}
我将采集到的裸数据以call的形式返回到调用出在外部,在外部可以进行放入队列或者是重采样编码等操作