gpt4 book ai didi

SwiftUI:如何在使用 ImagePickerController 从设备加载视频后正确编码 AVPlayer?

转载 作者:行者123 更新时间:2023-12-03 16:38:37 27 4
gpt4 key购买 nike

我使用 SwiftUI 创建了一个视频播放器,它使用 imagePickerController 加载视频,然后假设从设备检索到视频后播放视频。我发现视频播放器在检索视频后没有刷新。我不确定如何提供刷新它所必需的适当的@State|@Binding。

我学习了如何使用可用的在线资源编写视频播放器。而且我找到了一种从我的设备加载视频并将其加载到我的视频播放器的方法。但是,当我按下播放按钮时,加载视频后,只播放声音。我试图制作视频播放器@State|@Binding,但找不到解决方案,因为它似乎没有直观地做到这一点。

谁能建议如何使用 SwiftUI 更新我的视频播放器代码?

附言 1)您必须使用实际设备加载视频;和 2) slider 还不能工作。接下来我会继续努力。

披露:

我从在线资源中改编了这段代码。
大部分工作的原始源代码可以在这些链接中找到:

How to open the ImagePicker in SwiftUI?

https://www.raywenderlich.com/5135-how-to-play-record-and-merge-videos-in-ios-and-swift

https://medium.com/@chris.mash/avplayer-swiftui-part-2-player-controls-c28b721e7e27

import SwiftUI
import AVKit
import PhotosUI
import MobileCoreServices

struct ContentView: View {

@State var showImagePicker: Bool = false
@State var url: URL?

var body: some View {
ZStack {
VStack {
Button(action: {
withAnimation {
self.showImagePicker.toggle()
}
}) {
Text("Show image picker")
}

// The video player will needs to be a @State??? as it is not updated with UIView changes but works when no view changes occur.
PlayerContainerView(player: AVPlayer(url: url ?? URL(string: "https://bitdash-a.akamaihd.net/content/sintel/hls/playlist.m3u8")!))
}

if (showImagePicker) {
ImagePicker(isShown: $showImagePicker, url: $url)
}
}
}
}

struct PlayerView: UIViewRepresentable {
let player: AVPlayer
func updateUIView(_ uiView: UIView, context: UIViewRepresentableContext<PlayerView>) {
}
func makeUIView(context: Context) -> UIView {
return PlayerUIView(player: player)
}
}

class PlayerUIView: UIView {
private let playerLayer = AVPlayerLayer()
init(player: AVPlayer) {
super.init(frame: .zero)

playerLayer.player = player
layer.addSublayer(playerLayer)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutSubviews() {
super.layoutSubviews()
playerLayer.frame = bounds
}
}

struct PlayerContainerView : View {

@State var seekPos = 0.0

private let player: AVPlayer
init(player: AVPlayer) {
self.player = player
}
var body: some View {
VStack {
PlayerView(player: player)
PlayerControlsView(player: player)
}
}
}

struct PlayerControlsView : View {
@State var playerPaused = true
@State var seekPos = 0.0
let player: AVPlayer
var body: some View {
HStack {
Button(action: {
self.playerPaused.toggle()
if self.playerPaused {
self.player.pause()
}
else {
self.player.play()
}
}) {
Image(systemName: playerPaused ? "play" : "pause")
.padding(.leading, 20)
.padding(.trailing, 20)
}
Slider(value: $seekPos, from: 0, through: 1, onEditingChanged: { _ in
guard let item = self.player.currentItem else {
return
}

let targetTime = self.seekPos * item.duration.seconds
self.player.seek(to: CMTime(seconds: targetTime, preferredTimescale: 600))
})
.padding(.trailing, 20)
}
}
}

struct ImagePicker: UIViewControllerRepresentable {

@Binding var isShown: Bool
@Binding var url: URL?

class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate {

@Binding var isShown: Bool
@Binding var url: URL?

init(isShown: Binding<Bool>, url: Binding<URL?>) {
$isShown = isShown
$url = url
}

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {

let info = convertFromUIImagePickerControllerInfoKeyDictionary(info)
guard let mediaType = info[convertFromUIImagePickerControllerInfoKey(UIImagePickerController.InfoKey.mediaType)] as? String,
mediaType == (kUTTypeMovie as String),
let uiURL = info[convertFromUIImagePickerControllerInfoKey(UIImagePickerController.InfoKey.mediaURL)] as? URL
else { return }

url = uiURL
isShown = false
}

func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
isShown = false
}

}

func makeCoordinator() -> Coordinator {
return Coordinator(isShown: $isShown, url: $url)
}

func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePicker>) -> UIImagePickerController {
let picker = UIImagePickerController()
picker.mediaTypes = [kUTTypeMovie as String]
picker.delegate = context.coordinator
return picker
}

func updateUIViewController(_ uiViewController: UIImagePickerController,
context: UIViewControllerRepresentableContext<ImagePicker>) {
}
}

fileprivate func convertFromUIImagePickerControllerInfoKeyDictionary(_ input: [UIImagePickerController.InfoKey: Any]) -> [String: Any] {
return Dictionary(uniqueKeysWithValues: input.map {key, value in (key.rawValue, value)})
}

