/* 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; }
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); if (!(*audio_buffer)) { //fprintf (stderr, "mp4ff_read_sample: malloc failure (tried to alloc %d bytes). possible mp4ff bug or memleak! please report a bug to deadbeef developers (i'm serious).\n", *bytes); return 0; } 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(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; }
uint16_t mp4ff_read_int16(mp4ff_t *f) { uint32_t result; uint32_t a, b; uint8_t data[2]; mp4ff_read_data(f, data, 2); a = data[0]; b = data[1]; result = (a<<8) | b; return (uint16_t)result; }
uint32_t mp4ff_read_int24(mp4ff_t *f) { uint32_t result; uint32_t a, b, c; uint8_t data[4]; mp4ff_read_data(f, data, 3); a = data[0]; b = data[1]; c = data[2]; result = (a<<16) | (b<<8) | c; return (uint32_t)result; }
uint64_t mp4ff_read_int64(mp4ff_t *f) { uint8_t data[8]; uint64_t result = 0; int 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; uint8_t data[4]; mp4ff_read_data(f, data, 4); a = data[0]; b = data[1]; c = data[2]; d = data[3]; result = (a<<24) | (b<<16) | (c<<8) | d; return (uint32_t)result; }
static int32_t mp4ff_read_key(mp4ff_t *f, uint64_t size) { uint8_t *data = malloc(size); mp4ff_read_data(f, data, size); if (f->track[f->total_tracks - 1]->p_drms != 0) { drms_init(f->track[f->total_tracks - 1]->p_drms, FOURCC_key, data, size ); } if (data) free(data); return 0; }
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; }
char * mp4ff_read_string(mp4ff_t * f,uint32_t length) { char * str = malloc(length + 1); if (str!=0) { if ((uint32_t)mp4ff_read_data(f,(uint8_t *)str,length)!=length) { free(str); str = 0; } else { str[length] = 0; } } return str; }
static int32_t mp4ff_read_frma(mp4ff_t *f) { uint8_t atom_type; int8_t type[4]; mp4ff_read_data(f, type, 4); atom_type = mp4ff_atom_name_to_type(type[0], type[1], type[2], type[3]); if (atom_type == ATOM_MP4A) { f->track[f->total_tracks - 1]->type = TRACK_AUDIO; } 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; } 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; }
uint8_t mp4ff_read_char(mp4ff_t *f) { uint8_t output; mp4ff_read_data(f, &output, 1); return output; }
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 (parent_atom_type == ATOM_COVER) { if (data) { free(data); data = NULL; } if (f->load_covers) { uint32_t datasize = (uint32_t)(subsize-(header_size+8)); data = malloc(datasize); if (!data) { // allocation error } else if (datasize != mp4ff_read_data(f, data, datasize)) { free (data); data = NULL; } else { mp4ff_cover_append_item (f, data, datasize); data = NULL; } } } 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; }