Skip to content

Commit d9079f9

Browse files
Seeking now accounts for packets with multiple frames
1 parent 17787f8 commit d9079f9

File tree

6 files changed

+124
-44
lines changed

6 files changed

+124
-44
lines changed

FFmpegPlayer/FFmpegPlayer.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
3E2A84D624DD0E9C0031BFDC /* libavutil.56.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = 3E2A84CD24DD0E960031BFDC /* libavutil.56.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
1717
3E2A84D724DD0E9D0031BFDC /* libswresample.3.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = 3E2A84CF24DD0E960031BFDC /* libswresample.3.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
1818
3E2A84E024DD253B0031BFDC /* OpenDialogButtonCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E2A84DF24DD253B0031BFDC /* OpenDialogButtonCell.swift */; };
19+
3E3D249724E26C0200975403 /* PacketFrames.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E3D249624E26C0200975403 /* PacketFrames.swift */; };
1920
3E540DE024DC3F28002B3E78 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E540DDF24DC3F28002B3E78 /* AppDelegate.swift */; };
2021
3E540DE224DC3F29002B3E78 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3E540DE124DC3F29002B3E78 /* Assets.xcassets */; };
2122
3E540DE524DC3F29002B3E78 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 3E540DE324DC3F29002B3E78 /* MainMenu.xib */; };
@@ -84,6 +85,7 @@
8485
3E2A84D924DD13290031BFDC /* README.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README.txt; sourceTree = "<group>"; };
8586
3E2A84DA24DD13290031BFDC /* build-ffmpeg.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = "build-ffmpeg.sh"; sourceTree = "<group>"; };
8687
3E2A84DF24DD253B0031BFDC /* OpenDialogButtonCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenDialogButtonCell.swift; sourceTree = "<group>"; };
88+
3E3D249624E26C0200975403 /* PacketFrames.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PacketFrames.swift; sourceTree = "<group>"; };
8789
3E540DDC24DC3F28002B3E78 /* FFmpegPlayer.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = FFmpegPlayer.app; sourceTree = BUILT_PRODUCTS_DIR; };
8890
3E540DDF24DC3F28002B3E78 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
8991
3E540DE124DC3F29002B3E78 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
@@ -270,6 +272,7 @@
270272
3E540E2024DC408F002B3E78 /* Chapter.swift */,
271273
3E540E2824DC408F002B3E78 /* PacketTable.swift */,
272274
3E540E1F24DC408F002B3E78 /* Errors.swift */,
275+
3E3D249624E26C0200975403 /* PacketFrames.swift */,
273276
);
274277
path = FFmpegWrappers;
275278
sourceTree = "<group>";
@@ -414,6 +417,7 @@
414417
3E540E0324DC400E002B3E78 /* AudioEngine.swift in Sources */,
415418
3E540E6624DC4157002B3E78 /* ffmpeg.c in Sources */,
416419
3E540E3824DC408F002B3E78 /* PacketTable.swift in Sources */,
420+
3E3D249724E26C0200975403 /* PacketFrames.swift in Sources */,
417421
3E540E4C24DC40A8002B3E78 /* UtilsExtensions.swift in Sources */,
418422
3E540E4924DC40A8002B3E78 /* AtomicCounter.swift in Sources */,
419423
3E540E0024DC400E002B3E78 /* Muxer.swift in Sources */,

