From ddeb42e3232ff28162305b81db49bc5eccc0e123 Mon Sep 17 00:00:00 2001 From: Peter <> Date: Tue, 13 Nov 2018 22:51:52 +0400 Subject: [PATCH] Localization preview fixes --- TelegramUI/FetchVideoThumbnail.swift | 129 +++++++++--------- .../LanguageLinkPreviewContentNode.swift | 8 +- .../LocalizationListControllerNode.swift | 9 -- 3 files changed, 73 insertions(+), 73 deletions(-) diff --git a/TelegramUI/FetchVideoThumbnail.swift b/TelegramUI/FetchVideoThumbnail.swift index 6e8ad54145..c15a800039 100644 --- a/TelegramUI/FetchVideoThumbnail.swift +++ b/TelegramUI/FetchVideoThumbnail.swift @@ -13,30 +13,13 @@ private func readPacketCallback(userData: UnsafeMutableRawPointer?, buffer: Unsa return 0 } let context = Unmanaged.fromOpaque(userData!).takeUnretainedValue() - var bufferPointer = 0 - while bufferPointer < Int(bufferSize) && context.readOffset < context.size { - let bytesRemaining = Int(bufferSize) - bufferPointer - if context.readOffset < context.header.count { - let currentRead = min(bytesRemaining, context.header.count - context.readOffset) - if currentRead != 0 { - context.header.copyBytes(to: buffer.advanced(by: bufferPointer), from: context.readOffset ..< (context.readOffset + currentRead)) - context.readOffset += currentRead - bufferPointer += currentRead - } - } else if context.readOffset >= context.header.count && context.readOffset < context.header.count + context.spacing { - let currentRead = min(bytesRemaining, context.header.count + context.spacing - context.readOffset) - memset(buffer, 0, currentRead) - context.readOffset += currentRead - bufferPointer += currentRead - } else if context.readOffset >= context.header.count + context.spacing { - let normalizedReadOffset = context.readOffset - (context.header.count + context.spacing) - let currentRead = min(bytesRemaining, context.tail.count - normalizedReadOffset) - context.tail.copyBytes(to: buffer.advanced(by: bufferPointer), from: normalizedReadOffset ..< (normalizedReadOffset + currentRead)) - context.readOffset += currentRead - bufferPointer += currentRead + while !context.cancelled && !context.readingError { + if !RunLoop.current.run(mode: RunLoopMode.defaultRunLoopMode, before: .distantFuture) { + break } } - return Int32(bufferPointer) + return -1 + //return Int32(bufferPointer) } private func seekCallback(userData: UnsafeMutableRawPointer?, offset: Int64, whence: Int32) -> Int64 { @@ -70,24 +53,24 @@ private final class SoftwareVideoStream { } private final class FetchVideoThumbnailSource { - fileprivate let header: Data - fileprivate let spacing: Int - fileprivate let tail: Data + fileprivate let mediaBox: MediaBox + fileprivate let resourceReference: MediaResourceReference + fileprivate let size: Int32 fileprivate var readOffset: Int = 0 - private var readingError = false + fileprivate var cancelled = false + fileprivate var readingError = false + private var videoStream: SoftwareVideoStream? private var avIoContext: UnsafeMutablePointer? private var avFormatContext: UnsafeMutablePointer? - fileprivate let size: Int32 - init(header: Data, spacing: Int, tail: Data) { + init(mediaBox: MediaBox, resourceReference: MediaResourceReference, size: Int32) { let _ = FFMpegMediaFrameSourceContextHelpers.registerFFMpegGlobals - self.header = header - self.spacing = spacing - self.tail = tail - self.size = Int32(header.count + spacing + tail.count) + self.mediaBox = mediaBox + self.resourceReference = resourceReference + self.size = size var avFormatContextRef = avformat_alloc_context() guard let avFormatContext = avFormatContextRef else { @@ -235,7 +218,15 @@ private final class FetchVideoThumbnailSource { } private final class FetchVideoThumbnailSourceParameters: NSObject { + let mediaBox: MediaBox + let resourceReference: MediaResourceReference + let size: Int32 + init(mediaBox: MediaBox, resourceReference: MediaResourceReference, size: Int32) { + self.mediaBox = mediaBox + self.resourceReference = resourceReference + self.size = size + } } private final class FetchVideoThumbnailSourceTimerTarget: NSObject { @@ -243,6 +234,12 @@ private final class FetchVideoThumbnailSourceTimerTarget: NSObject { } } +private let threadContextKey = "FetchVideoThumbnailSourceThreadContext" + +private final class FetchVideoThumbnailSourceThreadContext { + +} + private final class FetchVideoThumbnailSourceThreadImpl: NSObject { private var timer: Foundation.Timer private var disposed = false @@ -259,6 +256,7 @@ private final class FetchVideoThumbnailSourceThreadImpl: NSObject { } @objc func entryPoint() { + Thread.current.threadDictionary[threadContextKey] = FetchVideoThumbnailSourceThreadContext() RunLoop.current.add(self.timer, forMode: RunLoopMode.defaultRunLoopMode) while !self.disposed { if !RunLoop.current.run(mode: RunLoopMode.defaultRunLoopMode, before: .distantFuture) { @@ -268,36 +266,8 @@ private final class FetchVideoThumbnailSourceThreadImpl: NSObject { } @objc func fetch(_ parameters: FetchVideoThumbnailSourceParameters) { - print("fetch") - } -} - -private let headerSize = 250 * 1024 -private let tailSize = 16 * 1024 - -func fetchedPartialVideoThumbnailData(postbox: Postbox, fileReference: FileMediaReference) -> Signal { - return Signal { subscriber in - guard let size = fileReference.media.size else { - subscriber.putCompletion() - return EmptyDisposable - } - let fetchedHead = fetchedMediaResource(postbox: postbox, reference: fileReference.resourceReference(fileReference.media.resource), range: (0 ..< min(size, headerSize), .elevated), statsCategory: .video, reportResultStatus: false, preferBackgroundReferenceRevalidation: false).start() - let fetchedTail = fetchedMediaResource(postbox: postbox, reference: fileReference.resourceReference(fileReference.media.resource), range: (max(0, size - tailSize) ..< size, .elevated), statsCategory: .video, reportResultStatus: false, preferBackgroundReferenceRevalidation: false).start() - - return ActionDisposable { - fetchedHead.dispose() - fetchedTail.dispose() - } - } -} - -private func partialVideoThumbnailData(postbox: Postbox, resource: MediaResource) -> Signal<(Data, Int, Data), NoError> { - guard let size = resource.size else { - return .complete() - } - return combineLatest(postbox.mediaBox.resourceData(resource, size: size, in: 0 ..< min(size, headerSize)), postbox.mediaBox.resourceData(resource, size: size, in: max(0, size - tailSize) ..< size)) - |> mapToSignal { header, tail -> Signal<(Data, Int, Data), NoError> in - return .single((header, max(0, size - header.count - tail.count), tail)) + let source = FetchVideoThumbnailSource(mediaBox: parameters.mediaBox, resourceReference: parameters.resourceReference, size: parameters.size) + let _ = source.readFrame() } } @@ -363,7 +333,7 @@ private func imageFromSampleBuffer(sampleBuffer: CMSampleBuffer) -> UIImage? { } -func fetchPartialVideoThumbnail(postbox: Postbox, resource: MediaResource) -> Signal { +/*func fetchPartialVideoThumbnail(postbox: Postbox, resource: MediaResource) -> Signal { return partialVideoThumbnailData(postbox: postbox, resource: resource) |> take(1) |> mapToSignal { header, spacing, tail -> Signal in @@ -400,4 +370,37 @@ func fetchPartialVideoThumbnail(postbox: Postbox, resource: MediaResource) -> Si impl.perform(#selector(impl.dispose), on: thread, with: nil, waitUntilDone: false) } }*/ +}*/ + +func fetchedStreamingVideoThumbnail(postbox: Postbox, fileReference: FileMediaReference) -> Signal { + return Signal { subscriber in + let resourceReference = fileReference.resourceReference(fileReference.media.resource) + guard let size = resourceReference.resource.size else { + subscriber.putCompletion() + return EmptyDisposable + } + let impl = FetchVideoThumbnailSourceThreadImpl() + let thread = Thread(target: impl, selector: #selector(impl.entryPoint), object: nil) + thread.name = "fetchedStreamingVideoThumbnail" + impl.perform(#selector(impl.fetch(_:)), on: thread, with: FetchVideoThumbnailSourceParameters(mediaBox: postbox.mediaBox, resourceReference: resourceReference, size: Int32(size)), waitUntilDone: false) + thread.start() + + return ActionDisposable { + impl.perform(#selector(impl.dispose), on: thread, with: nil, waitUntilDone: false) + } + } +} + +func streamingVideoThumbnail(postbox: Postbox, fileReference: FileMediaReference) -> Signal { + return Signal { subscriber in + let impl = FetchVideoThumbnailSourceThreadImpl() + let thread = Thread(target: impl, selector: #selector(impl.entryPoint), object: nil) + thread.name = "streamingVideoThumbnail" + //impl.perform(#selector(impl.fetch(_:)), on: thread, with: FetchVideoThumbnailSourceParameters(), waitUntilDone: false) + thread.start() + + return ActionDisposable { + impl.perform(#selector(impl.dispose), on: thread, with: nil, waitUntilDone: false) + } + } } diff --git a/TelegramUI/LanguageLinkPreviewContentNode.swift b/TelegramUI/LanguageLinkPreviewContentNode.swift index 636b1ccdb5..42b746b465 100644 --- a/TelegramUI/LanguageLinkPreviewContentNode.swift +++ b/TelegramUI/LanguageLinkPreviewContentNode.swift @@ -53,7 +53,13 @@ final class LanguageLinkPreviewContentNode: ASDisplayNode, ShareContentContainer } self.textNode.tapAttributeAction = { attributes in if let _ = attributes[NSAttributedStringKey(rawValue: TelegramTextAttributes.URL)] { - openTranslationUrl("https://translations.telegram.org/\(localizationInfo.languageCode)/") + let url: String + if localizationInfo.platformUrl.isEmpty { + url = localizationInfo.platformUrl + } else { + url = "https://translations.telegram.org/\(localizationInfo.languageCode)/" + } + openTranslationUrl(url) } } } diff --git a/TelegramUI/LocalizationListControllerNode.swift b/TelegramUI/LocalizationListControllerNode.swift index a017767aa9..2c5310eb7d 100644 --- a/TelegramUI/LocalizationListControllerNode.swift +++ b/TelegramUI/LocalizationListControllerNode.swift @@ -13,7 +13,6 @@ private enum LanguageListSection: ItemListSectionId { private enum LanguageListEntryId: Hashable { case search case localization(String) - case unofficialHeader } private enum LanguageListEntryType { @@ -24,7 +23,6 @@ private enum LanguageListEntryType { private enum LanguageListEntry: Comparable, Identifiable { case search(Int) case localization(index: Int, info: LocalizationInfo, type: LanguageListEntryType, selected: Bool, activity: Bool, revealed: Bool, editing: Bool) - case unofficialHeader(Int) var stableId: LanguageListEntryId { switch self { @@ -32,8 +30,6 @@ private enum LanguageListEntry: Comparable, Identifiable { return .search case let .localization(_, info, _, _, _, _, _): return .localization(info.languageCode) - case .unofficialHeader: - return .unofficialHeader } } @@ -43,8 +39,6 @@ private enum LanguageListEntry: Comparable, Identifiable { return index case let .localization(index, _, _, _, _, _, _): return index - case let .unofficialHeader(index): - return index } } @@ -62,8 +56,6 @@ private enum LanguageListEntry: Comparable, Identifiable { return LocalizationListItem(theme: theme, strings: strings, id: info.languageCode, title: info.title, subtitle: info.localizedTitle, checked: selected, activity: activity, editing: LocalizationListItemEditing(editable: !searchMode && !info.isOfficial, editing: editing, revealed: revealed, reorderable: false), sectionId: type == .official ? LanguageListSection.official.rawValue : LanguageListSection.unofficial.rawValue, alwaysPlain: searchMode, action: { selectLocalization(info) }, setItemWithRevealedOptions: setItemWithRevealedOptions, removeItem: removeItem) - case .unofficialHeader: - return ItemListSectionHeaderItem(theme: theme, text: strings.Settings_AppLanguage_Unofficial, sectionId: LanguageListSection.unofficial.rawValue) } } } @@ -396,7 +388,6 @@ final class LocalizationListControllerNode: ViewControllerTracingNode { updateCanStartEditing(isEditing) } if !availableSavedLocalizations.isEmpty { - //entries.append(.unofficialHeader(entries.count)) for info in availableSavedLocalizations { if existingIds.contains(info.languageCode) { continue