mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
ffmpeg sync
This commit is contained in:
parent
7f78d57780
commit
d3a399ed6a
@ -27,6 +27,7 @@ typedef struct FFMpegStreamMetrics {
|
|||||||
extern int FFMpegCodecIdH264;
|
extern int FFMpegCodecIdH264;
|
||||||
extern int FFMpegCodecIdHEVC;
|
extern int FFMpegCodecIdHEVC;
|
||||||
extern int FFMpegCodecIdMPEG4;
|
extern int FFMpegCodecIdMPEG4;
|
||||||
|
extern int FFMpegCodecIdVP9;
|
||||||
|
|
||||||
@class FFMpegAVCodecContext;
|
@class FFMpegAVCodecContext;
|
||||||
|
|
||||||
@ -47,6 +48,8 @@ extern int FFMpegCodecIdMPEG4;
|
|||||||
- (FFMpegFpsAndTimebase)fpsAndTimebaseForStreamIndex:(int32_t)streamIndex defaultTimeBase:(CMTime)defaultTimeBase;
|
- (FFMpegFpsAndTimebase)fpsAndTimebaseForStreamIndex:(int32_t)streamIndex defaultTimeBase:(CMTime)defaultTimeBase;
|
||||||
- (FFMpegStreamMetrics)metricsForStreamAtIndex:(int32_t)streamIndex;
|
- (FFMpegStreamMetrics)metricsForStreamAtIndex:(int32_t)streamIndex;
|
||||||
|
|
||||||
|
- (void)forceVideoCodecId:(int)videoCodecId;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
NS_ASSUME_NONNULL_END
|
||||||
|
@ -7,6 +7,11 @@ typedef NS_ENUM(NSUInteger, FFMpegAVFrameColorRange) {
|
|||||||
FFMpegAVFrameColorRangeFull
|
FFMpegAVFrameColorRangeFull
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef NS_ENUM(NSUInteger, FFMpegAVFramePixelFormat) {
|
||||||
|
FFMpegAVFramePixelFormatYUV,
|
||||||
|
FFMpegAVFramePixelFormatYUVA
|
||||||
|
};
|
||||||
|
|
||||||
@interface FFMpegAVFrame : NSObject
|
@interface FFMpegAVFrame : NSObject
|
||||||
|
|
||||||
@property (nonatomic, readonly) int32_t width;
|
@property (nonatomic, readonly) int32_t width;
|
||||||
@ -16,6 +21,7 @@ typedef NS_ENUM(NSUInteger, FFMpegAVFrameColorRange) {
|
|||||||
@property (nonatomic, readonly) int64_t pts;
|
@property (nonatomic, readonly) int64_t pts;
|
||||||
@property (nonatomic, readonly) int64_t duration;
|
@property (nonatomic, readonly) int64_t duration;
|
||||||
@property (nonatomic, readonly) FFMpegAVFrameColorRange colorRange;
|
@property (nonatomic, readonly) FFMpegAVFrameColorRange colorRange;
|
||||||
|
@property (nonatomic, readonly) FFMpegAVFramePixelFormat pixelFormat;
|
||||||
|
|
||||||
- (instancetype)init;
|
- (instancetype)init;
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
int FFMpegCodecIdH264 = AV_CODEC_ID_H264;
|
int FFMpegCodecIdH264 = AV_CODEC_ID_H264;
|
||||||
int FFMpegCodecIdHEVC = AV_CODEC_ID_HEVC;
|
int FFMpegCodecIdHEVC = AV_CODEC_ID_HEVC;
|
||||||
int FFMpegCodecIdMPEG4 = AV_CODEC_ID_MPEG4;
|
int FFMpegCodecIdMPEG4 = AV_CODEC_ID_MPEG4;
|
||||||
|
int FFMpegCodecIdVP9 = AV_CODEC_ID_VP9;
|
||||||
|
|
||||||
@interface FFMpegAVFormatContext () {
|
@interface FFMpegAVFormatContext () {
|
||||||
AVFormatContext *_impl;
|
AVFormatContext *_impl;
|
||||||
@ -144,4 +145,9 @@ int FFMpegCodecIdMPEG4 = AV_CODEC_ID_MPEG4;
|
|||||||
return (FFMpegStreamMetrics){ .width = _impl->streams[streamIndex]->codecpar->width, .height = _impl->streams[streamIndex]->codecpar->height, .rotationAngle = rotationAngle, .extradata = _impl->streams[streamIndex]->codecpar->extradata, .extradataSize = _impl->streams[streamIndex]->codecpar->extradata_size };
|
return (FFMpegStreamMetrics){ .width = _impl->streams[streamIndex]->codecpar->width, .height = _impl->streams[streamIndex]->codecpar->height, .rotationAngle = rotationAngle, .extradata = _impl->streams[streamIndex]->codecpar->extradata, .extradataSize = _impl->streams[streamIndex]->codecpar->extradata_size };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)forceVideoCodecId:(int)videoCodecId {
|
||||||
|
_impl->video_codec_id = videoCodecId;
|
||||||
|
_impl->video_codec = avcodec_find_decoder(videoCodecId);
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -62,4 +62,13 @@
|
|||||||
return _impl;
|
return _impl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (FFMpegAVFramePixelFormat)pixelFormat {
|
||||||
|
switch (_impl->format) {
|
||||||
|
case AV_PIX_FMT_YUVA420P:
|
||||||
|
return FFMpegAVFramePixelFormatYUVA;
|
||||||
|
default:
|
||||||
|
return FFMpegAVFramePixelFormatYUV;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -245,6 +245,17 @@ public final class FFMpegMediaVideoFrameDecoder: MediaTrackFrameDecoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var pixelBufferRef: CVPixelBuffer?
|
var pixelBufferRef: CVPixelBuffer?
|
||||||
|
|
||||||
|
let pixelFormat: OSType
|
||||||
|
switch frame.pixelFormat {
|
||||||
|
case .YUV:
|
||||||
|
pixelFormat = kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange
|
||||||
|
case .YUVA:
|
||||||
|
pixelFormat = kCVPixelFormatType_420YpCbCr8VideoRange_8A_TriPlanar
|
||||||
|
default:
|
||||||
|
pixelFormat = kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange
|
||||||
|
}
|
||||||
|
|
||||||
if let pixelBufferPool = self.pixelBufferPool {
|
if let pixelBufferPool = self.pixelBufferPool {
|
||||||
let auxAttributes: [String: Any] = [kCVPixelBufferPoolAllocationThresholdKey as String: bufferCount as NSNumber];
|
let auxAttributes: [String: Any] = [kCVPixelBufferPoolAllocationThresholdKey as String: bufferCount as NSNumber];
|
||||||
let err = CVPixelBufferPoolCreatePixelBufferWithAuxAttributes(kCFAllocatorDefault, pixelBufferPool, auxAttributes as CFDictionary, &pixelBufferRef)
|
let err = CVPixelBufferPoolCreatePixelBufferWithAuxAttributes(kCFAllocatorDefault, pixelBufferPool, auxAttributes as CFDictionary, &pixelBufferRef)
|
||||||
@ -262,7 +273,7 @@ public final class FFMpegMediaVideoFrameDecoder: MediaTrackFrameDecoder {
|
|||||||
CVPixelBufferCreate(kCFAllocatorDefault,
|
CVPixelBufferCreate(kCFAllocatorDefault,
|
||||||
Int(frame.width),
|
Int(frame.width),
|
||||||
Int(frame.height),
|
Int(frame.height),
|
||||||
kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange,
|
pixelFormat,
|
||||||
options as CFDictionary,
|
options as CFDictionary,
|
||||||
&pixelBufferRef)
|
&pixelBufferRef)
|
||||||
}
|
}
|
||||||
@ -273,6 +284,7 @@ public final class FFMpegMediaVideoFrameDecoder: MediaTrackFrameDecoder {
|
|||||||
|
|
||||||
let srcPlaneSize = Int(frame.lineSize[1]) * Int(frame.height / 2)
|
let srcPlaneSize = Int(frame.lineSize[1]) * Int(frame.height / 2)
|
||||||
let dstPlaneSize = srcPlaneSize * 2
|
let dstPlaneSize = srcPlaneSize * 2
|
||||||
|
|
||||||
let dstPlane: UnsafeMutablePointer<UInt8>
|
let dstPlane: UnsafeMutablePointer<UInt8>
|
||||||
if let (existingDstPlane, existingDstPlaneSize) = self.dstPlane, existingDstPlaneSize == dstPlaneSize {
|
if let (existingDstPlane, existingDstPlaneSize) = self.dstPlane, existingDstPlaneSize == dstPlaneSize {
|
||||||
dstPlane = existingDstPlane
|
dstPlane = existingDstPlane
|
||||||
@ -285,25 +297,26 @@ public final class FFMpegMediaVideoFrameDecoder: MediaTrackFrameDecoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fillDstPlane(dstPlane, frame.data[1]!, frame.data[2]!, srcPlaneSize)
|
fillDstPlane(dstPlane, frame.data[1]!, frame.data[2]!, srcPlaneSize)
|
||||||
|
|
||||||
let status = CVPixelBufferLockBaseAddress(pixelBuffer, [])
|
let status = CVPixelBufferLockBaseAddress(pixelBuffer, [])
|
||||||
if status != kCVReturnSuccess {
|
if status != kCVReturnSuccess {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
let bytePerRowY = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 0)
|
let bytesPerRowY = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 0)
|
||||||
|
|
||||||
let bytesPerRowUV = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 1)
|
let bytesPerRowUV = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 1)
|
||||||
|
let bytesPerRowA = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 2)
|
||||||
|
|
||||||
var base = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 0)!
|
var base = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 0)!
|
||||||
if bytePerRowY == frame.lineSize[0] {
|
if bytesPerRowY == frame.lineSize[0] {
|
||||||
memcpy(base, frame.data[0]!, bytePerRowY * Int(frame.height))
|
memcpy(base, frame.data[0]!, bytesPerRowY * Int(frame.height))
|
||||||
} else {
|
} else {
|
||||||
var dest = base
|
var dest = base
|
||||||
var src = frame.data[0]!
|
var src = frame.data[0]!
|
||||||
let linesize = Int(frame.lineSize[0])
|
let linesize = Int(frame.lineSize[0])
|
||||||
for _ in 0 ..< Int(frame.height) {
|
for _ in 0 ..< Int(frame.height) {
|
||||||
memcpy(dest, src, linesize)
|
memcpy(dest, src, linesize)
|
||||||
dest = dest.advanced(by: bytePerRowY)
|
dest = dest.advanced(by: bytesPerRowY)
|
||||||
src = src.advanced(by: linesize)
|
src = src.advanced(by: linesize)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -322,6 +335,22 @@ public final class FFMpegMediaVideoFrameDecoder: MediaTrackFrameDecoder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if case .YUVA = frame.pixelFormat {
|
||||||
|
base = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 2)!
|
||||||
|
if bytesPerRowA == frame.lineSize[3] {
|
||||||
|
memcpy(base, frame.data[3]!, bytesPerRowA * Int(frame.height))
|
||||||
|
} else {
|
||||||
|
var dest = base
|
||||||
|
var src = frame.data[3]!
|
||||||
|
let linesize = Int(frame.lineSize[3])
|
||||||
|
for _ in 0 ..< Int(frame.height) {
|
||||||
|
memcpy(dest, src, linesize)
|
||||||
|
dest = dest.advanced(by: bytesPerRowA)
|
||||||
|
src = src.advanced(by: linesize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
CVPixelBufferUnlockBaseAddress(pixelBuffer, [])
|
CVPixelBufferUnlockBaseAddress(pixelBuffer, [])
|
||||||
|
|
||||||
var formatRef: CMVideoFormatDescription?
|
var formatRef: CMVideoFormatDescription?
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
#if !os(macOS)
|
||||||
import UIKit
|
import UIKit
|
||||||
|
#else
|
||||||
|
import AppKit
|
||||||
|
#endif
|
||||||
import CoreMedia
|
import CoreMedia
|
||||||
import SwiftSignalKit
|
import SwiftSignalKit
|
||||||
import FFMpegBinding
|
import FFMpegBinding
|
||||||
@ -57,7 +61,7 @@ public final class SoftwareVideoSource {
|
|||||||
private var enqueuedFrames: [(MediaTrackFrame, CGFloat, CGFloat, Bool)] = []
|
private var enqueuedFrames: [(MediaTrackFrame, CGFloat, CGFloat, Bool)] = []
|
||||||
private var hasReadToEnd: Bool = false
|
private var hasReadToEnd: Bool = false
|
||||||
|
|
||||||
public init(path: String) {
|
public init(path: String, hintVP9: Bool) {
|
||||||
let _ = FFMpegMediaFrameSourceContextHelpers.registerFFMpegGlobals
|
let _ = FFMpegMediaFrameSourceContextHelpers.registerFFMpegGlobals
|
||||||
|
|
||||||
var s = stat()
|
var s = stat()
|
||||||
@ -74,7 +78,9 @@ public final class SoftwareVideoSource {
|
|||||||
self.path = path
|
self.path = path
|
||||||
|
|
||||||
let avFormatContext = FFMpegAVFormatContext()
|
let avFormatContext = FFMpegAVFormatContext()
|
||||||
|
if hintVP9 {
|
||||||
|
avFormatContext.forceVideoCodecId(FFMpegCodecIdVP9)
|
||||||
|
}
|
||||||
let ioBufferSize = 64 * 1024
|
let ioBufferSize = 64 * 1024
|
||||||
|
|
||||||
let avIoContext = FFMpegAVIOContext(bufferSize: Int32(ioBufferSize), opaqueContext: Unmanaged.passUnretained(self).toOpaque(), readPacket: readPacketCallback, writePacket: nil, seek: seekCallback)
|
let avIoContext = FFMpegAVIOContext(bufferSize: Int32(ioBufferSize), opaqueContext: Unmanaged.passUnretained(self).toOpaque(), readPacket: readPacketCallback, writePacket: nil, seek: seekCallback)
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
#if !os(macOS)
|
||||||
import UIKit
|
import UIKit
|
||||||
|
#else
|
||||||
|
import AppKit
|
||||||
|
#endif
|
||||||
import SwiftSignalKit
|
import SwiftSignalKit
|
||||||
import Postbox
|
import Postbox
|
||||||
import TelegramCore
|
import TelegramCore
|
||||||
@ -111,7 +115,7 @@ private final class UniversalSoftwareVideoSourceImpl {
|
|||||||
fileprivate var currentNumberOfReads: Int = 0
|
fileprivate var currentNumberOfReads: Int = 0
|
||||||
fileprivate var currentReadBytes: Int = 0
|
fileprivate var currentReadBytes: Int = 0
|
||||||
|
|
||||||
init?(mediaBox: MediaBox, fileReference: FileMediaReference, state: ValuePromise<UniversalSoftwareVideoSourceState>, cancelInitialization: Signal<Bool, NoError>, automaticallyFetchHeader: Bool) {
|
init?(mediaBox: MediaBox, fileReference: FileMediaReference, state: ValuePromise<UniversalSoftwareVideoSourceState>, cancelInitialization: Signal<Bool, NoError>, automaticallyFetchHeader: Bool, hintVP9: Bool = false) {
|
||||||
guard let size = fileReference.media.size else {
|
guard let size = fileReference.media.size else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -134,6 +138,9 @@ private final class UniversalSoftwareVideoSourceImpl {
|
|||||||
self.avIoContext = avIoContext
|
self.avIoContext = avIoContext
|
||||||
|
|
||||||
let avFormatContext = FFMpegAVFormatContext()
|
let avFormatContext = FFMpegAVFormatContext()
|
||||||
|
if hintVP9 {
|
||||||
|
avFormatContext.forceVideoCodecId(FFMpegCodecIdVP9)
|
||||||
|
}
|
||||||
avFormatContext.setIO(avIoContext)
|
avFormatContext.setIO(avIoContext)
|
||||||
|
|
||||||
if !avFormatContext.openInput() {
|
if !avFormatContext.openInput() {
|
||||||
@ -286,19 +293,22 @@ private final class UniversalSoftwareVideoSourceThreadParams: NSObject {
|
|||||||
let state: ValuePromise<UniversalSoftwareVideoSourceState>
|
let state: ValuePromise<UniversalSoftwareVideoSourceState>
|
||||||
let cancelInitialization: Signal<Bool, NoError>
|
let cancelInitialization: Signal<Bool, NoError>
|
||||||
let automaticallyFetchHeader: Bool
|
let automaticallyFetchHeader: Bool
|
||||||
|
let hintVP9: Bool
|
||||||
|
|
||||||
init(
|
init(
|
||||||
mediaBox: MediaBox,
|
mediaBox: MediaBox,
|
||||||
fileReference: FileMediaReference,
|
fileReference: FileMediaReference,
|
||||||
state: ValuePromise<UniversalSoftwareVideoSourceState>,
|
state: ValuePromise<UniversalSoftwareVideoSourceState>,
|
||||||
cancelInitialization: Signal<Bool, NoError>,
|
cancelInitialization: Signal<Bool, NoError>,
|
||||||
automaticallyFetchHeader: Bool
|
automaticallyFetchHeader: Bool,
|
||||||
|
hintVP9: Bool
|
||||||
) {
|
) {
|
||||||
self.mediaBox = mediaBox
|
self.mediaBox = mediaBox
|
||||||
self.fileReference = fileReference
|
self.fileReference = fileReference
|
||||||
self.state = state
|
self.state = state
|
||||||
self.cancelInitialization = cancelInitialization
|
self.cancelInitialization = cancelInitialization
|
||||||
self.automaticallyFetchHeader = automaticallyFetchHeader
|
self.automaticallyFetchHeader = automaticallyFetchHeader
|
||||||
|
self.hintVP9 = hintVP9
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -381,8 +391,8 @@ public final class UniversalSoftwareVideoSource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(mediaBox: MediaBox, fileReference: FileMediaReference, automaticallyFetchHeader: Bool = false) {
|
public init(mediaBox: MediaBox, fileReference: FileMediaReference, automaticallyFetchHeader: Bool = false, hintVP9: Bool = false) {
|
||||||
self.thread = Thread(target: UniversalSoftwareVideoSourceThread.self, selector: #selector(UniversalSoftwareVideoSourceThread.entryPoint(_:)), object: UniversalSoftwareVideoSourceThreadParams(mediaBox: mediaBox, fileReference: fileReference, state: self.stateValue, cancelInitialization: self.cancelInitialization.get(), automaticallyFetchHeader: automaticallyFetchHeader))
|
self.thread = Thread(target: UniversalSoftwareVideoSourceThread.self, selector: #selector(UniversalSoftwareVideoSourceThread.entryPoint(_:)), object: UniversalSoftwareVideoSourceThreadParams(mediaBox: mediaBox, fileReference: fileReference, state: self.stateValue, cancelInitialization: self.cancelInitialization.get(), automaticallyFetchHeader: automaticallyFetchHeader, hintVP9: hintVP9))
|
||||||
self.thread.name = "UniversalSoftwareVideoSource"
|
self.thread.name = "UniversalSoftwareVideoSource"
|
||||||
self.thread.start()
|
self.thread.start()
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,7 @@ private let inlineBotPrefixFont = Font.regular(14.0)
|
|||||||
private let inlineBotNameFont = nameFont
|
private let inlineBotNameFont = nameFont
|
||||||
|
|
||||||
protocol GenericAnimatedStickerNode: ASDisplayNode {
|
protocol GenericAnimatedStickerNode: ASDisplayNode {
|
||||||
func setOverlayColor(_ color: UIColor?, replace: Bool, animated: Bool)
|
func setOverlayColor(_ color: UIColor?, animated: Bool)
|
||||||
|
|
||||||
var currentFrameIndex: Int { get }
|
var currentFrameIndex: Int { get }
|
||||||
func setFrameIndex(_ frameIndex: Int)
|
func setFrameIndex(_ frameIndex: Int)
|
||||||
@ -58,7 +58,7 @@ private class VideoStickerNode: ASDisplayNode, GenericAnimatedStickerNode {
|
|||||||
private var layerHolder: SampleBufferLayer?
|
private var layerHolder: SampleBufferLayer?
|
||||||
var manager: SoftwareVideoLayerFrameManager?
|
var manager: SoftwareVideoLayerFrameManager?
|
||||||
|
|
||||||
func setOverlayColor(_ color: UIColor?, replace: Bool, animated: Bool) {
|
func setOverlayColor(_ color: UIColor?, animated: Bool) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -367,15 +367,10 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
|||||||
if let shareButtonNode = strongSelf.shareButtonNode, shareButtonNode.frame.contains(point) {
|
if let shareButtonNode = strongSelf.shareButtonNode, shareButtonNode.frame.contains(point) {
|
||||||
return .fail
|
return .fail
|
||||||
}
|
}
|
||||||
if let reactionButtonsNode = strongSelf.reactionButtonsNode {
|
|
||||||
if let _ = reactionButtonsNode.hitTest(strongSelf.view.convert(point, to: reactionButtonsNode.view), with: nil) {
|
|
||||||
return .fail
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if strongSelf.telegramFile == nil {
|
if false, strongSelf.telegramFile == nil {
|
||||||
if let animationNode = strongSelf.animationNode, animationNode.frame.contains(point) {
|
if let animationNode = strongSelf.animationNode, animationNode.frame.contains(point) {
|
||||||
return .waitForSingleTap
|
return .waitForDoubleTap
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -898,7 +893,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if item.associatedData.isCopyProtectionEnabled || item.message.isCopyProtected() {
|
if item.associatedData.isCopyProtectionEnabled {
|
||||||
needsShareButton = false
|
needsShareButton = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -945,8 +940,8 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
|||||||
var dateReplies = 0
|
var dateReplies = 0
|
||||||
let dateReactionsAndPeers = mergedMessageReactionsAndPeers(message: item.message)
|
let dateReactionsAndPeers = mergedMessageReactionsAndPeers(message: item.message)
|
||||||
for attribute in item.message.attributes {
|
for attribute in item.message.attributes {
|
||||||
if let attribute = attribute as? EditedMessageAttribute, isEmoji {
|
if let _ = attribute as? EditedMessageAttribute, isEmoji {
|
||||||
edited = !attribute.isHidden
|
edited = true
|
||||||
} else if let attribute = attribute as? ViewCountMessageAttribute {
|
} else if let attribute = attribute as? ViewCountMessageAttribute {
|
||||||
viewCount = attribute.count
|
viewCount = attribute.count
|
||||||
} else if let attribute = attribute as? ReplyThreadMessageAttribute, case .peer = item.chatLocation {
|
} else if let attribute = attribute as? ReplyThreadMessageAttribute, case .peer = item.chatLocation {
|
||||||
@ -977,8 +972,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
|||||||
reactionPeers: dateReactionsAndPeers.peers,
|
reactionPeers: dateReactionsAndPeers.peers,
|
||||||
replyCount: dateReplies,
|
replyCount: dateReplies,
|
||||||
isPinned: item.message.tags.contains(.pinned) && !item.associatedData.isInPinnedListMode && !isReplyThread,
|
isPinned: item.message.tags.contains(.pinned) && !item.associatedData.isInPinnedListMode && !isReplyThread,
|
||||||
hasAutoremove: item.message.isSelfExpiring,
|
hasAutoremove: item.message.isSelfExpiring
|
||||||
canViewReactionList: canViewMessageReactionList(message: item.message)
|
|
||||||
))
|
))
|
||||||
|
|
||||||
let (dateAndStatusSize, dateAndStatusApply) = statusSuggestedWidthAndContinue.1(statusSuggestedWidthAndContinue.0)
|
let (dateAndStatusSize, dateAndStatusApply) = statusSuggestedWidthAndContinue.1(statusSuggestedWidthAndContinue.0)
|
||||||
@ -1111,9 +1105,9 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
|||||||
|
|
||||||
let reactions: ReactionsMessageAttribute
|
let reactions: ReactionsMessageAttribute
|
||||||
if shouldDisplayInlineDateReactions(message: item.message) {
|
if shouldDisplayInlineDateReactions(message: item.message) {
|
||||||
reactions = ReactionsMessageAttribute(canViewList: false, reactions: [], recentPeers: [])
|
reactions = ReactionsMessageAttribute(reactions: [], recentPeers: [])
|
||||||
} else {
|
} else {
|
||||||
reactions = mergedMessageReactions(attributes: item.message.attributes) ?? ReactionsMessageAttribute(canViewList: false, reactions: [], recentPeers: [])
|
reactions = mergedMessageReactions(attributes: item.message.attributes) ?? ReactionsMessageAttribute(reactions: [], recentPeers: [])
|
||||||
}
|
}
|
||||||
var reactionButtonsFinalize: ((CGFloat) -> (CGSize, (_ animation: ListViewItemUpdateAnimation) -> ChatMessageReactionButtonsNode))?
|
var reactionButtonsFinalize: ((CGFloat) -> (CGSize, (_ animation: ListViewItemUpdateAnimation) -> ChatMessageReactionButtonsNode))?
|
||||||
if !reactions.reactions.isEmpty {
|
if !reactions.reactions.isEmpty {
|
||||||
@ -1144,7 +1138,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
|||||||
layoutSize.height += actionButtonsSizeAndApply.0.height
|
layoutSize.height += actionButtonsSizeAndApply.0.height
|
||||||
}
|
}
|
||||||
if let reactionButtonsSizeAndApply = reactionButtonsSizeAndApply {
|
if let reactionButtonsSizeAndApply = reactionButtonsSizeAndApply {
|
||||||
layoutSize.height += 4.0 + reactionButtonsSizeAndApply.0.height
|
layoutSize.height += reactionButtonsSizeAndApply.0.height
|
||||||
}
|
}
|
||||||
|
|
||||||
return (ListViewItemNodeLayout(contentSize: layoutSize, insets: layoutInsets), { [weak self] animation, _, _ in
|
return (ListViewItemNodeLayout(contentSize: layoutSize, insets: layoutInsets), { [weak self] animation, _, _ in
|
||||||
@ -1411,13 +1405,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
|||||||
|
|
||||||
if let reactionButtonsSizeAndApply = reactionButtonsSizeAndApply {
|
if let reactionButtonsSizeAndApply = reactionButtonsSizeAndApply {
|
||||||
let reactionButtonsNode = reactionButtonsSizeAndApply.1(animation)
|
let reactionButtonsNode = reactionButtonsSizeAndApply.1(animation)
|
||||||
var reactionButtonsFrame = CGRect(origin: CGPoint(x: imageFrame.minX, y: imageFrame.maxY), size: reactionButtonsSizeAndApply.0)
|
let reactionButtonsFrame = CGRect(origin: CGPoint(x: imageFrame.minX, y: imageFrame.maxY), size: reactionButtonsSizeAndApply.0)
|
||||||
if !incoming {
|
|
||||||
reactionButtonsFrame.origin.x = imageFrame.maxX - reactionButtonsSizeAndApply.0.width
|
|
||||||
}
|
|
||||||
if let actionButtonsSizeAndApply = actionButtonsSizeAndApply {
|
|
||||||
reactionButtonsFrame.origin.y += 4.0 + actionButtonsSizeAndApply.0.height
|
|
||||||
}
|
|
||||||
if reactionButtonsNode !== strongSelf.reactionButtonsNode {
|
if reactionButtonsNode !== strongSelf.reactionButtonsNode {
|
||||||
strongSelf.reactionButtonsNode = reactionButtonsNode
|
strongSelf.reactionButtonsNode = reactionButtonsNode
|
||||||
reactionButtonsNode.reactionSelected = { value in
|
reactionButtonsNode.reactionSelected = { value in
|
||||||
@ -1426,14 +1414,6 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
|||||||
}
|
}
|
||||||
item.controllerInteraction.updateMessageReaction(item.message, .reaction(value))
|
item.controllerInteraction.updateMessageReaction(item.message, .reaction(value))
|
||||||
}
|
}
|
||||||
reactionButtonsNode.openReactionPreview = { gesture, sourceNode, value in
|
|
||||||
guard let strongSelf = self, let item = strongSelf.item else {
|
|
||||||
gesture?.cancel()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
item.controllerInteraction.openMessageReactionContextMenu(item.message, sourceNode, gesture, value)
|
|
||||||
}
|
|
||||||
reactionButtonsNode.frame = reactionButtonsFrame
|
reactionButtonsNode.frame = reactionButtonsFrame
|
||||||
if let (rect, containerSize) = strongSelf.absoluteRect {
|
if let (rect, containerSize) = strongSelf.absoluteRect {
|
||||||
var rect = rect
|
var rect = rect
|
||||||
@ -1516,10 +1496,6 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
|||||||
}
|
}
|
||||||
} else if case .tap = gesture {
|
} else if case .tap = gesture {
|
||||||
item.controllerInteraction.clickThroughMessage()
|
item.controllerInteraction.clickThroughMessage()
|
||||||
} else if case .doubleTap = gesture {
|
|
||||||
if canAddMessageReactions(message: item.message) {
|
|
||||||
item.controllerInteraction.updateMessageReaction(item.message, .default)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@ -2193,10 +2169,10 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
|||||||
|
|
||||||
if highlighted {
|
if highlighted {
|
||||||
self.imageNode.setOverlayColor(item.presentationData.theme.theme.chat.message.mediaHighlightOverlayColor, animated: false)
|
self.imageNode.setOverlayColor(item.presentationData.theme.theme.chat.message.mediaHighlightOverlayColor, animated: false)
|
||||||
self.animationNode?.setOverlayColor(item.presentationData.theme.theme.chat.message.mediaHighlightOverlayColor, replace: false, animated: false)
|
self.animationNode?.setOverlayColor(item.presentationData.theme.theme.chat.message.mediaHighlightOverlayColor, animated: false)
|
||||||
} else {
|
} else {
|
||||||
self.imageNode.setOverlayColor(nil, animated: animated)
|
self.imageNode.setOverlayColor(nil, animated: animated)
|
||||||
self.animationNode?.setOverlayColor(nil, replace: false, animated: false)
|
self.animationNode?.setOverlayColor(nil, animated: false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2406,13 +2382,6 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override func openMessageContextMenu() {
|
|
||||||
guard let item = self.item else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
item.controllerInteraction.openMessageContextMenu(item.message, false, self, self.imageNode.frame, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
override func targetReactionView(value: String) -> UIView? {
|
override func targetReactionView(value: String) -> UIView? {
|
||||||
if let result = self.reactionButtonsNode?.reactionTargetView(value: value) {
|
if let result = self.reactionButtonsNode?.reactionTargetView(value: value) {
|
||||||
return result
|
return result
|
||||||
|
@ -380,6 +380,10 @@ public final class ChatMessageItem: ListViewItem, CustomStringConvertible {
|
|||||||
|
|
||||||
loop: for media in self.message.media {
|
loop: for media in self.message.media {
|
||||||
if let telegramFile = media as? TelegramMediaFile {
|
if let telegramFile = media as? TelegramMediaFile {
|
||||||
|
if let fileName = telegramFile.fileName, fileName.hasSuffix(".webm") {
|
||||||
|
viewClassName = ChatMessageAnimatedStickerItemNode.self
|
||||||
|
break loop
|
||||||
|
}
|
||||||
if telegramFile.isAnimatedSticker, let size = telegramFile.size, size > 0 && size <= 128 * 1024 {
|
if telegramFile.isAnimatedSticker, let size = telegramFile.size, size > 0 && size <= 128 * 1024 {
|
||||||
if self.message.id.peerId.namespace == Namespaces.Peer.SecretChat {
|
if self.message.id.peerId.namespace == Namespaces.Peer.SecretChat {
|
||||||
if telegramFile.fileId.namespace == Namespaces.Media.CloudFile {
|
if telegramFile.fileId.namespace == Namespaces.Media.CloudFile {
|
||||||
|
@ -14,6 +14,7 @@ final class SoftwareVideoLayerFrameManager {
|
|||||||
private let fetchDisposable: Disposable
|
private let fetchDisposable: Disposable
|
||||||
private var dataDisposable = MetaDisposable()
|
private var dataDisposable = MetaDisposable()
|
||||||
private let source = Atomic<SoftwareVideoSource?>(value: nil)
|
private let source = Atomic<SoftwareVideoSource?>(value: nil)
|
||||||
|
private let hintVP9: Bool
|
||||||
|
|
||||||
private var baseTimestamp: Double?
|
private var baseTimestamp: Double?
|
||||||
private var frames: [MediaTrackFrame] = []
|
private var frames: [MediaTrackFrame] = []
|
||||||
@ -31,7 +32,7 @@ final class SoftwareVideoLayerFrameManager {
|
|||||||
|
|
||||||
private var layerRotationAngleAndAspect: (CGFloat, CGFloat)?
|
private var layerRotationAngleAndAspect: (CGFloat, CGFloat)?
|
||||||
|
|
||||||
init(account: Account, fileReference: FileMediaReference, layerHolder: SampleBufferLayer) {
|
init(account: Account, fileReference: FileMediaReference, layerHolder: SampleBufferLayer, hintVP9: Bool = false) {
|
||||||
var resource = fileReference.media.resource
|
var resource = fileReference.media.resource
|
||||||
var secondaryResource: MediaResource?
|
var secondaryResource: MediaResource?
|
||||||
for attribute in fileReference.media.attributes {
|
for attribute in fileReference.media.attributes {
|
||||||
@ -46,6 +47,7 @@ final class SoftwareVideoLayerFrameManager {
|
|||||||
nextWorker += 1
|
nextWorker += 1
|
||||||
self.account = account
|
self.account = account
|
||||||
self.resource = resource
|
self.resource = resource
|
||||||
|
self.hintVP9 = hintVP9
|
||||||
self.secondaryResource = secondaryResource
|
self.secondaryResource = secondaryResource
|
||||||
self.queue = ThreadPoolQueue(threadPool: workers)
|
self.queue = ThreadPoolQueue(threadPool: workers)
|
||||||
self.layerHolder = layerHolder
|
self.layerHolder = layerHolder
|
||||||
@ -108,7 +110,7 @@ final class SoftwareVideoLayerFrameManager {
|
|||||||
let size = fileSize(path)
|
let size = fileSize(path)
|
||||||
Logger.shared.log("SoftwareVideo", "loaded video from \(stringForResource(resource)) (file size: \(String(describing: size))")
|
Logger.shared.log("SoftwareVideo", "loaded video from \(stringForResource(resource)) (file size: \(String(describing: size))")
|
||||||
|
|
||||||
let _ = strongSelf.source.swap(SoftwareVideoSource(path: path))
|
let _ = strongSelf.source.swap(SoftwareVideoSource(path: path, hintVP9: strongSelf.hintVP9))
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
38
submodules/ffmpeg/BUILD
vendored
38
submodules/ffmpeg/BUILD
vendored
@ -120,6 +120,24 @@ filegroup(
|
|||||||
srcs = source_files,
|
srcs = source_files,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
vpx_headers = [
|
||||||
|
"vp8.h",
|
||||||
|
"vp8cx.h",
|
||||||
|
"vp8dx.h",
|
||||||
|
"vpx_codec.h",
|
||||||
|
"vpx_decoder.h",
|
||||||
|
"vpx_encoder.h",
|
||||||
|
"vpx_frame_buffer.h",
|
||||||
|
"vpx_image.h",
|
||||||
|
"vpx_integer.h",
|
||||||
|
"vpx_version.h",
|
||||||
|
"vpx_ext_ratectrl.h",
|
||||||
|
]
|
||||||
|
|
||||||
|
vpx_libs = [
|
||||||
|
"VPX",
|
||||||
|
]
|
||||||
|
|
||||||
opus_headers = [
|
opus_headers = [
|
||||||
"opus.h",
|
"opus.h",
|
||||||
"opus_defines.h",
|
"opus_defines.h",
|
||||||
@ -136,6 +154,10 @@ genrule(
|
|||||||
name = "libffmpeg_build",
|
name = "libffmpeg_build",
|
||||||
srcs = [
|
srcs = [
|
||||||
":FFMpegSources"
|
":FFMpegSources"
|
||||||
|
] + [
|
||||||
|
"//third-party/libvpx:Public/vpx/{}".format(x) for x in vpx_headers
|
||||||
|
] + [
|
||||||
|
"//third-party/libvpx:Public/vpx/lib{}.a".format(x) for x in vpx_libs
|
||||||
] + [
|
] + [
|
||||||
"//third-party/opus:Public/opus/{}".format(x) for x in opus_headers
|
"//third-party/opus:Public/opus/{}".format(x) for x in opus_headers
|
||||||
] + [
|
] + [
|
||||||
@ -153,6 +175,21 @@ genrule(
|
|||||||
|
|
||||||
cp -R "submodules/ffmpeg/Sources/FFMpeg" "$$SOURCE_PATH"
|
cp -R "submodules/ffmpeg/Sources/FFMpeg" "$$SOURCE_PATH"
|
||||||
|
|
||||||
|
mkdir "$$SOURCE_PATH/libvpx"
|
||||||
|
mkdir -p "$$SOURCE_PATH/libvpx/include/vpx"
|
||||||
|
mkdir -p "$$SOURCE_PATH/libvpx/lib"
|
||||||
|
""" +
|
||||||
|
"\n" +
|
||||||
|
"\n".join([
|
||||||
|
"cp $(location //third-party/libvpx:Public/vpx/{}) $$SOURCE_PATH/libvpx/include/vpx/".format(x) for x in vpx_headers
|
||||||
|
]) +
|
||||||
|
"\n" +
|
||||||
|
"\n".join([
|
||||||
|
"cp $(location //third-party/libvpx:Public/vpx/libVPX.a) $$SOURCE_PATH/libvpx/lib/".format(x) for x in vpx_libs
|
||||||
|
]) +
|
||||||
|
"\n" +
|
||||||
|
"""
|
||||||
|
|
||||||
mkdir "$$SOURCE_PATH/libopus"
|
mkdir "$$SOURCE_PATH/libopus"
|
||||||
mkdir -p "$$SOURCE_PATH/libopus/include/opus"
|
mkdir -p "$$SOURCE_PATH/libopus/include/opus"
|
||||||
mkdir -p "$$SOURCE_PATH/libopus/lib"
|
mkdir -p "$$SOURCE_PATH/libopus/lib"
|
||||||
@ -231,6 +268,7 @@ objc_library(
|
|||||||
],
|
],
|
||||||
deps = [
|
deps = [
|
||||||
":ffmpeg_lib",
|
":ffmpeg_lib",
|
||||||
|
"//third-party/libvpx:vpx",
|
||||||
"//third-party/opus:opus",
|
"//third-party/opus:opus",
|
||||||
],
|
],
|
||||||
visibility = [
|
visibility = [
|
||||||
|
@ -45,9 +45,10 @@ CONFIGURE_FLAGS="--enable-cross-compile --disable-programs \
|
|||||||
--enable-avformat \
|
--enable-avformat \
|
||||||
--disable-xlib \
|
--disable-xlib \
|
||||||
--enable-libopus \
|
--enable-libopus \
|
||||||
|
--enable-libvpx \
|
||||||
--enable-audiotoolbox \
|
--enable-audiotoolbox \
|
||||||
--enable-bsf=aac_adtstoasc \
|
--enable-bsf=aac_adtstoasc \
|
||||||
--enable-decoder=h264,hevc,libopus,mp3,aac,flac,alac_at,pcm_s16le,pcm_s24le,gsm_ms_at \
|
--enable-decoder=h264,libvpx_vp9,hevc,libopus,mp3,aac,flac,alac_at,pcm_s16le,pcm_s24le,gsm_ms_at \
|
||||||
--enable-demuxer=aac,mov,m4v,mp3,ogg,libopus,flac,wav,aiff,matroska \
|
--enable-demuxer=aac,mov,m4v,mp3,ogg,libopus,flac,wav,aiff,matroska \
|
||||||
--enable-parser=aac,h264,mp3,libopus \
|
--enable-parser=aac,h264,mp3,libopus \
|
||||||
--enable-protocol=file \
|
--enable-protocol=file \
|
||||||
@ -122,6 +123,7 @@ then
|
|||||||
pushd "$SCRATCH/$RAW_ARCH"
|
pushd "$SCRATCH/$RAW_ARCH"
|
||||||
|
|
||||||
LIBOPUS_PATH="$SOURCE_DIR/libopus"
|
LIBOPUS_PATH="$SOURCE_DIR/libopus"
|
||||||
|
LIBVPX_PATH="$SOURCE_DIR/libvpx"
|
||||||
|
|
||||||
CFLAGS="$EXTRA_CFLAGS -arch $ARCH"
|
CFLAGS="$EXTRA_CFLAGS -arch $ARCH"
|
||||||
if [ "$RAW_ARCH" = "i386" -o "$RAW_ARCH" = "x86_64" ]
|
if [ "$RAW_ARCH" = "i386" -o "$RAW_ARCH" = "x86_64" ]
|
||||||
@ -174,7 +176,7 @@ then
|
|||||||
--extra-ldflags="$LDFLAGS" \
|
--extra-ldflags="$LDFLAGS" \
|
||||||
--prefix="$THIN/$RAW_ARCH" \
|
--prefix="$THIN/$RAW_ARCH" \
|
||||||
--pkg-config="$PKG_CONFIG" \
|
--pkg-config="$PKG_CONFIG" \
|
||||||
--pkg-config-flags="--libopus_path $LIBOPUS_PATH" \
|
--pkg-config-flags="--libopus_path $LIBOPUS_PATH --libvpx_path $LIBVPX_PATH" \
|
||||||
|| exit 1
|
|| exit 1
|
||||||
echo "$CONFIGURE_FLAGS" > "$CONFIGURED_MARKER"
|
echo "$CONFIGURE_FLAGS" > "$CONFIGURED_MARKER"
|
||||||
fi
|
fi
|
||||||
|
@ -14,6 +14,8 @@ elif [ "$1" == "--exists" ]; then
|
|||||||
exit 0
|
exit 0
|
||||||
elif [ "$NAME" == "opus" ]; then
|
elif [ "$NAME" == "opus" ]; then
|
||||||
exit 0
|
exit 0
|
||||||
|
elif [ "$NAME" == "vpx" ]; then
|
||||||
|
exit 0
|
||||||
else
|
else
|
||||||
if [ "PRINT_ERRORS" == "1" ]; then
|
if [ "PRINT_ERRORS" == "1" ]; then
|
||||||
echo "Package $NAME was not found in the pkg-config search path."
|
echo "Package $NAME was not found in the pkg-config search path."
|
||||||
@ -25,9 +27,15 @@ elif [ "$1" == "--exists" ]; then
|
|||||||
elif [ "$1" == "--cflags" ]; then
|
elif [ "$1" == "--cflags" ]; then
|
||||||
NAME="$2"
|
NAME="$2"
|
||||||
LIBOPUS_PATH=""
|
LIBOPUS_PATH=""
|
||||||
|
LIBVPX_PATH=""
|
||||||
if [ "$2" == "--libopus_path" ]; then
|
if [ "$2" == "--libopus_path" ]; then
|
||||||
LIBOPUS_PATH="$3"
|
LIBOPUS_PATH="$3"
|
||||||
NAME="$4"
|
NAME="$6"
|
||||||
|
else
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ "$4" == "--libvpx_path" ]; then
|
||||||
|
LIBVPX_PATH="$5"
|
||||||
else
|
else
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
@ -37,15 +45,24 @@ elif [ "$1" == "--cflags" ]; then
|
|||||||
elif [ "$NAME" == "opus" ]; then
|
elif [ "$NAME" == "opus" ]; then
|
||||||
echo "-I$LIBOPUS_PATH/include/opus"
|
echo "-I$LIBOPUS_PATH/include/opus"
|
||||||
exit 0
|
exit 0
|
||||||
|
elif [ "$NAME" == "vpx" ]; then
|
||||||
|
echo "-I$LIBVPX_PATH/include"
|
||||||
|
exit 0
|
||||||
else
|
else
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
elif [ "$1" == "--libs" ]; then
|
elif [ "$1" == "--libs" ]; then
|
||||||
NAME="$2"
|
NAME="$2"
|
||||||
LIBOPUS_PATH=""
|
LIBOPUS_PATH=""
|
||||||
|
LIBVPX_PATH=""
|
||||||
if [ "$2" == "--libopus_path" ]; then
|
if [ "$2" == "--libopus_path" ]; then
|
||||||
LIBOPUS_PATH="$3"
|
LIBOPUS_PATH="$3"
|
||||||
NAME="$4"
|
NAME="$6"
|
||||||
|
else
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ "$4" == "--libvpx_path" ]; then
|
||||||
|
LIBVPX_PATH="$5"
|
||||||
else
|
else
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
@ -55,6 +72,9 @@ elif [ "$1" == "--libs" ]; then
|
|||||||
elif [ "$NAME" == "opus" ]; then
|
elif [ "$NAME" == "opus" ]; then
|
||||||
echo "-L$LIBOPUS_PATH/lib -lopus"
|
echo "-L$LIBOPUS_PATH/lib -lopus"
|
||||||
exit 0
|
exit 0
|
||||||
|
elif [ "$NAME" == "vpx" ]; then
|
||||||
|
echo "-L$LIBVPX_PATH/lib -lVPX"
|
||||||
|
exit 0
|
||||||
else
|
else
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
Loading…
x
Reference in New Issue
Block a user