From cc2160de5cc05dc3aa77f3a34358e66f6193c8c9 Mon Sep 17 00:00:00 2001 From: MichaÅ‚ CichoÅ„ Date: Tue, 26 Jun 2012 20:35:30 +0200 Subject: Add support for AAC. --- faad2/src/common/Makefile.am | 1 + faad2/src/common/faad/aacinfo.c | 372 ++++++++++ faad2/src/common/faad/aacinfo.h | 53 ++ faad2/src/common/faad/aacinfo.sln | 19 + faad2/src/common/faad/aacinfo.vcproj | 224 ++++++ faad2/src/common/faad/filestream.c | 470 +++++++++++++ faad2/src/common/faad/filestream.h | 57 ++ faad2/src/common/faad/getopt.c | 755 ++++++++++++++++++++ faad2/src/common/faad/getopt.h | 130 ++++ faad2/src/common/faad/id3v2tag.c | 1124 ++++++++++++++++++++++++++++++ faad2/src/common/faad/id3v2tag.h | 54 ++ faad2/src/common/mp4ff/Makefile.am | 7 + faad2/src/common/mp4ff/mp4atom.c | 689 ++++++++++++++++++ faad2/src/common/mp4ff/mp4ff.c | 475 +++++++++++++ faad2/src/common/mp4ff/mp4ff.h | 138 ++++ faad2/src/common/mp4ff/mp4ff.vcproj | 326 +++++++++ faad2/src/common/mp4ff/mp4ff_int_types.h | 27 + faad2/src/common/mp4ff/mp4ffint.h | 344 +++++++++ faad2/src/common/mp4ff/mp4meta.c | 461 ++++++++++++ faad2/src/common/mp4ff/mp4sample.c | 155 ++++ faad2/src/common/mp4ff/mp4tagupdate.c | 656 +++++++++++++++++ faad2/src/common/mp4ff/mp4util.c | 191 +++++ 22 files changed, 6728 insertions(+) create mode 100644 faad2/src/common/Makefile.am create mode 100644 faad2/src/common/faad/aacinfo.c create mode 100644 faad2/src/common/faad/aacinfo.h create mode 100644 faad2/src/common/faad/aacinfo.sln create mode 100644 faad2/src/common/faad/aacinfo.vcproj create mode 100644 faad2/src/common/faad/filestream.c create mode 100644 faad2/src/common/faad/filestream.h create mode 100644 faad2/src/common/faad/getopt.c create mode 100644 faad2/src/common/faad/getopt.h create mode 100644 faad2/src/common/faad/id3v2tag.c create mode 100644 faad2/src/common/faad/id3v2tag.h create mode 100644 faad2/src/common/mp4ff/Makefile.am create mode 100644 faad2/src/common/mp4ff/mp4atom.c create mode 100644 faad2/src/common/mp4ff/mp4ff.c create mode 100644 faad2/src/common/mp4ff/mp4ff.h create mode 100644 faad2/src/common/mp4ff/mp4ff.vcproj create mode 100644 faad2/src/common/mp4ff/mp4ff_int_types.h create mode 100644 faad2/src/common/mp4ff/mp4ffint.h create mode 100644 faad2/src/common/mp4ff/mp4meta.c create mode 100644 faad2/src/common/mp4ff/mp4sample.c create mode 100644 faad2/src/common/mp4ff/mp4tagupdate.c create mode 100644 faad2/src/common/mp4ff/mp4util.c (limited to 'faad2/src/common') diff --git a/faad2/src/common/Makefile.am b/faad2/src/common/Makefile.am new file mode 100644 index 0000000..dd8b9ca --- /dev/null +++ b/faad2/src/common/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = mp4ff diff --git a/faad2/src/common/faad/aacinfo.c b/faad2/src/common/faad/aacinfo.c new file mode 100644 index 0000000..1cfbab2 --- /dev/null +++ b/faad2/src/common/faad/aacinfo.c @@ -0,0 +1,372 @@ +/* +** FAAD2 - Freeware Advanced Audio (AAC) Decoder including SBR decoding +** Copyright (C) 2003 M. Bakker, Ahead Software AG, http://www.nero.com +** +** This program 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 of the License, or +** (at your option) any later version. +** +** This program 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 this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +** +** Any non-GPL usage of this software or parts of this software is strictly +** forbidden. +** +** Commercial non-GPL licensing of this software is possible. +** For more info contact Ahead Software through Mpeg4AAClicense@nero.com. +** +** $Id: aacinfo.c,v 1.4 2003/07/29 08:20:11 menno Exp $ +**/ + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#endif +#include +#include "filestream.h" +#include "aacinfo.h" + +#define ADIF_MAX_SIZE 30 /* Should be enough */ +#define ADTS_MAX_SIZE 10 /* Should be enough */ + +static int sample_rates[] = {96000,88200,64000,48000,44100,32000,24000,22050,16000,12000,11025,8000}; + +static int read_ADIF_header(FILE_STREAM *file, faadAACInfo *info) +{ + int bitstream; + unsigned char buffer[ADIF_MAX_SIZE]; + int skip_size = 0; + int sf_idx; + + /* Get ADIF header data */ + info->headertype = 1; + + if(read_buffer_filestream(file, buffer, ADIF_MAX_SIZE) < 0) + return -1; + + /* copyright string */ + if(buffer[0] & 0x80) + skip_size += 9; /* skip 9 bytes */ + + bitstream = buffer[0 + skip_size] & 0x10; + info->bitrate = ((unsigned int)(buffer[0 + skip_size] & 0x0F)<<19)| + ((unsigned int)buffer[1 + skip_size]<<11)| + ((unsigned int)buffer[2 + skip_size]<<3)| + ((unsigned int)buffer[3 + skip_size] & 0xE0); + + if (bitstream == 0) + { + info->object_type = ((buffer[6 + skip_size]&0x01)<<1)|((buffer[7 + skip_size]&0x80)>>7); + sf_idx = (buffer[7 + skip_size]&0x78)>>3; + } else { + info->object_type = (buffer[4 + skip_size] & 0x18)>>3; + sf_idx = ((buffer[4 + skip_size] & 0x07)<<1)|((buffer[5 + skip_size] & 0x80)>>7); + } + info->sampling_rate = sample_rates[sf_idx]; + + return 0; +} + +static int read_ADTS_header(FILE_STREAM *file, faadAACInfo *info, + unsigned long **seek_table, int *seek_table_len, + int tagsize, int no_seek_table) +{ + /* Get ADTS header data */ + unsigned char buffer[ADTS_MAX_SIZE]; + int frames, framesinsec=0, t_framelength = 0, frame_length, sr_idx, ID; + int second = 0, pos; + int i; + float frames_per_sec = 0; + unsigned long bytes; + unsigned long *tmp_seek_table = NULL; + + info->headertype = 2; + + /* Read all frames to ensure correct time and bitrate */ + for(frames=0; /* */; frames++, framesinsec++) + { + /* If streaming, only go until we hit 5 seconds worth */ + if(file->http) + { + if(frames >= 43 * 5) + { + break; + } + } + + pos = tell_filestream(file); + + /* 12 bit SYNCWORD */ + bytes = read_buffer_filestream(file, buffer, ADTS_MAX_SIZE); + + if(bytes != ADTS_MAX_SIZE) + { + /* Bail out if no syncword found */ + break; + } + + /* check syncword */ + if (!((buffer[0] == 0xFF)&&((buffer[1] & 0xF6) == 0xF0))) + break; + + if(!frames) + { + /* fixed ADTS header is the same for every frame, so we read it only once */ + /* Syncword found, proceed to read in the fixed ADTS header */ + ID = buffer[1] & 0x08; + info->object_type = (buffer[2]&0xC0)>>6; + sr_idx = (buffer[2]&0x3C)>>2; + info->channels = ((buffer[2]&0x01)<<2)|((buffer[3]&0xC0)>>6); + + frames_per_sec = sample_rates[sr_idx] / 1024.f; + } + + /* ...and the variable ADTS header */ + if (ID == 0) { + info->version = 4; + } else { /* MPEG-2 */ + info->version = 2; + } + frame_length = ((((unsigned int)buffer[3] & 0x3)) << 11) + | (((unsigned int)buffer[4]) << 3) | (buffer[5] >> 5); + + t_framelength += frame_length; + + if(!file->http) + { + if(framesinsec == 43) + framesinsec = 0; + + if(framesinsec == 0 && seek_table_len) + { + tmp_seek_table = (unsigned long *) realloc(tmp_seek_table, (second + 1) * sizeof(unsigned long)); + tmp_seek_table[second] = pos; + } + if(framesinsec == 0) + second++; + } + + /* NOTE: While simply skipping ahead by reading may seem to be more work than seeking, + it is actually much faster, and keeps compatibility with streaming */ + for(i=0; i < frame_length - ADTS_MAX_SIZE; i++) + { + if(read_byte_filestream(file) < 0) + break; + } + } + + if(seek_table_len) + { + *seek_table_len = second; + *seek_table = tmp_seek_table; + } + + info->sampling_rate = sample_rates[sr_idx]; + info->bitrate = (int)(((t_framelength / frames) * (info->sampling_rate/1024.0)) +0.5)*8; + + if(file->http) + { + /* Since we only use 5 seconds of aac data to get a rough bitrate, we must use a different + method of calculating the overall length */ + if(filelength_filestream(file)) + { + info->length = (int)((filelength_filestream(file)/(((info->bitrate*8)/1024)*16))*1000); + } + else + { + /* Since the server didnt tell us how long the file is, + we have no way of determining length */ + info->length = 0; + } + } + else + { + info->length = (int)((float)(frames/frames_per_sec))*1000; + } + + return 0; +} + +int get_AAC_format(char *filename, faadAACInfo *info, + unsigned long **seek_table, int *seek_table_len, + int no_seek_table) +{ + unsigned long tagsize; + FILE_STREAM *file; + char buffer[10]; + unsigned long file_len; + unsigned char adxx_id[5]; + unsigned long tmp; + + memset(info, 0, sizeof(faadAACInfo)); + + file = open_filestream(filename); + + if(file == NULL) + return -1; + + file_len = filelength_filestream(file); + + /* Skip the tag, if it's there */ + tmp = read_buffer_filestream(file, buffer, 10); + + if (StringComp(buffer, "ID3", 3) == 0) + { + unsigned int i; + + /* high bit is not used */ + tagsize = (buffer[6] << 21) | (buffer[7] << 14) | + (buffer[8] << 7) | (buffer[9] << 0); + + for(i=0; i < tagsize; i++) + if(read_byte_filestream(file) < 0) + return -1; + + tagsize += 10; + } + else + { + tagsize = 0; + + /* Simple hack to reset to the beginning */ + file->buffer_offset = 0; + file->file_offset = 0; + } + + if(file_len) + file_len -= tagsize; + + tmp = read_buffer_filestream(file, adxx_id, 2); + //seek_filestream(file, tagsize, FILE_BEGIN); + + adxx_id[5-1] = 0; + info->length = 0; + + /* Determine the header type of the file, check the first two bytes */ + if(StringComp(adxx_id, "AD", 2) == 0) + { + /* We think its an ADIF header, but check the rest just to make sure */ + tmp = read_buffer_filestream(file, adxx_id + 2, 2); + + if(StringComp(adxx_id, "ADIF", 4) == 0) + { + read_ADIF_header(file, info); + } + } + else + { + /* No ADIF, check for ADTS header */ + if ((adxx_id[0] == 0xFF)&&((adxx_id[1] & 0xF6) == 0xF0)) + { + /* ADTS header located */ + /* Since this routine must work for streams, we can't use the seek function to go backwards, thus + we have to use a quick hack as seen below to go back where we need to. */ + + if(file->buffer_offset >= 2) + { + // simple seeking hack, though not really safe, the probability of it causing a problem is low. + file->buffer_offset -= 2; + file->file_offset -= 2; + } + + read_ADTS_header(file, info, seek_table, seek_table_len, tagsize, + no_seek_table); + } + else + { + /* Unknown/headerless AAC file, assume format: */ + info->version = 2; + info->bitrate = 128000; + info->sampling_rate = 44100; + info->channels = 2; + info->headertype = 0; + info->object_type = 1; + } + } + + close_filestream(file); + + return 0; +} + +int StringComp(char const *str1, char const *str2, unsigned long len) +{ + signed int c1 = 0, c2 = 0; + + while (len--) { + c1 = *str1++; + c2 = *str2++; + + if (c1 == 0 || c1 != c2) + break; + } + + return c1 - c2; +} + +#ifdef TEST +/* Program to test aacinfo functionality */ + +#include + +void main(int argc, char *argv[]) +{ + faadAACInfo info; + unsigned long *seek_table = NULL; + int seek_table_len = 0; + char *header, *object; + + if (argc < 2) + { + fprintf(stderr, "USAGE: aacinfo aacfile.aac\n"); + return; + } + + get_AAC_format(argv[1], &info, &seek_table, &seek_table_len, 0); + + fprintf(stdout, "MPEG version: %d\n", info.version); + fprintf(stdout, "channels: %d\n", info.channels); + fprintf(stdout, "sampling_rate: %d\n", info.sampling_rate); + fprintf(stdout, "bitrate: %d\n", info.bitrate); + fprintf(stdout, "length: %.3f\n", (float)info.length/1000.0); + + switch (info.object_type) + { + case 0: + object = "MAIN"; + break; + case 1: + object = "LC"; + break; + case 2: + object = "SSR"; + break; + case 3: + object = "LTP"; + break; + } + fprintf(stdout, "object_type: %s\n", object); + + switch (info.headertype) + { + case 0: + header = "RAW"; + break; + case 1: + header = "ADIF"; + break; + case 2: + header = "ADTS"; + break; + } + fprintf(stdout, "headertype: %s\n", header); +} + +#endif \ No newline at end of file diff --git a/faad2/src/common/faad/aacinfo.h b/faad2/src/common/faad/aacinfo.h new file mode 100644 index 0000000..c0257a8 --- /dev/null +++ b/faad2/src/common/faad/aacinfo.h @@ -0,0 +1,53 @@ +/* +** FAAD2 - Freeware Advanced Audio (AAC) Decoder including SBR decoding +** Copyright (C) 2003 M. Bakker, Ahead Software AG, http://www.nero.com +** +** This program 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 of the License, or +** (at your option) any later version. +** +** This program 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 this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +** +** Any non-GPL usage of this software or parts of this software is strictly +** forbidden. +** +** Commercial non-GPL licensing of this software is possible. +** For more info contact Ahead Software through Mpeg4AAClicense@nero.com. +** +** $Id: aacinfo.h,v 1.3 2003/07/29 08:20:11 menno Exp $ +**/ + +#ifndef AACINFO_H__ +#define AACINFO_H__ + +#include "filestream.h" + +typedef struct { + int version; + int channels; + int sampling_rate; + int bitrate; + int length; + int object_type; + int headertype; +} faadAACInfo; + +int get_AAC_format(char *filename, faadAACInfo *info, + unsigned long **seek_table, int *seek_table_len, + int no_seek_table); + +static int read_ADIF_header(FILE_STREAM *file, faadAACInfo *info); +static int read_ADTS_header(FILE_STREAM *file, faadAACInfo *info, + unsigned long **seek_table, int *seek_table_len, + int tagsize, int no_seek_table); +int StringComp(char const *str1, char const *str2, unsigned long len); + +#endif diff --git a/faad2/src/common/faad/aacinfo.sln b/faad2/src/common/faad/aacinfo.sln new file mode 100644 index 0000000..68a8a36 --- /dev/null +++ b/faad2/src/common/faad/aacinfo.sln @@ -0,0 +1,19 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "aacinfo", "aacinfo.vcproj", "{FE985E4D-79DB-4DD3-BFED-824B4677A161}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {FE985E4D-79DB-4DD3-BFED-824B4677A161}.Debug|Win32.ActiveCfg = Debug|Win32 + {FE985E4D-79DB-4DD3-BFED-824B4677A161}.Debug|Win32.Build.0 = Debug|Win32 + {FE985E4D-79DB-4DD3-BFED-824B4677A161}.Release|Win32.ActiveCfg = Release|Win32 + {FE985E4D-79DB-4DD3-BFED-824B4677A161}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/faad2/src/common/faad/aacinfo.vcproj b/faad2/src/common/faad/aacinfo.vcproj new file mode 100644 index 0000000..bb0984c --- /dev/null +++ b/faad2/src/common/faad/aacinfo.vcproj @@ -0,0 +1,224 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/faad2/src/common/faad/filestream.c b/faad2/src/common/faad/filestream.c new file mode 100644 index 0000000..0f82bdf --- /dev/null +++ b/faad2/src/common/faad/filestream.c @@ -0,0 +1,470 @@ +/* +** FAAD2 - Freeware Advanced Audio (AAC) Decoder including SBR decoding +** Copyright (C) 2003 M. Bakker, Ahead Software AG, http://www.nero.com +** +** This program 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 of the License, or +** (at your option) any later version. +** +** This program 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 this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +** +** Any non-GPL usage of this software or parts of this software is strictly +** forbidden. +** +** Commercial non-GPL licensing of this software is possible. +** For more info contact Ahead Software through Mpeg4AAClicense@nero.com. +** +** $Id: filestream.c,v 1.3 2003/07/29 08:20:11 menno Exp $ +**/ + +/* Not very portable yet */ + +#include // Note: Must be *before* windows.h +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#endif +#include "filestream.h" +#include "aacinfo.h" + +/* TEMPROARY HACK */ +#define CommonExit(A) MessageBox(NULL, A, "FAAD Plugin", MB_OK) + +int winsock_init=0; // 0=winsock not initialized, 1=success +long m_local_buffer_size = 64; +long m_stream_buffer_size = 128; + +FILE_STREAM *open_filestream(char *filename) +{ + FILE_STREAM *fs; + + if(StringComp(filename,"http://", 7) == 0) + { + fs = (FILE_STREAM *)LocalAlloc(LPTR, sizeof(FILE_STREAM) + m_stream_buffer_size * 1024); + + if(fs == NULL) + return NULL; + + fs->data = (unsigned char *)&fs[1]; + + if(http_file_open(filename, fs) < 0) + { + LocalFree(fs); + return NULL; + } + + fs->http = 1; + } + else + { + fs = (FILE_STREAM*)LocalAlloc(LPTR, sizeof(FILE_STREAM) + m_local_buffer_size * 1024); + + if(fs == NULL) + return NULL; + + fs->data = (unsigned char *)&fs[1]; + + fs->stream = CreateFile(filename, GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, 0, + OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, 0); + if (fs->stream == INVALID_HANDLE_VALUE) + { + LocalFree(fs); + return NULL; + } + + fs->http = 0; + } + + fs->buffer_length = 0; + fs->buffer_offset = 0; + fs->file_offset = 0; + + return fs; +} + +int read_byte_filestream(FILE_STREAM *fs) +{ + if(fs->buffer_offset == fs->buffer_length) + { + fs->buffer_offset = 0; + + if(fs->http) + fs->buffer_length = recv(fs->inetStream, fs->data, m_stream_buffer_size * 1024, 0); + else + ReadFile(fs->stream, fs->data, m_local_buffer_size * 1024, &fs->buffer_length, 0); + + if(fs->buffer_length <= 0) + { + if(fs->http) + { + int x; + x = WSAGetLastError(); + + if(x == 0) + { + /* Equivalent of a successful EOF for HTTP */ + } + } + + fs->buffer_length = 0; + return -1; + } + } + + fs->file_offset++; + + return fs->data[fs->buffer_offset++]; +} + +int read_buffer_filestream(FILE_STREAM *fs, void *data, int length) +{ + int i, tmp; + unsigned char *data2 = (unsigned char *)data; + + for(i=0; i < length; i++) + { + if((tmp = read_byte_filestream(fs)) < 0) + { + if(i) + { + break; + } + else + { + return -1; + } + } + data2[i] = tmp; + } + + return i; +} + +unsigned long filelength_filestream(FILE_STREAM *fs) +{ + unsigned long fsize; + + if (fs->http) + { + fsize = fs->http_file_length; + } + else + { + fsize = GetFileSize(fs->stream, NULL); + } + + return fsize; +} + +void seek_filestream(FILE_STREAM *fs, unsigned long offset, int mode) +{ + if(fs->http) + { + return; + } + + SetFilePointer(fs->stream, offset, NULL, mode); + + if(mode == FILE_CURRENT) + fs->file_offset += offset; + else if(mode == FILE_END) + fs->file_offset = filelength_filestream(fs) + offset; + else + fs->file_offset = offset; + + fs->buffer_length = 0; + fs->buffer_offset = 0; +} + +unsigned long tell_filestream(FILE_STREAM *fs) +{ + return fs->file_offset; +} + +void close_filestream(FILE_STREAM *fs) +{ + if(fs) + { + if (fs->http) + { + if (fs->inetStream) + { + /* The 'proper' way to close a TCP connection */ + if(fs->inetStream) + { + CloseTCP(fs->inetStream); + } + } + } + else + { + if(fs->stream) + CloseHandle(fs->stream); + } + + LocalFree(fs); + fs = NULL; + } +} + +int WinsockInit() +{ + /* Before using winsock, you must load the DLL... */ + WSADATA wsaData; + + /* Load version 2.0 */ + if (WSAStartup( MAKEWORD( 2, 0 ), &wsaData )) + { + /* Disable streaming */ + return -1; + } + + winsock_init = 1; + + return 0; +} + +void WinsockDeInit() +{ + /* Unload the DLL */ + + if(winsock_init) + WSACleanup(); +} + +int FindCRLF(char *str) +{ + int i; + + for(i=0; i != lstrlen(str) && str[i] != '\r'; i++); + + return i; +} + +void CloseTCP(int s) +{ + char tempbuf[1024]; + + /* Set the socket to ignore any new incoming data */ + shutdown(s, 1); + + /* Get any old remaining data */ + while(recv(s, tempbuf, 1024, 0) > 0); + + /* Deallocate the socket */ + closesocket(s); +} + +int resolve_host(char *host, SOCKADDR_IN *sck_addr, unsigned short remote_port) +{ + HOSTENT *hp; + + if (isalpha(host[0])) + { + /* server address is a name */ + hp = gethostbyname(host); + } + else + { + unsigned long addr; + /* Convert nnn.nnn address to a usable one */ + addr = inet_addr(host); + hp = gethostbyaddr((char *)&addr, 4, AF_INET); + } + + if (hp == NULL) + { + char tmp[128]; + wsprintf(tmp, "Error resolving host address [%s]!\n", host); + CommonExit(tmp); + return -1; + } + + ZeroMemory(sck_addr, sizeof(SOCKADDR_IN)); + sck_addr->sin_family = AF_INET; + sck_addr->sin_port = htons(remote_port); + CopyMemory(&sck_addr->sin_addr, hp->h_addr, hp->h_length); + + return 0; +} + +int http_file_open(char *url, FILE_STREAM *fs) +{ + SOCKET sck; + SOCKADDR_IN host; + char server[1024], file[1024], request[1024], *temp = NULL, *tmpfile = NULL; + int i, j, port = 80, bytes_recv, http_code; + + /* No winsock, no streaming */ + if(!winsock_init) + { + return -1; + } + + url += 7; // Skip over http:// + + /* Extract data from the URL */ + for(i=0; url[i] != '/' && url[i] != ':' && url[i] != 0; i++); + + ZeroMemory(server, 1024); + CopyMemory(server, url, i); + + if(url[i] == ':') + { + /* A certain port was specified */ + port = atol(url + (i + 1)); + } + + for(; url[i] != '/' && url[i] != 0; i++); + + ZeroMemory(file, 1024); + + CopyMemory(file, url + i, lstrlen(url)); + + /* END OF URL PARSING */ + + /* Create a TCP/IP socket */ + sck = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + + if(sck == INVALID_SOCKET) + { + CommonExit("Error creating TCP/IP new socket"); + return -1; + } + + /* Resolve the host address (turn www.blah.com into an IP) */ + if(resolve_host(server, &host, (unsigned short)port)) + { + CommonExit("Error resolving host address"); + CloseTCP(sck); + return -1; + } + + /* Connect to the server */ + if(connect(sck, (SOCKADDR *)&host, sizeof(SOCKADDR)) == SOCKET_ERROR) + { + CommonExit("Error connecting to remote server"); + CloseTCP(sck); + return -1; + } + + tmpfile = calloc(1, (strlen(file) * 3) + 1); + + /* Encode URL */ + for(i=0, j=0; i < (int)strlen(file); i++) + { + if((unsigned char)file[i] <= 31 || (unsigned char)file[i] >= 127) + { + /* encode ASCII-control characters */ + wsprintf(tmpfile + j, "%%%X", (unsigned char)file[i]); + j += 3; + continue; + } + else + { + switch(file[i]) + { + /* encode characters that could confuse some servers */ + case ' ': + case '"': + case '>': + case '<': + case '#': + case '%': + case '{': + case '}': + case '|': + case '\\': + case '^': + case '~': + case '[': + case ']': + case '`': + + wsprintf(tmpfile + j, "%%%X", (unsigned char)file[i]); + j += 3; + continue; + } + } + + tmpfile[j] = file[i]; + j++; + } + + wsprintf(request, "GET %s\r\n\r\n", tmpfile); + + free(tmpfile); + + /* Send the request */ + if(send(sck, request, lstrlen(request), 0) <= 0) + { + /* Error sending data */ + CloseTCP(sck); + return -1; + } + + ZeroMemory(request, 1024); + + /* Send the request */ + if((bytes_recv = recv(sck, request, 1024, 0)) <= 0) + { + /* Error sending data */ + CloseTCP(sck); + return -1; + } + + if(StringComp(request,"HTTP/1.", 7) != 0) + { + /* Invalid header */ + CloseTCP(sck); + return -1; + } + + http_code = atol(request + 9); + + if(http_code < 200 || http_code > 299) + { + /* HTTP error */ + CloseTCP(sck); + return -1; + } + + // Search for a length field + fs->http_file_length = 0; + + /* Limit search to only 20 loops */ + if((temp = strstr(request, "Content-Length: ")) != NULL) + { + /* Has a content-length field, copy into structure */ + fs->http_file_length = atol(temp + 16); + } + + /* Copy the handle data into the structure */ + fs->inetStream = sck; + + /* Copy any excess data beyond the header into the filestream buffers */ + temp = strstr(request, "\r\n\r\n"); + + if(temp) + { + temp += 4; + } + + if(temp - request < bytes_recv) + { + memcpy(fs->data, temp, (temp - request) - bytes_recv); + fs->buffer_length = (temp - request) - bytes_recv; + fs->buffer_offset = 0; + } + + return 0; +} diff --git a/faad2/src/common/faad/filestream.h b/faad2/src/common/faad/filestream.h new file mode 100644 index 0000000..58e40b9 --- /dev/null +++ b/faad2/src/common/faad/filestream.h @@ -0,0 +1,57 @@ +/* +** FAAD2 - Freeware Advanced Audio (AAC) Decoder including SBR decoding +** Copyright (C) 2003 M. Bakker, Ahead Software AG, http://www.nero.com +** +** This program 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 of the License, or +** (at your option) any later version. +** +** This program 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 this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +** +** Any non-GPL usage of this software or parts of this software is strictly +** forbidden. +** +** Commercial non-GPL licensing of this software is possible. +** For more info contact Ahead Software through Mpeg4AAClicense@nero.com. +** +** $Id: filestream.h,v 1.3 2003/07/29 08:20:11 menno Exp $ +**/ + +#ifndef FILESTREAM_H +#define FILESTREAM_H + +typedef struct { + HANDLE stream; + unsigned short inetStream; + unsigned char *data; + int http; + int buffer_offset; + int buffer_length; + int file_offset; + int http_file_length; +} FILE_STREAM; + +extern long m_local_buffer_size; +extern long m_stream_buffer_size; + +FILE_STREAM *open_filestream(char *filename); +int read_byte_filestream(FILE_STREAM *fs); +int read_buffer_filestream(FILE_STREAM *fs, void *data, int length); +unsigned long filelength_filestream(FILE_STREAM *fs); +void close_filestream(FILE_STREAM *fs); +void seek_filestream(FILE_STREAM *fs, unsigned long offset, int mode); +unsigned long tell_filestream(FILE_STREAM *fs); +int http_file_open(char *url, FILE_STREAM *fs); + +int WinsockInit(); +void WinsockDeInit(); +void CloseTCP(int s); +#endif \ No newline at end of file diff --git a/faad2/src/common/faad/getopt.c b/faad2/src/common/faad/getopt.c new file mode 100644 index 0000000..6c21d73 --- /dev/null +++ b/faad2/src/common/faad/getopt.c @@ -0,0 +1,755 @@ +/* Getopt for GNU. + NOTE: getopt is now part of the C library, so if you don't know what + "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu + before changing it! + + Copyright (C) 1987, 88, 89, 90, 91, 92, 1993 + Free Software Foundation, Inc. + + This program 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. + + This program 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 this program; if not, write to the Free Software + Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifndef __STDC__ +# ifndef const +# define const +# endif +#endif + +/* This tells Alpha OSF/1 not to define a getopt prototype in . */ +#ifndef _NO_PROTO +#define _NO_PROTO +#endif + +#include + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#if defined (_LIBC) || !defined (__GNU_LIBRARY__) || !__MacOSX__ + + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +/* Don't include stdlib.h for non-GNU C libraries because some of them + contain conflicting prototypes for getopt. */ +#include +#endif /* GNU C library. */ + +/* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a + long-named option. Because this is not POSIX.2 compliant, it is + being phased out. */ +/* #define GETOPT_COMPAT */ + +/* This version of `getopt' appears to the caller like standard Unix `getopt' + but it behaves differently for the user, since it allows the user + to intersperse the options with the other arguments. + + As `getopt' works, it permutes the elements of ARGV so that, + when it is done, all the options precede everything else. Thus + all application programs are extended to handle flexible argument order. + + Setting the environment variable POSIXLY_CORRECT disables permutation. + Then the behavior is completely standard. + + GNU application programs can use a third alternative mode in which + they can distinguish the relative order of options and other arguments. */ + +#include "getopt.h" + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +char *optarg = 0; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns EOF, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +/* XXX 1003.2 says this must be 1 before any call. */ +int optind = 0; + +/* The next char to be scanned in the option-element + in which the last option character we returned was found. + This allows us to pick up the scan where we left off. + + If this is zero, or a null string, it means resume the scan + by advancing to the next ARGV-element. */ + +static char *nextchar; + +/* Callers store zero here to inhibit the error message + for unrecognized options. */ + +int opterr = 1; + +/* Set to an option character which was unrecognized. + This must be initialized on some systems to avoid linking in the + system's own getopt implementation. */ + +#define BAD_OPTION '\0' +int optopt = BAD_OPTION; + +/* Describe how to deal with options that follow non-option ARGV-elements. + + If the caller did not specify anything, + the default is REQUIRE_ORDER if the environment variable + POSIXLY_CORRECT is defined, PERMUTE otherwise. + + REQUIRE_ORDER means don't recognize them as options; + stop option processing when the first non-option is seen. + This is what Unix does. + This mode of operation is selected by either setting the environment + variable POSIXLY_CORRECT, or using `+' as the first character + of the list of option characters. + + PERMUTE is the default. We permute the contents of ARGV as we scan, + so that eventually all the non-options are at the end. This allows options + to be given in any order, even with programs that were not written to + expect this. + + RETURN_IN_ORDER is an option available to programs that were written + to expect options and other ARGV-elements in any order and that care about + the ordering of the two. We describe each non-option ARGV-element + as if it were the argument of an option with character code 1. + Using `-' as the first character of the list of option characters + selects this mode of operation. + + The special argument `--' forces an end of option-scanning regardless + of the value of `ordering'. In the case of RETURN_IN_ORDER, only + `--' can cause `getopt' to return EOF with `optind' != ARGC. */ + +static enum +{ + REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER +} ordering; + +#ifdef __GNU_LIBRARY__ +/* We want to avoid inclusion of string.h with non-GNU libraries + because there are many ways it can cause trouble. + On some systems, it contains special magic macros that don't work + in GCC. */ +#include +#define my_index strchr +#define my_strlen strlen +#else + +/* Avoid depending on library functions or files + whose names are inconsistent. */ + +#if __STDC__ || defined(PROTO) +extern char *getenv(const char *name); +extern int strcmp (const char *s1, const char *s2); +extern int strncmp(const char *s1, const char *s2, unsigned int n); + +static int my_strlen(const char *s); +static char *my_index (const char *str, int chr); +#else +extern char *getenv (); +#endif + +static int +my_strlen (str) + const char *str; +{ + int n = 0; + while (*str++) + n++; + return n; +} + +static char * +my_index (str, chr) + const char *str; + int chr; +{ + while (*str) + { + if (*str == chr) + return (char *) str; + str++; + } + return 0; +} + +#endif /* GNU C library. */ + +/* Handle permutation of arguments. */ + +/* Describe the part of ARGV that contains non-options that have + been skipped. `first_nonopt' is the index in ARGV of the first of them; + `last_nonopt' is the index after the last of them. */ + +static int first_nonopt; +static int last_nonopt; + +/* Exchange two adjacent subsequences of ARGV. + One subsequence is elements [first_nonopt,last_nonopt) + which contains all the non-options that have been skipped so far. + The other is elements [last_nonopt,optind), which contains all + the options processed since those non-options were skipped. + + `first_nonopt' and `last_nonopt' are relocated so that they describe + the new indices of the non-options in ARGV after they are moved. + + To perform the swap, we first reverse the order of all elements. So + all options now come before all non options, but they are in the + wrong order. So we put back the options and non options in original + order by reversing them again. For example: + original input: a b c -x -y + reverse all: -y -x c b a + reverse options: -x -y c b a + reverse non options: -x -y a b c +*/ + +#if __STDC__ || defined(PROTO) +static void exchange (char **argv); +#endif + +static void +exchange (argv) + char **argv; +{ + char *temp, **first, **last; + + /* Reverse all the elements [first_nonopt, optind) */ + first = &argv[first_nonopt]; + last = &argv[optind-1]; + while (first < last) { + temp = *first; *first = *last; *last = temp; first++; last--; + } + /* Put back the options in order */ + first = &argv[first_nonopt]; + first_nonopt += (optind - last_nonopt); + last = &argv[first_nonopt - 1]; + while (first < last) { + temp = *first; *first = *last; *last = temp; first++; last--; + } + + /* Put back the non options in order */ + first = &argv[first_nonopt]; + last_nonopt = optind; + last = &argv[last_nonopt-1]; + while (first < last) { + temp = *first; *first = *last; *last = temp; first++; last--; + } +} + +/* Scan elements of ARGV (whose length is ARGC) for option characters + given in OPTSTRING. + + If an element of ARGV starts with '-', and is not exactly "-" or "--", + then it is an option element. The characters of this element + (aside from the initial '-') are option characters. If `getopt' + is called repeatedly, it returns successively each of the option characters + from each of the option elements. + + If `getopt' finds another option character, it returns that character, + updating `optind' and `nextchar' so that the next call to `getopt' can + resume the scan with the following option character or ARGV-element. + + If there are no more option characters, `getopt' returns `EOF'. + Then `optind' is the index in ARGV of the first ARGV-element + that is not an option. (The ARGV-elements have been permuted + so that those that are not options now come last.) + + OPTSTRING is a string containing the legitimate option characters. + If an option character is seen that is not listed in OPTSTRING, + return BAD_OPTION after printing an error message. If you set `opterr' to + zero, the error message is suppressed but we still return BAD_OPTION. + + If a char in OPTSTRING is followed by a colon, that means it wants an arg, + so the following text in the same ARGV-element, or the text of the following + ARGV-element, is returned in `optarg'. Two colons mean an option that + wants an optional arg; if there is text in the current ARGV-element, + it is returned in `optarg', otherwise `optarg' is set to zero. + + If OPTSTRING starts with `-' or `+', it requests different methods of + handling the non-option ARGV-elements. + See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. + + Long-named options begin with `--' instead of `-'. + Their names may be abbreviated as long as the abbreviation is unique + or is an exact match for some defined option. If they have an + argument, it follows the option name in the same ARGV-element, separated + from the option name by a `=', or else the in next ARGV-element. + When `getopt' finds a long-named option, it returns 0 if that option's + `flag' field is nonzero, the value of the option's `val' field + if the `flag' field is zero. + + The elements of ARGV aren't really const, because we permute them. + But we pretend they're const in the prototype to be compatible + with other systems. + + LONGOPTS is a vector of `struct option' terminated by an + element containing a name which is zero. + + LONGIND returns the index in LONGOPT of the long-named option found. + It is only valid when a long-named option has been found by the most + recent call. + + If LONG_ONLY is nonzero, '-' as well as '--' can introduce + long-named options. */ + +int +_getopt_internal (argc, argv, optstring, longopts, longind, long_only) + int argc; + char *const *argv; + const char *optstring; + const struct option *longopts; + int *longind; + int long_only; +{ + int option_index; + + optarg = 0; + + /* Initialize the internal data when the first call is made. + Start processing options with ARGV-element 1 (since ARGV-element 0 + is the program name); the sequence of previously skipped + non-option ARGV-elements is empty. */ + + if (optind == 0) + { + first_nonopt = last_nonopt = optind = 1; + + nextchar = NULL; + + /* Determine how to handle the ordering of options and nonoptions. */ + + if (optstring[0] == '-') + { + ordering = RETURN_IN_ORDER; + ++optstring; + } + else if (optstring[0] == '+') + { + ordering = REQUIRE_ORDER; + ++optstring; + } + else if (getenv ("POSIXLY_CORRECT") != NULL) + ordering = REQUIRE_ORDER; + else + ordering = PERMUTE; + } + + if (nextchar == NULL || *nextchar == '\0') + { + if (ordering == PERMUTE) + { + /* If we have just processed some options following some non-options, + exchange them so that the options come first. */ + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (last_nonopt != optind) + first_nonopt = optind; + + /* Now skip any additional non-options + and extend the range of non-options previously skipped. */ + + while (optind < argc + && (argv[optind][0] != '-' || argv[optind][1] == '\0') +#ifdef GETOPT_COMPAT + && (longopts == NULL + || argv[optind][0] != '+' || argv[optind][1] == '\0') +#endif /* GETOPT_COMPAT */ + ) + optind++; + last_nonopt = optind; + } + + /* Special ARGV-element `--' means premature end of options. + Skip it like a null option, + then exchange with previous non-options as if it were an option, + then skip everything else like a non-option. */ + + if (optind != argc && !strcmp (argv[optind], "--")) + { + optind++; + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (first_nonopt == last_nonopt) + first_nonopt = optind; + last_nonopt = argc; + + optind = argc; + } + + /* If we have done all the ARGV-elements, stop the scan + and back over any non-options that we skipped and permuted. */ + + if (optind == argc) + { + /* Set the next-arg-index to point at the non-options + that we previously skipped, so the caller will digest them. */ + if (first_nonopt != last_nonopt) + optind = first_nonopt; + return EOF; + } + + /* If we have come to a non-option and did not permute it, + either stop the scan or describe it to the caller and pass it by. */ + + if ((argv[optind][0] != '-' || argv[optind][1] == '\0') +#ifdef GETOPT_COMPAT + && (longopts == NULL + || argv[optind][0] != '+' || argv[optind][1] == '\0') +#endif /* GETOPT_COMPAT */ + ) + { + if (ordering == REQUIRE_ORDER) + return EOF; + optarg = argv[optind++]; + return 1; + } + + /* We have found another option-ARGV-element. + Start decoding its characters. */ + + nextchar = (argv[optind] + 1 + + (longopts != NULL && argv[optind][1] == '-')); + } + + if (longopts != NULL + && ((argv[optind][0] == '-' + && (argv[optind][1] == '-' || long_only)) +#ifdef GETOPT_COMPAT + || argv[optind][0] == '+' +#endif /* GETOPT_COMPAT */ + )) + { + const struct option *p; + char *s = nextchar; + int exact = 0; + int ambig = 0; + const struct option *pfound = NULL; + int indfound = 0; + + while (*s && *s != '=') + s++; + + /* Test all options for either exact match or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; + p++, option_index++) + if (!strncmp (p->name, nextchar, s - nextchar)) + { + if (s - nextchar == my_strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else + /* Second nonexact match found. */ + ambig = 1; + } + + if (ambig && !exact) + { + if (opterr) + fprintf (stderr, "%s: option `%s' is ambiguous\n", + argv[0], argv[optind]); + nextchar += my_strlen (nextchar); + optind++; + return BAD_OPTION; + } + + if (pfound != NULL) + { + option_index = indfound; + optind++; + if (*s) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + optarg = s + 1; + else + { + if (opterr) + { + if (argv[optind - 1][1] == '-') + /* --option */ + fprintf (stderr, + "%s: option `--%s' doesn't allow an argument\n", + argv[0], pfound->name); + else + /* +option or -option */ + fprintf (stderr, + "%s: option `%c%s' doesn't allow an argument\n", + argv[0], argv[optind - 1][0], pfound->name); + } + nextchar += my_strlen (nextchar); + return BAD_OPTION; + } + } + else if (pfound->has_arg == 1) + { + if (optind < argc) + optarg = argv[optind++]; + else + { + if (opterr) + fprintf (stderr, "%s: option `%s' requires an argument\n", + argv[0], argv[optind - 1]); + nextchar += my_strlen (nextchar); + return optstring[0] == ':' ? ':' : BAD_OPTION; + } + } + nextchar += my_strlen (nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + /* Can't find it as a long option. If this is not getopt_long_only, + or the option starts with '--' or is not a valid short + option, then it's an error. + Otherwise interpret it as a short option. */ + if (!long_only || argv[optind][1] == '-' +#ifdef GETOPT_COMPAT + || argv[optind][0] == '+' +#endif /* GETOPT_COMPAT */ + || my_index (optstring, *nextchar) == NULL) + { + if (opterr) + { + if (argv[optind][1] == '-') + /* --option */ + fprintf (stderr, "%s: unrecognized option `--%s'\n", + argv[0], nextchar); + else + /* +option or -option */ + fprintf (stderr, "%s: unrecognized option `%c%s'\n", + argv[0], argv[optind][0], nextchar); + } + nextchar = (char *) ""; + optind++; + return BAD_OPTION; + } + } + + /* Look at and handle the next option-character. */ + + { + char c = *nextchar++; + char *temp = my_index (optstring, c); + + /* Increment `optind' when we start to process its last character. */ + if (*nextchar == '\0') + ++optind; + + if (temp == NULL || c == ':') + { + if (opterr) + { +#if 0 + if (c < 040 || c >= 0177) + fprintf (stderr, "%s: unrecognized option, character code 0%o\n", + argv[0], c); + else + fprintf (stderr, "%s: unrecognized option `-%c'\n", argv[0], c); +#else + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c); +#endif + } + optopt = c; + return BAD_OPTION; + } + if (temp[1] == ':') + { + if (temp[2] == ':') + { + /* This is an option that accepts an argument optionally. */ + if (*nextchar != '\0') + { + optarg = nextchar; + optind++; + } + else + optarg = 0; + nextchar = NULL; + } + else + { + /* This is an option that requires an argument. */ + if (*nextchar != '\0') + { + optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + optind++; + } + else if (optind == argc) + { + if (opterr) + { +#if 0 + fprintf (stderr, "%s: option `-%c' requires an argument\n", + argv[0], c); +#else + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, "%s: option requires an argument -- %c\n", + argv[0], c); +#endif + } + optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = BAD_OPTION; + } + else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + optarg = argv[optind++]; + nextchar = NULL; + } + } + return c; + } +} + +int +getopt (argc, argv, optstring) + int argc; + char *const *argv; + const char *optstring; +{ + return _getopt_internal (argc, argv, optstring, + (const struct option *) 0, + (int *) 0, + 0); +} + +int +getopt_long (argc, argv, options, long_options, opt_index) + int argc; + char *const *argv; + const char *options; + const struct option *long_options; + int *opt_index; +{ + return _getopt_internal (argc, argv, options, long_options, opt_index, 0); +} + +#endif /* _LIBC or not __GNU_LIBRARY__. */ + +#ifdef TEST + +/* Compile with -DTEST to make an executable for use in testing + the above definition of `getopt'. */ + +int +main (argc, argv) + int argc; + char **argv; +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + + c = getopt (argc, argv, "abc:d:0123456789"); + if (c == EOF) + break; + + switch (c) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value `%s'\n", optarg); + break; + + case BAD_OPTION: + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ diff --git a/faad2/src/common/faad/getopt.h b/faad2/src/common/faad/getopt.h new file mode 100644 index 0000000..ea03d28 --- /dev/null +++ b/faad2/src/common/faad/getopt.h @@ -0,0 +1,130 @@ +/* Declarations for getopt. + Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc. + + This program 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. + + This program 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 this program; if not, write to the Free Software + Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef _GETOPT_H +#define _GETOPT_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __MacOSX__ + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +extern char *optarg; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns EOF, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +extern int optind; + +/* Callers store zero here to inhibit the error message `getopt' prints + for unrecognized options. */ + +extern int opterr; + +/* Set to an option character which was unrecognized. */ + +extern int optopt; +#endif + +/* Describe the long-named options requested by the application. + The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector + of `struct option' terminated by an element containing a name which is + zero. + + The field `has_arg' is: + no_argument (or 0) if the option does not take an argument, + required_argument (or 1) if the option requires an argument, + optional_argument (or 2) if the option takes an optional argument. + + If the field `flag' is not NULL, it points to a variable that is set + to the value given in the field `val' when the option is found, but + left unchanged if the option is not found. + + To have a long-named option do something other than set an `int' to + a compiled-in constant, such as set a value from `optarg', set the + option's `flag' field to zero and its `val' field to a nonzero + value (the equivalent single-letter option character, if there is + one). For long options that have a zero `flag' field, `getopt' + returns the contents of the `val' field. */ + +struct option +{ +#if __STDC__ + const char *name; +#else + char *name; +#endif + /* has_arg can't be an enum because some compilers complain about + type mismatches in all the code that assumes it is an int. */ + int has_arg; + int *flag; + int val; +}; + +/* Names for the values of the `has_arg' field of `struct option'. */ + +#define no_argument 0 +#define required_argument 1 +#define optional_argument 2 + +//#if __STDC__ || defined(PROTO) +#if defined(__GNU_LIBRARY__) +/* Many other libraries have conflicting prototypes for getopt, with + differences in the consts, in stdlib.h. To avoid compilation + errors, only prototype getopt for the GNU C library. */ +extern int getopt (int argc, char *const *argv, const char *shortopts); +#endif /* not __GNU_LIBRARY__ */ +extern int getopt_long (int argc, char *const *argv, const char *shortopts, + const struct option *longopts, int *longind); +extern int getopt_long_only (int argc, char *const *argv, + const char *shortopts, + const struct option *longopts, int *longind); + +/* Internal only. Users should not call this directly. */ +extern int _getopt_internal (int argc, char *const *argv, + const char *shortopts, + const struct option *longopts, int *longind, + int long_only); +//#else /* not __STDC__ */ +extern int getopt (int argc, char *const *argv, const char *shortopts); +//extern int getopt_long (); +//extern int getopt_long_only (); + +//extern int _getopt_internal (); +//#endif /* not __STDC__ */ + +#ifdef __cplusplus +} +#endif + +#endif /* _GETOPT_H */ diff --git a/faad2/src/common/faad/id3v2tag.c b/faad2/src/common/faad/id3v2tag.c new file mode 100644 index 0000000..ec4af9f --- /dev/null +++ b/faad2/src/common/faad/id3v2tag.c @@ -0,0 +1,1124 @@ +/* +** FAAD2 - Freeware Advanced Audio (AAC) Decoder including SBR decoding +** Copyright (C) 2003 M. Bakker, Ahead Software AG, http://www.nero.com +** +** This program 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 of the License, or +** (at your option) any later version. +** +** This program 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 this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +** +** Any non-GPL usage of this software or parts of this software is strictly +** forbidden. +** +** Commercial non-GPL licensing of this software is possible. +** For more info contact Ahead Software through Mpeg4AAClicense@nero.com. +** +** $Id: id3v2tag.c,v 1.4 2003/07/29 08:20:11 menno Exp $ +**/ + +#define WIN32_LEAN_AND_MEAN +#include +#include +#include + +#include + +#include + +HWND m_hwndList; + +LPSTR ID3Frames[] = +{ + "No known frame", + "Audio encryption", + "Attached picture", + "Comments", + "Commercial frame", + "Encryption method registration", + "Equalization", + "Event timing codes", + "General encapsulated object", + "Group identification registration", + "Involved people list", + "Linked information", + "Music CD identifier", + "MPEG location lookup table", + "Ownership frame", + "Private frame", + "Play counter", + "Popularimeter", + "Position synchronisation frame", + "Recommended buffer size", + "Relative volume adjustment", + "Reverb", + "Synchronized lyric", + "Synchronized tempo codes", + "Album title", + "BPM (beats per minute)", + "Composer", + "Genre", //"Content type", + "Copyright message", + "Date", + "Playlist delay", + "Encoded by", + "Lyricist", + "File type", + "Time", + "Content group description", + "Title", + "Subtitle", + "Initial key", + "Language(s)", + "Length", + "Media type", + "Original album title", + "Original filename", + "Original lyricist(s)", + "Original artist(s)", + "Original release year", + "File owner", + "Lead performer(s)", + "Band/orchestra/accompaniment", + "Conductor/performer refinement", + "Interpreted, remixed, or otherwise modified by", + "Part of a set", + "Publisher", + "Track number", + "Recording dates", + "Internet radio station name", + "Internet radio station owner", + "Size", + "ISRC (international standard recording code)", + "Software/Hardware and settings used for encoding", + "User defined text information", + "Year", + "Unique file identifier", + "Terms of use", + "Unsynchronized lyric", + "Commercial information", + "Copyright/Legal information", + "Official audio file webpage", + "Official artist webpage", + "Official audio source webpage", + "Official internet radio station homepage", + "Payment", + "Official publisher webpage", + "User defined URL link", + "Encrypted meta frame (id3v2.2.x)", + "Compressed meta frame (id3v2.2.1)" +}; + +ID3GENRES ID3Genres[]= +{ + 123, "Acapella", + 34, "Acid", + 74, "Acid Jazz", + 73, "Acid Punk", + 99, "Acoustic", + 20, "Alternative", + 40, "AlternRock", + 26, "Ambient", + 90, "Avantgarde", + 116, "Ballad", + 41, "Bass", + 85, "Bebob", + 96, "Big Band", + 89, "Bluegrass", + 0, "Blues", + 107, "Booty Bass", + 65, "Cabaret", + 88, "Celtic", + 104, "Chamber Music", + 102, "Chanson", + 97, "Chorus", + 61, "Christian Rap", + 1, "Classic Rock", + 32, "Classical", + 112, "Club", + 57, "Comedy", + 2, "Country", + 58, "Cult", + 3, "Dance", + 125, "Dance Hall", + 50, "Darkwave", + 254, "Data", + 22, "Death Metal", + 4, "Disco", + 55, "Dream", + 122, "Drum Solo", + 120, "Duet", + 98, "Easy Listening", + 52, "Electronic", + 48, "Ethnic", + 124, "Euro-House", + 25, "Euro-Techno", + 54, "Eurodance", + 84, "Fast Fusion", + 80, "Folk", + 81, "Folk-Rock", + 115, "Folklore", + 119, "Freestyle", + 5, "Funk", + 30, "Fusion", + 36, "Game", + 59, "Gangsta", + 38, "Gospel", + 49, "Gothic", + 91, "Gothic Rock", + 6, "Grunge", + 79, "Hard Rock", + 7, "Hip-Hop", + 35, "House", + 100, "Humour", + 19, "Industrial", + 33, "Instrumental", + 46, "Instrumental Pop", + 47, "Instrumental Rock", + 8, "Jazz", + 29, "Jazz+Funk", + 63, "Jungle", + 86, "Latin", + 71, "Lo-Fi", + 45, "Meditative", + 9, "Metal", + 77, "Musical", + 82, "National Folk", + 64, "Native American", + 10, "New Age", + 66, "New Wave", + 39, "Noise", + 255, "Not Set", + 11, "Oldies", + 103, "Opera", + 12, "Other", + 75, "Polka", + 13, "Pop", + 62, "Pop/Funk", + 53, "Pop-Folk", + 109, "Porn Groove", + 117, "Power Ballad", + 23, "Pranks", + 108, "Primus", + 92, "Progressive Rock", + 67, "Psychadelic", + 93, "Psychedelic Rock", + 43, "Punk", + 121, "Punk Rock", + 14, "R&B", + 15, "Rap", + 68, "Rave", + 16, "Reggae", + 76, "Retro", + 87, "Revival", + 118, "Rhythmic Soul", + 17, "Rock", + 78, "Rock & Roll", + 114, "Samba", + 110, "Satire", + 69, "Showtunes", + 21, "Ska", + 111, "Slow Jam", + 95, "Slow Rock", + 105, "Sonata", + 42, "Soul", + 37, "Sound Clip", + 24, "Soundtrack", + 56, "Southern Rock", + 44, "Space", + 101, "Speech", + 83, "Swing", + 94, "Symphonic Rock", + 106, "Symphony", + 113, "Tango", + 18, "Techno", + 51, "Techno-Industrial", + 60, "Top 40", + 70, "Trailer", + 31, "Trance", + 72, "Tribal", + 27, "Trip-Hop", + 28, "Vocal" +}; + +const int NUMFRAMES = sizeof(ID3Frames)/sizeof(ID3Frames[0]); +const int NUMGENRES = sizeof(ID3Genres)/sizeof(ID3Genres[0]); + + +LPSTR DupString(LPSTR lpsz) +{ + int cb = lstrlen(lpsz) + 1; + LPSTR lpszNew = LocalAlloc(LMEM_FIXED, cb); + if (lpszNew != NULL) + CopyMemory(lpszNew, lpsz, cb); + return lpszNew; +} + +LPSTR GetFrameDesc(ID3_FrameID id) +{ + return DupString(ID3Frames[id]); +} + +LPSTR GetGenre(LPSTR lpsz) +{ + int id = atoi(lpsz + 1); + int i; + + if ((*(lpsz + 1) > '0') && (*(lpsz + 1) < '9')) + { + for (i = 0; i < NUMGENRES; i++) + { + if (id == ID3Genres[i].id) + return DupString(ID3Genres[i].name); + } + } + return DupString(lpsz); +} + +void FillID3List(HWND hwndDlg, HWND hwndList, char *filename) +{ + ID3Tag *tag; + ID3Frame *frame; + ID3Field *field; + ID3_FrameID eFrameID; + char info[1024]; + int numFrames; + int i; + int iItem = 0; + + + if ((tag = ID3Tag_New()) != NULL) + { + ID3Tag_Link(tag, filename); + + numFrames = ID3Tag_NumFrames(tag); + + for (i = 0; i < numFrames; i++) + { + iItem++; + + frame = ID3Tag_GetFrameNum(tag, i); + eFrameID = ID3Frame_GetID(frame); + + switch (eFrameID) + { + case ID3FID_ALBUM: case ID3FID_BPM: + case ID3FID_COMPOSER: case ID3FID_CONTENTTYPE: + case ID3FID_COPYRIGHT: case ID3FID_DATE: + case ID3FID_PLAYLISTDELAY: case ID3FID_ENCODEDBY: + case ID3FID_LYRICIST: case ID3FID_FILETYPE: + case ID3FID_TIME: case ID3FID_CONTENTGROUP: + case ID3FID_TITLE: case ID3FID_SUBTITLE: + case ID3FID_INITIALKEY: case ID3FID_LANGUAGE: + case ID3FID_SONGLEN: case ID3FID_MEDIATYPE: + case ID3FID_ORIGALBUM: case ID3FID_ORIGFILENAME: + case ID3FID_ORIGLYRICIST: case ID3FID_ORIGARTIST: + case ID3FID_ORIGYEAR: case ID3FID_FILEOWNER: + case ID3FID_LEADARTIST: case ID3FID_BAND: + case ID3FID_CONDUCTOR: case ID3FID_MIXARTIST: + case ID3FID_PARTINSET: case ID3FID_PUBLISHER: + case ID3FID_TRACKNUM: case ID3FID_RECORDINGDATES: + case ID3FID_NETRADIOSTATION: case ID3FID_NETRADIOOWNER: + case ID3FID_SIZE: case ID3FID_ISRC: + case ID3FID_ENCODERSETTINGS: case ID3FID_YEAR: + { + LV_ITEM lvi; + ID3ITEM *pItem = LocalAlloc(LPTR, sizeof(ID3ITEM)); + + /* Initialize LV_ITEM members that are common to all items. */ + lvi.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM | LVIF_STATE; + lvi.state = 0; + lvi.stateMask = 0; + lvi.pszText = LPSTR_TEXTCALLBACK; /* app. maintains text */ + lvi.iImage = 0; + lvi.iItem = iItem; + lvi.iSubItem = 0; + + pItem->frameId = eFrameID; + pItem->aCols[0] = GetFrameDesc(eFrameID); + + field = ID3Frame_GetField(frame, ID3FN_TEXT); + ID3Field_GetASCII(field, info, 1024, 1); + if (eFrameID == ID3FID_CONTENTTYPE) + pItem->aCols[1] = GetGenre(info); + else + pItem->aCols[1] = DupString(info); + + lvi.lParam = (LPARAM)pItem; /* item data */ + + /* Add the item. */ + ListView_InsertItem(hwndList, &lvi); + + break; + } + case ID3FID_USERTEXT: + case ID3FID_COMMENT: /* Can also contain an extra language field (but not used now) */ + case ID3FID_UNSYNCEDLYRICS: /* Can also contain an extra language field (but not used now) */ + { + LV_ITEM lvi; + ID3ITEM *pItem = LocalAlloc(LPTR, sizeof(ID3ITEM)); + + /* Initialize LV_ITEM members that are common to all items. */ + lvi.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM | LVIF_STATE; + lvi.state = 0; + lvi.stateMask = 0; + lvi.pszText = LPSTR_TEXTCALLBACK; /* app. maintains text */ + lvi.iImage = 0; + lvi.iItem = iItem; + lvi.iSubItem = 0; + + pItem->frameId = eFrameID; + + field = ID3Frame_GetField(frame, ID3FN_DESCRIPTION); + ID3Field_GetASCII(field, info, 1024, 1); + pItem->aCols[0] = DupString(info); + + field = ID3Frame_GetField(frame, ID3FN_TEXT); + ID3Field_GetASCII(field, info, 1024, 1); + pItem->aCols[1] = DupString(info); + + lvi.lParam = (LPARAM)pItem; /* item data */ + + /* Add the item. */ + ListView_InsertItem(hwndList, &lvi); + + break; + } + case ID3FID_WWWAUDIOFILE: case ID3FID_WWWARTIST: + case ID3FID_WWWAUDIOSOURCE: case ID3FID_WWWCOMMERCIALINFO: + case ID3FID_WWWCOPYRIGHT: case ID3FID_WWWPUBLISHER: + case ID3FID_WWWPAYMENT: case ID3FID_WWWRADIOPAGE: + { + LV_ITEM lvi; + ID3ITEM *pItem = LocalAlloc(LPTR, sizeof(ID3ITEM)); + + /* Initialize LV_ITEM members that are common to all items. */ + lvi.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM | LVIF_STATE; + lvi.state = 0; + lvi.stateMask = 0; + lvi.pszText = LPSTR_TEXTCALLBACK; /* app. maintains text */ + lvi.iImage = 0; + lvi.iItem = iItem; + lvi.iSubItem = 0; + + pItem->frameId = eFrameID; + + pItem->aCols[0] = GetFrameDesc(eFrameID); + + field = ID3Frame_GetField(frame, ID3FN_URL); + ID3Field_GetASCII(field, info, 1024, 1); + pItem->aCols[1] = DupString(info); + + lvi.lParam = (LPARAM)pItem; /* item data */ + + /* Add the item. */ + ListView_InsertItem(hwndList, &lvi); + + break; + } + case ID3FID_WWWUSER: + { + LV_ITEM lvi; + ID3ITEM *pItem = LocalAlloc(LPTR, sizeof(ID3ITEM)); + + /* Initialize LV_ITEM members that are common to all items. */ + lvi.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM | LVIF_STATE; + lvi.state = 0; + lvi.stateMask = 0; + lvi.pszText = LPSTR_TEXTCALLBACK; /* app. maintains text */ + lvi.iImage = 0; + lvi.iItem = iItem; + lvi.iSubItem = 0; + + pItem->frameId = eFrameID; + + field = ID3Frame_GetField(frame, ID3FN_DESCRIPTION); + ID3Field_GetASCII(field, info, 1024, 1); + pItem->aCols[0] = DupString(info); + + field = ID3Frame_GetField(frame, ID3FN_URL); + ID3Field_GetASCII(field, info, 1024, 1); + pItem->aCols[1] = DupString(info); + + lvi.lParam = (LPARAM)pItem; /* item data */ + + /* Add the item. */ + ListView_InsertItem(hwndList, &lvi); + + break; + } + default: + break; + } + } + ID3Tag_Delete(tag); + } +} + +BOOL CALLBACK AddFrameProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + int i, cursel; + + switch (message) { + case WM_INITDIALOG: + EnableWindow(GetDlgItem(hwndDlg, IDC_COL0), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE); + + /* Note: FRAMEID is the index in the combo box + 1 */ + for (i = 1; i < NUMFRAMES; i++) + { + SendMessage(GetDlgItem(hwndDlg, IDC_FRAMETYPE), CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)ID3Frames[i]); + } + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDC_FRAMETYPE: + if (HIWORD(wParam) == CBN_SELCHANGE) + { + cursel = SendMessage(GetDlgItem(hwndDlg, IDC_FRAMETYPE), CB_GETCURSEL, 0, 0); + + switch (cursel + 1) + { + case ID3FID_ALBUM: case ID3FID_BPM: + case ID3FID_COMPOSER: case ID3FID_COPYRIGHT: + case ID3FID_DATE: case ID3FID_PLAYLISTDELAY: + case ID3FID_ENCODEDBY: case ID3FID_LYRICIST: + case ID3FID_FILETYPE: case ID3FID_TIME: + case ID3FID_CONTENTGROUP: case ID3FID_TITLE: + case ID3FID_SUBTITLE: case ID3FID_INITIALKEY: + case ID3FID_LANGUAGE: case ID3FID_SONGLEN: + case ID3FID_MEDIATYPE: case ID3FID_ORIGALBUM: + case ID3FID_ORIGFILENAME: case ID3FID_ORIGLYRICIST: + case ID3FID_ORIGARTIST: case ID3FID_ORIGYEAR: + case ID3FID_FILEOWNER: case ID3FID_LEADARTIST: + case ID3FID_BAND: case ID3FID_CONDUCTOR: + case ID3FID_MIXARTIST: case ID3FID_PARTINSET: + case ID3FID_PUBLISHER: case ID3FID_TRACKNUM: + case ID3FID_RECORDINGDATES: case ID3FID_NETRADIOSTATION: + case ID3FID_NETRADIOOWNER: case ID3FID_SIZE: + case ID3FID_ISRC: case ID3FID_ENCODERSETTINGS: + case ID3FID_YEAR: case ID3FID_WWWAUDIOFILE: + case ID3FID_WWWARTIST: case ID3FID_WWWAUDIOSOURCE: + case ID3FID_WWWCOMMERCIALINFO: case ID3FID_WWWCOPYRIGHT: + case ID3FID_WWWPUBLISHER: case ID3FID_WWWPAYMENT: + case ID3FID_WWWRADIOPAGE: case ID3FID_CONTENTTYPE: + { + SetDlgItemText(hwndDlg, IDC_COL0, ID3Frames[cursel+1]); + EnableWindow(GetDlgItem(hwndDlg, IDC_COL0), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDOK), TRUE); + break; + } + case ID3FID_USERTEXT: case ID3FID_COMMENT: + case ID3FID_UNSYNCEDLYRICS: case ID3FID_WWWUSER: + { + SetDlgItemText(hwndDlg, IDC_COL0, ID3Frames[cursel+1]); + EnableWindow(GetDlgItem(hwndDlg, IDC_COL0), TRUE); + EnableWindow(GetDlgItem(hwndDlg, IDOK), TRUE); + break; + } + default: + MessageBox(hwndDlg, "Sorry, this frame type cannot be added (yet).", "Sorry", MB_OK); + EnableWindow(GetDlgItem(hwndDlg, IDC_COL0), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE); + break; + } + } + return TRUE; + case IDOK: + { + LV_ITEM lvi; + ID3ITEM *pItem = LocalAlloc(LPTR, sizeof(ID3ITEM)); + char *col0 = LocalAlloc(LPTR, 1024); + char *col1 = LocalAlloc(LPTR, 1024); + + /* Initialize LV_ITEM members that are common to all items. */ + lvi.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM | LVIF_STATE; + lvi.state = 0; + lvi.stateMask = 0; + lvi.pszText = LPSTR_TEXTCALLBACK; /* app. maintains text */ + lvi.iImage = 0; + lvi.iItem = ListView_GetItemCount(m_hwndList) + 1; + lvi.iSubItem = 0; + + cursel = SendMessage(GetDlgItem(hwndDlg, IDC_FRAMETYPE), CB_GETCURSEL, 0, 0); + pItem->frameId = cursel + 1; + GetDlgItemText(hwndDlg, IDC_COL0, col0, 1024); + GetDlgItemText(hwndDlg, IDC_COL1, col1, 1024); + pItem->aCols[0] = col0; + pItem->aCols[1] = col1; + + lvi.lParam = (LPARAM)pItem; /* item data */ + + /* Add the item. */ + ListView_InsertItem(m_hwndList, &lvi); + ListView_Update(m_hwndList, lvi.iItem); + } + case IDCANCEL: + EndDialog(hwndDlg, wParam); + return TRUE; + } + } + return FALSE; +} + +BOOL List_AddFrame(HWND hwndApp, HWND hwndList) +{ + int result; + + m_hwndList = hwndList; + + result = DialogBox(hInstance_for_id3editor, MAKEINTRESOURCE(IDD_ADDFRAME), + hwndApp, AddFrameProc); + + if (LOWORD(result) == IDOK) + return TRUE; + return FALSE; +} + + +void InsertTextFrame(HWND dlg, HWND list, int control, int item, int frame_id) +{ + LV_ITEM lvi; + ID3ITEM *pItem = LocalAlloc(LPTR, sizeof(ID3ITEM)); + + /* Initialize LV_ITEM members that are common to all items. */ + lvi.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM | LVIF_STATE; + lvi.state = 0; + lvi.stateMask = 0; + lvi.pszText = LPSTR_TEXTCALLBACK; /* app. maintains text */ + lvi.iImage = 0; + lvi.iItem = item; + lvi.iSubItem = 0; + + pItem->frameId = frame_id; + pItem->aCols[0] = GetFrameDesc(frame_id); + + pItem->aCols[1] = LocalAlloc(LPTR, 1024); + GetDlgItemText(dlg, control, pItem->aCols[1], 1024); + + lvi.lParam = (LPARAM)pItem; /* item data */ + + /* Add the item. */ + ListView_InsertItem(list, &lvi); +} + +void AddFrameFromRAWData(HWND hwndList, int frameId, LPSTR data1, LPSTR data2) +{ + LV_ITEM lvi; + ID3ITEM *pItem = LocalAlloc(LPTR, sizeof(ID3ITEM)); + int nextItem; + + nextItem = ListView_GetItemCount(hwndList); + + /* Initialize LV_ITEM members that are common to all items. */ + lvi.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM | LVIF_STATE; + lvi.state = 0; + lvi.stateMask = 0; + lvi.pszText = LPSTR_TEXTCALLBACK; /* app. maintains text */ + lvi.iImage = 0; + lvi.iItem = nextItem; + lvi.iSubItem = 0; + + pItem->frameId = frameId; + + pItem->aCols[0] = LocalAlloc(LPTR, 1024); + pItem->aCols[1] = LocalAlloc(LPTR, 1024); + + lstrcpy(pItem->aCols[0], data1); + lstrcpy(pItem->aCols[1], data2); + + lvi.lParam = (LPARAM)pItem; /* item data */ + + /* Add the item. */ + ListView_InsertItem(hwndList, &lvi); +} + +HWND m_hwndDlg; +int changed; + +BOOL CALLBACK AddStandardProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + int added = 0; + + switch (message) { + case WM_INITDIALOG: + changed = 0; + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDOK: + { + if (GetWindowTextLength(GetDlgItem(hwndDlg, IDC_TRACK)) > 0) { + InsertTextFrame(hwndDlg, m_hwndList, IDC_TRACK, ListView_GetItemCount(m_hwndList)+1, ID3FID_TRACKNUM); + added++; + } + + if (GetWindowTextLength(GetDlgItem(hwndDlg, IDC_TITLE)) > 0) { + InsertTextFrame(hwndDlg, m_hwndList, IDC_TITLE, ListView_GetItemCount(m_hwndList)+1, ID3FID_TITLE); + added++; + } + + if (GetWindowTextLength(GetDlgItem(hwndDlg, IDC_ARTIST)) > 0) { + InsertTextFrame(hwndDlg, m_hwndList, IDC_ARTIST, ListView_GetItemCount(m_hwndList)+1, ID3FID_LEADARTIST); + added++; + } + + if (GetWindowTextLength(GetDlgItem(hwndDlg, IDC_ALBUM)) > 0) { + InsertTextFrame(hwndDlg, m_hwndList, IDC_ALBUM, ListView_GetItemCount(m_hwndList)+1, ID3FID_ALBUM); + added++; + } + + if (GetWindowTextLength(GetDlgItem(hwndDlg, IDC_YEAR)) > 0) { + InsertTextFrame(hwndDlg, m_hwndList, IDC_YEAR, ListView_GetItemCount(m_hwndList)+1, ID3FID_YEAR); + added++; + } + + if (GetWindowTextLength(GetDlgItem(hwndDlg, IDC_GENRE)) > 0) { + InsertTextFrame(hwndDlg, m_hwndList, IDC_GENRE, ListView_GetItemCount(m_hwndList)+1, ID3FID_CONTENTTYPE); + added++; + } + + if (GetWindowTextLength(GetDlgItem(hwndDlg, IDC_COMMENT)) > 0) { + InsertTextFrame(hwndDlg, m_hwndList, IDC_COMMENT, ListView_GetItemCount(m_hwndList)+1, ID3FID_COMMENT); + added++; + } + + if (GetWindowTextLength(GetDlgItem(hwndDlg, IDC_COMPOSER)) > 0) { + InsertTextFrame(hwndDlg, m_hwndList, IDC_COMPOSER, ListView_GetItemCount(m_hwndList)+1, ID3FID_COMPOSER); + added++; + } + + if (GetWindowTextLength(GetDlgItem(hwndDlg, IDC_ORIGARTIST)) > 0) { + InsertTextFrame(hwndDlg, m_hwndList, IDC_ORIGARTIST, ListView_GetItemCount(m_hwndList)+1, ID3FID_ORIGARTIST); + added++; + } + + if (GetWindowTextLength(GetDlgItem(hwndDlg, IDC_COPYRIGHT)) > 0) { + InsertTextFrame(hwndDlg, m_hwndList, IDC_COPYRIGHT, ListView_GetItemCount(m_hwndList)+1, ID3FID_COPYRIGHT); + added++; + } + + if (GetWindowTextLength(GetDlgItem(hwndDlg, IDC_URL)) > 0) { + InsertTextFrame(hwndDlg, m_hwndList, IDC_URL, ListView_GetItemCount(m_hwndList)+1, ID3FID_WWWARTIST); + added++; + } + + if (GetWindowTextLength(GetDlgItem(hwndDlg, IDC_ENCBY)) > 0) { + InsertTextFrame(hwndDlg, m_hwndList, IDC_ENCBY, ListView_GetItemCount(m_hwndList)+1, ID3FID_ENCODEDBY); + added++; + } + + if (added > 0) + changed = 1; + } + case IDCANCEL: + EndDialog(hwndDlg, changed); + return TRUE; + } + } + return FALSE; +} + + +BOOL List_AddStandardFrames(HWND hwndApp, HWND hwndList) +{ + int result; + + m_hwndList = hwndList; + m_hwndDlg = hwndApp; + + result = DialogBox(hInstance_for_id3editor, MAKEINTRESOURCE(IDD_ADDSTANDARD), + hwndApp, AddStandardProc); + + return result?TRUE:FALSE; +} + + +/* List_OnGetDispInfo - processes the LVN_GETDISPINFO */ +/* notification message. */ +/* pnmv - value of lParam (points to an LV_DISPINFO structure) */ +void List_OnGetDispInfo(LV_DISPINFO *pnmv) +{ + /* Provide the item or subitem's text, if requested. */ + if (pnmv->item.mask & LVIF_TEXT) { + ID3ITEM *pItem = (ID3ITEM *) (pnmv->item.lParam); + lstrcpy(pnmv->item.pszText, + pItem->aCols[pnmv->item.iSubItem]); + } +} + +ID3ITEM *pItem; +int editItemIndex; + +BOOL CALLBACK EditTextFrameProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + LV_ITEM lvi; + + switch (message) { + case WM_INITDIALOG: + SetDlgItemText(hwndDlg, IDC_TEXTFRAMENAME, pItem->aCols[0]); + SetDlgItemText(hwndDlg, IDC_EDITTEXTFRAME, pItem->aCols[1]); + + switch (pItem->frameId) + { + case ID3FID_ALBUM: case ID3FID_BPM: + case ID3FID_COMPOSER: case ID3FID_COPYRIGHT: + case ID3FID_DATE: case ID3FID_PLAYLISTDELAY: + case ID3FID_ENCODEDBY: case ID3FID_LYRICIST: + case ID3FID_FILETYPE: case ID3FID_TIME: + case ID3FID_CONTENTGROUP: case ID3FID_TITLE: + case ID3FID_SUBTITLE: case ID3FID_INITIALKEY: + case ID3FID_LANGUAGE: case ID3FID_SONGLEN: + case ID3FID_MEDIATYPE: case ID3FID_ORIGALBUM: + case ID3FID_ORIGFILENAME: case ID3FID_ORIGLYRICIST: + case ID3FID_ORIGARTIST: case ID3FID_ORIGYEAR: + case ID3FID_FILEOWNER: case ID3FID_LEADARTIST: + case ID3FID_BAND: case ID3FID_CONDUCTOR: + case ID3FID_MIXARTIST: case ID3FID_PARTINSET: + case ID3FID_PUBLISHER: case ID3FID_TRACKNUM: + case ID3FID_RECORDINGDATES: case ID3FID_NETRADIOSTATION: + case ID3FID_NETRADIOOWNER: case ID3FID_SIZE: + case ID3FID_ISRC: case ID3FID_ENCODERSETTINGS: + case ID3FID_YEAR: case ID3FID_WWWAUDIOFILE: + case ID3FID_WWWARTIST: case ID3FID_WWWAUDIOSOURCE: + case ID3FID_WWWCOMMERCIALINFO: case ID3FID_WWWCOPYRIGHT: + case ID3FID_WWWPUBLISHER: case ID3FID_WWWPAYMENT: + case ID3FID_WWWRADIOPAGE: case ID3FID_CONTENTTYPE: + { + EnableWindow(GetDlgItem(hwndDlg, IDC_TEXTFRAMENAME), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_EDITTEXTFRAME), TRUE); + break; + } + case ID3FID_USERTEXT: case ID3FID_COMMENT: + case ID3FID_UNSYNCEDLYRICS: case ID3FID_WWWUSER: + { + EnableWindow(GetDlgItem(hwndDlg, IDC_TEXTFRAMENAME), TRUE); + EnableWindow(GetDlgItem(hwndDlg, IDC_EDITTEXTFRAME), TRUE); + break; + } + default: + EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_TEXTFRAMENAME), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_EDITTEXTFRAME), FALSE); + break; + } + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDOK: + { + GetDlgItemText(hwndDlg, IDC_TEXTFRAMENAME, pItem->aCols[0], 1024); + GetDlgItemText(hwndDlg, IDC_EDITTEXTFRAME, pItem->aCols[1], 1024); + lvi.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM | LVIF_STATE; + lvi.state = 0; + lvi.stateMask = 0; + lvi.pszText = LPSTR_TEXTCALLBACK; /* app. maintains text */ + lvi.iImage = 0; + lvi.iItem = editItemIndex; + lvi.iSubItem = 0; + lvi.lParam = (LPARAM)pItem; /* item data */ + + /* Add the item. */ + ListView_SetItem(m_hwndList, &lvi); + ListView_Update(m_hwndList, editItemIndex); + } /* Fall through */ + case IDCANCEL: + EndDialog(hwndDlg, wParam); + return TRUE; + } + } + return FALSE; +} + + +/* Double clicking means editing a frame */ +BOOL List_EditData(HWND hwndApp, HWND hwndList) +{ + LV_ITEM lvi; + BOOL result; + + /* First get the selected item */ + int index = ListView_GetNextItem(hwndList, -1, LVNI_SELECTED); + + m_hwndList = hwndList; + + if (index != -1) + { + lvi.mask = LVIF_PARAM; + lvi.iItem = index; + lvi.iSubItem = 0; + + if (ListView_GetItem(hwndList, &lvi) == TRUE) + { + pItem = (ID3ITEM*)lvi.lParam; + editItemIndex = lvi.iItem; + + result = DialogBox(hInstance_for_id3editor, MAKEINTRESOURCE(IDD_EDITTEXTFRAME), + hwndApp, EditTextFrameProc); + if (LOWORD(result) == IDOK) + return TRUE; + } + } + return FALSE; +} + + +/* Delete the selected frame */ +BOOL List_DeleteSelected(HWND hwndApp, HWND hwndList) +{ + int items; + + /* First get the selected item */ + int index = ListView_GetNextItem(hwndList, -1, LVNI_SELECTED); + + if (index != -1) + ListView_DeleteItem(hwndList, index); + + items = ListView_GetItemCount(hwndList); + if (index != -1) return TRUE; + else return FALSE; +} + + +/* Save the ID3 to the file */ +void List_SaveID3(HWND hwndApp, HWND hwndList, char *filename) +{ + LV_ITEM lvi; + ID3ITEM *pItem1; + int i, items; + ID3Tag *tag; + ID3Frame *frame; + ID3Field *field; + + /* Strip the tag first, before completely rewriting it */ + if ((tag = ID3Tag_New()) != NULL) + { + ID3Tag_Link(tag, filename); + ID3Tag_Strip(tag, ID3TT_ALL); + ID3Tag_Clear(tag); + + if (SendMessage(GetDlgItem(hwndApp, IDC_ID3V2TAG), BM_GETCHECK, 0, 0) == BST_UNCHECKED) + { + /* No frames saved */ + ID3Tag_Delete(tag); + EnableWindow(GetDlgItem(hwndApp, IDC_ID3V2TAG), FALSE); + ListView_DeleteAllItems(hwndList); + return; + } + + /* First get the number of items */ + items = ListView_GetItemCount(hwndList); + + if (items > 0) + { + for (i = 0; i < items; i++) + { + lvi.mask = LVIF_PARAM; + lvi.iItem = i; + lvi.iSubItem = 0; + + if (ListView_GetItem(hwndList, &lvi) == TRUE) + { + pItem1 = (ID3ITEM*)lvi.lParam; + + frame = ID3Frame_NewID(pItem1->frameId); + + switch (pItem1->frameId) + { + case ID3FID_ALBUM: case ID3FID_BPM: + case ID3FID_COMPOSER: case ID3FID_CONTENTTYPE: + case ID3FID_COPYRIGHT: case ID3FID_DATE: + case ID3FID_PLAYLISTDELAY: case ID3FID_ENCODEDBY: + case ID3FID_LYRICIST: case ID3FID_FILETYPE: + case ID3FID_TIME: case ID3FID_CONTENTGROUP: + case ID3FID_TITLE: case ID3FID_SUBTITLE: + case ID3FID_INITIALKEY: case ID3FID_LANGUAGE: + case ID3FID_SONGLEN: case ID3FID_MEDIATYPE: + case ID3FID_ORIGALBUM: case ID3FID_ORIGFILENAME: + case ID3FID_ORIGLYRICIST: case ID3FID_ORIGARTIST: + case ID3FID_ORIGYEAR: case ID3FID_FILEOWNER: + case ID3FID_LEADARTIST: case ID3FID_BAND: + case ID3FID_CONDUCTOR: case ID3FID_MIXARTIST: + case ID3FID_PARTINSET: case ID3FID_PUBLISHER: + case ID3FID_TRACKNUM: case ID3FID_RECORDINGDATES: + case ID3FID_NETRADIOSTATION: case ID3FID_NETRADIOOWNER: + case ID3FID_SIZE: case ID3FID_ISRC: + case ID3FID_ENCODERSETTINGS: case ID3FID_YEAR: + { + field = ID3Frame_GetField(frame, ID3FN_TEXT); + ID3Field_SetASCII(field, pItem1->aCols[1]); + ID3Tag_AddFrame(tag, frame); + break; + } + case ID3FID_USERTEXT: + case ID3FID_COMMENT: /* Can also contain an extra language field (but not used now) */ + case ID3FID_UNSYNCEDLYRICS: /* Can also contain an extra language field (but not used now) */ + { + field = ID3Frame_GetField(frame, ID3FN_DESCRIPTION); + ID3Field_SetASCII(field, pItem1->aCols[0]); + field = ID3Frame_GetField(frame, ID3FN_TEXT); + ID3Field_SetASCII(field, pItem1->aCols[1]); + ID3Tag_AddFrame(tag, frame); + break; + } + case ID3FID_WWWAUDIOFILE: case ID3FID_WWWARTIST: + case ID3FID_WWWAUDIOSOURCE: case ID3FID_WWWCOMMERCIALINFO: + case ID3FID_WWWCOPYRIGHT: case ID3FID_WWWPUBLISHER: + case ID3FID_WWWPAYMENT: case ID3FID_WWWRADIOPAGE: + { + field = ID3Frame_GetField(frame, ID3FN_URL); + ID3Field_SetASCII(field, pItem1->aCols[1]); + ID3Tag_AddFrame(tag, frame); + break; + } + case ID3FID_WWWUSER: + { + field = ID3Frame_GetField(frame, ID3FN_DESCRIPTION); + ID3Field_SetASCII(field, pItem1->aCols[0]); + field = ID3Frame_GetField(frame, ID3FN_URL); + ID3Field_SetASCII(field, pItem1->aCols[1]); + ID3Tag_AddFrame(tag, frame); + break; + } + default: + break; + } + } + } + ID3Tag_UpdateByTagType(tag, ID3TT_ID3V2); + } + + ID3Tag_Delete(tag); + } +} + +/* Get the title from the file */ +void GetID3FileTitle(char *filename, char *title, char *format) +{ + ID3Tag *tag; + ID3Frame *frame; + ID3Field *field; + char buffer[255]; + int some_info = 0; + char *in = format; + char *out = title; + char *bound = out + (MAX_PATH - 10 - 1); + + + if ((tag = ID3Tag_New()) != NULL) + { + ID3Tag_Link(tag, filename); + + while (*in && out < bound) + { + switch (*in) { + case '%': + ++in; + break; + + default: + *out++ = *in++; + continue; + } + + /* handle % escape sequence */ + switch (*in++) { + case '0': + if ((frame = ID3Tag_FindFrameWithID(tag, ID3FID_TRACKNUM)) != NULL) { + int size; + field = ID3Frame_GetField(frame, ID3FN_TEXT); + size = ID3Field_GetASCII(field, buffer, 255, 1); + lstrcpy(out, buffer); out += size; + some_info = 1; + } + break; + case '1': + if ((frame = ID3Tag_FindFrameWithID(tag, ID3FID_LEADARTIST)) != NULL) { + int size; + field = ID3Frame_GetField(frame, ID3FN_TEXT); + size = ID3Field_GetASCII(field, buffer, 255, 1); + lstrcpy(out, buffer); out += size; + some_info = 1; + } + break; + case '2': + if ((frame = ID3Tag_FindFrameWithID(tag, ID3FID_TITLE)) != NULL) { + int size; + field = ID3Frame_GetField(frame, ID3FN_TEXT); + size = ID3Field_GetASCII(field, buffer, 255, 1); + lstrcpy(out, buffer); out += size; + some_info = 1; + } + break; + case '3': + if ((frame = ID3Tag_FindFrameWithID(tag, ID3FID_ALBUM)) != NULL) { + int size; + field = ID3Frame_GetField(frame, ID3FN_TEXT); + size = ID3Field_GetASCII(field, buffer, 255, 1); + lstrcpy(out, buffer); out += size; + some_info = 1; + } + break; + case '4': + if ((frame = ID3Tag_FindFrameWithID(tag, ID3FID_YEAR)) != NULL) { + int size; + field = ID3Frame_GetField(frame, ID3FN_TEXT); + size = ID3Field_GetASCII(field, buffer, 255, 1); + lstrcpy(out, buffer); out += size; + some_info = 1; + } + break; + case '5': + if ((frame = ID3Tag_FindFrameWithID(tag, ID3FID_COMMENT)) != NULL) { + int size; + field = ID3Frame_GetField(frame, ID3FN_TEXT); + size = ID3Field_GetASCII(field, buffer, 255, 1); + lstrcpy(out, buffer); out += size; + some_info = 1; + } + break; + case '6': + if ((frame = ID3Tag_FindFrameWithID(tag, ID3FID_CONTENTTYPE)) != NULL) { + int size; char *tmp; + field = ID3Frame_GetField(frame, ID3FN_TEXT); + size = ID3Field_GetASCII(field, buffer, 255, 1); + tmp = GetGenre(buffer); + lstrcpy(out, tmp); out += size; + some_info = 1; + } + break; + case '7': + { + char *p=filename+lstrlen(filename); + int len = 0; + while (*p != '\\' && p >= filename) { p--; len++; } + lstrcpy(out, ++p); out += len; + some_info = 1; + break; + } + } + } + + *out = '\0'; + ID3Tag_Delete(tag); + } + + if (!some_info) + { + char *p=filename+lstrlen(filename); + while (*p != '\\' && p >= filename) p--; + lstrcpy(title,++p); + } +} + diff --git a/faad2/src/common/faad/id3v2tag.h b/faad2/src/common/faad/id3v2tag.h new file mode 100644 index 0000000..041f524 --- /dev/null +++ b/faad2/src/common/faad/id3v2tag.h @@ -0,0 +1,54 @@ +/* +** FAAD2 - Freeware Advanced Audio (AAC) Decoder including SBR decoding +** Copyright (C) 2003 M. Bakker, Ahead Software AG, http://www.nero.com +** +** This program 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 of the License, or +** (at your option) any later version. +** +** This program 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 this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +** +** Any non-GPL usage of this software or parts of this software is strictly +** forbidden. +** +** Commercial non-GPL licensing of this software is possible. +** For more info contact Ahead Software through Mpeg4AAClicense@nero.com. +** +** $Id: id3v2tag.h,v 1.3 2003/07/29 08:20:11 menno Exp $ +**/ + +#ifndef __ID3V2TAG_H__ +#define __ID3V2TAG_H__ + +void GetID3FileTitle(char *filename, char *title, char *format); +void FillID3List(HWND hwndDlg, HWND hwndList, char *filename); +void List_OnGetDispInfo(LV_DISPINFO *pnmv); +BOOL List_EditData(HWND hwndApp, HWND hwndList); +void List_SaveID3(HWND hwndApp, HWND hwndList, char *filename); +BOOL List_DeleteSelected(HWND hwndApp, HWND hwndList); +BOOL List_AddFrame(HWND hwndApp, HWND hwndList); +BOOL List_AddStandardFrames(HWND hwndApp, HWND hwndList); +void AddFrameFromRAWData(HWND hwndList, int frameId, LPSTR data1, LPSTR data2); + +HINSTANCE hInstance_for_id3editor; + +typedef struct ID3GENRES_TAG +{ + BYTE id; + char name[30]; +} ID3GENRES; + +typedef struct id3item_tag { + int frameId; + LPSTR aCols[2]; +} ID3ITEM; + +#endif \ No newline at end of file diff --git a/faad2/src/common/mp4ff/Makefile.am b/faad2/src/common/mp4ff/Makefile.am new file mode 100644 index 0000000..abb8021 --- /dev/null +++ b/faad2/src/common/mp4ff/Makefile.am @@ -0,0 +1,7 @@ +lib_LIBRARIES = libmp4ff.a +include_HEADERS = mp4ff.h mp4ffint.h + +libmp4ff_a_CFLAGS = -DUSE_TAGGING=1 + +libmp4ff_a_SOURCES = mp4ff.c mp4atom.c mp4meta.c mp4sample.c mp4util.c \ + mp4tagupdate.c mp4ff.h mp4ffint.h mp4ff_int_types.h diff --git a/faad2/src/common/mp4ff/mp4atom.c b/faad2/src/common/mp4ff/mp4atom.c new file mode 100644 index 0000000..8acd9b3 --- /dev/null +++ b/faad2/src/common/mp4ff/mp4atom.c @@ -0,0 +1,689 @@ +/* +** FAAD2 - Freeware Advanced Audio (AAC) Decoder including SBR decoding +** Copyright (C) 2003-2005 M. Bakker, Nero AG, http://www.nero.com +** +** This program 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 of the License, or +** (at your option) any later version. +** +** This program 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 this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +** +** Any non-GPL usage of this software or parts of this software is strictly +** forbidden. +** +** The "appropriate copyright message" mentioned in section 2c of the GPLv2 +** must read: "Code from FAAD2 is copyright (c) Nero AG, www.nero.com" +** +** Commercial non-GPL licensing of this software is possible. +** For more info contact Nero AG through Mpeg4AAClicense@nero.com. +** +** $Id: mp4atom.c,v 1.29 2009/01/19 23:56:30 menno Exp $ +**/ + +#include +#ifndef _WIN32 +#include "config.h" +#else +#include +#include +#endif +#ifdef HAVE_GETPWUID +# include +#endif +#ifdef HAVE_STRING_H +# include +#endif +#include "mp4ffint.h" + +#define COPYRIGHT_SYMBOL ((int8_t)0xA9) + +/* parse atom header size */ +static int32_t mp4ff_atom_get_size(const int8_t *data) +{ + uint32_t result; + uint32_t a, b, c, d; + + a = (uint8_t)data[0]; + b = (uint8_t)data[1]; + c = (uint8_t)data[2]; + d = (uint8_t)data[3]; + + result = (a<<24) | (b<<16) | (c<<8) | d; + //if (result > 0 && result < 8) result = 8; + + return (int32_t)result; +} + +/* comnapre 2 atom names, returns 1 for equal, 0 for unequal */ +static int32_t mp4ff_atom_compare(const int8_t a1, const int8_t b1, const int8_t c1, const int8_t d1, + const int8_t a2, const int8_t b2, const int8_t c2, const int8_t d2) +{ + if (a1 == a2 && b1 == b2 && c1 == c2 && d1 == d2) + return 1; + else + return 0; +} + +static uint8_t mp4ff_atom_name_to_type(const int8_t a, const int8_t b, + const int8_t c, const int8_t d) +{ + if (a == 'm') + { + if (mp4ff_atom_compare(a,b,c,d, 'm','o','o','v')) + return ATOM_MOOV; + else if (mp4ff_atom_compare(a,b,c,d, 'm','i','n','f')) + return ATOM_MINF; + else if (mp4ff_atom_compare(a,b,c,d, 'm','d','i','a')) + return ATOM_MDIA; + else if (mp4ff_atom_compare(a,b,c,d, 'm','d','a','t')) + return ATOM_MDAT; + else if (mp4ff_atom_compare(a,b,c,d, 'm','d','h','d')) + return ATOM_MDHD; + else if (mp4ff_atom_compare(a,b,c,d, 'm','v','h','d')) + return ATOM_MVHD; + else if (mp4ff_atom_compare(a,b,c,d, 'm','p','4','a')) + return ATOM_MP4A; + else if (mp4ff_atom_compare(a,b,c,d, 'm','p','4','v')) + return ATOM_MP4V; + else if (mp4ff_atom_compare(a,b,c,d, 'm','p','4','s')) + return ATOM_MP4S; + else if (mp4ff_atom_compare(a,b,c,d, 'm','e','t','a')) + return ATOM_META; + } else if (a == 't') { + if (mp4ff_atom_compare(a,b,c,d, 't','r','a','k')) + return ATOM_TRAK; + else if (mp4ff_atom_compare(a,b,c,d, 't','k','h','d')) + return ATOM_TKHD; + else if (mp4ff_atom_compare(a,b,c,d, 't','r','e','f')) + return ATOM_TREF; + else if (mp4ff_atom_compare(a,b,c,d, 't','r','k','n')) + return ATOM_TRACK; + else if (mp4ff_atom_compare(a,b,c,d, 't','m','p','o')) + return ATOM_TEMPO; + else if (mp4ff_atom_compare(a,b,c,d, 't','v','n','n')) + return ATOM_NETWORK; + else if (mp4ff_atom_compare(a,b,c,d, 't','v','s','h')) + return ATOM_SHOW; + else if (mp4ff_atom_compare(a,b,c,d, 't','v','e','n')) + return ATOM_EPISODENAME; + else if (mp4ff_atom_compare(a,b,c,d, 't','v','s','n')) + return ATOM_SEASON; + else if (mp4ff_atom_compare(a,b,c,d, 't','v','e','s')) + return ATOM_EPISODE; + } else if (a == 's') { + if (mp4ff_atom_compare(a,b,c,d, 's','t','b','l')) + return ATOM_STBL; + else if (mp4ff_atom_compare(a,b,c,d, 's','m','h','d')) + return ATOM_SMHD; + else if (mp4ff_atom_compare(a,b,c,d, 's','t','s','d')) + return ATOM_STSD; + else if (mp4ff_atom_compare(a,b,c,d, 's','t','t','s')) + return ATOM_STTS; + else if (mp4ff_atom_compare(a,b,c,d, 's','t','c','o')) + return ATOM_STCO; + else if (mp4ff_atom_compare(a,b,c,d, 's','t','s','c')) + return ATOM_STSC; + else if (mp4ff_atom_compare(a,b,c,d, 's','t','s','z')) + return ATOM_STSZ; + else if (mp4ff_atom_compare(a,b,c,d, 's','t','z','2')) + return ATOM_STZ2; + else if (mp4ff_atom_compare(a,b,c,d, 's','k','i','p')) + return ATOM_SKIP; + else if (mp4ff_atom_compare(a,b,c,d, 's','i','n','f')) + return ATOM_SINF; + else if (mp4ff_atom_compare(a,b,c,d, 's','c','h','i')) + return ATOM_SCHI; + else if (mp4ff_atom_compare(a,b,c,d, 's','o','n','m')) + return ATOM_SORTTITLE; + else if (mp4ff_atom_compare(a,b,c,d, 's','o','a','l')) + return ATOM_SORTALBUM; + else if (mp4ff_atom_compare(a,b,c,d, 's','o','a','r')) + return ATOM_SORTARTIST; + else if (mp4ff_atom_compare(a,b,c,d, 's','o','a','a')) + return ATOM_SORTALBUMARTIST; + else if (mp4ff_atom_compare(a,b,c,d, 's','o','c','o')) + return ATOM_SORTWRITER; + else if (mp4ff_atom_compare(a,b,c,d, 's','o','s','n')) + return ATOM_SORTSHOW; + } else if (a == COPYRIGHT_SYMBOL) { + if (mp4ff_atom_compare(a,b,c,d, COPYRIGHT_SYMBOL,'n','a','m')) + return ATOM_TITLE; + else if (mp4ff_atom_compare(a,b,c,d, COPYRIGHT_SYMBOL,'A','R','T')) + return ATOM_ARTIST; + else if (mp4ff_atom_compare(a,b,c,d, COPYRIGHT_SYMBOL,'w','r','t')) + return ATOM_WRITER; + else if (mp4ff_atom_compare(a,b,c,d, COPYRIGHT_SYMBOL,'a','l','b')) + return ATOM_ALBUM; + else if (mp4ff_atom_compare(a,b,c,d, COPYRIGHT_SYMBOL,'d','a','y')) + return ATOM_DATE; + else if (mp4ff_atom_compare(a,b,c,d, COPYRIGHT_SYMBOL,'t','o','o')) + return ATOM_TOOL; + else if (mp4ff_atom_compare(a,b,c,d, COPYRIGHT_SYMBOL,'c','m','t')) + return ATOM_COMMENT; + else if (mp4ff_atom_compare(a,b,c,d, COPYRIGHT_SYMBOL,'g','e','n')) + return ATOM_GENRE1; + else if (mp4ff_atom_compare(a,b,c,d, COPYRIGHT_SYMBOL,'g','r','p')) + return ATOM_CONTENTGROUP; + else if (mp4ff_atom_compare(a,b,c,d, COPYRIGHT_SYMBOL,'l','y','r')) + return ATOM_LYRICS; + } + + if (mp4ff_atom_compare(a,b,c,d, 'e','d','t','s')) + return ATOM_EDTS; + else if (mp4ff_atom_compare(a,b,c,d, 'e','s','d','s')) + return ATOM_ESDS; + else if (mp4ff_atom_compare(a,b,c,d, 'f','t','y','p')) + return ATOM_FTYP; + else if (mp4ff_atom_compare(a,b,c,d, 'f','r','e','e')) + return ATOM_FREE; + else if (mp4ff_atom_compare(a,b,c,d, 'h','m','h','d')) + return ATOM_HMHD; + else if (mp4ff_atom_compare(a,b,c,d, 'v','m','h','d')) + return ATOM_VMHD; + else if (mp4ff_atom_compare(a,b,c,d, 'u','d','t','a')) + return ATOM_UDTA; + else if (mp4ff_atom_compare(a,b,c,d, 'i','l','s','t')) + return ATOM_ILST; + else if (mp4ff_atom_compare(a,b,c,d, 'n','a','m','e')) + return ATOM_NAME; + else if (mp4ff_atom_compare(a,b,c,d, 'd','a','t','a')) + return ATOM_DATA; + else if (mp4ff_atom_compare(a,b,c,d, 'd','i','s','k')) + return ATOM_DISC; + else if (mp4ff_atom_compare(a,b,c,d, 'g','n','r','e')) + return ATOM_GENRE2; + else if (mp4ff_atom_compare(a,b,c,d, 'c','o','v','r')) + return ATOM_COVER; + else if (mp4ff_atom_compare(a,b,c,d, 'c','p','i','l')) + return ATOM_COMPILATION; + else if (mp4ff_atom_compare(a,b,c,d, 'c','t','t','s')) + return ATOM_CTTS; + else if (mp4ff_atom_compare(a,b,c,d, 'd','r','m','s')) + return ATOM_DRMS; + else if (mp4ff_atom_compare(a,b,c,d, 'f','r','m','a')) + return ATOM_FRMA; + else if (mp4ff_atom_compare(a,b,c,d, 'p','r','i','v')) + return ATOM_PRIV; + else if (mp4ff_atom_compare(a,b,c,d, 'i','v','i','v')) + return ATOM_IVIV; + else if (mp4ff_atom_compare(a,b,c,d, 'u','s','e','r')) + return ATOM_USER; + else if (mp4ff_atom_compare(a,b,c,d, 'k','e','y',' ')) + return ATOM_KEY; + else if (mp4ff_atom_compare(a,b,c,d, 'a','A','R','T')) + return ATOM_ALBUM_ARTIST; + else if (mp4ff_atom_compare(a,b,c,d, 'd','e','s','c')) + return ATOM_DESCRIPTION; + else if (mp4ff_atom_compare(a,b,c,d, 'p','c','s','t')) + return ATOM_PODCAST; + else + return ATOM_UNKNOWN; +} + +/* read atom header, return atom size, atom size is with header included */ +uint64_t mp4ff_atom_read_header(mp4ff_t *f, uint8_t *atom_type, uint8_t *header_size) +{ + uint64_t size; + int32_t ret; + int8_t atom_header[8]; + + ret = mp4ff_read_data(f, atom_header, 8); + if (ret != 8) + return 0; + + size = mp4ff_atom_get_size(atom_header); + *header_size = 8; + + /* check for 64 bit atom size */ + if (size == 1) + { + *header_size = 16; + size = mp4ff_read_int64(f); + } + + //printf("%c%c%c%c\n", atom_header[4], atom_header[5], atom_header[6], atom_header[7]); + + *atom_type = mp4ff_atom_name_to_type(atom_header[4], atom_header[5], atom_header[6], atom_header[7]); + + return size; +} + +static int32_t mp4ff_read_stsz(mp4ff_t *f) +{ + mp4ff_read_char(f); /* version */ + mp4ff_read_int24(f); /* flags */ + f->track[f->total_tracks - 1]->stsz_sample_size = mp4ff_read_int32(f); + f->track[f->total_tracks - 1]->stsz_sample_count = mp4ff_read_int32(f); + + if (f->track[f->total_tracks - 1]->stsz_sample_size == 0) + { + int32_t i; + f->track[f->total_tracks - 1]->stsz_table = + (int32_t*)malloc(f->track[f->total_tracks - 1]->stsz_sample_count*sizeof(int32_t)); + + for (i = 0; i < f->track[f->total_tracks - 1]->stsz_sample_count; i++) + { + f->track[f->total_tracks - 1]->stsz_table[i] = mp4ff_read_int32(f); + } + } + + return 0; +} + +static int32_t mp4ff_read_esds(mp4ff_t *f) +{ + uint8_t tag; + uint32_t temp; + + mp4ff_read_char(f); /* version */ + mp4ff_read_int24(f); /* flags */ + + /* get and verify ES_DescrTag */ + tag = mp4ff_read_char(f); + if (tag == 0x03) + { + /* read length */ + if (mp4ff_read_mp4_descr_length(f) < 5 + 15) + { + return 1; + } + /* skip 3 bytes */ + mp4ff_read_int24(f); + } else { + /* skip 2 bytes */ + mp4ff_read_int16(f); + } + + /* get and verify DecoderConfigDescrTab */ + if (mp4ff_read_char(f) != 0x04) + { + return 1; + } + + /* read length */ + temp = mp4ff_read_mp4_descr_length(f); + if (temp < 13) return 1; + + f->track[f->total_tracks - 1]->audioType = mp4ff_read_char(f); + mp4ff_read_int32(f);//0x15000414 ???? + f->track[f->total_tracks - 1]->maxBitrate = mp4ff_read_int32(f); + f->track[f->total_tracks - 1]->avgBitrate = mp4ff_read_int32(f); + + /* get and verify DecSpecificInfoTag */ + if (mp4ff_read_char(f) != 0x05) + { + return 1; + } + + /* read length */ + f->track[f->total_tracks - 1]->decoderConfigLen = mp4ff_read_mp4_descr_length(f); + + if (f->track[f->total_tracks - 1]->decoderConfig) + free(f->track[f->total_tracks - 1]->decoderConfig); + f->track[f->total_tracks - 1]->decoderConfig = malloc(f->track[f->total_tracks - 1]->decoderConfigLen); + if (f->track[f->total_tracks - 1]->decoderConfig) + { + mp4ff_read_data(f, f->track[f->total_tracks - 1]->decoderConfig, f->track[f->total_tracks - 1]->decoderConfigLen); + } else { + f->track[f->total_tracks - 1]->decoderConfigLen = 0; + } + + /* will skip the remainder of the atom */ + return 0; +} + +static int32_t mp4ff_read_mp4a(mp4ff_t *f) +{ + uint64_t size; + int32_t i; + uint8_t atom_type = 0; + uint8_t header_size = 0; + + for (i = 0; i < 6; i++) + { + mp4ff_read_char(f); /* reserved */ + } + /* data_reference_index */ mp4ff_read_int16(f); + + mp4ff_read_int32(f); /* reserved */ + mp4ff_read_int32(f); /* reserved */ + + f->track[f->total_tracks - 1]->channelCount = mp4ff_read_int16(f); + f->track[f->total_tracks - 1]->sampleSize = mp4ff_read_int16(f); + + mp4ff_read_int16(f); + mp4ff_read_int16(f); + + f->track[f->total_tracks - 1]->sampleRate = mp4ff_read_int16(f); + + mp4ff_read_int16(f); + + size = mp4ff_atom_read_header(f, &atom_type, &header_size); + if (atom_type == ATOM_ESDS) + { + mp4ff_read_esds(f); + } + + return 0; +} + +static int32_t mp4ff_read_stsd(mp4ff_t *f) +{ + int32_t i; + uint8_t header_size = 0; + + mp4ff_read_char(f); /* version */ + mp4ff_read_int24(f); /* flags */ + + f->track[f->total_tracks - 1]->stsd_entry_count = mp4ff_read_int32(f); + + for (i = 0; i < f->track[f->total_tracks - 1]->stsd_entry_count; i++) + { + uint64_t skip = mp4ff_position(f); + uint64_t size; + uint8_t atom_type = 0; + size = mp4ff_atom_read_header(f, &atom_type, &header_size); + skip += size; + + if (atom_type == ATOM_MP4A) + { + f->track[f->total_tracks - 1]->type = TRACK_AUDIO; + mp4ff_read_mp4a(f); + } else if (atom_type == ATOM_MP4V) { + f->track[f->total_tracks - 1]->type = TRACK_VIDEO; + } else if (atom_type == ATOM_MP4S) { + f->track[f->total_tracks - 1]->type = TRACK_SYSTEM; + } else { + f->track[f->total_tracks - 1]->type = TRACK_UNKNOWN; + } + + mp4ff_set_position(f, skip); + } + + return 0; +} + +static int32_t mp4ff_read_stsc(mp4ff_t *f) +{ + int32_t i; + + mp4ff_read_char(f); /* version */ + mp4ff_read_int24(f); /* flags */ + f->track[f->total_tracks - 1]->stsc_entry_count = mp4ff_read_int32(f); + + f->track[f->total_tracks - 1]->stsc_first_chunk = + (int32_t*)malloc(f->track[f->total_tracks - 1]->stsc_entry_count*sizeof(int32_t)); + f->track[f->total_tracks - 1]->stsc_samples_per_chunk = + (int32_t*)malloc(f->track[f->total_tracks - 1]->stsc_entry_count*sizeof(int32_t)); + f->track[f->total_tracks - 1]->stsc_sample_desc_index = + (int32_t*)malloc(f->track[f->total_tracks - 1]->stsc_entry_count*sizeof(int32_t)); + + for (i = 0; i < f->track[f->total_tracks - 1]->stsc_entry_count; i++) + { + f->track[f->total_tracks - 1]->stsc_first_chunk[i] = mp4ff_read_int32(f); + f->track[f->total_tracks - 1]->stsc_samples_per_chunk[i] = mp4ff_read_int32(f); + f->track[f->total_tracks - 1]->stsc_sample_desc_index[i] = mp4ff_read_int32(f); + } + + return 0; +} + +static int32_t mp4ff_read_stco(mp4ff_t *f) +{ + int32_t i; + + mp4ff_read_char(f); /* version */ + mp4ff_read_int24(f); /* flags */ + f->track[f->total_tracks - 1]->stco_entry_count = mp4ff_read_int32(f); + + f->track[f->total_tracks - 1]->stco_chunk_offset = + (int32_t*)malloc(f->track[f->total_tracks - 1]->stco_entry_count*sizeof(int32_t)); + + for (i = 0; i < f->track[f->total_tracks - 1]->stco_entry_count; i++) + { + f->track[f->total_tracks - 1]->stco_chunk_offset[i] = mp4ff_read_int32(f); + } + + return 0; +} + +static int32_t mp4ff_read_ctts(mp4ff_t *f) +{ + int32_t i; + mp4ff_track_t * p_track = f->track[f->total_tracks - 1]; + + if (p_track->ctts_entry_count) return 0; + + mp4ff_read_char(f); /* version */ + mp4ff_read_int24(f); /* flags */ + p_track->ctts_entry_count = mp4ff_read_int32(f); + + p_track->ctts_sample_count = (int32_t*)malloc(p_track->ctts_entry_count * sizeof(int32_t)); + p_track->ctts_sample_offset = (int32_t*)malloc(p_track->ctts_entry_count * sizeof(int32_t)); + + if (p_track->ctts_sample_count == 0 || p_track->ctts_sample_offset == 0) + { + if (p_track->ctts_sample_count) {free(p_track->ctts_sample_count);p_track->ctts_sample_count=0;} + if (p_track->ctts_sample_offset) {free(p_track->ctts_sample_offset);p_track->ctts_sample_offset=0;} + p_track->ctts_entry_count = 0; + return 0; + } + else + { + for (i = 0; i < f->track[f->total_tracks - 1]->ctts_entry_count; i++) + { + p_track->ctts_sample_count[i] = mp4ff_read_int32(f); + p_track->ctts_sample_offset[i] = mp4ff_read_int32(f); + } + return 1; + } +} + +static int32_t mp4ff_read_stts(mp4ff_t *f) +{ + int32_t i; + mp4ff_track_t * p_track = f->track[f->total_tracks - 1]; + + if (p_track->stts_entry_count) return 0; + + mp4ff_read_char(f); /* version */ + mp4ff_read_int24(f); /* flags */ + p_track->stts_entry_count = mp4ff_read_int32(f); + + p_track->stts_sample_count = (int32_t*)malloc(p_track->stts_entry_count * sizeof(int32_t)); + p_track->stts_sample_delta = (int32_t*)malloc(p_track->stts_entry_count * sizeof(int32_t)); + + if (p_track->stts_sample_count == 0 || p_track->stts_sample_delta == 0) + { + if (p_track->stts_sample_count) {free(p_track->stts_sample_count);p_track->stts_sample_count=0;} + if (p_track->stts_sample_delta) {free(p_track->stts_sample_delta);p_track->stts_sample_delta=0;} + p_track->stts_entry_count = 0; + return 0; + } + else + { + for (i = 0; i < f->track[f->total_tracks - 1]->stts_entry_count; i++) + { + p_track->stts_sample_count[i] = mp4ff_read_int32(f); + p_track->stts_sample_delta[i] = mp4ff_read_int32(f); + } + return 1; + } +} + +static int32_t mp4ff_read_mvhd(mp4ff_t *f) +{ + int32_t i; + + mp4ff_read_char(f); /* version */ + mp4ff_read_int24(f); /* flags */ + /* creation_time */ mp4ff_read_int32(f); + /* modification_time */ mp4ff_read_int32(f); + f->time_scale = mp4ff_read_int32(f); + f->duration = mp4ff_read_int32(f); + /* preferred_rate */ mp4ff_read_int32(f); /*mp4ff_read_fixed32(f);*/ + /* preferred_volume */ mp4ff_read_int16(f); /*mp4ff_read_fixed16(f);*/ + for (i = 0; i < 10; i++) + { + /* reserved */ mp4ff_read_char(f); + } + for (i = 0; i < 9; i++) + { + mp4ff_read_int32(f); /* matrix */ + } + /* preview_time */ mp4ff_read_int32(f); + /* preview_duration */ mp4ff_read_int32(f); + /* poster_time */ mp4ff_read_int32(f); + /* selection_time */ mp4ff_read_int32(f); + /* selection_duration */ mp4ff_read_int32(f); + /* current_time */ mp4ff_read_int32(f); + /* next_track_id */ mp4ff_read_int32(f); + + return 0; +} + +#if 0 +static int32_t mp4ff_read_tkhd(mp4ff_t *f) +{ + uint8_t version; + uint32_t flags; + version = mp4ff_read_char(f); /* version */ + flags = mp4ff_read_int24(f); /* flags */ + if (version==1) + { + mp4ff_read_int64(f);//creation-time + mp4ff_read_int64(f);//modification-time + mp4ff_read_int32(f);//track-id + mp4ff_read_int32(f);//reserved + f->track[f->total_tracks - 1]->duration = mp4ff_read_int64(f);//duration + } + else //version == 0 + { + mp4ff_read_int32(f);//creation-time + mp4ff_read_int32(f);//modification-time + mp4ff_read_int32(f);//track-id + mp4ff_read_int32(f);//reserved + f->track[f->total_tracks - 1]->duration = mp4ff_read_int32(f);//duration + if (f->track[f->total_tracks - 1]->duration == 0xFFFFFFFF) + f->track[f->total_tracks - 1]->duration = 0xFFFFFFFFFFFFFFFF; + + } + mp4ff_read_int32(f);//reserved + mp4ff_read_int32(f);//reserved + mp4ff_read_int16(f);//layer + mp4ff_read_int16(f);//pre-defined + mp4ff_read_int16(f);//volume + mp4ff_read_int16(f);//reserved + + //matrix + mp4ff_read_int32(f); mp4ff_read_int32(f); mp4ff_read_int32(f); + mp4ff_read_int32(f); mp4ff_read_int32(f); mp4ff_read_int32(f); + mp4ff_read_int32(f); mp4ff_read_int32(f); mp4ff_read_int32(f); + mp4ff_read_int32(f);//width + mp4ff_read_int32(f);//height + return 1; +} +#endif + +static int32_t mp4ff_read_mdhd(mp4ff_t *f) +{ + uint32_t version; + + version = mp4ff_read_int32(f); + if (version==1) + { + mp4ff_read_int64(f);//creation-time + mp4ff_read_int64(f);//modification-time + f->track[f->total_tracks - 1]->timeScale = mp4ff_read_int32(f);//timescale + f->track[f->total_tracks - 1]->duration = mp4ff_read_int64(f);//duration + } + else //version == 0 + { + uint32_t temp; + + mp4ff_read_int32(f);//creation-time + mp4ff_read_int32(f);//modification-time + f->track[f->total_tracks - 1]->timeScale = mp4ff_read_int32(f);//timescale + temp = mp4ff_read_int32(f); + f->track[f->total_tracks - 1]->duration = (temp == (uint32_t)(-1)) ? (uint64_t)(-1) : (uint64_t)(temp); + } + mp4ff_read_int16(f); + mp4ff_read_int16(f); + return 1; +} +#ifdef USE_TAGGING +static int32_t mp4ff_read_meta(mp4ff_t *f, const uint64_t size) +{ + uint64_t subsize, sumsize = 0; + uint8_t atom_type; + uint8_t header_size = 0; + + mp4ff_read_char(f); /* version */ + mp4ff_read_int24(f); /* flags */ + + while (sumsize < (size-(header_size+4))) + { + subsize = mp4ff_atom_read_header(f, &atom_type, &header_size); + if (subsize <= header_size+4) + return 1; + if (atom_type == ATOM_ILST) + { + mp4ff_parse_metadata(f, (uint32_t)(subsize-(header_size+4))); + } else { + mp4ff_set_position(f, mp4ff_position(f)+subsize-header_size); + } + sumsize += subsize; + } + + return 0; +} +#endif + +int32_t mp4ff_atom_read(mp4ff_t *f, const int32_t size, const uint8_t atom_type) +{ + uint64_t dest_position = mp4ff_position(f)+size-8; + if (atom_type == ATOM_STSZ) + { + /* sample size box */ + mp4ff_read_stsz(f); + } else if (atom_type == ATOM_STTS) { + /* time to sample box */ + mp4ff_read_stts(f); + } else if (atom_type == ATOM_CTTS) { + /* composition offset box */ + mp4ff_read_ctts(f); + } else if (atom_type == ATOM_STSC) { + /* sample to chunk box */ + mp4ff_read_stsc(f); + } else if (atom_type == ATOM_STCO) { + /* chunk offset box */ + mp4ff_read_stco(f); + } else if (atom_type == ATOM_STSD) { + /* sample description box */ + mp4ff_read_stsd(f); + } else if (atom_type == ATOM_MVHD) { + /* movie header box */ + mp4ff_read_mvhd(f); + } else if (atom_type == ATOM_MDHD) { + /* track header */ + mp4ff_read_mdhd(f); +#ifdef USE_TAGGING + } else if (atom_type == ATOM_META) { + /* iTunes Metadata box */ + mp4ff_read_meta(f, size); +#endif + } + + mp4ff_set_position(f, dest_position); + + + return 0; +} diff --git a/faad2/src/common/mp4ff/mp4ff.c b/faad2/src/common/mp4ff/mp4ff.c new file mode 100644 index 0000000..f513e86 --- /dev/null +++ b/faad2/src/common/mp4ff/mp4ff.c @@ -0,0 +1,475 @@ +/* +** FAAD2 - Freeware Advanced Audio (AAC) Decoder including SBR decoding +** Copyright (C) 2003-2005 M. Bakker, Nero AG, http://www.nero.com +** +** This program 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 of the License, or +** (at your option) any later version. +** +** This program 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 this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +** +** Any non-GPL usage of this software or parts of this software is strictly +** forbidden. +** +** The "appropriate copyright message" mentioned in section 2c of the GPLv2 +** must read: "Code from FAAD2 is copyright (c) Nero AG, www.nero.com" +** +** Commercial non-GPL licensing of this software is possible. +** For more info contact Nero AG through Mpeg4AAClicense@nero.com. +** +** $Id: mp4ff.c,v 1.22 2009/01/26 23:01:40 menno Exp $ +**/ + +#include +#include +#include "mp4ffint.h" + +mp4ff_t *mp4ff_open_read(mp4ff_callback_t *f) +{ + mp4ff_t *ff = malloc(sizeof(mp4ff_t)); + + memset(ff, 0, sizeof(mp4ff_t)); + + ff->stream = f; + + parse_atoms(ff,0); + + return ff; +} + +mp4ff_t *mp4ff_open_read_metaonly(mp4ff_callback_t *f) +{ + mp4ff_t *ff = malloc(sizeof(mp4ff_t)); + + memset(ff, 0, sizeof(mp4ff_t)); + + ff->stream = f; + + parse_atoms(ff,1); + + return ff; +} + +void mp4ff_close(mp4ff_t *ff) +{ + int32_t i; + + for (i = 0; i < ff->total_tracks; i++) + { + if (ff->track[i]) + { + if (ff->track[i]->stsz_table) + free(ff->track[i]->stsz_table); + if (ff->track[i]->stts_sample_count) + free(ff->track[i]->stts_sample_count); + if (ff->track[i]->stts_sample_delta) + free(ff->track[i]->stts_sample_delta); + if (ff->track[i]->stsc_first_chunk) + free(ff->track[i]->stsc_first_chunk); + if (ff->track[i]->stsc_samples_per_chunk) + free(ff->track[i]->stsc_samples_per_chunk); + if (ff->track[i]->stsc_sample_desc_index) + free(ff->track[i]->stsc_sample_desc_index); + if (ff->track[i]->stco_chunk_offset) + free(ff->track[i]->stco_chunk_offset); + if (ff->track[i]->decoderConfig) + free(ff->track[i]->decoderConfig); + if (ff->track[i]->ctts_sample_count) + free(ff->track[i]->ctts_sample_count); + if (ff->track[i]->ctts_sample_offset) + free(ff->track[i]->ctts_sample_offset); +#ifdef ITUNES_DRM + if (ff->track[i]->p_drms) + drms_free(ff->track[i]->p_drms); +#endif + free(ff->track[i]); + } + } + +#ifdef USE_TAGGING + mp4ff_tag_delete(&(ff->tags)); +#endif + + if (ff) free(ff); +} + +void mp4ff_track_add(mp4ff_t *f) +{ + f->total_tracks++; + + f->track[f->total_tracks - 1] = malloc(sizeof(mp4ff_track_t)); + + memset(f->track[f->total_tracks - 1], 0, sizeof(mp4ff_track_t)); +} + +static int need_parse_when_meta_only(uint8_t atom_type) +{ + switch(atom_type) + { + case ATOM_EDTS: +// case ATOM_MDIA: +// case ATOM_MINF: + case ATOM_DRMS: + case ATOM_SINF: + case ATOM_SCHI: +// case ATOM_STBL: +// case ATOM_STSD: + case ATOM_STTS: + case ATOM_STSZ: + case ATOM_STZ2: + case ATOM_STCO: + case ATOM_STSC: +// case ATOM_CTTS: + case ATOM_FRMA: + case ATOM_IVIV: + case ATOM_PRIV: + return 0; + default: + return 1; + } +} + +/* parse atoms that are sub atoms of other atoms */ +int32_t parse_sub_atoms(mp4ff_t *f, const uint64_t total_size,int meta_only) +{ + uint64_t size; + uint8_t atom_type = 0; + uint64_t counted_size = 0; + uint8_t header_size = 0; + + while (counted_size < total_size) + { + size = mp4ff_atom_read_header(f, &atom_type, &header_size); + counted_size += size; + + /* check for end of file */ + if (size == 0) + break; + + /* we're starting to read a new track, update index, + * so that all data and tables get written in the right place + */ + if (atom_type == ATOM_TRAK) + { + mp4ff_track_add(f); + } + + /* parse subatoms */ + if (meta_only && !need_parse_when_meta_only(atom_type)) + { + mp4ff_set_position(f, mp4ff_position(f)+size-header_size); + } else if (atom_type < SUBATOMIC) + { + parse_sub_atoms(f, size-header_size,meta_only); + } else { + mp4ff_atom_read(f, (uint32_t)size, atom_type); + } + } + + return 0; +} + +/* parse root atoms */ +int32_t parse_atoms(mp4ff_t *f,int meta_only) +{ + uint64_t size; + uint8_t atom_type = 0; + uint8_t header_size = 0; + + f->file_size = 0; + + while ((size = mp4ff_atom_read_header(f, &atom_type, &header_size)) != 0) + { + f->file_size += size; + f->last_atom = atom_type; + + if (atom_type == ATOM_MDAT && f->moov_read) + { + /* moov atom is before mdat, we can stop reading when mdat is encountered */ + /* file position will stay at beginning of mdat data */ +// break; + } + + if (atom_type == ATOM_MOOV && size > header_size) + { + f->moov_read = 1; + f->moov_offset = mp4ff_position(f)-header_size; + f->moov_size = size; + } + + /* parse subatoms */ + if (meta_only && !need_parse_when_meta_only(atom_type)) + { + mp4ff_set_position(f, mp4ff_position(f)+size-header_size); + } else if (atom_type < SUBATOMIC) + { + parse_sub_atoms(f, size-header_size,meta_only); + } else { + /* skip this atom */ + mp4ff_set_position(f, mp4ff_position(f)+size-header_size); + } + } + + return 0; +} + +int32_t mp4ff_get_decoder_config(const mp4ff_t *f, const int32_t track, + uint8_t** ppBuf, uint32_t* pBufSize) +{ + if (track >= f->total_tracks) + { + *ppBuf = NULL; + *pBufSize = 0; + return 1; + } + + if (f->track[track]->decoderConfig == NULL || f->track[track]->decoderConfigLen == 0) + { + *ppBuf = NULL; + *pBufSize = 0; + } else { + *ppBuf = malloc(f->track[track]->decoderConfigLen); + if (*ppBuf == NULL) + { + *pBufSize = 0; + return 1; + } + memcpy(*ppBuf, f->track[track]->decoderConfig, f->track[track]->decoderConfigLen); + *pBufSize = f->track[track]->decoderConfigLen; + } + + return 0; +} + +int32_t mp4ff_get_track_type(const mp4ff_t *f, const int track) +{ + return f->track[track]->type; +} + +int32_t mp4ff_total_tracks(const mp4ff_t *f) +{ + return f->total_tracks; +} + +int32_t mp4ff_time_scale(const mp4ff_t *f, const int32_t track) +{ + return f->track[track]->timeScale; +} + +uint32_t mp4ff_get_avg_bitrate(const mp4ff_t *f, const int32_t track) +{ + return f->track[track]->avgBitrate; +} + +uint32_t mp4ff_get_max_bitrate(const mp4ff_t *f, const int32_t track) +{ + return f->track[track]->maxBitrate; +} + +int64_t mp4ff_get_track_duration(const mp4ff_t *f, const int32_t track) +{ + return f->track[track]->duration; +} + +int64_t mp4ff_get_track_duration_use_offsets(const mp4ff_t *f, const int32_t track) +{ + int64_t duration = mp4ff_get_track_duration(f,track); + if (duration!=-1) + { + int64_t offset = mp4ff_get_sample_offset(f,track,0); + if (offset > duration) duration = 0; + else duration -= offset; + } + return duration; +} + + +int32_t mp4ff_num_samples(const mp4ff_t *f, const int32_t track) +{ + int32_t i; + int32_t total = 0; + + for (i = 0; i < f->track[track]->stts_entry_count; i++) + { + total += f->track[track]->stts_sample_count[i]; + } + return total; +} + + + + +uint32_t mp4ff_get_sample_rate(const mp4ff_t *f, const int32_t track) +{ + return f->track[track]->sampleRate; +} + +uint32_t mp4ff_get_channel_count(const mp4ff_t * f,const int32_t track) +{ + return f->track[track]->channelCount; +} + +uint32_t mp4ff_get_audio_type(const mp4ff_t * f,const int32_t track) +{ + return f->track[track]->audioType; +} + +int32_t mp4ff_get_sample_duration_use_offsets(const mp4ff_t *f, const int32_t track, const int32_t sample) +{ + int32_t d,o; + d = mp4ff_get_sample_duration(f,track,sample); + if (d!=-1) + { + o = mp4ff_get_sample_offset(f,track,sample); + if (o>d) d = 0; + else d -= o; + } + return d; +} + +int32_t mp4ff_get_sample_duration(const mp4ff_t *f, const int32_t track, const int32_t sample) +{ + int32_t i, co = 0; + + for (i = 0; i < f->track[track]->stts_entry_count; i++) + { + int32_t delta = f->track[track]->stts_sample_count[i]; + if (sample < co + delta) + return f->track[track]->stts_sample_delta[i]; + co += delta; + } + return (int32_t)(-1); +} + +int64_t mp4ff_get_sample_position(const mp4ff_t *f, const int32_t track, const int32_t sample) +{ + int32_t i, co = 0; + int64_t acc = 0; + + for (i = 0; i < f->track[track]->stts_entry_count; i++) + { + int32_t delta = f->track[track]->stts_sample_count[i]; + if (sample < co + delta) + { + acc += f->track[track]->stts_sample_delta[i] * (sample - co); + return acc; + } + else + { + acc += f->track[track]->stts_sample_delta[i] * delta; + } + co += delta; + } + return (int64_t)(-1); +} + +int32_t mp4ff_get_sample_offset(const mp4ff_t *f, const int32_t track, const int32_t sample) +{ + int32_t i, co = 0; + + for (i = 0; i < f->track[track]->ctts_entry_count; i++) + { + int32_t delta = f->track[track]->ctts_sample_count[i]; + if (sample < co + delta) + return f->track[track]->ctts_sample_offset[i]; + co += delta; + } + return 0; +} + +int32_t mp4ff_find_sample(const mp4ff_t *f, const int32_t track, const int64_t offset,int32_t * toskip) +{ + int32_t i, co = 0; + int64_t offset_total = 0; + mp4ff_track_t * p_track = f->track[track]; + + for (i = 0; i < p_track->stts_entry_count; i++) + { + int32_t sample_count = p_track->stts_sample_count[i]; + int32_t sample_delta = p_track->stts_sample_delta[i]; + int64_t offset_delta = (int64_t)sample_delta * (int64_t)sample_count; + if (offset < offset_total + offset_delta) + { + int64_t offset_fromstts = offset - offset_total; + if (toskip) *toskip = (int32_t)(offset_fromstts % sample_delta); + return co + (int32_t)(offset_fromstts / sample_delta); + } + else + { + offset_total += offset_delta; + } + co += sample_count; + } + return (int32_t)(-1); +} + +int32_t mp4ff_find_sample_use_offsets(const mp4ff_t *f, const int32_t track, const int64_t offset,int32_t * toskip) +{ + return mp4ff_find_sample(f,track,offset + mp4ff_get_sample_offset(f,track,0),toskip); +} + +int32_t mp4ff_read_sample(mp4ff_t *f, const int32_t track, const int32_t sample, + uint8_t **audio_buffer, uint32_t *bytes) +{ + int32_t result = 0; + + *bytes = mp4ff_audio_frame_size(f, track, sample); + + if (*bytes==0) return 0; + + *audio_buffer = (uint8_t*)malloc(*bytes); + + mp4ff_set_sample_position(f, track, sample); + + result = mp4ff_read_data(f, *audio_buffer, *bytes); + + if (!result) + { + free(*audio_buffer); + *audio_buffer = 0; + return 0; + } + +#ifdef ITUNES_DRM + if (f->track[track]->p_drms != NULL) + { + drms_decrypt(f->track[track]->p_drms, (uint32_t*)*audio_buffer, *bytes); + } +#endif + + return *bytes; +} + + +int32_t mp4ff_read_sample_v2(mp4ff_t *f, const int track, const int sample,unsigned char *buffer) +{ + int32_t result = 0; + int32_t size = mp4ff_audio_frame_size(f,track,sample); + if (size<=0) return 0; + mp4ff_set_sample_position(f, track, sample); + result = mp4ff_read_data(f,buffer,size); + +#ifdef ITUNES_DRM + if (f->track[track]->p_drms != NULL) + { + drms_decrypt(f->track[track]->p_drms, (uint32_t*)buffer, size); + } +#endif + + return result; +} + +int32_t mp4ff_read_sample_getsize(mp4ff_t *f, const int track, const int sample) +{ + int32_t temp = mp4ff_audio_frame_size(f, track, sample); + if (temp<0) temp = 0; + return temp; +} diff --git a/faad2/src/common/mp4ff/mp4ff.h b/faad2/src/common/mp4ff/mp4ff.h new file mode 100644 index 0000000..7e68428 --- /dev/null +++ b/faad2/src/common/mp4ff/mp4ff.h @@ -0,0 +1,138 @@ +/* +** FAAD2 - Freeware Advanced Audio (AAC) Decoder including SBR decoding +** Copyright (C) 2003-2005 M. Bakker, Nero AG, http://www.nero.com +** +** This program 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 of the License, or +** (at your option) any later version. +** +** This program 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 this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +** +** Any non-GPL usage of this software or parts of this software is strictly +** forbidden. +** +** The "appropriate copyright message" mentioned in section 2c of the GPLv2 +** must read: "Code from FAAD2 is copyright (c) Nero AG, www.nero.com" +** +** Commercial non-GPL licensing of this software is possible. +** For more info contact Nero AG through Mpeg4AAClicense@nero.com. +** +** $Id: mp4ff.h,v 1.27 2009/01/29 00:41:08 menno Exp $ +**/ + +#ifndef MP4FF_H +#define MP4FF_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#ifdef HAVE_STDINT_H +#include +#else +#include "mp4ff_int_types.h" +#endif + +/* file callback structure */ +typedef struct +{ + uint32_t (*read)(void *user_data, void *buffer, uint32_t length); + uint32_t (*write)(void *udata, void *buffer, uint32_t length); + uint32_t (*seek)(void *user_data, uint64_t position); + uint32_t (*truncate)(void *user_data); + void *user_data; +} mp4ff_callback_t; + +/* mp4 main file structure */ +typedef void* mp4ff_t; + + +/* API */ + +mp4ff_t *mp4ff_open_read(mp4ff_callback_t *f); +mp4ff_t *mp4ff_open_read_metaonly(mp4ff_callback_t *f); +void mp4ff_close(mp4ff_t *f); +int32_t mp4ff_get_sample_duration(const mp4ff_t *f, const int32_t track, const int32_t sample); +int32_t mp4ff_get_sample_duration_use_offsets(const mp4ff_t *f, const int32_t track, const int32_t sample); +int64_t mp4ff_get_sample_position(const mp4ff_t *f, const int32_t track, const int32_t sample); +int32_t mp4ff_get_sample_offset(const mp4ff_t *f, const int32_t track, const int32_t sample); +int32_t mp4ff_find_sample(const mp4ff_t *f, const int32_t track, const int64_t offset,int32_t * toskip); +int32_t mp4ff_find_sample_use_offsets(const mp4ff_t *f, const int32_t track, const int64_t offset,int32_t * toskip); + +int32_t mp4ff_read_sample(mp4ff_t *f, const int track, const int sample, + unsigned char **audio_buffer, unsigned int *bytes); + +int32_t mp4ff_read_sample_v2(mp4ff_t *f, const int track, const int sample,unsigned char *buffer);//returns 0 on error, number of bytes read on success, use mp4ff_read_sample_getsize() to check buffer size needed +int32_t mp4ff_read_sample_getsize(mp4ff_t *f, const int track, const int sample);//returns 0 on error, buffer size needed for mp4ff_read_sample_v2() on success + + + +int32_t mp4ff_get_decoder_config(const mp4ff_t *f, const int track, + unsigned char** ppBuf, unsigned int* pBufSize); +int32_t mp4ff_get_track_type(const mp4ff_t *f, const int track); +int32_t mp4ff_total_tracks(const mp4ff_t *f); +int32_t mp4ff_num_samples(const mp4ff_t *f, const int track); +int32_t mp4ff_time_scale(const mp4ff_t *f, const int track); + +uint32_t mp4ff_get_avg_bitrate(const mp4ff_t *f, const int32_t track); +uint32_t mp4ff_get_max_bitrate(const mp4ff_t *f, const int32_t track); +int64_t mp4ff_get_track_duration(const mp4ff_t *f, const int32_t track); //returns (-1) if unknown +int64_t mp4ff_get_track_duration_use_offsets(const mp4ff_t *f, const int32_t track); //returns (-1) if unknown +uint32_t mp4ff_get_sample_rate(const mp4ff_t *f, const int32_t track); +uint32_t mp4ff_get_channel_count(const mp4ff_t * f,const int32_t track); +uint32_t mp4ff_get_audio_type(const mp4ff_t * f,const int32_t track); + + +/* metadata */ +int mp4ff_meta_get_num_items(const mp4ff_t *f); +int mp4ff_meta_get_by_index(const mp4ff_t *f, unsigned int index, + char **item, char **value); +int mp4ff_meta_get_title(const mp4ff_t *f, char **value); +int mp4ff_meta_get_artist(const mp4ff_t *f, char **value); +int mp4ff_meta_get_writer(const mp4ff_t *f, char **value); +int mp4ff_meta_get_album(const mp4ff_t *f, char **value); +int mp4ff_meta_get_date(const mp4ff_t *f, char **value); +int mp4ff_meta_get_tool(const mp4ff_t *f, char **value); +int mp4ff_meta_get_comment(const mp4ff_t *f, char **value); +int mp4ff_meta_get_genre(const mp4ff_t *f, char **value); +int mp4ff_meta_get_track(const mp4ff_t *f, char **value); +int mp4ff_meta_get_disc(const mp4ff_t *f, char **value); +int mp4ff_meta_get_totaltracks(const mp4ff_t *f, char **value); +int mp4ff_meta_get_totaldiscs(const mp4ff_t *f, char **value); +int mp4ff_meta_get_compilation(const mp4ff_t *f, char **value); +int mp4ff_meta_get_tempo(const mp4ff_t *f, char **value); +int32_t mp4ff_meta_get_coverart(const mp4ff_t *f, char **value); +#ifdef USE_TAGGING + +/* metadata tag structure */ +typedef struct +{ + char *item; + char *value; +} mp4ff_tag_t; + +/* metadata list structure */ +typedef struct +{ + mp4ff_tag_t *tags; + uint32_t count; +} mp4ff_metadata_t; + +int32_t mp4ff_meta_update(mp4ff_callback_t *f,const mp4ff_metadata_t * data); + +#endif + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/faad2/src/common/mp4ff/mp4ff.vcproj b/faad2/src/common/mp4ff/mp4ff.vcproj new file mode 100644 index 0000000..db1e8d1 --- /dev/null +++ b/faad2/src/common/mp4ff/mp4ff.vcproj @@ -0,0 +1,326 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/faad2/src/common/mp4ff/mp4ff_int_types.h b/faad2/src/common/mp4ff/mp4ff_int_types.h new file mode 100644 index 0000000..3d3089c --- /dev/null +++ b/faad2/src/common/mp4ff/mp4ff_int_types.h @@ -0,0 +1,27 @@ +#ifndef _MP4FF_INT_TYPES_H_ +#define _MP4FF_INT_TYPES_H_ + +#if defined (_WIN32) + +#ifdef __MINGW32__ +#include +#endif /* #ifdef __MINGW32__ */ + +typedef signed char int8_t; +typedef unsigned char uint8_t; +typedef signed short int16_t; +typedef unsigned short uint16_t; +typedef signed long int32_t; +typedef unsigned long uint32_t; + +typedef signed __int64 int64_t; +typedef unsigned __int64 uint64_t; + +#else + +#include + +#endif + + +#endif diff --git a/faad2/src/common/mp4ff/mp4ffint.h b/faad2/src/common/mp4ff/mp4ffint.h new file mode 100644 index 0000000..8052d43 --- /dev/null +++ b/faad2/src/common/mp4ff/mp4ffint.h @@ -0,0 +1,344 @@ +/* +** FAAD2 - Freeware Advanced Audio (AAC) Decoder including SBR decoding +** Copyright (C) 2003-2005 M. Bakker, Nero AG, http://www.nero.com +** +** This program 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 of the License, or +** (at your option) any later version. +** +** This program 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 this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +** +** Any non-GPL usage of this software or parts of this software is strictly +** forbidden. +** +** The "appropriate copyright message" mentioned in section 2c of the GPLv2 +** must read: "Code from FAAD2 is copyright (c) Nero AG, www.nero.com" +** +** Commercial non-GPL licensing of this software is possible. +** For more info contact Nero AG through Mpeg4AAClicense@nero.com. +** +** $Id: mp4ffint.h,v 1.26 2009/01/25 20:14:34 menno Exp $ +**/ + +#ifndef MP4FF_INTERNAL_H +#define MP4FF_INTERNAL_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include "mp4ff_int_types.h" +#include + +#define MAX_TRACKS 1024 +#define TRACK_UNKNOWN 0 +#define TRACK_AUDIO 1 +#define TRACK_VIDEO 2 +#define TRACK_SYSTEM 3 + + +#define SUBATOMIC 128 + +/* atoms without subatoms */ +#define ATOM_FTYP 129 +#define ATOM_MDAT 130 +#define ATOM_MVHD 131 +#define ATOM_TKHD 132 +#define ATOM_TREF 133 +#define ATOM_MDHD 134 +#define ATOM_VMHD 135 +#define ATOM_SMHD 136 +#define ATOM_HMHD 137 +#define ATOM_STSD 138 +#define ATOM_STTS 139 +#define ATOM_STSZ 140 +#define ATOM_STZ2 141 +#define ATOM_STCO 142 +#define ATOM_STSC 143 +#define ATOM_MP4A 144 +#define ATOM_MP4V 145 +#define ATOM_MP4S 146 +#define ATOM_ESDS 147 +#define ATOM_META 148 /* iTunes Metadata box */ +#define ATOM_NAME 149 /* iTunes Metadata name box */ +#define ATOM_DATA 150 /* iTunes Metadata data box */ +#define ATOM_CTTS 151 +#define ATOM_FRMA 152 +#define ATOM_IVIV 153 +#define ATOM_PRIV 154 +#define ATOM_USER 155 +#define ATOM_KEY 156 + +#define ATOM_ALBUM_ARTIST 157 +#define ATOM_CONTENTGROUP 158 +#define ATOM_LYRICS 159 +#define ATOM_DESCRIPTION 160 +#define ATOM_NETWORK 161 +#define ATOM_SHOW 162 +#define ATOM_EPISODENAME 163 +#define ATOM_SORTTITLE 164 +#define ATOM_SORTALBUM 165 +#define ATOM_SORTARTIST 166 +#define ATOM_SORTALBUMARTIST 167 +#define ATOM_SORTWRITER 168 +#define ATOM_SORTSHOW 169 +#define ATOM_SEASON 170 +#define ATOM_EPISODE 171 +#define ATOM_PODCAST 172 + +#define ATOM_UNKNOWN 255 +#define ATOM_FREE ATOM_UNKNOWN +#define ATOM_SKIP ATOM_UNKNOWN + +/* atoms with subatoms */ +#define ATOM_MOOV 1 +#define ATOM_TRAK 2 +#define ATOM_EDTS 3 +#define ATOM_MDIA 4 +#define ATOM_MINF 5 +#define ATOM_STBL 6 +#define ATOM_UDTA 7 +#define ATOM_ILST 8 /* iTunes Metadata list */ +#define ATOM_TITLE 9 +#define ATOM_ARTIST 10 +#define ATOM_WRITER 11 +#define ATOM_ALBUM 12 +#define ATOM_DATE 13 +#define ATOM_TOOL 14 +#define ATOM_COMMENT 15 +#define ATOM_GENRE1 16 +#define ATOM_TRACK 17 +#define ATOM_DISC 18 +#define ATOM_COMPILATION 19 +#define ATOM_GENRE2 20 +#define ATOM_TEMPO 21 +#define ATOM_COVER 22 +#define ATOM_DRMS 23 +#define ATOM_SINF 24 +#define ATOM_SCHI 25 + +#ifdef HAVE_CONFIG_H +#include "../../config.h" +#endif + +#if !(defined(_WIN32) || defined(_WIN32_WCE)) +#define stricmp strcasecmp +#else +#define stricmp _stricmp +#define strdup _strdup +#endif + +/* file callback structure */ +typedef struct +{ + uint32_t (*read)(void *user_data, void *buffer, uint32_t length); + uint32_t (*write)(void *udata, void *buffer, uint32_t length); + uint32_t (*seek)(void *user_data, uint64_t position); + uint32_t (*truncate)(void *user_data); + void *user_data; +} mp4ff_callback_t; + + +/* metadata tag structure */ +typedef struct +{ + char *item; + char *value; +} mp4ff_tag_t; + +/* metadata list structure */ +typedef struct +{ + mp4ff_tag_t *tags; + uint32_t count; +} mp4ff_metadata_t; + + +typedef struct +{ + int32_t type; + int32_t channelCount; + int32_t sampleSize; + uint16_t sampleRate; + int32_t audioType; + + /* stsd */ + int32_t stsd_entry_count; + + /* stsz */ + int32_t stsz_sample_size; + int32_t stsz_sample_count; + int32_t *stsz_table; + + /* stts */ + int32_t stts_entry_count; + int32_t *stts_sample_count; + int32_t *stts_sample_delta; + + /* stsc */ + int32_t stsc_entry_count; + int32_t *stsc_first_chunk; + int32_t *stsc_samples_per_chunk; + int32_t *stsc_sample_desc_index; + + /* stsc */ + int32_t stco_entry_count; + int32_t *stco_chunk_offset; + + /* ctts */ + int32_t ctts_entry_count; + int32_t *ctts_sample_count; + int32_t *ctts_sample_offset; + + /* esde */ + uint8_t *decoderConfig; + int32_t decoderConfigLen; + + uint32_t maxBitrate; + uint32_t avgBitrate; + + uint32_t timeScale; + uint64_t duration; + +} mp4ff_track_t; + +/* mp4 main file structure */ +typedef struct +{ + /* stream to read from */ + mp4ff_callback_t *stream; + int64_t current_position; + + int32_t moov_read; + uint64_t moov_offset; + uint64_t moov_size; + uint8_t last_atom; + uint64_t file_size; + + /* mvhd */ + int32_t time_scale; + int32_t duration; + + /* incremental track index while reading the file */ + int32_t total_tracks; + + /* track data */ + mp4ff_track_t *track[MAX_TRACKS]; + + /* metadata */ + mp4ff_metadata_t tags; +} mp4ff_t; + + + + +/* mp4util.c */ +int32_t mp4ff_read_data(mp4ff_t *f, int8_t *data, uint32_t size); +int32_t mp4ff_write_data(mp4ff_t *f, int8_t *data, uint32_t size); +uint64_t mp4ff_read_int64(mp4ff_t *f); +uint32_t mp4ff_read_int32(mp4ff_t *f); +uint32_t mp4ff_read_int24(mp4ff_t *f); +uint16_t mp4ff_read_int16(mp4ff_t *f); +uint8_t mp4ff_read_char(mp4ff_t *f); +int32_t mp4ff_write_int32(mp4ff_t *f,const uint32_t data); +uint32_t mp4ff_read_mp4_descr_length(mp4ff_t *f); +int64_t mp4ff_position(const mp4ff_t *f); +int32_t mp4ff_set_position(mp4ff_t *f, const int64_t position); +int32_t mp4ff_truncate(mp4ff_t * f); +char * mp4ff_read_string(mp4ff_t * f,uint32_t length); + +/* mp4atom.c */ +static int32_t mp4ff_atom_get_size(const int8_t *data); +static int32_t mp4ff_atom_compare(const int8_t a1, const int8_t b1, const int8_t c1, const int8_t d1, + const int8_t a2, const int8_t b2, const int8_t c2, const int8_t d2); +static uint8_t mp4ff_atom_name_to_type(const int8_t a, const int8_t b, const int8_t c, const int8_t d); +uint64_t mp4ff_atom_read_header(mp4ff_t *f, uint8_t *atom_type, uint8_t *header_size); +static int32_t mp4ff_read_stsz(mp4ff_t *f); +static int32_t mp4ff_read_esds(mp4ff_t *f); +static int32_t mp4ff_read_mp4a(mp4ff_t *f); +static int32_t mp4ff_read_stsd(mp4ff_t *f); +static int32_t mp4ff_read_stsc(mp4ff_t *f); +static int32_t mp4ff_read_stco(mp4ff_t *f); +static int32_t mp4ff_read_stts(mp4ff_t *f); +#ifdef USE_TAGGING +static int32_t mp4ff_read_meta(mp4ff_t *f, const uint64_t size); +#endif +int32_t mp4ff_atom_read(mp4ff_t *f, const int32_t size, const uint8_t atom_type); + +/* mp4sample.c */ +static int32_t mp4ff_chunk_of_sample(const mp4ff_t *f, const int32_t track, const int32_t sample, + int32_t *chunk_sample, int32_t *chunk); +static int32_t mp4ff_chunk_to_offset(const mp4ff_t *f, const int32_t track, const int32_t chunk); +static int32_t mp4ff_sample_range_size(const mp4ff_t *f, const int32_t track, + const int32_t chunk_sample, const int32_t sample); +static int32_t mp4ff_sample_to_offset(const mp4ff_t *f, const int32_t track, const int32_t sample); +int32_t mp4ff_audio_frame_size(const mp4ff_t *f, const int32_t track, const int32_t sample); +int32_t mp4ff_set_sample_position(mp4ff_t *f, const int32_t track, const int32_t sample); + +#ifdef USE_TAGGING +/* mp4meta.c */ +static int32_t mp4ff_tag_add_field(mp4ff_metadata_t *tags, const char *item, const char *value); +static int32_t mp4ff_tag_set_field(mp4ff_metadata_t *tags, const char *item, const char *value); +static int32_t mp4ff_set_metadata_name(mp4ff_t *f, const uint8_t atom_type, char **name); +static int32_t mp4ff_parse_tag(mp4ff_t *f, const uint8_t parent_atom_type, const int32_t size); +static int32_t mp4ff_meta_find_by_name(const mp4ff_t *f, const char *item, char **value); +int32_t mp4ff_parse_metadata(mp4ff_t *f, const int32_t size); +int32_t mp4ff_tag_delete(mp4ff_metadata_t *tags); +int32_t mp4ff_meta_get_num_items(const mp4ff_t *f); +int32_t mp4ff_meta_get_by_index(const mp4ff_t *f, uint32_t index, + char **item, char **value); +int32_t mp4ff_meta_get_title(const mp4ff_t *f, char **value); +int32_t mp4ff_meta_get_artist(const mp4ff_t *f, char **value); +int32_t mp4ff_meta_get_writer(const mp4ff_t *f, char **value); +int32_t mp4ff_meta_get_album(const mp4ff_t *f, char **value); +int32_t mp4ff_meta_get_date(const mp4ff_t *f, char **value); +int32_t mp4ff_meta_get_tool(const mp4ff_t *f, char **value); +int32_t mp4ff_meta_get_comment(const mp4ff_t *f, char **value); +int32_t mp4ff_meta_get_genre(const mp4ff_t *f, char **value); +int32_t mp4ff_meta_get_track(const mp4ff_t *f, char **value); +int32_t mp4ff_meta_get_disc(const mp4ff_t *f, char **value); +int32_t mp4ff_meta_get_compilation(const mp4ff_t *f, char **value); +int32_t mp4ff_meta_get_tempo(const mp4ff_t *f, char **value); +int32_t mp4ff_meta_get_coverart(const mp4ff_t *f, char **value); +#endif + +/* mp4ff.c */ +mp4ff_t *mp4ff_open_read(mp4ff_callback_t *f); +#ifdef USE_TAGGING +mp4ff_t *mp4ff_open_edit(mp4ff_callback_t *f); +#endif +void mp4ff_close(mp4ff_t *ff); +//void mp4ff_track_add(mp4ff_t *f); +int32_t parse_sub_atoms(mp4ff_t *f, const uint64_t total_size,int meta_only); +int32_t parse_atoms(mp4ff_t *f,int meta_only); + +int32_t mp4ff_get_sample_duration(const mp4ff_t *f, const int32_t track, const int32_t sample); +int64_t mp4ff_get_sample_position(const mp4ff_t *f, const int32_t track, const int32_t sample); +int32_t mp4ff_get_sample_offset(const mp4ff_t *f, const int32_t track, const int32_t sample); +int32_t mp4ff_find_sample(const mp4ff_t *f, const int32_t track, const int64_t offset,int32_t * toskip); + +int32_t mp4ff_read_sample(mp4ff_t *f, const int32_t track, const int32_t sample, + uint8_t **audio_buffer, uint32_t *bytes); +int32_t mp4ff_get_decoder_config(const mp4ff_t *f, const int32_t track, + uint8_t** ppBuf, uint32_t* pBufSize); +int32_t mp4ff_total_tracks(const mp4ff_t *f); +int32_t mp4ff_time_scale(const mp4ff_t *f, const int32_t track); +int32_t mp4ff_num_samples(const mp4ff_t *f, const int32_t track); + +uint32_t mp4ff_meta_genre_to_index(const char * genrestr);//returns 1-based index, 0 if not found +const char * mp4ff_meta_index_to_genre(uint32_t idx);//returns pointer to static string + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/faad2/src/common/mp4ff/mp4meta.c b/faad2/src/common/mp4ff/mp4meta.c new file mode 100644 index 0000000..4e75862 --- /dev/null +++ b/faad2/src/common/mp4ff/mp4meta.c @@ -0,0 +1,461 @@ +/* +** FAAD2 - Freeware Advanced Audio (AAC) Decoder including SBR decoding +** Copyright (C) 2003-2005 M. Bakker, Nero AG, http://www.nero.com +** +** This program 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 of the License, or +** (at your option) any later version. +** +** This program 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 this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +** +** Any non-GPL usage of this software or parts of this software is strictly +** forbidden. +** +** The "appropriate copyright message" mentioned in section 2c of the GPLv2 +** must read: "Code from FAAD2 is copyright (c) Nero AG, www.nero.com" +** +** Commercial non-GPL licensing of this software is possible. +** For more info contact Nero AG through Mpeg4AAClicense@nero.com. +** +** $Id: mp4meta.c,v 1.21 2009/01/19 23:56:30 menno Exp $ +**/ + +#ifdef USE_TAGGING + +#include +#include +#include +#include "mp4ffint.h" + + + +static int32_t mp4ff_tag_add_field(mp4ff_metadata_t *tags, const char *item, const char *value) +{ + void *backup = (void *)tags->tags; + + if (!item || (item && !*item) || !value) return 0; + + tags->tags = (mp4ff_tag_t*)realloc(tags->tags, (tags->count+1) * sizeof(mp4ff_tag_t)); + if (!tags->tags) + { + if (backup) free(backup); + return 0; + } else { + tags->tags[tags->count].item = strdup(item); + tags->tags[tags->count].value = strdup(value); + + if (!tags->tags[tags->count].item || !tags->tags[tags->count].value) + { + if (!tags->tags[tags->count].item) free (tags->tags[tags->count].item); + if (!tags->tags[tags->count].value) free (tags->tags[tags->count].value); + tags->tags[tags->count].item = NULL; + tags->tags[tags->count].value = NULL; + return 0; + } + + tags->count++; + return 1; + } +} + +static int32_t mp4ff_tag_set_field(mp4ff_metadata_t *tags, const char *item, const char *value) +{ + unsigned int i; + + if (!item || (item && !*item) || !value) return 0; + + for (i = 0; i < tags->count; i++) + { + if (!stricmp(tags->tags[i].item, item)) + { + free(tags->tags[i].value); + tags->tags[i].value = strdup(value); + return 1; + } + } + + return mp4ff_tag_add_field(tags, item, value); +} + +int32_t mp4ff_tag_delete(mp4ff_metadata_t *tags) +{ + uint32_t i; + + for (i = 0; i < tags->count; i++) + { + if (tags->tags[i].item) free(tags->tags[i].item); + if (tags->tags[i].value) free(tags->tags[i].value); + } + + if (tags->tags) free(tags->tags); + + tags->tags = NULL; + tags->count = 0; + + return 0; +} + +static const char* ID3v1GenreList[] = { + "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk", + "Grunge", "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies", + "Other", "Pop", "R&B", "Rap", "Reggae", "Rock", + "Techno", "Industrial", "Alternative", "Ska", "Death Metal", "Pranks", + "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop", "Vocal", "Jazz+Funk", + "Fusion", "Trance", "Classical", "Instrumental", "Acid", "House", + "Game", "Sound Clip", "Gospel", "Noise", "AlternRock", "Bass", + "Soul", "Punk", "Space", "Meditative", "Instrumental Pop", "Instrumental Rock", + "Ethnic", "Gothic", "Darkwave", "Techno-Industrial", "Electronic", "Pop-Folk", + "Eurodance", "Dream", "Southern Rock", "Comedy", "Cult", "Gangsta", + "Top 40", "Christian Rap", "Pop/Funk", "Jungle", "Native American", "Cabaret", + "New Wave", "Psychadelic", "Rave", "Showtunes", "Trailer", "Lo-Fi", + "Tribal", "Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical", + "Rock & Roll", "Hard Rock", "Folk", "Folk/Rock", "National Folk", "Swing", + "Fast-Fusion", "Bebob", "Latin", "Revival", "Celtic", "Bluegrass", "Avantgarde", + "Gothic Rock", "Progressive Rock", "Psychedelic Rock", "Symphonic Rock", "Slow Rock", "Big Band", + "Chorus", "Easy Listening", "Acoustic", "Humour", "Speech", "Chanson", + "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass", "Primus", + "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba", + "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle", "Duet", + "Punk Rock", "Drum Solo", "A capella", "Euro-House", "Dance Hall", + "Goa", "Drum & Bass", "Club House", "Hardcore", "Terror", + "Indie", "BritPop", "NegerPunk", "Polsk Punk", "Beat", + "Christian Gangsta", "Heavy Metal", "Black Metal", "Crossover", "Contemporary C", + "Christian Rock", "Merengue", "Salsa", "Thrash Metal", "Anime", "JPop", + "SynthPop", +}; + +uint32_t mp4ff_meta_genre_to_index(const char * genrestr) +{ + unsigned n; + for(n=0;n0 && idx<=sizeof(ID3v1GenreList)/sizeof(ID3v1GenreList[0])) + { + return ID3v1GenreList[idx-1]; + } + else + { + return 0; + } +} + + +static int32_t TrackToString(char** str, const uint16_t track, const uint16_t totalTracks) +{ + char temp[32]; + sprintf(temp, "%.5u of %.5u", track, totalTracks); + *str = strdup(temp); + return 0; +} + +static int32_t mp4ff_set_metadata_name(mp4ff_t *f, const uint8_t atom_type, char **name) +{ + static char *tag_names[] = { + "unknown", "title", "artist", "writer", "album", + "date", "tool", "comment", "genre", "track", + "disc", "compilation", "genre", "tempo", "cover", + "album_artist", "contentgroup", "lyrics", "description", + "network", "show", "episodename", + "sorttitle", "sortalbum", "sortartist", "sortalbumartist", + "sortwriter", "sortshow", + "season", "episode", "podcast" + + }; + uint8_t tag_idx = 0; + + switch (atom_type) + { + case ATOM_TITLE: tag_idx = 1; break; + case ATOM_ARTIST: tag_idx = 2; break; + case ATOM_WRITER: tag_idx = 3; break; + case ATOM_ALBUM: tag_idx = 4; break; + case ATOM_DATE: tag_idx = 5; break; + case ATOM_TOOL: tag_idx = 6; break; + case ATOM_COMMENT: tag_idx = 7; break; + case ATOM_GENRE1: tag_idx = 8; break; + case ATOM_TRACK: tag_idx = 9; break; + case ATOM_DISC: tag_idx = 10; break; + case ATOM_COMPILATION: tag_idx = 11; break; + case ATOM_GENRE2: tag_idx = 12; break; + case ATOM_TEMPO: tag_idx = 13; break; + case ATOM_COVER: tag_idx = 14; break; + case ATOM_ALBUM_ARTIST: tag_idx = 15; break; + case ATOM_CONTENTGROUP: tag_idx = 16; break; + case ATOM_LYRICS: tag_idx = 17; break; + case ATOM_DESCRIPTION: tag_idx = 18; break; + case ATOM_NETWORK: tag_idx = 19; break; + case ATOM_SHOW: tag_idx = 20; break; + case ATOM_EPISODENAME: tag_idx = 21; break; + case ATOM_SORTTITLE: tag_idx = 22; break; + case ATOM_SORTALBUM: tag_idx = 23; break; + case ATOM_SORTARTIST: tag_idx = 24; break; + case ATOM_SORTALBUMARTIST: tag_idx = 25; break; + case ATOM_SORTWRITER: tag_idx = 26; break; + case ATOM_SORTSHOW: tag_idx = 27; break; + case ATOM_SEASON: tag_idx = 28; break; + case ATOM_EPISODE: tag_idx = 29; break; + case ATOM_PODCAST: tag_idx = 30; break; + default: tag_idx = 0; break; + } + + *name = strdup(tag_names[tag_idx]); + + return 0; +} + +static int32_t mp4ff_parse_tag(mp4ff_t *f, const uint8_t parent_atom_type, const int32_t size) +{ + uint8_t atom_type; + uint8_t header_size = 0; + uint64_t subsize, sumsize = 0; + char * name = NULL; + char * data = NULL; + uint32_t done = 0; + + + while (sumsize < size) + { + uint64_t destpos; + subsize = mp4ff_atom_read_header(f, &atom_type, &header_size); + destpos = mp4ff_position(f)+subsize-header_size; + if (!done) + { + if (atom_type == ATOM_DATA) + { + mp4ff_read_char(f); /* version */ + mp4ff_read_int24(f); /* flags */ + mp4ff_read_int32(f); /* reserved */ + + /* some need special attention */ + if (parent_atom_type == ATOM_GENRE2 || parent_atom_type == ATOM_TEMPO) + { + if (subsize - header_size >= 8 + 2) + { + uint16_t val = mp4ff_read_int16(f); + + if (parent_atom_type == ATOM_TEMPO) + { + char temp[16]; + sprintf(temp, "%.5u BPM", val); + mp4ff_tag_add_field(&(f->tags), "tempo", temp); + } + else + { + const char * temp = mp4ff_meta_index_to_genre(val); + if (temp) + { + mp4ff_tag_add_field(&(f->tags), "genre", temp); + } + } + done = 1; + } + } else if (parent_atom_type == ATOM_TRACK || parent_atom_type == ATOM_DISC) { + /* if (!done && subsize - header_size >= 8 + 8) */ + /* modified by AJS */ + if ( !done && (subsize - header_size) >= + (sizeof(char) + sizeof(uint8_t)*3 + sizeof(uint32_t) + /* version + flags + reserved */ + + sizeof(uint16_t) /* leading uint16_t */ + + sizeof(uint16_t) /* track / disc */ + + sizeof(uint16_t)) /* totaltracks / totaldiscs */ + ) + { + uint16_t index,total; + char temp[32]; + mp4ff_read_int16(f); + index = mp4ff_read_int16(f); + total = mp4ff_read_int16(f); + /* modified by AJS */ + /* mp4ff_read_int16(f); */ + + sprintf(temp,"%d",index); + mp4ff_tag_add_field(&(f->tags), parent_atom_type == ATOM_TRACK ? "track" : "disc", temp); + if (total>0) + { + sprintf(temp,"%d",total); + mp4ff_tag_add_field(&(f->tags), parent_atom_type == ATOM_TRACK ? "totaltracks" : "totaldiscs", temp); + } + done = 1; + } + } else + { + if (data) {free(data);data = NULL;} + data = mp4ff_read_string(f,(uint32_t)(subsize-(header_size+8))); + } + } else if (atom_type == ATOM_NAME) { + if (!done) + { + mp4ff_read_char(f); /* version */ + mp4ff_read_int24(f); /* flags */ + if (name) free(name); + name = mp4ff_read_string(f,(uint32_t)(subsize-(header_size+4))); + } + } + mp4ff_set_position(f, destpos); + sumsize += subsize; + } + } + + if (data) + { + if (!done) + { + if (name == NULL) mp4ff_set_metadata_name(f, parent_atom_type, &name); + if (name) mp4ff_tag_add_field(&(f->tags), name, data); + } + + free(data); + } + if (name) free(name); + return 1; +} + +int32_t mp4ff_parse_metadata(mp4ff_t *f, const int32_t size) +{ + uint64_t subsize, sumsize = 0; + uint8_t atom_type; + uint8_t header_size = 0; + + while (sumsize < size) + { + subsize = mp4ff_atom_read_header(f, &atom_type, &header_size); + if (subsize == 0) + break; + mp4ff_parse_tag(f, atom_type, (uint32_t)(subsize-header_size)); + sumsize += subsize; + } + + return 0; +} + +/* find a metadata item by name */ +/* returns 0 if item found, 1 if no such item */ +static int32_t mp4ff_meta_find_by_name(const mp4ff_t *f, const char *item, char **value) +{ + uint32_t i; + + for (i = 0; i < f->tags.count; i++) + { + if (!stricmp(f->tags.tags[i].item, item)) + { + *value = strdup(f->tags.tags[i].value); + return 1; + } + } + + *value = NULL; + + /* not found */ + return 0; +} + +int32_t mp4ff_meta_get_num_items(const mp4ff_t *f) +{ + return f->tags.count; +} + +int32_t mp4ff_meta_get_by_index(const mp4ff_t *f, uint32_t index, + char **item, char **value) +{ + if (index >= f->tags.count) + { + *item = NULL; + *value = NULL; + return 0; + } else { + *item = strdup(f->tags.tags[index].item); + *value = strdup(f->tags.tags[index].value); + return 1; + } +} + +int32_t mp4ff_meta_get_title(const mp4ff_t *f, char **value) +{ + return mp4ff_meta_find_by_name(f, "title", value); +} + +int32_t mp4ff_meta_get_artist(const mp4ff_t *f, char **value) +{ + return mp4ff_meta_find_by_name(f, "artist", value); +} + +int32_t mp4ff_meta_get_writer(const mp4ff_t *f, char **value) +{ + return mp4ff_meta_find_by_name(f, "writer", value); +} + +int32_t mp4ff_meta_get_album(const mp4ff_t *f, char **value) +{ + return mp4ff_meta_find_by_name(f, "album", value); +} + +int32_t mp4ff_meta_get_date(const mp4ff_t *f, char **value) +{ + return mp4ff_meta_find_by_name(f, "date", value); +} + +int32_t mp4ff_meta_get_tool(const mp4ff_t *f, char **value) +{ + return mp4ff_meta_find_by_name(f, "tool", value); +} + +int32_t mp4ff_meta_get_comment(const mp4ff_t *f, char **value) +{ + return mp4ff_meta_find_by_name(f, "comment", value); +} + +int32_t mp4ff_meta_get_genre(const mp4ff_t *f, char **value) +{ + return mp4ff_meta_find_by_name(f, "genre", value); +} + +int32_t mp4ff_meta_get_track(const mp4ff_t *f, char **value) +{ + return mp4ff_meta_find_by_name(f, "track", value); +} + +int32_t mp4ff_meta_get_totaltracks(const mp4ff_t *f, char **value) +{ + return mp4ff_meta_find_by_name(f, "totaltracks", value); +} + +int32_t mp4ff_meta_get_disc(const mp4ff_t *f, char **value) +{ + return mp4ff_meta_find_by_name(f, "disc", value); +} + +int32_t mp4ff_meta_get_totaldiscs(const mp4ff_t *f, char **value) +{ + return mp4ff_meta_find_by_name(f, "totaldiscs", value); +} + +int32_t mp4ff_meta_get_compilation(const mp4ff_t *f, char **value) +{ + return mp4ff_meta_find_by_name(f, "compilation", value); +} + +int32_t mp4ff_meta_get_tempo(const mp4ff_t *f, char **value) +{ + return mp4ff_meta_find_by_name(f, "tempo", value); +} + +int32_t mp4ff_meta_get_coverart(const mp4ff_t *f, char **value) +{ + return mp4ff_meta_find_by_name(f, "cover", value); +} + +#endif \ No newline at end of file diff --git a/faad2/src/common/mp4ff/mp4sample.c b/faad2/src/common/mp4ff/mp4sample.c new file mode 100644 index 0000000..5bed06e --- /dev/null +++ b/faad2/src/common/mp4ff/mp4sample.c @@ -0,0 +1,155 @@ +/* +** FAAD2 - Freeware Advanced Audio (AAC) Decoder including SBR decoding +** Copyright (C) 2003-2005 M. Bakker, Nero AG, http://www.nero.com +** +** This program 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 of the License, or +** (at your option) any later version. +** +** This program 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 this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +** +** Any non-GPL usage of this software or parts of this software is strictly +** forbidden. +** +** The "appropriate copyright message" mentioned in section 2c of the GPLv2 +** must read: "Code from FAAD2 is copyright (c) Nero AG, www.nero.com" +** +** Commercial non-GPL licensing of this software is possible. +** For more info contact Nero AG through Mpeg4AAClicense@nero.com. +** +** $Id: mp4sample.c,v 1.20 2007/11/01 12:33:29 menno Exp $ +**/ + +#include +#include "mp4ffint.h" + + +static int32_t mp4ff_chunk_of_sample(const mp4ff_t *f, const int32_t track, const int32_t sample, + int32_t *chunk_sample, int32_t *chunk) +{ + int32_t total_entries = 0; + int32_t chunk2entry; + int32_t chunk1, chunk2, chunk1samples, range_samples, total = 0; + + if (f->track[track] == NULL) + { + return -1; + } + + total_entries = f->track[track]->stsc_entry_count; + + chunk1 = 1; + chunk1samples = 0; + chunk2entry = 0; + + do + { + chunk2 = f->track[track]->stsc_first_chunk[chunk2entry]; + *chunk = chunk2 - chunk1; + range_samples = *chunk * chunk1samples; + + if (sample < total + range_samples) break; + + chunk1samples = f->track[track]->stsc_samples_per_chunk[chunk2entry]; + chunk1 = chunk2; + + if(chunk2entry < total_entries) + { + chunk2entry++; + total += range_samples; + } + } while (chunk2entry < total_entries); + + if (chunk1samples) + *chunk = (sample - total) / chunk1samples + chunk1; + else + *chunk = 1; + + *chunk_sample = total + (*chunk - chunk1) * chunk1samples; + + return 0; +} + +static int32_t mp4ff_chunk_to_offset(const mp4ff_t *f, const int32_t track, const int32_t chunk) +{ + const mp4ff_track_t * p_track = f->track[track]; + + if (p_track->stco_entry_count && (chunk > p_track->stco_entry_count)) + { + return p_track->stco_chunk_offset[p_track->stco_entry_count - 1]; + } else if (p_track->stco_entry_count) { + return p_track->stco_chunk_offset[chunk - 1]; + } else { + return 8; + } + + return 0; +} + +static int32_t mp4ff_sample_range_size(const mp4ff_t *f, const int32_t track, + const int32_t chunk_sample, const int32_t sample) +{ + int32_t i, total; + const mp4ff_track_t * p_track = f->track[track]; + + if (p_track->stsz_sample_size) + { + return (sample - chunk_sample) * p_track->stsz_sample_size; + } + else + { + if (sample>=p_track->stsz_sample_count) return 0;//error + + for(i = chunk_sample, total = 0; i < sample; i++) + { + total += p_track->stsz_table[i]; + } + } + + return total; +} + +static int32_t mp4ff_sample_to_offset(const mp4ff_t *f, const int32_t track, const int32_t sample) +{ + int32_t chunk, chunk_sample, chunk_offset1, chunk_offset2; + + mp4ff_chunk_of_sample(f, track, sample, &chunk_sample, &chunk); + + chunk_offset1 = mp4ff_chunk_to_offset(f, track, chunk); + chunk_offset2 = chunk_offset1 + mp4ff_sample_range_size(f, track, chunk_sample, sample); + + return chunk_offset2; +} + +int32_t mp4ff_audio_frame_size(const mp4ff_t *f, const int32_t track, const int32_t sample) +{ + int32_t bytes; + const mp4ff_track_t * p_track = f->track[track]; + + if (p_track->stsz_sample_size) + { + bytes = p_track->stsz_sample_size; + } else { + bytes = p_track->stsz_table[sample]; + } + + return bytes; +} + +int32_t mp4ff_set_sample_position(mp4ff_t *f, const int32_t track, const int32_t sample) +{ + int32_t offset; + + offset = mp4ff_sample_to_offset(f, track, sample); + mp4ff_set_position(f, offset); + + return 0; +} diff --git a/faad2/src/common/mp4ff/mp4tagupdate.c b/faad2/src/common/mp4ff/mp4tagupdate.c new file mode 100644 index 0000000..ae29e12 --- /dev/null +++ b/faad2/src/common/mp4ff/mp4tagupdate.c @@ -0,0 +1,656 @@ +#include +#include +#include "mp4ffint.h" + +#ifdef USE_TAGGING + +static uint32_t fix_byte_order_32(uint32_t src) +{ + uint32_t result; + uint32_t a, b, c, d; + int8_t data[4]; + + memcpy(data,&src,sizeof(src)); + a = (uint8_t)data[0]; + b = (uint8_t)data[1]; + c = (uint8_t)data[2]; + d = (uint8_t)data[3]; + + result = (a<<24) | (b<<16) | (c<<8) | d; + return (uint32_t)result; +} + +static uint16_t fix_byte_order_16(uint16_t src) +{ + uint16_t result; + uint16_t a, b; + int8_t data[2]; + + memcpy(data,&src,sizeof(src)); + a = (uint8_t)data[0]; + b = (uint8_t)data[1]; + + result = (a<<8) | b; + return (uint16_t)result; +} + + +typedef struct +{ + void * data; + unsigned written; + unsigned allocated; + unsigned error; +} membuffer; + +unsigned membuffer_write(membuffer * buf,const void * ptr,unsigned bytes) +{ + unsigned dest_size = buf->written + bytes; + + if (buf->error) return 0; + if (dest_size > buf->allocated) + { + do + { + buf->allocated <<= 1; + } while(dest_size > buf->allocated); + + { + void * newptr = realloc(buf->data,buf->allocated); + if (newptr==0) + { + free(buf->data); + buf->data = 0; + buf->error = 1; + return 0; + } + buf->data = newptr; + } + } + + if (ptr) memcpy((char*)buf->data + buf->written,ptr,bytes); + buf->written += bytes; + return bytes; +} + +#define membuffer_write_data membuffer_write + +unsigned membuffer_write_int32(membuffer * buf,uint32_t data) +{ + uint8_t temp[4] = {(uint8_t)(data>>24),(uint8_t)(data>>16),(uint8_t)(data>>8),(uint8_t)data}; + return membuffer_write_data(buf,temp,4); +} + +unsigned membuffer_write_int24(membuffer * buf,uint32_t data) +{ + uint8_t temp[3] = {(uint8_t)(data>>16),(uint8_t)(data>>8),(uint8_t)data}; + return membuffer_write_data(buf,temp,3); +} + +unsigned membuffer_write_int16(membuffer * buf,uint16_t data) +{ + uint8_t temp[2] = {(uint8_t)(data>>8),(uint8_t)data}; + return membuffer_write_data(buf,temp,2); +} + +unsigned membuffer_write_atom_name(membuffer * buf,const char * data) +{ + return membuffer_write_data(buf,data,4)==4 ? 1 : 0; +} + +void membuffer_write_atom(membuffer * buf,const char * name,unsigned size,const void * data) +{ + membuffer_write_int32(buf,size + 8); + membuffer_write_atom_name(buf,name); + membuffer_write_data(buf,data,size); +} + +unsigned membuffer_write_string(membuffer * buf,const char * data) +{ + return membuffer_write_data(buf,data,strlen(data)); +} + +unsigned membuffer_write_int8(membuffer * buf,uint8_t data) +{ + return membuffer_write_data(buf,&data,1); +} + +void * membuffer_get_ptr(const membuffer * buf) +{ + return buf->data; +} + +unsigned membuffer_get_size(const membuffer * buf) +{ + return buf->written; +} + +unsigned membuffer_error(const membuffer * buf) +{ + return buf->error; +} + +void membuffer_set_error(membuffer * buf) {buf->error = 1;} + +unsigned membuffer_transfer_from_file(membuffer * buf,mp4ff_t * src,unsigned bytes) +{ + unsigned oldsize; + void * bufptr; + + oldsize = membuffer_get_size(buf); + if (membuffer_write_data(buf,0,bytes) != bytes) return 0; + + bufptr = membuffer_get_ptr(buf); + if (bufptr==0) return 0; + + if ((unsigned)mp4ff_read_data(src,(char*)bufptr + oldsize,bytes)!=bytes) + { + membuffer_set_error(buf); + return 0; + } + + return bytes; +} + + +membuffer * membuffer_create() +{ + const unsigned initial_size = 256; + + membuffer * buf = (membuffer *) malloc(sizeof(membuffer)); + buf->data = malloc(initial_size); + buf->written = 0; + buf->allocated = initial_size; + buf->error = buf->data == 0 ? 1 : 0; + + return buf; +} + +void membuffer_free(membuffer * buf) +{ + if (buf->data) free(buf->data); + free(buf); +} + +void * membuffer_detach(membuffer * buf) +{ + void * ret; + + if (buf->error) return 0; + + ret = realloc(buf->data,buf->written); + + if (ret == 0) free(buf->data); + + buf->data = 0; + buf->error = 1; + + return ret; +} + +#if 0 +/* metadata tag structure */ +typedef struct +{ + char *item; + char *value; +} mp4ff_tag_t; + +/* metadata list structure */ +typedef struct +{ + mp4ff_tag_t *tags; + uint32_t count; +} mp4ff_metadata_t; +#endif + +typedef struct +{ + const char * atom; + const char * name; +} stdmeta_entry; + +static stdmeta_entry stdmetas[] = +{ + {"\xA9" "nam","title"}, + {"\xA9" "ART","artist"}, + {"\xA9" "wrt","writer"}, + {"\xA9" "alb","album"}, + {"\xA9" "day","date"}, + {"\xA9" "too","tool"}, + {"\xA9" "cmt","comment"}, +// {"\xA9" "gen","genre"}, + {"cpil","compilation"}, +// {"trkn","track"}, +// {"disk","disc"}, +// {"gnre","genre"}, + {"covr","cover"}, + /* added by AJS */ + {"aART","album_artist"}, +}; + + +static const char* find_standard_meta(const char * name) //returns atom name if found, 0 if not +{ + unsigned n; + for(n=0;ncount); + memset(mask,0,data->count); + + { + const char * tracknumber_ptr = 0, * totaltracks_ptr = 0; + const char * discnumber_ptr = 0, * totaldiscs_ptr = 0; + const char * genre_ptr = 0, * tempo_ptr = 0; + for(metaptr = 0; metaptr < data->count; metaptr++) + { + mp4ff_tag_t * tag = &data->tags[metaptr]; + if (!stricmp(tag->item,"tracknumber") || !stricmp(tag->item,"track")) + { + if (tracknumber_ptr==0) tracknumber_ptr = tag->value; + mask[metaptr] = 1; + } + else if (!stricmp(tag->item,"totaltracks")) + { + if (totaltracks_ptr==0) totaltracks_ptr = tag->value; + mask[metaptr] = 1; + } + else if (!stricmp(tag->item,"discnumber") || !stricmp(tag->item,"disc")) + { + if (discnumber_ptr==0) discnumber_ptr = tag->value; + mask[metaptr] = 1; + } + else if (!stricmp(tag->item,"totaldiscs")) + { + if (totaldiscs_ptr==0) totaldiscs_ptr = tag->value; + mask[metaptr] = 1; + } + else if (!stricmp(tag->item,"genre")) + { + if (genre_ptr==0) genre_ptr = tag->value; + mask[metaptr] = 1; + } + else if (!stricmp(tag->item,"tempo")) + { + if (tempo_ptr==0) tempo_ptr = tag->value; + mask[metaptr] = 1; + } + + } + + if (tracknumber_ptr) membuffer_write_track_tag(buf,"trkn",myatoi(tracknumber_ptr),myatoi(totaltracks_ptr)); + if (discnumber_ptr) membuffer_write_track_tag(buf,"disk",myatoi(discnumber_ptr),myatoi(totaldiscs_ptr)); + if (tempo_ptr) membuffer_write_int16_tag(buf,"tmpo",(uint16_t)myatoi(tempo_ptr)); + + if (genre_ptr) + { + uint32_t index = mp4ff_meta_genre_to_index(genre_ptr); + if (index==0) + membuffer_write_std_tag(buf,"©gen",genre_ptr); + else + membuffer_write_int16_tag(buf,"gnre",(uint16_t)index); + } + } + + for(metaptr = 0; metaptr < data->count; metaptr++) + { + if (!mask[metaptr]) + { + mp4ff_tag_t * tag = &data->tags[metaptr]; + const char * std_meta_atom = find_standard_meta(tag->item); + if (std_meta_atom) + { + membuffer_write_std_tag(buf,std_meta_atom,tag->value); + } + else + { + membuffer_write_custom_tag(buf,tag->item,tag->value); + } + } + } + + free(mask); + + if (membuffer_error(buf)) + { + membuffer_free(buf); + return 0; + } + + *out_size = membuffer_get_size(buf); + *out_buffer = membuffer_detach(buf); + membuffer_free(buf); + + return 1; +} + +static uint32_t find_atom(mp4ff_t * f,uint64_t base,uint32_t size,const char * name) +{ + uint32_t remaining = size; + uint64_t atom_offset = base; + for(;;) + { + char atom_name[4]; + uint32_t atom_size; + + mp4ff_set_position(f,atom_offset); + + if (remaining < 8) break; + atom_size = mp4ff_read_int32(f); + if (atom_size > remaining || atom_size < 8) break; + mp4ff_read_data(f,atom_name,4); + + if (!memcmp(atom_name,name,4)) + { + mp4ff_set_position(f,atom_offset); + return 1; + } + + remaining -= atom_size; + atom_offset += atom_size; + } + return 0; +} + +static uint32_t find_atom_v2(mp4ff_t * f,uint64_t base,uint32_t size,const char * name,uint32_t extraheaders,const char * name_inside) +{ + uint64_t first_base = (uint64_t)(-1); + while(find_atom(f,base,size,name))//try to find atom with atom in it + { + uint64_t mybase = mp4ff_position(f); + uint32_t mysize = mp4ff_read_int32(f); + + if (first_base == (uint64_t)(-1)) first_base = mybase; + + if (mysize < 8 + extraheaders) break; + + if (find_atom(f,mybase+(8+extraheaders),mysize-(8+extraheaders),name_inside)) + { + mp4ff_set_position(f,mybase); + return 2; + } + base += mysize; + if (size<=mysize) {size=0;break;} + size -= mysize; + } + + if (first_base != (uint64_t)(-1))//wanted atom inside not found + { + mp4ff_set_position(f,first_base); + return 1; + } + else return 0; +} + +static uint32_t create_meta(const mp4ff_metadata_t * data,void ** out_buffer,uint32_t * out_size) +{ + membuffer * buf; + uint32_t ilst_size; + void * ilst_buffer; + + if (!create_ilst(data,&ilst_buffer,&ilst_size)) return 0; + + buf = membuffer_create(); + + membuffer_write_int32(buf,0); + membuffer_write_atom(buf,"ilst",ilst_size,ilst_buffer); + free(ilst_buffer); + + *out_size = membuffer_get_size(buf); + *out_buffer = membuffer_detach(buf); + membuffer_free(buf); + return 1; +} + +static uint32_t create_udta(const mp4ff_metadata_t * data,void ** out_buffer,uint32_t * out_size) +{ + membuffer * buf; + uint32_t meta_size; + void * meta_buffer; + + if (!create_meta(data,&meta_buffer,&meta_size)) return 0; + + buf = membuffer_create(); + + membuffer_write_atom(buf,"meta",meta_size,meta_buffer); + + free(meta_buffer); + + *out_size = membuffer_get_size(buf); + *out_buffer = membuffer_detach(buf); + membuffer_free(buf); + return 1; +} + +static uint32_t modify_moov(mp4ff_t * f,const mp4ff_metadata_t * data,void ** out_buffer,uint32_t * out_size) +{ + uint64_t total_base = f->moov_offset + 8; + uint32_t total_size = (uint32_t)(f->moov_size - 8); + + uint64_t udta_offset,meta_offset,ilst_offset; + uint32_t udta_size, meta_size, ilst_size; + + uint32_t new_ilst_size; + void * new_ilst_buffer; + + uint8_t * p_out; + int32_t size_delta; + + + if (!find_atom_v2(f,total_base,total_size,"udta",0,"meta")) + { + membuffer * buf; + void * new_udta_buffer; + uint32_t new_udta_size; + if (!create_udta(data,&new_udta_buffer,&new_udta_size)) return 0; + + buf = membuffer_create(); + mp4ff_set_position(f,total_base); + membuffer_transfer_from_file(buf,f,total_size); + + membuffer_write_atom(buf,"udta",new_udta_size,new_udta_buffer); + + free(new_udta_buffer); + + *out_size = membuffer_get_size(buf); + *out_buffer = membuffer_detach(buf); + membuffer_free(buf); + return 1; + } + else + { + udta_offset = mp4ff_position(f); + udta_size = mp4ff_read_int32(f); + if (!find_atom_v2(f,udta_offset+8,udta_size-8,"meta",4,"ilst")) + { + membuffer * buf; + void * new_meta_buffer; + uint32_t new_meta_size; + if (!create_meta(data,&new_meta_buffer,&new_meta_size)) return 0; + + buf = membuffer_create(); + mp4ff_set_position(f,total_base); + membuffer_transfer_from_file(buf,f,(uint32_t)(udta_offset - total_base)); + + membuffer_write_int32(buf,udta_size + 8 + new_meta_size); + membuffer_write_atom_name(buf,"udta"); + membuffer_transfer_from_file(buf,f,udta_size); + + membuffer_write_atom(buf,"meta",new_meta_size,new_meta_buffer); + free(new_meta_buffer); + + *out_size = membuffer_get_size(buf); + *out_buffer = membuffer_detach(buf); + membuffer_free(buf); + return 1; + } + meta_offset = mp4ff_position(f); + meta_size = mp4ff_read_int32(f); + if (!find_atom(f,meta_offset+12,meta_size-12,"ilst")) return 0;//shouldn't happen, find_atom_v2 above takes care of it + ilst_offset = mp4ff_position(f); + ilst_size = mp4ff_read_int32(f); + + if (!create_ilst(data,&new_ilst_buffer,&new_ilst_size)) return 0; + + size_delta = new_ilst_size - (ilst_size - 8); + + *out_size = total_size + size_delta; + *out_buffer = malloc(*out_size); + if (*out_buffer == 0) + { + free(new_ilst_buffer); + return 0; + } + + p_out = (uint8_t*)*out_buffer; + + mp4ff_set_position(f,total_base); + mp4ff_read_data(f,p_out,(uint32_t)(udta_offset - total_base )); p_out += (uint32_t)(udta_offset - total_base ); + *(uint32_t*)p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta); p_out += 4; + mp4ff_read_data(f,p_out,4); p_out += 4; + mp4ff_read_data(f,p_out,(uint32_t)(meta_offset - udta_offset - 8)); p_out += (uint32_t)(meta_offset - udta_offset - 8); + *(uint32_t*)p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta); p_out += 4; + mp4ff_read_data(f,p_out,4); p_out += 4; + mp4ff_read_data(f,p_out,(uint32_t)(ilst_offset - meta_offset - 8)); p_out += (uint32_t)(ilst_offset - meta_offset - 8); + *(uint32_t*)p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta); p_out += 4; + mp4ff_read_data(f,p_out,4); p_out += 4; + + memcpy(p_out,new_ilst_buffer,new_ilst_size); + p_out += new_ilst_size; + + mp4ff_set_position(f,ilst_offset + ilst_size); + mp4ff_read_data(f,p_out,(uint32_t)(total_size - (ilst_offset - total_base) - ilst_size)); + + free(new_ilst_buffer); + } + return 1; + +} + +int32_t mp4ff_meta_update(mp4ff_callback_t *f,const mp4ff_metadata_t * data) +{ + void * new_moov_data; + uint32_t new_moov_size; + + mp4ff_t *ff = malloc(sizeof(mp4ff_t)); + + memset(ff, 0, sizeof(mp4ff_t)); + ff->stream = f; + mp4ff_set_position(ff,0); + + parse_atoms(ff,1); + + + if (!modify_moov(ff,data,&new_moov_data,&new_moov_size)) + { + mp4ff_close(ff); + return 0; + } + + /* copy moov atom to end of the file */ + if (ff->last_atom != ATOM_MOOV) + { + char *free_data = "free"; + + /* rename old moov to free */ + mp4ff_set_position(ff, ff->moov_offset + 4); + mp4ff_write_data(ff, free_data, 4); + + mp4ff_set_position(ff, ff->file_size); + mp4ff_write_int32(ff,new_moov_size + 8); + mp4ff_write_data(ff,"moov",4); + mp4ff_write_data(ff, new_moov_data, new_moov_size); + } + else + { + mp4ff_set_position(ff, ff->moov_offset); + mp4ff_write_int32(ff,new_moov_size + 8); + mp4ff_write_data(ff,"moov",4); + mp4ff_write_data(ff, new_moov_data, new_moov_size); + } + + mp4ff_truncate(ff); + + mp4ff_close(ff); + return 1; +} +#endif diff --git a/faad2/src/common/mp4ff/mp4util.c b/faad2/src/common/mp4ff/mp4util.c new file mode 100644 index 0000000..8acfcfe --- /dev/null +++ b/faad2/src/common/mp4ff/mp4util.c @@ -0,0 +1,191 @@ +/* +** FAAD2 - Freeware Advanced Audio (AAC) Decoder including SBR decoding +** Copyright (C) 2003-2005 M. Bakker, Nero AG, http://www.nero.com +** +** This program 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 of the License, or +** (at your option) any later version. +** +** This program 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 this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +** +** Any non-GPL usage of this software or parts of this software is strictly +** forbidden. +** +** The "appropriate copyright message" mentioned in section 2c of the GPLv2 +** must read: "Code from FAAD2 is copyright (c) Nero AG, www.nero.com" +** +** Commercial non-GPL licensing of this software is possible. +** For more info contact Nero AG through Mpeg4AAClicense@nero.com. +** +** $Id: mp4util.c,v 1.20 2007/11/01 12:33:29 menno Exp $ +**/ + +#include "mp4ffint.h" +#include + +int32_t mp4ff_read_data(mp4ff_t *f, int8_t *data, uint32_t size) +{ + int32_t result = 1; + + result = f->stream->read(f->stream->user_data, data, size); + + f->current_position += size; + + return result; +} + +int32_t mp4ff_truncate(mp4ff_t * f) +{ + return f->stream->truncate(f->stream->user_data); +} + +int32_t mp4ff_write_data(mp4ff_t *f, int8_t *data, uint32_t size) +{ + int32_t result = 1; + + result = f->stream->write(f->stream->user_data, data, size); + + f->current_position += size; + + return result; +} + +int32_t mp4ff_write_int32(mp4ff_t *f,const uint32_t data) +{ + uint32_t result; + uint32_t a, b, c, d; + int8_t temp[4]; + + *(uint32_t*)temp = data; + a = (uint8_t)temp[0]; + b = (uint8_t)temp[1]; + c = (uint8_t)temp[2]; + d = (uint8_t)temp[3]; + + result = (a<<24) | (b<<16) | (c<<8) | d; + + return mp4ff_write_data(f,(uint8_t*)&result,sizeof(result)); +} + +int32_t mp4ff_set_position(mp4ff_t *f, const int64_t position) +{ + f->stream->seek(f->stream->user_data, position); + f->current_position = position; + + return 0; +} + +int64_t mp4ff_position(const mp4ff_t *f) +{ + return f->current_position; +} + +uint64_t mp4ff_read_int64(mp4ff_t *f) +{ + uint8_t data[8]; + uint64_t result = 0; + int8_t i; + + mp4ff_read_data(f, data, 8); + + for (i = 0; i < 8; i++) + { + result |= ((uint64_t)data[i]) << ((7 - i) * 8); + } + + return result; +} + +uint32_t mp4ff_read_int32(mp4ff_t *f) +{ + uint32_t result; + uint32_t a, b, c, d; + int8_t data[4]; + + mp4ff_read_data(f, data, 4); + a = (uint8_t)data[0]; + b = (uint8_t)data[1]; + c = (uint8_t)data[2]; + d = (uint8_t)data[3]; + + result = (a<<24) | (b<<16) | (c<<8) | d; + return (uint32_t)result; +} + +uint32_t mp4ff_read_int24(mp4ff_t *f) +{ + uint32_t result; + uint32_t a, b, c; + int8_t data[4]; + + mp4ff_read_data(f, data, 3); + a = (uint8_t)data[0]; + b = (uint8_t)data[1]; + c = (uint8_t)data[2]; + + result = (a<<16) | (b<<8) | c; + return (uint32_t)result; +} + +uint16_t mp4ff_read_int16(mp4ff_t *f) +{ + uint32_t result; + uint32_t a, b; + int8_t data[2]; + + mp4ff_read_data(f, data, 2); + a = (uint8_t)data[0]; + b = (uint8_t)data[1]; + + result = (a<<8) | b; + return (uint16_t)result; +} + +char * mp4ff_read_string(mp4ff_t * f,uint32_t length) +{ + char * str = (char*)malloc(length + 1); + if (str!=0) + { + if ((uint32_t)mp4ff_read_data(f,str,length)!=length) + { + free(str); + str = 0; + } + else + { + str[length] = 0; + } + } + return str; +} + +uint8_t mp4ff_read_char(mp4ff_t *f) +{ + uint8_t output; + mp4ff_read_data(f, &output, 1); + return output; +} + +uint32_t mp4ff_read_mp4_descr_length(mp4ff_t *f) +{ + uint8_t b; + uint8_t numBytes = 0; + uint32_t length = 0; + + do + { + b = mp4ff_read_char(f); + numBytes++; + length = (length << 7) | (b & 0x7F); + } while ((b & 0x80) && numBytes < 4); + + return length; +} -- cgit v1.2.3