blob: a43027bb56ee648e9e6b5965791ecdd8a5f3641e [file] [log] [blame]
/*
* Copyright (c) 2021 Amlogic, Inc. All rights reserved.
*
* This source code is subject to the terms and conditions defined in the
* file 'LICENSE' which is part of this source code package.
*
* Description: test for pcr master mode
*
* Author: song.zhao@amlogic.com
*/
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include "aml_avsync.h"
#include "aml_avsync_log.h"
#define FRAME_NUM 32
#define PATTERN_32_DURATION 3750
#define PATTERN_22_DURATION 3000
#define REFRESH_RATE 60
#define PTS_START 0x12345678
static struct vframe *frame;
static int frame_received;
void *v_h, *a_h, *pcr_h;
static pthread_t vfeed_t;
static pthread_t afeed_t;
static bool quit_a_thread;
static pthread_t pcr_feed_t;
static bool quit_pcr_thread;
static bool audio_can_start;
static int pts_interval = PATTERN_32_DURATION;
static void frame_free(struct vframe * frame)
{
log_info("free %d\n", (int)frame->private);
frame_received++;
}
static void * v_thread(void * arg)
{
int i = 0;
int sleep_us = 1000000/REFRESH_RATE;
struct vframe *last_frame = NULL, *pop_frame;
/* push max frames */
while (i < FRAME_NUM) {
frame[i].private = (void *)i;
frame[i].pts = PTS_START + pts_interval * i;
frame[i].duration = pts_interval;
frame[i].free = frame_free;
if (av_sync_push_frame(v_h, &frame[i])) {
log_error("queue %d fail", i);
break;
}
log_info("queue %d", i);
usleep(10000);
i++;
}
i = 0;
while (frame_received < FRAME_NUM) {
usleep(sleep_us);
pop_frame = av_sync_pop_frame(v_h);
if (pop_frame)
log_info("pop frame %02d", (int)pop_frame->private);
if (pop_frame != last_frame) {
i++;
last_frame = pop_frame;
frame_received++;
log_info("frame received %d", frame_received);
}
}
return NULL;
}
static int start_v_thread()
{
int ret;
frame = (struct vframe*)calloc(FRAME_NUM, sizeof(struct vframe));
if (!frame) {
log_error("oom");
exit(1);
}
ret = pthread_create(&vfeed_t, NULL, v_thread, NULL);
if (ret) {
log_error("fail");
exit(1);
}
return 0;
}
static void stop_v_thread()
{
pthread_join(vfeed_t, NULL);
free(frame);
}
static int audio_start(void *priv, avs_ascb_reason reason)
{
log_info("received");
audio_can_start = true;
return 0;
}
static void * a_thread(void * arg)
{
int i = 0;
avs_start_ret ret;
int adjust = 0;
ret = av_sync_audio_start(a_h, PTS_START, 4500, audio_start, NULL);
if (ret == AV_SYNC_ASTART_ASYNC) {
log_info("begin wait audio start");
while (!audio_can_start)
usleep(10000);
log_info("finish wait audio start");
}
//5s, assume each package is 10ms
while (!quit_a_thread) {
int ret;
struct audio_policy policy;
ret = av_sync_audio_render(a_h, adjust + PTS_START + i * 900, &policy);
if (ret) {
log_error("fail");
return NULL;
}
switch (policy.action) {
case AV_SYNC_AA_RENDER:
log_info("render 10 ms %x", PTS_START + i * 900);
usleep(10 * 1000);
break;
case AV_SYNC_AA_DROP:
log_info("drop %d ms", policy.delta/90);
adjust += policy.delta;
break;
case AV_SYNC_AA_INSERT:
log_info("insert %d ms", (-policy.delta)/90);
usleep(-policy.delta/90 * 1000 + 10 * 1000);
break;
default:
log_error("should not happen");
break;
}
i++;
}
return NULL;
}
static int start_a_thread()
{
int ret;
ret = pthread_create(&afeed_t, NULL, a_thread, NULL);
if (ret) {
log_error("fail");
exit(1);
}
return 0;
}
static void stop_a_thread()
{
quit_a_thread = true;
pthread_join(afeed_t, NULL);
}
static void * pcr_thread(void * arg)
{
int i = 0;
//5s, 50ms interval
while (!quit_pcr_thread) {
int ret;
ret = av_sync_set_pcr_clock(pcr_h, PTS_START + i * 4500);
if (ret)
log_error("fail");
log_debug("pcr is %x", PTS_START + i * 4500);
usleep(50000);
i++;
}
return NULL;
}
static int start_pcr_thread()
{
int ret;
ret = pthread_create(&pcr_feed_t, NULL, pcr_thread, NULL);
if (ret) {
log_error("fail");
exit(1);
}
return 0;
}
static void stop_pcr_thread()
{
quit_pcr_thread = true;
pthread_join(pcr_feed_t, NULL);
}
static void test()
{
int i = 0;
int session, session_id;
session = av_sync_open_session(&session_id);
if (session < 0) {
log_error("fail");
exit(1);
}
v_h = av_sync_create(session_id, AV_SYNC_MODE_PCR_MASTER, AV_SYNC_TYPE_VIDEO, 2);
if (!v_h) {
log_error("fail");
exit(1);
}
a_h = av_sync_create(session_id, AV_SYNC_MODE_PCR_MASTER, AV_SYNC_TYPE_AUDIO, 0);
if (!a_h) {
log_error("fail");
exit(1);
}
pcr_h = av_sync_create(session_id, AV_SYNC_MODE_PCR_MASTER, AV_SYNC_TYPE_PCR, 0);
if (!pcr_h) {
log_error("fail");
exit(1);
}
start_v_thread();
start_a_thread();
start_pcr_thread();
//wait for 5s
while (i < 100) {
usleep(50 * 1000);
i++;
}
stop_v_thread();
stop_a_thread();
stop_pcr_thread();
av_sync_destroy(v_h);
av_sync_destroy(a_h);
av_sync_destroy(pcr_h);
av_sync_close_session(session);
}
int main(int argc, const char** argv)
{
log_set_level(LOG_TRACE);
log_info("\n----------------start------------\n");
test();
log_info("\n----------------end--------------\n");
return 0;
}