fileprivate func convertFromUIImagePickerControllerInfoKey(_ input: UIImagePickerController.InfoKey) -> String {
return input.rawValue
}

#if DEBUG
struct ContentView_Previews : PreviewProvider {
static var previews: some View {
ContentView(showImagePicker: true)
}
}
#endif

视频播放器没有按预期播放视频,它只播放了向我表明它正在播放视频的声音;但是,我看不到它正在播放。它仍然是一个黑匣子。

更新:以下是按预期工作的完全编辑的代码( slider 除外),在下面的评论中得到了回答:
import SwiftUI
import AVKit
import PhotosUI
import MobileCoreServices

struct ContentView: View {

@State var showImagePicker: Bool = false
@State var url: URL?

var body: some View {
ZStack {
VStack {
Button(action: {
withAnimation {
self.showImagePicker.toggle()
}
}) {
Text("Show image picker")
}

PlayerContainerView(player: AVPlayer(url: url ?? URL(string: "https://bitdash-a.akamaihd.net/content/sintel/hls/playlist.m3u8")!))
}

if (showImagePicker) {
ImagePicker(isShown: $showImagePicker, url: $url)
}
}
}
}

struct PlayerView: UIViewRepresentable {
let player: AVPlayer
func updateUIView(_ uiView: UIView, context: UIViewRepresentableContext<PlayerView>) {
(uiView as? PlayerUIView)?.updatePlayer(player: player)
}

func makeUIView(context: Context) -> UIView {
return PlayerUIView(player: player)
}
}

class PlayerUIView: UIView {
private let playerLayer = AVPlayerLayer()
init(player: AVPlayer) {
super.init(frame: .zero)

playerLayer.player = player
layer.addSublayer(playerLayer)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutSubviews() {
super.layoutSubviews()
playerLayer.frame = bounds
}

func updatePlayer(player: AVPlayer) {
self.playerLayer.player = player
}
}

struct PlayerContainerView : View {

@State var seekPos = 0.0

private let player: AVPlayer
init(player: AVPlayer) {
self.player = player
}
var body: some View {
VStack {
PlayerView(player: player)
PlayerControlsView(player: player)
}
}
}

struct PlayerControlsView : View {
@State var playerPaused = true
@State var seekPos = 0.0
let player: AVPlayer
var body: some View {
HStack {
Button(action: {
self.playerPaused.toggle()
if self.playerPaused {
self.player.pause()
}
else {
self.player.play()
}
}) {
Image(systemName: playerPaused ? "play" : "pause")
.padding(.leading, 20)
.padding(.trailing, 20)
}
Slider(value: $seekPos, from: 0, through: 1, onEditingChanged: { _ in
guard let item = self.player.currentItem else {
return
}

let targetTime = self.seekPos * item.duration.seconds
self.player.seek(to: CMTime(seconds: targetTime, preferredTimescale: 600))
})
.padding(.trailing, 20)
}
}
}

struct ImagePicker: UIViewControllerRepresentable {

@Binding var isShown: Bool
@Binding var url: URL?

class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate {

@Binding var isShown: Bool
@Binding var url: URL?

init(isShown: Binding<Bool>, url: Binding<URL?>) {
_isShown = isShown
_url = url
}

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {

let info = convertFromUIImagePickerControllerInfoKeyDictionary(info)
guard let mediaType = info[convertFromUIImagePickerControllerInfoKey(UIImagePickerController.InfoKey.mediaType)] as? String,
mediaType == (kUTTypeMovie as String),
let uiURL = info[convertFromUIImagePickerControllerInfoKey(UIImagePickerController.InfoKey.mediaURL)] as? URL
else { return }

url = uiURL
isShown = false
}

func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
isShown = false
}

}

func makeCoordinator() -> Coordinator {
return Coordinator(isShown: $isShown, url: $url)
}

func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePicker>) -> UIImagePickerController {
let picker = UIImagePickerController()
picker.mediaTypes = [kUTTypeMovie as String]
picker.delegate = context.coordinator
return picker
}

func updateUIViewController(_ uiViewController: UIImagePickerController,
context: UIViewControllerRepresentableContext<ImagePicker>) {
}
}

fileprivate func convertFromUIImagePickerControllerInfoKeyDictionary(_ input: [UIImagePickerController.InfoKey: Any]) -> [String: Any] {
return Dictionary(uniqueKeysWithValues: input.map {key, value in (key.rawValue, value)})
}

fileprivate func convertFromUIImagePickerControllerInfoKey(_ input: UIImagePickerController.InfoKey) -> String {
return input.rawValue
}

#if DEBUG
struct ContentView_Previews : PreviewProvider {
static var previews: some View {
ContentView(showImagePicker: true)
}
}
#endif

最佳答案

您将 updateUIView 留空。你应该实现它:

func updateUIView(_ uiView: UIView, context: UIViewRepresentableContext<PlayerView>) {
(uiView as? PlayerUIView)?.updatePlayer(player: player)
}

并将以下方法添加到您的 PlayerUIView:

func updatePlayer(player: AVPlayer) {
self.playerLayer.player = player
}

关于SwiftUI:如何在使用 ImagePickerController 从设备加载视频后正确编码 AVPlayer?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57024870/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com