I'm seeing slow I/O performance in libav while muxing mp4 files.
some analysis show that file_write() function in libavformat/file.c
receives lots of calls with small writes. this is bad for i/o performance.

changing the implementation of file.c to use fopen/fwrite increased
performance considerably.

the question is, why is libav using unbuffered I/O, and does moving to
fopen make sense?

see my modified version below



/* standard file protocol */

static int ufile_open(URLContext *h, const char *filename, int flags)
{
const char* access = NULL;
FILE* fd = NULL;

    if (flags & AVIO_FLAG_WRITE && flags & AVIO_FLAG_READ) {
        access = L"wb+";
    } else if (flags & AVIO_FLAG_WRITE) {
        access = L"wb";
    } else {
        access = L"r";
    }

fd = fopen(filename, access);
h->priv_data = (void *)fd;
if (fd == 0) {
const int err = AVERROR(ENOENT);
assert (err < 0);
return err;
}
return 0;
}

static int ufile_read(URLContext *h, unsigned char *buf, int size)
{
FILE* fd = (FILE*)h->priv_data;
int nBytes = fread(buf, 1, size, fd);
return nBytes;
}

static int ufile_write(URLContext *h, const unsigned char *buf, int size)
{
FILE* fd = (FILE*)h->priv_data;
int nBytes = fwrite(buf, 1, size, fd);
return nBytes;
}

#if LIBAVFORMAT_VERSION_MAJOR >= 52
static int64_t ufile_seek(URLContext *h, int64_t pos, int whence)
#else
static offset_t ufile_seek(URLContext *h, offset_t pos, int whence)
#endif
{
assert(whence == SEEK_SET || whence == SEEK_CUR || whence == SEEK_END ||
whence == AVSEEK_SIZE);
FILE* fd = (FILE*)h->priv_data;
if(whence == AVSEEK_SIZE) {
struct __stat64 buf;
if(_fstat64(_fileno(fd), &buf) != 0)
return AVERROR(errno);

return buf.st_size;
}

const __int64 nBytes = _fseeki64(fd, pos, whence);
return nBytes;
}

static int ufile_close(URLContext *h)
{
FILE* fd = (FILE*)h->priv_data;
if(fd != 0) {
return fclose(fd);
}

return 0;
}


#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53, 0, 0)
static int ufile_get_handle(URLContext *h)
{
    return (intptr_t) h->priv_data;
}

static int ufile_check(URLContext *h, int mask)
{
    struct stat st;
    int ret = stat(h->filename, &st);
    if (ret < 0)
        return AVERROR(errno);

#if defined(_MSC_VER) && !defined(S_IRUSR)
# define S_IRUSR _S_IREAD
#endif

#if defined(_MSC_VER) && !defined(S_IWUSR)
# define S_IWUSR _S_IWRITE
#endif

    ret |= st.st_mode&S_IRUSR ? mask&AVIO_FLAG_READ  : 0;
    ret |= st.st_mode&S_IWUSR ? mask&AVIO_FLAG_WRITE : 0;

    return ret;
}

#endif


URLProtocol rayv::media::ufile_protocol = {
"ufile",
ufile_open,
ufile_read,
ufile_write,
ufile_seek,
ufile_close,
#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53, 0, 0)
/* next           = */ NULL,
/* url_read_pause = */ NULL,
/* url_read_seek  = */ NULL,
    ufile_get_handle,
    /* priv_data_size = */ NULL,
/* priv_data_class= */ NULL,
    /* flags          = */ NULL,
    ufile_check,
#endif
};

-- 
Aviad Rozenhek
_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to