MediaCodec 编码结合 FFmpeg 封装流
音视频开发进阶
共 3077字,需浏览 7分钟
· 2022-05-22
在 Android 平台上合成视频一般使用 MediaCodec 进行硬编码,使用 MediaMuxer 进行封装,但是因为 MediaMuxer 在某些机型上合成的视频在其他手机上播放会出现问题,而且只支持一个音频轨道,因此可以选用 FFmpeg 来封装编码后的音视频流。
具体流程如下:
1. 创建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);
2. 添加音视频流
这里以添加 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;
3. 设置视频流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;
4. 写入视频文件头信息,放在文件开头位置
AVDictionary*dict=nullptr;
av_dict_set(&dict, "movflags", "faststart", 0);
intret=avformat_write_header(ofmt_ctx, &dict);
5. 写入视频流和音频流已编码数据
同样以写入视频流数据为例,⚠️注意视频流和音频流在不同线程写入时需要同步
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);
6. 结束并关闭文件
av_write_trailer(ofmt_ctx);
avio_closep(&ofmt_ctx->pb);
avformat_free_context(ofmt_ctx);
至此,整个流程就结束了。
作者:VE 视频引擎
来源:https://segmentfault.com/a/1190000039402914
更多内容可以在星球菜单中找到,随着时间推移,干货也会越来越多!!!
给出 10元 优惠券,涨价在即,目前还是白菜价,基本上提几个问题就回本,投资自己就是最好的投资!!!
加我微信 ezglumes ,拉你进技术交流群
推荐阅读:
觉得不错,点个在看呗~
评论
3人运营,不用投流,年翻十倍...这些头部商家如何在得物获得确定性新增长
是新朋友吗?记得先点蓝字关注我哦~这场硬仗一定要打,也一定要打赢。文/靳舒乔珠宝品牌周大生2022年一季报数据显示,2021年周大生营收91.55亿元,门店突破4500家,遂加快线上渠道布局。一次跟得物官方交流,感觉这款App上的年轻人非常活跃,很契合线上发展需求。那时,得物App更名一年有余,正打
调皮电商
2
免费AI编程助手,支持Visual Studio,让编码愉悦又轻松
前言前有Copilot各种酷炫操作,今有国产软件杀出重围。给大家介绍的是一款国内的国产编程神器,可与微软GitHub Copilot比比身手。关键它还是完全免费。它就是:非十团队国产自主研发的Fitten Code。此工具的速度是GitHub Copilot的两倍,同时它的精确度还有大约2
dotNET全栈开发
10
熊猫饭圈中,谁是最大的顶流?
大数据文摘授权转载自湃客工坊4 月 3 日,中国的旅韩大熊猫“福宝”就将从韩国回到四川省中国大熊猫保护研究中心卧龙神树坪基地。一个月前,福宝在韩国爱宝乐园的最后一个公众展出日,数千名韩国民众专门前去送别。“福宝”的最新摄影集《福宝,我永远爱你》今年出版后在韩热销,刚发售便冲上畅销书榜第三。有读者在韩
大数据文摘
0
基于 ffmpeg + Webassembly 实现前端视频帧提取
大厂技术 高级前端 Node进阶点击上方 程序员成长指北,关注公众号回复1,加入高级Node交流群作者:jordiwang https://juejin.im/post/6854573219454844935现有的前端视频帧提取主要是
程序员成长指北
871
Python-Docx:Word与Python的完美结合
今天给大家分享Python处理Word的第三方库:Python-Docx。什么是Python-Docx?Python-Docx是用于创建和更新Microsoft Word(.docx)文件的Python库。日常需要经常处理Word文档,用Python的免费第三方包:Python-Docx处理docx
机器学习算法与Python实战
10
记录一次有挑战的经历:使用xgplayer拉流端直播
一、背景介绍为了强化官方验的心智,平台要做一版新的质检直播间,将我们的质检车间全方位透明的展现给用户。按照产品的设计来实现的话,其实就是将各个镜头的内容同时在一个页面内进行播放,除了工作时间的直播,还有休息时间的录播播放。不过直播和录播的生成都是在后端实现,前端只负责视频资源的播放。二、前期调研对于
前端迷
10
Vue3 开发秘籍,封装一个超级好用的 Hook
关注我,回复“加群”加入我们一起学习,天天进步Vue3 的 Composition API 为我们提供了另一种代码组织方式,这个概念借鉴自 React 的 Hook。在 16.8 的版本中,React 引入了 React Hook,通过封装有状态的函数,提高了组件的编写效率和可维护性,在后面统一使用
高级前端进阶
10
抖音自主投流广告模板大揭秘。
如果你是一个从事信息流投放或短视频素材编导的同学,希望这篇文章能给你些许启发。很多刚刚从事短视频信息流投手的同学,都会将信息流效果广告的作用过度放大。甚至很多新生品牌主理人、新手品牌负责人也一样。将信...
木木老贼
0