MediaCodec编码结合FFmpeg封装流
Posted VE视频引擎
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MediaCodec编码结合FFmpeg封装流相关的知识,希望对你有一定的参考价值。
在android平台上合成视频一般使用MediaCodec进行硬编码,使用MediaMuxer进行封装,但是因为MediaMuxer在某些机型上合成的视频在其他手机上播放会出现问题,而且只支持一个音频轨道,因此可以选用FFmpeg来封装编码后的音视频流。
创建FFmpeg AVFormatContext
AVFormatContext*ofmt_ctx=nullptr;
intret=avformat_alloc_output_context2(&ofmt_ctx, nullptr, "mp4", filePath);
AVOutputFormat*ofmt=ofmt_ctx->oformat;
ret=avio_open(&ofmt_ctx->pb, filePath, AVIO_FLAG_WRITE);
添加音视频流
这里以添加h264视频流为例
AVStream*stream=avformat_new_stream(ofmt_ctx, nullptr);
intvideo_stream=stream->index;
AVCodecParameters*codecpar=stream->codecpar;
codecpar->codec_type=AVMEDIA_TYPE_VIDEO;
codecpar->codec_id=AV_CODEC_ID_H264;
codecpar->width=width;
codecpar->height=height;
设置视频流sps和pps
sps和pps能在MediaCodec产生第一帧画面之前获取到,以java MediaCodec异步编码方式为例
// java接口获取sps和pps数据
@Override
publicvoidonOutputBufferAvailable(@NonNullMediaCodeccodec, intindex, @NonNullMediaCodec.BufferInfoinfo) {
ByteBufferbuffer=encoder.getOutputBuffer(index);
if ((info.flags&MediaCodec.BUFFER_FLAG_CODEC_CONFIG) !=0) {
// 传递 buffer和info.size到native
}
// ...
}
// native获取sps和pps数据地址
uint8_t*data=static_cast<uint8_t*>(env->GetDirectBufferAddress(buffer));
// 复制给视频流extradata
AVCodecParameters*codecpar=ofmt_ctx->streams[video_stream]->codecpar;
codecpar->extradata= (uint8_t*) av_mallocz(size+AV_INPUT_BUFFER_PADDING_SIZE);
memcpy(codecpar->extradata, data, size);
codecpar->extradata_size=size;
写入视频文件头信息,放在文件开头位置
AVDictionary*dict=nullptr;
av_dict_set(&dict, "movflags", "faststart", 0);
intret=avformat_write_header(ofmt_ctx, &dict);
写入视频流和音频流已编码数据
同样以写入视频流数据为例,⚠️注意视频流和音频流在不同线程写入时需要同步
// onOutputBufferAvailable回调中
booleanisKeyFrame= (info.flags&MediaCodec.BUFFER_FLAG_KEY_FRAME) !=0;
// 传递buffer, info.size, isKeyFrame, info.presentationTimeUs到native
// 获取视频编码数据地址
uint8_t *data = static_cast<uint8_t *>(env->GetDirectBufferAddress(buffer));
AVPacket *packet = av_packet_alloc();
av_init_packet(packet);
packet->stream_index = video_stream;
packet->data = data;
packet->size = size;
packet->pts = av_rescale_q(pts, { 1, 1000000 }, ofmt_ctx->streams[video_stream]->time_base);
if (isKeyFrame) packet->flags |= AV_PKT_FLAG_KEY;
int ret = av_interleaved_write_frame(ofmt_ctx, packet);
av_packet_unref(packet);
av_packet_free(&packet);
结束并关闭文件
至此,整个流程就结束了
av_write_trailer(ofmt_ctx);
avio_closep(&ofmt_ctx->pb);
avformat_free_context(ofmt_ctx);
本文由博客群发一文多发等运营工具平台 OpenWrite 发布
以上是关于MediaCodec编码结合FFmpeg封装流的主要内容,如果未能解决你的问题,请参考以下文章
研究Android音视频-3-在Android设备上采集音视频并使用MediaCodec编码为H.264
研究Android音视频-3-在Android设备上采集音视频并使用MediaCodec编码为H.264
研究Android音视频-3-在Android设备上采集音视频并使用MediaCodec编码为H.264
ffmpeg视频编解码 demo初探(包含下载指定windows版本ffmpeg)将YUV图片序列作为流读入,编码封装成x264 MP4视频
ffmpeg视频编解码 demo初探(包含下载指定windows版本ffmpeg)将YUV图片序列作为流读入,编码封装成x264 MP4视频