muxer_mpeg.c

来自「君正早期ucos系统(只有早期的才不没有打包成库),MPLAYER,文件系统,图」· C语言 代码 · 共 2,496 行 · 第 1/5 页

C
2,496
字号
			if(!vpriv->is_ready)				return 0;			n = found = calc_frames_to_flush(vpriv);		}		else if(s->type == MUXER_TYPE_AUDIO)			as = s;	}		if((! found) && finalize)	{		if(vpriv != NULL)			found = n = vpriv->framebuf_used;	}	if(found)	{		mp_msg(MSGT_MUXER, MSGL_DBG2, "\nVIDEO, FLUSH %d frames (of %d), 0 to %d\n", n, vpriv->framebuf_used, n-1);		vpriv = (muxer_headers_t*) vs->priv;				duration = 0;		iduration = 0;		for(i = 0; i < n; i++)			iduration += vpriv->framebuf[i].idur;		duration = (double) (iduration / 27000000.0);				if(as != NULL)		{			apriv = (muxer_headers_t*) as->priv;			iaduration = 0;			for(i = 0; i < apriv->framebuf_used; i++)			{				iaduration += apriv->framebuf[i].idur;			}			if(iaduration < iduration)			{				mp_msg(MSGT_MUXER, MSGL_DBG2, "Not enough audio data exit\n");				return 0;			}		}				if(as != NULL && (apriv->size == 0))		{			init_delay = vpriv->framebuf[0].pts - vpriv->framebuf[0].dts;					for(i = 0; i < apriv->framebuf_cnt; i++)			{				apriv->framebuf[i].pts += init_delay;				apriv->framebuf[i].dts += init_delay;			}			apriv->last_pts += init_delay;			mp_msg(MSGT_MUXER, MSGL_DBG2, "\r\nINITIAL VIDEO DELAY: %.3lf, currAPTS: %.3lf\r\n", (double) init_delay/27000000.0f, (double) apriv->last_pts/27000000.0f);		}				if((priv->is_xvcd || priv->is_xsvcd) && (vpriv->size == 0))			vpriv->buffer_size = (conf_vbuf_size ? conf_vbuf_size : (priv->is_xvcd ? 46 : 230))*1024;					i = 0;		skip_cnt = 0;					while(1)		{			update_scr(muxer);			i = find_best_stream(muxer);			if(i < 0)				continue;			if(!fill_packet(muxer, muxer->streams[i], finalize))				skip_cnt++;			if(skip_cnt == muxer->avih.dwStreams)			{				found = 0;				break;			}		}	}			muxer->file_end = priv->scr;	return found;}static inline uint64_t parse_fps(float fps){	// 90000 * 300 * 1001 / d , there's no rounding error with any of the admitted framerates	int d = (int)(fps*1001+0.5);		return 27027000000ULL / d;}static int soft_telecine(muxer_priv_t *priv, muxer_headers_t *vpriv, uint8_t *fps_ptr, uint8_t *se_ptr, uint8_t *pce_ptr, int n){	if(! pce_ptr)		return 0;	if(fps_ptr != NULL)	{		*fps_ptr = (*fps_ptr & 0xf0) | priv->vframerate;		vpriv->nom_delta_pts = parse_fps(conf_vframerate);	}		//in pce_ptr starting from bit 0 bit 24 is tff, bit 30 is rff, 	if(pce_ptr[3] & 0x2)	{		mp_msg(MSGT_MUXER, MSGL_ERR, "\nERROR! RFF bit is already set, disabling telecining\n");		vpriv->telecine = 0;		return 0;	}	vpriv->picture.progressive_sequence = 0;	vpriv->picture.progressive_frame = 1;	if(se_ptr)		se_ptr[1] &= 0xf7;		//disable tff and rff and overwrite them with the value in bff_mask	pce_ptr[3] = (pce_ptr[3] & 0x7d) | bff_mask[vpriv->display_frame % MAX_PATTERN_LENGTH];	pce_ptr[4] |= 0x80;	//sets progressive frame		vpriv->display_frame += n;	if(! vpriv->vframes)		mp_msg(MSGT_MUXER, MSGL_INFO, "\nENABLED SOFT TELECINING, FPS=%.3f\n",conf_vframerate);		return 1;}static size_t parse_mpeg12_video(muxer_stream_t *s, muxer_priv_t *priv, muxer_headers_t *spriv, float fps, size_t len){	uint8_t *fps_ptr = NULL;	//pointer to the fps byte in the sequence header	uint8_t *se_ptr = NULL;		//pointer to sequence extension	uint8_t *pce_ptr = NULL;	//pointer to picture coding extension	int frames_diff, d1, gop_reset = 0;	//how any frames we advanced respect to the last one	int ret;	int i, err;	uint32_t temp_ref;	int pt;		mp_msg(MSGT_MUXER, MSGL_DBG2,"parse_mpeg12_video, len=%u\n", (uint32_t) len);	if(s->buffer[0] != 0 || s->buffer[1] != 0 || s->buffer[2] != 1 || len<6) 	{		mp_msg(MSGT_MUXER, MSGL_ERR,"Unknown video format, possibly non-MPEG1/2 stream, len=%d!\n", len);		return 0;	}	temp_ref = 0;	pt = 0;	err = 0;	i = 0;	while(i + 4 < len)	{	// Video (0) Sequence header (b3) or GOP (b8)		if((s->buffer[i] == 0) && (s->buffer[i+1] == 0) && (s->buffer[i+2] == 1))		{			switch(s->buffer[i+3])			{				case 0xb3: //sequence				{					if(i + 11 > len)					{						err=1;						break;					}					fps_ptr = &(s->buffer[i+7]);					mp_header_process_sequence_header(&(spriv->picture), &(s->buffer[i+4]));					spriv->delta_pts = spriv->nom_delta_pts = parse_fps(spriv->picture.fps);										spriv->delta_clock = (double) 1/fps;					//the 2 lines below are needed to handle non-standard frame rates (such as 18)					if(! spriv->delta_pts)						spriv->delta_pts = spriv->nom_delta_pts = (uint64_t) ((double)27000000.0 * spriv->delta_clock );					mp_msg(MSGT_MUXER, MSGL_DBG2, "\nFPS: %.3f, FRAMETIME: %.3lf\n", fps, (double)1/fps);					if(priv->patch_seq)						patch_seq(priv, &(s->buffer[i]));				}				break;				case 0xb5:					if(i + 9 > len)					{						err = 1;						break;					}					mp_header_process_extension(&(spriv->picture), &(s->buffer[i+4]));					if(((s->buffer[i+4] & 0xf0) == 0x10))						se_ptr = &(s->buffer[i+4]);					if(((s->buffer[i+4] & 0xf0) == 0x20))					{						if(priv->patch_sde)							patch_panscan(priv, &(s->buffer[i+4]));					}					if((s->buffer[i+4] & 0xf0) == 0x80)					{						pce_ptr = &(s->buffer[i+4]);					}					break;						case 0xb8:					gop_reset = 1;					break;						case 0x00:					if(i + 5 > len)					{						err = 1;						break;					}					pt = (s->buffer[i+5] & 0x1c) >> 3;					temp_ref = (s->buffer[i+4]<<2)+(s->buffer[i+5]>>6);					break;				}			if(err) break;	//something went wrong			if(s->buffer[i+3] >= 0x01 && s->buffer[i+3] <= 0xAF) break;	//slice, we have already analized what we need		}		i++;	}	if(err)		mp_msg(MSGT_MUXER, MSGL_ERR,"Warning: picture too short or broken!\n");		//following 2 lines are workaround: lavf doesn't sync to sequence headers before passing demux_packets	if(!spriv->nom_delta_pts)			spriv->delta_pts = spriv->nom_delta_pts = parse_fps(fps);	if(!spriv->vframes)		spriv->last_tr = spriv->max_tr = temp_ref;	d1 = temp_ref - spriv->last_tr;	if(gop_reset)		frames_diff = spriv->max_tr + 1 + temp_ref - spriv->last_tr;	else	{		if(d1 < -6)	//there's a wraparound			frames_diff = spriv->max_tr + 1 + temp_ref - spriv->last_tr;		else if(d1 > 6)	//there's a wraparound			frames_diff = spriv->max_tr + 1 + spriv->last_tr - temp_ref;		else if(!d1)	//pre-emptive fix against broken sequences			frames_diff = 1;		else				frames_diff = d1;	}	mp_msg(MSGT_MUXER, MSGL_DBG2, "\nLAST: %d, TR: %d, GOP: %d, DIFF: %d, MAX: %d, d1: %d\n", 	spriv->last_tr, temp_ref, gop_reset, frames_diff, spriv->max_tr, d1);	if(temp_ref > spriv->max_tr || gop_reset)		spriv->max_tr = temp_ref;		spriv->last_tr = temp_ref;	if(spriv->picture.mpeg1 == 0) 	{		if(spriv->telecine && pce_ptr)		{			soft_telecine(priv, spriv, fps_ptr, se_ptr, pce_ptr, frames_diff);			spriv->picture.display_time = 100;			mp_header_process_extension(&(spriv->picture), pce_ptr);			if(spriv->picture.display_time >= 50 && spriv->picture.display_time <= 300) 				spriv->delta_pts = (spriv->nom_delta_pts * spriv->picture.display_time) / 100;		}	}		if(! spriv->vframes)		frames_diff = 1;	spriv->last_dts += spriv->delta_pts;	spriv->last_pts += spriv->nom_delta_pts*(frames_diff-1) + spriv->delta_pts;	ret = add_frame(spriv, spriv->delta_pts, s->buffer, len, pt, spriv->last_dts, spriv->last_pts);	if(ret < 0)	{		mp_msg(MSGT_MUXER, MSGL_FATAL, "\r\nPARSE_MPEG12: add_frames(%d) failed, exit\r\n", len);		return 0;	}	mp_msg(MSGT_MUXER, MSGL_DBG2, "\r\nVIDEO FRAME, PT: %C, tr: %d, diff: %d, dts: %.3lf, pts: %.3lf, pdt: %u, gop_reset: %d\r\n",		ftypes[pt], temp_ref, frames_diff, ((double) spriv->last_dts/27000000.0f), 		((double) spriv->last_pts/27000000.0f), spriv->picture.display_time, gop_reset);	if(pt == B_FRAME)	{		int j, n, adj = 0;		int64_t diff = spriv->last_dts - spriv->last_pts;				if(diff != 0)		{			n = spriv->framebuf_used - 1;						for(j = n; j >= 0; j--)			{				if(spriv->framebuf[j].pts >= spriv->last_pts)				{					spriv->framebuf[j].pts += diff;					adj++;				}			}			mp_msg(MSGT_MUXER, MSGL_V, "\r\nResynced B-frame by %d units, DIFF: %"PRId64" (%.3lf),[pd]ts=%.3lf\r\n",				n, diff, (double) diff/27000000.0f, (double) spriv->last_pts/27000000.0f);			spriv->last_pts = spriv->last_dts;		}	}	spriv->vframes++;		mp_msg(MSGT_MUXER, MSGL_DBG2,"parse_mpeg12_video, return %u\n", (uint32_t) len);	return len;}static uint64_t fix_mp4_frame_duration(muxer_headers_t *vpriv){	uint64_t mn, md, mx, diff;	uint32_t i;	mn = mx = vpriv->framebuf[0].pts;	for(i = 0; i < 3; i++) 	{		mp_msg(MSGT_DECVIDEO,MSGL_DBG2, "PTS: %"PRIu64"\n", vpriv->framebuf[i].pts);		if(vpriv->framebuf[i].pts < mn)			mn = vpriv->framebuf[i].pts;		if(vpriv->framebuf[i].pts > mx)			mx = vpriv->framebuf[i].pts;	}	md = mn;	for(i=0; i<3; i++) 	{		if((vpriv->framebuf[i].pts > mn) && (vpriv->framebuf[i].pts < mx))		md = vpriv->framebuf[i].pts;	}		if(mx - md > md - mn)		diff = md - mn;	else		diff = mx - md;	mp_msg(MSGT_DECVIDEO,MSGL_DBG2, "MIN: %"PRIu64", mid: %"PRIu64", max: %"PRIu64", diff: %"PRIu64"\n", mn, md, mx, diff);	if(diff > 0)	{		for(i=0; i<3; i++) 		{			vpriv->framebuf[i].pts += diff;			vpriv->framebuf[i].dts += i * diff;			mp_msg(MSGT_MUXER, MSGL_DBG2, "FIXED_PTS: %.3lf, FIXED_DTS: %.3lf\n", 				(double) (vpriv->framebuf[i].pts/27000000.0), (double) (vpriv->framebuf[i].dts/27000000.0));		}		return diff;	}	else		return 0;}static size_t parse_mpeg4_video(muxer_stream_t *s, muxer_priv_t *priv, muxer_headers_t *vpriv, float fps, size_t len){	size_t ptr = 0;	int64_t delta_pts=0;	uint8_t pt;	int ret;		mp_msg(MSGT_MUXER, MSGL_DBG2,"parse_mpeg4_video, len=%u\n", (uint32_t) len);	if(len<6) 	{		mp_msg(MSGT_MUXER, MSGL_ERR,"Frame too short: %d, exit!\n", len);		return 0;	}		pt = 0;	while(ptr < len - 5)	{		if(s->buffer[ptr] != 0 || s->buffer[ptr+1] != 0 || s->buffer[ptr+2] != 1)		{			ptr++;			continue;		}				if(s->buffer[ptr+3] >= 0x20 && s->buffer[ptr+3] <= 0x2f) //VOL		{			mp4_header_process_vol(&(vpriv->picture), &(s->buffer[ptr+4]));		}		else if(s->buffer[ptr+3] == 0xb3)	//gov		{			//fprintf(stderr, "\nGOV\n");		}		else if(s->buffer[ptr+3] == 0xb6)	//vop		{			int32_t delta;			mp4_header_process_vop(&(vpriv->picture), &(s->buffer[ptr+4]));						delta = vpriv->picture.timeinc_unit - vpriv->last_tr;			if((delta > 0) && (delta > (vpriv->picture.timeinc_resolution/2)))				delta -= vpriv->picture.timeinc_resolution;			else if((delta < 0) && (delta < (-(vpriv->picture.timeinc_resolution/2))))				delta += vpriv->picture.timeinc_resolution;						delta_pts = (27000000 * (int64_t) delta) / vpriv->picture.timeinc_resolution;			//warning, it seems that packed bops can lead to delta == 0						pt = vpriv->picture.picture_type + 1;			mp_msg(MSGT_MUXER, MSGL_DBG2, "\nTYPE: %c, RESOLUTION: %d, TEMP: %d, delta: %d, delta_pts: %"PRId64" = %.3lf, delta2: %.3lf\n", 				FTYPE(pt), vpriv->picture.timeinc_resolution, vpriv->picture.timeinc_unit, delta, delta_pts, (double) (delta_pts/27000000.0),				(double) delta / (double) vpriv->picture.timeinc_resolution);						vpriv->last_tr = vpriv->picture.timeinc_unit;							break;		}				ptr++;	}		if(vpriv->vframes)	{		vpriv->last_dts += vpriv->frame_duration;		vpriv->last_pts += delta_pts;	}		ret = add_frame(vpriv, delta_pts, s->buffer, len, pt, vpriv->last_dts, vpriv->last_pts);	if(ret < 0)	{		mp_msg(MSGT_MUXER, MSGL_FATAL, "\r\nPARSE_MPEG4: add_frames(%d) failed, exit\r\n", len);		return 0;	}		if(!vpriv->frame_duration && vpriv->framebuf_used == 3)	{		vpriv->frame_duration = fix_mp4_frame_duration(vpriv);		if(vpriv->frame_duration)		{			vpriv->last_pts += vpriv->frame_duration;			vpriv->last_dts = vpriv->framebuf[vpriv->framebuf_used-1].dts;			vpriv->delta_clock = ((double) vpriv->frame_duration)/27000000.0;			mp_msg(MSGT_MUXER, MSGL_INFO, "FRAME DURATION: %"PRIu64"   %.3lf\n", 				vpriv->frame_duration, (double) (vpriv->frame_duration/27000000.0));			vpriv->is_ready = 1;		}	}		mp_msg(MSGT_MUXER, MSGL_DBG2, "LAST_PTS: %.3lf, LAST_DTS: %.3lf\n", 		(double) (vpriv->last_pts/27000000.0), (double) (vpriv->last_dts/27000000.0));	vpriv->vframes++;		return len;}static int fill_last_frame(muxer_headers_t *spriv,  uint8_t *ptr, int len){	int idx;	if(!len)		return 0;		if(spriv->framebuf_used == 0)		idx = spriv->framebuf_used;	else		idx = spriv->framebuf_used - 1;	if(spriv->framebuf[idx].alloc_size < spriv->framebuf[idx].size + len)	{		if(spriv->framebuf[idx].size > SIZE_MAX - (size_t)len)			return 0;		spriv->framebuf[idx].buffer = (uint8_t*) realloc(spriv->framebuf[idx].buffer, spriv->framebuf[idx].size + len);		if(! spriv->framebuf[idx].buffer)			return 0;		spriv->framebuf[idx].alloc_size = spriv->framebuf[idx].size + len;	}	memcpy(&(spriv->framebuf[idx].buffer[spriv->framebuf[idx].size]), ptr, len);	spriv->framebuf[idx].size += len;	return len;}static int add_frame(muxer_headers_t *spriv, uint64_t idur, uint8_t *ptr, int len, uint8_t pt, uint64_t dts, uint64_t pts){	int idx;	idx = spriv->framebuf_used;	if(idx >= spriv->framebuf_cnt)	{		spriv->framebuf = (mpeg_frame_t*) realloc_struct(spriv->framebuf, (spriv->framebuf_cnt+1), sizeof(mpeg_frame_t));		if(spriv->framebuf == NULL)		{			mp_msg(MSGT_MUXER, MSGL_FATAL, "Couldn't realloc frame buffer(idx), abort\n");			return -1;		}				spriv->framebuf[spriv->framebuf_cnt].size = 0;		spriv->framebuf[spriv->framebuf_cnt].alloc_size = 0;		spriv->framebuf[spriv->framebuf_cnt].pos = 0;				spriv->framebuf[spriv->framebuf_cnt].buffer = (uint8_t*) malloc(len);		if(spriv->framebuf[spriv->framebuf_cnt].buffer == NULL)		{			mp_msg(MSGT_MUXER, MSGL_FATAL, "Couldn't realloc frame buffer(frame), abort\n");			return -1;		}		spriv->framebuf[spriv->framebuf_cnt].alloc_size = len;				spriv->framebuf_cnt++;	}		if(spriv->framebuf[idx].alloc_size < spriv->framebuf[idx].size + len)	{		if(spriv->framebuf[idx].size > SIZE_MAX - (size_t)len)		{			mp_msg(MSGT_MUXER, MSGL_FATAL, "Size overflow, couldn't realloc frame buffer(frame), abort\n");			return -1;		}		spriv->framebuf[idx].buffer = realloc(spriv->framebuf[idx].buffer, spriv->framebuf[idx].size + len);

⌨️ 快捷键说明

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