{"id":673,"date":"2008-12-06T18:55:34","date_gmt":"2008-12-07T02:55:34","guid":{"rendered":"http:\/\/multimedia.cx\/eggs\/?p=673"},"modified":"2020-07-25T22:21:09","modified_gmt":"2020-07-26T05:21:09","slug":"designing-a-download-strategy","status":"publish","type":"post","link":"https:\/\/multimedia.cx\/eggs\/designing-a-download-strategy\/","title":{"rendered":"Designing A Download Strategy"},"content":{"rendered":"<p>The <a href=\"http:\/\/multimedia.cx\/eggs\/i-heart-picsearch-and-python\/\">uncommon video codecs list mentioned in the last post<\/a> is amazing. Here are some FourCCs I have never heard of before: 3ivd, abyr, acdv, aura, brco, bt20, bw10, cfcc, cfhd, digi, dpsh, dslv, es07, fire, g2m3, gain, geox, imm4, inmc, mohd, mplo, qivg, suvf, ty0n, xith, xplo, and zdsv. There are several that have been found to be variations of other codecs. And there are some that were only rumored to exist, such as aflc as a codec for storing <a href=\"http:\/\/wiki.multimedia.cx\/index.php?title=Flic_Video\">FLIC data<\/a> in an AVI container, and azpr as an alternate FourCC for <a href=\"http:\/\/wiki.multimedia.cx\/index.php?title=Apple_RPZA\">rpza<\/a>. We now have samples. The existence of many of these FourCCs has, in fact, been cataloged on <a href=\"http:\/\/fourcc.org\/\">FourCC.org<\/a>. But I was always reticent to document the FourCCs in the <a href=\"http:\/\/wiki.multimedia.cx\/\">MultimediaWiki<\/a> unless I could find either samples or a binary codec.<\/p>\n<p><strong>But how to obtain all of these samples?<\/strong><\/p>\n<p>Do you ever download files from the internet? Of course you do. Do you ever download a bunch of files at a time? Maybe. But have you ever had to download a few thousand files?<\/p>\n<p>I have some experience to guide me in this. <!--more--> I didn&#8217;t get away from dialup internet access until mid-2004, even though I had been hacking on multimedia for several years which necessitates downloading bulky samples. When I had to download a number of large files over the web, I made a text file with a series of wget commands:<\/p>\n<pre>\r\n  wget --continue http:\/\/movietrailersite.com\/trailer1.mov\r\n  wget --continue http:\/\/movietrailersite.com\/trailer2.mov\r\n<\/pre>\n<p>&#8230;etc. The &#8211;continue option on each line was useful because I could break and subsequently resume the script any time I needed my 3.5 kbytes\/sec downstream capacity for a higher-priority task.<\/p>\n<p>So my first impulse for downloading the list of 5100 crashers was to put &#8216;wget &#8211;continue&#8217; in front of each one and let it rip. Since there are more than a few slow, confused, or misbehaving servers out there, it wasn&#8217;t long before I noticed that I should limit the number of retries to something less forgiving, like 3, using &#8211;tries.<\/p>\n<p>Traditionally, when I do bulk file downloads like this, the files all live on the same server. Not so in this case; 5100 files on roughly 5100 different sites (probably not that many but still a huge amount). Thanks to <a href=\"http:\/\/wiki.multimedia.cx\/index.php?title=User:Compn\">compn<\/a> for pointing out that I should parallelize the task in order to maximize my current downstream bandwidth which peaks at about 800 kbytes\/sec sustained. So I broke the same list up into 4 different text files on 4 different terminals, and things moved a lot more efficiently.<\/p>\n<p>How I processed them comes in a separate post. Now for the challenge of downloading the lists of uncommon A\/V codec samples. We received 2 lists of files formatted as such:<\/p>\n<pre>\r\nhttp:\/\/somesite.com\/sample.mov <em>&lt;hard tab&gt;<\/em> G2M3 \/ 0x334D3247, 1152x864\r\nhttp:\/\/othersite.net\/media.wmv <em>&lt;hard tab&gt;<\/em> G2M3 \/ 0x334D3247, 1280x964\r\nhttp:\/\/thatsite.org\/file.avi <em>&lt;hard tab&gt;<\/em> fraps, yuv420p, 1024x768\r\n<\/pre>\n<p>Again, my first impulse is to shove wget commands in front of each URL. The extra metadata at the end of each line will have to be disposed of. But I also need to sort this media into separate bins for it to really be useful.<\/p>\n<p>I imported the lists into a spreadsheet and tried to manipulate them there. That&#8217;s when I remembered that I know even less about spreadsheet programs than I do about shell scripting. The lists are grouped by types of codecs (lots of G2M3 samples, then lots of fraps samples, etc), and each block is delimited by a column header line that starts with &#8220;url&#8221;. At first, I was thinking of turning the list into a glorified shell script that would create a directory named after the codec for the next group when it encountered a &#8220;url&#8221; line and then download the group&#8217;s files into that directory. But that would be a lot of manual, error-prone labor. Plus, learning from the previous process, the script should be able to download more than one file at once. If I&#8217;m going to automate that kind of task, why not just operate directly on the unmodified lists?<\/p>\n<p>So it came to be: a script named download-lots-of-samples.py which iterates through the list and downloads up to 4 files in parallel using wget. The parallelization mechanism is rather sloppy (maintain a list of 4 open wget processes; if all are full, poll-sleep-poll the process states until one of them finishes) which might be improved by a native Python HTTP downloader that could leverage the select I\/O facility. But I decided to just let wget do what wget does best. Further, the script catalogs the samples by the relevant part of the metadata.<\/p>\n<p>A new requirement emerged after I kicked off the script: My cable broadband provider, Comcast, quite infamously imposed a 250 GB\/month total bandwidth cap under penalty of summary service termination. And unlike the samples on the crasher list, the samples on the uncommon lists are generally very large and are being served by some very bandwidth-rich servers. I started to worry about the possibility of exhausting my limit after what appeared to be an entire night of my connection working at full tear and scarcely making a dent in the lists. I calculate it would only take about 3.5 days of 800 kbytes\/sec to hit the limit.<\/p>\n<p>At first, I hacked the script to blacklist a few of the metadata types I felt had enough samples already and then restarted, but that wasn&#8217;t a very scalable solution. Instead, the script now automatically skips entries if there are already enough samples collected (5 is the limit I imposed).<\/p>\n<p>For the curious, I have included the script. I don&#8217;t know what <a href=\"http:\/\/blog.flameeyes.eu\/\">Flameeyes<\/a> is talking about when he <a href=\"http:\/\/multimedia.cx\/eggs\/actual-regression-test-output\/#comment-136492\">laments the unreadability of Python<\/a>. I mean, what could possibly be unclear about the statement &#8216;type = type[:type.find(&#8220;\/&#8221;)]&#8217;? Actually, I can&#8217;t believe that I thought of that one, or that it actually does exactly what I needed.<\/p>\n<p><script src=\"https:\/\/gist.github.com\/multimediamike\/97974fce37e263fb49b4eeb55b2997cc.js\"><\/script><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Discovering a wealth of new multimedia file formats first requires some innovative tools to retrieve and catalog the samples.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1,55],"tags":[285,102],"class_list":["post-673","post","type-post","status-publish","format-standard","hentry","category-general","category-python","tag-python","tag-samples"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/multimedia.cx\/eggs\/wp-json\/wp\/v2\/posts\/673","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/multimedia.cx\/eggs\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/multimedia.cx\/eggs\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/multimedia.cx\/eggs\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/multimedia.cx\/eggs\/wp-json\/wp\/v2\/comments?post=673"}],"version-history":[{"count":21,"href":"https:\/\/multimedia.cx\/eggs\/wp-json\/wp\/v2\/posts\/673\/revisions"}],"predecessor-version":[{"id":4584,"href":"https:\/\/multimedia.cx\/eggs\/wp-json\/wp\/v2\/posts\/673\/revisions\/4584"}],"wp:attachment":[{"href":"https:\/\/multimedia.cx\/eggs\/wp-json\/wp\/v2\/media?parent=673"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/multimedia.cx\/eggs\/wp-json\/wp\/v2\/categories?post=673"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/multimedia.cx\/eggs\/wp-json\/wp\/v2\/tags?post=673"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}