You are here: Home » Reply

Reply To: Transcoding to lossy format for bandwidth reasons



I’m new to the forums, but here’s a very bad hack to get Firefly Media Server to automatically transcode your library to a lower bitrate, lossy format that iTunes and other DAAP clients can play. Note that this assumes you have high-bitrate mp3s (say, 320 kbps, which my library is in), and you want to transcode to very low bitrate mp3s (say, 96 kbps, to play on your smartphone over crummy EV-DO speeds)

This involves three steps:
1) Modify the script to include mp3 output support
2) Modify the plugins.c file to change the headers sent to the client
3) Modify the rsp.c and out-daap-proto.c files to change the database information sent to the client

Step 1:
In, add an mp3_file() function that pipes the file through lame, encode it at 96 kbps (which is about as high as my mobile phone can stream without getting choppy), and spit it back out.

mp3_file() {
cat "$FILE" | lame --mp3input --preset 96 - -

I know the LAME fanatics will surely have a better set of command-line options; especially in terms of quality of conversion. Since this only needs to be done in realtime, you can use pretty high conversion quality settings.

If you’ve got non-mp3 formats, you’ll have to use something else to either decode to a middleman wave file that can then be piped through lame (without the –mp3input, of course), or maybe find a program that can transcode straight to mp3.

Make sure to call the function in the body of the script. My library has all mp3s, so my script only has the mp3 function and call for it. But again, you could still test for other formats and transcode them, too.

Step 2:
in plugin.c, change “audio/wav” to “audio/mp3” so Firefly emits the correct header. Also, we need to send out a content-length header, so change:

ws_writefd(pwsc,"HTTP/1.1 200 OKrn");


ws_addresponseheader(pwsc,"Content-Length","%ld",(long)((pmp3->song_length)* 12));
ws_writefd(pwsc,"HTTP/1.1 200 OKrn");

This is a very, very, very bad hack, but I don’t know how else to know the filesize of the file until it’s been transcoded, and I want playback to begin immediately. I hope someone else on the forums who’s more familiar with mp3 file structure (and isn’t a beginning C/C++ student like me) can help.

Anyway, pmp3->song_length * 12 is an overestimate of the filesize of an mp3 file encoded at 96 kbps. If the estimate is too low, your client won’t download the whole track, and the song will cut off. If the estimate is too high, certainly clients might not be able to play the end of the song (because they’re waiting for data that isn’t there). I haven’t had any problems with WiFiTunes on my WM6 phone, or iTunes 8 on Windows.

Even worse off, I haven’t bothered changing the Content-Range if there *is* an offset value — iTunes still lets you scrub, but it has to progressively download the track first. I never scrub my tracks, so it wasn’t a priority.

Step 3:
in rsp.c and out-daap-proto.c, change all

transcode = _ppi->should_transcode(pwsc,row[37]);


// transcode = _ppi->should_transcode(pwsc,row[37]);
transcode = 0;

There are two of these in the daap-proto.c and one in the rsp.c that need to be changed.

This prevents firefly from changing the “Kind” and “Type” formats from their original to “WAV audio” and such. However, again, this is a hack — if you’ve got a non-mp3 file, its type will be left as “mpeg4” or whatever (when it should be converted to mp3). This is easier than changing all the XL output code to emit “mp3” and such.

If this is a feature that a lot of people are looking for, some more major modifications would have to be made to the source code to make this more robust, as Ron noted.

Perhaps a global “transcode to mp3” option in the config file, with an accompanying “transcoded bitrate” option, that would pipe the output of the through lame (while leaving the conversion to wave intact), plus calculating the exact file size (easily done if you know anything about mp3 files, which I don’t) to send in the headers and to iTunes (thank god it doesn’t actually play this music back at the bitrate the library thinks it’s encoded at…). It’s not hard, but someone with more knowledge of the source for this program would have to spend a solid afternoon tinkering.

And the idea of testing the IP address (to see if it’s local or remote) is definitely brilliant.

But at least now we have a laundry list of things needed to be changed, and a poor hack to show it can be done fairly easily.