Xamarin Forms:如何捕获 webview video/audio 播放时间?
Xamarin Forms: How to capture the webview video/audio play time?
我正在使用 webview 在我的项目中播放视频和音频,如下图所示。
我需要在从该页面返回时捕获 video/audio 播放时间。我对此进行了研究,但没有得到任何有用的信息。
有什么方法可以获取 video/audio 播放时间吗?
更新
视频:XAML
<local:VideoWebview
x:Name="web_view"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand">
</local:VideoWebview>
XAML.CS
if (Device.RuntimePlatform == Device.iOS)
{
Device.BeginInvokeOnMainThread(() =>
{
web_view.Url = videourl;
});
}
else
{
web_view.Source = videourl;
}
音频:XAML
<WebView
x:Name="web_view"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand">
</WebView>
XAML.CS
web_view.Source = audiourl;
示例视频 URL:https://player.vimeo.com/video/434126696?api=1&player_id=player1
我在 ios 视频网络视图中使用自定义渲染器来实现透明背景。
public class VideoWebviewRenderer : ViewRenderer<VideoWebview, WKWebView>
{
WKWebView wkWebView;
protected override void OnElementChanged(ElementChangedEventArgs<VideoWebview> e)
{
base.OnElementChanged(e);
if (Control == null)
{
WKWebViewConfiguration configuration = new WKWebViewConfiguration();
configuration.AllowsInlineMediaPlayback = true;
wkWebView = new WKWebView(CGRect.Empty, configuration);
//transparent background
wkWebView = new WKWebView(CGRect.Empty, configuration);
wkWebView.BackgroundColor = UIColor.Clear;
wkWebView.ScrollView.BackgroundColor = UIColor.Clear;
wkWebView.Opaque = false;
if (Element.Url != null)
{
wkWebView.LoadRequest(new NSUrlRequest(new NSUrl((Element).Url)));
}
SetNativeControl(wkWebView);
}
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName.Equals(nameof(Element.Url)))
{
wkWebView.LoadRequest(new NSUrlRequest(new NSUrl((Element).Url)));
}
}
public override void Draw(CGRect rect)
{
base.Draw(rect);
Control.Frame = rect;
}
}
更新1
@Pete 我试过 MediaElement
但是 UI 上没有显示视频或音频。
我做了一个样例并上传了here,你能检查一下我遗漏了什么吗?
而且我没有完成第一步,如何为我的 Vimeo 视频创建流?对于音频文件,我需要创建流吗?你能解释一下音频部分的实现吗?我在示例中添加了音频部分,它在 UI 上不可见,但我可以听到音频。
示例视频 URL:https://player.vimeo.com/video/434126696?api=1&player_id=player1
我的 Vimeo 视频没有像 .mp4 这样的扩展名
更新2
所以在播放视频之前,我们需要下载视频的配置。我看了一下配置,有 5 种不同的配置。所以我们需要从progressive list中取出URL的值对吧?
不幸的是,我已经从共享源link在本地站点进行了测试,但无法获取播放时间。
Video URL: https://player.vimeo.com/video/434126696?api=1&player_id=player1
视频 url 是一个包装播放器 link。我们需要玩家暴露 javascript api 的播放时间。然后我们可以在本机代码中调用它。
音频url是一个原始来源(.mp3),我们只能得到它的持续时间。
NSString url = new NSString("xxx.mp3");
if (url.PathExtension == new NSString("mp3"))
{
NSUrl videoUrl = new NSUrl(url.ToString());
AVUrlAsset avUrl = new AVUrlAsset(videoUrl, new NSDictionary(AVUrlAsset.PreferPreciseDurationAndTimingKey, true));
CMTime time = avUrl.Duration;
float seconds = time.Value / time.TimeScale;
Console.WriteLine("====================" + seconds );
}
如果需要获取播放时间,也可以使用wrapped audio player。并且还晒出了它javascriptapi的播放时间
一般,如果使用audio
和video
属性 of Html 要播放 原始来源 url ,我们可以调用 js 来获取 iOS 中的 currentTime
和 duration
如下:
//video
string JsStr = "(document.getElementsByTagName(\"video\")[0]).currentTime";
// audio
//string JsStr = "(document.getElementsByTagName(\"audio\")[0]).currentTime";
WKJavascriptEvaluationResult handler = (NSObject result, NSError err) =>
{
if (err != null)
{
System.Console.WriteLine("================"+err);
}
if (result != null)
{
System.Console.WriteLine("currentTime is : "+result);
}
};
wkWebView.EvaluateJavaScript(JsStr, handler);
下面是如何使用 Xamarin.Forms 执行此操作的答案,正如您在评论中提到的,如果有任何替代播放器提供获取游戏时间,那么这里是:-
要在 Xamarin.Forms 中执行此操作,您可以使用 [=][=] 中引入的 MediaElement 149=]4.5.
为此,您需要做几件事:-
- 根据存储在 Vimeo.
上的视频配置确定要播放的流
您可以通过检查从下面 url:-
返回的 JSON 来获取此配置
http://player.vimeo.com/video/36671239/config
即,36671239 是您在 Vimeo 上的 视频 ID。
下面是一个流的例子,它是 mp4 视频格式:-
https://vod-progressive.akamaized.net/exp=1597882056~acl=%2A%2F84157673.mp4%2A~hmac=1230da01c045577d047b307a0d3679b46cc9b0bbc1d0312e272b67bb31d5129c/vimeo-prod-skyfire-std-us/01/2334/1/36671239/84157673.mp4
- 非常重要:-
MediaElement在预览版中,如果您在申请时不执行以下操作start-up,您将几乎总是收到 System.Reflection.TargetInvocationException 被抛出并崩溃,你会困惑一段时间。
为避免这种情况,暂时在 App() 构造函数中添加以下内容:-
Device.SetFlags(new[] { "MediaElement_Experimental" });
- MediaElement 不会为 Position 发出 PropertyChanged 通知 属性, 目前.
然而,要解决此问题,您可以使用自己的 Timer,并检索视频的 Position 属性那是暴露的,但是请使用它。
这绝不适合生产,因为您不希望计时器总是如此 运行,但这只是为了说明您可以实现您想要的:-
像这样在构造函数中设置一个活动计时器:-
Device.StartTimer(TimeSpan.FromSeconds(0.5), () =>
{
if (videoPlayer.CurrentState == MediaElementState.Playing)
{
string strPlayPosition = videoPlayer.Position.ToString(@"hh\:mm\:ss");
lblCurrentVideoTime.Text = strPlayPosition;
}
return true;
});
- 在 ContentPage 添加以下内容:-
<pre><code><Grid BackgroundColor="#242475">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<MediaElement
x:Name="videoPlayer"
Grid.Row="0"
Aspect="AspectFit"
BackgroundColor="Black"
ShowsPlaybackControls="True"
Source="https://vod-progressive.akamaized.net/exp=1597882056~acl=%2A%2F84157673.mp4%2A~hmac=1230da01c045577d047b307a0d3679b46cc9b0bbc1d0312e272b67bb31d5129c/vimeo-prod-skyfire-std-us/01/2334/1/36671239/84157673.mp4" />
<StackLayout
Grid.Row="1"
HorizontalOptions="CenterAndExpand"
Orientation="Horizontal"
VerticalOptions="Center">
<Label
FontAttributes="Bold"
FontSize="18"
Text="CURRENT VIDEO TIME : "
TextColor="White" />
<Label
x:Name="lblCurrentVideoTime"
FontAttributes="Bold"
FontSize="18"
TextColor="White" />
</StackLayout>
</Grid>
你会看到类似下面的内容,以及你想从 Vimeo 观看的任何视频:-
MediaElement 也可用于 audio。
更新 1
我看过你提到的视频 ID (434126696)。
并且在配置中指定了多个 mp4 流。
一个这样的流是:-
https://vod-progressive.akamaized.net/exp=1598157872~acl=%2Fvimeo-prod-skyfire-std-us%2F01%2F1825%2F17%2F434126696%2F1890592390.mp4~hmac=a0ac67f23fdd68df9d16fb2db33e8b2b00d0dc3626375d2a4c6ba7a5203b935e/vimeo-prod-skyfire-std-us/01/1825/17/434126696/1890592390.mp4
如果您将此 mp4 link 放在 MediaElement 中,在我的示例中,就像这样:-
<pre><code> <MediaElement
x:Name="videoPlayer"
Grid.Row="0"
Aspect="AspectFit"
BackgroundColor="Black"
ShowsPlaybackControls="True"
Source="https://vod-progressive.akamaized.net/exp=1598157872~acl=%2Fvimeo-prod-skyfire-std-us%2F01%2F1825%2F17%2F434126696%2F1890592390.mp4~hmac=a0ac67f23fdd68df9d16fb2db33e8b2b00d0dc3626375d2a4c6ba7a5203b935e/vimeo-prod-skyfire-std-us/01/1825/17/434126696/1890592390.mp4" />
您将看到您的视频正在播放。
你必须分析返回的JSON。在 C# 中,您可以像这样下载配置:-
使用 (var objClient = new WebClient())
{
string strResponse = objClient.DownloadString("http://player.vimeo.com/video/434126696/config");
}
然后如果你使用 JSON 检查器,你将能够看到暴露的各种 mp4 流为您的视频提供不同的分辨率。然后,您可以选择一个合适的视频来显示您的视频。
执行 JSON 提取的代码:
public void ExtractConfiguration(string vimeoUrl)
{
try
{
using (var objClient = new WebClient())
{
string strResponse = objClient.DownloadString(vimeoUrl);
VimeoConfig vimeoConfig = new VimeoConfig();
vimeoConfig = JsonConvert.DeserializeObject<VimeoConfig>(strResponse.ToString());
string url = vimeoConfig.request.files.progressive[0].url;
videoPlayer.Source = url;
}
}
catch(Exception e)
{
Debug.WriteLine("Exception:>>"+e);
}
}
//Model
public class VimeoConfig
{
public Request request { get; set; }
}
public class Request
{
public Files files { get; set; }
}
public class Files
{
public List<Progressive> progressive { get; set; }
}
public class Progressive
{
public string url { get; set; }
}
我正在使用 webview 在我的项目中播放视频和音频,如下图所示。
我需要在从该页面返回时捕获 video/audio 播放时间。我对此进行了研究,但没有得到任何有用的信息。
有什么方法可以获取 video/audio 播放时间吗?
更新
视频:XAML
<local:VideoWebview
x:Name="web_view"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand">
</local:VideoWebview>
XAML.CS
if (Device.RuntimePlatform == Device.iOS)
{
Device.BeginInvokeOnMainThread(() =>
{
web_view.Url = videourl;
});
}
else
{
web_view.Source = videourl;
}
音频:XAML
<WebView
x:Name="web_view"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand">
</WebView>
XAML.CS
web_view.Source = audiourl;
示例视频 URL:https://player.vimeo.com/video/434126696?api=1&player_id=player1
我在 ios 视频网络视图中使用自定义渲染器来实现透明背景。
public class VideoWebviewRenderer : ViewRenderer<VideoWebview, WKWebView>
{
WKWebView wkWebView;
protected override void OnElementChanged(ElementChangedEventArgs<VideoWebview> e)
{
base.OnElementChanged(e);
if (Control == null)
{
WKWebViewConfiguration configuration = new WKWebViewConfiguration();
configuration.AllowsInlineMediaPlayback = true;
wkWebView = new WKWebView(CGRect.Empty, configuration);
//transparent background
wkWebView = new WKWebView(CGRect.Empty, configuration);
wkWebView.BackgroundColor = UIColor.Clear;
wkWebView.ScrollView.BackgroundColor = UIColor.Clear;
wkWebView.Opaque = false;
if (Element.Url != null)
{
wkWebView.LoadRequest(new NSUrlRequest(new NSUrl((Element).Url)));
}
SetNativeControl(wkWebView);
}
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName.Equals(nameof(Element.Url)))
{
wkWebView.LoadRequest(new NSUrlRequest(new NSUrl((Element).Url)));
}
}
public override void Draw(CGRect rect)
{
base.Draw(rect);
Control.Frame = rect;
}
}
更新1
@Pete 我试过 MediaElement
但是 UI 上没有显示视频或音频。
我做了一个样例并上传了here,你能检查一下我遗漏了什么吗?
而且我没有完成第一步,如何为我的 Vimeo 视频创建流?对于音频文件,我需要创建流吗?你能解释一下音频部分的实现吗?我在示例中添加了音频部分,它在 UI 上不可见,但我可以听到音频。
示例视频 URL:https://player.vimeo.com/video/434126696?api=1&player_id=player1
我的 Vimeo 视频没有像 .mp4 这样的扩展名
更新2
所以在播放视频之前,我们需要下载视频的配置。我看了一下配置,有 5 种不同的配置。所以我们需要从progressive list中取出URL的值对吧?
不幸的是,我已经从共享源link在本地站点进行了测试,但无法获取播放时间。
Video URL: https://player.vimeo.com/video/434126696?api=1&player_id=player1
视频 url 是一个包装播放器 link。我们需要玩家暴露 javascript api 的播放时间。然后我们可以在本机代码中调用它。
音频url是一个原始来源(.mp3),我们只能得到它的持续时间。
NSString url = new NSString("xxx.mp3");
if (url.PathExtension == new NSString("mp3"))
{
NSUrl videoUrl = new NSUrl(url.ToString());
AVUrlAsset avUrl = new AVUrlAsset(videoUrl, new NSDictionary(AVUrlAsset.PreferPreciseDurationAndTimingKey, true));
CMTime time = avUrl.Duration;
float seconds = time.Value / time.TimeScale;
Console.WriteLine("====================" + seconds );
}
如果需要获取播放时间,也可以使用wrapped audio player。并且还晒出了它javascriptapi的播放时间
一般,如果使用audio
和video
属性 of Html 要播放 原始来源 url ,我们可以调用 js 来获取 iOS 中的 currentTime
和 duration
如下:
//video
string JsStr = "(document.getElementsByTagName(\"video\")[0]).currentTime";
// audio
//string JsStr = "(document.getElementsByTagName(\"audio\")[0]).currentTime";
WKJavascriptEvaluationResult handler = (NSObject result, NSError err) =>
{
if (err != null)
{
System.Console.WriteLine("================"+err);
}
if (result != null)
{
System.Console.WriteLine("currentTime is : "+result);
}
};
wkWebView.EvaluateJavaScript(JsStr, handler);
下面是如何使用 Xamarin.Forms 执行此操作的答案,正如您在评论中提到的,如果有任何替代播放器提供获取游戏时间,那么这里是:-
要在 Xamarin.Forms 中执行此操作,您可以使用 [=][=] 中引入的 MediaElement 149=]4.5.
为此,您需要做几件事:-
- 根据存储在 Vimeo. 上的视频配置确定要播放的流
您可以通过检查从下面 url:-
返回的 JSON 来获取此配置
http://player.vimeo.com/video/36671239/config
即,36671239 是您在 Vimeo 上的 视频 ID。
下面是一个流的例子,它是 mp4 视频格式:-
https://vod-progressive.akamaized.net/exp=1597882056~acl=%2A%2F84157673.mp4%2A~hmac=1230da01c045577d047b307a0d3679b46cc9b0bbc1d0312e272b67bb31d5129c/vimeo-prod-skyfire-std-us/01/2334/1/36671239/84157673.mp4
- 非常重要:-
MediaElement在预览版中,如果您在申请时不执行以下操作start-up,您将几乎总是收到 System.Reflection.TargetInvocationException 被抛出并崩溃,你会困惑一段时间。
为避免这种情况,暂时在 App() 构造函数中添加以下内容:-
Device.SetFlags(new[] { "MediaElement_Experimental" });
- MediaElement 不会为 Position 发出 PropertyChanged 通知 属性, 目前.
然而,要解决此问题,您可以使用自己的 Timer,并检索视频的 Position 属性那是暴露的,但是请使用它。
这绝不适合生产,因为您不希望计时器总是如此 运行,但这只是为了说明您可以实现您想要的:-
像这样在构造函数中设置一个活动计时器:-
Device.StartTimer(TimeSpan.FromSeconds(0.5), () =>
{
if (videoPlayer.CurrentState == MediaElementState.Playing)
{
string strPlayPosition = videoPlayer.Position.ToString(@"hh\:mm\:ss");
lblCurrentVideoTime.Text = strPlayPosition;
}
return true;
});
- 在 ContentPage 添加以下内容:-
<pre><code><Grid BackgroundColor="#242475">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<MediaElement
x:Name="videoPlayer"
Grid.Row="0"
Aspect="AspectFit"
BackgroundColor="Black"
ShowsPlaybackControls="True"
Source="https://vod-progressive.akamaized.net/exp=1597882056~acl=%2A%2F84157673.mp4%2A~hmac=1230da01c045577d047b307a0d3679b46cc9b0bbc1d0312e272b67bb31d5129c/vimeo-prod-skyfire-std-us/01/2334/1/36671239/84157673.mp4" />
<StackLayout
Grid.Row="1"
HorizontalOptions="CenterAndExpand"
Orientation="Horizontal"
VerticalOptions="Center">
<Label
FontAttributes="Bold"
FontSize="18"
Text="CURRENT VIDEO TIME : "
TextColor="White" />
<Label
x:Name="lblCurrentVideoTime"
FontAttributes="Bold"
FontSize="18"
TextColor="White" />
</StackLayout>
</Grid>
你会看到类似下面的内容,以及你想从 Vimeo 观看的任何视频:-
MediaElement 也可用于 audio。
更新 1
我看过你提到的视频 ID (434126696)。
并且在配置中指定了多个 mp4 流。
一个这样的流是:-
https://vod-progressive.akamaized.net/exp=1598157872~acl=%2Fvimeo-prod-skyfire-std-us%2F01%2F1825%2F17%2F434126696%2F1890592390.mp4~hmac=a0ac67f23fdd68df9d16fb2db33e8b2b00d0dc3626375d2a4c6ba7a5203b935e/vimeo-prod-skyfire-std-us/01/1825/17/434126696/1890592390.mp4
如果您将此 mp4 link 放在 MediaElement 中,在我的示例中,就像这样:-
<pre><code> <MediaElement
x:Name="videoPlayer"
Grid.Row="0"
Aspect="AspectFit"
BackgroundColor="Black"
ShowsPlaybackControls="True"
Source="https://vod-progressive.akamaized.net/exp=1598157872~acl=%2Fvimeo-prod-skyfire-std-us%2F01%2F1825%2F17%2F434126696%2F1890592390.mp4~hmac=a0ac67f23fdd68df9d16fb2db33e8b2b00d0dc3626375d2a4c6ba7a5203b935e/vimeo-prod-skyfire-std-us/01/1825/17/434126696/1890592390.mp4" />
您将看到您的视频正在播放。
你必须分析返回的JSON。在 C# 中,您可以像这样下载配置:-
使用 (var objClient = new WebClient()) { string strResponse = objClient.DownloadString("http://player.vimeo.com/video/434126696/config"); }
然后如果你使用 JSON 检查器,你将能够看到暴露的各种 mp4 流为您的视频提供不同的分辨率。然后,您可以选择一个合适的视频来显示您的视频。
执行 JSON 提取的代码:
public void ExtractConfiguration(string vimeoUrl)
{
try
{
using (var objClient = new WebClient())
{
string strResponse = objClient.DownloadString(vimeoUrl);
VimeoConfig vimeoConfig = new VimeoConfig();
vimeoConfig = JsonConvert.DeserializeObject<VimeoConfig>(strResponse.ToString());
string url = vimeoConfig.request.files.progressive[0].url;
videoPlayer.Source = url;
}
}
catch(Exception e)
{
Debug.WriteLine("Exception:>>"+e);
}
}
//Model
public class VimeoConfig
{
public Request request { get; set; }
}
public class Request
{
public Files files { get; set; }
}
public class Files
{
public List<Progressive> progressive { get; set; }
}
public class Progressive
{
public string url { get; set; }
}