diff --git a/submodules/MediaPlayer/Sources/FFMpegMediaVideoFrameDecoder.swift b/submodules/MediaPlayer/Sources/FFMpegMediaVideoFrameDecoder.swift index b28f899c46..d59e684b61 100644 --- a/submodules/MediaPlayer/Sources/FFMpegMediaVideoFrameDecoder.swift +++ b/submodules/MediaPlayer/Sources/FFMpegMediaVideoFrameDecoder.swift @@ -115,7 +115,7 @@ public final class FFMpegMediaVideoFrameDecoder: MediaTrackFrameDecoder { } } - public func decode(frame: MediaTrackDecodableFrame, ptsOffset: CMTime?) -> MediaTrackFrame? { + public func decode(frame: MediaTrackDecodableFrame, ptsOffset: CMTime?, forceARGB: Bool = false) -> MediaTrackFrame? { let status = frame.packet.send(toDecoder: self.codecContext) if status == 0 { self.defaultDuration = frame.duration @@ -126,7 +126,7 @@ public final class FFMpegMediaVideoFrameDecoder: MediaTrackFrameDecoder { if let ptsOffset = ptsOffset { pts = CMTimeAdd(pts, ptsOffset) } - return convertVideoFrame(self.videoFrame, pts: pts, dts: pts, duration: frame.duration) + return convertVideoFrame(self.videoFrame, pts: pts, dts: pts, duration: frame.duration, forceARGB: forceARGB) } } @@ -236,7 +236,7 @@ public final class FFMpegMediaVideoFrameDecoder: MediaTrackFrameDecoder { return UIImage(cgImage: image, scale: 1.0, orientation: .up) } - private func convertVideoFrame(_ frame: FFMpegAVFrame, pts: CMTime, dts: CMTime, duration: CMTime) -> MediaTrackFrame? { + private func convertVideoFrame(_ frame: FFMpegAVFrame, pts: CMTime, dts: CMTime, duration: CMTime, forceARGB: Bool = false) -> MediaTrackFrame? { if frame.data[0] == nil { return nil } @@ -247,13 +247,26 @@ public final class FFMpegMediaVideoFrameDecoder: MediaTrackFrameDecoder { var pixelBufferRef: CVPixelBuffer? let pixelFormat: OSType - switch frame.pixelFormat { - case .YUV: - pixelFormat = kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange - case .YUVA: - pixelFormat = kCVPixelFormatType_32ARGB - default: - pixelFormat = kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange + var hasAlpha = false + if forceARGB { + pixelFormat = kCVPixelFormatType_32ARGB + switch frame.pixelFormat { + case .YUV: + hasAlpha = false + case .YUVA: + hasAlpha = true + default: + hasAlpha = false + } + } else { + switch frame.pixelFormat { + case .YUV: + pixelFormat = kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange + case .YUVA: + pixelFormat = kCVPixelFormatType_420YpCbCr8VideoRange_8A_TriPlanar + default: + pixelFormat = kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange + } } if let pixelBufferPool = self.pixelBufferPool { @@ -290,7 +303,7 @@ public final class FFMpegMediaVideoFrameDecoder: MediaTrackFrameDecoder { var base: UnsafeMutableRawPointer if pixelFormat == kCVPixelFormatType_32ARGB { let bytesPerRow = CVPixelBufferGetBytesPerRow(pixelBuffer) - decodeYUVAPlanesToRGBA(frame.data[0], Int32(frame.lineSize[0]), frame.data[1], Int32(frame.lineSize[1]), frame.data[2], Int32(frame.lineSize[2]), frame.data[3], CVPixelBufferGetBaseAddress(pixelBuffer)?.assumingMemoryBound(to: UInt8.self), Int32(frame.width), Int32(frame.height), Int32(bytesPerRow)) + decodeYUVAPlanesToRGBA(frame.data[0], Int32(frame.lineSize[0]), frame.data[1], Int32(frame.lineSize[1]), frame.data[2], Int32(frame.lineSize[2]), hasAlpha, frame.data[3], CVPixelBufferGetBaseAddress(pixelBuffer)?.assumingMemoryBound(to: UInt8.self), Int32(frame.width), Int32(frame.height), Int32(bytesPerRow)) } else { let srcPlaneSize = Int(frame.lineSize[1]) * Int(frame.height / 2) let uvPlaneSize = srcPlaneSize * 2 diff --git a/submodules/MediaPlayer/Sources/SoftwareVideoSource.swift b/submodules/MediaPlayer/Sources/SoftwareVideoSource.swift index 5653fa8028..754f61f689 100644 --- a/submodules/MediaPlayer/Sources/SoftwareVideoSource.swift +++ b/submodules/MediaPlayer/Sources/SoftwareVideoSource.swift @@ -58,12 +58,16 @@ public final class SoftwareVideoSource { fileprivate let fd: Int32? fileprivate let size: Int32 + private let hintVP9: Bool + private var enqueuedFrames: [(MediaTrackFrame, CGFloat, CGFloat, Bool)] = [] private var hasReadToEnd: Bool = false public init(path: String, hintVP9: Bool) { let _ = FFMpegMediaFrameSourceContextHelpers.registerFFMpegGlobals + self.hintVP9 = hintVP9 + var s = stat() stat(path, &s) self.size = Int32(s.st_size) @@ -224,7 +228,7 @@ public final class SoftwareVideoSource { if let maxPts = maxPts, CMTimeCompare(decodableFrame.pts, maxPts) < 0 { ptsOffset = maxPts } - result = (videoStream.decoder.decode(frame: decodableFrame, ptsOffset: ptsOffset), CGFloat(videoStream.rotationAngle), CGFloat(videoStream.aspect), loop) + result = (videoStream.decoder.decode(frame: decodableFrame, ptsOffset: ptsOffset, forceARGB: self.hintVP9), CGFloat(videoStream.rotationAngle), CGFloat(videoStream.aspect), loop) } else { result = (nil, CGFloat(videoStream.rotationAngle), CGFloat(videoStream.aspect), loop) } diff --git a/submodules/YuvConversion/PublicHeaders/YuvConversion/YUV.h b/submodules/YuvConversion/PublicHeaders/YuvConversion/YUV.h index dfdf99fb01..e7101ef184 100644 --- a/submodules/YuvConversion/PublicHeaders/YuvConversion/YUV.h +++ b/submodules/YuvConversion/PublicHeaders/YuvConversion/YUV.h @@ -4,4 +4,4 @@ void encodeRGBAToYUVA(uint8_t *yuva, uint8_t const *argb, int width, int height, void resizeAndEncodeRGBAToYUVA(uint8_t *yuva, uint8_t const *argb, int width, int height, int bytesPerRow, int originalWidth, int originalHeight, int originalBytesPerRow); void decodeYUVAToRGBA(uint8_t const *yuva, uint8_t *argb, int width, int height, int bytesPerRow); -void decodeYUVAPlanesToRGBA(uint8_t const *srcYpData, int srcYpBytesPerRow, uint8_t const *srcCbData, int srcCbBytesPerRow, uint8_t const *srcCrData, int srcCrBytesPerRow, uint8_t const *alphaData, uint8_t *argb, int width, int height, int bytesPerRow); +void decodeYUVAPlanesToRGBA(uint8_t const *srcYpData, int srcYpBytesPerRow, uint8_t const *srcCbData, int srcCbBytesPerRow, uint8_t const *srcCrData, int srcCrBytesPerRow, bool hasAlpha, uint8_t const *alphaData, uint8_t *argb, int width, int height, int bytesPerRow); diff --git a/submodules/YuvConversion/Sources/YUV.m b/submodules/YuvConversion/Sources/YUV.m index b2445ba58f..0882f01ed1 100644 --- a/submodules/YuvConversion/Sources/YUV.m +++ b/submodules/YuvConversion/Sources/YUV.m @@ -169,7 +169,7 @@ void decodeYUVAToRGBA(uint8_t const *yuva, uint8_t *argb, int width, int height, } } -void decodeYUVAPlanesToRGBA(uint8_t const *srcYpData, int srcYpBytesPerRow, uint8_t const *srcCbData, int srcCbBytesPerRow, uint8_t const *srcCrData, int srcCrBytesPerRow, uint8_t const *alphaData, uint8_t *argb, int width, int height, int bytesPerRow) { +void decodeYUVAPlanesToRGBA(uint8_t const *srcYpData, int srcYpBytesPerRow, uint8_t const *srcCbData, int srcCbBytesPerRow, uint8_t const *srcCrData, int srcCrBytesPerRow, bool hasAlpha, uint8_t const *alphaData, uint8_t *argb, int width, int height, int bytesPerRow) { static vImage_YpCbCrToARGB info; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ @@ -204,12 +204,14 @@ void decodeYUVAPlanesToRGBA(uint8_t const *srcYpData, int srcYpBytesPerRow, uint dest.rowBytes = bytesPerRow; error = vImageConvert_420Yp8_Cb8_Cr8ToARGB8888(&srcYp, &srcCb, &srcCr, &dest, &info, NULL, 0xff, kvImageDoNotTile); - for (int y = 0; y < height; y += 1) { - uint8_t *argbRow = argb + y * bytesPerRow; - int alphaRow = y * srcYpBytesPerRow; - - for (int x = 0; x < width; x += 1) { - argbRow[x * 4] = alphaData[alphaRow + x]; + if (hasAlpha) { + for (int y = 0; y < height; y += 1) { + uint8_t *argbRow = argb + y * bytesPerRow; + int alphaRow = y * srcYpBytesPerRow; + + for (int x = 0; x < width; x += 1) { + argbRow[x * 4] = alphaData[alphaRow + x]; + } } }