FFmpeg解码内存中的二进制视频

背景

要求使用FFmpeg解码一个已经读入内存的视频,视频在内存中已二进制数据的形式保存。适用FFmpeg版本4.x

思路

常规的FFmpeg解码视频的方式如图所示(盗的图)
在这里插入图片描述
其中avformat_open_input接口中完成数据流输入的工作,其定义如下:

/**
 * Open an input stream and read the header. The codecs are not opened.
 * The stream must be closed with avformat_close_input().
 *
 * @param ps Pointer to user-supplied AVFormatContext (allocated by avformat_alloc_context).
 *           May be a pointer to NULL, in which case an AVFormatContext is allocated by this
 *           function and written into ps.
 *           Note that a user-supplied AVFormatContext will be freed on failure.
 * @param url URL of the stream to open.
 * @param fmt If non-NULL, this parameter forces a specific input format.
 *            Otherwise the format is autodetected.
 * @param options  A dictionary filled with AVFormatContext and demuxer-private options.
 *                 On return this parameter will be destroyed and replaced with a dict containing
 *                 options that were not found. May be NULL.
 *
 * @return 0 on success, a negative AVERROR on failure.
 *
 * @note 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);

常规情况下,可以直接将视频的url作为参数直接传入。但是本问题中,视频已经已二进制的形式在内存中了,没有url可以传入。那么我们就要从AVFormatContext **ps 结构入手。

AVFormatContext中保存数据流上下文信息,是最主要数据结构,其中AVIOContext结构用于控制输入数据,可以考虑通过这个结构,把二进制数据作为输出。

typedef struct AVFormatContext {
...

    /**
     * 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;

...
}

进一步观察avformat_open_input函数的源码,发现台调用了一个init_input来初始化输入流

static int init_input(AVFormatContext *s, const char *filename,
                      AVDictionary **options) 
{
    int ret;
    AVProbeData pd = { filename, NULL, 0 };
    int score = AVPROBE_SCORE_RETRY;
 
    if (s->pb) {
        s->flags |= AVFMT_FLAG_CUSTOM_IO;
        if (!s->iformat)
            return av_probe_input_buffer2(s->pb, &s->iformat, filename,
                                          s, 0, s->format_probesize);
        else if (s->iformat->flags & AVFMT_NOFILE)
            av_log(s, AV_LOG_WARNING, "Custom AVIOContext makes no sense and "
                                      "will be ignored with AVFMT_NOFILE format.\n");
        return 0;
    }
 
    if ((s->iformat && s->iformat->flags & AVFMT_NOFILE) ||
        (!s->iformat && (s->iformat = av_probe_input_format2(&pd, 0, &score))))
        return score;
 
    if ((ret = s->io_open(s, &s->pb, filename, AVIO_FLAG_READ | s->avio_flags, options)) < 0)
        return ret;
 
    if (s->iformat)
        return 0;
    return av_probe_input_buffer2(s->pb, &s->iformat, filename,
                                  s, 0, s->format_probesize);
}

函数中对pb字段进行了判断(第7行),如果该结构在之前已经初始化过了,那么就直接返回结果,不会执行到从文件url读数据的代码(第19行)

那么我们需要做的就是在avformat_open_input调用之前,创建一个AVIOContext结构,并将其赋值给AVFormatContext 的pd字段。

翻翻文档找到初始化AVIOContext的方法

AVIOContext* avio_alloc_context(unsigned char * buffer,
                                int buffer_size,
                                int write_flag,
                                void * opaque,
                                int(*)(void *opaque, uint8_t *buf, int buf_size) read_packet,
                                int(*)(void *opaque, uint8_t *buf, int buf_size) write_packet,
                                int64_t(*)(void *opaque, int64_t offset, int whence) seek 
                                )

如此一来,只需将二进制数据直接传入,并且定义好自己所需的读写函数即可。

问题解决

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值