Improve UniversalSoftwareVideoSource seeking

This commit is contained in:
Peter 2019-07-19 13:29:23 +01:00
parent 23b399f94e
commit 3a1a825e69
5 changed files with 37 additions and 40 deletions

View File

@ -551,7 +551,7 @@ final class FFMpegMediaFrameSourceContext: NSObject {
for stream in [initializedState.videoStream, initializedState.audioStream] {
if let stream = stream {
let pts = CMTimeMakeWithSeconds(timestamp, preferredTimescale: stream.timebase.timescale)
initializedState.avFormatContext.seekFrame(forStreamIndex: Int32(stream.index), pts: pts.value)
initializedState.avFormatContext.seekFrame(forStreamIndex: Int32(stream.index), pts: pts.value, positionOnKeyframe: true)
break
}
}

View File

@ -174,7 +174,7 @@ public final class SoftwareVideoSource {
} else {
if let avFormatContext = self.avFormatContext, let videoStream = self.videoStream {
endOfStream = true
avFormatContext.seekFrame(forStreamIndex: Int32(videoStream.index), pts: 0)
avFormatContext.seekFrame(forStreamIndex: Int32(videoStream.index), pts: 0, positionOnKeyframe: true)
} else {
endOfStream = true
break
@ -228,7 +228,7 @@ public final class SoftwareVideoSource {
public func seek(timestamp: Double) {
if let stream = self.videoStream, let avFormatContext = self.avFormatContext {
let pts = CMTimeMakeWithSeconds(timestamp, preferredTimescale: stream.timebase.timescale)
avFormatContext.seekFrame(forStreamIndex: Int32(stream.index), pts: pts.value)
avFormatContext.seekFrame(forStreamIndex: Int32(stream.index), pts: pts.value, positionOnKeyframe: true)
stream.decoder.reset()
}
}

View File

@ -6,6 +6,7 @@ import FFMpeg
private func readPacketCallback(userData: UnsafeMutableRawPointer?, buffer: UnsafeMutablePointer<UInt8>?, bufferSize: Int32) -> Int32 {
let context = Unmanaged<UniversalSoftwareVideoSourceImpl>.fromOpaque(userData!).takeUnretainedValue()
let data: Signal<Data, NoError>
let resourceSize: Int = context.size
@ -216,20 +217,11 @@ private final class UniversalSoftwareVideoSourceImpl {
let frame = MediaTrackDecodableFrame(type: .video, packet: packet, pts: pts, dts: dts, duration: duration)
frames.append(frame)
}
} else {
if endOfStream {
break
} else {
if let avFormatContext = self.avFormatContext, let videoStream = self.videoStream {
endOfStream = true
avFormatContext.seekFrame(forStreamIndex: Int32(videoStream.index), pts: 0)
} else {
endOfStream = true
break
}
}
}
}
if endOfStream {
if let videoStream = self.videoStream {
@ -240,8 +232,21 @@ private final class UniversalSoftwareVideoSourceImpl {
return (frames.first, endOfStream)
}
func readImage() -> (UIImage?, CGFloat, CGFloat, Bool) {
if let videoStream = self.videoStream {
private func seek(timestamp: Double) {
if let stream = self.videoStream, let avFormatContext = self.avFormatContext {
let pts = CMTimeMakeWithSeconds(timestamp, preferredTimescale: stream.timebase.timescale)
avFormatContext.seekFrame(forStreamIndex: Int32(stream.index), pts: pts.value, positionOnKeyframe: true)
stream.decoder.reset()
}
}
func readImage(at timestamp: Double) -> (UIImage?, CGFloat, CGFloat, Bool) {
guard let videoStream = self.videoStream, let _ = self.avFormatContext else {
return (nil, 0.0, 1.0, false)
}
self.seek(timestamp: timestamp)
self.currentNumberOfReads = 0
self.currentReadBytes = 0
for i in 0 ..< 10 {
@ -254,17 +259,6 @@ private final class UniversalSoftwareVideoSourceImpl {
}
}
return (nil, CGFloat(videoStream.rotationAngle), CGFloat(videoStream.aspect), true)
} else {
return (nil, 0.0, 1.0, false)
}
}
public func seek(timestamp: Double) {
if let stream = self.videoStream, let avFormatContext = self.avFormatContext {
let pts = CMTimeMakeWithSeconds(timestamp, preferredTimescale: stream.timebase.timescale)
avFormatContext.seekFrame(forStreamIndex: Int32(stream.index), pts: pts.value)
stream.decoder.reset()
}
}
}
@ -339,8 +333,7 @@ private final class UniversalSoftwareVideoSourceThread: NSObject {
source.requiredDataIsNotLocallyAvailable = params.requiredDataIsNotLocallyAvailable
source.state.set(.generatingFrame)
let startTime = CFAbsoluteTimeGetCurrent()
source.seek(timestamp: params.timestamp)
let image = source.readImage().0
let image = source.readImage(at: params.timestamp).0
params.completion(image)
source.state.set(.ready)
print("take frame: \(CFAbsoluteTimeGetCurrent() - startTime) s")

View File

@ -37,7 +37,7 @@ extern int FFMpegCodecIdMPEG4;
- (void)setIOContext:(FFMpegAVIOContext *)ioContext;
- (bool)openInput;
- (bool)findStreamInfo;
- (void)seekFrameForStreamIndex:(int32_t)streamIndex pts:(int64_t)pts;
- (void)seekFrameForStreamIndex:(int32_t)streamIndex pts:(int64_t)pts positionOnKeyframe:(bool)positionOnKeyframe;
- (bool)readFrameIntoPacket:(FFMpegPacket *)packet;
- (NSArray<NSNumber *> *)streamIndicesForType:(FFMpegAVFormatStreamType)type;
- (bool)isAttachedPicAtStreamIndex:(int32_t)streamIndex;

View File

@ -54,8 +54,12 @@ int FFMpegCodecIdMPEG4 = AV_CODEC_ID_MPEG4;
return result >= 0;
}
- (void)seekFrameForStreamIndex:(int32_t)streamIndex pts:(int64_t)pts {
av_seek_frame(_impl, streamIndex, pts, AVSEEK_FLAG_BACKWARD | AVSEEK_FLAG_FRAME);
- (void)seekFrameForStreamIndex:(int32_t)streamIndex pts:(int64_t)pts positionOnKeyframe:(bool)positionOnKeyframe {
int options = AVSEEK_FLAG_FRAME | AVSEEK_FLAG_BACKWARD;
if (!positionOnKeyframe) {
options |= AVSEEK_FLAG_ANY;
}
av_seek_frame(_impl, streamIndex, pts, options);
}
- (bool)readFrameIntoPacket:(FFMpegPacket *)packet {