xref: /plan9/sys/src/games/mp3enc/VbrTag.c (revision 8f5875f3e9b20916b4c52ad4336922bc8653eb7b)
1 /*
2  *	Xing VBR tagging for LAME.
3  *
4  *	Copyright (c) 1999 A.L. Faber
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21 
22 /* $Id: VbrTag.c,v 1.20 2001/02/27 09:59:16 robert Exp $ */
23 
24 #ifdef HAVE_CONFIG_H
25 # include <config.h>
26 #endif
27 
28 #include "machine.h"
29 #if defined(__riscos__) && defined(FPA10)
30 #include	"ymath.h"
31 #else
32 #include	<math.h>
33 #endif
34 #include "VbrTag.h"
35 #include "version.h"
36 #include "bitstream.h"
37 #include "VbrTag.h"
38 #include	<assert.h>
39 
40 #ifdef WITH_DMALLOC
41 #include <dmalloc.h>
42 #endif
43 
44 
45 #ifdef _DEBUG
46 /*  #define DEBUG_VBRTAG */
47 #endif
48 
49 /*
50 //    4 bytes for Header Tag
51 //    4 bytes for Header Flags
52 //  100 bytes for entry (NUMTOCENTRIES)
53 //    4 bytes for FRAME SIZE
54 //    4 bytes for STREAM_SIZE
55 //    4 bytes for VBR SCALE. a VBR quality indicator: 0=best 100=worst
56 //   20 bytes for LAME tag.  for example, "LAME3.12 (beta 6)"
57 // ___________
58 //  140 bytes
59 */
60 #define VBRHEADERSIZE (NUMTOCENTRIES+4+4+4+4+4)
61 
62 /* the size of the Xing header (MPEG1 and MPEG2) in kbps */
63 #define XING_BITRATE1 128
64 #define XING_BITRATE2  64
65 #define XING_BITRATE25 32
66 
67 
68 
69 const static char	VBRTag[]={"Xing"};
70 const int SizeOfEmptyFrame[2][2]=
71 {
72 	{17,9},
73 	{32,17},
74 };
75 
76 
77 /***********************************************************************
78  *  Robert Hegemann 2001-01-17
79  ***********************************************************************/
80 
addVbr(VBR_seek_info_t * v,int bitrate)81 void addVbr(VBR_seek_info_t * v, int bitrate)
82 {
83     int i;
84 
85     v->sum += bitrate;
86     v->seen ++;
87 
88     if (v->seen < v->want) {
89         return;
90     }
91 
92     if (v->pos < v->size) {
93         v->bag[v->pos] = v->sum;
94         v->pos ++;
95         v->seen = 0;
96     }
97     if (v->pos == v->size) {
98         for (i = 1; i < v->size; i += 2) {
99             v->bag[i/2] = v->bag[i];
100         }
101         v->want *= 2;
102         v->pos  /= 2;
103     }
104 }
105 
Xing_seek_table(VBR_seek_info_t * v,unsigned char * t)106 void Xing_seek_table(VBR_seek_info_t * v, unsigned char *t)
107 {
108     int i, index;
109     int seek_point;
110 
111     if (v->pos <= 0)
112         return;
113 
114     for (i = 1; i < NUMTOCENTRIES; ++i) {
115         float j = i/(float)NUMTOCENTRIES, act, sum;
116         index = (int)(floor(j * v->pos));
117         if (index > v->pos-1)
118             index = v->pos-1;
119         act = v->bag[index];
120         sum = v->sum;
121         seek_point = (int)(256. * act / sum);
122         if (seek_point > 255)
123             seek_point = 255;
124         t[i] = seek_point;
125     }
126 }
127 
128 #if 0
129 void print_seeking(unsigned char *t)
130 {
131     int i;
132 
133     printf("seeking table ");
134     for (i = 0; i < NUMTOCENTRIES; ++i) {
135         printf(" %d ", t[i]);
136     }
137     printf("\n");
138 }
139 #endif
140 
141 
142 
143 /****************************************************************************
144  * AddVbrFrame: Add VBR entry, used to fill the VBR the TOC entries
145  * Paramters:
146  *	nStreamPos: how many bytes did we write to the bitstream so far
147  *				(in Bytes NOT Bits)
148  ****************************************************************************
149 */
AddVbrFrame(lame_global_flags * gfp)150 void AddVbrFrame(lame_global_flags *gfp)
151 {
152     lame_internal_flags *gfc = gfp->internal_flags;
153 
154     int kbps = bitrate_table[gfp->version][gfc->bitrate_index];
155 
156     if (gfc->VBR_seek_table.bag == NULL) {
157         gfc->VBR_seek_table.sum  = 0;
158         gfc->VBR_seek_table.seen = 0;
159         gfc->VBR_seek_table.want = 1;
160         gfc->VBR_seek_table.pos  = 0;
161         gfc->VBR_seek_table.bag  = malloc (400*sizeof(int));
162         if (gfc->VBR_seek_table.bag != NULL) {
163             gfc->VBR_seek_table.size = 400;
164         }
165         else {
166             gfc->VBR_seek_table.size = 0;
167             ERRORF (gfc,"Error: can't allocate VbrFrames buffer\n");
168             return;
169         }
170     }
171     addVbr(&gfc->VBR_seek_table, kbps);
172     gfp->nVbrNumFrames++;
173 }
174 
175 
176 /*-------------------------------------------------------------*/
ExtractI4(unsigned char * buf)177 static int ExtractI4(unsigned char *buf)
178 {
179 	int x;
180 	/* big endian extract */
181 	x = buf[0];
182 	x <<= 8;
183 	x |= buf[1];
184 	x <<= 8;
185 	x |= buf[2];
186 	x <<= 8;
187 	x |= buf[3];
188 	return x;
189 }
190 
CreateI4(unsigned char * buf,int nValue)191 void CreateI4(unsigned char *buf, int nValue)
192 {
193         /* big endian create */
194 	buf[0]=(nValue>>24)&0xff;
195 	buf[1]=(nValue>>16)&0xff;
196 	buf[2]=(nValue>> 8)&0xff;
197 	buf[3]=(nValue    )&0xff;
198 }
199 
200 
201 /*-------------------------------------------------------------*/
202 /* Same as GetVbrTag below, but only checks for the Xing tag.
203    requires buf to contain only 40 bytes */
204 /*-------------------------------------------------------------*/
CheckVbrTag(unsigned char * buf)205 int CheckVbrTag(unsigned char *buf)
206 {
207 	int			h_id, h_mode, h_sr_index;
208 
209 	/* get selected MPEG header data */
210 	h_id       = (buf[1] >> 3) & 1;
211 	h_sr_index = (buf[2] >> 2) & 3;
212 	h_mode     = (buf[3] >> 6) & 3;
213 
214 	/*  determine offset of header */
215 	if( h_id )
216 	{
217                 /* mpeg1 */
218 		if( h_mode != 3 )	buf+=(32+4);
219 		else				buf+=(17+4);
220 	}
221 	else
222 	{
223                 /* mpeg2 */
224 		if( h_mode != 3 ) buf+=(17+4);
225 		else              buf+=(9+4);
226 	}
227 
228 	if( buf[0] != VBRTag[0] ) return 0;    /* fail */
229 	if( buf[1] != VBRTag[1] ) return 0;    /* header not found*/
230 	if( buf[2] != VBRTag[2] ) return 0;
231 	if( buf[3] != VBRTag[3] ) return 0;
232 	return 1;
233 }
234 
GetVbrTag(VBRTAGDATA * pTagData,unsigned char * buf)235 int GetVbrTag(VBRTAGDATA *pTagData,  unsigned char *buf)
236 {
237 	int			i, head_flags;
238 	int			h_bitrate,h_id, h_mode, h_sr_index;
239 
240 	/* get Vbr header data */
241 	pTagData->flags = 0;
242 
243 	/* get selected MPEG header data */
244 	h_id       = (buf[1] >> 3) & 1;
245 	h_sr_index = (buf[2] >> 2) & 3;
246 	h_mode     = (buf[3] >> 6) & 3;
247         h_bitrate  = ((buf[2]>>4)&0xf);
248 	h_bitrate = bitrate_table[h_id][h_bitrate];
249 
250 
251 	/*  determine offset of header */
252 	if( h_id )
253 	{
254                 /* mpeg1 */
255 		if( h_mode != 3 )	buf+=(32+4);
256 		else				buf+=(17+4);
257 	}
258 	else
259 	{
260                 /* mpeg2 */
261 		if( h_mode != 3 ) buf+=(17+4);
262 		else              buf+=(9+4);
263 	}
264 
265 	if( buf[0] != VBRTag[0] ) return 0;    /* fail */
266 	if( buf[1] != VBRTag[1] ) return 0;    /* header not found*/
267 	if( buf[2] != VBRTag[2] ) return 0;
268 	if( buf[3] != VBRTag[3] ) return 0;
269 
270 	buf+=4;
271 
272 	pTagData->h_id = h_id;
273 	pTagData->samprate = samplerate_table[h_id][h_sr_index];
274 
275 	if( h_id == 0 )
276 		pTagData->samprate >>= 1;
277 
278 	head_flags = pTagData->flags = ExtractI4(buf); buf+=4;      /* get flags */
279 
280 	if( head_flags & FRAMES_FLAG )
281 	{
282 		pTagData->frames   = ExtractI4(buf); buf+=4;
283 	}
284 
285 	if( head_flags & BYTES_FLAG )
286 	{
287 		pTagData->bytes = ExtractI4(buf); buf+=4;
288 	}
289 
290 	if( head_flags & TOC_FLAG )
291 	{
292 		if( pTagData->toc != NULL )
293 		{
294 			for(i=0;i<NUMTOCENTRIES;i++)
295 				pTagData->toc[i] = buf[i];
296 		}
297 		buf+=NUMTOCENTRIES;
298 	}
299 
300 	pTagData->vbr_scale = -1;
301 
302 	if( head_flags & VBR_SCALE_FLAG )
303 	{
304 		pTagData->vbr_scale = ExtractI4(buf); buf+=4;
305 	}
306 
307 	pTagData->headersize =
308 	  ((h_id+1)*72000*h_bitrate) / pTagData->samprate;
309 
310 
311 #ifdef DEBUG_VBRTAG
312 	DEBUGF("\n\n********************* VBR TAG INFO *****************\n");
313 	DEBUGF("tag         :%s\n",VBRTag);
314 	DEBUGF("head_flags  :%d\n",head_flags);
315 	DEBUGF("bytes       :%d\n",pTagData->bytes);
316 	DEBUGF("frames      :%d\n",pTagData->frames);
317 	DEBUGF("VBR Scale   :%d\n",pTagData->vbr_scale);
318 	DEBUGF("toc:\n");
319 	if( pTagData->toc != NULL )
320 	{
321 		for(i=0;i<NUMTOCENTRIES;i++)
322 		{
323 			if( (i%10) == 0 ) DEBUGF("\n");
324 			DEBUGF(" %3d", (int)(pTagData->toc[i]));
325 		}
326 	}
327 	DEBUGF("\n***************** END OF VBR TAG INFO ***************\n");
328 #endif
329 	return 1;       /* success */
330 }
331 
332 
333 /****************************************************************************
334  * InitVbrTag: Initializes the header, and write empty frame to stream
335  * Paramters:
336  *				fpStream: pointer to output file stream
337  *				nMode	: Channel Mode: 0=STEREO 1=JS 2=DS 3=MONO
338  ****************************************************************************
339 */
InitVbrTag(lame_global_flags * gfp)340 int InitVbrTag(lame_global_flags *gfp)
341 {
342 	int nMode,SampIndex;
343 	lame_internal_flags *gfc = gfp->internal_flags;
344 #define MAXFRAMESIZE 576
345 	//	u_char pbtStreamBuffer[MAXFRAMESIZE];
346 	nMode = gfp->mode;
347 	SampIndex = gfc->samplerate_index;
348 
349 
350 	/* Clear Frame position array variables */
351 	gfp->pVbrFrames=NULL;
352 	gfp->nVbrNumFrames=0;
353 	gfp->nVbrFrameBufferSize=0;
354 
355 
356 	/* Clear stream buffer */
357 	//	memset(pbtStreamBuffer,0x00,sizeof(pbtStreamBuffer));
358 
359 
360 
361 	/* Reserve the proper amount of bytes */
362 	if (nMode==3)
363 	{
364 		gfp->nZeroStreamSize=SizeOfEmptyFrame[gfp->version][1]+4;
365 	}
366 	else
367 	{
368 		gfp->nZeroStreamSize=SizeOfEmptyFrame[gfp->version][0]+4;
369 	}
370 
371 	/*
372 	// Xing VBR pretends to be a 48kbs layer III frame.  (at 44.1kHz).
373         // (at 48kHz they use 56kbs since 48kbs frame not big enough for
374         // table of contents)
375 	// let's always embed Xing header inside a 64kbs layer III frame.
376 	// this gives us enough room for a LAME version string too.
377 	// size determined by sampling frequency (MPEG1)
378 	// 32kHz:    216 bytes@48kbs    288bytes@ 64kbs
379 	// 44.1kHz:  156 bytes          208bytes@64kbs     (+1 if padding = 1)
380 	// 48kHz:    144 bytes          192
381 	//
382 	// MPEG 2 values are the same since the framesize and samplerate
383         // are each reduced by a factor of 2.
384 	*/
385 	{
386 	int i,bitrate,tot;
387 	if (1==gfp->version) {
388 	  bitrate = XING_BITRATE1;
389 	} else {
390 	  if (gfp->out_samplerate < 16000 )
391 	    bitrate = XING_BITRATE25;
392 	  else
393 	    bitrate = XING_BITRATE2;
394 	}
395 	gfp->TotalFrameSize=
396 	  ((gfp->version+1)*72000*bitrate) / gfp->out_samplerate;
397 	tot = (gfp->nZeroStreamSize+VBRHEADERSIZE);
398 	tot += 20;  /* extra 20 bytes for LAME & version string */
399 
400 	assert(gfp->TotalFrameSize >= tot );
401 	assert(gfp->TotalFrameSize <= MAXFRAMESIZE );
402 
403 	for (i=0; i<gfp->TotalFrameSize; ++i)
404 	  add_dummy_byte(gfp,0);
405 	}
406 
407 	/* Success */
408 	return 0;
409 }
410 
411 
412 
413 /****************************************************************************
414  * PutVbrTag: Write final VBR tag to the file
415  * Paramters:
416  *				lpszFileName: filename of MP3 bit stream
417  *				nVbrScale	: encoder quality indicator (0..100)
418  ****************************************************************************
419 */
PutVbrTag(lame_global_flags * gfp,FILE * fpStream,int nVbrScale)420 int PutVbrTag(lame_global_flags *gfp,FILE *fpStream,int nVbrScale)
421 {
422         lame_internal_flags * gfc = gfp->internal_flags;
423 
424 	long lFileSize;
425 	int nStreamIndex;
426 	char abyte,bbyte;
427 	u_char		btToc[NUMTOCENTRIES];
428 	u_char pbtStreamBuffer[MAXFRAMESIZE];
429 	char str1[80];
430         unsigned char id3v2Header[10];
431         size_t id3v2TagSize;
432 
433         if (gfc->VBR_seek_table.pos <= 0)
434 		return -1;
435 
436 
437 	/* Clear stream buffer */
438 	memset(pbtStreamBuffer,0x00,sizeof(pbtStreamBuffer));
439 
440 	/* Seek to end of file*/
441 	fseek(fpStream,0,SEEK_END);
442 
443 	/* Get file size */
444 	lFileSize=ftell(fpStream);
445 
446 	/* Abort if file has zero length. Yes, it can happen :) */
447 	if (lFileSize==0)
448 		return -1;
449 
450         /*
451          * The VBR tag may NOT be located at the beginning of the stream.
452          * If an ID3 version 2 tag was added, then it must be skipped to write
453          * the VBR tag data.
454          */
455 
456         /* seek to the beginning of the stream */
457 	fseek(fpStream,0,SEEK_SET);
458         /* read 10 bytes in case there's an ID3 version 2 header here */
459         fread(id3v2Header,1,sizeof id3v2Header,fpStream);
460         /* does the stream begin with the ID3 version 2 file identifier? */
461         if (!strncmp((char *)id3v2Header,"ID3",3)) {
462           /* the tag size (minus the 10-byte header) is encoded into four
463            * bytes where the most significant bit is clear in each byte */
464           id3v2TagSize=(((id3v2Header[6] & 0x7f)<<21)
465             | ((id3v2Header[7] & 0x7f)<<14)
466             | ((id3v2Header[8] & 0x7f)<<7)
467             | (id3v2Header[9] & 0x7f))
468             + sizeof id3v2Header;
469         } else {
470           /* no ID3 version 2 tag in this stream */
471           id3v2TagSize=0;
472         }
473 
474 	/* Seek to first real frame */
475 	fseek(fpStream,id3v2TagSize+gfp->TotalFrameSize,SEEK_SET);
476 
477 	/* Read the header (first valid frame) */
478 	fread(pbtStreamBuffer,4,1,fpStream);
479 
480 	/* the default VBR header. 48 kbps layer III, no padding, no crc */
481 	/* but sampling freq, mode andy copyright/copy protection taken */
482 	/* from first valid frame */
483 	pbtStreamBuffer[0]=(u_char) 0xff;
484 	abyte = (pbtStreamBuffer[1] & (char) 0xf1);
485 	{ int bitrate;
486 	if (1==gfp->version) {
487 	  bitrate = XING_BITRATE1;
488 	} else {
489 	  if (gfp->out_samplerate < 16000 )
490 	    bitrate = XING_BITRATE25;
491 	  else
492 	    bitrate = XING_BITRATE2;
493 	}
494 	  bbyte = 16*BitrateIndex(bitrate,gfp->version,gfp->out_samplerate);
495 	}
496 
497 	/* Use as much of the info from the real frames in the
498 	 * Xing header:  samplerate, channels, crc, etc...
499 	 */
500 	if (gfp->version==1) {
501 	  /* MPEG1 */
502 	  pbtStreamBuffer[1]=abyte | (char) 0x0a;     /* was 0x0b; */
503 	  abyte = pbtStreamBuffer[2] & (char) 0x0d;   /* AF keep also private bit */
504 	  pbtStreamBuffer[2]=(char) bbyte | abyte;     /* 64kbs MPEG1 frame */
505 	}else{
506 	  /* MPEG2 */
507 	  pbtStreamBuffer[1]=abyte | (char) 0x02;     /* was 0x03; */
508 	  abyte = pbtStreamBuffer[2] & (char) 0x0d;   /* AF keep also private bit */
509 	  pbtStreamBuffer[2]=(char) bbyte | abyte;     /* 64kbs MPEG2 frame */
510 	}
511 
512 
513 	/*Seek to the beginning of the stream */
514 	fseek(fpStream,id3v2TagSize,SEEK_SET);
515 
516 	/* Clear all TOC entries */
517 	memset(btToc,0,sizeof(btToc));
518 
519         Xing_seek_table (&gfc->VBR_seek_table, btToc);
520         /* print_seeking (btToc); */
521 
522 	/* Start writing the tag after the zero frame */
523 	nStreamIndex=gfp->nZeroStreamSize;
524 
525 	/* Put Vbr tag */
526 	pbtStreamBuffer[nStreamIndex++]=VBRTag[0];
527 	pbtStreamBuffer[nStreamIndex++]=VBRTag[1];
528 	pbtStreamBuffer[nStreamIndex++]=VBRTag[2];
529 	pbtStreamBuffer[nStreamIndex++]=VBRTag[3];
530 
531 	/* Put header flags */
532 	CreateI4(&pbtStreamBuffer[nStreamIndex],FRAMES_FLAG+BYTES_FLAG+TOC_FLAG+VBR_SCALE_FLAG);
533 	nStreamIndex+=4;
534 
535 	/* Put Total Number of frames */
536 	CreateI4(&pbtStreamBuffer[nStreamIndex],gfp->nVbrNumFrames);
537 	nStreamIndex+=4;
538 
539 	/* Put Total file size */
540 	CreateI4(&pbtStreamBuffer[nStreamIndex],(int)lFileSize);
541 	nStreamIndex+=4;
542 
543 	/* Put TOC */
544 	memcpy(&pbtStreamBuffer[nStreamIndex],btToc,sizeof(btToc));
545 	nStreamIndex+=sizeof(btToc);
546 
547 	/* Put VBR SCALE */
548 	CreateI4(&pbtStreamBuffer[nStreamIndex],nVbrScale);
549 	nStreamIndex+=4;
550 
551 	/* Put LAME ID */
552         sprintf ( str1, "LAME%s", get_lame_short_version () );
553         strncpy ( (char*)pbtStreamBuffer + nStreamIndex, str1, 20 );
554         nStreamIndex += 20;
555 
556 
557 #ifdef DEBUG_VBRTAG
558 {
559 	VBRTAGDATA TestHeader;
560 	GetVbrTag(&TestHeader,pbtStreamBuffer);
561 }
562 #endif
563 
564         /* Put it all to disk again */
565 	if (fwrite(pbtStreamBuffer,(unsigned int)gfp->TotalFrameSize,1,fpStream)!=1)
566 	{
567 		return -1;
568 	}
569 	/* Save to delete the frame buffer */
570 	free(gfp->pVbrFrames);
571 	gfp->pVbrFrames=NULL;
572 
573 	return 0;       /* success */
574 }
575 
576