FFmpegPlayer/Sources/FFmpegWrappers/AudioCodec.swift

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ class AudioCodec: Codec {
5656
///
5757
/// - throws: **DecoderError** if an error occurs during decoding.
5858
///
59-
func decode(packet: Packet) throws -> [Frame] {
59+
func decode(packet: Packet) throws -> PacketFrames {
6060

6161
// Send the packet to the decoder for decoding.
6262
let resultCode: ResultCode = avcodec_send_packet(contextPointer, packet.pointer)
@@ -68,7 +68,7 @@ class AudioCodec: Codec {
6868
throw DecoderError(resultCode)
6969
}
7070

71-
return receiveFrames()
71+
return receiveFrames(for: packet)
7272
}
7373

7474
func decodeAndDrop(packet: Packet) {
@@ -89,32 +89,32 @@ class AudioCodec: Codec {
8989
///
9090
/// - returns: An ordered list of frames.
9191
///
92-
private func receiveFrames() -> [Frame] {
92+
private func receiveFrames(for packet: Packet? = nil) -> PacketFrames {
9393

9494
// Receive (potentially) multiple frames
9595

9696
// Resuse a single Frame object multiple times.
9797
var frame = Frame(sampleFormat: self.sampleFormat)
9898

9999
// Collect the received frames in an array.
100-
var bufferedFrames: [Frame] = []
100+
let packetFrames: PacketFrames = packet == nil ? PacketFrames() : PacketFrames(from: packet!)
101101

102102
// Receive a decoded frame from the codec.
103103
var resultCode: Int32 = avcodec_receive_frame(contextPointer, frame.pointer)
104104

105105
// Keep receiving frames while no errors are encountered
106106
while resultCode.isZero, frame.hasSamples {
107107

108-
let reald = Double(frame.avFrame.nb_samples) / Double(frame.sampleRate)
109-
print("Frame PTS: \(frame.pts) \(Double(frame.pts) * AudioStream.timeBase.ratio), sampleCount = \(frame.sampleCount), duration = \(reald), isKeyFrame: \(frame.avFrame.key_frame == 1)")
108+
// let reald = Double(frame.avFrame.nb_samples) / Double(frame.sampleRate)
109+
// print("Frame PTS: \(frame.pts) \(Double(frame.pts) * AudioStream.timeBase.ratio), sampleCount = \(frame.sampleCount), duration = \(reald), isKeyFrame: \(frame.avFrame.key_frame == 1)")
110110

111-
bufferedFrames.append(frame)
111+
packetFrames.appendFrame(frame: frame)
112112

113113
frame = Frame(sampleFormat: self.sampleFormat)
114114
resultCode = avcodec_receive_frame(contextPointer, frame.pointer)
115115
}
116116

117-
return bufferedFrames
117+
return packetFrames
118118
}
119119

120120
///
@@ -124,7 +124,7 @@ class AudioCodec: Codec {
124124
///
125125
/// - throws: **DecoderError** if an error occurs while draining the codec.
126126
///
127-
func drain() throws -> [Frame] {
127+
func drain() throws -> PacketFrames {
128128

129129
// Send the "flush packet" to the decoder
130130
let resultCode: Int32 = avcodec_send_packet(contextPointer, nil)
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import Foundation
2+
3+
/// Holds all frames for a single packet together as a single unit, and performs functions useful when seeking.
4+
class PacketFrames {
5+
6+
var frames: [Frame] = []
7+
var sampleCount: Int32 = 0
8+
var packet: Packet?
9+
10+
init() {}
11+
12+
init(from packet: Packet) {
13+
self.packet = packet
14+
}
15+
16+
func appendFrame(frame: Frame) {
17+
18+
// Update the sample count, and append the frame.
19+
self.sampleCount += frame.sampleCount
20+
frames.append(frame)
21+
}
22+
23+
func keepLastNSamples(sampleCount: Int32) {
24+
25+
if sampleCount < self.sampleCount {
26+
27+
var samplesSoFar: Int32 = 0
28+
var firstFrameToKeep: Int = 0
29+
30+
for (index, frame) in frames.enumerated().reversed() {
31+
32+
let samplesInThisFrame = frame.sampleCount
33+
print("\nFrame \(index) has \(samplesInThisFrame) samples.")
34+
35+
if samplesSoFar + samplesInThisFrame <= sampleCount {
36+
samplesSoFar += samplesInThisFrame
37+
print("Frame \(index) will fit. Keeping ALL \(samplesInThisFrame) samples.")
38+
39+
} else {
40+
41+
// Need to truncate frame
42+
let samplesToKeep = sampleCount - samplesSoFar
43+
samplesSoFar += samplesToKeep
44+
frame.keepLastNSamples(sampleCount: samplesToKeep)
45+
print("Frame \(index) did NOT fit. Keeping ONLY \(samplesToKeep) samples.")
46+
}
47+
48+
if samplesSoFar == sampleCount {
49+
50+
print("We will keep frames: \(index)-\(frames.count - 1)")
51+
52+
firstFrameToKeep = index
53+
break
54+
}
55+
}
56+
57+
if firstFrameToKeep > 0 {
58+
frames.removeFirst(firstFrameToKeep)
59+
}
60+
61+
self.sampleCount = sampleCount
62+
}
63+
}
64+
}

FFmpegPlayer/Sources/Player/Utils/Decoder.swift

Lines changed: 46 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ class Decoder {
135135
do {
136136

137137
let drainFrames = try codec.drain()
138-
terminalFrames.append(contentsOf: drainFrames)
138+
terminalFrames.append(contentsOf: drainFrames.frames)
139139

140140
} catch {
141141
print("\nDecoder drain error:", error)
@@ -169,65 +169,77 @@ class Decoder {
169169
try format.seek(within: stream, to: time)
170170

171171
let etime = measureExecutionTime {
172-
172+
173173
do {
174-
175-
var packetsRead: [(pkt: Packet, timestamp: Double)] = []
176-
var ptime: Double = 0
177-
178-
while ptime < time {
179-
180-
if let packet = try format.readPacket(from: stream) {
181-
182-
print("\n*** LOOP - LAST PKT READ: \(packet.pts), TIME = \(Double(packet.pts) * stream.timeBase.ratio)")
183-
ptime = Double(packet.pts) * stream.timeBase.ratio
184-
packetsRead.append((packet, ptime))
174+
175+
var packetsRead: [(pkt: Packet, timestamp: Double)] = []
176+
var ptime: Double = 0
177+
178+
while ptime < time {
179+
180+
if let packet = try format.readPacket(from: stream) {
181+
182+
print("\n*** LOOP - LAST PKT READ: \(packet.pts), TIME = \(Double(packet.pts) * stream.timeBase.ratio)")
183+
ptime = Double(packet.pts) * stream.timeBase.ratio
184+
packetsRead.append((packet, ptime))
185+
}
185186
}
186-
}
187-
187+
188188
if let firstIndexAfterTargetTime = packetsRead.firstIndex(where: {$0.timestamp > time}) {
189189

190190
if 0 < firstIndexAfterTargetTime - 1 {
191-
191+
192192
for index in 0..<(firstIndexAfterTargetTime - 1) {
193-
193+
194194
let pkt = packetsRead[index].pkt
195195
print("\n*** DROPPING PKT: \(pkt.pts)")
196196
codec.decodeAndDrop(packet: pkt)
197197
}
198198
}
199199

200200
let firstUsablePacketIndex = max(firstIndexAfterTargetTime - 1, 0)
201-
201+
202+
var framesFromUsablePackets: [PacketFrames] = []
203+
202204
for index in firstUsablePacketIndex..<packetsRead.count {
203-
205+
204206
let pkt = packetsRead[index].pkt
205-
207+
206208
print("\n*** TRYING PKT: \(pkt.pts)")
207-
208-
for frame in try codec.decode(packet: pkt) {
209-
frameQueue.enqueue(frame)
210-
print("\n*** ENQUEUED ONE \(frame.pts) with \(frame.sampleCount) samples FOR: \(pkt.pts)")
211-
}
209+
framesFromUsablePackets.append(try codec.decode(packet: pkt))
212210
}
213211

214-
let err = abs(time - packetsRead[firstUsablePacketIndex].timestamp)
215-
print("\nSEEK-ERROR = \(err)")
216-
217-
if err > 0.01 {
212+
// Check the seek error (time difference)
213+
if framesFromUsablePackets.count > 1, time - packetsRead[firstUsablePacketIndex].timestamp > 0.01 {
214+
215+
print("\nSEEK-ERROR = \(time - packetsRead[firstUsablePacketIndex].timestamp)")
218216

219-
let frame = frameQueue.peek()!
220217
let numSamplesToKeep = Int32((packetsRead[firstIndexAfterTargetTime].timestamp - time) * Double(codec.sampleRate))
218+
print("\nKeeping last \(numSamplesToKeep) in start frame with PTS \(packetsRead[firstUsablePacketIndex].pkt.pts).")
221219

222-
print("\nKeeping last \(numSamplesToKeep) in start frame with PTS \(frame.pts).")
220+
framesFromUsablePackets[0].keepLastNSamples(sampleCount: numSamplesToKeep)
221+
}
222+
223+
// for frame in framesFromAllPackets.flatMap({$0.frames}) {
224+
// frameQueue.enqueue(frame)
225+
// print("\n*** ENQUEUED ONE \(frame.pts) with \(frame.sampleCount) samples FOR: \(pkt.pts)")
226+
// }
227+
228+
for pktFrames in framesFromUsablePackets {
223229

224-
frame.keepLastNSamples(sampleCount: numSamplesToKeep)
230+
for frame in pktFrames.frames {
231+
232+
frameQueue.enqueue(frame)
233+
print("\n*** ENQUEUED ONE \(frame.pts) with \(frame.sampleCount) samples FOR: \(pktFrames.packet!.pts)")
234+
}
235+
236+
print("---------------")
225237
}
226238
}
227239

228240
} catch {}
229241
}
230-
242+
231243
print("\nSKIPPING TOOK \(etime * 1000) msec")
232244

233245
// If the seek succeeds, we have not reached EOF.
@@ -266,7 +278,7 @@ class Decoder {
266278

267279
if let packet = try format.readPacket(from: stream) {
268280

269-
for frame in try codec.decode(packet: packet) {
281+
for frame in try codec.decode(packet: packet).frames {
270282
frameQueue.enqueue(frame)
271283
}
272284
}

FFmpegPlayer/Sources/Player/Utils/FrameBuffer.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ class FrameBuffer {
107107
///
108108
func constructAudioBuffer(format: AVAudioFormat) -> AVAudioPCMBuffer? {
109109

110-
print("\n**** Constructing audio buffer with \(sampleCount) samples")
110+
// print("\n**** Constructing audio buffer with \(sampleCount) samples")
111111

112112
guard sampleCount > 0 else {return nil}
113113

0 commit comments

Comments
 (0)