【ffmpeg数据结构 6】AVIOContext

343 阅读4分钟

3.7.1 打开文件的方式

下面提供一个简单的示例代码,演示了两种读取文件的方法:一种是直接使用 avformat_open_input 打开文件,另一种是通过创建自定义的 AVIOContext 进行文件读取。请注意,这个示例只是为了说明概念,实际使用中可能需要添加更多的错误处理和资源释放代码。

 #include <libavformat/avformat.h>
 ​
 // 读取文件的回调函数
 int custom_read(void* opaque, uint8_t* buf, int buf_size) {
     // 在这里实现自定义的文件读取逻辑
     // 将文件数据拷贝到 buf 中,并返回实际读取的字节数
     // 如果到达文件末尾,返回 0 表示结束
     // 返回负值表示出现错误
 ​
     // 示例中直接返回 0,表示文件结束
     return 0;
 }
 ​
 int main() {
     // 方法1: 直接使用 avformat_open_input 打开文件
     AVFormatContext* format_ctx1 = avformat_alloc_context();
     int ret1 = avformat_open_input(&format_ctx1, "input_file.mp4", NULL, NULL);
     ...
     avformat_close_input(&format_ctx1);
 ​
     // 方法2: 使用自定义的 AVIOContext 打开文件
     AVFormatContext* format_ctx2 = avformat_alloc_context();
     
     // 创建自定义的 AVIOContext
     AVIOContext* avio_ctx = avio_alloc_context(
         malloc(4096),  // 缓冲区
         4096,          // 缓冲区大小
         0,             // 是否自动释放缓冲区
         fd,          // 用户数据,这里可以传递自定义结构体  FILE *fd = fread();
         custom_read,   // 读取数据的回调函数
         NULL,          // 写入数据的回调函数,这里不需要写入
         NULL           // 定位文件指针的回调函数,这里不需要定位
     );
 ​
     format_ctx2->pb = avio_ctx;
 ​
     int ret2 = avformat_open_input(&format_ctx2, NULL, NULL, NULL);
 ​
     if (ret2 < 0) {
         // 错误处理
         fprintf(stderr, "Error opening file using custom AVIOContext: %s\n", av_err2str(ret2));
         return ret2;
     }
 ​
     // 处理 format_ctx2,例如读取音视频流等...
 ​
     // 释放资源
     avformat_close_input(&format_ctx2);
     av_freep(&avio_ctx->buffer);  // 释放缓冲区
     avio_context_free(&avio_ctx); // 释放 AVIOContext
 ​
     return 0;
 }

在这个示例中,第一种方法直接使用 avformat_open_input 打开文件,而第二种方法通过创建自定义的 AVIOContext 并关联到 AVFormatContext 中,实现了自定义的文件读取逻辑。在实际使用中,你需要根据具体的需求来实现自定义的文件读取逻辑,并根据情况调整缓冲区大小、对齐等参数。

3.7.2 其余接口

AVIOContext 是 FFmpeg 中用于输入/输出(I/O)操作的上下文结构体。以下是与 AVIOContext 相关的一些主要接口和函数:

  1. avio_alloc_context:

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

    用于分配并初始化一个 AVIOContext 结构体。可以指定读写标志、缓冲区等参数,以及一些回调函数,如读取、写入、定位等。

  2. avio_open:

     int avio_open(AVIOContext **s, const char *url, int flags);
     ​
     s: 一个指向 AVIOContext 结构体指针的指针,用于存储创建的输入/输出上下文。
     url: 表示要打开的文件的 URL 或路径。
     flags: 表示打开文件的模式,可以是 AVIO_FLAG_READ(读取模式)、AVIO_FLAG_WRITE(写入模式)等
     // 使用方法
     AVFormatContext *fmt_ctx = avformat_alloc_context();
     ret = avio_open(&fmt_ctx->pb, filename, AVIO_FLAG_WRITE);
    

    用于打开输入/输出上下文,通常用于文件或网络流。将创建的 AVIOContext 存储在 s 指针指向的位置。

  3. avio_close:

     int avio_close(AVIOContext *s);
    

    用于关闭输入/输出上下文,并释放相关资源。

  4. avio_read:

     int avio_read(AVIOContext *s, unsigned char *buf, int size);
    

    从输入上下文读取数据到缓冲区。

  5. avio_write:

     int avio_write(AVIOContext *s, const unsigned char *buf, int size);
    

    将数据写入输出上下文。

  6. avio_seek:

     int64_t avio_seek(AVIOContext *s, int64_t offset, int whence);
    

    用于定位输入/输出上下文中的位置。

  7. avio_flush:

     void avio_flush(AVIOContext *s);
    

    刷新缓冲区,确保所有缓冲的数据被写入。

  8. avio_feof:

     int avio_feof(const AVIOContext *s);
    

    检查是否已经到达输入流的末尾。

这些函数提供了对 AVIOContext 结构体的常用操作,使得 FFmpeg 可以与不同的数据源进行交互,包括文件、网络流等。在使用这些函数时,需要根据具体的需求和场景选择合适的参数和回调函数。