Saturday, July 21, 2007

StreamReader: annoying design decisions in the .NET framework

You would be surprised the simple things that people forget to include in APIs that make using them very annoying.

Here's an example: StreamReader. Intelligently, StreamReader buffers, for performance reasons, input from the stream, so while you may only call ReadBlock() for 14 characters, StreamReader has read ahead 50 characters.

That's great and all, except they forgot to *support their own features*.

The most obvious problem is seeking: they didn't add buffer-aware seeking functions to StreamReader itself. So you have to dig around the underlying BaseStream to make the magic happen. Except that StreamReader doesn't actually check the current position of the base stream before it reads from its buffer.

So, when you try to seek on BaseStream, and then do a read, StreamReader happily (and very blindly) reads from its invalid buffer, thus fucking your shit up.

Apparently someone, somewhere, was vaguely aware of this, and provided "DiscardBufferedData()" -- one call to this and the buffer is emptied, so reading from StreamReader will pull the fresh data instead of the old data.

Except DiscardBufferedData() doesn't update the underlying stream's position. Oops!

So while you think you've read 540 bytes and the stream should be at 540, its actually at 560, because StreamReader buffered an extra 20 bytes for performance.

No big deal, though, right? We'll just see how much data was in the StreamReader buffer, and seek backwards that amount.

Or, we would, if DiscardBufferedData() had been designed properly so the discarded buffer size was the return value.

No biggie, we'll just check out the BufferSize property that the developers decided wasn't worth including as a class member. Shoot.

Of course, this isn't an insurmountable problem: you just have to keep tabs, manually, on where the stream position *SHOULD BE*, and then do your seeking calculations with those numbers in mind.

But, being able to work-around it isn't the problem: the fact that you *HAVE* to work around it is the big annoyance here. It's a "WTF PLZ" that shouldn't even be in the framework, much less having survived three iterations of .NET RTM.

There was a time where I would have sent that up as a feature request, but every time I visit Connect I see a whole bunch of feedback issues with the same replies from "Microsoft": "we can't fix this in time for X,Y,Z, but we'll keep an eye on it for future releases (not really)!"

I think I'll actually do it this time, though.

I'm a bit curious to see if or how they'll dodge it.

Thursday, July 12, 2007

Convert FLV's from YouTube into audio-only mp3 files.

Took me awhile to figure out how to make VLC do this right due to its clunky UI, but whatever.

You'll find this useful if, like me, you want to take a particularly long YouTube file with you on the go but you need it to play on your mp3 player as audio only (space concerns, the video on your media player sucks, whatever).

For your enjoyment:

You'll need:

  • VLC Media Player
  • Some way to grab FLV files -- I recommend VideoDownloader since that's the easiest way to get the FLV from a site like YouTube -- what's up with the VideoDownloader URL? I don't really know.
Download, and install VLC Media Player, and make sure it doesn't mess with your file associations.

Now, by default, VLC Media Player will attempt to always encode the video of an FLV and there's no way to change this behavior via the GUI, which is stupid, so we have to work around it using the command line -- don't worry, its really easy.

Make a new short-cut to the VLC Media Player by copying the short-cut on your desktop or if you're savvy navigating to %Program Files%\VideoLan\VLC\vlc.exe and right clicking + 'create new shortcut.'
Next, edit the short-cut. In the "Target" field, outside -- OUTSIDE -- of the quotations that contain the path to the VLC Media Player, type in "--no-video" (no quotation marks), save the short-cut, then rename the short-cut to "VLC Media Player -- No Audio" so you don't get it confused with the fully functional version.

Download a FLV and open it in VLC Media Player to make sure that everything's working. You should hear audio but see no video -- if so, you're a winner. If not, start over from step 1 and try again.

Now, open your FLV in VLC Media Player once you're ready to rock and roll -- either drag and drop it onto the VLC Player or open it via File --> Quick Open.

Click File --> "Wizard"

Select "Transcode / Save File" then click Next.

Select an Existing Playlist Item, select the FLV you just started playing, and click Next.

Check "Transcode Audio" and from the drop down list select "MP3" -- don't mess with the "bit-rate" option, even though I'm sure you want to. Click Next.

Select "RAW" on this screen and select "Next" again.

Click browse, enter a file name -- don't forget the .mp3 extension, that is IMPORTANT because VLC Media Player won't do this for you -- and click "Finish."

The VLC GUI will seem like its playing a file called "Streaming...", that's the transcoding process, don't touch the player at all until its finished. Yeah, I know it looks stupid. But, it works.

Your new mp3 file has been created. Congrats!