ffmpeg(2) 关于AVFMT_NOFILE

本文深入探讨了FFmpeg中的AVFMT_NOFILE旗标的作用及其应用场景,特别是对于那些不通过标准文件I/O操作的特殊设备。文章还详细介绍了与该旗标相关的AVIOContext和AVIOInterruptCB的使用细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转自:http://blog.csdn.net/xiruanliuwei/article/details/20325467


在学习ffmpeg源码时,常常看到一个Flag:AVFMT_NOFILE,这个Flag非常重要,其在avformat.h中定义:#define AVFMT_NOFILE        0x0001

在整个工程中搜索AVFMT_NOFILE,能够看到ff_alsa_demuxer、ff_bktr_demuxer、ff_dshow_demuxer、ff_dv1394_demuxer、ff_fbdev_demuxer、ff_image2_demuxer等部分

AVInputFormat类型的变量,其结构体成员flags的值被设置为AVFMT_NOFILE,当然,不是只有AVInputFormat类型的变量,部分AVOutputFormat类型的变量,其结构体成员

flags的值也被设置为AVFMT_NOFILE,查看AVFMT_NOFILE的搜索结果,对其稍微详细的解释在avdevice.h中:

/**
 * @defgroup lavd Special devices muxing/demuxing library
 * @{
 * Libavdevice is a complementary library to @ref libavf "libavformat". It
 * provides various "special" platform-specific muxers and demuxers, e.g. for
 * grabbing devices, audio capture and playback etc. As a consequence, the
 * (de)muxers in libavdevice are of the AVFMT_NOFILE type (they use their own
 * I/O functions). The filename passed to avformat_open_input() often does not
 * refer to an actually existing file, but has some special device-specific
 * meaning - e.g. for x11grab it is the display name.
 *
 * To use libavdevice, simply call avdevice_register_all() to register all
 * compiled muxers and demuxers. They all use standard libavformat API.
 * @}
 */

libavdevice目录中的内容是libavformat目录中内容的补充,libavdevice提供的是各种特殊平台专用的muxers和demuxers,例如grabbing devices、audio capture、playback等,

因此,libavdevice中的muxers和demuxers,都是AVFMT_NOFILE类型的,这些muxers和demuxers都使用它们自己的I/O函数,传递给avformat_open_input()函数的函数filename,

通常不是指一个实际存在的文件,而是根据特定的设备确定,例如,x11grab,就是display name?显示器名字?


在AVFormatContext结构体中:

    /**
     * I/O context.
     *
     * decoding: either set by the user before avformat_open_input() (then
     * the user must close it manually) or set by avformat_open_input().
     * encoding: set by the user.
     *
     * 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;


AVIOContext表示字节流输入/输出的上下文,在muxers和demuxers的数据成员flags有设置AVFMT_NOFILE时,这个成员变量pb就不需要设置,因为muxers和demuxers会

使用其它的方式处理输入/输出。


    /**
     * Custom interrupt callbacks for the I/O layer.
     *
     * decoding: set by the user before avformat_open_input().
     * encoding: set by the user before avformat_write_header()
     * (mainly useful for AVFMT_NOFILE formats). The callback
     * should also be passed to avio_open2() if it's used to
     * open the file.
     */
    AVIOInterruptCB interrupt_callback;


AVIOInterruptCB在cflags有设置AVFMT_NOFILE时使用,传递给函数avio_open2使用。

/**
 * Callback for checking whether to abort blocking functions.
 * AVERROR_EXIT is returned in this case by the interrupted
 * function. During blocking operations, callback is called with
 * opaque as parameter. If the callback returns 1, the
 * blocking operation will be aborted.
 *
 * No members can be added to this struct without a major bump, if
 * new elements have been added after this struct in AVFormatContext
 * or AVIOContext.
 */
typedef struct AVIOInterruptCB 
{
    int (*callback)(void*);
    void *opaque;
} AVIOInterruptCB;


另外,就是:

/**
 * Guess the file format.
 *
 * @param is_opened Whether the file is already opened; determines whether
 *                  demuxers with or without AVFMT_NOFILE are probed.
 */
AVInputFormat *av_probe_input_format(AVProbeData *pd, int is_opened);


/**
 * Guess the file format.
 *
 * @param is_opened Whether the file is already opened; determines whether
 *                  demuxers with or without AVFMT_NOFILE are probed.
 * @param score_max A probe score larger that this is required to accept a
 *                  detection, the variable is set to the actual detection
 *                  score afterwards.
 *                  If the score is <= AVPROBE_SCORE_MAX / 4 it is recommended
 *                  to retry with a larger probe buffer.
 */
AVInputFormat *av_probe_input_format2(AVProbeData *pd, int is_opened, int *score_max);


参数is_opened,与muxers和demuxers有关系。


关于avio_open2:

/**
 * Create and initialize a AVIOContext for accessing the
 * resource indicated by url.
 * @note When the resource indicated by url has been opened in
 * read+write mode, the AVIOContext can be used only for writing.
 *
 * @param s Used to return the pointer to the created AVIOContext.
 * In case of failure the pointed to value is set to NULL.
 * @param flags flags which control how the resource indicated by url
 * is to be opened
 * @param int_cb an interrupt callback to be used at the protocols level
 * @param options  A dictionary filled with protocol-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 in case of success, a negative value corresponding to an
 * AVERROR code in case of failure
 */
