AVFormatContext
1. AVFormatContext
的通用性
1.1 通用结构
AVFormatContext
是 FFmpeg 中的一个通用结构体,用于描述多媒体文件或流的上下文信息。- 它既可以用于输入文件/流,也可以用于输出文件/流。
- 关键字段(如
iformat
和oformat
)决定了AVFormatContext
是用于输入还是输出。
1.2 输入和输出的区别
- 输入
AVFormatContext
:- 用于描述输入文件或流的上下文信息。
- 通过
iformat
字段(AVInputFormat
)指定输入格式。 - 通过
avformat_open_input
自动分配和初始化。
- 输出
AVFormatContext
:- 用于描述输出文件或流的上下文信息。
- 通过
oformat
字段(AVOutputFormat
)指定输出格式。 - 通过
avformat_alloc_output_context2
或avformat_alloc_context
手动分配和初始化。
2. avformat_alloc_context
的作用
2.1 通用分配函数
avformat_alloc_context
是一个通用的分配函数,用于分配并初始化一个空的AVFormatContext
。- 它不会自动设置
iformat
或oformat
,需要手动设置。
2.2 使用场景
- 输入文件/流:
- 通常不直接使用
avformat_alloc_context
,而是通过avformat_open_input
自动分配和初始化AVFormatContext
。
- 通常不直接使用
- 输出文件/流:
- 通常使用
avformat_alloc_output_context2
,它会自动设置oformat
。
- 通常使用
3. 输入和输出的 AVFormatContext
的创建方式
3.1 输入 AVFormatContext
- 使用
avformat_open_input
打开输入文件/流时,FFmpeg 会自动分配并初始化一个AVFormatContext
。 - 示例:
import Foundation import FFmpeg class FFmpegInputManager { static func openInputFile(filePath: String) -> UnsafeMutablePointer<AVFormatContext>? { var formatContext: UnsafeMutablePointer<AVFormatContext>? = nil // 打开输入文件 if avformat_open_input(&formatContext, filePath, nil, nil) < 0 { print("Failed to open input file: \(filePath)") return nil } print("Input file opened successfully: \(filePath)") return formatContext } } // 调用示例 if let inputContext = FFmpegInputManager.openInputFile(filePath: "input.mp4") { // 使用 inputContext print("Input context created: \(inputContext)") // 打印文件信息 av_dump_format(inputContext, 0, "input.mp4", 0) // 释放资源 avformat_close_input(&inputContext) }
关键点
avformat_open_input
会自动分配并初始化AVFormatContext
。iformat
字段会被设置为输入文件的格式(AVInputFormat
)。
3.2 输出 AVFormatContext
- 使用
avformat_alloc_output_context2
或avformat_alloc_context
手动分配和初始化一个AVFormatContext
。 - 示例:
import Foundation import FFmpeg class FFmpegOutputManager { static func createOutputFile(filePath: String, formatName: String) -> UnsafeMutablePointer<AVFormatContext>? { var formatContext: UnsafeMutablePointer<AVFormatContext>? = nil // 创建输出文件 if avformat_alloc_output_context2(&formatContext, nil, formatName, filePath) < 0 { print("Failed to create output file: \(filePath)") return nil } print("Output file created successfully: \(filePath)") return formatContext } } // 调用示例 if let outputContext = FFmpegOutputManager.createOutputFile(filePath: "output.mp4", formatName: "mp4") { // 使用 outputContext print("Output context created: \(outputContext)") // 释放资源 avformat_free_context(outputContext) }
关键点
avformat_alloc_output_context2
会自动分配并初始化AVFormatContext
,并设置oformat
字段为输出格式(AVOutputFormat
)。- 如果使用
avformat_alloc_context
,需要手动设置oformat
。
4. 输入和输出的 AVFormatContext
的区别
属性 | 输入 AVFormatContext | 输出 AVFormatContext |
---|---|---|
创建方式 | 使用 avformat_open_input 自动分配和初始化 | 使用 avformat_alloc_output_context2 或 avformat_alloc_context 手动分配 |
格式字段 | iformat (AVInputFormat ) | oformat (AVOutputFormat ) |
用途 | 描述输入文件/流的上下文信息 | 描述输出文件/流的上下文信息 |
流信息 | 包含输入文件/流的所有流信息 | 包含输出文件/流的所有流信息 |
常见操作 | 打开文件、读取数据 | 写入文件头、写入数据、写入文件尾 |
5. 示例:完整的输入和输出处理流程
以下是一个完整的示例,展示如何使用 输入 AVFormatContext
和 输出 AVFormatContext
处理音频文件。
5.1 示例代码
import Foundation
import FFmpeg
class FFmpegProcessor {
static func processFile(inputFile: String, outputFile: String) {
var inputContext: UnsafeMutablePointer<AVFormatContext>? = nil
var outputContext: UnsafeMutablePointer<AVFormatContext>? = nil
// 打开输入文件
if avformat_open_input(&inputContext, inputFile, nil, nil) < 0 {
print("Failed to open input file: \(inputFile)")
return
}
// 创建输出文件
if avformat_alloc_output_context2(&outputContext, nil, "mp4", outputFile) < 0 {
print("Failed to create output file: \(outputFile)")
avformat_close_input(&inputContext)
return
}
// 添加流到输出文件
for i in 0..<inputContext!.pointee.nb_streams {
let inStream = inputContext!.pointee.streams[Int(i)]!
let outStream = avformat_new_stream(outputContext, nil)
if outStream == nil {
print("Failed to allocate output stream")
avformat_close_input(&inputContext)
avformat_free_context(outputContext)
return
}
// 复制流参数
if avcodec_parameters_copy(outStream!.pointee.codecpar, inStream.pointee.codecpar) < 0 {
print("Failed to copy codec parameters")
avformat_close_input(&inputContext)
avformat_free_context(outputContext)
return
}
outStream!.pointee.codecpar.pointee.codec_tag = 0
}
// 打开输出文件
if avio_open(&outputContext!.pointee.pb, outputFile, AVIO_FLAG_WRITE) < 0 {
print("Failed to open output file")
avformat_close_input(&inputContext)
avformat_free_context(outputContext)
return
}
// 写入文件头
if avformat_write_header(outputContext, nil) < 0 {
print("Failed to write header")
avformat_close_input(&inputContext)
avformat_free_context(outputContext)
return
}
// 释放资源
avformat_close_input(&inputContext)
avformat_free_context(outputContext)
print("Processing completed successfully")
}
}
// 调用示例
FFmpegProcessor.processFile(inputFile: "input.mp4", outputFile: "output.mp4")
6. 总结
AVFormatContext
是通用的结构体,既可以用于输入,也可以用于输出。- 输入和输出的区别:
- 输入通过
iformat
(AVInputFormat
)描述。 - 输出通过
oformat
(AVOutputFormat
)描述。
- 输入通过
- 创建方式:
- 输入:使用
avformat_open_input
自动分配和初始化。 - 输出:使用
avformat_alloc_output_context2
或avformat_alloc_context
手动分配和初始化。
- 输入:使用
通过这种方式,FFmpeg 可以灵活地处理多媒体文件和流。