Brian Nickel’s Online Journal

If you don’t C# you’ll B♭

Archive for the ‘TagLib#’ Category

taglib-sharp.com

Posted by Brian on April 20, 2008

The website is being moved from one server to another.  It should be back up in a bit.

- Brian

Posted in TagLib# | 2 Comments »

TagLib# has a new home, and a new release!

Posted by Brian on April 27, 2007

If you’re looking for TagLib#, you have somewhere new to go: taglib-sharp.com! The new, graciously donated, site features a blog, a forum, and a wiki!

And what’s a new site without a sweet new release? TagLib# 1.9.9991 AKA Beta 1 is out featuring all previous formats plus MPEG-4 video, MPEG-1/2, and AVI. It’s a format bonanza! Visit the new download page.

PS. This is the last TagLib# post on this blog. New posts will be on the new blog.

Posted in TagLib# | 1 Comment »

TagLib#: MPEG-(1|2|4) Video

Posted by Brian on April 18, 2007

The past 3 days I’ve committed a couple major changes to TagLib#. Namely, support for MPEG-1/2 files and support for MPEG-4 video. The latter was pretty easy, but the former was an amazing pain, largely due to the amazing lack of online documentation for this 14 year old format. As such, here’s my brief explanation of:

HOW MPEG-1/2 FILES LOOK AND HOW TO UNDERSTAND THEM

MPEG contains two key parts, an audio stream and a video stream. If you were to extract the audio stream from an MPEG file, you’d have an MP3 (which could actually really be an MP2 or and MP1). The MP3 stream is very well documented online. For my personal favorite, click here. MPEG video is a very different format, but the important thing is that we have two streams, audio and video, and we’re combining them into one.

To do this, MPEG does pretty much the exact same thing as OGG, it takes the two streams, splits them into packets, and shuffles them together like playing cards. When you know what each of these cards looks like, the format stops being scary and becomes managable. So, what do the cards look like?

Each packet starts off with a simple packet identifier: 0x000001??. The ?? is replaced with a byte explaining the purpose of the packet. These are:

  • BA: This packet contains information on the MPEG version, a timestamp, and most likely some other useful information. This packet will always appear before BB, C0, or E0. BA should also be the first packet of the file.
  • BB: This contains some more useful information (I’m guessing.)
  • BE: A padding packet.
  • C0: An audio packet.
  • E0: A video packet.
  • B9: End of stream notification.

BA is a very important packet because it provides information on time. It appears before each audio or video packet to let you know when it’s happening. If you have the first and last BA packet, you can determine the duration of the movie. It sure beats the guessing in MP3 and doesn’t depend on weird codec dependent calculations like in OGG.

Now that we know the MPEG version and we know the duration, it is time to piece together the audio information. The first audio and video packets SHOULD contain complete headers for their respective formats and should tell us all we need to know. Audio is no problem for us, as we can just scan to the first C0 and sic our FindFrameHeader functions from the MP3 parser on it, and get every bit of information we need to know.

Video is a completely different format, but now that we understand MPEG files we should be able to understand this, as it uses exactly the same format: 0x000001??. The first packet should be B3, which we parse with VideoHeader.cs.

That just about covers everything except packet size. For all but BA, which is version specific, the first two bytes following the packet identifier describe the packet’s content length (total packet size – 6). This means you can just skip through the file pretty quickly (about 0×800 bytes at a time, depending).

All the work is in subversion. Be sure to note that the file sticks an ID3v2.4 and ID3v1 packet at the it’s end.

Posted in Programming, TagLib# | Leave a Comment »

Entertaining comments: New name for TagLib#, Website & Hosting

Posted by Brian on April 9, 2007

UPDATE: The website is now hosted at http://www.taglib-sharp.com and I’m keeping the name as is. Thanks to everyone who volunteered to host it.

1. TagLib# has gone through enormous changes since it was originally ported from TagLib (C++/Linux), it deals with a different audience, it handles different files, and the name similarity has caused some confusion for new users. I am thinking of renaming the project, maybe dropping the “-sharp” moniker, perhaps commenting on the impending Video support.

In short, What should I call it?

2. It seems like the Windows developer community and newer developers (I’m not dogging on the Windows community, but the two groups are similar in this respect) are more comfortable with forums and online documentation than mailing lists and monodoc. As such, TagLib# needs its own website, preferably new-project-name.com, that said, two things:

What all should go on a library’s website? Examples, Forum, Documentation, etc.

Is anyone willing to host a website and buy me a domain? I’m broke!

Please comment.

Posted in Programming, TagLib# | 2 Comments »

TagLib#: Special thanks to the people at #theora

Posted by Brian on April 4, 2007

I’ve made a bit of progress:

