/* * mpg123.c * * Copyright (C) Thomas Oestreich - June 2001 * Copyright (c) 1999 Albert L Faber * * This file is part of transcode, a video stream processing tool * * transcode is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * transcode is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Make; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include "transcode.h" #include "tcinfo.h" #include "ioaux.h" #include "magic.h" #include "tc.h" #include "libtc/libtc.h" #ifdef HAVE_LAME #include "mpg123.h" #define MAX_U_32_NUM 0xFFFFFFFF #define MAX_BUF 4096 static char sbuffer[MAX_BUF]; static int fskip(FILE * fp, long offset, int whence) { #ifndef PIPE_BUF char buffer[4096]; #else char buffer[PIPE_BUF]; #endif int read; if (0 == fseek(fp, offset, whence)) return 0; if (whence != SEEK_CUR || offset < 0) { tc_log_warn(__FILE__, "fskip problem: Mostly the return status of functions is not evaluate so it is more secure to polute ."); return -1; } while (offset > 0) { read = offset > sizeof(buffer) ? sizeof(buffer) : offset; if ((read = fread(buffer, 1, read, fp)) <= 0) return -1; offset -= read; } return 0; } static int check_aid(const unsigned char *header) { return 0 == strncmp(header, "AiD\1", 4); } /* * Please check this and don't kill me if there's a bug * This is a (nearly?) complete header analysis for a MPEG-1/2/2.5 Layer I, II or III * data stream */ static int is_syncword_mp123(const void *const headerptr) { const unsigned char *const p = headerptr; static const char abl2[16] = { 0, 7, 7, 7, 0, 7, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8 }; if ((p[0] & 0xFF) != 0xFF) return 0; // first 8 bits must be '1' if ((p[1] & 0xE0) != 0xE0) return 0; // next 3 bits are also if ((p[1] & 0x18) == 0x08) return 0; // no MPEG-1, -2 or -2.5 if ((p[1] & 0x06) == 0x00) return 0; // no Layer I, II and III if ((p[2] & 0xF0) == 0xF0) return 0; // bad bitrate if ((p[2] & 0x0C) == 0x0C) return 0; // no sample frequency with (32,44.1,48)/(1,2,4) if ((p[1] & 0x06) == 0x04) // illegal Layer II bitrate/Channel Mode comb if (abl2[p[2] >> 4] & (1 << (p[3] >> 6))) return 0; return 1; } static int is_syncword_mp3(const void *const headerptr) { const unsigned char *const p = headerptr; if ((p[0] & 0xFF) != 0xFF) return 0; // first 8 bits must be '1' if ((p[1] & 0xE0) != 0xE0) return 0; // next 3 bits are also if ((p[1] & 0x18) == 0x08) return 0; // no MPEG-1, -2 or -2.5 if ((p[1] & 0x06) != 0x02) return 0; // no Layer III (can be merged with 'next 3 bits are also' test, but don't do this, this decreases readability) if ((p[2] & 0xF0) == 0xF0) return 0; // bad bitrate if ((p[2] & 0x0C) == 0x0C) return 0; // no sample frequency with (32,44.1,48)/(1,2,4) return 1; } int lame_decode_initfile(FILE * fd, mp3data_struct * mp3data, int format) { // VBRTAGDATA pTagData; // int xing_header,len2,num_frames; #define bufsize 100 unsigned char buf[bufsize]; int ret; int len, aid_header; short int pcm_l[1152], pcm_r[1152]; memset(mp3data, 0, sizeof(mp3data_struct)); memset(buf, 0, bufsize); lame_decode_init(); if (!format) format = 0x55; len = 4; if (fread(buf, 1, len, fd) != len) return -1; /* failed */ aid_header = check_aid(buf); if (aid_header) { if (fread(buf, 2, 1, fd) != 1) return -1; /* failed */ aid_header = (unsigned char) buf[0] + 256 * (unsigned char) buf[1]; tc_log_msg(__FILE__, "Album ID found. length=%i", aid_header); /* skip rest of AID, except for 6 bytes we have already read */ fskip(fd, aid_header - 6, SEEK_CUR); /* read 4 more bytes to set up buffer for MP3 header check */ len = fread(buf, 1, 4, fd); } /* look for valid 4 byte MPEG header */ if (len < 4) return -1; if (format == 0x55) { while ( !is_syncword_mp3(buf)) { int i; for (i = 0; i < len - 1; i++) buf[i] = buf[i + 1]; if (fread(buf + len - 1, 1, 1, fd) != 1) return -1; /* failed */ } } else if (format == 0x50) { while ( !is_syncword_mp123(buf)) { int i; for (i = 0; i < len - 1; i++) buf[i] = buf[i + 1]; if (fread(buf + len - 1, 1, 1, fd) != 1) return -1; /* failed */ } } // now parse the current buffer looking for MP3 headers. // (as of 11/00: mpglib modified so that for the first frame where // headers are parsed, no data will be decoded. // However, for freeformat, we need to decode an entire frame, // so mp3data->bitrate will be 0 until we have decoded the first // frame. Cannot decode first frame here because we are not // yet prepared to handle the output. ret = lame_decode1_headers(buf, len, pcm_l, pcm_r, mp3data); if (-1 == ret) return -1; /* repeat until we decode a valid mp3 header. */ while (!mp3data->header_parsed) { len = fread(buf, 1, sizeof(buf), fd); if (len != sizeof(buf)) return -1; ret = lame_decode1_headers(buf, len, pcm_l, pcm_r, mp3data); if (-1 == ret) return -1; } if (mp3data->bitrate==0) { tc_log_msg(__FILE__,"Input file is freeformat."); } if (mp3data->totalframes > 0) { /* mpglib found a Xing VBR header and computed nsamp & totalframes */ } else { /* set as unknown. Later, we will take a guess based on file size * ant bitrate */ mp3data->nsamp = MAX_U_32_NUM; } return 0; } /* For lame_decode_fromfile: return code -1 error n number of samples output. either 576 or 1152 depending on MP3 file. For lame_decode1_headers(): return code -1 error 0 ok, but need more data before outputing any samples n number of samples output. either 576 or 1152 depending on MP3 file. */ int lame_decode_fromfile(FILE * fd, short pcm_l[], short pcm_r[], mp3data_struct * mp3data) { int ret = 0, len=0; unsigned char buf[1024]; /* first see if we still have data buffered in the decoder: */ ret = lame_decode1_headers(buf, len, pcm_l, pcm_r, mp3data); if (ret!=0) return ret; /* read until we get a valid output frame */ while (1) { len = fread(buf, 1, 1024, fd); if (len == 0) { /* we are done reading the file, but check for buffered data */ ret = lame_decode1_headers(buf, len, pcm_l, pcm_r, mp3data); if (ret<=0) return -1; // done with file break; } ret = lame_decode1_headers(buf, len, pcm_l, pcm_r, mp3data); if (ret == -1) return -1; if (ret >0) break; } return ret; } static int verbose_flag; int buf_probe_mp3(unsigned char *_buf, int len, ProbeTrackInfo *pcm) { // VBRTAGDATA pTagData; // int xing_header,len2,num_frames; char *buf; mp3data_struct *mp3data; int i, ret; int format=0; short int pcm_l[1152], pcm_r[1152]; int type; if((mp3data = tc_zalloc(sizeof(mp3data_struct)))==NULL) { tc_log_error(__FILE__, "out of memory"); exit(1); } lame_decode_init(); buf=_buf; for (i = 0; i < len - 1; i++) { if(is_syncword_mp123(buf)) { // catch false positives switch(buf[1] & 0xff) { case 0xFD: case 0xFC: format = CODEC_MP2; break; case 0xFB: format = CODEC_MP3; break; } if (format) break; } ++buf; } type = buf[1] & 0xff; ret = lame_decode1_headers(buf, len, pcm_l, pcm_r, mp3data); if (-1 == ret) { //tc_log_error(__FILE__, "failed to probe mp3 header (%d)", len); return -1; } //copy infos: pcm->samplerate = mp3data->samplerate; pcm->chan = mp3data->stereo; pcm->bits = 16; pcm->format = CODEC_MP3; pcm->bitrate = mp3data->bitrate; if(verbose_flag & TC_DEBUG) tc_log_msg(__FILE__, "channels=%d, samplerate=%d Hz, bitrate=%d kbps, (fsize=%d)", mp3data->stereo, mp3data->samplerate, mp3data->bitrate, mp3data->framesize); switch(type) { case 0xFD: case 0xFC: pcm->format = CODEC_MP2; break; case 0xFB: pcm->format = CODEC_MP3; break; } return 0; } void probe_mp3(info_t *ipipe) { ssize_t ret=0; // need to find syncframe: if((ret = tc_pread(ipipe->fd_in, sbuffer, MAX_BUF)) != MAX_BUF) { if (!ret) { ipipe->error=1; return; } } verbose_flag = ipipe->verbose; //for single MP3 stream only if(buf_probe_mp3(sbuffer, ret, &ipipe->probe_info->track[0])<0) { ipipe->error=1; return; } switch(ipipe->probe_info->track[0].format) { case CODEC_MP2: ipipe->probe_info->magic = TC_MAGIC_MP2; break; case CODEC_MP3: ipipe->probe_info->magic = TC_MAGIC_MP3; break; } ++ipipe->probe_info->num_tracks; return; } #else // HAVE_LAME void probe_mp3(info_t *ipipe) { tc_log_error(__FILE__, "no lame support available"); return; } #endif