You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
372 lines
9.5 KiB
372 lines
9.5 KiB
/*
|
|
* 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 <stderr>.");
|
|
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
|