forked from sunlubo/SwiftFFmpeg
-
Notifications
You must be signed in to change notification settings - Fork 1
/
decode_audio.swift
108 lines (89 loc) · 2.5 KB
/
decode_audio.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
//
// decode_audio.swift
// SwiftFFmpegExamples
//
// Created by sunlubo on 2019/1/9.
//
import SwiftFFmpeg
#if canImport(Darwin)
import Darwin
#else
import Glibc
#endif
private func decode(
codecCtx: AVCodecContext,
frame: AVFrame,
pkt: AVPacket?,
file: UnsafeMutablePointer<FILE>
) throws {
try codecCtx.sendPacket(pkt)
while true {
do {
try codecCtx.receiveFrame(frame)
} catch let err as AVError where err == .tryAgain || err == .eof {
break
}
let dataSize = codecCtx.sampleFormat.bytesPerSample
for i in 0..<frame.sampleCount {
for j in 0..<codecCtx.channelCount {
fwrite(frame.data[j]!.advanced(by: dataSize * i), 1, dataSize, file)
}
}
print(String(format: "write: %3d %5d", codecCtx.frameNumber, frame.sampleCount))
frame.unref()
}
}
func decode_audio() throws {
if CommandLine.argc < 4 {
print("Usage: \(CommandLine.arguments[0]) \(CommandLine.arguments[1]) input_file output_file")
return
}
let input = CommandLine.arguments[2]
let output = CommandLine.arguments[3]
guard let inFile = fopen(input, "rb") else {
fatalError("Could not open \(input).")
}
defer { fclose(inFile) }
guard let outFile = fopen(output, "w") else {
fatalError("Could not open \(output).")
}
defer { fclose(outFile) }
let codec = AVCodec.findDecoderById(.MP2)!
let codecCtx = AVCodecContext(codec: codec)
try codecCtx.openCodec()
let parser = AVCodecParserContext(codecContext: codecCtx)!
let pkt = AVPacket()
let frame = AVFrame()
let inbufSize = 20480
let refillThresh = 4096
let inbuf = UnsafeMutablePointer<UInt8>.allocate(
capacity: inbufSize + AVConstant.inputBufferPaddingSize)
inbuf.initialize(to: 0)
defer { inbuf.deallocate() }
// decode until eof
var size = fread(inbuf, 1, inbufSize, inFile)
var data = inbuf
while size > 0 {
// use the parser to split the data into frames
let (buf, bufSize, used) = try parser.parse(data: data, size: size)
pkt.data = buf
pkt.size = bufSize
data = data.advanced(by: used)
size -= used
if pkt.size > 0 {
try decode(codecCtx: codecCtx, frame: frame, pkt: pkt, file: outFile)
}
if size < refillThresh {
memmove(inbuf, data, size)
data = inbuf
let len = fread(data.advanced(by: size), 1, inbufSize - size, inFile)
if len > 0 {
size += len
}
}
}
// flush the decoder
pkt.data = nil
pkt.size = 0
try decode(codecCtx: codecCtx, frame: frame, pkt: pkt, file: outFile)
}