diff options
Diffstat (limited to 'v4l2-mfc-example')
-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 */ |