summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--v4l2-mfc-example/CHANGELOG.txt8
-rw-r--r--v4l2-mfc-example/args.c14
-rw-r--r--v4l2-mfc-example/main.c36
-rw-r--r--v4l2-mfc-example/parser.c178
-rw-r--r--v4l2-mfc-example/parser.h5
-rw-r--r--v4l2-mfc-example/queue.c9
-rw-r--r--v4l2-mfc-example/queue.h2
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 */