当前位置: 首页 > news >正文

FFmpeg 内存输入输出

[[N_FFmpeg]]

实例 内存输入/输出

ffmpeg内存编解码

内存输入

关键点就两个:

  1. 初始化AVIOContext时, 指定自定义的回调函数指针
//AVIOContext中的缓存
unsigned char* _iobuffer = (unsigned char*)av_malloc(40690);// 注意缓存容器要足够大
AVIOContext* avio = avio_alloc_context(_iobuffer , 40690 , 0 , this, fill_buffer,nullptr,nullptr);
assert( avio != NULL);
pFormatCtx->pb = avio;//给AVFormatContext
if(avformat_open_input(&pFormatCtx,NULL,NULL,NULL)!=0){printf("Couldn't open inputstream.(无法打开输入流)\n");return -1;
}
  1. 回调函数
///注意缓存 容器 要足够大
int fill_buffer(void * opaque,uint8_t *buf, int bufsize){SDKSource2Player *instance = static_cast<SDKSource2Player*>( opaque);callback_data * data =  instance->source2->takeDataPacketSync();memcpy( buf, data->data, data->size);//复制到容器 给 ffmpegint size =  data->size;SDKSource2::destoryDataPacket(data);//销毁return size;}

内存输出

  1. 回调函数
//内存输出数据
int fill_buffer_out(void * opaque, uint8_t *buf, int bufsize){WebSocketPlayer *instance = static_cast<WebSocketPlayer*>( opaque);instance->onAVPacketOutData(buf,bufsize );return bufsize;
}
  1. 分配
// 内存输出
unsigned char* out_buffer = (unsigned char*)av_malloc(40690);//~40k
AVIOContext* out_avio = avio_alloc_context(out_buffer , 40690 , 1 , this, nullptr,nullptr,nullptr);
assert( out_avio != NULL);
AVOutputFormat *oformat = av_guess_format("mp4", nullptr, nullptr);
ret = avformat_alloc_output_context2(&outAvFormatCtx,oformat,nullptr,nullptr);
outAvFormatCtx->pb = out_avio;
outAvFormatCtx->flags = AVFMT_FLAG_CUSTOM_IO;
  1. 踩坑指南
  • 内存输出的时候需要注意 avio_alloc_context 的第三个参数 write_flag=1 表示 可写
  • 输出 AVFormatContext 的flag 需要标记为 AVFMT_FLAG_CUSTOM_IO
...
outAvFormatCtx->pb = out_avio;
outAvFormatCtx->flags = AVFMT_FLAG_CUSTOM_IO;
...
  • 打开输出avio_open的时候, 第二参数不能是 NULL, 即使没有什么意义; ~~貌似自定义输出,不调用也可以 (实测) ~~
avio_open(&outAvFormatCtx->pb, "nothing",AVIO_FLAG_WRITE) ;
if (!outAvFormatCtx->pb ) {qDebug()<<"错误: format->pd is NULL";throw ("Error open ouput fail ");
}

NDK的一个实例


// ============================
//      自定义 AVIO 输出
// ============================struct AVIOCtxWrapper {JNIEnv *env;jobject wsServer;jmethodID broadcastFrame;
};
// 将 FFmpeg 封装输出的数据通过 WebSocket 发出
static int write_packet(void *opaque, uint8_t *buf, int buf_size) {auto *wrapper = (AVIOCtxWrapper *)opaque;if (!wrapper || !wrapper->env || !wrapper->wsServer) return 0;jbyteArray arr = wrapper->env->NewByteArray(buf_size);if (!arr) return 0;wrapper->env->SetByteArrayRegion(arr, 0, buf_size, reinterpret_cast<const jbyte*>(buf));wrapper->env->CallVoidMethod(wrapper->wsServer, wrapper->broadcastFrame, arr);wrapper->env->DeleteLocalRef(arr);return buf_size;
}................// --- 创建输出 fMP4 ---if (avformat_alloc_output_context2(&out_fmt, nullptr, "mp4", nullptr) < 0) {LOGE("Failed to alloc output context");cleanup();return;}out_fmt->flags = AVFMT_FLAG_CUSTOM_IO;// 注意:write_packet 期望 wrapper 中持有一个有效的 JNIEnv 与 wsServer/global refAVIOCtxWrapper wrapper;wrapper.env = env;wrapper.wsServer = ctx->wsServer;wrapper.broadcastFrame = broadcastFrame;avio = avio_alloc_context(avioBuffer, 8192, 1, &wrapper,nullptr,reinterpret_cast<int (*)(void *, const uint8_t *, int)>(write_packet),nullptr);if (!avio) {LOGE("avio_alloc_context failed");cleanup();return;}out_fmt->pb = avio;

AVFormatContext 的pd 属性

AVFormatContext 有个 pd 属性指针, 读写数据都是通过它