$ mono ReadFromUri.exe ~/Downloads/mac_pc_linux_2.OGG
/home/brian/Downloads/mac_pc_linux_2.OGG
Audio
Video
Title:
Artists:
Performers:
Composers:
Album:
Comment:
Genres:
Year:       0
Track:      0
TrackCount: 0
Disc:       0
DiscCount:  0
Lyrics:

Audio Properties
Bitrate:    56
SampleRate: 22050
Channels:   2

Video Properties
Width:      320
Height:     240

Length:     00:00:41.8750000

Embedded Pictures: 0

---------------------------------------

Total running time:    00:00:00.2400040
Total files read:      1
Average time per file: 00:00:00.2400040

The original file ended with a Vorbis page, which is easy to read, so I corrupted it and got duration parsing from a final Theora header (with some great help from the people at #theora on freenode).

The main problem now is: How do I update the tags. I’m going to have to look at the TagLib implementation more thoroughly, but at this point I’m scratching my head. Should I extract all the packets from the first page containing comment data to the last, then generate my own pages? It’ll probably take me a couple days to figure this out.

And then… M4V, MPEG (Just stick a ID3v2.4 on the end?), AVI, and I’m done! With all this change, I think this’ll be 2.0.

Posted in Programming, TagLib# | Leave a Comment »

Speakers, Ogg, and Flashing Realizations that I’m Wasting My Life

Posted by Brian on April 4, 2007

Speakers

This weekend, my chapter hosted the Western Regional Convention for Theta Tau. As we are a professional fraternity, we had a few speakers. One talked about some fascinating molecules which are liquid at room temperature and solidify at body temperature (counter-intuitive, huh?) and the other discussed what ABET says an engineer should be, what’s wrong with ASU’s current direction for engineering, and the most important thing an engineer should do with his life: Get a PhD in public policy and become a legislator. Needless to say, the talk was incredibly mind blowing and inspirational, not to mention dead on. As engineers, it is our life’s work to build, to invent, to improve. The weakest link in the betterment of mankind is those who say what we can and cannot do… Mainly because they cannot or do not know what we can and cannot do. We need rational, analytical, and just plain logical people making decisions.

On Monday, I found a insert in my New York Times advertising the launch of the School of Earth and Space Exploration (because “school of geology and astronomy” sounds lame) at ASU, and attended the some really interesting lectures by science writers. Science writing is a huge challenge because it is taking some of the greatest and most profound ideas and discoveries, then simplifying and clarifying it so that everyone can understand it. I feel the two lectures go hand in hand. We must be both effective thinkers and effective speakers if we are going to move the world forward. Profound thoughts are meaningless if the mouth and the pen cannot convey them to the audience.

Ogg

OGG is a great protocol for streaming. Really top of the line. Its like an MPEG stream but without the codec limitations. That said, OGG is a thorn in my side. As it is currently written, TagLib# has a TagLib.Ogg.File and a TagLib.Ogg.Vorbis.File, the former featuring File.GetPacket(int) which parses the stream (assumed singular) for packets, and the latter featuring File.Read() which gets the metadata from packet[0] and the comment from packet[1]. (I do not yet understand how writing works.)

So, I decided to abolish TagLib.Ogg.Vorbis.File and TagLib.Ogg.Flac.File in place of TagLib.Ogg.File + TagLib.Ogg.Codecs.Vorbis, etc. This will be helpful when I have multi-streamed files, like Vorbis + Theora. That being said, I’ve come up with this little diagram of how to read a stream:

-> Read Page
   -> Send Page to Bitstream Parser
      -> If BOS:
         -> Get Codec
         -> Add stream to "working streams"
      -> Send Page to Codec
      -> Returns false if more info needed.
   -> If not all streams return "true" (there are "working streams", Read Page

After that, I should know everything except the duration. For that, I have to read the last page of the stream, figure out which bitstream it belongs to, then use (last_granular_position – first_granular_position) / codec_encoding_specific_context.

-> File.RFind ("OggS")
-> Codec.GetDuration (GetPageHeader().last_granular_position)

Overall, it’s not that bad. But unlike the other big two containers (MPEG-4 and ASF), I have to worry about the codec, as there is no general “Media Properties” block, and I have to seek to the end of the file and do a backward search for a value. OGG, MPEG-4, and ASF SHOULD NOT be categorized together two are boxed formats and one is just a method for multiplexing data streams.

Flashing Realizations that I’m Wasting My Life

These are always the worst when they strike. I had one of those recently and changed my major from the loathsome Chemical Engineering to Computer Systems Engineering. I’ve had my reservations about CSE, but truth be told, I hate reactor design, I hate separations, and I do not want to watch valves. Well, as I was sitting around trying to piece together my financial situation for the remainder of my schooling, I realized that I’m a mess. As such I started cleaning my room and doing my much overdue laundry. But what I really need to do is start making money. If I am going to survive the fall and spring semesters, I will need to devote almost all my time to my coursework, and as such will not be working. As such, I estimate that I will need $6707.50 and a serious change in behavior before summer ends. Even with Summer of Code (God willing), I’ll need to work my tail off until June 1st to make everything work out. And stop spending. Alas.

Posted in Arizona State University, Folly, Programming, TagLib#, Theta Tau | Leave a Comment »

TagLib#: Video, a work in progress…

Posted by Brian on March 28, 2007

This is just a start, I’ve replaced AudioProperties with Properties, which contains {Duration, AudioBitrate, AudioSampleRate, AudioChannels, VideoWidth, VideoHeight, MediaTypes}, and added MediaTypes {Unknown, Audio, Video}. All I’ve really done so far was the massive code rename, but it should be relatively fast from here. See what about 10 lines of code gives us in ASF:

brian ~/Programming/taglib-sharp/examples $ mono ReadFromUri.exe /media/shared/Movies/Clips/Clinton\ Interview.wmv
/media/shared/Movies/Clips/Clinton Interview.wmv
Title:
Artists:
Performers:
Composers:
Album:
Comment:
Genres:
Year:       0
Track:      0
TrackCount: 0
Disc:       0
DiscCount:  0
Lyrics:

Audio Properties
Length:     00:15:56.0840000
Bitrate:    32
SampleRate: 44100
Channels:   1

Video Properties
Length:     00:15:56.0840000
Width:      320
Height:     240

Embedded Pictures: 0

---------------------------------------
Total running time:    00:00:00.2000030
Total files read:      1
Average time per file: 00:00:00.2000030
brian ~/Programming/taglib-sharp/examples $

Posted in Programming, TagLib# | Leave a Comment »

TagLib#: Go Speed Racer…

Posted by Brian on March 12, 2007

Note: The changes discussed in this post have yet to be rolled in to Subversion. Things have changed that require me to recode the some of the rendering parts.

When I way a young lad, nary a few fortnights ago, Aaron Bockover posted a blog entry comparing TagLib#’s performance to Entagged#’s performance, and this comparison was by no means flattering. I, being entrapped in a stupor of my own greatness, and too busy making things work to consider such trivialities as performance, didn’t pay too much heed to this at the time. That all changed one fateful day, when I committed a mortal sin, revision 71776. Working diligently to remove the vestigial organs in the body that is the library, I went too far, pulling out a stop cap which lead to a flood of file operations, making life unbearable for those souls do not fancy Id3v2. While fixing this wound, I noticed a rather startling thing, that those who abstained from the wicked art of Id3v2 lives quicker and cheerier lives. With the scent of victory in my nostrils, I was off, like a bloodhound after a fox, determined that by sheer will alone, I would cure my library of the venom that ailed it. Tearing through the code, piece by piece, I slaughtered my foe, liberating all MP3’s from the bondage they were in. Again I struck, and again, until no difference could be seen between the sons of MP3 and the sons of Ogg. There was much rejoicing throughout the land, but it was not enough. For MPEG-4, on its mighty mountain, looking down from afar was still cursed with the poison. But today, this very day, there should be rejoicing in the kingdom once more. For MPEG-4 has been freed from captivity and may walk once more among his brothers…

I apologize for that. I started typing and then got carried away, but there is much to celebrate today, as I have made another great step forward, and reduced the reading time on MPEG-4 (AKA. iTunes files) but almost 70%, bringing the average read time to just more than a millisecond. But there is only so much words can say, perhaps this picture could best explain what has happened:

Warm file read times for my music directory with my current hacking version.

This happened when I tried, one more time, to tackle the problem of why exactly MPEG-4 was taking so long to read. I had figured the culperate was the many, many tiny file reads I was doing. Reading many, many tiny blocks was my best guess, but I had no really good way of stopping this (due to the whole “box inside a box” style), so I moved the entire thing to reading one big block, but it resulted in marginal gains. Then I recoded it to just read the “udta” box and the files loading near at Ogg speeds. So I changed the reading system again, this time doing tiny file read but ignoring a few gigantic boxes I didn’t need to read. This cut the read times in half. It was sweet, but still not good enough. So, I decided to go back to the orginal comparison of TagLib# vs. Entagged#, and peeked at how Entagged# does things. Essentially, it does a very quick recursive lookup of box header and for very standard container boxes ({header}{child1}{child2}…{childN}), it recurses through them. This exposes the four main boxes that TagLib# is interested in: ‘meta’, ’stco/co64′, ‘mvhd’, and ’stsd’. Using switch cases and our classic Box factory, we can extract the rest of the useful data. Presto! Everything we need, nothing we don’t. Why didn’t I think of that?

Now I need to rewrite some of the writing code, but once that is done, I’ll be able to roll it all into subversion. Look forward to yet another release in the next couple days!

PS. The results of the new TagLib# vs. Entagged# battle:

              File         Reader      Avg.     Total
-----------------------------------------------------
       sample.flac         TagLib  0.000322    3.2200
                         Entagged  0.000269    2.6900

     sample_v1.mp3         TagLib  0.000213    2.1300
                         Entagged  0.000250    2.5000

        sample.m4a         TagLib  0.000896    8.9601
                         Entagged  0.000619    6.1901

     sample_v2.mp3         TagLib  0.000717    7.1701
                         Entagged  0.000382    3.8201

        sample.wma         TagLib  0.000673    6.7301
                         Entagged  0.000398    3.9801

        sample.mpc         TagLib  0.000531    5.3101
                         Entagged  0.000324    3.2400

        sample.ogg         TagLib  0.000512    5.1201
                         Entagged  0.003756   37.5606

   sample_both.mp3         TagLib  0.000727    7.2701
                         Entagged  0.000469    4.6901

Considering that one of the main differences between TagLib# and Entagged# is that TagLib# reads everything and Entagged# reads just what is necessary, really, really quickly, I don’t think we’ll ever be as good as TagLib# on everything, but I think we’re doing a pretty decent job.

Posted in Programming, TagLib# | Leave a Comment »

Man, this was a bad idea… Id3v2.3 write support!

Posted by Brian on March 9, 2007

Well, adding write support for Id3v2.3 isn’t really a bad idea. The bad idea is staying up until 4 in the morning on a 6 hour coding spree. Revision 73998 contains a tonne of minor code changes and a single powerful static property:

TagLib.Id3v2.Tag.RenderVersion

This can be set to 2, 3, or 4, but it is very important to recognize that internally, all tag data is stored as Id3v2.4. This means that you may lose a few frames while reading and you may lose a few frames while writing. Use this with caution.

Posted in Programming, TagLib# | Leave a Comment »

Transmitting file data ……………………. Committed revision 73980.

Posted by Brian on March 9, 2007

Banshee bug 412273 should now be solved, as well as minor bugs that may show up in a few files here and there. To summarize the change, let me first present you with the Changelog:

2007-03-08 Brian Nickel <**********>
   * src/TagLib/Mpc/File.cs: Inherit NonContainer.File
   * src/TagLib/CombinedTag.cs: Add some useful features for NonContainer.*
   * src/TagLib/Id3v1/Tag.cs: Add Tag.Size instead of repeated hardcoding of
   128.
   * src/TagLib/Id3v2/Footer.cs:
   * src/TagLib/Id3v2/Header.cs: Throw proper CorruptFileExceptions
   * src/TagLib/Mpeg/File.cs: Inherit NonContainer.File
   * src/TagLib/WavPack/File.cs: Inherit NonContainer.File
   * src/TagLib/NonContainer:
   * src/TagLib/NonContainer/Tag.cs:
   * src/TagLib/NonContainer/File.cs:
   * src/TagLib/NonContainer/EndTag.cs:
   * src/TagLib/NonContainer/StartTag.cs: New generic abstracts for files
   that can start/end with an assortment of tags. (FLAC, WV, MPC, MP3)
   * src/TagLib/Ape/Tag.cs: Read backwards if a footer is found and forwards if
   a header is found.
   * src/TagLib/Ape/Footer.cs: FooterPresent and IsHeader were read
   incorrectly. Also throw proper exceptions while reading.
   * src/TagLib/Flac/File.cs: Inherit NonContainer.File
   * src/TagLib/Flac/BlockHeader.cs:
   * src/TagLib/Flac/Block.cs: Removed from Flac.File, made public.
   * src/TagLib/Mpeg4/File.cs: Remove old commented code.
   * src/Makefile.am:
   * src/taglib-sharp.csproj:
   * src/taglib-sharp.mdp:
   * taglib-sharp.mds:
   * tests/tests.mdp:
   * examples/SetPictures.mdp:
   * examples/ReadFromUri.mdp: Updates.

To solve this bug, I created a new namespace, TagLib.NonContainer, which provides an abstract file which does the following:

  1. Checks the very beginning of the file for a valid APE or ID3 tag, reads it, and then checks after that tag for another, until none is found.
  2. It then lets the child class read whatever it wants to at the beginning of the file. For most formats, this is just going to be the first header block, and for FLAC it’s a vorbis comment and embedded images.
  3. It then advanced to the end and searches backwards in similar manner.
  4. Same as 2, but at the end.
  5. Have the child class read the audio properties, if necessary.

So, now you can read ID3v2 tags at the end or APE tags at the front, not to mention fun combinations like (APE, APE, ID3v2, APE). The combinations are infinite! (sarcasm implied)

On the plus side, now the child classes are much cleaner and easier to work with internally.

Enjoy!

Posted in Programming, TagLib# | Leave a Comment »