mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Fix video frame duration handling
This commit is contained in:
parent
1b010bc17f
commit
25d8dfc800
@ -10,6 +10,9 @@ objc_library(
|
|||||||
hdrs = glob([
|
hdrs = glob([
|
||||||
"Public/**/*.h",
|
"Public/**/*.h",
|
||||||
]),
|
]),
|
||||||
|
copts = [
|
||||||
|
"-Werror",
|
||||||
|
],
|
||||||
includes = [
|
includes = [
|
||||||
"Public",
|
"Public",
|
||||||
],
|
],
|
||||||
|
@ -3,14 +3,14 @@
|
|||||||
#import "libavcodec/avcodec.h"
|
#import "libavcodec/avcodec.h"
|
||||||
|
|
||||||
@interface FFMpegAVCodec () {
|
@interface FFMpegAVCodec () {
|
||||||
AVCodec *_impl;
|
AVCodec const *_impl;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation FFMpegAVCodec
|
@implementation FFMpegAVCodec
|
||||||
|
|
||||||
- (instancetype)initWithImpl:(AVCodec *)impl {
|
- (instancetype)initWithImpl:(AVCodec const *)impl {
|
||||||
self = [super init];
|
self = [super init];
|
||||||
if (self != nil) {
|
if (self != nil) {
|
||||||
_impl = impl;
|
_impl = impl;
|
||||||
@ -19,7 +19,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
+ (FFMpegAVCodec * _Nullable)findForId:(int)codecId {
|
+ (FFMpegAVCodec * _Nullable)findForId:(int)codecId {
|
||||||
AVCodec *codec = avcodec_find_decoder(codecId);
|
AVCodec const *codec = avcodec_find_decoder(codecId);
|
||||||
if (codec) {
|
if (codec) {
|
||||||
return [[FFMpegAVCodec alloc] initWithImpl:codec];
|
return [[FFMpegAVCodec alloc] initWithImpl:codec];
|
||||||
} else {
|
} else {
|
||||||
@ -28,7 +28,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (void *)impl {
|
- (void *)impl {
|
||||||
return _impl;
|
return (void *)_impl;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -35,7 +35,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (int32_t)channels {
|
- (int32_t)channels {
|
||||||
return (int32_t)_impl->channels;
|
return (int32_t)_impl->ch_layout.nb_channels;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (int32_t)sampleRate {
|
- (int32_t)sampleRate {
|
||||||
|
@ -45,7 +45,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (int64_t)duration {
|
- (int64_t)duration {
|
||||||
return _impl->pkt_duration;
|
return _impl->duration;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (FFMpegAVFrameColorRange)colorRange {
|
- (FFMpegAVFrameColorRange)colorRange {
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
#import "libavformat/avformat.h"
|
#import "libavformat/avformat.h"
|
||||||
|
|
||||||
@interface FFMpegPacket () {
|
@interface FFMpegPacket () {
|
||||||
AVPacket _impl;
|
AVPacket *_impl;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@ -16,49 +16,49 @@
|
|||||||
- (instancetype)init {
|
- (instancetype)init {
|
||||||
self = [super init];
|
self = [super init];
|
||||||
if (self != nil) {
|
if (self != nil) {
|
||||||
av_init_packet(&_impl);
|
_impl = av_packet_alloc();
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)dealloc {
|
- (void)dealloc {
|
||||||
av_packet_unref(&_impl);
|
av_packet_free(&_impl);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void *)impl {
|
- (void *)impl {
|
||||||
return &_impl;
|
return _impl;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (int64_t)pts {
|
- (int64_t)pts {
|
||||||
if (_impl.pts == 0x8000000000000000) {
|
if (_impl->pts == 0x8000000000000000) {
|
||||||
return _impl.dts;
|
return _impl->dts;
|
||||||
} else {
|
} else {
|
||||||
return _impl.pts;
|
return _impl->pts;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (int64_t)dts {
|
- (int64_t)dts {
|
||||||
return _impl.dts;
|
return _impl->dts;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (int64_t)duration {
|
- (int64_t)duration {
|
||||||
return _impl.duration;
|
return _impl->duration;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (int32_t)streamIndex {
|
- (int32_t)streamIndex {
|
||||||
return (int32_t)_impl.stream_index;
|
return (int32_t)_impl->stream_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (int32_t)size {
|
- (int32_t)size {
|
||||||
return (int32_t)_impl.size;
|
return (int32_t)_impl->size;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (uint8_t *)data {
|
- (uint8_t *)data {
|
||||||
return _impl.data;
|
return _impl->data;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (int32_t)sendToDecoder:(FFMpegAVCodecContext *)codecContext {
|
- (int32_t)sendToDecoder:(FFMpegAVCodecContext *)codecContext {
|
||||||
return avcodec_send_packet((AVCodecContext *)[codecContext impl], &_impl);
|
return avcodec_send_packet((AVCodecContext *)[codecContext impl], _impl);
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -34,18 +34,18 @@
|
|||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
static int readPacketImpl(void * _Nullable opaque, uint8_t * _Nullable buffer, int length) {
|
/*static int readPacketImpl(void * _Nullable opaque, uint8_t * _Nullable buffer, int length) {
|
||||||
FFMpegRemuxerContext *context = (__bridge FFMpegRemuxerContext *)opaque;
|
FFMpegRemuxerContext *context = (__bridge FFMpegRemuxerContext *)opaque;
|
||||||
context->_offset += length;
|
context->_offset += length;
|
||||||
printf("read %lld bytes (offset is now %lld)\n", (int64_t)length, context->_offset);
|
printf("read %lld bytes (offset is now %lld)\n", (int64_t)length, context->_offset);
|
||||||
return read(context->_fd, buffer, length);
|
return (int)read(context->_fd, buffer, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int writePacketImpl(void * _Nullable opaque, uint8_t * _Nullable buffer, int length) {
|
static int writePacketImpl(void * _Nullable opaque, uint8_t * _Nullable buffer, int length) {
|
||||||
FFMpegRemuxerContext *context = (__bridge FFMpegRemuxerContext *)opaque;
|
FFMpegRemuxerContext *context = (__bridge FFMpegRemuxerContext *)opaque;
|
||||||
context->_offset += length;
|
context->_offset += length;
|
||||||
printf("write %lld bytes (offset is now %lld)\n", (int64_t)length, context->_offset);
|
printf("write %lld bytes (offset is now %lld)\n", (int64_t)length, context->_offset);
|
||||||
return write(context->_fd, buffer, length);
|
return (int)write(context->_fd, buffer, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int64_t seekImpl(void * _Nullable opaque, int64_t offset, int whence) {
|
static int64_t seekImpl(void * _Nullable opaque, int64_t offset, int whence) {
|
||||||
@ -57,7 +57,7 @@ static int64_t seekImpl(void * _Nullable opaque, int64_t offset, int whence) {
|
|||||||
context->_offset = offset;
|
context->_offset = offset;
|
||||||
return lseek(context->_fd, offset, SEEK_SET);
|
return lseek(context->_fd, offset, SEEK_SET);
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
|
|
||||||
@implementation FFMpegRemuxer
|
@implementation FFMpegRemuxer
|
||||||
|
|
||||||
|
@ -52,7 +52,9 @@
|
|||||||
swr_free(&_context);
|
swr_free(&_context);
|
||||||
_context = NULL;
|
_context = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||||
_context = swr_alloc_set_opts(NULL,
|
_context = swr_alloc_set_opts(NULL,
|
||||||
av_get_default_channel_layout((int)_destinationChannelCount),
|
av_get_default_channel_layout((int)_destinationChannelCount),
|
||||||
(enum AVSampleFormat)_destinationSampleFormat,
|
(enum AVSampleFormat)_destinationSampleFormat,
|
||||||
@ -62,6 +64,7 @@
|
|||||||
(int)_sourceSampleRate,
|
(int)_sourceSampleRate,
|
||||||
0,
|
0,
|
||||||
NULL);
|
NULL);
|
||||||
|
#pragma clang diagnostic pop
|
||||||
_currentSourceChannelCount = channelCount;
|
_currentSourceChannelCount = channelCount;
|
||||||
_ratio = MAX(1, _destinationSampleRate / MAX(_sourceSampleRate, 1)) * MAX(1, _destinationChannelCount / channelCount) * 2;
|
_ratio = MAX(1, _destinationSampleRate / MAX(_sourceSampleRate, 1)) * MAX(1, _destinationChannelCount / channelCount) * 2;
|
||||||
if (_context) {
|
if (_context) {
|
||||||
@ -72,7 +75,7 @@
|
|||||||
- (NSData * _Nullable)resample:(FFMpegAVFrame *)frame {
|
- (NSData * _Nullable)resample:(FFMpegAVFrame *)frame {
|
||||||
AVFrame *frameImpl = (AVFrame *)[frame impl];
|
AVFrame *frameImpl = (AVFrame *)[frame impl];
|
||||||
|
|
||||||
int numChannels = frameImpl->channels;
|
int numChannels = frameImpl->ch_layout.nb_channels;
|
||||||
if (numChannels != _currentSourceChannelCount) {
|
if (numChannels != _currentSourceChannelCount) {
|
||||||
[self resetContextForChannelCount:numChannels];
|
[self resetContextForChannelCount:numChannels];
|
||||||
}
|
}
|
||||||
|
@ -65,7 +65,7 @@ final class FFMpegAudioFrameDecoder: MediaTrackFrameDecoder {
|
|||||||
while true {
|
while true {
|
||||||
let result = self.codecContext.receive(into: self.audioFrame)
|
let result = self.codecContext.receive(into: self.audioFrame)
|
||||||
if case .success = result {
|
if case .success = result {
|
||||||
if let convertedFrame = convertAudioFrame(self.audioFrame, pts: frame.pts, duration: frame.duration) {
|
if let convertedFrame = convertAudioFrame(self.audioFrame, pts: frame.pts) {
|
||||||
self.delayedFrames.append(convertedFrame)
|
self.delayedFrames.append(convertedFrame)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -121,7 +121,7 @@ final class FFMpegAudioFrameDecoder: MediaTrackFrameDecoder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func convertAudioFrame(_ frame: FFMpegAVFrame, pts: CMTime, duration: CMTime) -> MediaTrackFrame? {
|
private func convertAudioFrame(_ frame: FFMpegAVFrame, pts: CMTime) -> MediaTrackFrame? {
|
||||||
guard let data = self.swrContext.resample(frame) else {
|
guard let data = self.swrContext.resample(frame) else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -135,18 +135,12 @@ final class FFMpegAudioFrameDecoder: MediaTrackFrameDecoder {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//var timingInfo = CMSampleTimingInfo(duration: duration, presentationTimeStamp: pts, decodeTimeStamp: pts)
|
|
||||||
var sampleBuffer: CMSampleBuffer?
|
var sampleBuffer: CMSampleBuffer?
|
||||||
//var sampleSize = data.count
|
|
||||||
|
|
||||||
guard CMAudioSampleBufferCreateReadyWithPacketDescriptions(allocator: nil, dataBuffer: blockBuffer!, formatDescription: self.formatDescription, sampleCount: Int(data.count / 2), presentationTimeStamp: pts, packetDescriptions: nil, sampleBufferOut: &sampleBuffer) == noErr else {
|
guard CMAudioSampleBufferCreateReadyWithPacketDescriptions(allocator: nil, dataBuffer: blockBuffer!, formatDescription: self.formatDescription, sampleCount: Int(data.count / 2), presentationTimeStamp: pts, packetDescriptions: nil, sampleBufferOut: &sampleBuffer) == noErr else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
/*guard CMSampleBufferCreate(allocator: nil, dataBuffer: blockBuffer, dataReady: true, makeDataReadyCallback: nil, refcon: nil, formatDescription: self.formatDescription, sampleCount: Int(frame.duration), sampleTimingEntryCount: 1, sampleTimingArray: &timingInfo, sampleSizeEntryCount: 1, sampleSizeArray: &sampleSize, sampleBufferOut: &sampleBuffer) == noErr else {
|
|
||||||
return nil
|
|
||||||
}*/
|
|
||||||
|
|
||||||
let resetDecoder = self.resetDecoderOnNextFrame
|
let resetDecoder = self.resetDecoderOnNextFrame
|
||||||
self.resetDecoderOnNextFrame = false
|
self.resetDecoderOnNextFrame = false
|
||||||
|
|
||||||
|
@ -725,7 +725,7 @@ private func videoFrameFromPacket(_ packet: FFMpegPacket, videoStream: StreamCon
|
|||||||
if frameDuration != 0 {
|
if frameDuration != 0 {
|
||||||
duration = CMTimeMake(value: frameDuration * videoStream.timebase.value, timescale: videoStream.timebase.timescale)
|
duration = CMTimeMake(value: frameDuration * videoStream.timebase.value, timescale: videoStream.timebase.timescale)
|
||||||
} else {
|
} else {
|
||||||
duration = videoStream.fps
|
duration = CMTimeMake(value: Int64(videoStream.fps.timescale), timescale: Int32(videoStream.fps.value))
|
||||||
}
|
}
|
||||||
|
|
||||||
return MediaTrackDecodableFrame(type: .video, packet: packet, pts: pts, dts: dts, duration: duration)
|
return MediaTrackDecodableFrame(type: .video, packet: packet, pts: pts, dts: dts, duration: duration)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user