通过CustomIO实现ffmpeg内存输入
来源:互联网 发布:淘宝返利网站有哪些 编辑:程序博客网 时间:2024/05/22 04:24
Introduction
In this short Article I will explain how to use a custom IO-Context with FFmpeg. Although I used an IStream Object the code can be used for other Streams like std::istream
.
FFmpeg can only read from files or named pipes easily, but if you want to read directly from memory, from sockets or IStreams you have to provide a custom IO-Context. I could not find any resource in the internet which offeres a complete and working solution with the current version of FFmpeg explaining how to deal correctly with an IO-Context. After some hours of experimentation I finally managed to get this working without getting access-violations in FFmpeg functions.
Creating the IO-Context
FFmpeg uses a custom IO-Context, when you allocate the AVFormatContext
-structure yourself and provide your own version of AVIOContext
but there are several other things to consider. At first we will create the AVIOContext and the AVFormatContext
structures. The size of the internal buffer is up to you, I decided to provide 32kb for internal buffering. The two functions ReadFunc
and SeekFunc
are shown later.
typedef struct CustomStream {
uint64_t pos_cur;
uint64_t length;
uint8_t *buf;
} CustomStream;
// CustomStream-Interface that was already created elsewhere:CustomStream* pInStream; // Create internal Buffer for FFmpeg:const int iBufSize = 32 * 1024;BYTE* pBuffer = new BYTE[iBufSize]; // Allocate the AVIOContext:// The fourth parameter (pStream) is a user parameter which will be passed to our callback functionsAVIOContext* pIOCtx = avio_alloc_context(pBuffer, iBufSize, // internal Buffer and its size 0, // bWriteable (1=true,0=false) pInStream, // user data ; will be passed to our callback functions ReadFunc, 0, // Write callback function (not used in this example) SeekFunc); // Allocate the AVFormatContext:AVFormatContext* pCtx = avformat_alloc_context(); // Set the IOContext:pCtx->pb = pIOCtx;
Note: As you can see, the custom IO-Context can also be used for writing, but this is not explained here.
Now you have to tell FFmpeg, which input format it has to use. For a custom IO-Context this is necessary! FFmpeg will otherwise read about 5Mb data from the stream by default to determine the input format. By doing this, FFmpeg will crash because of a buffer overrun. I have not tested whether it will work, if the internal buffer is large enough to hold the 5Mb data because it was easier for me to determine the input format on my own.
// Determining the input format:ULONG ulReadBytes = 0;if(FAILED(pInStream->Read(pBuffer, iBufSize, &ulReadBytes))) // Error Handling...// Don't forget to reset the data pointer back to the beginning!if(FAILED(pInStream->Seek(0, SEEK_SET))) // Error Handling...// Now we set the ProbeData-structure for av_probe_input_format:AVProbeData probeData;probeData.buf = pBuffer;probeData.buf_size = ulReadBytes;probeData.filename = ""; // Determine the input-format:pCtx->iformat = av_probe_input_format(&probeData, 1);
The last thing to do is to set the flags of the AVFormatContext
. This is not directly mentioned in the documentation and although FFmpeg realizes that you have set your own AVIOContext
you have to set the AVFMT_FLAG_CUSTOM_IO
-flag on your own.
pCtx->flags = AVFMT_FLAG_CUSTOM_IO;
Now we use the avformat_open_input function to tell FFmpeg that it can start to read from the stream.
if(avformat_open_input(&pCtx, "", 0, 0)) != 0) // Error Handling
The second parameter of avformat_open_input is the filename. This is not used, because we want to use the custom IO-Context. Older versions of FFmpeg will crash if you pass 0 as filename instead of "". This issue was fixed in newer versions of FFmpeg.
The callback functions ReadFunc
and SeekFunc
are easily implemented:
int ReadFunc(void* ptr, uint8_t* buf, int buf_size){
CustomStream* pStream = (CustomStream *)ptr;
if (pStream->pos_cur >= pStream->length) {
return 0;
}
int readBytes = buf_size;
if (pStream->pos_cur + buf_size > pStream->length) {
readBytes = pStream->length - pStream->pos_cur;
}
memcpy(buf, pStream->buf + pStream->pos_cur, readBytes);
pStream->pos_cur += readBytes;
return readBytes;
}// whence: SEEK_SET, SEEK_CUR, SEEK_END (like fseek) and AVSEEK_SIZEint64_t SeekFunc(void* ptr, int64_t pos, int whence){ // Quelle Abfragen: CustomStream* pStream = reinterpret_cast<IStream*>(ptr); // Seek: LARGE_INTEGER in = { pos }; ULARGE_INTEGER out = { 0 }; if(FAILED(pStream->Seek(in, whence, &out))) return -1; // Return the new position: return out.QuadPart;}
The whence-parameter has one more option than fseek: AVSEEK_SIZE
. When this option is passed to the seek function it should return the file size (if possible). If its not possible, the function may return and do nothing -1. In my implementation pStream->Seek(...)
will fail with AVSEEK_SIZE
and SeekFunc
will return -1.
Freeing resources
One last comment on which functions are to use to release all the allocated resources:
avformat_close_input(pCtx); // AVFormatContext is released by avformat_close_inputav_free(pIOCtx); // AVIOContext is released by av_freedelete[] pBuffer;
- 通过CustomIO实现ffmpeg内存输入
- ffmpeg输入rtmp时存在内存泄露
- FFMPEG中的两输入Filter实现(一)
- FFMPEG中的两输入Filter实现(二)
- 通过消息实现自定义输入框(InputBox)
- 通过expect实现scp密码自动输入
- 通过Js实现输入框数字校验
- 通过EASYUI的combogrid实现联想输入
- 通过layer实现可输入的模态框
- Java通过while循环实现输入异常重新输入功能
- 通过windows + MinGW + MSYS编译ffmpeg实现文件播放
- nodejs 通过ffmpeg,实现微信jsapi上传mp3录音
- 通过内存映射实现进程间通信
- ffmpeg---输入命令分组
- Android实现Filterable通过输入文本框实现联系人自动筛选
- Android实现Filterable通过输入文本框实现联系人自动筛选
- Android实现Filterable通过输入文本框实现联系人自动筛选
- Android实现Filterable通过输入文本框实现联系人自动筛选
- 欢迎使用CSDN-markdown编辑器
- c# 键盘控制事件
- Xcode8快捷键
- Java代码简洁之道
- mac重装系统后,将原来的的ssh复制进去,无法登录服务器
- 通过CustomIO实现ffmpeg内存输入
- Python笔记-几种取整方式
- 一个附言字段需求的总结
- java项目在eclipse中相关文件说明
- 摆渡是什么意思
- c# 传参数
- Linux下SVN常用命令
- 详解React Native动画
- 如何将自己的图片,放到云存储免费调用…………