2023-03-27:avio_list_dir.c 是 FFmpeg 库自带的一个示例程序,它提供了列出目录中所有文件和子目录的功能,请用go语言改写。

2023-03-27 21:39:31 浏览数 (2)

2023-03-27:avio_list_dir.c 是 FFmpeg 库自带的一个示例程序,它提供了列出目录中所有文件和子目录的功能,请用go语言改写。

答案2023-03-27:

这段代码实现了通过 AVIOContext 列出指定目录下的文件和子目录,并打印出它们的名称、大小、类型、权限等信息。

具体流程如下:

1.设置 FFmpeg 库的路径,以及调用 AvformatNetworkInit() 初始化网络相关的组件。

2.调用 AvioOpenDir() 打开指定目录,获取 AVIODirContext 对象。

3.循环调用 AVIODirContext.AvioReadDir() 方法读取目录下的文件和子目录,每次读取到一个目录项后,输出该目录项的信息。如果已经读取完所有目录项,则退出循环。

4.输出格式化的目录项信息,包括类型、大小、名称、权限等。

5.在每次循环中需要调用 AVIODirContext.AvioFreeDirectoryEntry() 方法释放当前目录项所占用的内存空间。

6.最后调用 AvioCloseDir() 关闭目录并销毁 AVIODirContext 对象,调用 AvformatNetworkDeinit() 释放网络相关的资源。

需要注意的是,这段代码只能在支持 AVIOContext 的平台上运行,例如 Linux 上的文件系统或者 S3、HDFS 等云存储服务。而 Windows 平台上不支持 AVIOContext,因此无法使用该方法列出目录下的文件和子目录。

代码见github/moonfdd/ffmpeg-go。

执行命令:

代码语言:go复制
go run ./examples/internalexamples/avio_list_dir/main.go .

golang代码如下:

代码语言:go复制
package main

import (
	"fmt"
	"os"

	"github.com/moonfdd/ffmpeg-go/ffcommon"
	"github.com/moonfdd/ffmpeg-go/libavformat"
	"github.com/moonfdd/ffmpeg-go/libavutil"
)

func main() {

	os.Setenv("Path", os.Getenv("Path") ";./lib")
	ffcommon.SetAvutilPath("./lib/avutil-56.dll")
	ffcommon.SetAvcodecPath("./lib/avcodec-58.dll")
	ffcommon.SetAvdevicePath("./lib/avdevice-58.dll")
	ffcommon.SetAvfilterPath("./lib/avfilter-56.dll")
	ffcommon.SetAvformatPath("./lib/avformat-58.dll")
	ffcommon.SetAvpostprocPath("./lib/postproc-55.dll")
	ffcommon.SetAvswresamplePath("./lib/swresample-3.dll")
	ffcommon.SetAvswscalePath("./lib/swscale-5.dll")

	genDir := "./out"
	_, err := os.Stat(genDir)
	if err != nil {
		if os.IsNotExist(err) {
			os.Mkdir(genDir, 0777) //  Everyone can read write and execute
		}
	}
	main0()
}
func main0() (ret ffcommon.FInt) {

	libavutil.AvLogSetLevel(libavutil.AV_LOG_DEBUG)

	if len(os.Args) < 2 {
		usage(os.Args[0])
		ret = 1
		return
	}

	libavformat.AvformatNetworkInit()

	ret = list_op(os.Args[1])

	libavformat.AvformatNetworkDeinit()

	if ret < 0 {
		ret = 1
	}
	return
}

func type_string(type0 int32) string {
	switch type0 {
	case libavformat.AVIO_ENTRY_DIRECTORY:
		return "<DIR>"
	case libavformat.AVIO_ENTRY_FILE:
		return "<FILE>"
	case libavformat.AVIO_ENTRY_BLOCK_DEVICE:
		return "<BLOCK DEVICE>"
	case libavformat.AVIO_ENTRY_CHARACTER_DEVICE:
		return "<CHARACTER DEVICE>"
	case libavformat.AVIO_ENTRY_NAMED_PIPE:
		return "<PIPE>"
	case libavformat.AVIO_ENTRY_SYMBOLIC_LINK:
		return "<LINK>"
	case libavformat.AVIO_ENTRY_SOCKET:
		return "<SOCKET>"
	case libavformat.AVIO_ENTRY_SERVER:
		return "<SERVER>"
	case libavformat.AVIO_ENTRY_SHARE:
		return "<SHARE>"
	case libavformat.AVIO_ENTRY_WORKGROUP:
		return "<WORKGROUP>"
	case libavformat.AVIO_ENTRY_UNKNOWN:
	default:
		break
	}
	return "<UNKNOWN>"
}

func list_op(input_dir string) (ret int32) {
	var entry *libavformat.AVIODirEntry
	var ctx *libavformat.AVIODirContext
	var cnt int32
	var filemode [4]byte
	var uid_and_gid [20]byte

	//注意Windows下会返回-40,也就是Function not implement,方法未实现,也就是说windows下不支持此方法
	ret = libavformat.AvioOpenDir(&ctx, input_dir, nil)
	defer libavformat.AvioCloseDir(&ctx)

	if ret < 0 {
		libavutil.AvLog(uintptr(0), libavutil.AV_LOG_ERROR, "Cannot open directory: %s.n", libavutil.AvErr2str(ret))
		return
	}

	cnt = 0
	for {
		ret = ctx.AvioReadDir(&entry)
		if ret < 0 {
			libavutil.AvLog(uintptr(0), libavutil.AV_LOG_ERROR, "Cannot list directory: %s.n", libavutil.AvErr2str(ret))
			return
		}
		if entry == nil {
			break
		}
		if entry.Filemode == -1 {
			filemode[0] = '?'
			filemode[1] = '?'
			filemode[2] = '?'
		} else {
			f := fmt.Sprint(entry.Filemode)
			if len(f) >= 1 {
				filemode[0] = f[0]
			}
			if len(f) >= 2 {
				filemode[1] = f[1]
			}
			if len(f) >= 3 {
				filemode[2] = f[2]
			}
		}
		u := fmt.Sprintf("%d%d", entry.UserId, entry.GroupId)
		copy(uid_and_gid[0:19], []byte(u))

		if cnt == 0 {
			libavutil.AvLog(uintptr(0), libavutil.AV_LOG_INFO, "%-9s s 0s s %s s s sn",
				"TYPE", "SIZE", "NAME", "UID(GID)", "UGO", "MODIFIED",
				"ACCESSED", "STATUS_CHANGED")
		}
		libavutil.AvLog(uintptr(0), libavutil.AV_LOG_INFO, "%-9s s 0s s %s s s sn",
			type_string(entry.Type),
			fmt.Sprint(entry.Size),
			ffcommon.StringFromPtr(entry.Name),
			string(uid_and_gid[:]),
			fmt.Sprint(filemode),
			fmt.Sprint(entry.ModificationTimestamp),
			fmt.Sprint(entry.AccessTimestamp),
			fmt.Sprint(entry.StatusChangeTimestamp))
		libavformat.AvioFreeDirectoryEntry(&entry)
		cnt  
	}
	return
}

func usage(program_name string) {
	fmt.Printf("usage: %s input_dirnAPI example program to show how to list files in directory accessed through AVIOContext.n", program_name)
}

0 人点赞