1、简述
在学习FFmpeg源码中的例子时,发现FFmpeg封装了操作目录和文件的接口。这篇博客把这些接口罗列出来,作为笔记简单记录下。
2、接口列表
- 打开目录,准备读取目录信息
int avio_open_dir(AVIODirContext **s, const char *url, AVDictionary **options);
参数说明:
url——是传入的目录路径;
s——是返回的目录上下文,类似文件描述符,AVIODirContext定义如下
typedef struct AVIODirContext {
struct URLContext *url_context;
} AVIODirContext;
- 关闭目录
int avio_close_dir(AVIODirContext **s); - 获取目录中的子项信息AVIODirEntry
int avio_read_dir(AVIODirContext *s, AVIODirEntry **next);
每调取一次,将会获得下一子项,AVIODirEntry 用来描述目录子项信息,原型如下
typedef struct AVIODirEntry {
char *name; // 文件名
int type; // 文件类型
int utf8; // 值为1,表示文件名是以UTF-8编码;值为0,表示其它编码
int64_t size;//文件大小
int64_t modification_timestamp;//修改时间戳,从Epoch(1970年1月1日00:00:00 UTC )到现在的微秒数,下同;
int64_t access_timestamp; //访问时间戳
int64_t status_change_timestamp;//更改文件属性时间戳
int64_t user_id; //用户ID
int64_t group_id;//组ID
int64_t filemode;//文件模式
} AVIODirEntry;
文件类型列表如下
enum AVIODirEntryType {
AVIO_ENTRY_UNKNOWN, // 位置
AVIO_ENTRY_BLOCK_DEVICE,//块设备,如硬盘等
AVIO_ENTRY_CHARACTER_DEVICE,// 字符设备
AVIO_ENTRY_DIRECTORY,//目录
AVIO_ENTRY_NAMED_PIPE,//管道
AVIO_ENTRY_SYMBOLIC_LINK,//链接文件
AVIO_ENTRY_SOCKET,//socket描述符
AVIO_ENTRY_FILE,//普通文件
AVIO_ENTRY_SERVER,//???
AVIO_ENTRY_SHARE,//共享内存???
AVIO_ENTRY_WORKGROUP,//???
};
- 释放AVIODirEntry
void avio_free_directory_entry(AVIODirEntry **entry); - 删除目录、文件或者是其它url资源
int avpriv_io_delete(const char *url); - 移动或重命名目录文件或者是其它url资源
int avpriv_io_move(const char *url_src, const char *url_dst);
3、FFmpeg源码中示例执行结果
./avio_dir_cmd list pc-uninstalled/
TYPE SIZE NAME UID(GID) UGO MODIFIED ACCESSED STATUS_CHANGED
<FILE> 240 libavutil-uninstalled.pc 1000(1000) 664 1568617590000000 1584780235000000 1568617590000000
<FILE> 432 libavdevice-uninstalled.pc 1000(1000) 664 1568616453000000 1584780235000000 1568616453000000
<FILE> 331 libavformat-uninstalled.pc 1000(1000) 664 1568617585000000 1584780235000000 1568617585000000
<FILE> 275 libpostproc-uninstalled.pc 1000(1000) 664 1568617590000000 1584780235000000 1568617590000000
<FILE> 291 libavcodec-uninstalled.pc 1000(1000) 664 1568617588000000 1584780235000000 1568617588000000
<FILE> 282 libswresample-uninstalled.pc 1000(1000) 664 1568617590000000 1584780235000000 1568617590000000
<FILE> 272 libswscale-uninstalled.pc 1000(1000) 664 1568617590000000 1584780235000000 1568617590000000
<FILE> 412 libavfilter-uninstalled.pc 1000(1000) 664 1568617584000000 1584780235000000 1568617584000000
4、源码doc/examples/avio_dir_cmd.c
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavformat/avio.h>
static const char *type_string(int type)
{
switch (type) {
case AVIO_ENTRY_DIRECTORY:
return "<DIR>";
case AVIO_ENTRY_FILE:
return "<FILE>";
case AVIO_ENTRY_BLOCK_DEVICE:
return "<BLOCK DEVICE>";
case AVIO_ENTRY_CHARACTER_DEVICE:
return "<CHARACTER DEVICE>";
case AVIO_ENTRY_NAMED_PIPE:
return "<PIPE>";
case AVIO_ENTRY_SYMBOLIC_LINK:
return "<LINK>";
case AVIO_ENTRY_SOCKET:
return "<SOCKET>";
case AVIO_ENTRY_SERVER:
return "<SERVER>";
case AVIO_ENTRY_SHARE:
return "<SHARE>";
case AVIO_ENTRY_WORKGROUP:
return "<WORKGROUP>";
case AVIO_ENTRY_UNKNOWN:
default:
break;
}
return "<UNKNOWN>";
}
static int list_op(const char *input_dir)
{
AVIODirEntry *entry = NULL;
AVIODirContext *ctx = NULL;
int cnt, ret;
char filemode[4], uid_and_gid[20];
if ((ret = avio_open_dir(&ctx, input_dir, NULL)) < 0) {
av_log(NULL, AV_LOG_ERROR, "Cannot open directory: %s.\n", av_err2str(ret));
goto fail;
}
cnt = 0;
for (;;) {
if ((ret = avio_read_dir(ctx, &entry)) < 0) {
av_log(NULL, AV_LOG_ERROR, "Cannot list directory: %s.\n", av_err2str(ret));
goto fail;
}
if (!entry)
break;
if (entry->filemode == -1) {
snprintf(filemode, 4, "???");
} else {
snprintf(filemode, 4, "%3"PRIo64, entry->filemode);
}
snprintf(uid_and_gid, 20, "%"PRId64"(%"PRId64")", entry->user_id, entry->group_id);
if (cnt == 0)
av_log(NULL, AV_LOG_INFO, "%-9s %12s %30s %10s %s %16s %16s %16s\n",
"TYPE", "SIZE", "NAME", "UID(GID)", "UGO", "MODIFIED",
"ACCESSED", "STATUS_CHANGED");
av_log(NULL, AV_LOG_INFO, "%-9s %12"PRId64" %30s %10s %s %16"PRId64" %16"PRId64" %16"PRId64"\n",
type_string(entry->type),
entry->size,
entry->name,
uid_and_gid,
filemode,
entry->modification_timestamp,
entry->access_timestamp,
entry->status_change_timestamp);
avio_free_directory_entry(&entry);
cnt++;
};
fail:
avio_close_dir(&ctx);
return ret;
}
static int del_op(const char *url)
{
int ret = avpriv_io_delete(url);
if (ret < 0)
av_log(NULL, AV_LOG_ERROR, "Cannot delete '%s': %s.\n", url, av_err2str(ret));
return ret;
}
static int move_op(const char *src, const char *dst)
{
int ret = avpriv_io_move(src, dst);
if (ret < 0)
av_log(NULL, AV_LOG_ERROR, "Cannot move '%s' into '%s': %s.\n", src, dst, av_err2str(ret));
return ret;
}
static void usage(const char *program_name)
{
fprintf(stderr, "usage: %s OPERATION entry1 [entry2]\n"
"API example program to show how to manipulate resources "
"accessed through AVIOContext.\n"
"OPERATIONS:\n"
"list list content of the directory\n"
"move rename content in directory\n"
"del delete content in directory\n",
program_name);
}
int main(int argc, char *argv[])
{
const char *op = NULL;
int ret;
av_log_set_level(AV_LOG_DEBUG);
if (argc < 2) {
usage(argv[0]);
return 1;
}
avformat_network_init();
op = argv[1];
if (strcmp(op, "list") == 0) {
if (argc < 3) {
av_log(NULL, AV_LOG_INFO, "Missing argument for list operation.\n");
ret = AVERROR(EINVAL);
} else {
ret = list_op(argv[2]);
}
} else if (strcmp(op, "del") == 0) {
if (argc < 3) {
av_log(NULL, AV_LOG_INFO, "Missing argument for del operation.\n");
ret = AVERROR(EINVAL);
} else {
ret = del_op(argv[2]);
}
} else if (strcmp(op, "move") == 0) {
if (argc < 4) {
av_log(NULL, AV_LOG_INFO, "Missing argument for move operation.\n");
ret = AVERROR(EINVAL);
} else {
ret = move_op(argv[2], argv[3]);
}
} else {
av_log(NULL, AV_LOG_INFO, "Invalid operation %s\n", op);
ret = AVERROR(EINVAL);
}
avformat_network_deinit();
return ret < 0 ? 1 : 0;
}