通过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)