www.pudn.com > NETVIDEO.rar > libmpeg3.c
#include "libmpeg3.h" #include "mpeg3protos.h" #include#include #include #ifndef MAX #define MAX(a, b) ((a) > (b) ? (a) : (b)) #endif mpeg3_t* mpeg3_new(const char *path) { int i; mpeg3_t *file = calloc(1, sizeof(mpeg3_t)); file->cpus = 1; file->fs = mpeg3_new_fs(path); file->demuxer = mpeg3_new_demuxer(file, 0, 0, -1); file->seekable = 1; return file; } int mpeg3_delete(mpeg3_t *file) { int i; for(i = 0; i < file->total_vstreams; i++) mpeg3_delete_vtrack(file, file->vtrack[i]); for(i = 0; i < file->total_astreams; i++) mpeg3_delete_atrack(file, file->atrack[i]); mpeg3_delete_fs(file->fs); mpeg3_delete_demuxer(file->demuxer); if(file->frame_offsets) { for(i = 0; i < file->total_vstreams; i++) { free(file->frame_offsets[i]); free(file->keyframe_numbers[i]); } free(file->frame_offsets); free(file->keyframe_numbers); free(file->total_frame_offsets); free(file->total_keyframe_numbers); } if(file->sample_offsets) { for(i = 0; i < file->total_astreams; i++) free(file->sample_offsets[i]); free(file->sample_offsets); free(file->total_sample_offsets); } free(file); return 0; } int mpeg3_check_sig(const char *path) { mpeg3_fs_t *fs; u_int32_t bits; char *ext; int result = 0; fs = mpeg3_new_fs(path); if(mpeg3io_open_file(fs)) { /* File not found */ return 0; } bits = mpeg3io_read_int32(fs); /* Test header */ if(bits == MPEG3_TOC_PREFIX) { result = 1; } else if((((bits >> 24) & 0xff) == MPEG3_SYNC_BYTE) || (bits == MPEG3_PACK_START_CODE) || ((bits & 0xfff00000) == 0xfff00000) || ((bits & 0xffff0000) == 0xffe30000) || (bits == MPEG3_SEQUENCE_START_CODE) || (bits == MPEG3_PICTURE_START_CODE) || (((bits & 0xffff0000) >> 16) == MPEG3_AC3_START_CODE) || ((bits >> 8) == MPEG3_ID3_PREFIX) || (bits == MPEG3_RIFF_CODE) || (bits == MPEG3_IFO_PREFIX)) { result = 1; ext = strrchr(path, '.'); if(ext) { /* Test file extension. */ if(strncasecmp(ext, ".ifo", 4) && strncasecmp(ext, ".mp2", 4) && strncasecmp(ext, ".mp3", 4) && strncasecmp(ext, ".m1v", 4) && strncasecmp(ext, ".m2v", 4) && strncasecmp(ext, ".m2s", 4) && strncasecmp(ext, ".mpg", 4) && strncasecmp(ext, ".vob", 4) && strncasecmp(ext, ".mpeg", 4) && strncasecmp(ext, ".ac3", 4)) result = 0; } } mpeg3io_close_file(fs); mpeg3_delete_fs(fs); return result; } static uint32_t read_int32(unsigned char *buffer, int *position) { uint32_t temp; if(MPEG3_LITTLE_ENDIAN) { ((unsigned char*)&temp)[3] = buffer[(*position)++]; ((unsigned char*)&temp)[2] = buffer[(*position)++]; ((unsigned char*)&temp)[1] = buffer[(*position)++]; ((unsigned char*)&temp)[0] = buffer[(*position)++]; } else { ((unsigned char*)&temp)[0] = buffer[(*position)++]; ((unsigned char*)&temp)[1] = buffer[(*position)++]; ((unsigned char*)&temp)[2] = buffer[(*position)++]; ((unsigned char*)&temp)[3] = buffer[(*position)++]; } return temp; } static uint64_t read_int64(unsigned char *buffer, int *position) { uint64_t temp; if(MPEG3_LITTLE_ENDIAN) { ((unsigned char*)&temp)[7] = buffer[(*position)++]; ((unsigned char*)&temp)[6] = buffer[(*position)++]; ((unsigned char*)&temp)[5] = buffer[(*position)++]; ((unsigned char*)&temp)[4] = buffer[(*position)++]; ((unsigned char*)&temp)[3] = buffer[(*position)++]; ((unsigned char*)&temp)[2] = buffer[(*position)++]; ((unsigned char*)&temp)[1] = buffer[(*position)++]; ((unsigned char*)&temp)[0] = buffer[(*position)++]; } else { ((unsigned char*)&temp)[0] = buffer[(*position)++]; ((unsigned char*)&temp)[1] = buffer[(*position)++]; ((unsigned char*)&temp)[2] = buffer[(*position)++]; ((unsigned char*)&temp)[3] = buffer[(*position)++]; ((unsigned char*)&temp)[4] = buffer[(*position)++]; ((unsigned char*)&temp)[5] = buffer[(*position)++]; ((unsigned char*)&temp)[6] = buffer[(*position)++]; ((unsigned char*)&temp)[7] = buffer[(*position)++]; } return temp; } static int read_toc(mpeg3_t *file) { unsigned char *buffer; int file_type; int position = 4; int stream_type; int atracks; int vtracks; int i, j; buffer = malloc(mpeg3io_total_bytes(file->fs)); mpeg3io_seek(file->fs, 0); mpeg3io_read_data(buffer, mpeg3io_total_bytes(file->fs), file->fs); //printf("read_toc %lld\n", mpeg3io_total_bytes(file->fs)); // File type file_type = buffer[position++]; switch(file_type) { case FILE_TYPE_PROGRAM: file->is_program_stream = 1; break; case FILE_TYPE_TRANSPORT: file->is_transport_stream = 1; break; case FILE_TYPE_AUDIO: file->is_audio_stream = 1; break; case FILE_TYPE_VIDEO: file->is_video_stream = 1; break; } // Stream ID's while((stream_type = buffer[position]) != TITLE_PATH) { int offset; int stream_id; //printf("read_toc %d %x\n", position, buffer[position]); position++; offset = read_int32(buffer, &position); stream_id = read_int32(buffer, &position); if(stream_type == STREAM_AUDIO) { file->demuxer->astream_table[offset] = stream_id; } if(stream_type == STREAM_VIDEO) { file->demuxer->vstream_table[offset] = stream_id; } } // Titles while(buffer[position] == TITLE_PATH) { char string[MPEG3_STRLEN]; int string_len = 0; mpeg3_title_t *title; position++; while(buffer[position] != 0) string[string_len++] = buffer[position++]; string[string_len++] = 0; position++; title = file->demuxer->titles[file->demuxer->total_titles++] = mpeg3_new_title(file, string); title->total_bytes = read_int64(buffer, &position); // Cells title->timecode_table_size = title->timecode_table_allocation = read_int32(buffer, &position); title->timecode_table = calloc(title->timecode_table_size, sizeof(mpeg3demux_timecode_t)); for(i = 0; i < title->timecode_table_size; i++) { title->timecode_table[i].start_byte = read_int64(buffer, &position); title->timecode_table[i].end_byte = read_int64(buffer, &position); title->timecode_table[i].program = read_int32(buffer, &position); } } // Audio streams // Skip ATRACK_COUNT position++; atracks = read_int32(buffer, &position); // Skip VTRACK_COUNT position++; vtracks = read_int32(buffer, &position); if(atracks) { file->sample_offsets = malloc(sizeof(int64_t*) * atracks); file->total_sample_offsets = malloc(sizeof(int*) * atracks); for(i = 0; i < atracks; i++) { file->total_sample_offsets[i] = read_int32(buffer, &position); file->sample_offsets[i] = malloc(file->total_sample_offsets[i] * sizeof(int64_t)); for(j = 0; j < file->total_sample_offsets[i]; j++) { file->sample_offsets[i][j] = read_int64(buffer, &position); //printf("samples %llx\n", file->sample_offsets[i][j]); } } } if(vtracks) { file->frame_offsets = malloc(sizeof(int64_t*) * vtracks); file->total_frame_offsets = malloc(sizeof(int*) * vtracks); file->keyframe_numbers = malloc(sizeof(int64_t*) * vtracks); file->total_keyframe_numbers = malloc(sizeof(int*) * vtracks); for(i = 0; i < vtracks; i++) { file->total_frame_offsets[i] = read_int32(buffer, &position); file->frame_offsets[i] = malloc(file->total_frame_offsets[i] * sizeof(int64_t)); for(j = 0; j < file->total_frame_offsets[i]; j++) { file->frame_offsets[i][j] = read_int64(buffer, &position); //printf("frame %llx\n", file->frame_offsets[i][j]); } file->total_keyframe_numbers[i] = read_int32(buffer, &position); file->keyframe_numbers[i] = malloc(file->total_keyframe_numbers[i] * sizeof(int64_t)); for(j = 0; j < file->total_keyframe_numbers[i]; j++) { file->keyframe_numbers[i][j] = read_int64(buffer, &position); } } } free(buffer); //printf("read_toc 1\n"); mpeg3demux_open_title(file->demuxer, 0); //printf("read_toc 2 %llx\n", mpeg3demux_tell(file->demuxer)); return 0; } mpeg3_t* mpeg3_open_copy(const char *path, mpeg3_t *old_file) { mpeg3_t *file = 0; unsigned int bits; int i, done; /* Initialize the file structure */ file = mpeg3_new(path); //printf("mpeg3_open_copy %s\n", path); /* Need to perform authentication before reading a single byte. */ if(mpeg3io_open_file(file->fs)) { mpeg3_delete(file); return 0; } /* =============================== Create the title objects ========================= */ bits = mpeg3io_read_int32(file->fs); //printf("mpeg3_open 1 %p %d %d %d %d\n", old_file, file->is_transport_stream, file->is_program_stream, file->is_video_stream, file->is_audio_stream); if(bits == MPEG3_TOC_PREFIX) /* TOC */ { /* Table of contents for another title set */ if(!old_file) { //printf("libmpeg3 1\n"); if(read_toc(file)) { //printf("libmpeg3 1\n"); mpeg3io_close_file(file->fs); mpeg3_delete(file); return 0; } //printf("libmpeg3 1\n"); } mpeg3io_close_file(file->fs); } else // IFO file #ifndef _WIN32 if(bits == MPEG3_IFO_PREFIX) { //printf("libmpeg3 1\n"); if(!old_file) { //printf("libmpeg3 2\n"); if(mpeg3_read_ifo(file, 0)) { mpeg3_delete(file); mpeg3io_close_file(file->fs); return 0; } //printf("libmpeg3 3\n"); } file->is_ifo_file = 1; mpeg3io_close_file(file->fs); } else #endif if(((bits >> 24) & 0xff) == MPEG3_SYNC_BYTE) { /* Transport stream */ //printf("libmpeg3 2\n"); file->is_transport_stream = 1; } else if(bits == MPEG3_PACK_START_CODE) { /* Program stream */ /* Determine packet size empirically */ //printf("libmpeg3 3\n"); file->is_program_stream = 1; } else if((bits & 0xfff00000) == 0xfff00000 || (bits & 0xffff0000) == 0xffe30000 || ((bits >> 8) == MPEG3_ID3_PREFIX) || (bits == MPEG3_RIFF_CODE)) { /* MPEG Audio only */ //printf("libmpeg3 4\n"); file->is_audio_stream = 1; } else if(bits == MPEG3_SEQUENCE_START_CODE || bits == MPEG3_PICTURE_START_CODE) { /* Video only */ //printf("libmpeg3 5\n"); file->is_video_stream = 1; } else if(((bits & 0xffff0000) >> 16) == MPEG3_AC3_START_CODE) { /* AC3 Audio only */ //printf("libmpeg3 6\n"); file->is_audio_stream = 1; } else { //printf("libmpeg3 7\n"); mpeg3_delete(file); fprintf(stderr, "mpeg3_open: not an MPEG 2 stream\n"); return 0; } //printf("mpeg3_open 2 %p %d %d %d %d\n", // old_file, file->is_transport_stream, file->is_program_stream, file->is_video_stream, file->is_audio_stream); // Configure packet size if(file->is_transport_stream) file->packet_size = MPEG3_TS_PACKET_SIZE; else if(file->is_program_stream) file->packet_size = 0; else if(file->is_audio_stream) file->packet_size = MPEG3_DVD_PACKET_SIZE; else if(file->is_video_stream) file->packet_size = MPEG3_DVD_PACKET_SIZE; //printf("mpeg3_open 1\n"); /* Create titles */ /* Copy timecodes from an old demuxer */ if(old_file && mpeg3_get_demuxer(old_file)) { mpeg3demux_copy_titles(file->demuxer, mpeg3_get_demuxer(old_file)); file->is_transport_stream = old_file->is_transport_stream; file->is_program_stream = old_file->is_program_stream; } else /* Start from scratch */ if(!file->demuxer->total_titles) { mpeg3demux_create_title(file->demuxer, 0, 0); } //printf("mpeg3_open 2\n"); /* Generate tracks */ if(file->is_transport_stream || file->is_program_stream) { /* Create video tracks */ /* Video must be created before audio because audio uses the video timecode */ /* to get its length. */ for(i = 0; i < MPEG3_MAX_STREAMS; i++) { if(file->demuxer->vstream_table[i]) { file->vtrack[file->total_vstreams] = mpeg3_new_vtrack(file, i, file->demuxer, file->total_vstreams); if(file->vtrack[file->total_vstreams]) file->total_vstreams++; //printf("libmpeg3 %d %d %p %d\n", i, file->demuxer->vstream_table[i], file->vtrack[file->total_vstreams], file->total_vstreams); } } /* Create audio tracks */ for(i = 0; i < MPEG3_MAX_STREAMS; i++) { if(file->demuxer->astream_table[i]) { file->atrack[file->total_astreams] = mpeg3_new_atrack(file, i, file->demuxer->astream_table[i], file->demuxer, file->total_astreams); if(file->atrack[file->total_astreams]) file->total_astreams++; } } } else if(file->is_video_stream) { /* Create video tracks */ //printf("mpeg3_open 3\n"); file->vtrack[0] = mpeg3_new_vtrack(file, -1, file->demuxer, 0); //printf("mpeg3_open 4\n"); if(file->vtrack[0]) file->total_vstreams++; } else if(file->is_audio_stream) { /* Create audio tracks */ //printf("mpeg3_open 3\n"); file->atrack[0] = mpeg3_new_atrack(file, -1, AUDIO_UNKNOWN, file->demuxer, 0); //printf("mpeg3_open 3\n"); if(file->atrack[0]) file->total_astreams++; } //printf("mpeg3_open 5\n"); mpeg3io_close_file(file->fs); return file; } mpeg3_t* mpeg3_open(const char *path) { return mpeg3_open_copy(path, 0); } int mpeg3_close(mpeg3_t *file) { /* File is closed in the same procedure it is opened in. */ mpeg3_delete(file); return 0; } int mpeg3_has_audio(mpeg3_t *file) { return file->total_astreams > 0; } int mpeg3_total_astreams(mpeg3_t *file) { return file->total_astreams; } int mpeg3_audio_channels(mpeg3_t *file, int stream) { if(file->total_astreams) return file->atrack[stream]->channels; return -1; } int mpeg3_sample_rate(mpeg3_t *file, int stream) { if(file->total_astreams) return file->atrack[stream]->sample_rate; return -1; } int mpeg3_audio_samples_per_frame(mpeg3_t *file, int stream) { if(file->total_astreams) return file->atrack[stream]->samples_per_frame; return -1; } uint32_t mpeg3_audio_get_number_of_frames (mpeg3_t *file, int stream) { if (file->total_astreams) return file->atrack[stream]->total_frames; return -1; } char* mpeg3_audio_format(mpeg3_t *file, int stream) { if(stream < file->total_astreams) { switch(file->atrack[stream]->format) { case AUDIO_UNKNOWN: return "Unknown"; break; case AUDIO_MPEG: return "MPEG"; break; case AUDIO_AC3: return "AC3"; break; case AUDIO_PCM: return "PCM"; break; case AUDIO_AAC: return "AAC"; break; case AUDIO_JESUS: return "Vorbis"; break; } } return ""; } int mpeg3_has_video(mpeg3_t *file) { return file->total_vstreams > 0; } int mpeg3_total_vstreams(mpeg3_t *file) { return file->total_vstreams; } int mpeg3_video_width(mpeg3_t *file, int stream) { if(file->total_vstreams) return file->vtrack[stream]->width; return -1; } int mpeg3_video_height(mpeg3_t *file, int stream) { if(file->total_vstreams) return file->vtrack[stream]->height; return -1; } float mpeg3_aspect_ratio(mpeg3_t *file, int stream) { if(file->total_vstreams) return file->vtrack[stream]->aspect_ratio; return 0; } float mpeg3_frame_rate(mpeg3_t *file, int stream) { if(file->total_vstreams) return file->vtrack[stream]->frame_rate; return -1; } long mpeg3_video_frames(mpeg3_t *file, int stream) { if(file->total_vstreams) return file->vtrack[stream]->total_frames; return -1; } long mpeg3_get_frame(mpeg3_t *file, int stream) { if(file->total_vstreams) return file->vtrack[stream]->current_position; return -1; } int mpeg3_set_frame(mpeg3_t *file, long frame, int stream) { if(file->total_vstreams) { file->vtrack[stream]->current_position = frame; mpeg3vtrack_seek_frame(file->vtrack[stream], frame); return 0; } return -1; } int mpeg3_seek_percentage(mpeg3_t *file, double percentage) { int i; for(i = 0; i < file->total_vstreams; i++) { mpeg3vtrack_seek_percentage(file->vtrack[i], percentage); } for(i = 0; i < file->total_astreams; i++) { mpeg3atrack_seek_percentage(file->atrack[i], percentage); } return 0; } int mpeg3_seek_audio_percentage(mpeg3_t *file, int stream, double percentage) { mpeg3atrack_seek_percentage(file->atrack[stream], percentage); return 0; } int mpeg3_seek_video_percentage(mpeg3_t *file, int stream, double percentage) { mpeg3vtrack_seek_percentage(file->vtrack[stream], percentage); return 0; } #if 0 int mpeg3_previous_frame(mpeg3_t *file, int stream) { file->last_type_read = 2; file->last_stream_read = stream; if(file->total_vstreams) return mpeg3video_previous_frame(file->vtrack[stream]->video); return 0; } #endif double mpeg3_tell_percentage(mpeg3_t *file) { double percent = 0; if(file->last_type_read == 1) { percent = mpeg3demux_tell_percentage(file->atrack[file->last_stream_read]->demuxer); } if(file->last_type_read == 2) { percent = mpeg3demux_tell_percentage(file->vtrack[file->last_stream_read]->demuxer); } return percent; } int mpeg3_end_of_audio(mpeg3_t *file, int stream) { int result = 0; result = mpeg3demux_eof(file->atrack[stream]->demuxer); return result; } int mpeg3_end_of_video(mpeg3_t *file, int stream) { int result = 0; result = mpeg3demux_eof(file->vtrack[stream]->demuxer); return result; } int mpeg3_read_audio_frame (mpeg3_t *file, unsigned char **output, uint32_t *size, uint32_t *max_size, int stream) { int result = -1; if (file->total_astreams) { result = mpeg3_atrack_read_frame(file->atrack[stream], output, size, max_size); file->last_type_read = 1; file->last_stream_read = stream; } return result; } int mpeg3_get_audio_format (mpeg3_t *file, int stream) { if (file->total_astreams) { return (file->atrack[stream]->format); } return AUDIO_UNKNOWN; } int mpeg3_read_video_chunk(mpeg3_t *file, unsigned char *output, long *size, long max_size, int stream) { int result = 0; if(file->total_vstreams) { result = mpeg3vtrack_read_raw(file->vtrack[stream], output, size, max_size); file->last_type_read = 2; file->last_stream_read = stream; } return result; } int mpeg3_read_video_chunk_resize (mpeg3_t *file, unsigned char **output, long *size, int stream) { int result = 0; if(file->total_vstreams) { result = mpeg3vtrack_read_raw_resize(file->vtrack[stream], output, size); file->last_type_read = 2; file->last_stream_read = stream; } return result; } void mpeg3_read_video_chunk_cleanup (mpeg3_t *file, int stream) { int result = 0; if(file->total_vstreams) { mpeg3vtrack_cleanup_frame(file->vtrack[stream]); } }