/*** I/O context.** - demuxing: either set by the user before avformat_open_input() (then*             the user must close it manually) or set by avformat_open_input().* - muxing: set by the user before avformat_write_header(). The caller must*           take care of closing / freeing the IO context.** Do NOT set this field if AVFMT_NOFILE flag is set in* iformat/oformat.flags. In such a case, the (de)muxer will handle* I/O in some other way and this field will be NULL.*/
AVIOContext *pb;

avio_alloc_context

/*** Allocate and initialize an AVIOContext for buffered I/O. It must be later* freed with avio_context_free().** @param buffer Memory block for input/output operations via AVIOContext.*        The buffer must be allocated with av_malloc() and friends.*        It may be freed and replaced with a new buffer by libavformat.*        AVIOContext.buffer holds the buffer currently in use,*        which must be later freed with av_free(). (输入输出的'操作容器',必须使用av_malloc()和friends来分配,av_free()释放, AVIOContext.buffer属性保存当前正在使用的)* @param buffer_size The buffer size is very important for performance.*        For protocols with fixed blocksize it should be set to this blocksize.*        For others a typical size is a cache page, e.g. 4kb.['操作容器' 的大小]* @param write_flag Set to 1 if the buffer should be writable, 0 otherwise.(如果 '操作容器' 可以写设置为1, 否则设置为0] 简而言之是否可写 /注意是个小坑)* @param opaque An opaque pointer to user-specific data.[用户数据指针, 回调用]* @param read_packet  A function for refilling the buffer, may be NULL.*                     For stream protocols, must never return 0 but rather*                     a proper AVERROR code. [读的 回调函数指针]* @param write_packet A function for writing the buffer contents, may be NULL.*        The function may not change the input buffers content.[写的 回调函数指针]* @param seek A function for seeking to specified byte position, may be NULL.** @return Allocated AVIOContext or NULL on failure.*/
AVIOContext *avio_alloc_context(unsigned char *buffer,int buffer_size,int write_flag,void *opaque,int (*read_packet)(void *opaque, uint8_t *buf, int buf_size),int (*write_packet)(void *opaque, uint8_t *buf, int buf_size),int64_t (*seek)(void *opaque, int64_t offset, int whence));

可参考官方API 关于 avformat_open_input的文档:

If you want to use custom IO, preallocate the format context and set its pb field.

int avformat_open_input	(	AVFormatContext** 	ps,
const char * 	url,
AVInputFormat * 	fmt,
AVDictionary** 	options 
)

雷神的博客 - https://blog.csdn.net/leixiaohua1020/article/details/39759163

http://www.jsqmd.com/news/118424/

相关文章:

  • 15、Windows系统文件备份与恢复全攻略
  • Excalidraw OCR文字提取功能设想
  • 10 个降AI率工具,自考学生必备神器!
  • Excalidraw冲突解决机制解析
  • 275. Java Stream API - flatMap 操作:展开一对多的关系,拉平你的流!
  • 2025年rohs检测仪优质供应商推荐,rohs检测仪专业制造商靠谱厂家全解析 - mypinpai
  • Excalidraw反向代理配置(Nginx/Apache)
  • Excalidraw字体渲染机制详解:保持手绘风格一致性
  • 2025年12月制造业咨询公司选购终极指南:附五大领先机构全景对比与推荐 - 十大品牌推荐
  • 【无代码AI时代来临】:Open-AutoGLM让你7天掌握智能流程构建
  • 4、文档编辑与图像处理实用指南
  • 2025年可靠的实验室球磨机公司、卧式行星球磨机工厂年度排名 - myqiye
  • 响应速度提升10倍的秘密武器,Open-AutoGLM用户都在问的优化方案,你还没用?
  • 多巴胺:驱动人类的分子,现代生活的陷阱与救赎
  • Excalidraw高可用架构设计方案
  • 彩色无纺布服务商哪家性价比高?哪家质量靠谱? - mypinpai
  • 深入解析:【每天一个AI小知识】:什么是卷积神经网络?
  • 5、图像打印、幻灯片制作与媒体播放指南
  • 2025年12月制造业咨询公司怎么选?五大实力派机构全方位对比与推荐 - 十大品牌推荐
  • 机器学习模型评估指标:R²分数与均方误差(MSE)详解
  • 企业管理咨询公司哪家强?2025年12月最新市场盘点与十大实力机构推荐 - 十大品牌推荐
  • 6、电脑文件操作与媒体播放全攻略
  • Excalidraw与Google Drive同步集成方法
  • Open-AutoGLM脚本库深度解析(99%工程师忽略的性能优化技巧)
  • 2025年资深环保工程师推荐:当前最值得关注的5家无害化设备厂家全方位横评。 - 十大品牌推荐
  • Open-AutoGLM你不知道的隐藏功能:高精度错误分类模型一键部署方案
  • XBOX精英二代霍尔板机故障修复及校准
  • 冬至是农历年计算的基点
  • 8、Windows Vista 使用指南:用户管理、共享设置与笔记本功能
  • 9、笔记本电脑使用与网络连接全攻略