diff options
author | Philipp Zabel <p.zabel@pengutronix.de> | 2014-07-11 11:36:31 +0200 |
---|---|---|
committer | Mauro Carvalho Chehab <m.chehab@samsung.com> | 2014-07-22 17:08:15 +0200 |
commit | 846ced9c0ebfcb4d42718fcbb487d6e0e52142ec (patch) | |
tree | 5087398810ad217253a365e5a16ddac6615e5a5d /drivers/media/platform | |
parent | [media] coda: try to schedule a decode run after a stop command (diff) | |
download | linux-846ced9c0ebfcb4d42718fcbb487d6e0e52142ec.tar.xz linux-846ced9c0ebfcb4d42718fcbb487d6e0e52142ec.zip |
[media] coda: add decoder timestamp queue
The coda driver advertises timestamp_type V4L2_BUF_FLAG_TIMESTAMP_COPY on
both queues, so we have to copy timestamps from input v4l2 buffers to the
corresponding destination v4l2 buffers. Since the h.264 decoder can reorder
frames, a timestamp queue is needed to keep track of and assign the correct
timestamp to destination buffers.
Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Kamil Debski <k.debski@samsung.com>
Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
Diffstat (limited to 'drivers/media/platform')
-rw-r--r-- | drivers/media/platform/coda.c | 50 |
1 files changed, 49 insertions, 1 deletions
diff --git a/drivers/media/platform/coda.c b/drivers/media/platform/coda.c index 4ce17ac15fa0..c7e557a5788f 100644 --- a/drivers/media/platform/coda.c +++ b/drivers/media/platform/coda.c @@ -201,6 +201,13 @@ struct gdi_tiled_map { #define GDI_LINEAR_FRAME_MAP 0 }; +struct coda_timestamp { + struct list_head list; + u32 sequence; + struct v4l2_timecode timecode; + struct timeval timestamp; +}; + struct coda_ctx { struct coda_dev *dev; struct mutex buffer_mutex; @@ -235,6 +242,8 @@ struct coda_ctx { struct coda_aux_buf slicebuf; struct coda_aux_buf internal_frames[CODA_MAX_FRAMEBUFFERS]; u32 frame_types[CODA_MAX_FRAMEBUFFERS]; + struct coda_timestamp frame_timestamps[CODA_MAX_FRAMEBUFFERS]; + struct list_head timestamp_list; struct coda_aux_buf workbuf; int num_internal_frames; int idx; @@ -1011,7 +1020,7 @@ static int coda_bitstream_queue(struct coda_ctx *ctx, struct vb2_buffer *src_buf dma_sync_single_for_device(&ctx->dev->plat_dev->dev, ctx->bitstream.paddr, ctx->bitstream.size, DMA_TO_DEVICE); - ctx->qsequence++; + src_buf->v4l2_buf.sequence = ctx->qsequence++; return 0; } @@ -1047,12 +1056,26 @@ static bool coda_bitstream_try_queue(struct coda_ctx *ctx, static void coda_fill_bitstream(struct coda_ctx *ctx) { struct vb2_buffer *src_buf; + struct coda_timestamp *ts; while (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) > 0) { src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); if (coda_bitstream_try_queue(ctx, src_buf)) { + /* + * Source buffer is queued in the bitstream ringbuffer; + * queue the timestamp and mark source buffer as done + */ src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + + ts = kmalloc(sizeof(*ts), GFP_KERNEL); + if (ts) { + ts->sequence = src_buf->v4l2_buf.sequence; + ts->timecode = src_buf->v4l2_buf.timecode; + ts->timestamp = src_buf->v4l2_buf.timestamp; + list_add_tail(&ts->list, &ctx->timestamp_list); + } + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); } else { break; @@ -2600,6 +2623,14 @@ static void coda_stop_streaming(struct vb2_queue *q) } if (!ctx->streamon_out && !ctx->streamon_cap) { + struct coda_timestamp *ts; + + while (!list_empty(&ctx->timestamp_list)) { + ts = list_first_entry(&ctx->timestamp_list, + struct coda_timestamp, list); + list_del(&ts->list); + kfree(ts); + } kfifo_init(&ctx->bitstream_fifo, ctx->bitstream.vaddr, ctx->bitstream.size); ctx->runcounter = 0; @@ -2887,6 +2918,7 @@ static int coda_open(struct file *file) ctx->bitstream.vaddr, ctx->bitstream.size); mutex_init(&ctx->bitstream_mutex); mutex_init(&ctx->buffer_mutex); + INIT_LIST_HEAD(&ctx->timestamp_list); coda_lock(ctx); list_add(&ctx->list, &dev->instances); @@ -2978,6 +3010,7 @@ static void coda_finish_decode(struct coda_ctx *ctx) struct coda_q_data *q_data_src; struct coda_q_data *q_data_dst; struct vb2_buffer *dst_buf; + struct coda_timestamp *ts; int width, height; int decoded_idx; int display_idx; @@ -3099,6 +3132,18 @@ static void coda_finish_decode(struct coda_ctx *ctx) v4l2_err(&dev->v4l2_dev, "decoded frame index out of range: %d\n", decoded_idx); } else { + ts = list_first_entry(&ctx->timestamp_list, + struct coda_timestamp, list); + list_del(&ts->list); + val = coda_read(dev, CODA_RET_DEC_PIC_FRAME_NUM) - 1; + if (val != ts->sequence) { + v4l2_err(&dev->v4l2_dev, + "sequence number mismatch (%d != %d)\n", + val, ts->sequence); + } + ctx->frame_timestamps[decoded_idx] = *ts; + kfree(ts); + val = coda_read(dev, CODA_RET_DEC_PIC_TYPE) & 0x7; if (val == 0) ctx->frame_types[decoded_idx] = V4L2_BUF_FLAG_KEYFRAME; @@ -3132,6 +3177,9 @@ static void coda_finish_decode(struct coda_ctx *ctx) V4L2_BUF_FLAG_PFRAME | V4L2_BUF_FLAG_BFRAME); dst_buf->v4l2_buf.flags |= ctx->frame_types[ctx->display_idx]; + ts = &ctx->frame_timestamps[ctx->display_idx]; + dst_buf->v4l2_buf.timecode = ts->timecode; + dst_buf->v4l2_buf.timestamp = ts->timestamp; vb2_set_plane_payload(dst_buf, 0, width * height * 3 / 2); |