Forum Xamarin.Forms

Announcement:

The Xamarin Forums have officially moved to the new Microsoft Q&A experience. Microsoft Q&A is the home for technical questions and answers at across all products at Microsoft now including Xamarin!

To create new threads and ask questions head over to Microsoft Q&A for .NET and get involved today.

Xamarin Forms: How to capture the webview video/audio play time?

SreeeeSreeee INMember ✭✭✭✭✭
edited August 2020 in Xamarin.Forms

I am using webview for playing video and audio in my projects like the below screenshot.

enter image description here

I need to capture the video/audio playtime when going back from that page. I research about this but didn't get anything useful.

Is there any way to fetch the video/audio playtime?

Update

Video: 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;
}

Audio: XAML

<WebView 
    x:Name="web_view"
    HorizontalOptions="FillAndExpand"
    VerticalOptions="FillAndExpand">
</WebView>

XAML.CS

web_view.Source = audiourl;

Sample Video URL: https://player.vimeo.com/video/434126696?api=1&player_id=player1

Sample Audio URL: http://catholic-brain.s3.amazonaws.com/qa/dc/cbrain-app/files/doc-lib/2017/08/16/11/21/59/604/head/Catholic-brain-01-The-Rosary-Song.mp3

I am using a custom renderer in ios video webview for the transparent background.

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;
    }
}

Best Answers

  • jezhjezh Member, Xamarin Team Xamurai
    Accepted Answer

    To do this in Xamarin.Forms you can use the MediaElement that was introduced in Xamarin.Forms 4.5.
    To do so, there are a couple things you need to do:-

    1.Determine a stream to play from the video configuration stored on Vimeo.
    You can get this configuration by inspecting the JSON that is returned from the below url:-

      http://player.vimeo.com/video/36671239/config
    

    i.e., where 36671239 is your Video ID on Vimeo.

    Below is an example of one of stream, which is in mp4 video format:-

    https://vod-progressive.akamaized.net/exp=1597882056~acl=*/84157673.mp4*~hmac=1230da01c045577d047b307a0d3679b46cc9b0bbc1d0312e272b67bb31d5129c/vimeo-prod-skyfire-std-us/01/2334/1/36671239/84157673.mp4

    2.Very Important
    The MediaElement is in Preview Release, and if you don't do the following upon application start-up you will almost always receive System.Reflection.TargetInvocationException being thrown with it crashing and you will be puzzled for a while.

    To avoid this add the following for the time being in the App() constructor:-

     Device.SetFlags(new[] { "MediaElement_Experimental" });
    

    3.The MediaElement doesn't issue PropertyChanged notifications for the Position property, at present.
    To get around this however, you can use your own Timer, and retrieve the Position property of the video that is exposed, and use that however.

    This is by no means fit for production, as you wouldn't want the timer always running, but is to just illustrate that you can achieve what you want:-

    Set up an active timer in the constructor like so:-

    Device.StartTimer(TimeSpan.FromSeconds(0.5), () =>
    {
        if (videoPlayer.CurrentState == MediaElementState.Playing)
        {
            string strPlayPosition = videoPlayer.Position.ToString(@"hh\:mm\:ss");
            lblCurrentVideoTime.Text = strPlayPosition;
        }
        return true;
    });
    

    4.Add the following on the ContentPage:-

    <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>
    

    The result will like this:

    Refer :https://stackoverflow.com/a/63496183/10308336

  • SreeeeSreeee INMember ✭✭✭✭✭
    Accepted Answer

    Code for performing the JSON extraction:

    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; }
    }
    

