Feature request: Progressive AVI playback

Adam Zey
2006-04-11
2013-05-08
  • Adam Zey
    Adam Zey
    2006-04-11

    When MPC currently plays an AVI file on an HTTP server, it downloads the entire file before it begins playing. It'd be nice if MPC would start playing the file immediately, and allow you to navigate within the part that is already downloaded.

    HTTP 1.1 has support for the "Range" header, which allows a player to begin a download from any part in the file. On the surface, it seems like playing a file over HTTP could very easily be made to work just like a local file; do a HEAD request to get the file info, and then use ranges to do random access reads on the file (Most will be sequential, you'd only need random access at the start to grab the index and stuff). This method would sort of be a hack, but it'd be a very easy way to allow the player to treat an AVI file on an HTTP server just like a local file.

    For a reference of a decent implementation of progressive downloading, see the DivX client (Not the current version, the one before they added the download manager). How it works is that you give it a URL, and it starts downloading the file to disk. When it has a bit of the file, it starts playing from the partial file as it downloads. As the download progresses, the progress bar extends accross the timeline bar, and you can navigate anywhere within the downloaded section.

    VLC can also do progressive downloading, but it treats AVI files like streams, so you can't do any navigation at all. Even pausing seems to give it trouble. And you've got to ensure you have a big enough buffer, because it doesn't save to disk.

     
    • Celtic Druid
      Celtic Druid
      2006-04-11

      avi isn't really designed for streaming. Perhaps another container would work better?

       
    • Adam Zey
      Adam Zey
      2006-04-13

      AVI can be streamed fine. HTTP supports seeking (Make a new request for a different byte range), so a media player can read the index from the end of the file, then start playing. Really it could be done through a wrapper in the program, intercepting read and seek requests and farming the work out to HTTP.

      I just finished a proof-of-concept hack that is sort of neat. It downloads (using HTTP and byte ranges) an AVI file, but the first thing it downloads is the last 1% of the file (to grab the index), then it starts downloading from the start of the file.

      When you open the "fake" AVI file in MPC, it seeks to the end to get the index, which it finds. Then it seeks to the beginning after the header and starts playing. MPC doesn't know that most of the inside of the file is just null bytes, all it knows is that the file looks good.

      As long as the file downloads faster than the media bitrate, MPC never catches up to the part of the file where the hack is writing (as it downloads). In my test of the hack, MPC was tricked, and I was able to watch an AVI as it downloaded. I watched the whole AVI without any issues.

      One oddity is that MPC will refuse to open the file if it ends in ".avi". It says "file not found". Perhaps it just doesn't like that another process has the file open and is writing to it.

      By using another extention (I called it test.avi.part), MPC is happy to open the file just fine. I don't know why this produces different behaviour, but MPC determines the format is AVI just fine and everything works.

       
      • Gabest
        Gabest
        2006-04-13

        You didn't mention how your filter registers itself under HKCU\Media Type. There might be another source filter registered for .avi than yours, and I don't understand how your filter loads for the http protocol automatically, did you replace the "Source Filter" entry under HKCU\http? This is, btw, the problem with dshow and urls, the source filter can be set only on protocol level, and we need to have multiple source filters for http, some combination of protocol and checkbytes would be better but it's a bit too late now.

         
        • Adam Zey
          Adam Zey
          2006-04-13

          You misunderstand, this is a simple hack. By hack I mean very quickly written proof of concept program. It is an external program that handles the downloading of the file.

          It opens the file with a fileshare of read, so that MPC can read it while it is downloading. You start up the program, let it download the index and a bit at the start, then open the file up in MPC. MPC will play it fine because the part of the file that is being downloaded is ahead of the part that MPC is reading.

          MPC could implement this too. Create a file on disk, download the index via HTTP to the end of the file, start downloading the start of the file, and then open the file. MPC knows where the download pointer is, so it knows how much of the file is downloaded, and where to let the user seek (and it can show the information in the GUI). You don't actually need to expose HTTP to DirectShow at any time, and the whole process can be done seamlessly to the user.

          My approach is to:

          1) Do a HEAD request to find out how big the file is

          2) Seek to the end of the file  minus one byte and write a byte (to allocate the file)

          3) Do a GET request with a byterange of the last 1% of the file (I don't know enough about AVI to tell how big an index is, but you would know).

          4) Seek back to the start of the file

          5) Do another GET request, this time for the first  99% of the file.

          6) Open the file with MPC as it is being downloaded, MPC's current time never catches up with the download position, assuming download speed > bitrate.

          To get back to the .avi versus .avi.part, these are just files on a disk. If I drag the open .avi file into MPC, it produces a file not found error. If I drag the open .avi.part file into MPC, it plays it. My guess is that whatever method that is used to open unknown files is different from the method used to open AVI files, even after deciding the unknown file is an AVI.

           
          • Gabest
            Gabest
            2006-04-13

            To get back to the .avi versus .avi.part, these are just files on a disk. If I drag the open .avi file into MPC, it produces a file not found error. If I drag the open .avi.part file into MPC, it plays it. My guess is that whatever method that is used to open unknown files is different from the method used to open AVI files, even after deciding the unknown file is an AVI.

            ----

            Actually, I override CreateFile and let the file reader open .part files, that's why it works.

             
            • Tianhao Qiu
              Tianhao Qiu
              2006-09-19

              Actually, I override CreateFile and let the file reader open .part files, that's why it works. 

              ----

              I guess the trick is done in mplayerc.cpp: Mine_CreateFileA/W() where FILE_SHARE_WRITE flag is specified for .part files. Then pGB->RenderFile() will not fail due to "File not found" anymore. But to avoid the "Cannot render the file" error, the index part has to be presented at the end of the file. Quite interesting.

              I wonder if the same applies to rmvb or wmv files as well. As far as I know, both formats also store the index part at the end. Adam, can you share your proof of concept program so that I can test it? Thanks in advance.

               
    • Tianhao Qiu
      Tianhao Qiu
      2006-09-19

      Actually, I override CreateFile and let the file reader open .part files, that's why it works.

      ----

      I guess the trick is done in mplayerc.cpp: Mine_CreateFileA/W() where FILE_SHARE_WRITE flag is specified for .part files. Then pGB->RenderFile() will not fail due to "File not found" anymore. But to avoid the "Cannot render the file" error, the index part has to be presented at the end of the file. Quite interesting.

      I wonder if the same applies to rmvb or wmv files as well. As far as I know, both formats also store the index part at the end. Adam, can you share your proof of concept program so that I can test it? Thanks in advance.

       
    • Wvlle
      Wvlle
      2006-10-21

      I think this is an excellent and original idea and with the author proving the concept I see no reason why it would not be put on the to-do list.
      I really like this kind of 'busting open the window' manner of thinking where you use known and implemented but forgotten technology and specification and apply them to be put to good use.
      There are s many possibilities in existing things like the HTTP specifications and it's sad how often people with good ideas run into a wall of being ignored.

       
    • Doors
      Doors
      2006-10-21

      >By using another extention (I called it test.avi.part), MPC is happy to open the file just fine.
      >I don't know why this produces different behaviour, but MPC determines the format is AVI just fine and everything works.

      I believe the .part extension is the OS's way of denoting a partially downloaded file. Perhaps you could add the .part to the filename sent to MPC?
      Just a thought.