温馨提示:本文翻译自stackoverflow.com,查看原文请点击:c - FFMPEG remux sample without writing to file
c ffmpeg

c - FFMPEG remux示例,无需写入文件

发布于 2020-04-09 10:24:54

让我们考虑一下horgh的这个非常好用的remux样本

我想完成相同的任务:将RTSP H264编码的流转换为分段的MP4流。此代码正是完成此任务。

但是我根本不想将mp4写入磁盘,但是我需要在C中获得一个字节缓冲区或包含通常写入磁盘的内容的数组。

这是如何实现的?此示例使用vs_open_output定义输出格式,并且此函数需要输出URL。

如果我不想将内容输出到磁盘,该如何修改此代码?或者也可能有更好的选择,也欢迎这些选择。

更新:

按照szatmary的建议,我检查了他的示例链接

但是,正如我在问题中所述,我需要将输出作为缓冲区而不是文件。该示例很好地演示了如何读取自定义源并将其提供给ffmpeg。

我需要的是如何以标准方式(使用avformat_open_input打开输入,然后对数据包进行自定义修改,然后写入文件,写入缓冲区。

我尝试了什么?

基于szatmary的示例,我创建了一些缓冲区和初始化:

uint8_t *buffer;
buffer = (uint8_t *)av_malloc(4096);

format_ctx = avformat_alloc_context();
format_ctx->pb = avio_alloc_context(
                buffer, 4096, // internal buffer and its size
                1,            // write flag (1=true, 0=false)
                opaque,  // user data, will be passed to our callback functions
                0,      // no read
                &IOWriteFunc,
                &IOSeekFunc
);
format_ctx->flags |= AVFMT_FLAG_CUSTOM_IO; 

AVOutputFormat * const output_format = av_guess_format("mp4", NULL, NULL);
format_ctx->oformat = output_format;

avformat_alloc_output_context2(&format_ctx, output_format,
            NULL, NULL)

然后,当然我创建了'IOWriteFunc'和'IOSeekFunc':

static int IOWriteFunc(void *opaque, uint8_t *buf, int buf_size) {
    printf("Bytes read: %d\n", buf_size);
    int len = buf_size;
    return (int)len;
}

static int64_t IOSeekFunc (void *opaque, int64_t offset, int whence) {
    switch(whence){
        case SEEK_SET:
            return 1;
            break;
        case SEEK_CUR:
            return 1;
            break;
        case SEEK_END:
            return 1;
            break;
        case AVSEEK_SIZE:
            return 4096;
            break;
        default:
           return -1;
    }
    return 1;
}

然后,我需要将标头写入输出缓冲区,并且此处的预期行为是打印“读取的字节:x”

AVDictionary * opts = NULL;
av_dict_set(&opts, "movflags", "frag_keyframe+empty_moov", 0);
av_dict_set_int(&opts, "flush_packets", 1, 0);

avformat_write_header(output->format_ctx, &opts)

在执行过程的最后一行,它总是会遇到segfault,这是回溯:

#0  0x00007ffff7a6ee30 in  () at /usr/lib/x86_64-linux-gnu/libavformat.so.57
#1  0x00007ffff7a98189 in avformat_init_output () at /usr/lib/x86_64-linux-gnu/libavformat.so.57
#2  0x00007ffff7a98ca5 in avformat_write_header () at /usr/lib/x86_64-linux-gnu/libavformat.so.57
...

该示例对我来说困难的是它使用avformat_open_input

但是,输出没有这样的东西(没有avformat_open_ouput)。

更新2:

我找到了另一个阅读示例doc / examples / avio_reading.c

提到过类似的写作示例(avio_writing.c),但是ffmpeg没有这个功能(至少在我的Google搜索中如此)。

这个任务真的很难解决吗?标准rtsp输入到自定义avio?

幸运的是ffmpeg.org已经关闭。大。

查看更多

提问者
Daniel
被浏览
101
Daniel 2020-02-01 01:03

这是一个愚蠢的错误:

在初始化部分,我将此称为:

avformat_alloc_output_context2(&format_ctx, output_format,
        NULL, NULL)

但是在此之前,我已经将avio缓冲区放入了format_ctx中:

format_ctx->pb = ...

另外,此行也是不必要的:

format_ctx = avformat_alloc_context();

正确的顺序:

AVOutputFormat * const output_format = av_guess_format("mp4", NULL, NULL);

avformat_alloc_output_context2(&format_ctx, output_format,
            NULL, NULL)

format_ctx->pb = avio_alloc_context(
                buffer, 4096, // internal buffer and its size
                1,            // write flag (1=true, 0=false)
                opaque,  // user data, will be passed to our callback functions
                0,      // no read
                &IOWriteFunc,
                &IOSeekFunc
);
format_ctx->flags |= AVFMT_FLAG_CUSTOM_IO; 
format_ctx->oformat = output_format; //might be unncessary too

Segfault现在不见了。