ffmpeg关于io的输入输出操作

                                     ffmpeg关于io的输入输出操作

ffmpeg 无论转码是本地文件输入输出,例如将mp4文件 转成 flv文件,或者从rtmp流接入到rtsp流,这时候我们在输入输出端拿不到数据流,只能拿到输入输出的地址,这时候ffmpeg的 io就出场了,道理是把输入输出流写入到缓存中,在做处理。应用场景例如:从http 拿到的数据流,从摄像头拿到的数据流,这些都能作为io输入,将mux后的数据write到io用于存成文件,或者librtmp打包出去,这些都用于io输出。具体操作如下:

1:ffmpeg的IO输入

			Io_Buf_Info buf_info;
			//这里必须用av_malloc申请,用calloc申请会崩溃
			buf_info.BufLen = DEMUX_MAX_IO_BUF_SIZE;
			buf_info.Buf = (char * )av_malloc(buf_info.BufLen);
			m_list_format_io_buf[rtmpaddress_id] = (buf_info);

			AVIOContext * pb = NULL;
			AVInputFormat *piFmt = NULL;
			AVFormatContext * m_pFmt = NULL;

			//step1:申请一个AVIOContext,传入回调函数
			//填写当前要读的rtmpaddress_id 回调里面才能知道去读哪一个地址的流
			param->use_rtmpaddress_id = rtmpaddress_id;
			pb = avio_alloc_context((unsigned char *)buf_info.Buf, buf_info.BufLen,0, param,
				param->read_packet_cb, NULL,param->seek_cb);
			if (!pb) 
			{
				printf("ERROR : avio alloc failed!\n");
				return -1;
			}
			//step2:探测流格式
			if (av_probe_input_buffer2(pb, &piFmt, "", NULL,0,0) < 0) 
			{
				printf("ERROR : probe failed!\n");
				return -1;
			} 
			else 
			{
				printf("SUCCESS :probe success!\n");
				printf("format: %s[%s]\n", piFmt->name, piFmt->long_name);
			}

			m_pFmt = avformat_alloc_context();
			m_pFmt->pb = pb; //step3:这一步很关键
			//step4:打开流
			if (avformat_open_input(&m_pFmt, "", piFmt, NULL) < 0)
			{
				printf("ERROR : avformat open failed.\n");
				return -1;
			} 
			else 
			{
				printf("SUCCESS : open stream success!\n");
			}

			av_dump_format(m_pFmt, 0, "", 0);
这样就和本地文件一样用av_read_frame读取数据read_packet_cb中放入数据。

2:ffmpeg的IO输出

<pre name="code" class="cpp">		Module_StreamInfo * module_streaminfo = in_video->second;
		AVFormatContext * formatcontext = avformat_alloc_context();
		AVIOContext * pb = NULL;
		AVStream * ovideo_st = NULL;   
		Io_Buf_Info  io_buf_info_video;

		io_cb_write_pram * cb_pram_video = NULL;
		cb_pram_video = (io_cb_write_pram *)malloc(sizeof(io_cb_write_pram )* 1);
		cb_pram_video->thisclass  = this;
		cb_pram_video->pram = module_streaminfo;
		m_list_cb_write_pram[module_streaminfo->stream_id] = (cb_pram_video);

		//step1 申请一个AVFormatContext 
		if (m_mux_info.mux_format == MuxFormat_Flv)
		{
			avformat_alloc_output_context2(&formatcontext, NULL,"flv",NULL); 
		}
		else if (m_mux_info.mux_format == MuxFormat_Mpegts)
		{
			avformat_alloc_output_context2(&formatcontext, NULL,"mpegts",NULL); 
		}
		else if (m_mux_info.mux_format == MuxFormat_Mp4)
		{
			avformat_alloc_output_context2(&formatcontext, NULL,"mp4",NULL); 
		}
		else
		{
			avformat_alloc_output_context2(&formatcontext, NULL,"flv",NULL); 
		}
		if (!formatcontext)   
		{  
			return -1;
		}    

		//step2申请一个AVIOContext
		//这里分配大小一定要是4096的整数倍,足够一帧大小否则中断
		io_buf_info_video.BufLen = (module_streaminfo->VideoInfo.Width * module_streaminfo->VideoInfo.Height * 3 /20 + 100) /
			4096 * 4096;
		io_buf_info_video.Buf =(char *)calloc(module_streaminfo->BufLen,sizeof(char));
		m_list_format_io_buf[in_video->first] = (io_buf_info_video);

		pb = avio_alloc_context((unsigned char *)m_list_format_io_buf[in_video->first].Buf,
			m_list_format_io_buf[in_video->first].BufLen,1,cb_pram_video, NULL, cb_write_data, NULL);
		if (!pb) 
		{
			printf("error : avio alloc failed!\n");
			return -1;
		}

		//step3:这一步很关键,将输出的buf和AVFormatContext关联
		formatcontext->pb = pb; 
		//The caller has supplied a custom AVIOContext, don't avio_close() it.
		//AVFMT_FLAG_FLUSH_PACKETS这个值相当重要,他决定每次写av_interleaved_write_frame,是否立刻返回
		formatcontext->flags = AVFMT_FLAG_CUSTOM_IO | AVFMT_FLAG_FLUSH_PACKETS;  

		//step4 添加流信息
		ovideo_st = add_out_stream2(formatcontext,AVMEDIA_TYPE_VIDEO,module_streaminfo);
		if (ovideo_st == NULL)
		{
			return -1;
		}

		//这里要填写1否则中断
		av_dump_format(formatcontext, 0, "", 1);
		ret = avformat_write_header(formatcontext, NULL);  
		if (ret != 0)  
		{  
			printf("Call avformat_write_header function failed.\n");  
			return -1;  
		}
		avio_flush(pb);

 这样在cb_write_data回调中就有要的数据了。 



如有错误请指正:

交流请加QQ群:62054820
QQ:379969650.


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值