diff options
Diffstat (limited to 'lib/faad2/frontend/mp4read.c')
| -rw-r--r-- | lib/faad2/frontend/mp4read.c | 1109 |
1 files changed, 0 insertions, 1109 deletions
diff --git a/lib/faad2/frontend/mp4read.c b/lib/faad2/frontend/mp4read.c deleted file mode 100644 index a157d7d6..00000000 --- a/lib/faad2/frontend/mp4read.c +++ /dev/null @@ -1,1109 +0,0 @@ -/**************************************************************************** - MP4 input module - - Copyright (C) 2017 Krzysztof Nikiel - - 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 3 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, see <http://www.gnu.org/licenses/>. -****************************************************************************/ - -#define _CRT_SECURE_NO_WARNINGS - -#include <stdlib.h> -#include <stdio.h> -#include <stdint.h> -#include <string.h> -#include <time.h> -#include <limits.h> - -#include "unicode_support.h" -#include "mp4read.h" - -enum ATOM_TYPE -{ - ATOM_STOP = 0 /* end of atoms */ , - ATOM_NAME /* plain atom */ , - ATOM_DESCENT, /* starts group of children */ - ATOM_ASCENT, /* ends group */ - ATOM_DATA, -}; - -typedef int (*parse_t)(int); - -typedef struct -{ - uint16_t opcode; - const char *name; - parse_t parse; -} creator_t; - -#define STOP() {ATOM_STOP, NULL, NULL} -#define NAME(N) {ATOM_NAME, N, NULL} -#define DESCENT() {ATOM_DESCENT, NULL, NULL} -#define ASCENT() {ATOM_ASCENT, NULL, NULL} -#define DATA(N, F) {ATOM_NAME, N, NULL}, {ATOM_DATA, NULL, F} - -mp4config_t mp4config = { 0 }; - -static FILE *g_fin = NULL; - -enum {ERR_OK = 0, ERR_FAIL = -1, ERR_UNSUPPORTED = -2}; - -#define freeMem(A) if (*(A)) {free(*(A)); *(A) = NULL;} - -static size_t datain(void *data, size_t size) -{ - return fread(data, 1, size, g_fin); -} - -static int stringin(char *txt, int sizemax) -{ - int size; - for (size = 0; size < sizemax; size++) - { - if (fread(txt + size, 1, 1, g_fin) != 1) - return ERR_FAIL; - if (!txt[size]) - break; - } - txt[sizemax-1] = '\0'; - - return size; -} - -static uint32_t u32in(void) -{ - uint8_t u8[4]; - datain(&u8, 4); - return (uint32_t)u8[3] | ((uint32_t)u8[2] << 8) | ((uint32_t)u8[1] << 16) | ((uint32_t)u8[0] << 24); -} - -static uint16_t u16in(void) -{ - uint8_t u8[2]; - datain(&u8, 2); - return (uint16_t)u8[1] | ((uint16_t)u8[0] << 8); -} - -static int u8in(void) -{ - uint8_t u8; - datain(&u8, 1); - return u8; -} - -static int ftypin(int size) -{ - enum {BUFSIZE = 40}; - char buf[BUFSIZE]; - uint32_t u32; - - buf[4] = 0; - datain(buf, 4); - u32 = u32in(); - - if (mp4config.verbose.header) - fprintf(stderr, "Brand:\t\t\t%s(version %d)\n", buf, u32); - - stringin(buf, BUFSIZE); - - if (mp4config.verbose.header) - fprintf(stderr, "Compatible brands:\t%s\n", buf); - - return size; -} - -enum -{ SECSINDAY = 24 * 60 * 60 }; -static char *mp4time(time_t t) -{ - int y; - - // subtract some seconds from the start of 1904 to the start of 1970 - for (y = 1904; y < 1970; y++) - { - t -= 365 * SECSINDAY; - if (!(y & 3)) - t -= SECSINDAY; - } - return ctime(&t); -} - -static int mdhdin(int size) -{ - // version/flags - u32in(); - // Creation time - mp4config.ctime = u32in(); - // Modification time - mp4config.mtime = u32in(); - // Time scale - mp4config.samplerate = u32in(); - // Duration - mp4config.samples = u32in(); - // Language - u16in(); - // pre_defined - u16in(); - - return size; -} - -static int hdlr1in(int size) -{ - uint8_t buf[5]; - - buf[4] = 0; - // version/flags - u32in(); - // pre_defined - u32in(); - // Component subtype - datain(buf, 4); - if (mp4config.verbose.header) - fprintf(stderr, "*track media type: '%s': ", buf); - if (memcmp("soun", buf, 4)) - { - if (mp4config.verbose.header) - fprintf(stderr, "unsupported, skipping\n"); - return ERR_UNSUPPORTED; - } - else - { - if (mp4config.verbose.header) - fprintf(stderr, "OK\n"); - } - // reserved - u32in(); - u32in(); - u32in(); - // name - // null terminate - u8in(); - - return size; -} - -static int stsdin(int size) -{ - // version/flags - u32in(); - // Number of entries(one 'mp4a') - if (u32in() != 1) //fixme: error handling - return ERR_FAIL; - - return size; -} - -static int mp4ain(int size) -{ - // Reserved (6 bytes) - u32in(); - u16in(); - // Data reference index - u16in(); - // Version - u16in(); - // Revision level - u16in(); - // Vendor - u32in(); - // Number of channels - mp4config.channels = u16in(); - // Sample size (bits) - mp4config.bits = u16in(); - // Compression ID - u16in(); - // Packet size - u16in(); - // Sample rate (16.16) - // fractional framerate, probably not for audio - // rate integer part - u16in(); - // rate reminder part - u16in(); - - return size; -} - - -static uint32_t getsize(void) -{ - int cnt; - uint32_t size = 0; - for (cnt = 0; cnt < 4; cnt++) - { - int tmp = u8in(); - - size <<= 7; - size |= (tmp & 0x7f); - if (!(tmp & 0x80)) - break; - } - return size; -} - -static int esdsin(int size) -{ - // descriptor tree: - // MP4ES_Descriptor - // MP4DecoderConfigDescriptor - // MP4DecSpecificInfoDescriptor - // MP4SLConfigDescriptor - enum - { TAG_ES = 3, TAG_DC = 4, TAG_DSI = 5, TAG_SLC = 6 }; - - // version/flags - u32in(); - if (u8in() != TAG_ES) - return ERR_FAIL; - getsize(); - // ESID - u16in(); - // flags(url(bit 6); ocr(5); streamPriority (0-4)): - u8in(); - - if (u8in() != TAG_DC) - return ERR_FAIL; - getsize(); - if (u8in() != 0x40) /* not MPEG-4 audio */ - return ERR_FAIL; - // flags - u8in(); - // buffer size (24 bits) - mp4config.buffersize = u16in() << 8; - mp4config.buffersize |= u8in(); - // bitrate - mp4config.bitratemax = u32in(); - mp4config.bitrateavg = u32in(); - - if (u8in() != TAG_DSI) - return ERR_FAIL; - mp4config.asc.size = getsize(); - if (mp4config.asc.size > sizeof(mp4config.asc.buf)) - return ERR_FAIL; - // get AudioSpecificConfig - datain(mp4config.asc.buf, mp4config.asc.size); - - if (u8in() != TAG_SLC) - return ERR_FAIL; - getsize(); - // "predefined" (no idea) - u8in(); - - return size; -} - -/* stbl "Sample Table" layout: - * - stts "Time-to-Sample" - useless - * - stsc "Sample-to-Chunk" - condensed table chunk-to-num-samples - * - stsz "Sample Size" - size table - * - stco "Chunk Offset" - chunk starts - * - * When receiving stco we can combine stsc and stsz tables to produce final - * sample offsets. - */ - -static int sttsin(int size) -{ - uint32_t ntts; - - if (size < 8) - return ERR_FAIL; - - // version/flags - u32in(); - ntts = u32in(); - - if (ntts < 1) - return ERR_FAIL; - - /* 2 x uint32_t per entry */ - if (((size - 8u) / 8u) < ntts) - return ERR_FAIL; - - return size; -} - -static int stscin(int size) -{ - uint32_t i, tmp, firstchunk, prevfirstchunk, samplesperchunk; - - if (size < 8) - return ERR_FAIL; - - // version/flags - u32in(); - - mp4config.frame.nsclices = u32in(); - - tmp = sizeof(slice_info_t) * mp4config.frame.nsclices; - if (tmp < mp4config.frame.nsclices) - return ERR_FAIL; - mp4config.frame.map = malloc(tmp); - if (!mp4config.frame.map) - return ERR_FAIL; - - /* 3 x uint32_t per entry */ - if (((size - 8u) / 12u) < mp4config.frame.nsclices) - return ERR_FAIL; - - prevfirstchunk = 0; - for (i = 0; i < mp4config.frame.nsclices; ++i) { - firstchunk = u32in(); - samplesperchunk = u32in(); - // id - unused - u32in(); - if (firstchunk <= prevfirstchunk) - return ERR_FAIL; - if (samplesperchunk < 1) - return ERR_FAIL; - mp4config.frame.map[i].firstchunk = firstchunk; - mp4config.frame.map[i].samplesperchunk = samplesperchunk; - prevfirstchunk = firstchunk; - } - - return size; -} - -static int stszin(int size) -{ - uint32_t i, tmp; - - if (size < 12) - return ERR_FAIL; - - // version/flags - u32in(); - // (uniform) Sample size - // TODO(eustas): add uniform sample size support? - u32in(); - mp4config.frame.nsamples = u32in(); - - if (!mp4config.frame.nsamples) - return ERR_FAIL; - - tmp = sizeof(frame_info_t) * mp4config.frame.nsamples; - if (tmp < mp4config.frame.nsamples) - return ERR_FAIL; - mp4config.frame.info = malloc(tmp); - if (!mp4config.frame.info) - return ERR_FAIL; - - if ((size - 12u) / 4u < mp4config.frame.nsamples) - return ERR_FAIL; - - for (i = 0; i < mp4config.frame.nsamples; i++) - { - mp4config.frame.info[i].len = u32in(); - mp4config.frame.info[i].offset = 0; - if (mp4config.frame.maxsize < mp4config.frame.info[i].len) - mp4config.frame.maxsize = mp4config.frame.info[i].len; - } - - return size; -} - -static int stcoin(int size) -{ - uint32_t numchunks, chunkn, slicen, samplesleft, i, offset; - uint32_t nextoffset; - - if (size < 8) - return ERR_FAIL; - - // version/flags - u32in(); - - // Number of entries - numchunks = u32in(); - if ((numchunks < 1) || ((numchunks + 1) == 0)) - return ERR_FAIL; - - if ((size - 8u) / 4u < numchunks) - return ERR_FAIL; - - chunkn = 0; - samplesleft = 0; - slicen = 0; - offset = 0; - - for (i = 0; i < mp4config.frame.nsamples; ++i) { - if (samplesleft == 0) - { - chunkn++; - if (chunkn > numchunks) - return ERR_FAIL; - if (slicen < mp4config.frame.nsclices && - (slicen + 1) < mp4config.frame.nsclices) { - if (chunkn == mp4config.frame.map[slicen + 1].firstchunk) - slicen++; - } - samplesleft = mp4config.frame.map[slicen].samplesperchunk; - offset = u32in(); - } - mp4config.frame.info[i].offset = offset; - nextoffset = offset + mp4config.frame.info[i].len; - if (nextoffset < offset) - return ERR_FAIL; - offset = nextoffset; - samplesleft--; - } - - freeMem(&mp4config.frame.map); - - return size; -} - -#if 0 -static int tagtxt(char *tagname, const char *tagtxt) -{ - //int txtsize = strlen(tagtxt); - int size = 0; - //int datasize = txtsize + 16; - -#if 0 - size += u32out(datasize + 8); - size += dataout(tagname, 4); - size += u32out(datasize); - size += dataout("data", 4); - size += u32out(1); - size += u32out(0); - size += dataout(tagtxt, txtsize); -#endif - - return size; -} - -static int tagu32(char *tagname, int n /*number of stored fields*/) -{ - //int numsize = n * 4; - int size = 0; - //int datasize = numsize + 16; - -#if 0 - size += u32out(datasize + 8); - size += dataout(tagname, 4); - size += u32out(datasize); - size += dataout("data", 4); - size += u32out(0); - size += u32out(0); -#endif - - return size; -} -#endif - -static int metain(int size) -{ - (void)size; /* why not used? */ - // version/flags - u32in(); - - return ERR_OK; -} - -static int hdlr2in(int size) -{ - uint8_t buf[4]; - - // version/flags - u32in(); - // Predefined - u32in(); - // Handler type - datain(buf, 4); - if (memcmp(buf, "mdir", 4)) - return ERR_FAIL; - datain(buf, 4); - if (memcmp(buf, "appl", 4)) - return ERR_FAIL; - // Reserved - u32in(); - u32in(); - // null terminator - u8in(); - - return size; -} - -static int ilstin(int size) -{ - enum {NUMSET = 1, GENRE, EXTAG}; - int read = 0; - - static struct { - char *name; - char *id; - int flag; - } tags[] = { - {"Album ", "\xa9" "alb"}, - {"Album Artist", "aART"}, - {"Artist ", "\xa9" "ART"}, - {"Comment ", "\xa9" "cmt"}, - {"Cover image ", "covr"}, - {"Compilation ", "cpil"}, - {"Copyright ", "cprt"}, - {"Date ", "\xa9" "day"}, - {"Disc# ", "disk", NUMSET}, - {"Genre ", "gnre", GENRE}, - {"Grouping ", "\xa9" "grp"}, - {"Lyrics ", "\xa9" "lyr"}, - {"Title ", "\xa9" "nam"}, - {"Rating ", "rtng"}, - {"BPM ", "tmpo"}, - {"Encoder ", "\xa9" "too"}, - {"Track ", "trkn", NUMSET}, - {"Composer ", "\xa9" "wrt"}, - {0, "----", EXTAG}, - {0}, - }; - - static const char *genres[] = { - "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", - "Alternative Rock", "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 US", "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", "Acapella", - "Euro-House", "Dance Hall", "Goa", "Drum & Bass", - "Club - House", "Hardcore", "Terror", "Indie", - "BritPop", "Negerpunk", "Polsk Punk", "Beat", - "Christian Gangsta Rap", "Heavy Metal", "Black Metal", "Crossover", - "Contemporary Christian", "Christian Rock", "Merengue", "Salsa", - "Thrash Metal", "Anime", "JPop", "Synthpop", - "Unknown", - }; - - fprintf(stderr, "----------tag list-------------\n"); - while(read < size) - { - int asize, dsize; - uint8_t id[5]; - int cnt; - uint32_t type; - - id[4] = 0; - - asize = u32in(); - read += asize; - asize -= 4; - if (datain(id, 4) < 4) - return ERR_FAIL; - asize -= 4; - - for (cnt = 0; tags[cnt].id; cnt++) - { - if (!memcmp(id, tags[cnt].id, 4)) - break; - } - - if (tags[cnt].name) - fprintf(stderr, "%s : ", tags[cnt].name); - else - { - if (tags[cnt].flag != EXTAG) - fprintf(stderr, "'%s' : ", id); - } - - dsize = u32in(); - asize -= 4; - if (datain(id, 4) < 4) - return ERR_FAIL; - asize -= 4; - - if (tags[cnt].flag != EXTAG) - { - if (memcmp(id, "data", 4)) - return ERR_FAIL; - } - else - { - int spc; - - if (memcmp(id, "mean", 4)) - goto skip; - dsize -= 8; - while (dsize > 0) - { - u8in(); - asize--; - dsize--; - } - if (asize >= 8) - { - dsize = u32in() - 8; - asize -= 4; - if (datain(id, 4) < 4) - return ERR_FAIL; - asize -= 4; - if (memcmp(id, "name", 4)) - goto skip; - u32in(); - asize -= 4; - dsize -= 4; - } - spc = 13 - dsize; - if (spc < 0) spc = 0; - while (dsize > 0) - { - fprintf(stderr, "%c",u8in()); - asize--; - dsize--; - } - while (spc--) - fprintf(stderr, " "); - fprintf(stderr, ": "); - if (asize >= 8) - { - dsize = u32in() - 8; - asize -= 4; - if (datain(id, 4) < 4) - return ERR_FAIL; - asize -= 4; - if (memcmp(id, "data", 4)) - goto skip; - u32in(); - asize -= 4; - dsize -= 4; - } - while (dsize > 0) - { - fprintf(stderr, "%c",u8in()); - asize--; - dsize--; - } - fprintf(stderr, "\n"); - - goto skip; - } - type = u32in(); - asize -= 4; - u32in(); - asize -= 4; - - switch(type) - { - case 1: - while (asize > 0) - { - fprintf(stderr, "%c",u8in()); - asize--; - } - break; - case 0: - switch(tags[cnt].flag) - { - case NUMSET: - u16in(); - asize -= 2; - - fprintf(stderr, "%d", u16in()); - asize -= 2; - fprintf(stderr, "/%d", u16in()); - asize -= 2; - break; - case GENRE: - { - uint16_t gnum = u16in(); - asize -= 2; - if (!gnum) - goto skip; - gnum--; - if (gnum >= 147) - gnum = 147; - fprintf(stderr, "%s", genres[gnum]); - } - break; - default: - while(asize > 0) - { - fprintf(stderr, "%d/", u16in()); - asize-=2; - } - } - break; - case 0x15: - //fprintf(stderr, "(8bit data)"); - while(asize > 0) - { - fprintf(stderr, "%d", u8in()); - asize--; - if (asize) - fprintf(stderr, "/"); - } - break; - case 0xd: - fprintf(stderr, "(image data)"); - break; - default: - fprintf(stderr, "(unknown data type)"); - break; - } - fprintf(stderr, "\n"); - - skip: - // skip to the end of atom - while (asize > 0) - { - u8in(); - asize--; - } - } - fprintf(stderr, "-------------------------------\n"); - - return size; -} - -static creator_t *g_atom = 0; -static int parse(uint32_t *sizemax) -{ - long apos = 0; - long aposmax = ftell(g_fin) + *sizemax; - uint32_t size; - - if (g_atom->opcode != ATOM_NAME) - { - fprintf(stderr, "parse error: root is not a 'name' opcode\n"); - return ERR_FAIL; - } - //fprintf(stderr, "looking for '%s'\n", (char *)g_atom->name); - - // search for atom in the file - while (1) - { - char name[4]; - uint32_t tmp; - - apos = ftell(g_fin); - if (apos >= (aposmax - 8)) - { - fprintf(stderr, "parse error: atom '%s' not found\n", g_atom->name); - return ERR_FAIL; - } - if ((tmp = u32in()) < 8) - { - fprintf(stderr, "invalid atom size %x @%lx\n", tmp, ftell(g_fin)); - return ERR_FAIL; - } - - size = tmp; - if (datain(name, 4) != 4) - { - // EOF - fprintf(stderr, "can't read atom name @%lx\n", ftell(g_fin)); - return ERR_FAIL; - } - - //fprintf(stderr, "atom: '%c%c%c%c'(%x)", name[0],name[1],name[2],name[3], size); - - if (!memcmp(name, g_atom->name, 4)) - { - //fprintf(stderr, "OK\n"); - break; - } - //fprintf(stderr, "\n"); - - fseek(g_fin, apos + size, SEEK_SET); - } - *sizemax = size; - g_atom++; - if (g_atom->opcode == ATOM_DATA) - { - int err = g_atom->parse(size - 8); - if (err < ERR_OK) - { - fseek(g_fin, apos + size, SEEK_SET); - return err; - } - g_atom++; - } - if (g_atom->opcode == ATOM_DESCENT) - { - long apos2 = ftell(g_fin); - - //fprintf(stderr, "descent\n"); - g_atom++; - while (g_atom->opcode != ATOM_STOP) - { - uint32_t subsize = size - 8; - int ret; - if (g_atom->opcode == ATOM_ASCENT) - { - g_atom++; - break; - } - // TODO: does not feel well - we always return to the same point! - fseek(g_fin, apos2, SEEK_SET); - if ((ret = parse(&subsize)) < 0) - return ret; - } - //fprintf(stderr, "ascent\n"); - } - - fseek(g_fin, apos + size, SEEK_SET); - - return ERR_OK; -} - -static int moovin(int sizemax) -{ - long apos = ftell(g_fin); - uint32_t atomsize; - creator_t *old_atom = g_atom; - int err, ret = sizemax; - - static creator_t mvhd[] = { - NAME("mvhd"), - STOP() - }; - static creator_t trak[] = { - NAME("trak"), - DESCENT(), - NAME("tkhd"), - NAME("mdia"), - DESCENT(), - DATA("mdhd", mdhdin), - DATA("hdlr", hdlr1in), - NAME("minf"), - DESCENT(), - NAME("smhd"), - NAME("dinf"), - NAME("stbl"), - DESCENT(), - DATA("stsd", stsdin), - DESCENT(), - DATA("mp4a", mp4ain), - DESCENT(), - DATA("esds", esdsin), - ASCENT(), - ASCENT(), - DATA("stts", sttsin), - DATA("stsc", stscin), - DATA("stsz", stszin), - DATA("stco", stcoin), - STOP() - }; - - g_atom = mvhd; - atomsize = sizemax + apos - ftell(g_fin); - if (parse(&atomsize) < 0) { - g_atom = old_atom; - return ERR_FAIL; - } - - fseek(g_fin, apos, SEEK_SET); - - while (1) - { - //fprintf(stderr, "TRAK\n"); - g_atom = trak; - atomsize = sizemax + apos - ftell(g_fin); - if (atomsize < 8) - break; - //fprintf(stderr, "PARSE(%x)\n", atomsize); - err = parse(&atomsize); - //fprintf(stderr, "SIZE: %x/%x\n", atomsize, sizemax); - if (err >= 0) - break; - if (err != ERR_UNSUPPORTED) { - ret = err; - break; - } - //fprintf(stderr, "UNSUPP\n"); - } - - g_atom = old_atom; - return ret; -} - - -static creator_t g_head[] = { - DATA("ftyp", ftypin), - STOP() -}; - -static creator_t g_moov[] = { - DATA("moov", moovin), - //DESCENT(), - //NAME("mvhd"), - STOP() -}; - -static creator_t g_meta1[] = { - NAME("moov"), - DESCENT(), - NAME("udta"), - DESCENT(), - DATA("meta", metain), - DESCENT(), - DATA("hdlr", hdlr2in), - DATA("ilst", ilstin), - STOP() -}; - -static creator_t g_meta2[] = { - DATA("meta", metain), - DESCENT(), - DATA("hdlr", hdlr2in), - DATA("ilst", ilstin), - STOP() -}; - - -int mp4read_frame(void) -{ - if (mp4config.frame.current >= mp4config.frame.nsamples) - return ERR_FAIL; - - // TODO(eustas): avoid no-op seeks - mp4read_seek(mp4config.frame.current); - - mp4config.bitbuf.size = mp4config.frame.info[mp4config.frame.current].len; - - if (fread(mp4config.bitbuf.data, 1, mp4config.bitbuf.size, g_fin) - != mp4config.bitbuf.size) - { - fprintf(stderr, "can't read frame data(frame %d@0x%x)\n", - mp4config.frame.current, - mp4config.frame.info[mp4config.frame.current].offset); - - return ERR_FAIL; - } - - mp4config.frame.current++; - - return ERR_OK; -} - -int mp4read_seek(uint32_t framenum) -{ - if (framenum > mp4config.frame.nsamples) - return ERR_FAIL; - if (fseek(g_fin, mp4config.frame.info[framenum].offset, SEEK_SET)) - return ERR_FAIL; - - mp4config.frame.current = framenum; - - return ERR_OK; -} - -static void mp4info(void) -{ - fprintf(stderr, "Modification Time:\t\t%s\n", mp4time(mp4config.mtime)); - fprintf(stderr, "Samplerate:\t\t%d\n", mp4config.samplerate); - fprintf(stderr, "Total samples:\t\t%d\n", mp4config.samples); - fprintf(stderr, "Total channels:\t\t%d\n", mp4config.channels); - fprintf(stderr, "Bits per sample:\t%d\n", mp4config.bits); - fprintf(stderr, "Buffer size:\t\t%d\n", mp4config.buffersize); - fprintf(stderr, "Max bitrate:\t\t%d\n", mp4config.bitratemax); - fprintf(stderr, "Average bitrate:\t%d\n", mp4config.bitrateavg); - fprintf(stderr, "Frames:\t\t\t%d\n", mp4config.frame.nsamples); - fprintf(stderr, "ASC size:\t\t%d\n", mp4config.asc.size); - fprintf(stderr, "Duration:\t\t%.1f sec\n", (float)mp4config.samples/mp4config.samplerate); - if (mp4config.frame.nsamples) - fprintf(stderr, "Data offset:\t%x\n", mp4config.frame.info[0].offset); -} - -int mp4read_close(void) -{ - freeMem(&mp4config.frame.info); - freeMem(&mp4config.frame.map); - freeMem(&mp4config.bitbuf.data); - - return ERR_OK; -} - -int mp4read_open(char *name) -{ - uint32_t atomsize; - int ret; - - mp4read_close(); - - g_fin = faad_fopen(name, "rb"); - if (!g_fin) - return ERR_FAIL; - - if (mp4config.verbose.header) - fprintf(stderr, "**** MP4 header ****\n"); - g_atom = g_head; - atomsize = INT_MAX; - if (parse(&atomsize) < 0) - goto err; - g_atom = g_moov; - atomsize = INT_MAX; - rewind(g_fin); - if ((ret = parse(&atomsize)) < 0) - { - fprintf(stderr, "parse:%d\n", ret); - goto err; - } - - // alloc frame buffer - mp4config.bitbuf.data = malloc(mp4config.frame.maxsize); - - if (!mp4config.bitbuf.data) - goto err; - - if (mp4config.verbose.header) - { - mp4info(); - fprintf(stderr, "********************\n"); - } - - if (mp4config.verbose.tags) - { - rewind(g_fin); - g_atom = g_meta1; - atomsize = INT_MAX; - ret = parse(&atomsize); - if (ret < 0) - { - rewind(g_fin); - g_atom = g_meta2; - atomsize = INT_MAX; - ret = parse(&atomsize); - } - } - - return ERR_OK; -err: - mp4read_close(); - return ERR_FAIL; -} |
