对于 Objective-C 中的 iOS 项目,我需要显示屏幕上未显示的 rtsp 视频流的缩略图(我无法截图)。 我的视图显示一个视频流和其他流的三个缩略图(定期刷新),以便用户可以在它们之间切换。
那么,我怎样才能生成这个缩略图呢? 我正在使用 MobileVLCKit 来显示我的主视频流(如果可能的话,我更愿意使用这个框架来生成我的缩略图......)。
我在论坛和谷歌结果中找到了很多结果,但没有一个符合我的情况:流+不显示视频。
感谢您的帮助!
编辑:
我也尝试过VLC的缩略图,但没有成功:
VLCMedia *media = [VLCMedia mediaWithURL:[NSURL URLWithString:<Rtsp Url>]];
thumbnailer = [VLCMediaThumbnailer thumbnailerWithMedia:media andDelegate:self];
但我总是陷入 mediaThumbnailerDidTimeOut 委托方法。
基本上您需要做的就是使用 VLCKit 'VLCMediaThumbnailer' 类并实现 'VLCMediaThumbnailerDelegate' 所需的两个函数
这是一个 Objective-C 示例:
@implementation DummyObject <VLCMediaThumbnailerDelegate>
- (void)workerMethod
{
NSURL *url = [NSURL urlWithString:@""];
VLCMedia *media = [VLCMedia mediaWithURL:url];
VLCMediaThumbnailer *thumbnailer = [VLCMediaThumbnailer thumbnailerWithMedia:media delegate:self];
CGSize thumbSize = CGSizeMake(800.,600.);
thumbnailer.thumbnailWidth = thumbSize.width;
thumbnailer.thumbnailHeight = thumbSize.height;
[thumbnailer fetchThumbnail];
}
- (void)mediaThumbnailer:(VLCMediaThumbnailer *)mediaThumbnailer didFinishThumbnail:(CGImageRef)thumbnail
{
if (thumbnail) {
UIImage *thumbnailImage = [UIImage imageWithCGImage:thumbnail scale:[UIScreen mainScreen].scale orientation:UIImageOrientationUp];
if (thumbnailImage) {
// do something with the thumbnail
}
}
}
- (void)mediaThumbnailerDidTimeOut:(VLCMediaThumbnailer *)mediaThumbnailer
{
// show error generating thumbnail
}
@end
这就是它在 swift 和 SwiftUI 中的样子
func generateThumbnails()
{
if mediaPlayer.media != nil
{
let vlcMediaThumbnailer: VLCMediaThumbnailer = VLCMediaThumbnailer(media: mediaPlayer.media, andDelegate: self)
vlcMediaThumbnailer.thumbnailWidth = 440
vlcMediaThumbnailer.thumbnailHeight = 225
vlcMediaThumbnailer.snapshotPosition = 0.5 // get thumbs from the middle of the video
vlcMediaThumbnailer.fetchThumbnail()
}
}
func mediaThumbnailerDidTimeOut(_ mediaThumbnailer: VLCMediaThumbnailer!)
{
print("failed generating thumbnail")
}
func mediaThumbnailer(_ mediaThumbnailer: VLCMediaThumbnailer!, didFinishThumbnail thumbnail: CGImage!)
{
print("got another thumbnail - do something with it")
}
这里是 tvOS 14.7 和 SwiftUI 中的 apple-tv 的 完整工作演示,用于 VLCKit 中的 缩略图:
import SwiftUI
import AVFoundation
class VideoModel: ObservableObject
{
@Published var thumbnails: [Image] = []
var videoUrl: String = ""
let thumbnailWidth: CGFloat = 400.0
let thumbnailHeight: CGFloat = 225.0
}
struct VLCPlayerTestView: View
{
@State var isPlayVideo: Bool = false
let videoUrl: String = "https://upload.wikimedia.org/wikipedia/commons/transcoded/c/c0/Big_Buck_Bunny_4K.webm/Big_Buck_Bunny_4K.webm.480p.vp9.webm"
var videoPlayer: VideoPlayer? = nil
@ObservedObject var videoModel = VideoModel()
init()
{
videoModel.videoUrl = videoUrl
videoPlayer = VideoPlayer(videoModel: videoModel)
}
var body: some View
{
HStack(spacing: 20)
{
ForEach(0..<videoModel.thumbnails.count, id: \.self) { itemIndex in
videoModel.thumbnails[itemIndex]
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: videoModel.thumbnailWidth, height: videoModel.thumbnailHeight, alignment: Alignment.center)
.focusable()
.onLongPressGesture(minimumDuration: 0.01) {
isPlayVideo = true
}
}
}
.fullScreenCover(isPresented: $isPlayVideo)
{
videoPlayer
.edgesIgnoringSafeArea(.all)
.onAppear {
videoPlayer!.player.playVideo()
}
.onDisappear {
videoPlayer!.player.stopVideo()
}
}
}
}
struct VideoPlayer: UIViewRepresentable
{
var player: VLCPlayerView
init(videoModel: VideoModel)
{
player = VLCPlayerView()
player.videoModel = videoModel
player.loadMedia()
player.generateThumbnails()
}
func updateUIView(_ uiView: UIView, context: UIViewRepresentableContext<VideoPlayer>)
{
}
func makeUIView(context: Context) -> UIView
{
return player
}
}
class VLCPlayerView: UIView, VLCMediaPlayerDelegate, VLCMediaThumbnailerDelegate
{
var videoModel: VideoModel?
let mediaPlayer: VLCMediaPlayer = VLCMediaPlayer()
override init(frame: CGRect)
{
super.init(frame: frame)
}
func loadMedia()
{
if !videoModel!.videoUrl.isEmpty
{
mediaPlayer.media = VLCMedia(url: URL(string: videoModel!.videoUrl)!)
mediaPlayer.delegate = self
mediaPlayer.drawable = self
generateThumbnails()
}
}
func playVideo()
{
if mediaPlayer.media != nil
{
mediaPlayer.play()
}
}
func pauseVideo()
{
if mediaPlayer.media != nil && mediaPlayer.isPlaying
{
mediaPlayer.pause()
}
}
func stopVideo()
{
if mediaPlayer.media != nil
{
mediaPlayer.stop()
}
}
required init?(coder: NSCoder)
{
fatalError("init(coder:) has not been implemented")
}
override func layoutSubviews()
{
super.layoutSubviews()
}
func generateThumbnails()
{
if mediaPlayer.media != nil
{
let vlcMediaThumbnailer: VLCMediaThumbnailer = VLCMediaThumbnailer(media: mediaPlayer.media, andDelegate: self)
vlcMediaThumbnailer.thumbnailWidth = videoModel!.thumbnailWidth
vlcMediaThumbnailer.thumbnailHeight = videoModel!.thumbnailHeight
vlcMediaThumbnailer.snapshotPosition = 0.5
vlcMediaThumbnailer.fetchThumbnail()
}
}
func mediaThumbnailerDidTimeOut(_ mediaThumbnailer: VLCMediaThumbnailer!)
{
print("failed generating thumbnail")
}
func mediaThumbnailer(_ mediaThumbnailer: VLCMediaThumbnailer!, didFinishThumbnail thumbnail: CGImage!)
{
print("got another thumbnail")
if(thumbnail != nil)
{
let thumbnailUIImage = UIImage(cgImage: thumbnail)
let image = Image(uiImage: thumbnailUIImage).renderingMode(.original)
videoModel!.thumbnails.append(image)
}
}
}
结果:
我尝试了自己的实现,但没有成功好几个小时,所以我看到了这篇文章。 总的来说,@Shaybc 提供的代码可以工作,但可以简化。
无论@Shaybc代码还是我的代码,我不明白为什么我不能生成指向不同位置的多个缩略图。
慢慢点击按钮会生成第一个缩略图,但其他缩略图会变黑。快速点击会使所有缩略图变黑。
如果有人有任何想法,我会接受!
import SwiftUI
import AVFoundation
import MobileVLCKit
struct VLCPlayerTestView: View
{
let videoUrl: String = "https://upload.wikimedia.org/wikipedia/commons/transcoded/c/c0/Big_Buck_Bunny_4K.webm/Big_Buck_Bunny_4K.webm.480p.vp9.webm"
@ObservedObject var container = ThumbnailerContainer()
var body: some View
{
Button {
container.generateThumbnail(urlString: videoUrl)
} label: {
Text("Generate Thumbnail")
}
ScrollView {
VStack(spacing: 20)
{
ForEach(0..<container.thumbnails.count, id: \.self) { itemIndex in
container.thumbnails[itemIndex]
.resizable()
.aspectRatio(contentMode: .fill)
}
}
}
}
}
class ThumbnailerContainer: ObservableObject {
@Published var thumbnailers: [Thumbnailer] = []
@Published var thumbnails: [Image] = []
func generateThumbnail(urlString: String) -> Void {
let thumbnailer = Thumbnailer(container: self)
thumbnailer.generateThumbnail(urlString: urlString)
thumbnailers.append(thumbnailer)
}
}
class Thumbnailer: VLCMediaThumbnailerDelegate, ObservableObject {
@Published var container: ThumbnailerContainer
init(container: ThumbnailerContainer) {
self.container = container
}
func generateThumbnail(urlString: String)
{
let media = VLCMedia(url: URL(string: urlString)!)
let vlcMediaThumbnailer: VLCMediaThumbnailer = VLCMediaThumbnailer(media: media, andDelegate: self)
vlcMediaThumbnailer.thumbnailWidth = 400
vlcMediaThumbnailer.thumbnailHeight = 225
vlcMediaThumbnailer.snapshotPosition = Float.random(in: 0...1)
print("Fetching thumbnail for position \(vlcMediaThumbnailer.snapshotPosition)")
vlcMediaThumbnailer.fetchThumbnail()
}
func mediaThumbnailerDidTimeOut(_ mediaThumbnailer: VLCMediaThumbnailer!)
{
print("failed generating thumbnail")
}
func mediaThumbnailer(_ mediaThumbnailer: VLCMediaThumbnailer!, didFinishThumbnail thumbnail: CGImage!)
{
print("Got a thumbnail for position \(mediaThumbnailer.snapshotPosition)")
let thumbnailUIImage = UIImage(cgImage: thumbnail)
let image = Image(uiImage: thumbnailUIImage).renderingMode(.original)
container.thumbnails.append(image)
}
}