void mp4_read_close(struct mp4_read_struct *p) { mp4_file_close(&p->file); if (!(p->video_handle < 0)) sceIoClose(p->video_handle); if (!(p->audio_handle < 0)) sceIoClose(p->audio_handle); if (p->video_buffer_0 != 0) free_64(p->video_buffer_0); if (p->video_buffer_1 != 0) free_64(p->video_buffer_1); if (p->audio_buffer_0 != 0) free_64(p->audio_buffer_0); if (p->audio_buffer_1 != 0) free_64(p->audio_buffer_1); if (p->audio_cache_buffer != 0) free_64(p->audio_cache_buffer); mp4_read_safe_constructor(p); }
char *mp4_file_open(struct mp4_file_struct *p, char *s) { mp4_file_safe_constructor(p); p->info = mp4info_open(s); if (p->info == 0){ mp4_file_close(p); return("mp4_file_open: can't open file"); } int i; for(i = 0; i < p->info->total_tracks; i++) { mp4info_track_t* track = p->info->tracks[i]; if (track->type != MP4_TRACK_VIDEO) continue; if ( track->width < 1 || track->height < 1 ) continue; if ( track->width > 720 || track->height > 480 ) continue; if ( track->video_type == 0x61766331 /*avc1*/) { if ( track->avc_profile==0x42 && (track->width > 480 || track->height > 272) ) continue; } else { if ( track->width > 480 || track->height > 272 ) continue; } p->video_track_id = i; p->video_type = track->video_type; if ( p->video_type == 0x61766331 ) { p->avc_profile = track->avc_profile; p->avc_sps_size = track->avc_sps_size; p->avc_pps_size = track->avc_pps_size; p->avc_nal_prefix_size = track->avc_nal_prefix_size; p->avc_sps = malloc_64(p->avc_sps_size); if ( ! p->avc_sps ) { mp4_file_close(p); return("mp4_file_open: can't malloc avc_sps buffer"); } memcpy(p->avc_sps, track->avc_sps, p->avc_sps_size); p->avc_pps = malloc_64(p->avc_pps_size); if ( ! p->avc_pps ) { mp4_file_close(p); return("mp4_file_open: can't malloc avc_pps buffer"); } memcpy(p->avc_pps, track->avc_pps, p->avc_pps_size); } else { p->mp4v_decinfo_size = track->mp4v_decinfo_size; p->mp4v_decinfo = malloc_64(p->mp4v_decinfo_size); if ( ! p->mp4v_decinfo ) { mp4_file_close(p); return("mp4_file_open: can't malloc mp4v_decinfo buffer"); } memcpy(p->mp4v_decinfo, track->mp4v_decinfo, p->mp4v_decinfo_size); } break; } if ( p->video_track_id < 0 ) { mp4_file_close(p); return("mp4_file_open: can't found video track in mp4 file"); } for(i = 0; i < p->info->total_tracks; i++) { mp4info_track_t* track = p->info->tracks[i]; if (track->type != MP4_TRACK_AUDIO) continue; if ( p->audio_tracks == 0 ) { if ( track->audio_type != 0x6D703461 && track->audio_type != 0x73616D72 ) continue; // if ( track->channels != 2 ) // continue; if ( track->samplerate != 8000 && track->samplerate != 22050 && track->samplerate != 24000 && track->samplerate != 44100 && track->samplerate != 48000 ) continue; // if ( track->samplebits != 16 ) // continue; p->audio_tracks++; p->audio_track_ids[p->audio_tracks-1] = i; p->audio_type = track->audio_type; if ( track->samplerate == 22050 || track->samplerate == 24000 ) p->audio_up_sample = 1; else if ( track->samplerate == 8000 ) p->audio_up_sample = 5; } else { mp4info_track_t* old_track = p->info->tracks[p->audio_track_ids[p->audio_tracks-1]]; if ( old_track->audio_type != track->audio_type ) continue; // if ( old_track->channels != track->channels ) // continue; if ( old_track->samplerate != track->samplerate ) continue; // if ( old_track->samplebits != track->samplebits ) // continue; p->audio_tracks++; p->audio_track_ids[p->audio_tracks-1] = i; } if ( p->audio_tracks == 6 ) break; } if ( p->audio_tracks == 0 ) { mp4_file_close(p); return("mp4_file_open: can't found audio track in mp4 file"); } // int sample_id = 0; // unsigned int trunk_size = 0; // int j, k; // // mp4info_track_t* video_track = p->info->tracks[p->video_track_id]; // for( i = 0; i < video_track->stsc_entry_count-1; i++ ) { // int trunk_num = video_track->stsc_first_chunk[i+1] - video_track->stsc_first_chunk[i]; // for( j = 0; j < trunk_num; j++ ) { // trunk_size = 0; // for( k = 0; k < video_track->stsc_samples_per_chunk[i]; k++, sample_id++) { // unsigned int sample_size = (video_track->stsz_sample_size ? video_track->stsz_sample_size : video_track->stsz_sample_size_table[sample_id]); // if ( sample_size > p->maximum_video_sample_size ) // p->maximum_video_sample_size = sample_size; // trunk_size += sample_size; // } // if ( trunk_size > p->maximum_video_trunk_size ) // p->maximum_video_trunk_size = trunk_size; // } // } // trunk_size = 0; // for( k = 0; k < video_track->stsc_samples_per_chunk[i]; k++, sample_id++) // trunk_size += (video_track->stsz_sample_size ? video_track->stsz_sample_size : video_track->stsz_sample_size_table[sample_id]); // if ( trunk_size > p->maximum_video_trunk_size ) // p->maximum_video_trunk_size = trunk_size; // // int l; // for( l = 0; l < p->audio_tracks; l++ ) { // sample_id = 0; // mp4info_track_t* audio_track = p->info->tracks[p->audio_track_ids[l]]; // for( i = 0; i < audio_track->stsc_entry_count-1; i++ ) { // int trunk_num = audio_track->stsc_first_chunk[i+1] - audio_track->stsc_first_chunk[i]; // for( j = 0; j < trunk_num; j++ ) { // trunk_size = 0; // for( k = 0; k < audio_track->stsc_samples_per_chunk[i]; k++, sample_id++) { // unsigned int sample_size = (audio_track->stsz_sample_size ? audio_track->stsz_sample_size : audio_track->stsz_sample_size_table[sample_id]); // if ( sample_size > p->maximum_audio_sample_size ) // p->maximum_audio_sample_size = sample_size; // trunk_size += sample_size; // } // if ( trunk_size > p->maximum_audio_trunk_size ) // p->maximum_audio_trunk_size = trunk_size; // } // } // trunk_size = 0; // for( k = 0; k < audio_track->stsc_samples_per_chunk[i]; k++, sample_id++) { // unsigned int sample_size = (audio_track->stsz_sample_size ? audio_track->stsz_sample_size : audio_track->stsz_sample_size_table[sample_id]); // if ( sample_size > p->maximum_audio_sample_size ) // p->maximum_audio_sample_size = sample_size; // trunk_size += sample_size; // } // if ( trunk_size > p->maximum_audio_trunk_size ) // p->maximum_audio_trunk_size = trunk_size; // } p->video_width = p->info->tracks[p->video_track_id]->width; p->video_height = p->info->tracks[p->video_track_id]->height; p->number_of_video_frames = 0; for( i = 0; i < p->info->tracks[p->video_track_id]->stts_entry_count; i++) p->number_of_video_frames += p->info->tracks[p->video_track_id]->stts_sample_count[i]; //p->number_of_video_frames = p->info->tracks[p->video_track_id]->stts_sample_count[0]; p->video_rate = p->info->tracks[p->video_track_id]->time_scale; p->video_scale = p->info->tracks[p->video_track_id]->duration / p->number_of_video_frames; //p->video_scale = p->info->tracks[p->video_track_id]->stts_sample_duration[0]; p->audio_actual_rate = p->info->tracks[p->audio_track_ids[0]]->samplerate; p->audio_rate = p->audio_actual_rate * (p->audio_up_sample+1) ; p->audio_scale = (p->audio_type == 0x6D703461 ? 1024 : 160); p->audio_resample_scale = p->audio_scale * (p->audio_up_sample+1); p->audio_stereo = 1; int64_t v0 = p->video_rate * p->audio_resample_scale; int64_t v1 = p->audio_rate * p->video_scale; if (v0 >= v1) p->video_audio_interval = (int)(v0 / v1); else p->video_audio_interval = (int)(-(v1/v0)); return(mp4_file_build_index(p)); }
char *mp4_file_build_index(struct mp4_file_struct *p) { int i,j; unsigned int ui; unsigned int trunk[MP4_MAX_TRACKS]; unsigned int current_sample = 0; unsigned int current_index = 0; mp4info_track_t* v_track = p->info->tracks[p->video_track_id]; mp4info_track_t* a_track = p->info->tracks[p->audio_track_ids[0]]; if ( (v_track->stco_chunk_offset[v_track->stco_entry_count-1] < a_track->stco_chunk_offset[0]) || (v_track->stco_chunk_offset[0] > a_track->stco_chunk_offset[a_track->stco_entry_count-1]) ) { if ( p->info->total_tracks > 2 ) { mp4_file_close(p); return("mp4_file_open: can't support this file"); } else p->is_not_interlace = 1; } for(i=0; i<p->info->total_tracks; i++) { p->sample_count += mp4_get_sample_count(p->info->tracks[i]); } p->index_count = p->info->tracks[p->video_track_id]->stss_entry_count; p->samples = malloc_64(p->sample_count * sizeof(struct mp4_sample_struct)); if ( !p->samples ) { mp4_file_close(p); return("mp4_file_open: can't malloc samples buffer"); } p->indexes = malloc_64(p->index_count * sizeof(struct mp4_index_struct)); if ( !p->indexes ) { mp4_file_close(p); return("mp4_file_open: can't malloc indexes buffer"); } for(i=0; i<MP4_MAX_TRACKS; i++) trunk[i] = 0; while(1) { int current_track = 0; unsigned int min_offset = 0xFFFFFFFF; unsigned int current_offset = 0xFFFFFFFF; unsigned int first_sample = 0; unsigned int last_sample = 0; for(i=0; i<p->info->total_tracks; i++) { current_offset = mp4_get_trunk_offset(p->info->tracks[i], trunk[i]); if ( current_offset < min_offset ) { min_offset = current_offset; current_track = i; } } if ( 0xFFFFFFFF == min_offset ) break; mp4info_track_t* track = p->info->tracks[current_track]; for( i = 0; i < track->stsc_entry_count-1; i++ ) { if ( (trunk[current_track]+1) >= track->stsc_first_chunk[i] && (trunk[current_track]+1) < track->stsc_first_chunk[i+1] ) break; } for( j = 0; j < i; j++ ) { first_sample += ( ( track->stsc_first_chunk[j+1] - track->stsc_first_chunk[j] ) * track->stsc_samples_per_chunk[j] ); } first_sample += ( ( (trunk[current_track]+1) - track->stsc_first_chunk[i] ) * track->stsc_samples_per_chunk[i] ); last_sample = first_sample + track->stsc_samples_per_chunk[i] - 1; for(ui = first_sample; ui <= last_sample; ui++) { p->samples[current_sample].sample_index = (current_track << 24) | (ui & 0x00FFFFFF); p->samples[current_sample].sample_size = mp4_get_sample_size(track, ui); if ( current_track == p->video_track_id ) { if ( 0xFFFFFFFF == p->first_video_offset) { p->first_video_offset = min_offset; p->first_video_sample = current_sample; } if ( p->samples[current_sample].sample_size > p->maximum_video_sample_size) { p->maximum_video_sample_size = p->samples[current_sample].sample_size; } if ( mp4_is_keyframe(track, ui) ) { uint64_t timestamp = 1000LL; timestamp *= ui; timestamp *= p->video_scale; timestamp /= p->video_rate; p->indexes[current_index].timestamp = timestamp; p->indexes[current_index].sample_index = current_sample; p->indexes[current_index].offset = min_offset; current_index++; } } else if ( current_track == p->audio_track_ids[0] ) { if ( 0xFFFFFFFF == p->first_audio_offset) { p->first_audio_offset = min_offset; p->first_audio_sample = current_sample; } } min_offset += p->samples[current_sample].sample_size; current_sample++; } trunk[current_track] += 1; } if ( !p->is_not_interlace ) { for(i = 0; i < p->info->total_tracks; i++) { mp4info_track_t* track = p->info->tracks[i]; if (track->type != MP4_TRACK_SUBTITLE) continue; p->subtitle_tracks++; p->subtitle_track_ids[p->subtitle_tracks-1] = i; p->subtitle_track_time_count[p->subtitle_tracks-1] = track->stts_entry_count; p->subtitle_track_time[p->subtitle_tracks-1] = malloc_64(track->stts_entry_count*2*sizeof(unsigned int)); if ( !p->subtitle_track_time[p->subtitle_tracks-1] ) { p->subtitle_tracks--; break; } else { for(j=0; j<track->stts_entry_count;j++) { p->subtitle_track_time[p->subtitle_tracks-1][2*j] = track->stts_sample_count[j]; p->subtitle_track_time[p->subtitle_tracks-1][2*j+1] = track->stts_sample_duration[j]; } } if ( p->subtitle_tracks == 4 ) break; } } mp4info_close(p->info); p->info = 0; return(0); }