Skip to content

Instantly share code, notes, and snippets.

Last active June 24, 2022 18:12
Show Gist options
  • Save xlphs/9895065 to your computer and use it in GitHub Desktop.
Save xlphs/9895065 to your computer and use it in GitHub Desktop.
#include <cstdio>
#include <string>
class MyIOContext {
std::string datafile;
AVIOContext *ioCtx;
uint8_t *buffer; // internal buffer for ffmpeg
int bufferSize;
FILE *fh;
MyIOContext(const std::string &datafile);
void initAVFormatContext(AVFormatContext *);
static int IOReadFunc(void *data, uint8_t *buf, int buf_size) {
MyIOContext *hctx = (MyIOContext*)data;
size_t len = fread(buf, 1, buf_size, hctx->fh);
if (len == 0) {
// Let FFmpeg know that we have reached EOF, or do something else
return (int)len;
// whence: SEEK_SET, SEEK_CUR, SEEK_END (like fseek) and AVSEEK_SIZE
static int64_t IOSeekFunc(void *data, int64_t pos, int whence) {
if (whence == AVSEEK_SIZE) {
// return the file size if you wish to
MyIOContext *hctx = (MyIOContext*)data;
int rs = fseek(hctx->fh, (long)pos, whence);
if (rs != 0) {
return -1;
long fpos = ftell(hctx->fh); // int64_t is usually long long
return (int64_t)fpos;
MyIOContext::MyIOContext(const std::string &s) {
// allocate buffer
bufferSize = 4096;
buffer = (uint8_t *)av_malloc(bufferSize); // see destructor for details
// open file
fh = fopen(datafile.c_str(), "rb");
if (!fh) {
fprintf(stderr, "MyIOContext: failed to open file %s\n",
// allocate the AVIOContext
ioCtx = avio_alloc_context(
buffer, bufferSize, // internal buffer and its size
0, // write flag (1=true, 0=false)
(void*)this, // user data, will be passed to our callback functions
0, // no writing
MyIOContext::~MyIOContext() {
if (fh) fclose(fh);
void MyIOContext::initAVFormatContext(AVFormatContext *pCtx) {
pCtx->pb = ioCtx;
pCtx->flags |= AVFMT_FLAG_CUSTOM_IO;
// you can specify a format directly
//pCtx->iformat = av_find_input_format("h264");
// or read some of the file and let ffmpeg do the guessing
size_t len = fread(buffer, 1, bufferSize, fh);
if (len == 0) return;
fseek(fh, 0, SEEK_SET); // reset to beginning of file
AVProbeData probeData;
probeData.buf = buffer;
probeData.buf_size = bufferSize - 1;
probeData.filename = "";
pCtx->iformat = av_probe_input_format(&probeData, 1);
Copy link

JanKrcek-zz commented Feb 12, 2021

Hello Marika, great job with this sample. Saved me a lot of time figuring out the interface for the callback functions.

If I may suggest an improvement, consider following changes:
line 49:

buffer = (uint8_t *)av_malloc(bufferSize + AVPROBE_PADDING_SIZE); // see destructor for details

line 90:

probeData.buf_size = bufferSize;
probeData.mime_type = "";

Setting the padding to 1 instead of the defined value in the library can cause invalid read outside of the buffer, which leads to segfault.
And apparently not setting the mime_type can cause trouble as well. Empty string should work fine, as avformat tries to match it against its known types, before using it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment