⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gop_list.c

📁 由bmp生成mpeg2 的I_frame 数据
💻 C
📖 第 1 页 / 共 2 页
字号:
/*******************************************************************
                         GOP list module
 *******************************************************************/

#include "endian.h"
#include "gl_dialog.h"

#define GOP_LIST_C
#include "gop_list.h"

typedef struct {
	int     index;
	int     sh_index;
	__int64 start;
	__int64 count;

	__int64 offset;

	void   *prev;
	void   *next;
} GOP_ENTRY;

typedef struct {
	int     index;
	SEQUENCE_HEADER sh;

	void *prev;
	void *next;
} SEQUENCE_ENTRY;

static const char GL_TAG[32] = {
	'G', 'O', 'P', '_', 'L', 'I', 'S', 'T',
	0, 0, 0, 0, 0, 0, 0, 0, 
	'0', '0', '0', '0', '0', '0', '0', '3',
	0, 0, 0, 0, 0, 0, 0, 0, 
};

GOP_LIST *new_gop_list(VIDEO_STREAM *in, READ_PICTURE_HEADER_OPTION *opt, int field_order);
void delete_gop_list(void *gop_list);
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);
static void release_sequence_entries(SEQUENCE_ENTRY *last);

static int save_sequence_header(SEQUENCE_HEADER *sh, FILE *fp);
static int load_sequence_header(SEQUENCE_HEADER *sh, FILE *fp);

