Find the damn MP3 song name II - New SHITMP3 V1.07 production revealed
Starry Studio Zhang Lin
cause:
In the sixth issue of "programmer 9CBS development masters", I published an article titled "Finding the Damn MP3 Song Name" (hereinafter referred to as "article" text). In fact, it is said that it is an article, it is better to say a vc routine, and the text has talked about how to automatically rename the MP3 file by retrieving the TAG information of the MP3 file. I am very happy that many readers are very interested in this article. In the past two months, I received a lot of readers and Shitmp3 users from Email, and everyone put forward a lot of questions and requirements, and some friends also corrected the shortcomings of the code, and more enthusiastic Friends have also written a lot of code to supplement Shitmp3's functional defects. Here, I want to express my attention to these readers' friends, thank you.
In this period, I made a more step-by-step study in MP3's song name information and renaming, combined with many opises and users, and learned more in-depth learning for MP3 file information, I I feel that there are still many things that make everyone know more. In fact, "put" SHITMP3V1.05 version has indeed achieved the ability to extract MP3 songs and rename the name of MP3, but I think there is, since everyone is so interested, we simply learn more about a matter of understanding. Is it better? To this end, I made a new version V1.00.07 of Shitmp3. This article, I will take this new SHITMP3 software as an example, and discuss with you. The purpose is not to promote what, but I think the discussion is really a good thing to promote each other. And I think this new Shitmp3 is not only my own work, but also everyone's work. So, if you like, then we will enter the world of MP3 songs. ^ _ ^
Deeper principle
Principle 1: The basic information of the MP3 file - "ID3V1" information Read in "Put", I introduced how we extract simple song information from an MP3 song file, and then rename the MP3 file name A set of methods. This method is not very difficult, we only need to find the corresponding singer name from the MP3 file information, the song name is OK. And next we have to study is a more step-by-step resolution of MP3 song information, which requires us to understand the MP3 song information structure. In the "Put", the basic song information of MP3 has the last 128 bytes of the MP3 file. The structure is: TypeDef struct // mp3 information {char IDentify [3]; // tag three Letters / / This can be used to identify not the file information content char Title [30]; // song name, 30 byte char artist [30]; // singer name, 30 byte char album [30]; / / 属, 30 byte char year [4]; // year, 4 bytes char comment [28]; // Note, 28 bytes unsigned char reserved; // reserved bit, 1 byte unsigned Char reserved2; // Reserved bit, 1 byte unsigned char reserved3; // reserved bit, 1 byte} mp3info;
Figure 1 Id3v1 information of MP3 seen in Winamp
There are several places worth our more and more steps. If we want to rename a MP3, then we only have to extract the Title (song name), Artist (singer name), plus the Album (album name) is enough. Just like Shitmp3v1.05, MP3's song name is similar to "12341234214.mp3" to "" Singer Name) Song Name .mp3. Just as some readers have asked "How did the basic information of Winamp's MP3 know how from this basic structure?" We have to resolve all the 128-bytes of information. Ok, let's take a look at the information displayed in WINAMP (Figure 1). I want to declare that this 128-byte MP3 song information has a name: called "ID3v1". We don't want to manage him why it is called "ID3v1", just like we ask "Why is this called dumplings?", There is not much significance. We have to know which information is stored in this structure. In the "Put" text, we know this information separately stored (Figure 2): Figure 2 Id3v1 information of an MP3 file
1-3 TAG4-33 Song Name 34-63 Singer Name 64-93 Album Name 94-97 98-125 Remarks 126-128 3 reserved positions in Winamp's ID3V1 song information (as shown in Figure 1), we see He also includes: Title (Song Name) ARTIST (Singer Name) Album (Year) Comment GENRE (Song Style) Note, see Table 1 TRACK # (Song in the order in the album It is our frequent "first few") strange, Title, Artist, Album, Year, and Comment We all can get in that 128 bytes, where is Genre and TRACK? In fact, we all pay attention to the first 125 information of the 128-byte information, and the two information is placed in the last 126-128 bytes. In fact, reserved2 is TRACK information, and reserved3 is GENRE information. Their storage methods are not characters. When we extract them, they need to pay attention to they are numbers. For example, as the RESERVER3 of this song we see is 0x0D, it is obvious that he is 13. That is, the POP is popular (Table 1). At this time, you should also guess that reserved2 and reserved3 make sense, natural reserved1 has its meaning! We know about 28 bytes in the "Put". This statement is not completely correct. Accurately, it should be correct. Sometimes the comments can also exceed this number. ID3v1 requires up to 30 bytes. So some readers will ask "MP3 ID3v1 is to have 130 bytes of information?" No, of course not. ID3v1 is a fixed 128 byte, you don't have to worry. In fact, Id3v1 is arranged in this way: if the NP3 comment is greater than 28 bytes, then the 126-127 two bytes will be borrowed. So the comment portion of ID3v1 may be 28 bytes or 30 bytes. So, how do you distinguish between 28 bytes or 30 bytes? Very simple, reserved1 is this, we just see if reserved1 is 0x00, if it is 0x00, then there is 28 bytes. If it is not equal to 0x00, then the comment is 30 bytes. Also don't forget, because the 127th byte stores TRACK information, if the comment is 30 bytes, the reserved2 in this song's ID3V1 is naturally not TRACK information. TRACK naturally has no place to save, so reserved2 has no TRACK meaning, it is just part of Comment. Please pay special attention when you decide to make a program that reads ID3v1. We finally know that the reserved1 is the annotation portion of the ID3v1 information is 28 bytes or 30 bytes of logo. Reserved2 is a track information (Track), while reserved3 is a song style.
Now we re-write a structure (SHITMP3V1.07): TypeDef struct // mp3 information SHITMP3V1.07 {char IDentify [3]; // tag three letters / / This can be used to identify not files Information content char TITLE [30]; // song name, 30 byte char artist [30]; // singer name, 30 byte char album [30]; // belonging, 30 bytes char year [ 4]; // year, 4 byte char comment [28]; // Note, 28 bytes (or 30 bytes!) Unsigned char commentflag; // Reserved bit 1, note length flags unsigned CHAR TRACK; // Reserved bit 2, the "first few", is an integer unsigned char genre; / / reserved bit 3, song style, between 0-148} MP3Info; principle 2: MP3 file There is no ID3v1 information Error understanding in Shitmp3v1.05, I really ignore a problem, that is, what can be called "MP3 file has no ID3v1 information". The method of detecting is to extract the last 128 byte information of the specified MP3 file, then determine the first 3 bytes of the 128 bytes of "tag". Many friends will agree to this method is no problem. However, the problem is not that simple. Figure 3 Most annoying "fake ID3v1"
Winamp or other MP3 playback related software has the write and read of MP3 information, but these software writes ID3v1 will do not conscious when you open this MP3 file, you will add this 128 words. The information of the section. That is to say, when we use this software to open the MP3 file, these software will automatically add a 128-byte ID3V1 structure at the end of this MP3 file, and still start with "tag"! (Figure 3). So clear, light against the three bytes of "tag", or not to completely determine if the MP3 has no ID3v1 information. We also have to determine the 125-byte of this "tag" is not correct. In general, the ID3V1 structure generated by such software is composed of a pile of 00, or a bunch of spaces, so we have to judge that information is not iD3v1 is a plurality of 00 or a bunch of spaces. If so, then the MP3 file has this "TAG" three letters, but it is still not a legal ID3v1 information. The MP3 file should still be considered no ID3v1 information. I think this thing is necessary to especially remind everyone to pay attention.
Principle 3: The extraction of ID3v2 information In "Put", we mentioned the MP3 song information stored in the last 128 bytes of the entire MP3 file, we called this information "ID3V1 information". This information structure is very easy, and it is not difficult to write to the file. But its information arrangements and scalability are very poor (only 128 bytes). As you know, the MP3 file has another information structure, which has better scalability, and the storage capacity is not limited (that is, the total length is not fixed). This information is ID3v2 information (relative to ID3v1). Since ID3v1 information is stored in the last 128 bytes of the file, then ID3V2 has to give up the end of the selection to store the file, so it is stored in the starting position of the file. The storage and reading of ID3v2 information is much more complicated than ID3v1 information. This is because ID3v2 information is no longer fixed, and since this information is stored in the first end of the file, it is much more troublesome than ID3v1 when rewriting. I use it as clear and concise, telling you about the reading method of ID3v2 information. ID3v2 is now 4 versions, but the more popular MP3 play software generally only supports the third edition, namely ID3v2.3. What we have to read is ID3v2.3 information. The ID3v2 information includes two parts, one part is the header information, and the other part is a fitting information. Among them, the header information is fixed, its structure is as follows: strunt id3v2header {char ID3v2header {char ID3v2 identification bit, it should be "id3" three letters for Struct {byte major; // Version, usually as mentioned above, this information is 3 Byte Revision; // Depth versions, generally 0} version; // version information structure Byte Flags; // flag, we generally use, you think He is 0 well size [4]; // Each BYTE value cannot be greater than 0x80, that is, each bit 7 of the size value is 0 / / here stores the length of the entire ID3V2 flag information. }; Here, we have to extract this ten bytes of information, the purpose is only two: one is to extract Identifier to see if "id3"; the other is to extract Size, get the length of ID3v2, easy to extract the back Soothing information. The four bytes of Size storage is not directly received by a variable of an int type. The size of each byte of the size is the 7-bit binary number of 0-128, not the 8-bit binary number of 0-256, and the highest bit of each byte is not used. So we have to calculate it, the calculation method is as follows: int ID3size; id3size = (size [0] & 0x7f) * 0x200000 (Size [1] & 0x7f) * 0x400 (Size [2] & 0x7f) * 0x80 (Size [3 ] & 0x7f); By resolving this header information We can know that an MP3 file is not ID3V2 information, if we know the total length of the ID3v2 data body. Next, we must parse the ID3v2 data body, don't worry, although it is complicated, but it is not the pain you imagine. The ID3v2's data body is also divided into many identical data structures. Each of the same data structures is divided into a header, a data body. I may say something complicated, and it is actually not so complicated.
First we still look at the header of a data structure: struct id3v2frameheader {char frameid [4]; // Structure flag bit, for example, if it is song information, then these four bytes are Tit2 Byte Size [4]; // The length of the structure of this structure byte flags [2]; // flag is rarely used, due to the space, not too much explanation}; here to explain this frameID, in ID3v1 we are based The fixed byte number and position occupied by each message are determined which information he is. In order to provide better scalability, ID3v2 is "dynamically", because the length is not pre-set, but stored in size [4]. This can no longer be fixed in this length. I think Id3v2 and ID3v1 is also a kind of aspect worthy of our consideration when we define files. If the structure is small and the amount stored is not large, we can use ID3v1 information storage mode. If the stored information is not fixed, it is required to have good scalability, then Id3v2 is of course the first choice. In fact, there are now many format files to store the storage mode of ID3v2 very close. JPEG can be said to be a model of this storage method. Ok, go back to the topic, first introduce the frameid has defined several flags (SHITMP31.07): Sign bit mark meaning Tit2 song name, equivalent to ID3v1 Title [30] TPE1 singer (Artist), the Artist [30] Talb album name (Album) equivalent to ID3V1, equivalent to the Album [30] TRCK track (TRACK) of ID3v1, is the first few songs in the album, equivalent to the id3v1 TRACK ( Reserved2) Tyer Year (Year), the Year [4] TCON music style equivalent to ID3v1, is equivalent to the Genre (Reserved3) of ID3V1, (see Schedule 1) Comm Notes (Comment), equivalent to ID3v1 Comment [ 28] Teenc encoding mode (Copyright) WXXX URL Link (URL) In addition to the above-mentioned flag, there are many other signs, but not very common. You can go to www.id3.org to learn. Therefore, we can understand which type of information is stored by the header of this data structure, which is stored in the bottom, then follow the Size size to extract the corresponding information. Until all read. Then there is a storage of the size section, no longer only 7 of the bytes such as the total header, which is stored in normal 8 bits. The method of obtaining a data body is as follows: int FSIZE; fsize = size [0] * 0x100000000 size [1] * 0x10000 size [2] * 0x100 size [3]; to facilitate everyone's understanding and comprehension, us Still take an example of an MP3 file. As shown in Figure 3, I opened an MP3 file with ID3v2 information, which is the autumn hall of uncle I like to listen to. First let's take a look at the total logo of ID3v2: 1-3 bytes: ID3 4th bytes: 3 Article 5: 0 League 6: 07-10 bytes: 00 00 01 50 from this ten words We can know that this MP3 file is an ID3v2 information (because the first three bytes are ID3), the fourth byte is the third version of ID3v2.
The last four bytes are the length of the ID3v2 data body. We get the length of the ID3v2 data body by the calculation method mentioned above: (1 & 0x7F) * 0x80 (50 & 0x7f) = 208 Figure 4 One MP3 song ID3V2 information
As shown in Figure 4, the highlighted part is the header of this ID3v2 and the 208-byte information behind it. The header is the data body. We extract the top ten bytes of the data body. We know that this data structure stores the frameID is Tit2, check the above table, indicating that the data structure is stored in the song name information. The size is 00 00 00 14, and it is 20. That is, the song name is 20 bytes after this sub-header. That is: "Love Hotel Autumn". The next piece of data structure is TPE1, indicating that the singer is 00 00 00 07, indicating that this data body has seven bytes, which is: "Zhou Huajian". And so on. Here you need to know that one Chinese character takes up two bytes. There is also a special reminder that the first four bytes of the ID3v2's annotation information (Frameid is a comm as), is not an comment, but the natural language used by comment, this example we see: " eNG / 0 ", we have to skip the four bytes of information for parsing. In addition, ID3v2's song type genre (frameID is TCON) is not the same. Since many MP3 players are not very consistent, it is inconsistent in Genre. For example, the id3v2 of this song is Classic Rock, in fact, there is also a written: (1), or 1, and (1) Classic Rock, so the format five flowers, we have to pay attention to when parsing. Also, it is worth mentioning that WinAMP will add a '/ 0' when the content is saved and read, and the byte is calculated in the size of the frame content. So the singer "Zhou Huajian" mentioned earlier should be 6 bytes, but it accounts for 7 bytes.
Principle 4: Id3v2 Information This is a more troublesome step, but if you already have the experience of Id3v2 reading, it is not too powerful. First of all, we still use a structure to get information to be written. Of course, the information of ID3v2 itself is not fixed, but we will write to the song name (Title), singer, album, song Type (GENRE), Year, Series (TRACK), Copyright, Encode BY and URL URL (URL) 10 kinds of information. // id3v2 information structure typef struct {cString Title; // song name cstring artist; // artist cstring album; // album name cString Year; // year cstring comment; // Note CSTRING GENRE; / / which style belonging to? Songs, see g_arrmp3genre array cstring copyright; // copyright cstring encodeby; // encoding method cstring URL; // URL URL BYTE TRACK; // is the first few songs in the record} MP3ID3V2Info;
When we get this information, we must inversely follow the methods that just analyze. Write down the header of each data, then write the head header, and finally enter the entire information to the file from the head. Since we want to write information to the file header, the write method is also written than ID3v1 to the file. It may be that the method I know is limited. Now I haven't found any way to insert a data into a header of a file. The only way is to rewrite the file. In general, the method of inserting a piece of data into a file is to first write the previous data before the insertion point, and the file after the insertion point, and then re-establish a file, put the data before the insertion point from memory from memory. In the file, write the information to be inserted, and finally write the insertion point file into it. In fact, this is not what we think is very slow, but it is only a bit of trouble. By the way, it is strictly forbidden to write two parts before and after the insertion point to the temporary file, that is too delayed, a MP3 file can have 3-4MB! After writing and then deleted, the yellow flower is cold. Since ID3v2 is the head of the MP3 file, we can write the MP3 file data after the insertion point is written in memory. Due to a deeper step:
Task 1: Let SHITMP3 can display all ID3v1 information
Figure 5 ShitMP3V1.07 shows ID3v1 information
As you can see, Shitmp3 can display a MP3 file ID3v1 all information, this is not very difficult, first, we have to read the structure of ID3v1 from the MP3 file:
// Error defined #define nofile -1; // No file #define fileUnopen -2; // File Can't open #define notag -3; // No MP3 flag #define allblank -4; // logo information all Empty #define norename -5; // Unable to replace the file name Bool Stargetmp3Info (CSTRING FileName, MP3INFO * MP3) {cfileFind Find; if (! Find.FindFile (filename)) Return Nofile; // Path does not exist
Cfile file; // File Unable to open if (! File.open (filename, cfile :: modeRead) Return fileUnopen; long seeek (-seekpos, cfile :: end); Byte Pbuf [128]; MEMSET (PBUF, 0, SIZEOF (PBUF));
File.read (PBUF, 128); // Get tag, if not tag, then return
IF (! ((PBUF [0] == 'T' || PBUF [0] == 't') && (PBUF [1] == 'a' || PBUF [1] == 'A') && (PBUF [2] == 'g' || PBUF [0] == 'g'))) Return NOTAG; MEMSET (MP3, 0, SIZEOF (* MP3)); MEMCPY (MP3, PBUF, SIZEOF (* MP3 )); Return True;
Thus, the ID3v1 of MP3 is stored in the variable of the MP3Info structure. We only need to put this data on the view.
Task 2: Let Shitmp3 store id3v1 information into the MP3 file
If the user wants to modify the information of the MP3 file, we must naturally reset this information in the MP3 file. Of course, if this MP3 file has no ID3v1 information at all, then we have to be a 128-byte ID3v1 structure to file up. If you update, we will write the last 128 bytes of the file over again. Bool cmp3 :: refreshmp3info (cstring filepath, mp3info * mp3) {BOOL RE = false; cfileFind Find; if (! Find.FindFile (filepath)) Return nofile; // The path does not exist if the cfile file; // File Unable to open IF ( File.open (FilePath, CFile :: ModeReadwrite) Return FileUnopen; long seekpos = 128; file.seek (-seekpos, cfile :: end); byte PBUF [128]; MEMSET (PBUF, 0, SIZEOF (PBUF) ); File.read (PBUF, 128); // If the file is not ID3V1 information if (! ((PBUF [0] == 't' || PBUF [0] == 'T') && (PBUF [1] == 'A' || PBUF [1] == 'a') && (PBUF [2] == 'g' || PBUF [0] == 'g'))) {file.seektoend (); / / Put the file to the last position of the file} else {file.seek (-seekpos, cfile :: end); // Put the file pointer to the file countdown 128th} file.write (& MP3F, SIZEOF (MP3F)) ; // Write id3v1 to file Return True;}
Figure 6 Shit3v2 information in Shitmp3
Task 3: Let SHITMP3 display the ID3v2 information of the MP3 file
Just in principle we talked about ID3v2 information of the MP3 file, read this information is more troublesome. We need to have a pointer, first get the total title information of ID3v2, from there, from the length of the ID3V2 information, whether or not the ID3v2 flag exists, if there is an id3v2 flag, we will read it in order according to the order of the data structure, until This pointer refers to the location of the MP3 file ID3v2 information body length value. During the period, each data structure is obtained, the data header of that data structure is mentioned, and the length of this structure is obtained, and then the content stored in this structure is then read. First, let's define what FrameID table: #define ID3V2_FRAMEID_TITLE "TIT2" // song name #define ID3V2_FRAMEID_ARTIST "TPE1" // artist name #define ID3V2_FRAMEID_ALBUM "TALB" // album name #define ID3V2_FRAMEID_TRACK "TRCK" // #define disc number ID3V2_FRAMEID_YEAR "TYER" // in #define ID3V2_FRAMEID_COMMENT "COMM" // comment #define ID3V2_FRAMEID_GENRE "TCON" // song style #define ID3V2_FRAMEID_ENCODEBY "TENC" // encoding #define ID3V2_FRAMEID_COPYRIGHT "TCOP" // copyright #define ID3V2_FRAMEID_URL "WXXX "// URL URL
Since Id3v2 is the previous three bytes of "ID3", we need to detect before reading, the current MP3 file is not satisfied. Bool Hasid3V2Tag (CString Path) // Parameter Bit File Path {CFile File; if (! File.open (path, cfile :: ModeRead) Return False; // File Unable to open BYTE ID3 [3]; MEMSET (ID3, 0 , SIZEOF (ID3)); file.read (ID3, 3); IF ((id3 [0] == 'I') && (ID3 [1] == 'd') && (ID3 [2] == ' 3 ')) {return true;} file.close ();} After detecting the specified MP3 file does have ID3v2 information, we have to do it from the ten bytes to get the mark we want. Head information, and this ten-byte header information, for our most important except, the test is not the "ID3" flag, and the remaining is the length of the entire ID3V2 information body. In the above principle, we already know how to do it. I will no longer be repeated here, just read the 7-10 bytes of the MP3 file with ID3V2 information. After getting the length of this data body, we will traverse all data structures to parse the contents of the data structure of ID3v2. First we need to define a pointer, let him only want the Id3V2 data part of the starting position (i.e., the 11th byte of the MP3 file with ID3V2 information). Then, first get the header of the first data structure, to obtain the corresponding data frameID from the header of the data structure, see which type of information is seen, and then get the length of the data content of this data structure, with these two Information, we can get the content of a data structure, save this hard bitter data to a variable we complete a data structure to resolve tasks. Void getFrameHeader (cfile * pfile) {if (! hasid3v2tag ()) Return; dword dwpos = 10; // This is the so-called pointer char cnull = 0 mentioned above; pfile-> seek (10, cfile :: begin ); // Let the file pointer on the 11th byte of the position for (;;) {if (dwpos> = m_nsize) // assume that m_nsize is the total length of the data obtained above;
// The header structure of the data structure, in the above principle we have mentioned ID3V2FrameHeader TfrmHeader; pfile-> read ((void *) & tfrmheader, 10);
IF (strcmp (tfrmHeader.frameid, & cnull)! = 0) {// assume the getfrmheadersize () function can get a data structure of a data structure, this // Algorithm We also mention DWPOS = DWPOS GetFrmHeadersize in front (tfrmheader) 10 1; // Get regular frameid // title title IF (strncmp ((char *) frmheader.fh_id, id3v2_frameid_title, 4) == 0) {...} // Artist Artist else IF (Strncmp (char *) frmheader.fh_id, ID3v2_frameid_artist, 4) == 0) {...} // Album Record ELSE IF (Strncmp (Char *) frmheader.fh_id, ID3v2_frameid_album, 4) == 0) {...} // Remarks are started in: eNG. Therefore, 4 bytes should be removed (Strncmp (Char *) frmheader.fh_id, id3v2_frameid_comment, 4) == 0) {...} // year else IF (strncmp ((char *) frmheader.fh_id, id3v2_frameid_year, 4) == 0) {...} // TRACK ELSE IF (Strncmp (CHAR *) frmheader.fh_id, ID3v2_frameid_track, 4) == 0) {... } // Genre song style else if (strncmp ((char *) frmheader.fh_id, ID3V2_FRAMEID_GENRE, 4) == 0) {......} // encode encoding else if (strncmp ((char *) frmheader.fh_id, ID3V2_FRAMEID_ENCODEBY , 4) == 0) {...} // Copyright copyright ELSE IF (Strncmp (Char *) frmheader.fh_id, id3v2_frameid_copyright, 4) == 0) {...} // URL URL ELSE IF (Strncmp ((char *) frmheader.fh_id, id3v2_frameid_url, 4) == 0) {...} // Return to the file PFILE-> Seek (dwpos, cfile :: begin);} else {breaf;}}} You can get every data structure through such retrieves. The data is naturally, which is naturally the ID3v2 information we want. Every "..." in the above function is the process of extracting the data body, basically very different. We only need to read the length of the data structure, which is too easy to resolve a data content. What is important is that we have to know that the above function is not only for ID3v2 information, in fact, for JPEG's resolution, the resolution of GIF, actually there is a wonderfulness, so you can take this The function is well saved, I want to use it in many places. If you can abstract him into a class, then just fine.
Task 4: Make SHITMP3 Save MP3 file ID3v2 information This work is clearly the most challenging, not only because the ID3v2 information is to be executed as complex inverse operations as the above parsing ID3V2; more people must know ID3V2 It is not like the end of the ID3v1 exists, we want to write, just put the file pointer to the end of the file, then Write is ok. ID3v2 is a file header with files, which brings us trouble. I have found various information, unfortunately, without any feasible way can insert information directly in a file (at least in the language of VC, if you have, then I will be very grateful to your enlightening). However, we all know that the files are read and written, so we can use the read and write realization insertion operation. When we determine that it is written to an ID3v2 to a MP3 file, we must first determine if this MP3 file has ID3v2 tag information. If the file is not ID3V2 tag, then we will add it. If we have to rewrite it. The specific steps are shown in Figure 6 If an MP3 file does not have ID3V2 information, we have to do it is to put the new ID3v2 information in memory, then put all the data from the original MP3 file in memory, then put this in memory This new MP3 file is written to this specified file. The order of generating ID3V2 information is to make every data structure (such as a singer, song name), then generate a data body (which is to exist in these data structures), then regenerate into a total header, and finalize these The finished information is placed in memory. In terms of generating data structures, I only have a generation of song names as an example, and the other things are similar, the methods are as follows: int TMPLENGTH = 0; // Generates the header ID3V2FrameHeader TitleHeader; // Principle mentioned The structure of the data structure Memset (& TitleHeader); cstring titlestring = ""; // assumes that the user entered ID3v2 song name is placed in a text box named m_ctrleditsong.GetWindowText (TitleSTring); // Get the title of the song name // mentioned that WinAmp is added more than one / 0 in the first byte of the content, so there are more natural lengths. TMPLENGTH = Titlestring.getLength () 1; // This length is written in a real structure. TitleHeader.Size [3] = (byte) TMPLENGTH; TitleHeader.Size [2] = (TMPLENGTH-TITLEHEADER.SIZE [3]) / 256; titleHeader.Size [1] = (TMPLENGTH-TitleHeader.Ifh_size [3] -titleHeader .Size [2] * 256) / 256/256; titleHeader.size [0] = (TMPLENGTH-TITLEHEADER.IFH_SIZE [3] -titleHeader.size [2] * 256-titleHeader.Ifh_size [1] * 256 * 256) / 256/256/256; // Write FrameID, in the extraction ID3v2 we mentioned the FrameID that definition table memcpy (titleHeader.FrameID, ID3v2_frameid_title, 4); // Store this data structure, header and The total length of the fitting body, because we finally get the total header, use int totaltitlesize = tMplength 10;
Well, we pass the above algorithms, we finally got TitleString (Song name) and TitleHeader (Song named data structure header), and a total length of TOTALTITLESIZE was used to facilitate calculation of ID3v2. With the same method, we can receive the data structure of all ID3v2 data structures and data structures in sequence. Below we have to generate the total length of the 10-byte header, just introduced the total length of the corresponding song name data structure in the TOTALTITLESize variable, and we got the total length of these data structures to get the total The total length of the header. Here is still a reminder, don't forget, the total header size is the maximum 128, not 256. (See the principles in detail). // Generate ID3V2 header ID3V2HEADER Header; // The header structure mentioned in front of the header Memset (& header, 0, sizeof (header)); Memcpy (Header. Identifier, "Id3", 3); // Write ID3 three bytes of flag bit header. Version.s_major = 3; // Write version header. Version.s_revision = 0; // Depth version header. Flags = 0; // flag INT TOTALSIZE = TotalTitLesize / / Joined song name data structure length TOTALATISTSIZE / / hypothesis: Singer Name Data Structure Length TotaLalbumsize // Assumption: Album Name Data Structure Length Totalcomments Item // Assumption: Comment Data Structure Length Totalyearsize // Assume: Year Data Structure Length TOTALGENRESIZE / / Assumption: Song State Data Structure Length TotalTracksize // Assumption: TotalEncodeBysize // Assumption: Coding Method Data Structure Length TotalURLSize // Assumption: URL URL Data Structure Length TotalcopyrightSize; // Assume : Copyright data structure length // Write the total length, remember is the maximum 128 header.size per bit [0] = Totalsize / 128/128/128; header. Size [1] = (Totalsize-header. Size [0] * 128 * 128 * 128) / 128/128; header. Size [2] = (Totalsize-header. Size [0] * 128 * 128-header. Size [1] * 128 * 128) / 128; header. Size [3] = (Totalsize-header. Size [0] * 128 * 128-header.size [1] * 128 * 128-header.size [2] * 128); Ok, this information has a designated structure. Or in the variable, we have to do it in a memory file, there is a special file class in VC , he is called "cmemfi LE ". This class can help us generate a file in memory (whitening, is a spatial storage information in memory).
/ / Suppose: FileLength is the length of the original file // Assumption: ID3Size is the ID3v2 information length in the original MP3 file, of course, if there is no ID3v2, then 0 // Totalsize is the new ID3v2 data size, plus 10, The total length of the new ID3V2 information is // So the final resulting MemfileLength is the length of the new file DWORD MEMFILENGTH = FileLength-Id3Size Totalsize 10; // New memory file cmemfile memfile; byte * buffer = (byte *) malloc (BYTE *) Malloc MemfileLength; Memfile.attach (Buffer, MemfileLength, 1024); Memfile.SetLength; // Write all information // Write ID3V2 total head // header is the header information mentioned above Memfile.Write & Header, sizeof (header); byte tmp = 0; // Write song name Memfile.Write (& TitleHeader); Memfile.Write (& TMP, 1); Memfile.Write (TitleString, Titlestring.getlength )); // Write the singer ... // Write an album name ... // Write a comment ... // Write a year ... // Write Track ... // Write genre ... // Write Enter Copyright ... // Write Encode ... // Write URL ... // Write MP3 main information file.seek (id3size, cfile :: begin); byte * tempBuffer = new byte [fileLength-id3size]; file .Readhuge (TempBuffer, FileLength); File.close (); Memfile.Writehuge (TempBuffer, FileLength-Id3Size); Ok, new file has been written in memory, because writing a variety of data structures Here I only wrote the song name as an example. "Memfile.Write (& TMP, 1);" Write a "/ 0" in the file, we will add a '/ 0' in front of the content when Winamp mentioned in principle is saved and read And calculate this byte in the size of the frame content. In addition, we don't forget the writing of the comments, some are not big, don't forget to add "eNG / 0" (mentioned in principle). In addition, careful readers may notice that when writing files, I used Writehuge without using Write, because in VC , when writing more than 64K data, use Writehuge functions, because it is very useful again. slow. A MP3 file body, how to say there is 3-4MB, so it is natural to choose Writehuge. Of course, Readhuge is also a truth. The last step is to write new and put on the memory information to the file. Don't forget to clean up memory.