v4l2-uvm-test: integrate with avsync-lib [2/2]
PD#SWPL-28037
Problem:
Missing AV sync function
Solution:
Use avync-lib for video AV sync.
When PTS is not in contrainer, use duration to fake PTS
Verify:
U212 + v4l2-uvm-test
Change-Id: I1f01ea58d151efbdc5a4b9cb04873f1f153a11a1
diff --git a/v4l2-uvm-test/Config.in b/v4l2-uvm-test/Config.in
index d6771a9..1cc424b 100755
--- a/v4l2-uvm-test/Config.in
+++ b/v4l2-uvm-test/Config.in
@@ -2,6 +2,7 @@
bool "v4l2_UVM_test"
select BR2_PACKAGE_LIBDRM
select BR2_PACKAGE_FFMPEG
+ select BR2_PACKAGE_AV_SYNC_LIB
help
Test application for v4l2 decoder using DRM-GEM UVM buffer.
http://openlinux.amlogic.com
diff --git a/v4l2-uvm-test/src/Makefile b/v4l2-uvm-test/src/Makefile
index f35c5e9..91de0ba 100644
--- a/v4l2-uvm-test/src/Makefile
+++ b/v4l2-uvm-test/src/Makefile
@@ -8,7 +8,7 @@
all: $(TARGET)
#TARGET_CFLAGS += -DDEBUG_FRAME
-LD_FLAG = -ldrm -lavformat -lavcodec -lavutil -lm -lpthread -lz -lswresample
+LD_FLAG = -ldrm -lavformat -lavcodec -lavutil -lm -lpthread -lz -lswresample -lamlavsync
ifeq ($(SECMEM), 1)
OBJ += secmem.c
@@ -18,7 +18,7 @@
$(TARGET): $(OBJ)
- $(CC) $(TARGET_CFLAGS) -D_FILE_OFFSET_BITS=64 -Wall -I$(STAGING_DIR)/usr/include/ -I$(STAGING_DIR)/usr/include/libdrm/ -L$(STAGING_DIR)/usr/lib $(LD_FLAG) $(OBJ) -o $@
+ $(CC) $(TARGET_CFLAGS) -g -D_FILE_OFFSET_BITS=64 -Wall -I$(STAGING_DIR)/usr/include/ -I$(STAGING_DIR)/usr/include/libdrm/ -L$(STAGING_DIR)/usr/lib $(LD_FLAG) $(OBJ) -o $@
.PHONY: clean
diff --git a/v4l2-uvm-test/src/demux.c b/v4l2-uvm-test/src/demux.c
index 9331ef4..5e1de97 100644
--- a/v4l2-uvm-test/src/demux.c
+++ b/v4l2-uvm-test/src/demux.c
@@ -19,7 +19,7 @@
#define HEVC_NAL_SPS 33
#define HEVC_NAL_PPS 34
-extern int ffmpeg_log;
+extern int log_level;
/* ffmpeg data structure */
static AVStream *video_stream = NULL;
static AVFormatContext *fmt_ctx = NULL;
@@ -37,6 +37,7 @@
static int thread_quit;
static struct dmx_v_data v_data;
static int video_frame_count = 0;
+static int64_t fake_pts = 0;
static void dump(const char* path, uint8_t *data, int size) {
FILE* fd = fopen(path, "wb");
@@ -82,13 +83,18 @@
if (pkt->stream_index != video_stream_idx)
return decoded;
- if (pkt->pts != AV_NOPTS_VALUE)
+ if (pkt->pts != AV_NOPTS_VALUE) {
pts_us = av_rescale_q(pkt->pts, video_stream->time_base, ns_r);
+ fake_pts = pts_us;
+ } else {
+ pts_us = fake_pts + av_rescale_q(pkt->duration, video_stream->time_base, ns_r);
+ fake_pts = pts_us;
+ }
/* video frame */
video_frame_count++;
#ifdef DEBUG_FRAME
- printf("video_frame n:%d pts:%llx size:%x\n",
+ printf("video_frame n:%d pts:%lld size:%x\n",
video_frame_count,
pts_us, pkt->size);
#endif
@@ -393,7 +399,7 @@
static void log_callback(void *ptr, int level,
const char *fmt, va_list vargs)
{
- if (ffmpeg_log)
+ if (log_level & 0x1)
vprintf(fmt, vargs);
}
diff --git a/v4l2-uvm-test/src/drm.c b/v4l2-uvm-test/src/drm.c
index d5e8637..9938ee4 100644
--- a/v4l2-uvm-test/src/drm.c
+++ b/v4l2-uvm-test/src/drm.c
@@ -28,6 +28,8 @@
#include <linux/videodev2.h>
#include <meson_drm.h>
+#include "aml_avsync.h"
+#include "aml_avsync_log.h"
#include "drm.h"
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
#define MAX_BUF_SIZE 32
@@ -40,6 +42,7 @@
extern unsigned int global_plane_id;
extern char mode_str[16];
extern unsigned int vfresh;
+extern int log_level;
struct gem_buffer {
uint32_t width;
@@ -69,7 +72,6 @@
uint32_t plane_crtc_w;
uint32_t plane_crtc_h;
uint32_t plane_zpos;
- uint32_t out_fence_ptr;
};
struct plane {
@@ -114,11 +116,15 @@
struct aml_display {
bool started;
pthread_t disp_t;
+#if 0
unsigned int q_len;
unsigned int ri; //read index
unsigned int wi; //write index
unsigned int total_num;
struct drm_frame *queue;
+#endif
+ void * avsync;
+ bool last_frame;
};
static struct gem_buffer *gem_buf;
@@ -126,6 +132,10 @@
static displayed_cb_func display_cb;
static struct aml_display aml_dis;
+#define TSYNC_MODE "/sys/class/tsync/mode"
+#define TSYNC_PCRSCR "/sys/class/tsync/pts_pcrscr"
+#define VPTS_INC_UPINT "/sys/class/video/vsync_pts_inc_upint"
+
static int create_meson_gem_buffer(int fd, enum frame_format fmt,
struct gem_buffer *buffer)
{
@@ -264,7 +274,6 @@
static int discover_properties(int fd, struct display_properties_ids *ids)
{
//int connector_id = setup.connector_id;
- int crtc_id = setup.crtc_id;
int plane_id = setup.plane_id;
drmModeObjectPropertiesPtr properties = NULL;
drmModePropertyPtr property = NULL;
@@ -284,7 +293,6 @@
{ DRM_MODE_OBJECT_PLANE, plane_id, "CRTC_Y", &ids->plane_crtc_y },
{ DRM_MODE_OBJECT_PLANE, plane_id, "CRTC_W", &ids->plane_crtc_w },
{ DRM_MODE_OBJECT_PLANE, plane_id, "CRTC_H", &ids->plane_crtc_h },
- { DRM_MODE_OBJECT_CRTC, crtc_id, "OUT_FENCE_PTR", &ids->out_fence_ptr},
};
unsigned int i, j;
int rc;
@@ -406,7 +414,7 @@
drmModeAtomicReqPtr request;
uint32_t flags = DRM_MODE_ATOMIC_NONBLOCK;
int rc;
- int out_fence_fd = 0;
+ //int out_fence_fd = 0;
//struct timeval t1, t2;
request = drmModeAtomicAlloc();
@@ -450,7 +458,6 @@
gem_buf->framebuffer_id);
drmModeAtomicAddProperty(request, plane_id, ids->plane_crtc_id,
crtc_id);
- drmModeAtomicAddProperty(request, crtc_id, ids->out_fence_ptr, (unsigned long)&out_fence_fd);
rc = drmModeAtomicCommit(fd, request, flags, NULL);
if (rc < 0) {
@@ -458,15 +465,6 @@
goto error;
}
- //gettimeofday(&t1, NULL);
- rc = sync_wait(out_fence_fd, 50);
- if (rc < 0)
- printf("wait out fence fail %d, %s\n", rc, strerror(errno));
- else {
- //gettimeofday(&t2, NULL);
- //printf("%s %d span:%d\n", __func__, __LINE__, span(&t1, &t2));
- }
- close(out_fence_fd);
rc = 0;
goto complete;
@@ -683,8 +681,9 @@
printf("fail to open %s\n", path);
return -1;
}
- if (write(fd, value, strlen(value)) != 1) {
+ if (write(fd, value, strlen(value)) != strlen(value)) {
printf("fail to write %s to %s\n", value, path);
+ close(fd);
return -1;
}
close(fd);
@@ -695,8 +694,8 @@
int display_engine_start(int smode)
{
unsigned int plane_id;
- drmModeModeInfo mode;
int rc;
+ drmModeModeInfo mode;
secure_mode = smode;
@@ -811,6 +810,18 @@
printf("drmModeSetCrtc fail %d\n", rc);
return -1;
}
+
+ /* video master mode for testing */
+ config_sys_node(TSYNC_MODE, "0");
+ config_sys_node(TSYNC_PCRSCR, "0");
+ config_sys_node(VPTS_INC_UPINT, "1");
+
+ log_set_level((log_level >> 1) & 0x7);
+ aml_dis.avsync = av_sync_create(0, 2, 2, 90000/mode.vrefresh);
+ if (!aml_dis.avsync) {
+ printf("create avsync fails\n");
+ return -1;
+ }
return 0;
}
@@ -890,9 +901,13 @@
aml_dis.started = false;
pthread_join(aml_dis.disp_t, NULL);
close_buffer(drm_cli_fd, &osd_gem_buf);
+ if (aml_dis.avsync)
+ av_sync_destroy(aml_dis.avsync);
+#if 0
if (aml_dis.queue)
free(aml_dis.queue);
+#endif
if (gem_buf)
free(gem_buf);
if (setup.plane) {
@@ -918,6 +933,7 @@
return 0;
}
+#if 0
static int queue_frame(struct drm_frame* frame)
{
if (aml_dis.total_num == aml_dis.q_len)
@@ -945,50 +961,82 @@
return 0;
}
+#endif
static void * display_thread_func(void * arg)
{
- struct drm_frame f, f_p1, f_p2;
- unsigned int fence_num;
+ struct vframe *sync_frame;
+ struct drm_frame *f = NULL, *f_p1 = NULL, *f_p2 = NULL;
+ drmVBlank vbl;
- f.pri_dec = NULL;
- f_p1.pri_dec = NULL;
- f_p2.pri_dec = NULL;
+ memset(&vbl, 0, sizeof(drmVBlank));
while (aml_dis.started) {
int rc;
struct gem_buffer* gem_buf;
- rc = dequeue_frame(&f);
- if (rc) {
- usleep(10);
- continue;
- }
- gem_buf = f.gem;
+ vbl.request.type = DRM_VBLANK_RELATIVE;
+ vbl.request.sequence = 1;
+ vbl.request.signal = 0;
- rc = page_flip(drm_fd, setup.crtc_id, setup.plane_id,
- &setup.properties_ids, gem_buf);
+ rc = drmWaitVBlank(drm_fd, &vbl);
if (rc) {
- printf("page_flip error\n");
- continue;
- }
- fence_num++;
- /* 2 fence delay on video layer, 1 fence delay on osd */
- if (f_p2.pri_dec) {
- display_cb(f_p2.pri_dec);
+ printf("drmWaitVBlank error %d\n", rc);
+ return NULL;
}
- f_p2 = f_p1;
- f_p1 = f;
+ sync_frame = av_sync_pop_frame(aml_dis.avsync);
+ if (!sync_frame)
+ continue;
+
+ f = sync_frame->private;
+
+ if (!f) {
+ aml_dis.last_frame = true;
+ break;
+ }
+
+ log_debug("pop frame: %d", f->pts);
+ if (f != f_p1) {
+ gem_buf = f->gem;
+ rc = page_flip(drm_fd, setup.crtc_id, setup.plane_id,
+ &setup.properties_ids, gem_buf);
+ if (rc) {
+ printf("page_flip error\n");
+ continue;
+ }
+ /* 2 fence delay on video layer, 1 fence delay on osd */
+ if (f_p2) {
+ display_cb(f_p2->pri_dec);
+ free(f_p2->pri_sync);
+ }
+
+ f_p2 = f_p1;
+ f_p1 = f;
+ }
}
+ printf("quit %s\n", __func__);
return NULL;
}
+static void sync_frame_free(struct vframe * sync_frame)
+{
+ struct drm_frame* drm_f = sync_frame->private;
+
+ if (drm_f) {
+ display_cb(drm_f->pri_dec);
+ free(sync_frame);
+ } else
+ aml_dis.last_frame = true;
+}
+
int display_engine_show(struct drm_frame* frame)
{
int rc;
+ struct vframe* sync_frame;
if (!aml_dis.started) {
+#if 0
aml_dis.queue = (struct drm_frame*)calloc(MAX_BUF_SIZE, sizeof(*aml_dis.queue));
if (!aml_dis.queue) {
printf("%s OOM\n", __func__);
@@ -996,7 +1044,9 @@
}
aml_dis.q_len = MAX_BUF_SIZE;
aml_dis.ri = aml_dis.wi = aml_dis.total_num = 0;
+#endif
aml_dis.started = true;
+ aml_dis.last_frame = false;
rc = pthread_create(&aml_dis.disp_t, NULL, display_thread_func, NULL);
if (rc) {
@@ -1005,13 +1055,27 @@
}
}
+ sync_frame = calloc(1, sizeof(*sync_frame));
+ if (!sync_frame) {
+ printf("%s OOM\n", __func__);
+ return -1;
+ }
+ if (!frame->last_flag) {
+ sync_frame->private = frame;
+ sync_frame->pts = frame->pts;
+ frame->pri_sync = sync_frame;
+ //TODO: fill correct duration
+ }
+ sync_frame->duration = 0;
+ sync_frame->free = sync_frame_free;
while (aml_dis.started) {
- if (queue_frame(frame)) {
- usleep(10);
+ if (av_sync_push_frame(aml_dis.avsync, sync_frame)) {
+ usleep(1000);
continue;
} else
break;
}
+ //printf("push frame: %d\n", sync_frame->pts);
return 0;
}
@@ -1024,7 +1088,7 @@
int display_wait_for_display()
{
- while (aml_dis.started && aml_dis.total_num) {
+ while (aml_dis.started && !aml_dis.last_frame) {
usleep(10);
}
if (!aml_dis.started)
diff --git a/v4l2-uvm-test/src/drm.h b/v4l2-uvm-test/src/drm.h
index fe74354..3daa4b4 100644
--- a/v4l2-uvm-test/src/drm.h
+++ b/v4l2-uvm-test/src/drm.h
@@ -25,6 +25,9 @@
void* gem;
void* pri_dec;
drm_frame_destroy destroy;
+ uint32_t pts;
+ bool last_flag;
+ void* pri_sync;
};
typedef int (*displayed_cb_func)(void* handle);
diff --git a/v4l2-uvm-test/src/test.c b/v4l2-uvm-test/src/test.c
index 7510c0b..9d93760 100644
--- a/v4l2-uvm-test/src/test.c
+++ b/v4l2-uvm-test/src/test.c
@@ -30,7 +30,7 @@
unsigned int vfresh;
int g_dw_mode = 16;
static int secure_mode = 0;
-int ffmpeg_log = 0;
+int log_level = 0x04;
static void usage(int argc, char **argv)
{
@@ -48,13 +48,13 @@
"-p | --plane=id select display plane. 26[pri] 28[overlay 1] 30[overlay 2] 32[video]\n"
"-m | --mode str set display mode. such as 3840x2160 or 3840x2160-60\n"
" 1920x1080 or 1920x1080-60\n"
- "-l | --log enable more ffmpeg demux log.\n"
+ "-l | --log enable more log bit 0: ffmpeg demux bit 1/2/3: avsync.\n"
"-s | --secure secure video path.\n"
"",
argv[0]);
}
-static const char short_options[] = "d:hf:p:m:ls";
+static const char short_options[] = "d:hf:p:m:l:s";
static const struct option
long_options[] = {
@@ -63,7 +63,7 @@
{ "help", no_argument, NULL, 'h' },
{ "plane", required_argument, NULL, 'p' },
{ "mode", required_argument, NULL, 'm' },
- { "log", no_argument, NULL, 'l' },
+ { "log", required_argument, NULL, 'l' },
{ "secure", no_argument, NULL, 's' },
{ 0, 0, 0, 0 }
};
@@ -103,7 +103,7 @@
break;
case 'l':
- ffmpeg_log = 1;
+ log_level = atoi(optarg);
break;
case 'd':
diff --git a/v4l2-uvm-test/src/v4l2-dec.c b/v4l2-uvm-test/src/v4l2-dec.c
index a157fec..4917a8f 100644
--- a/v4l2-uvm-test/src/v4l2-dec.c
+++ b/v4l2-uvm-test/src/v4l2-dec.c
@@ -21,6 +21,7 @@
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
+#include <libavformat/avformat.h>
#include "aml_driver.h"
#include "demux.h"
@@ -547,6 +548,10 @@
}
if (!(buf.flags & V4L2_BUF_FLAG_LAST)) {
struct drm_frame *drm_f = capture_p.buf[buf.index]->drm_frame;
+ uint64_t pts_us;
+
+ AVRational us_r = {1,DMX_SECOND};
+ AVRational ninty_k_r = {1,90000};
/* display capture buf */
if (res_profile.res_change) {
res_profile.res_change = false;
@@ -557,6 +562,10 @@
span(&res_profile.last_flag, &res_profile.first_frame));
}
drm_f->pri_dec = capture_p.buf[buf.index];
+ pts_us = buf.timestamp.tv_sec * DMX_SECOND;
+ pts_us += buf.timestamp.tv_usec;
+ drm_f->pts = av_rescale_q(pts_us, us_r, ninty_k_r);
+ drm_f->last_flag = false;
display_engine_show(drm_f);
} else {
uint32_t evt = 0;
@@ -574,6 +583,12 @@
d_c_rec_num++;
continue;
} else if (evt == V4L2_EVENT_EOS || eos_evt_pending) {
+ struct drm_frame *drm_f = capture_p.buf[buf.index]->drm_frame;
+
+ /* flush DRM */
+ drm_f->last_flag = true;
+ display_engine_show(drm_f);
+
printf("EOS received\n");
eos_received = true;
eos_evt_pending = false;
diff --git a/v4l2-uvm-test/v4l2-uvm-test.mk b/v4l2-uvm-test/v4l2-uvm-test.mk
index 4c25926..6f0bf94 100644
--- a/v4l2-uvm-test/v4l2-uvm-test.mk
+++ b/v4l2-uvm-test/v4l2-uvm-test.mk
@@ -7,6 +7,7 @@
V4L2_UVM_TEST_DEPENDENCIES += ffmpeg
V4L2_UVM_TEST_DEPENDENCIES += libdrm
+V4L2_UVM_TEST_DEPENDENCIES += avsync-lib
ifneq ($(BR2_PACKAGE_LIBSECMEM),y)
V4L2_UVM_TEST_DEPENDENCIES += libsecmem-bin