Answers

  • jezhjezh Member, Xamarin Team Xamurai
    edited August 2020

    It's not possible to do this just by opening a link via a webView.

    We can't extract the time from a tab playing an audio file or from embedded video (eg: Youtube or Vime.), we need to communicate to the decoder via JavaScript to know the decoded playback time.

    We could try to make custom html in a HtmlWebViewSource where the html creates an <audio> tag for mp3 or embeds video player. The html should have Javascript to echo the time via relevant methods(eg: using audio.currentTime if audio tag, or Video API's own command for extracting time values).

  • SreeeeSreeee INMember ✭✭✭✭✭
    edited August 2020

    @jezh Is there any way to call an event when the play/pause button of video/audio is pressed? If yes, we can start a stopwatch when the play button of video/audio is pressed. When pause we can stop the stopwatch and find out the playtime.

    what about implementing a video/audio(vimeo video) player? Suggest me the best player having the option to fetch playtime?

  • jezhjezh Member, Xamarin Team Xamurai
    Accepted Answer

    To do this in Xamarin.Forms you can use the MediaElement that was introduced in Xamarin.Forms 4.5.
    To do so, there are a couple things you need to do:-

    1.Determine a stream to play from the video configuration stored on Vimeo.
    You can get this configuration by inspecting the JSON that is returned from the below url:-

      http://player.vimeo.com/video/36671239/config
    

    i.e., where 36671239 is your Video ID on Vimeo.

    Below is an example of one of stream, which is in mp4 video format:-

    https://vod-progressive.akamaized.net/exp=1597882056~acl=*/84157673.mp4*~hmac=1230da01c045577d047b307a0d3679b46cc9b0bbc1d0312e272b67bb31d5129c/vimeo-prod-skyfire-std-us/01/2334/1/36671239/84157673.mp4

    2.Very Important
    The MediaElement is in Preview Release, and if you don't do the following upon application start-up you will almost always receive System.Reflection.TargetInvocationException being thrown with it crashing and you will be puzzled for a while.

    To avoid this add the following for the time being in the App() constructor:-

     Device.SetFlags(new[] { "MediaElement_Experimental" });
    

    3.The MediaElement doesn't issue PropertyChanged notifications for the Position property, at present.
    To get around this however, you can use your own Timer, and retrieve the Position property of the video that is exposed, and use that however.

    This is by no means fit for production, as you wouldn't want the timer always running, but is to just illustrate that you can achieve what you want:-

    Set up an active timer in the constructor like so:-

    Device.StartTimer(TimeSpan.FromSeconds(0.5), () =>
    {
        if (videoPlayer.CurrentState == MediaElementState.Playing)
        {
            string strPlayPosition = videoPlayer.Position.ToString(@"hh\:mm\:ss");
            lblCurrentVideoTime.Text = strPlayPosition;
        }
        return true;
    });
    

    4.Add the following on the ContentPage:-

    <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>
    

    The result will like this:

    Refer :https://stackoverflow.com/a/63496183/10308336

  • SreeeeSreeee INMember ✭✭✭✭✭

    @jezh I will do this and update you soon, thanks in advance

  • SreeeeSreeee INMember ✭✭✭✭✭
    edited August 2020

    @jezh I have tried the MediaElement but the video or audio is not displaying on the UI.

    I have done a sample and uploaded it here, could you please check what I am missing?

    And I didn't get the first step, how I can create a stream for my Vimeo videos? For audio files, do I need to create the stream? Could you please explain the audio part implementation? I have added the audio part in the sample, it is not visible on UI, but I can hear the audio.

    Sample Video URL: https://player.vimeo.com/video/434126696?api=1&player_id=player1

    Sample Audio URL: http://catholic-brain.s3.amazonaws.com/qa/dc/cbrain-app/files/doc-lib/2017/08/16/11/21/59/604/head/Catholic-brain-01-The-Rosary-Song.mp3

    My Vimeo videos have no extension like .mp4

  • SreeeeSreeee INMember ✭✭✭✭✭

    @jezh I have completed the audio part, but the video is not playing.

  • SreeeeSreeee INMember ✭✭✭✭✭
    Accepted Answer

    Code for performing the JSON extraction:

    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; }
    }
    
Sign In or Register to comment.