int avio_open2(AVIOContext **s, const char *url, int flags, const AVIOInterruptCB *int_cb, AVDictionary **options);


参数const AVIOInterruptCB *int_cb,经过层层调用,最终在函数url_alloc_for_protocol中,赋值给新分配的URLContext类型变量的数据成员AVIOInterruptCB interrupt_callback;

static int url_alloc_for_protocol(URLContext **puc, struct URLProtocol *up,
                                  const char *filename, int flags,
                                  const AVIOInterruptCB *int_cb)
{
    URLContext *uc;

   ...

   uc = av_mallocz(sizeof(URLContext) + strlen(filename) + 1);

   ...

       if (int_cb)
        uc->interrupt_callback = *int_cb;

   ...


接下来要做的事情,就是理清楚,在有AVFMT_NOFILE和没有AVFMT_NOFILE的两种情况下,avformat input open分别的流程,以及二者之间有什么差别?

另外,还有AVIOInterruptCB使用的问题。


### 关于 FFmpeg 中 `AVFMT_RAWPICTURE` 未声明问题的分析与解决方案 #### 问题描述 在使用 FFmpeg 进行开发时,遇到错误提示 `'AVFMT_RAWPICTURE' was not declared in this scope`。此类问题是由于代码试图访问 FFmpeg 提供的一个宏定义 (`AVFMT_RAWPICTURE`),但在当前环境中未能成功解析该宏。 这种现象通常由以下几个原因引起: 1. 当前使用的 FFmpeg 版本较低,尚未引入 `AVFMT_RAWPICTURE` 宏。 2. 开发环境中的头文件或库文件路径配置有误,导致编译器无法正确加载所需的 FFmpeg 头文件。 3. 使用了不兼容的 API 或者代码逻辑存在问题。 --- #### 原因分析及解决方法 ##### 方法一:确认 FFmpeg 版本是否支持 `AVFMT_RAWPICTURE` `AVFMT_RAWPICTURE` 是 FFmpeg 较新的特性之一,在早期版本中并未提供。因此,首要任务是检查当前系统的 FFmpeg 版本是否满足需求。运行以下命令获取版本信息: ```bash ffmpeg -version ``` 如果显示的版本号低于预期(例如早于 3.x),则需要升级至更高版本[^1]。 ##### 方法二:更新 FFmpeg 至最新稳定版 为了确保兼容性,推荐将 FFmpeg 更新到最新稳定版本。以下是适用于大多数 Linux 发行版的操作步骤: 1. **安装必要的工具链** ```bash sudo apt-get update sudo apt-get install build-essential yasm nasm libtool autoconf automake pkg-config git cmake ``` 2. **克隆并编译 FFmpeg 源码** ```bash git clone https://git.ffmpeg.org/ffmpeg.git ffmpeg cd ffmpeg ./configure --enable-gpl --enable-libx264 --enable-nonfree make -j$(nproc) sudo make install ``` 完成上述操作后,再次验证 FFmpeg 的版本以确保更新成功。 ##### 方法三:调整代码逻辑规避潜在问题 即使升级了 FFmpeg,仍可能存在部分遗留代码不适配的情况。对于 `AVFMT_RAWPICTURE` 的使用场景,可以考虑采用更通用的方式实现相同功能。例如,通过检测输出格式标志位代替直接调用宏定义: ```cpp if (fmt_ctx->oformat->flags & AVFMT_NOFILE) { // Handle raw picture format or other specific cases. } ``` 此处利用了 `AVFMT_NOFILE` 等其他标志位作为替代方案[^2]。 ##### 方法四:检查头文件路径配置 有时尽管安装了新版 FFmpeg,但由于头文件路径设置不当,可能导致编译器仍然引用旧版本的头文件。此时可通过以下方式排查并修正: 1. 查看 CMake 输出日志,定位实际被加载的头文件路径; 2. 显式指定正确的头文件路径给编译器,例如: ```bash g++ your_code.cpp -I/path/to/new/ffmpeg/include -L/path/to/new/ffmpeg/lib -lavformat -lavcodec ... ``` --- #### 示例代码片段 以下是一段简单示例代码展示如何安全地判断是否存在 `AVFMT_RAWPICTURE` 支持: ```cpp #include <iostream> extern "C" { #include <libavformat/avformat.h> } int main() { av_register_all(); const AVOutputFormat *ofmt = NULL; while ((ofmt = av_oformat_next(ofmt)) != NULL) { if (ofmt->flags & AVFMT_RAWPICTURE) { // Check for raw picture support std::cout << "Raw picture format supported by output format: " << ofmt->name << std::endl; } } return 0; } ``` 编译时需链接 FFmpeg 库: ```bash g++ test_avformat.cpp -o test_avformat `pkg-config --cflags --libs libavformat` ``` --- ### 总结 通过对 FFmpeg 版本、头文件路径以及代码逻辑进行全面审查,可以有效解决 `'AVFMT_RAWPICTURE' was not declared in this scope` 类型的问题。优先升级 FFmpeg 至最新版本是最直接有效的手段;同时注意保持良好的开发习惯,及时跟踪官方文档和技术社区动态以便应对未来可能出现的变化。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值