omz:forum

    • Register
    • Login
    • Search
    • Recent
    • Popular

    Welcome!

    This is the community forum for my apps Pythonista and Editorial.

    For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.


    Autoplay mp4 video in WebView

    Pythonista
    5
    13
    11371
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • yueqiw
      yueqiw last edited by

      I'm new to Pythonista and really like it. I'm trying to play .mp4 videos in ui.WebView(), but I cannot set the video to autoplay with playback controls hidden. The goal is to (1) program the video to start playing by itself and (2) disable/hide the playback control, so that it looks like background video.

      I tried two approaches. First by load_html() :
      webview = ui.WebView()
      html = TEMPLATE.replace('{{FPATH}}', absfilepath)
      webview.load_html(html)
      webview.present()
      

      The html has the following lines:

      <video autoplay>
          <source src="{{FPATH}}" type="video/mp4">
      </video>
      

      The video does not play when I set it to autoplay, It only plays when I use <video autoplay controls>, but in this case, I need to click the play button to start playing.

      It looks like the iOS WebKit now allows autoplay for videos without soundtrack. https://webkit.org/blog/6784/new-video-policies-for-ios/
      However, my video does not contain soundtrack, but it still cannot autoplay, even after I use <video muted autoplay>.

      Is there any solution to this?

      The second approach I tried is load_url()

      I tried webview.load_url(absfilepath) to load the .mp4 files directly onto WebView. It works and autoplays, but it always comes with playback controls. The video can be stopped by tapping on the screen and does not look like background video. Is there any way to hide the playback controls?

      Thanks!

      1 Reply Last reply Reply Quote 0
      • cvp
        cvp last edited by cvp

        For me, this works, after download of the MP4 as a local file

        cover_image = ui.WebView()
        cover_image.load_url(os.path.abspath(local_file))
        

        Sorry, perhaps I didn't read correctly your request, if so forget this reply

        But, it plays automatically the MP4 and hides the commands after one second!

        If you add

        cover_image.touch_enabled = False
        

        You can't stop the video

        1 Reply Last reply Reply Quote 1
        • scj643
          scj643 last edited by scj643

          My objc_tools library has view's for AV players which can do autoplay

          https://github.com/scj643/objc_tools/blob/master/objc_tools/ui/av.py

          You would want to use a PlayerLayerView

          1 Reply Last reply Reply Quote 1
          • yueqiw
            yueqiw last edited by yueqiw

            @cvp Thanks for the suggestion! I didn't know that ui.WebView() can inherit the methods of ui.View(). Now looks like there are a lot more things I can do with WebView.

            I ended up adding a button so that the background video (without playback control) starts playing after clicking the "start game" button. This is done by using eval_js() in the button_tapped() function

            The html template contains the following video tag:

            <video id="myvideo" preload="auto">
                <source src="{{FPATH}}" type="video/mp4">
            </video>
            

            The Python code load html and uses eval_js() to start video play after clicking the button.

            v = ui.View()
            webview = ui.WebView()
            v.add_subview(webview)
            
            html = TEMPLATE.replace('{{FPATH}}', absfilepath)
            webview.load_html(html)
            
            def button_tapped(sender):
                webview.eval_js('document.getElementById("myvideo").play();')
            
            button = ui.Button(title="Start Game")
            button.action = button_tapped
            v.add_subview(button)
            
            v.frame = (0,0,500,500)
            webview.frame = (0,0,500,500)
            v.present()
            

            So it looks like the user has to click on something to play any kind of video. Because simply calling webview.eval_js('document.getElementById("myvideo").play();') outside the button_tapped() function does not make the video play.

            1 Reply Last reply Reply Quote 0
            • JonB
              JonB last edited by

              I wonder if you have tried a pause of some kind, to make sure the page and vieeo have loaded before trying the javascript?

              I think in the past I have checked document.ready (I think) inside a while True/sleep loop. Since the user is not clickng on the webview, I dont think the webview knows the difference between a call from your button action, and a call from elsewhere. maybe (though i doubt it) you might need to run the command on the main thread, which could be the other difference.

              1 Reply Last reply Reply Quote 1
              • yueqiw
                yueqiw last edited by

                @scj643 Thanks! I'll definitely install the library and try it out. I don't have experience using Objective-C, though.

                1 Reply Last reply Reply Quote 0
                • yueqiw
                  yueqiw last edited by

                  @JonB I tried pause and other things to make sure the video is properly loaded. My conclusion is that the video has to be triggered by some kind of user input, either by the iOS playback controls or any kind of button click (a button in html/js or a button in ui.Button() with eval_js(). I'm not exactly sure how the system prevents autoplay internally (maybe a older version of iOS Webkit), but now I've decided to go with a button trigger.

                  1 Reply Last reply Reply Quote 0
                  • JonB
                    JonB last edited by JonB

                    My point is the webview doesn't know that a button in the ui was pushed. So this isnt some sort of security measure -- from the webviews perspective, it gets an evaljs that starts the video.

                    The code below worked for me. The view has to be presented, and maybe onscreen, already for this to work, which might be why it didnt work for you(if you called evaljs before present). The checking code i have was protective but might not be necessary. Also, I had to add a file://, but perhaps you already had that in your absfilepath.

                    One final note... if you simply load the video directly, no html,
                    webview.load_url(absfilepath)
                    the video is shown and played automatically, though you then have no control programatically i think.

                    import ui
                    import os,time
                    
                    # [~/Documents]$ wget http://techslides.com/demos/sample-videos/small.mp4
                    absfilepath=os.path.abspath('small.mp4')
                    
                    
                    TEMPLATE='''
                    <video id="myvideo" autoplay preload="auto">
                        <source src="file://{{FPATH}}" type="video/mp4">
                    </video>
                    '''
                    v = ui.View()
                    webview = ui.WebView()
                    v.add_subview(webview)
                    
                    html = TEMPLATE.replace('{{FPATH}}', absfilepath)
                    webview.load_html(html)
                    
                    #button = ui.Button(title="Start Game")
                    #button.action = button_tapped
                    #v.add_subview(button)
                    
                    v.frame = (0,0,500,500)
                    webview.frame = (0,0,500,500)
                    v.present()
                    
                    #after view is presented, check that html is loaded, then play
                    # might be better to check document.readyState, but sometimes this can be complete before you start
                    id=webview.eval_js('document.getElementById("myvideo").id')
                    while not id =='myvideo':
                    	print('sleeping')	
                    	time.sleep(1)
                    	id=webview.eval_js('document.getElementById("myvideo").id')
                    webview.eval_js('document.getElementById("myvideo").play();')
                    
                    1 Reply Last reply Reply Quote 0
                    • yueqiw
                      yueqiw last edited by

                      @JonB

                      The view has to be presented, and maybe onscreen, already for this to work, which might be why it didnt work for you(if you called evaljs before present).

                      You are correct! Simply putting webview.eval_js('document.getElementById("myvideo").play();') after v.present() solved the problem -- Now it autoplays without any trigger.

                      I did try webview.load_url(absfilepath), and as you said, it does not give much programatical control.

                      Thanks a lot for the help!

                      1 Reply Last reply Reply Quote 0
                      • scj643
                        scj643 last edited by ccc

                        If you are on slack I can discuss my module in more detail.

                        1 Reply Last reply Reply Quote 0
                        • yueqiw
                          yueqiw last edited by

                          @scj643 Thanks! I'll get a slack in case I need more help.

                          I thought I wouldn't have to use objc, but I just run into another problem that might need some objc: https://forum.omz-software.com/topic/3926/transparent-scene-background-using-objc_utils

                          1 Reply Last reply Reply Quote 0
                          • robertiii
                            robertiii last edited by

                            Not sure what I’m doing wrong but this isn’t working for me

                            1 Reply Last reply Reply Quote 0
                            • JonB
                              JonB last edited by

                              Do you have a gist or something of your code?

                              1 Reply Last reply Reply Quote 0
                              • First post
                                Last post
                              Powered by NodeBB Forums | Contributors