Song Zhao | ea5a041 | 2021-01-18 16:40:08 -0800 | [diff] [blame^] | 1 | /* |
| 2 | * Copyright (c) 2021 Amlogic, Inc. All rights reserved. |
| 3 | * |
| 4 | * This source code is subject to the terms and conditions defined in the |
| 5 | * file 'LICENSE' which is part of this source code package. |
| 6 | * |
| 7 | * Description: test for pcr master mode |
| 8 | * |
| 9 | * Author: song.zhao@amlogic.com |
| 10 | */ |
| 11 | #include <errno.h> |
| 12 | #include <sys/types.h> |
| 13 | #include <sys/stat.h> |
| 14 | #include <fcntl.h> |
| 15 | #include <stdbool.h> |
| 16 | #include <stdlib.h> |
| 17 | #include <stdio.h> |
| 18 | #include <string.h> |
| 19 | #include <unistd.h> |
| 20 | #include <pthread.h> |
| 21 | |
| 22 | #include "aml_avsync.h" |
| 23 | #include "aml_avsync_log.h" |
| 24 | |
| 25 | #define FRAME_NUM 32 |
| 26 | #define PATTERN_32_DURATION 3750 |
| 27 | #define PATTERN_22_DURATION 3000 |
| 28 | #define REFRESH_RATE 60 |
| 29 | #define PTS_START 0x12345678 |
| 30 | |
| 31 | static struct vframe *frame; |
| 32 | static int frame_received; |
| 33 | void *v_h, *a_h, *pcr_h; |
| 34 | static pthread_t vfeed_t; |
| 35 | static pthread_t afeed_t; |
| 36 | static bool quit_a_thread; |
| 37 | static pthread_t pcr_feed_t; |
| 38 | static bool quit_pcr_thread; |
| 39 | static bool audio_can_start; |
| 40 | static int pts_interval = PATTERN_32_DURATION; |
| 41 | |
| 42 | static void frame_free(struct vframe * frame) |
| 43 | { |
| 44 | log_info("free %d\n", (int)frame->private); |
| 45 | frame_received++; |
| 46 | } |
| 47 | |
| 48 | |
| 49 | static void * v_thread(void * arg) |
| 50 | { |
| 51 | int i = 0; |
| 52 | int sleep_us = 1000000/REFRESH_RATE; |
| 53 | struct vframe *last_frame = NULL, *pop_frame; |
| 54 | |
| 55 | /* push max frames */ |
| 56 | while (i < FRAME_NUM) { |
| 57 | frame[i].private = (void *)i; |
| 58 | frame[i].pts = PTS_START + pts_interval * i; |
| 59 | frame[i].duration = pts_interval; |
| 60 | frame[i].free = frame_free; |
| 61 | if (av_sync_push_frame(v_h, &frame[i])) { |
| 62 | log_error("queue %d fail", i); |
| 63 | break; |
| 64 | } |
| 65 | log_info("queue %d", i); |
| 66 | usleep(10000); |
| 67 | i++; |
| 68 | } |
| 69 | |
| 70 | i = 0; |
| 71 | while (frame_received < FRAME_NUM) { |
| 72 | usleep(sleep_us); |
| 73 | pop_frame = av_sync_pop_frame(v_h); |
| 74 | if (pop_frame) |
| 75 | log_info("pop frame %02d", (int)pop_frame->private); |
| 76 | if (pop_frame != last_frame) { |
| 77 | i++; |
| 78 | last_frame = pop_frame; |
| 79 | frame_received++; |
| 80 | log_info("frame received %d", frame_received); |
| 81 | } |
| 82 | } |
| 83 | |
| 84 | return NULL; |
| 85 | } |
| 86 | |
| 87 | static int start_v_thread() |
| 88 | { |
| 89 | int ret; |
| 90 | |
| 91 | frame = (struct vframe*)calloc(FRAME_NUM, sizeof(struct vframe)); |
| 92 | if (!frame) { |
| 93 | log_error("oom"); |
| 94 | exit(1); |
| 95 | } |
| 96 | |
| 97 | ret = pthread_create(&vfeed_t, NULL, v_thread, NULL); |
| 98 | if (ret) { |
| 99 | log_error("fail"); |
| 100 | exit(1); |
| 101 | } |
| 102 | return 0; |
| 103 | } |
| 104 | |
| 105 | static void stop_v_thread() |
| 106 | { |
| 107 | pthread_join(vfeed_t, NULL); |
| 108 | free(frame); |
| 109 | } |
| 110 | |
| 111 | static int audio_start(void *priv, avs_ascb_reason reason) |
| 112 | { |
| 113 | log_info("received"); |
| 114 | audio_can_start = true; |
| 115 | return 0; |
| 116 | } |
| 117 | |
| 118 | static void * a_thread(void * arg) |
| 119 | { |
| 120 | int i = 0; |
| 121 | avs_start_ret ret; |
| 122 | int adjust = 0; |
| 123 | |
| 124 | ret = av_sync_audio_start(a_h, PTS_START, 4500, audio_start, NULL); |
| 125 | |
| 126 | if (ret == AV_SYNC_ASTART_ASYNC) { |
| 127 | log_info("begin wait audio start"); |
| 128 | while (!audio_can_start) |
| 129 | usleep(10000); |
| 130 | log_info("finish wait audio start"); |
| 131 | } |
| 132 | |
| 133 | //5s, assume each package is 10ms |
| 134 | while (!quit_a_thread) { |
| 135 | int ret; |
| 136 | struct audio_policy policy; |
| 137 | |
| 138 | ret = av_sync_audio_render(a_h, adjust + PTS_START + i * 900, &policy); |
| 139 | if (ret) { |
| 140 | log_error("fail"); |
| 141 | return NULL; |
| 142 | } |
| 143 | |
| 144 | switch (policy.action) { |
| 145 | case AV_SYNC_AA_RENDER: |
| 146 | log_info("render 10 ms %x", PTS_START + i * 900); |
| 147 | usleep(10 * 1000); |
| 148 | break; |
| 149 | case AV_SYNC_AA_DROP: |
| 150 | log_info("drop %d ms", policy.delta/90); |
| 151 | adjust += policy.delta; |
| 152 | break; |
| 153 | case AV_SYNC_AA_INSERT: |
| 154 | log_info("insert %d ms", (-policy.delta)/90); |
| 155 | usleep(-policy.delta/90 * 1000 + 10 * 1000); |
| 156 | break; |
| 157 | default: |
| 158 | log_error("should not happen"); |
| 159 | break; |
| 160 | } |
| 161 | i++; |
| 162 | } |
| 163 | return NULL; |
| 164 | } |
| 165 | |
| 166 | static int start_a_thread() |
| 167 | { |
| 168 | int ret; |
| 169 | |
| 170 | ret = pthread_create(&afeed_t, NULL, a_thread, NULL); |
| 171 | if (ret) { |
| 172 | log_error("fail"); |
| 173 | exit(1); |
| 174 | } |
| 175 | return 0; |
| 176 | } |
| 177 | |
| 178 | static void stop_a_thread() |
| 179 | { |
| 180 | quit_a_thread = true; |
| 181 | pthread_join(afeed_t, NULL); |
| 182 | } |
| 183 | |
| 184 | static void * pcr_thread(void * arg) |
| 185 | { |
| 186 | int i = 0; |
| 187 | //5s, 50ms interval |
| 188 | while (!quit_pcr_thread) { |
| 189 | int ret; |
| 190 | |
| 191 | ret = av_sync_set_pcr_clock(pcr_h, PTS_START + i * 4500); |
| 192 | if (ret) |
| 193 | log_error("fail"); |
| 194 | log_debug("pcr is %x", PTS_START + i * 4500); |
| 195 | usleep(50000); |
| 196 | i++; |
| 197 | } |
| 198 | return NULL; |
| 199 | } |
| 200 | |
| 201 | static int start_pcr_thread() |
| 202 | { |
| 203 | int ret; |
| 204 | |
| 205 | ret = pthread_create(&pcr_feed_t, NULL, pcr_thread, NULL); |
| 206 | if (ret) { |
| 207 | log_error("fail"); |
| 208 | exit(1); |
| 209 | } |
| 210 | return 0; |
| 211 | } |
| 212 | |
| 213 | static void stop_pcr_thread() |
| 214 | { |
| 215 | quit_pcr_thread = true; |
| 216 | pthread_join(pcr_feed_t, NULL); |
| 217 | } |
| 218 | |
| 219 | static void test() |
| 220 | { |
| 221 | int i = 0; |
| 222 | int session, session_id; |
| 223 | |
| 224 | session = av_sync_open_session(&session_id); |
| 225 | if (session < 0) { |
| 226 | log_error("fail"); |
| 227 | exit(1); |
| 228 | } |
| 229 | v_h = av_sync_create(session_id, AV_SYNC_MODE_PCR_MASTER, AV_SYNC_TYPE_VIDEO, 2); |
| 230 | if (!v_h) { |
| 231 | log_error("fail"); |
| 232 | exit(1); |
| 233 | } |
| 234 | a_h = av_sync_create(session_id, AV_SYNC_MODE_PCR_MASTER, AV_SYNC_TYPE_AUDIO, 0); |
| 235 | if (!a_h) { |
| 236 | log_error("fail"); |
| 237 | exit(1); |
| 238 | } |
| 239 | pcr_h = av_sync_create(session_id, AV_SYNC_MODE_PCR_MASTER, AV_SYNC_TYPE_PCR, 0); |
| 240 | if (!pcr_h) { |
| 241 | log_error("fail"); |
| 242 | exit(1); |
| 243 | } |
| 244 | start_v_thread(); |
| 245 | start_a_thread(); |
| 246 | start_pcr_thread(); |
| 247 | |
| 248 | //wait for 5s |
| 249 | while (i < 100) { |
| 250 | usleep(50 * 1000); |
| 251 | i++; |
| 252 | } |
| 253 | |
| 254 | stop_v_thread(); |
| 255 | stop_a_thread(); |
| 256 | stop_pcr_thread(); |
| 257 | av_sync_destroy(v_h); |
| 258 | av_sync_destroy(a_h); |
| 259 | av_sync_destroy(pcr_h); |
| 260 | av_sync_close_session(session); |
| 261 | } |
| 262 | |
| 263 | int main(int argc, const char** argv) |
| 264 | { |
| 265 | log_set_level(LOG_TRACE); |
| 266 | |
| 267 | log_info("\n----------------start------------\n"); |
| 268 | test(); |
| 269 | log_info("\n----------------end--------------\n"); |
| 270 | |
| 271 | return 0; |
| 272 | } |