基于FFmpeg音视频流同步

通过ffmpeg将PCM音频数据和RGB视频数据转码、编码成AAC+H264,再通过内存读写数据封装MP4格式。

难点在于将转码后的数据输出到内存中,再从内存读取数据并封装

AVFormatContext *ic = NULL;  
ic = avformat_alloc_context();  

unsigned char * iobuffer=(unsigned char *)av_malloc(32768);//音视频大小  
AVIOContext *avio =avio_alloc_context(iobuffer, 32768,0,buffer,fill_iobuffer,NULL,NULL);  
ic->pb=avio;  
err = avformat_open_input(&ic, is->filename, is->iformat, &format_opts);

关键要在avformat_open_input()之前初始化一个AVIOContext,而且将原本的AVFormatContext的指针pb(AVIOContext类型)指向这个自行初始化AVIOContext。当自行指定了AVIOContext之后,avformat_open_input()里面的URL参数就不起作用了。示例代码开辟了一块空间iobuffer作为AVIOContext的缓存。

此外buffer就是期望读取数据的内存,fill_iobuffer则是读取buffer数据至iobuffer的回调函数。fill_iobuffer()形式(参数,返回值)是固定的,是一个回调函数,具体怎么读取数据可以自行设计。

//把数据从buffer向iobuf传  
//AVIOContext使用的回调函数  
//注意:返回值是读取的字节数  
//手动初始化AVIOContext只需要两个东西:内容来源的buffer,和读取这个buffer到ffmpeg中的函数  
int fill_iobuffer(void * buffer,uint8_t *iobuf, int bufsize){  
     int i;  
     for(i=0;i<bufsize;i++){  
     	iobuf[i]=mediabuf_get();  
     }  
     return i;  
}  

ffmpeg读写内存的关键点:

1.初始化自定义的AVIOContext,指定自定义的回调函数。

2.自己写回调函数。注意函数的参数和返回值。

源码

#define _CRT_SECURE_NO_WARNINGS

extern "C"
{
#include "libavcodec\avcodec.h"
#include "libavformat\avformat.h"
#include "libswscale\swscale.h"
};

#define VIDEO_AVIO_SIZE 6220800//176400//32768*8//1920*1080*3
#define AUDIO_AVIO_SIZE 16384//5120//512 * 10//4096*2*2

//video parameter
AVFormatContext* pFormatCtx_v;
AVStream* video_st;
AVCodecContext* pCodecCtx_v;
AVCodec* pCodec_v;
AVPacket pkt_v;
uint8_t *picture_buf_RGB, *picture_buf_YUV;
AVFrame *pFrameRGB, *pFrameYUV;
SwsContext* scxt;
int picture_size_RGB, picture_size_YUV;
int y_size;
int in_w = 1280, in_h = 720; //Input data's width and height
FILE *in_file_v = fopen("vid0_1280x720.rgb", "rb"); //Input raw RGB data

//audio parameter
AVFormatContext* pFormatCtx_a;
AVStream* audio_st;
AVCodecContext* pCodecCtx_a;
AVCodec* pCodec_a;
AVPacket pkt_a;
uint8_t* frame_buf_a;
AVFrame* frame_a;
int frame_size_a;
FILE *in_file_a = fopen("aud0.pcm", "rb");	//音频PCM采样数据 

//mux parameter
AVOutputFormat *ofmt = NULL;
//输入对应一个AVFormatContext,输出对应一个AVFormatContext
AVFormatContext *ifmt_ctx_v = NULL, *ifmt_ctx_a = NULL, *ofmt_ctx = NULL;
AVPacket pkt2;
int ret2, k;
int videoindex_v = -1, videoindex_out = -1;
int audioindex_a = -1, audioindex_out = -1;
int frame_index = 0;
int64_t cur_pts_v = 0, cur_pts_a = 0;
unsigned char* inbuffer_v = NULL;
AVIOContext *avio_in_v = NULL;
unsigned char* inbuffer_a = NULL;
AVIOContext *avio_in_a = NULL;
AVBitStreamFilterContext* aacbsfc;

int FirstFlg_video = 0;
int FirstFlg_audio = 0;
int InitFlg = 0;
//累计h264帧size,当AVIO的buffer满时调用mux
int videoencodesize = 0;
int audioencodesize = 0;
//mux帧数
int muxcount = 0;
char videoBuf[VIDEO_AVIO_SIZE];
unsigned int frmsize_v = 0;
char audioBuf[AUDIO_AVIO_SIZE];
unsigned int frmsize_a = 0;

int read_video_buffer(void *opaque, uint8_t *buf, int buf_size)
{
	int lsize = 0;
	if (videoencodesize != 0)
	{
		//printf("read video data: %d\n", readcnt++);
		memcpy(buf, videoBuf, videoencodesize);
		lsize = videoencodesize;
		//fwrite(videoBuf, 1, videoencodesize, out_video);
		videoencodesize = 0;
	}
	return lsize;
}

int read_audio_buffer(void *opaque, uint8_t *buf, int buf_size)
{
	int lsize = 0;
	if (audioencodesize != 0)
	{
		//printf("read audio data: %d\n", readcnt++);
		memcpy(buf, audioBuf, audioencodesize);
		lsize = audioencodesize;
		audioencodesize = 0;
	}
	return lsize;
}

int ffmpeg_muxer_video_init()
{
	//video in
	inbuffer_v = (unsigned char*)av_malloc(VIDEO_AVIO_SIZE);
	avio_in_v = avio_alloc_context(inbuffer_v, VIDEO_AVIO_SIZE, 0, 0,
		read_video_buffer, NULL, NULL)
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值