GOP_LIST *new_gop_list(VIDEO_STREAM *in, READ_PICTURE_HEADER_OPTION *pic_opt, int field_order)
{
	GOP_LIST *r;
	GL_DIALOG *dlg;

	int code;
	
	int broken_link;
	int closed_gop;
	int temporal_count;
	int intra_flag;

	int i;

	__int64 offset;
	__int64 frame;

	__int64 gop_offset;

	PICTURE_HEADER pic;
	SEQUENCE_HEADER sh;
	
	GOP_ENTRY *p;
	GOP_ENTRY *c;

	SEQUENCE_ENTRY *sp;
	SEQUENCE_ENTRY *sc;

	/* stream rewind */
	video_stream_seek(in, 0, SEEK_SET);

	p = NULL;
	c = NULL;

	sp = NULL;
	sc = NULL;
	
	frame = 0;

	code = 0;
	
	intra_flag = 1;
	broken_link = 1;
	closed_gop = 0;

	gop_offset = -1;

	memset(&pic, 0, sizeof(pic));

	dlg = create_gl_dialog();
	
	/* 1st step - find initial I picture */
	while(vs_next_start_code(in)){

		if(dlg->is_cancel(dlg)){
			dlg->delete(dlg);
			return NULL;
		}
		dlg->update(dlg, (int)(video_stream_tell(in)*100/in->file_length));
		
		code = vs_read_bits(in, 32);
		if(code == 0x1b3){
			
			vs_erase_bits(in, 32);

			if(! read_sequence_header(in, &sh)){
				dlg->delete(dlg);
				return NULL;
			}
			sc = (SEQUENCE_ENTRY *)malloc(sizeof(SEQUENCE_ENTRY));
			sc->index = 0;
			sc->prev = NULL;
			memcpy(&(sc->sh), &sh, sizeof(SEQUENCE_HEADER));

		}else if(code == 0x1b8){

			gop_offset = video_stream_tell(in);

			vs_erase_bits(in, 32); // erase gop_start_code
			vs_erase_bits(in, 25); // erase timecode

			closed_gop = vs_get_bits(in, 1);
			broken_link = vs_get_bits(in, 1);

		}else if(code == 0x100){
			
			offset = video_stream_tell(in);
			vs_erase_bits(in, 32);

			if(! read_picture_header(in, &pic, pic_opt)){
				dlg->delete(dlg);
				return NULL;
			}

			temporal_count = 1;
			if(pic.has_picture_coding_extension){
				if(pic.pc.picture_structure != 3){
					if(! skip_2nd_field(in, pic_opt)){
						dlg->delete(dlg);
						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->sh_index = sc->index;
				c->start = 0;
				if(gop_offset >= 0){
					c->offset = gop_offset;
				}else{
					c->offset = offset;
				}
				c->prev = NULL;

				frame = temporal_count;

				break; /* goto 2nd step */
			}

			gop_offset = -1;
			closed_gop = 0;
			broken_link = 1;
		}else{
			vs_erase_bits(in, 32);
		}
	}

	if(closed_gop){
		broken_link = 0;
	}else{
		broken_link = 1;
	}

	/* 2nd step - check all rest pictures */
	while(vs_next_start_code(in)){
		
		if(dlg->is_cancel(dlg)){
			dlg->delete(dlg);
			release_sequence_entries(sc);
			release_gop_entries(c);
			return NULL;
		}
		dlg->update(dlg, (int)(video_stream_tell(in)*100/in->file_length));
		
		code = vs_read_bits(in, 32);
		if(code == 0x1b3){
			vs_erase_bits(in, 32);

			if(! read_sequence_header(in, &sh)){
				dlg->delete(dlg);
				release_sequence_entries(sc);
				release_gop_entries(c);
				return NULL;
			}

			if( memcmp(&(sc->sh), &sh, sizeof(SEQUENCE_HEADER)) ){
				sp = sc;
				sc = (SEQUENCE_ENTRY *)malloc(sizeof(SEQUENCE_ENTRY));
				if(sc == NULL){
					dlg->delete(dlg);
					release_sequence_entries(sp);
					release_gop_entries(c);
					return NULL;
				}
				sp->next = sc;
				sc->prev = sp;

				sc->index = sp->index + 1;
				memcpy(&(sc->sh), &sh, sizeof(SEQUENCE_HEADER));
			}

		}else if(code == 0x100){
			offset = video_stream_tell(in);
			vs_erase_bits(in, 32);

			if(! read_picture_header(in, &pic, pic_opt)){
				dlg->delete(dlg);
				release_sequence_entries(sc);
				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)){
						dlg->delete(dlg);
						release_sequence_entries(sc);
						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){
					dlg->delete(dlg);
					release_sequence_entries(sc);
					release_gop_entries(p);
					return NULL;
				}
				p->next = c;
				c->prev = p;
				
				c->index = p->index + 1;
				c->sh_index = sc->index;
				c->start = p->start + frame;
				if(gop_offset >= 0){
					c->offset = gop_offset;
				}else{
					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){
						/* ignore this B picture */
						break;
					}
					if(closed_gop){
						frame += temporal_count;
					}else{
						c->start += temporal_count;
					}
				}else{
					frame += temporal_count;
				}
				break;
			default:
				dlg->delete(dlg);
				release_sequence_entries(sc);
				release_gop_entries(c);
				return NULL;
			}
			gop_offset = -1;
		}else if(code == 0x1b8){
			gop_offset = video_stream_tell(in);
			vs_erase_bits(in, 32); /* start_code */
			vs_erase_bits(in, 25); /* time_code */
			closed_gop = vs_get_bits(in, 1);
			broken_link = vs_get_bits(in, 1);
			if(closed_gop){
				broken_link = 0;
			}
		}else{
			vs_erase_bits(in, 32);
		}
	}

	dlg->delete(dlg);

	if(code != 0x1b7){ /* not sequence end code */
		frame -= 2;
	}

	c->count = frame;
	if(p != NULL){
		p->count = c->start - p->start;
	}
	r = (GOP_LIST *)calloc(1, sizeof(GOP_LIST));
	if(r == NULL){
		release_sequence_entries(sc);
		release_gop_entries(c);
		return NULL;
	}
	
	r->stream_length = in->file_length;
	r->num_of_frame = c->start + frame;
	r->num_of_gop = c->index + 1;
	r->num_of_sh = sc->index + 1;

	/* convert SEQUENCE_ENTRY to GOP_LIST::sh */
	r->sh = (SEQUENCE_HEADER *)malloc(r->num_of_sh*sizeof(SEQUENCE_HEADER));
	if(r->sh == NULL){
		release_sequence_entries(sc);
		release_gop_entries(c);
		return NULL;
	}

	for(i=r->num_of_sh-1;sc;i--){
		memcpy(r->sh+i, &(sc->sh), sizeof(SEQUENCE_HEADER));
		sp = sc->prev;
		free(sc);
		sc = sp;
	}

	/* convert GOP_ENTRY to GOP_LIST::gop */
	r->gop = (GOP *)malloc((r->num_of_gop)*sizeof(GOP));
	if(r->gop == NULL){
		release_sequence_entries(sc);
		release_gop_entries(c);
		return NULL;
	}

	for(i=r->num_of_gop-1;c;i--){
		r->gop[i].offset = c->offset;
		r->gop[i].start_frame = c->start;
		r->gop[i].frame_count = c->count;
		r->gop[i].sh = r->sh + c->sh_index;
		p = (GOP_ENTRY *)c->prev;
		free(c);
		c = p;
	}

	if(r->gop[0].start_frame != 0){ // closed_gop
		r->gop[0].frame_count += r->gop[0].start_frame;
		r->gop[0].start_frame = 0;
	}
	
	return r;
}

void delete_gop_list(void *gop_list)
{
	GOP_LIST *w;

	w = (GOP_LIST *)gop_list;
	
	if(w != NULL){
		if(w->gop != NULL){
			free(w->gop);
		}
		if(w->sh != NULL){
			free(w->sh);
		}
		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->gop[0].start_frame || frame > gl->num_of_frame-1){
		return r;
	}

	if(gl->gop[gl->num_of_gop-1].start_frame <= frame){
		return gl->gop[gl->num_of_gop-1];
	}

	first = 0;
	last = gl->num_of_gop - 1;

	i = last/2;
	
	while(1){
		if(gl->gop[i].start_frame <= frame && gl->gop[i+1].start_frame > frame){
			return gl->gop[i];
		}else if(gl->gop[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(fwrite(GL_TAG, 1, sizeof(GL_TAG), out) != sizeof(GL_TAG)){
		fclose(out);
		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;
	}

	if(! write_le_int32(in->num_of_sh, out) ){
		fclose(out);
		return 0;
	}

	for(i=0;i<in->num_of_gop;i++){
		if(! write_le_int64(in->gop[i].offset, out)){

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -