/******************************************************************* GOP list module *******************************************************************/ #include "endian.h" #define GOP_LIST_C #include "gop_list.h" typedef struct { int index; __int64 start; __int64 count; __int64 offset; void *prev; void *next; } GOP_ENTRY; GOP_LIST *new_gop_list(VIDEO_STREAM *in, READ_PICTURE_HEADER_OPTION *opt, int field_order); void delete_gop_list(void *p); GOP find_gop_with_gop_list(void *p, __int64 frame); int store_gop_list(GOP_LIST *in, char *filepath); GOP_LIST *load_gop_list(char *filepath); static void release_gop_entries(GOP_ENTRY *last); GOP_LIST *new_gop_list(VIDEO_STREAM *in, READ_PICTURE_HEADER_OPTION *pic_opt, int field_order) { GOP_LIST *r; int code; int broken_link; int temporal_count; int intra_flag; int i; __int64 offset; __int64 frame; PICTURE_HEADER pic; GOP_ENTRY *p; GOP_ENTRY *c; /* stream rewind */ video_stream_seek(in, 0, SEEK_SET); p = NULL; c = NULL; frame = 0; code = 0; intra_flag = 1; broken_link = 1; /* 1st step - find initial I picture */ while(vs_next_start_code(in)){ code = vs_read_bits(in, 32); if(code == 0x100){ offset = video_stream_tell(in); vs_erase_bits(in, 32); if(! read_picture_header(in, &pic, pic_opt)){ return NULL; } temporal_count = 1; if(pic.has_picture_coding_extension){ if(pic.pc.picture_structure != 3){ if(! skip_2nd_field(in, pic_opt)){ return NULL; } } if(pic.pc.repeat_first_field && (pic.pc.top_field_first == field_order)){ temporal_count += 1; } } if(pic.picture_coding_type == 1){ c = (GOP_ENTRY *)malloc(sizeof(GOP_ENTRY)); c->index = 0; c->start = 0; c->offset = offset; c->prev = NULL; frame = temporal_count; break; /* goto 2nd step */ } }else{ vs_erase_bits(in, 32); } } /* 2nd step - check all rest pictures */ while(vs_next_start_code(in)){ code = vs_read_bits(in, 32); if(code == 0x100){ offset = video_stream_tell(in); vs_erase_bits(in, 32); if(! read_picture_header(in, &pic, pic_opt)){ release_gop_entries(c); return NULL; } temporal_count = 1; if(pic.has_picture_coding_extension){ if(pic.pc.picture_structure != 3){ if(! skip_2nd_field(in, pic_opt)){ release_gop_entries(c); return NULL; } } if(pic.pc.repeat_first_field && (pic.pc.top_field_first == field_order) ){ temporal_count += 1; } } switch(pic.picture_coding_type){ case 1: if(intra_flag && p){ p->count = c->start - p->start; } p = c; c = (GOP_ENTRY *)malloc(sizeof(GOP_ENTRY)); if(c == NULL){ release_gop_entries(p); return NULL; } p->next = c; c->prev = p; c->index = p->index + 1; c->start = p->start + frame; c->offset = offset; frame = temporal_count; intra_flag = 1; break; case 2: if(intra_flag && p){ p->count = c->start - p->start; } frame += temporal_count; broken_link = 0; intra_flag = 0; break; case 3: if(intra_flag){ if(! broken_link){ c->start += temporal_count; } }else{ frame += temporal_count; } break; default: release_gop_entries(c); return NULL; } }else if(code == 0x1b8){ vs_erase_bits(in, 32); vs_erase_bits(in, 26); broken_link = vs_get_bits(in, 1); }else{ vs_erase_bits(in, 32); } } if(code != 0x1b7){ /* not sequence end code */ frame -= 2; } c->count = frame; p->count = c->start - p->start; r = (GOP_LIST *)calloc(1, sizeof(GOP_LIST)); r->stream_length = in->file_length; r->num_of_frame = c->start + frame; r->num_of_gop = c->index + 1; r->gops = (GOP *)malloc((r->num_of_gop)*sizeof(GOP)); for(i=r->num_of_gop-1;c;i--){ r->gops[i].offset = c->offset; r->gops[i].start_frame = c->start; r->gops[i].frame_count = c->count; p = (GOP_ENTRY *)c->prev; free(c); c = p; } return r; } void delete_gop_list(void *p) { GOP_LIST *w; w = (GOP_LIST *)p; if(w != NULL){ if(w->gops != NULL){ free(w->gops); } free(w); } } GOP find_gop_with_gop_list(void *p, __int64 frame) { int first, last; int i; GOP_LIST *gl; static const GOP r = { 0, 0, 0, }; gl = (GOP_LIST *)p; if(frame < gl->gops[0].start_frame || frame > gl->num_of_frame-1){ return r; } if(gl->gops[gl->num_of_gop-1].start_frame <= frame){ return gl->gops[gl->num_of_gop-1]; } first = 0; last = gl->num_of_gop - 1; i = last/2; while(1){ if(gl->gops[i].start_frame <= frame && gl->gops[i+1].start_frame > frame){ return gl->gops[i]; }else if(gl->gops[i].start_frame < frame){ first = i; }else{ last = i; } i = first + (last - first)/2; if(first == last){ return r; } } } int store_gop_list(GOP_LIST *in, char *filepath) { FILE *out; int i; out = fopen(filepath, "wb"); if(out == NULL){ return 0; } if(! write_le_int64(in->stream_length, out) ){ fclose(out); return 0; } if(! write_le_int64(in->num_of_frame, out) ){ fclose(out); return 0; } if(! write_le_int32(in->num_of_gop, out) ){ fclose(out); return 0; } for(i=0;inum_of_gop;i++){ if(! write_le_int64(in->gops[i].offset, out)){ fclose(out); return 0; } if(! write_le_int64(in->gops[i].start_frame, out)){ fclose(out); return 0; } if(! write_le_int64(in->gops[i].frame_count, out)){ fclose(out); return 0; } } fclose(out); return 1; } GOP_LIST *load_gop_list(char *filepath) { GOP_LIST *r; FILE *in; int i; in = fopen(filepath, "rb"); if(in == NULL){ return NULL; } r = (GOP_LIST *)calloc(1, sizeof(GOP_LIST)); if(r == NULL){ fclose(in); return NULL; } if(! read_le_int64(in, &(r->stream_length)) ){ fclose(in); free(r); return NULL; } if(! read_le_int64(in, &(r->num_of_frame)) ){ fclose(in); free(r); return NULL; } if(! read_le_int32(in, &(r->num_of_gop)) ){ fclose(in); free(r); return NULL; } if(r->num_of_gop < 1){ fclose(in); free(r); return NULL; } r->gops = (GOP *)calloc(r->num_of_gop, sizeof(GOP)); if(r->gops == NULL){ fclose(in); free(r); return NULL; } for(i=0;inum_of_gop;i++){ if(! read_le_int64(in, &(r->gops[i].offset)) ){ fclose(in); free(r->gops); free(r); return NULL; } if(! read_le_int64(in, &(r->gops[i].start_frame)) ){ fclose(in); free(r->gops); free(r); return NULL; } if(! read_le_int64(in, &(r->gops[i].frame_count)) ){ fclose(in); free(r->gops); free(r); return NULL; } } fclose(in); return r; } static void release_gop_entries(GOP_ENTRY *last) { GOP_ENTRY *p; GOP_ENTRY *c; c = last; while(c != NULL){ p = c->prev; free(c); c = p; } }