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; }
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_drms(mp4ff_t *f, uint64_t skip) { uint64_t size; int32_t i; uint8_t atom_type = 0; uint8_t header_size = 0; f->track[f->total_tracks - 1]->p_drms = drms_alloc( GetHomeDir() ); 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); } mp4ff_set_position(f, skip+size+28); size = mp4ff_atom_read_header(f, &atom_type, &header_size); if (atom_type == ATOM_SINF) { parse_sub_atoms(f, size-header_size,0); } return 0; }
/* parse root atoms */ static int32_t parse_atoms_int (mp4ff_t *f,int meta_only,int stop_on_mdat) { uint64_t size; uint8_t atom_type = 0; uint8_t header_size = 0; int had_valid_atoms = 0; f->file_size = 0; while ((size = mp4ff_atom_read_header(f, &atom_type, &header_size)) != 0) { // FIXME: ATOM_UNKNOWN is returned both when a valid (but unknown) atom is encontered, // and for invalid data. They need to be handled separately. if (atom_type == ATOM_UNKNOWN && !had_valid_atoms && mp4ff_position(f)+size > 100) { return -1; } had_valid_atoms = 1; 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 */ if (!stop_on_mdat) { 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_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); mp4ff_parse_tag(f, atom_type, (uint32_t)(subsize-header_size)); sumsize += subsize; } return 0; }
/* 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); } #if 0 if (atom_type == ATOM_TRAK) { trace ("mp4ff_track_create_chunks_index\n"); mp4ff_track_create_chunks_index (f, f->track[f->total_tracks-1]); trace ("mp4ff_track_create_samples_index\n"); mp4ff_track_create_samples_index (f, f->track[f->total_tracks-1]); } #endif } 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_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; if (atom_type == ATOM_UNKNOWN) mp4ff_set_position(f, mp4ff_position(f)+subsize-header_size); else mp4ff_parse_tag(f, atom_type, (uint32_t)(subsize-header_size)); sumsize += subsize; } 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) { uint16_t index,total; char temp[32]; mp4ff_read_int16(f); index = mp4ff_read_int16(f); total = mp4ff_read_int16(f); 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; }