Bootstrap

android ffmpeg 视频采集,FFmpeg编程开发笔记 —— Android环境使用FFmpeg录制视频

今天我们来谈谈Android 环境下,使用FFmpeg录制视频的流程。

基本流程解析

使用FFmpeg录制视频的流程大体如下:

1、初始化FFmpeg

2、打开音频流、视频流

3、将PCM编码为AAC

4、将YUV编码为H264

5、写入文件

6、写入文件尾部信息

7、关闭媒体流

初始化FFmpeg

初始化FFmpeg,主要是有一下几个步骤:

1、注册所有的编码器

2、分配输出格式上下文(AVFormatContext)

3、打开视频流,并初始化视频编码器

4、打开音频流,并初始化音频编码器

5、打开视频编码器

6、打开音频编码器

7、写入文件头不信息

整个过程实现代码如下:

/**

* 初始化编码器

* @return

*/

bool CainEncoder::initEncoder() {

if (isInited) {

return true;

}

do {

AVDictionary *opt = NULL;

int ret;

av_log_set_callback(ffmpeg_log);

// 注册

av_register_all();

// 分配输出媒体上下文

avformat_alloc_output_context2(&fmt_ctx, NULL, NULL, mOutputFile);

if (fmt_ctx == NULL) {

ALOGE("fail to avformat_alloc_output_context2 for %s", mOutputFile);

break;

}

// 获取AVOutputFormat

fmt = fmt_ctx->oformat;

// 使用默认格式编码器视频流,并初始化编码器

if (fmt->video_codec != AV_CODEC_ID_NONE) {

addStream(&video_st, fmt_ctx, &video_codec, fmt->video_codec);

have_video = true;

}

// 使用默认格式编码器音频流,并初始化编码器

if (fmt->audio_codec != AV_CODEC_ID_NONE && enableAudio) {

addStream(&audio_st, fmt_ctx, &audio_codec, fmt->audio_codec);

have_audio = true;

}

if(!have_video && !have_audio) {

ALOGE("no audio or video codec found for the fmt!");

break;

}

// 打开视频编码器

if (have_video) {

openVideo(video_codec, &video_st, opt);

}

// 打开音频编码器

if (have_audio) {

openAudio(audio_codec, &audio_st, opt);

}

// 打开输出文件

ret = avio_open(&fmt_ctx->pb, mOutputFile, AVIO_FLAG_READ_WRITE);

if (ret < 0) {

ALOGE("Could not open '%s': %s", mOutputFile, av_err2str(ret));

break;

}

// 写入文件头部信息

ret = avformat_write_header(fmt_ctx, NULL);

if (ret < 0) {

ALOGE("Error occurred when opening output file: %s", av_err2str(ret));

break;

}

isInited = true;

} while (0);

// 判断是否初始化成功,如果不成功,则需要重置所有状态

if (!isInited) {

reset();

}

return isInited;

}

其中,打开媒体流的方法如下:

/**

* 添加码流

* @param ost

* @param oc

* @param codec

* @param codec_id

* @return

*/

bool CainEncoder::addStream(OutputStream *ost, AVFormatContext *oc, AVCodec **codec,

enum AVCodecID codec_id) {

AVCodecContext *context;

// 查找编码器

*codec = avcodec_find_encoder(codec_id);

if (!(*codec)) {

ALOGE("Could not find encoder for '%s'\n", avcodec_get_name(codec_id));

return false;

}

// 创建输出码流

ost->st = avformat_new_stream(oc, *codec);

if (!ost->st) {

ALOGE("Could not allocate stream\n");

return false;

}

// 绑定码流的ID

ost->st->id = oc->nb_streams - 1;

// 创建编码上下文

context = avcodec_alloc_context3(*codec);

if (!context) {

ALOGE("Could not alloc an encoding context\n");

return false;

}

// 绑定编码上下文

ost->enc = context;

// 判断编码器的类型

switch ((*codec)->type) {

// 如果创建的是音频码流,则设置音频编码器的参数

case AVMEDIA_TYPE_AUDIO:

context->sample_fmt = (*codec)->sample_fmts

? (AVSampleFormat) (*codec)->sample_fmts[0]

: AV_SAMPLE_FMT_S16;

context->bit_rate = mAudioBitRate;

context->

;