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; }
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_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_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) { trace ("mp4ff_read_stsc\n"); 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_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; }
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; }
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; }
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_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; }
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_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; }
static int32_t mp4ff_read_chpl(mp4ff_t *f, const uint64_t size) { int i; int i_read = size; mp4ff_read_char(f); /* version */ mp4ff_read_int24(f); /* flags */ mp4ff_chapterdata_t *p_chpl = &f->chapters; p_chpl->i_chapter = mp4ff_read_char (f); i_read -= 5; for( i = 0; i < p_chpl->i_chapter; i++ ) { uint64_t i_start; uint8_t i_len; int i_copy; i_start = mp4ff_read_int64 (f); i_read -= 8; i_len = mp4ff_read_char (f); i_read -= 1; p_chpl->chapter[i].psz_name = malloc( i_len + 1 ); if( !p_chpl->chapter[i].psz_name ) goto error; i_copy = i_len < i_read ? i_len : i_read; if( i_copy > 0 ) mp4ff_read_data (f, p_chpl->chapter[i].psz_name, i_copy); p_chpl->chapter[i].psz_name[i_copy] = '\0'; p_chpl->chapter[i].i_start = i_start; i_read -= i_copy; } /* Bubble sort by increasing start date */ do { for( i = 0; i < p_chpl->i_chapter - 1; i++ ) { if( p_chpl->chapter[i].i_start > p_chpl->chapter[i+1].i_start ) { char *psz = p_chpl->chapter[i+1].psz_name; int64_t i64 = p_chpl->chapter[i+1].i_start; p_chpl->chapter[i+1].psz_name = p_chpl->chapter[i].psz_name; p_chpl->chapter[i+1].i_start = p_chpl->chapter[i].i_start; p_chpl->chapter[i].psz_name = psz; p_chpl->chapter[i].i_start = i64; i = -1; break; } } } while( i == -1 ); return 0; error: return -1; }