diff options
| author | Kamil Debski <k.debski@samsung.com> | 2012-03-22 09:36:27 +0100 | 
|---|---|---|
| committer | Kamil Debski <k.debski@samsung.com> | 2012-03-22 14:02:11 +0100 | 
| commit | 9c057b001e8873861a70f7025214003837a0860b (patch) | |
| tree | 2c43acb98b53569a6613f9a56388381848e34c84 | |
| parent | 5aaeaa28e782647843570f01b4661a65ff3aa376 (diff) | |
v4l-mfc-example: version 0.2
| -rw-r--r-- | v4l2-mfc-example/CHANGELOG.txt | 8 | ||||
| -rw-r--r-- | v4l2-mfc-example/args.c | 14 | ||||
| -rw-r--r-- | v4l2-mfc-example/main.c | 36 | ||||
| -rw-r--r-- | v4l2-mfc-example/parser.c | 178 | ||||
| -rw-r--r-- | v4l2-mfc-example/parser.h | 5 | ||||
| -rw-r--r-- | v4l2-mfc-example/queue.c | 9 | ||||
| -rw-r--r-- | v4l2-mfc-example/queue.h | 2 | 
7 files changed, 239 insertions, 13 deletions
diff --git a/v4l2-mfc-example/CHANGELOG.txt b/v4l2-mfc-example/CHANGELOG.txt index faca41a..55008b4 100644 --- a/v4l2-mfc-example/CHANGELOG.txt +++ b/v4l2-mfc-example/CHANGELOG.txt @@ -1,6 +1,14 @@  Changelog  ============================ +* Version 0.2 - 2012-03-22 * +============================ + +Added MPEG2 parser and support for H263. +Experimental support for XVID has also been added. +Bugfixes have been made in the MPEG4 parser. + +============================  * Version 0.1 - 2012-03-05 *  ============================ diff --git a/v4l2-mfc-example/args.c b/v4l2-mfc-example/args.c index 119bf22..2161285 100644 --- a/v4l2-mfc-example/args.c +++ b/v4l2-mfc-example/args.c @@ -57,6 +57,14 @@ int get_codec(char *str)  		return V4L2_PIX_FMT_MPEG4;  	} else if (strncasecmp("h264", str, 5) == 0) {  		return V4L2_PIX_FMT_H264; +	} else if (strncasecmp("h263", str, 5) == 0) { +		return V4L2_PIX_FMT_H263; +	} else if (strncasecmp("xvid", str, 5) == 0) { +		return V4L2_PIX_FMT_XVID; +	} else if (strncasecmp("mpeg2", str, 5) == 0) { +		return V4L2_PIX_FMT_MPEG2; +	} else if (strncasecmp("mpeg1", str, 5) == 0) { +		return V4L2_PIX_FMT_MPEG1;  	}  	return 0;  } @@ -104,12 +112,18 @@ int parse_args(struct instance *i, int argc, char **argv)  	}  	switch (i->parser.codec) { +	case V4L2_PIX_FMT_XVID: +	case V4L2_PIX_FMT_H263:  	case V4L2_PIX_FMT_MPEG4:  		i->parser.func = parse_mpeg4_stream;  		break;  	case V4L2_PIX_FMT_H264:  		i->parser.func = parse_h264_stream;  		break; +	case V4L2_PIX_FMT_MPEG1: +	case V4L2_PIX_FMT_MPEG2: +		i->parser.func = parse_mpeg2_stream; +		break;  	}  	return 0; diff --git a/v4l2-mfc-example/main.c b/v4l2-mfc-example/main.c index dba04ef..6232618 100644 --- a/v4l2-mfc-example/main.c +++ b/v4l2-mfc-example/main.c @@ -36,7 +36,7 @@  /* This is the size of the buffer for the compressed stream.   * It limits the maximum compressed frame size. */ -#define STREAM_BUUFER_SIZE	(128 * 1024) +#define STREAM_BUUFER_SIZE	(1024 * 1024)  /* The number of compress4ed stream buffers */  #define STREAM_BUFFER_CNT	2 @@ -72,7 +72,14 @@ int extract_and_process_header(struct instance *i)  		return -1;  	} -	i->in.offs += used; +	/* For H263 the header is passed with the first frame, so we should +	 * pass it again */ +	if (i->parser.codec != V4L2_PIX_FMT_H263) +		i->in.offs += used; +	else +	/* To do this we shall reset the stream parser to the initial +	 * configuration */ +		parse_stream_init(&i->parser.ctx);  	dbg("Extracted header of size %d", fs); @@ -137,18 +144,20 @@ void *parser_thread_func(void *args)  	int ret;  	int used, fs, n; -	while (!i->error && !i->finish) { +	while (!i->error && !i->finish && !i->parser.finished) {  		n = 0;  		while (n < i->mfc.out_buf_cnt && i->mfc.out_buf_flag[n])  			n++;  		if (n < i->mfc.out_buf_cnt && !i->parser.finished) { +			dbg("parser.func = %p", i->parser.func);  			ret = i->parser.func(&i->parser.ctx,  				i->in.p + i->in.offs, i->in.size - i->in.offs,  				i->mfc.out_buf_addr[n], i->mfc.out_buf_size,  				&used, &fs, 0); -			if (ret == 0) { + +			if (ret == 0 && i->in.offs == i->in.size) {  				dbg("Parser has extracted all frames");  				i->parser.finished = 1;  				fs = 0; @@ -156,13 +165,19 @@ void *parser_thread_func(void *args)  			dbg("Extracted frame of size %d", fs); +			dbg("Before OUTPUT queue");  			ret = mfc_dec_queue_buf_out(i, n, fs); +			dbg("After OUTPUT queue"); +  			i->mfc.out_buf_flag[n] = 1;  			i->in.offs += used; +  		} else { +			dbg("Before OUTPUT dequeue");  			ret = dequeue_output(i, &n); +			dbg("After OUTPUT dequeue");  			i->mfc.out_buf_flag[n] = 0;  			if (ret && !i->parser.finished) {  				err("Failed to dequeue a buffer in parser_thread"); @@ -232,9 +247,7 @@ void *mfc_thread_func(void *args)  			}  		} -		if (i->mfc.cap_buf_queued >= i->mfc.cap_buf_cnt_min || -			i->parser.finished -			) { +		if (i->mfc.cap_buf_queued >= i->mfc.cap_buf_cnt_min) {  			/* Can dequeue a processed buffer */  			if (dequeue_capture(i, &n, &finished)) {  				err("Error when dequeueing CAPTURE buffer"); @@ -267,11 +280,14 @@ void *mfc_thread_func(void *args)   * switching and synchronisation to the vsync of frame buffer. */  void *fimc_thread_func(void *args)  { +	static int frames = 0;  	static int first_run = 1;  	struct instance *i = (struct instance *)args;  	int n, tmp; -	while (!i->error && !i->finish) { +	while (!i->error && (!i->finish || +		(i->finish && !queue_empty(&i->fimc.queue)) +		)) {  		dbg("Before fimc.todo");  		sem_wait(&i->fimc.todo);  		dbg("After fimc.todo"); @@ -329,6 +345,10 @@ void *fimc_thread_func(void *args)  			}  		} +		frames++; + +		dbg("Processed frame number: %d", frames); +  		if (fimc_dec_dequeue_buf_cap(i, &tmp)) {  			i->error = 1;  			break; diff --git a/v4l2-mfc-example/parser.c b/v4l2-mfc-example/parser.c index 6691dd1..4fd84db 100644 --- a/v4l2-mfc-example/parser.c +++ b/v4l2-mfc-example/parser.c @@ -68,10 +68,23 @@ int parse_mpeg4_stream(  			if (*in == 0x1) {  				ctx->state = MPEG4_PARSER_CODE_1x1;  			} else if ((*in & 0xFC) == 0x80) { -				// Short header +				/* Short header */  				ctx->state = MPEG4_PARSER_NO_CODE; -				ctx->last_tag = MPEG4_TAG_HEAD; -				ctx->main_count++; +				/* Ignore the short header if the current hasn't +				 * been started with a short header. */ + +				if (get_head && !ctx->short_header) { +					ctx->last_tag = MPEG4_TAG_HEAD; +					ctx->headers_count++; +					ctx->short_header = 1; +				} else if (!ctx->seek_end || +					(ctx->seek_end && ctx->short_header)) { +					ctx->last_tag = MPEG4_TAG_VOP; +					ctx->main_count++; +					ctx->short_header = 1; +				} +			} else if (*in == 0x0) { +				ctx->tmp_code_start++;  			} else {  				ctx->state = MPEG4_PARSER_NO_CODE;  			} @@ -93,7 +106,7 @@ int parse_mpeg4_stream(  			break;  		} -		if (get_head == 1 && ctx->headers_count > 1 && ctx->main_count == 1) { +		if (get_head == 1 && ctx->headers_count >= 1 && ctx->main_count == 1) {  			ctx->code_end = ctx->tmp_code_start;  			ctx->got_end = 1;  			break; @@ -174,6 +187,10 @@ int parse_mpeg4_stream(  				ctx->seek_end = 0;  				ctx->main_count = 0;  				ctx->headers_count = 1; +				ctx->short_header = 0; +				/* If the last frame used the short then +				 * we shall save this information, otherwise +				 * it is necessary to clear it */  			}  			memcpy(ctx->bytes, in_orig + ctx->code_end, *consumed - ctx->code_end);  		} else { @@ -229,6 +246,8 @@ int parse_h264_stream(  		case H264_PARSER_CODE_0x3:  			if (*in == 0x1)  				ctx->state = H264_PARSER_CODE_1x1; +			else if (*in == 0x0) +				ctx->tmp_code_start++;  			else  				ctx->state = H264_PARSER_NO_CODE;  			break; @@ -254,7 +273,7 @@ int parse_h264_stream(  			break;  		} -		if (get_head == 1 && ctx->headers_count > 1 && ctx->main_count == 1) { +		if (get_head == 1 && ctx->headers_count >= 1 && ctx->main_count == 1) {  			ctx->code_end = ctx->tmp_code_start;  			ctx->got_end = 1;  			break; @@ -347,3 +366,152 @@ int parse_h264_stream(  	return frame_finished;  } +int parse_mpeg2_stream( +	struct mfc_parser_context *ctx, +	char* in, int in_size, char* out, int out_size, +	int *consumed, int *frame_size, char get_head) +{ +	char *in_orig; +	char frame_finished; +	int frame_length; + +	in_orig = in; + +	*consumed = 0; + +	frame_finished = 0; + +	while (in_size-- > 0) { +		switch (ctx->state) { +		case MPEG4_PARSER_NO_CODE: +			if (*in == 0x0) { +				ctx->state = MPEG4_PARSER_CODE_0x1; +				ctx->tmp_code_start = *consumed; +			} +			break; +		case MPEG4_PARSER_CODE_0x1: +			if (*in == 0x0) +				ctx->state = MPEG4_PARSER_CODE_0x2; +			else +				ctx->state = MPEG4_PARSER_NO_CODE; +			break; +		case MPEG4_PARSER_CODE_0x2: +			if (*in == 0x1) { +				ctx->state = MPEG4_PARSER_CODE_1x1; +			} else if (*in == 0x0) { +				/* We still have two zeroes */ +				ctx->tmp_code_start++; +				// TODO XXX check in h264 and mpeg4 +			} else { +				ctx->state = MPEG4_PARSER_NO_CODE; +			} +			break; +		case MPEG4_PARSER_CODE_1x1: +			if (*in == 0xb3 || *in == 0xb8) { +				ctx->state = MPEG4_PARSER_NO_CODE; +				ctx->last_tag = MPEG4_TAG_HEAD; +				ctx->headers_count++; +				dbg("Found header at %d (%x)", *consumed, *consumed); +			} else if (*in == 0x00) { +				ctx->state = MPEG4_PARSER_NO_CODE; +				ctx->last_tag = MPEG4_TAG_VOP; +				ctx->main_count++; +				dbg("Found picture at %d (%x)", *consumed, *consumed); +			} else +				ctx->state = MPEG4_PARSER_NO_CODE; +			break; +		} + +		if (get_head == 1 && ctx->headers_count >= 1 && ctx->main_count == 1) { +			ctx->code_end = ctx->tmp_code_start; +			ctx->got_end = 1; +			break; +		} + +		if (ctx->got_start == 0 && ctx->headers_count == 1 && ctx->main_count == 0) { +			ctx->code_start = ctx->tmp_code_start; +			ctx->got_start = 1; +		} + +		if (ctx->got_start == 0 && ctx->headers_count == 0 && ctx->main_count == 1) { +			ctx->code_start = ctx->tmp_code_start; +			ctx->got_start = 1; +			ctx->seek_end = 1; +			ctx->headers_count = 0; +			ctx->main_count = 0; +		} + +		if (ctx->seek_end == 0 && ctx->headers_count > 0 && ctx->main_count == 1) { +			ctx->seek_end = 1; +			ctx->headers_count = 0; +			ctx->main_count = 0; +		} + +		if (ctx->seek_end == 1 && (ctx->headers_count > 0 || ctx->main_count > 0)) { +			ctx->code_end = ctx->tmp_code_start; +			ctx->got_end = 1; +			if (ctx->headers_count == 0) +				ctx->seek_end = 1; +			else +				ctx->seek_end = 0; +			break; +		} + +		in++; +		(*consumed)++; +	} + +	*frame_size = 0; + +	if (ctx->got_end == 1) { +		frame_length = ctx->code_end; +	} else +		frame_length = *consumed; + + +	if (ctx->code_start >= 0) { +		frame_length -= ctx->code_start; +		in = in_orig + ctx->code_start; +	} else { +		memcpy(out, ctx->bytes, -ctx->code_start); +		*frame_size += -ctx->code_start; +		out += -ctx->code_start; +		in_size -= -ctx->code_start; +		in = in_orig; +	} + +	if (ctx->got_start) { +		if (out_size < frame_length) { +			err("Output buffer too small for current frame"); +			return 0; +		} + +		memcpy(out, in, frame_length); +		*frame_size += frame_length; + +		if (ctx->got_end) { +			ctx->code_start = ctx->code_end - *consumed; +			ctx->got_start = 1; +			ctx->got_end = 0; +			frame_finished = 1; +			if (ctx->last_tag == MPEG4_TAG_VOP) { +				ctx->seek_end = 1; +				ctx->main_count = 0; +				ctx->headers_count = 0; +			} else { +				ctx->seek_end = 0; +				ctx->main_count = 0; +				ctx->headers_count = 1; +			} +			memcpy(ctx->bytes, in_orig + ctx->code_end, *consumed - ctx->code_end); +		} else { +			ctx->code_start = 0; +			frame_finished = 0; +		} +	} + +	ctx->tmp_code_start -= *consumed; + +	return frame_finished; +} + diff --git a/v4l2-mfc-example/parser.h b/v4l2-mfc-example/parser.h index 3887a89..6eea179 100644 --- a/v4l2-mfc-example/parser.h +++ b/v4l2-mfc-example/parser.h @@ -66,6 +66,7 @@ struct mfc_parser_context {  	char got_start;  	char got_end;  	char seek_end; +	int short_header;  };  /* Initialize the stream parser */ @@ -86,5 +87,9 @@ int parse_h264_stream(struct mfc_parser_context *ctx,          char* in, int in_size, char* out, int out_size,          int *consumed, int *frame_size, char get_head); +int parse_mpeg2_stream(struct mfc_parser_context *ctx, +        char* in, int in_size, char* out, int out_size, +        int *consumed, int *frame_size, char get_head); +  #endif /* PARSER_H_ */ diff --git a/v4l2-mfc-example/queue.c b/v4l2-mfc-example/queue.c index 62b7dfd..f1fce13 100644 --- a/v4l2-mfc-example/queue.c +++ b/v4l2-mfc-example/queue.c @@ -72,6 +72,15 @@ int queue_remove(struct queue *q)  	return x;  } +int queue_empty(struct queue *q) +{ +	int x; +	pthread_mutex_lock(&q->mutex); +	x = (q->n == 0); +	pthread_mutex_unlock(&q->mutex); +	return x; +} +  void queue_free(struct queue *q)  {  	free(q->q); diff --git a/v4l2-mfc-example/queue.h b/v4l2-mfc-example/queue.h index 963cf90..a0313f6 100644 --- a/v4l2-mfc-example/queue.h +++ b/v4l2-mfc-example/queue.h @@ -42,6 +42,8 @@ int queue_add(struct queue *q, int e);  int queue_remove(struct queue *q);  /* Free the internal queue memory */  void queue_free(struct queue *q); +/* Check if the queue is empty */ +int queue_empty(struct queue *q);  #endif /* INCLUDE_QUEUE_H */  | 
