UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
testcard2.c
Go to the documentation of this file.
1
8/*
9 * Copyright (c) 2011-2024 CESNET
10 * All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, is permitted provided that the following conditions
14 * are met:
15 *
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 *
19 * 2. Redistributions in binary form must reproduce the above copyright
20 * notice, this list of conditions and the following disclaimer in the
21 * documentation and/or other materials provided with the distribution.
22 *
23 * 3. Neither the name of CESNET nor the names of its contributors may be
24 * used to endorse or promote products derived from this software without
25 * specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
28 * "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
29 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
30 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
31 * EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
32 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
33 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
34 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
37 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
38 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 */
40
41#ifdef HAVE_CONFIG_H
42#include "config.h" // for HAVE_LIBSDL_TTF, HAVE_SDL2
43#endif // defined HAVE_CONFIG_H
44
45#include <assert.h> // for assert
46#include <ctype.h> // for isdigit
47#include <errno.h> // for errno
48#include <limits.h> // for SHRT_MAX
49#include <math.h> // for sin, M_PI
50#include <pthread.h> // for pthread_mutex_lock, pthread_m...
51#include <stdbool.h> // for false, true, bool
52#include <stddef.h> // for ptrdiff_t
53#include <stdint.h> // for uint32_t
54#include <stdio.h> // for NULL, fprintf, printf, stderr
55#include <stdlib.h> // for free, rand, malloc, calloc, atoi
56#include <string.h> // for strchr, strtok_r, strlen, memcpy
57#include <time.h> // for time
58
59#ifdef HAVE_LIBSDL_TTF
60#ifdef HAVE_SDL2
61#include <SDL2/SDL_ttf.h>
62#else
63#include <SDL/SDL_ttf.h>
64#endif
65#endif
66
67#include "audio/types.h" // for audio_frame
68#include "compat/platform_semaphore.h" // for platform_sem_post, platform_s...
69#include "debug.h" // for log_msg, LOG_LEVEL_ERROR, LOG...
70#include "host.h" // for exit_uv, audio_capture_channels
71#include "lib_common.h" // for REGISTER_MODULE, library_class
72#include "testcard_common.h" // for testcard_rect, testcard_conve...
73#include "tv.h" // for tv_diff, tv_add_usec, tv_diff...
74#include "types.h" // for video_desc, RGBA, video_frame
75#include "utils/color_out.h" // for color_printf, TBOLD, TRED
76#include "utils/fs.h" // for MAX_PATH_SIZE
77#include "utils/macros.h" // for IS_KEY_PREFIX, MIN, IF_NOT_NU...
78#include "utils/thread.h" // for set_thread_name
79#include "video.h" // for get_video_desc_from_string
80#include "video_capture.h" // for VIDCAP_INIT_FAIL, VIDCAP_INIT...
81#include "video_capture_params.h" // for vidcap_params_get_fmt, vidcap...
82#include "video_codec.h" // for vc_get_linesize, vc_get_datalen
83#include "video_frame.h" // for parse_fps, vf_alloc_desc, vf_...
84
85#define AUDIO_BUFFER_SIZE (AUDIO_SAMPLE_RATE * AUDIO_BPS * \
86 s->audio.ch_count * BUFFER_SEC)
87#define AUDIO_BPS 2
88#define AUDIO_SAMPLE_RATE 48000
89#define BANNER_HEIGHT 150L
90#define BANNER_MARGIN_BOTTOM 75L
91#define BUFFER_SEC 1
92#define DEFAULT_FORMAT "1920:1080:24:UYVY"
93#define EPS_PLUS_1 1.0001
94#define FONT_HEIGHT 108
95#define MOD_NAME "[testcard2] "
96
97#ifdef HAVE_LIBSDL_TTF
98#ifdef _WIN32
99#define DEFAULT_FONT_DIR "C:\\windows\\fonts"
100static const char * const font_candidates[] = { "cour.ttf", };
101#elif defined __APPLE__
102#define DEFAULT_FONT_DIR "/System/Library/Fonts"
103static const char *const font_candidates[] = {
104 "Monaco.ttf",
105 "Monaco.dfont",
106 "Geneva.ttf",
107 "Keyboard.ttf",
108};
109#else
110#define DEFAULT_FONT_DIR "/usr/share/fonts"
111static const char *const font_candidates[] = {
112 "DejaVuSansMono.ttf", // bundled in AppImage
113 "truetype/freefont/FreeMonoBold.ttf", "truetype/dejavu/DejaVuSansMono.ttf", // Ubuntu
114 "TTF/DejaVuSansMono.ttf", "liberation/LiberationMono-Regular.ttf", // Arch
115 "liberation-mono/LiberationMono-Regular.ttf", // Fedora
116};
117#endif
118#endif // defined HAVE_LIBSDL_TTF
119
120void * vidcap_testcard2_thread(void *args);
121
123
124 int count;
125 unsigned char *bg;
126 struct timeval t0;
128 char *data;
129 pthread_mutex_t lock;
130 pthread_cond_t data_consumed_cv;
132 struct timeval start_time;
134
137 struct timeval last_audio_time;
139 unsigned int grab_audio:1;
141
142 pthread_t thread_id;
143
144 volatile bool should_exit;
145};
146
147static int configure_audio(struct testcard_state2 *s)
148{
149 s->audio.bps = AUDIO_BPS;
152
153 s->audio_silence = calloc(1, AUDIO_BUFFER_SIZE /* 1 sec */);
154
155 s->audio_tone = calloc(1, AUDIO_BUFFER_SIZE /* 1 sec */);
156 short int * data = (short int *)(void *) s->audio_tone;
157 for(int i=0; i < (int) AUDIO_BUFFER_SIZE/2; i+=2 )
158 {
159 data[i] = data[i+1] = (float) sin( ((double)i/(double)200) * M_PI * 2. ) * SHRT_MAX;
160 }
161
162 printf("[testcard2] playing audio\n");
163
164 return 0;
165}
166
167static bool parse_fmt(struct testcard_state2 *s, char *fmt) {
168 char *save_ptr = 0;
169 char *tmp = strtok_r(fmt, ":", &save_ptr);
170 if (!tmp) {
171 log_msg(LOG_LEVEL_ERROR, "Missing width for testcard\n");
172 return false;
173 }
174 errno = 0;
175 s->desc.width = strtol(tmp, NULL, 10);
176 if (s->desc.width == 0 || s->desc.width % 2 != 0 || errno != 0) {
178 "Width must be a positive multiple of 2.\n");
179 return false;
180 }
181 tmp = strtok_r(NULL, ":", &save_ptr);
182 if (tmp == NULL) {
183 log_msg(LOG_LEVEL_ERROR, "Missing height for testcard\n");
184 return false;
185 }
186 s->desc.height = strtol(tmp, NULL, 10);
187 if (s->desc.height == 0 || errno != 0) {
188 log_msg(LOG_LEVEL_ERROR, "Wrong height: %s.\n", tmp);
189 return false;
190 }
191 tmp = strtok_r(NULL, ":", &save_ptr);
192 if (tmp == NULL) {
193 log_msg(LOG_LEVEL_ERROR, "Missing FPS for testcard\n");
194 return false;
195 }
196 if (!parse_fps(tmp, &s->desc)) {
197 log_msg(LOG_LEVEL_ERROR, "Wrong FPS for testcard\n");
198 return false;
199 }
200
201 tmp = strtok_r(NULL, ":", &save_ptr);
202 if (tmp == NULL || get_codec_from_name(tmp) == VIDEO_CODEC_NONE) {
203 log_msg(LOG_LEVEL_ERROR, "Missing/wrong codec for testcard\n");
204 return false;
205 }
207 return true;
208}
209
211{
212 if (vidcap_params_get_fmt(params) == NULL || strcmp(vidcap_params_get_fmt(params), "help") == 0) {
213 color_printf("testcard2 is an alternative implementation of testing signal source.\n");
214 color_printf("It is less maintained than mainline testcard and has less features but has some extra ones, i. a. a timer (if SDL(2)_ttf is found.\n");
215 color_printf("\n");
216 color_printf("testcard2 options:\n");
217 color_printf(TBOLD(TRED("\t-t testcard2") "[:<width>:<height>:<fps>:<codec>]") "\n");
218 color_printf("or\n");
219 color_printf(TBOLD(TRED("\t-t testcard2") "[:size=<width>x<height>][:fps=<fps>][:codec=<codec>][:mode=<mode>]") "\n");
220 testcard_show_codec_help("testcard2", true);
221
222 return VIDCAP_INIT_NOERR;
223 }
224
225 struct testcard_state2 *s = calloc(1, sizeof(struct testcard_state2));
226 if (!s)
227 return VIDCAP_INIT_FAIL;
228 s->desc.tile_count = 1;
230
232 char *ptr = fmt;
233
234 if (strlen(ptr) > 0 && isdigit(ptr[0])) {
235 bool ret = parse_fmt(s, fmt);
236 free(fmt);
237 if (!ret) {
238 free(s);
239 return VIDCAP_INIT_FAIL;
240 }
241 } else {
242 char *default_fmt = strdup(DEFAULT_FORMAT);
243 parse_fmt(s, default_fmt);
244 free(default_fmt);
245
246 bool ret = true;
247 char *save_ptr = NULL;
248 char *tmp = strtok_r(ptr, ":", &save_ptr);
249 while (tmp) {
250 if (IS_KEY_PREFIX(tmp, "codec")) {
251 s->desc.color_spec = get_codec_from_name(strchr(tmp, '=') + 1);
252 if (s->desc.color_spec == VIDEO_CODEC_NONE) {
253 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Wrong color spec: %s\n", strchr(tmp, '=') + 1);
254 ret = false;
255 break;
256 }
257 } else if (IS_KEY_PREFIX(tmp, "mode")) {
258 codec_t saved_codec = s->desc.color_spec;
259 s->desc = get_video_desc_from_string(strchr(tmp, '=') + 1);
260 s->desc.color_spec = saved_codec;
261 } else if (IS_KEY_PREFIX(tmp, "size")) {
262 tmp = strchr(tmp, '=') + 1;
263 if (isdigit(tmp[0]) && strchr(tmp, 'x') != NULL) {
264 s->desc.width = atoi(tmp);
265 s->desc.height = atoi(strchr(tmp, 'x') + 1);
266 } else {
267 struct video_desc size_dsc =
269 s->desc.width = size_dsc.width;
270 s->desc.height = size_dsc.height;
271 }
272 } else if (IS_KEY_PREFIX(tmp, "fps")) {
273 if (!parse_fps(strchr(tmp, '=') + 1, &s->desc)) {
274 ret = false;
275 break;
276 }
277 } else {
278 fprintf(stderr, "[testcard2] Unknown option: %s\n", tmp);
279 ret = false;
280 break;
281 }
282 tmp = strtok_r(NULL, ":", &save_ptr);
283 }
284 free(fmt);
285 if (!ret) {
286 free(s);
287 return VIDCAP_INIT_FAIL;
288 }
289 }
290
291 if (s->desc.width <= 0 || s->desc.height <= 0) {
292 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Wrong video size, given: %dx%d\n",
293 s->desc.width, s->desc.height);
294 free(s);
295 return VIDCAP_INIT_FAIL;
296 }
297
298 {
299 unsigned int rect_size = (s->desc.width + COL_NUM - 1) / COL_NUM;
300 int col_num = 0;
301 struct testcard_pixmap surface;
302 surface.data = malloc(vc_get_datalen(s->desc.width, s->desc.height, RGBA));
303 surface.w = s->desc.width;
304 surface.h = s->desc.height;
305 for (unsigned i = 0; i < s->desc.width; i += rect_size) {
306 struct testcard_rect r;
307 r.w = MIN(rect_size, s->desc.width - i);
308 r.h = s->desc.height;
309 r.x = i;
310 r.y = 0;
311 log_msg(LOG_LEVEL_VERBOSE, MOD_NAME "Fill rect at %d,%d\n", r.x, r.y);
312 testcard_fillRect(&surface, &r,
313 rect_colors[col_num]);
314 col_num = (col_num + 1) % COL_NUM;
315 }
316 s->bg = malloc(vc_get_datalen(s->desc.width, s->desc.height, s->desc.color_spec));
318 free(surface.data);
319 }
320
322 s->grab_audio = 1;
323 if(configure_audio(s) != 0) {
324 s->grab_audio = 0;
325 fprintf(stderr, "[testcard2] Disabling audio output. "
326 "\n");
327 }
328 } else {
329 s->grab_audio = 0;
330 }
331
332 s->count = 0;
333 s->audio_remained = 0.0;
334 s->seconds_tone_played = 0.0;
335 s->play_audio_frame = 0;
336
337 platform_sem_init(&s->semaphore, 0, 0);
338 printf("Testcard capture set to %dx%d\n", s->desc.width, s->desc.height);
339
341 s->grab_audio = 1;
342 if(configure_audio(s) != 0) {
343 s->grab_audio = 0;
344 fprintf(stderr, "[testcard] Disabling audio output. "
345 "SDL-mixer missing, running on Mac or other problem.");
346 }
347 } else {
348 s->grab_audio = 0;
349 }
350
351 if(!s->grab_audio) {
352 s->audio_tone = NULL;
353 s->audio_silence = NULL;
354 }
355
356 gettimeofday(&s->start_time, NULL);
357
358 pthread_mutex_init(&s->lock, NULL);
359 pthread_cond_init(&s->data_consumed_cv, NULL);
360
361 pthread_create(&s->thread_id, NULL, vidcap_testcard2_thread, s);
362
363 *state = s;
364 return VIDCAP_INIT_OK;
365}
366
367static void vidcap_testcard2_done(void *state)
368{
369 struct testcard_state2 *s = state;
370
371 pthread_mutex_lock(&s->lock);
372 free(s->data);
373 s->data = NULL;
374 s->should_exit = true;
375 pthread_mutex_unlock(&s->lock);
376 pthread_cond_signal(&s->data_consumed_cv);
377
378 pthread_join(s->thread_id, NULL);
379
380 pthread_mutex_destroy(&s->lock);
381 pthread_cond_destroy(&s->data_consumed_cv);
382 free(s->audio_tone);
383 free(s->audio_silence);
384 free(s->bg);
385 free(s->data);
386 free(s);
387}
388
394void * vidcap_testcard2_thread(void *arg)
395{
396 set_thread_name(__func__);
397
398 struct testcard_state2 *s;
399 s = (struct testcard_state2 *)arg;
400 struct timeval next_frame_time = { 0 };
401 srand(time(NULL));
402 int prev_x1 = rand() % ((s->desc.width - 300) / 6) * 6;
403 int prev_y1 = rand() % ((s->desc.height - 300) / 6) * 6;
404 int down1 = rand() % 2, right1 = rand() % 2;
405 int prev_x2 = rand() % ((s->desc.width - 96) / 6) * 6;
406 int prev_y2 = rand() % ((s->desc.height - 96) / 6) * 6;
407 int down2 = rand() % 2, right2 = rand() % 2;
408
409 int stat_count_prev = 0;
410
411 gettimeofday(&s->last_audio_time, NULL);
412
413#ifdef HAVE_LIBSDL_TTF
414#define EXIT_THREAD { free(banner); exit_uv(1); s->should_exit = true; platform_sem_post(&s->semaphore); return NULL; }
415 TTF_Font * font = NULL;
416 uint32_t *banner = malloc(vc_get_datalen(s->desc.width, BANNER_HEIGHT, RGBA));
417 if(TTF_Init() == -1)
418 {
419 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Unable to initialize SDL_ttf: %s\n",
420 TTF_GetError());
421 EXIT_THREAD
422 }
423
424 const char *font_dir = IF_NOT_NULL_ELSE(getenv("UG_FONT_DIR"), DEFAULT_FONT_DIR);
425 char font_path[MAX_PATH_SIZE] = "";
426 for (unsigned i = 0; font == NULL && i < sizeof font_candidates / sizeof font_candidates[0]; ++i) {
427 strncpy(font_path, font_dir, sizeof font_path - 1); // NOLINT (security.insecureAPI.strcpy)
428 strncat(font_path, "/", sizeof font_path - strlen(font_path) - 1); // NOLINT (security.insecureAPI.strcpy)
429 strncat(font_path, font_candidates[i], sizeof font_path - strlen(font_path) - 1); // NOLINT (security.insecureAPI.strcpy)
430 font = TTF_OpenFont(font_path, FONT_HEIGHT);
431 if (font == NULL) {
432 MSG(VERBOSE, "Tried font %s: %s\n", font_path,
433 TTF_GetError());
434 }
435 }
436 if(!font) {
437 MSG(ERROR,
438 "Unable to load any usable font! Last font tried %s: %s\n",
439 font_path, TTF_GetError());
440 EXIT_THREAD
441 }
442 MSG(INFO, "Using font: %s\n", font_path);
443
444#endif
446 unsigned char square_cols[2][48];
447 uint32_t src[6 + MAX_PADDING] = { 0 };
448 testcard_convert_buffer(RGBA, s->desc.color_spec, square_cols[0], (unsigned char *) src, 6, 1);
449 for (int i = 0; i < 6; ++i) src[i] = 0xffff00aa;
450 testcard_convert_buffer(RGBA, s->desc.color_spec, square_cols[1], (unsigned char *) src, 6, 1);
451
452 ptrdiff_t block_size = 6 * EPS_PLUS_1 * get_bpp(s->desc.color_spec);
453
454 while(!s->should_exit)
455 {
456 size_t data_len = vc_get_datalen(s->desc.width, s->desc.height, s->desc.color_spec);
457 unsigned char *tmp = malloc(data_len);
458 memcpy(tmp, s->bg, data_len);
459
460 struct testcard_rect r;
461 r.w = 300;
462 r.h = 300;
463 r.x = prev_x1 + (right1 ? 1 : -1) * 6;
464 r.y = prev_y1 + (down1 ? 1 : -1) * 6;
465 if(r.x < 0) { right1 = 1; r.x = 0; }
466 if(r.y < 0) { down1 = 1; r.y = 0; }
467 if((unsigned int) r.x + r.w > s->desc.width) { right1 = 0; r.w = s->desc.width - r.x; }
468 if((unsigned int) r.y + r.h > s->desc.height) { down1 = 0; r.h = s->desc.height - r.y; }
469 prev_x1 = r.x;
470 prev_y1 = r.y;
471
472 unsigned char *ptr = tmp + r.y * vc_get_linesize(s->desc.width, s->desc.color_spec) + (int) (r.x * EPS_PLUS_1 * get_bpp(s->desc.color_spec));
473 for (int y = 0; y < r.h; ++y) {
474 for (int x = 0; x < r.w / 6; x += 1) {
475 memcpy(ptr + block_size * x, square_cols[0], block_size);
476 }
478 }
479
480 r.w = 96;
481 r.h = 96;
482 r.x = prev_x2 + (right2 ? 1 : -1) * 12;
483 r.y = prev_y2 + (down2 ? 1 : -1) * 9;
484 if(r.x < 0) { right2 = 1; r.x = 0; }
485 if(r.y < 0) { down2 = 1; r.y = 0; }
486 if((unsigned int) r.x + r.w > s->desc.width) { right2 = 0; r.w = s->desc.width - r.x; }
487 if((unsigned int) r.y + r.h > s->desc.height) { down2 = 0; r.h = s->desc.height - r.y; }
488 prev_x2 = r.x;
489 prev_y2 = r.y;
490
491 ptr = tmp + (long) r.y * vc_get_linesize(s->desc.width, s->desc.color_spec) + (long) (r.x * EPS_PLUS_1 * get_bpp(s->desc.color_spec));
492 for (int y = 0; y < r.h; ++y) {
493 for (int x = 0; x < r.w / 6; x += 1) {
494 memcpy(ptr + block_size * x, square_cols[1], block_size);
495 }
497 }
498
499#ifdef HAVE_LIBSDL_TTF
500 memset(banner, 0xFF, 4L * s->desc.width * BANNER_HEIGHT);
501
502 SDL_Color col = { 0, 0, 0, 0 };
503
504 char frames[64];
505 double since_start = tv_diff(next_frame_time, s->start_time);
506 snprintf(frames, sizeof frames, "%02d:%02d:%02d %3d", (int) since_start / 3600,
507 (int) since_start / 60 % 60,
508 (int) since_start % 60,
509 s->count % (int) s->desc.fps);
510 SDL_Surface *text = TTF_RenderText_Solid(font,
511 frames, col);
512 long xoff = ((long) s->desc.width - text->w) / 2;
513 long yoff = (BANNER_HEIGHT - text->h) / 2;
514 for (int i = 0 ; i < text->h; i++) {
515 uint32_t *d = banner + xoff + (i + yoff) * s->desc.width;
516 for (int j = 0 ; j < MIN(text->w, (int) s->desc.width - xoff); j++) {
517 if (((char *)text->pixels) [i * text->pitch + j]) {
518 *d = 0x00000000U;
519 }
520 d++;
521 }
522 }
524 SDL_FreeSurface(text);
525#endif
526
527next_frame:
528 next_frame_time = s->start_time;
529 long long since_start_usec = (s->count * 1000000LLU) / s->desc.fps;
530 tv_add_usec(&next_frame_time, since_start_usec);
531 struct timeval curr_time;
532 gettimeofday(&curr_time, NULL);
533 if(tv_gt(next_frame_time, curr_time)) {
534 int sleep_time = tv_diff_usec(next_frame_time, curr_time);
535 usleep(sleep_time);
536 } else {
537 if((++s->count) % ((int) s->desc.fps * 5) == 0) {
538 s->play_audio_frame = 1;
539 }
540 ++stat_count_prev;
541 goto next_frame;
542 }
543
544 if((++s->count) % ((int) s->desc.fps * 5) == 0) {
545 s->play_audio_frame = 1;
546 }
547 pthread_mutex_lock(&s->lock);
548 while (s->data != NULL) {
549 pthread_cond_wait(&s->data_consumed_cv, &s->lock);
550 }
551 s->data = (char *) tmp;
552 pthread_mutex_unlock(&s->lock);
554
555 double seconds = tv_diff(curr_time, s->t0);
556 if (seconds >= 5) {
557 float fps = (s->count - stat_count_prev) / seconds;
558 log_msg(LOG_LEVEL_INFO, "[testcard2] %d frames in %g seconds = %g FPS\n",
559 (s->count - stat_count_prev), seconds, fps);
560 s->t0 = curr_time;
561 stat_count_prev = s->count;
562 }
563 }
564
565#ifdef HAVE_LIBSDL_TTF
566 free(banner);
567#endif
568
569 return NULL;
570}
571
572static void grab_audio(struct testcard_state2 *s)
573{
574 struct timeval curr_time;
575 gettimeofday(&curr_time, NULL);
576
577 double seconds = tv_diff(curr_time, s->last_audio_time);
578 if(s->play_audio_frame) {
579 s->seconds_tone_played = 0.0;
580 s->play_audio_frame = 0;
581 }
582
583 s->audio.data_len = ((int)((seconds + s->audio_remained) * AUDIO_SAMPLE_RATE));
584 if(s->seconds_tone_played < 1.0) {
585 s->audio.data = s->audio_tone;
586 s->audio.data_len = s->audio.data_len / 400 * 400;
587 } else {
588 s->audio.data = s->audio_silence;
589 }
590
592
596
597 s->last_audio_time = curr_time;
598}
599
600static struct video_frame *vidcap_testcard2_grab(void *arg, struct audio_frame **audio)
601{
602 struct testcard_state2 *s = (struct testcard_state2 *)arg;
603
604 if (s->should_exit) {
605 return NULL;
606 }
608 if (s->should_exit) {
609 return NULL;
610 }
611 assert(s->data != NULL);
612
613 struct video_frame *frame = vf_alloc_desc(s->desc);
616
617 pthread_mutex_lock(&s->lock);
618 frame->tiles[0].data = s->data;
619 s->data = NULL;
620 pthread_mutex_unlock(&s->lock);
621 pthread_cond_signal(&s->data_consumed_cv);
622
623 *audio = NULL;
624 if(s->grab_audio){
625 grab_audio(s);
626 if(s->audio.data_len)
627 *audio = &s->audio;
628 else
629 *audio = NULL;
630 }
631
632 return frame;
633}
634
635static void vidcap_testcard2_probe(struct device_info **available_devices, int *count, void (**deleter)(void *))
636{
637 *deleter = free;
638 *available_devices = NULL;
639 *count = 0;
640}
641
649
651
void ** state
struct video_frame * frame
const char * fmt
struct audio_frame ** audio
int void(** deleter)(void *))
void vf_free(struct video_frame *buf)
Frees video_frame structure.
void vf_data_deleter(struct video_frame *buf)
int vc_get_linesize(unsigned int width, codec_t codec)
struct video_frame * vf_alloc_desc(struct video_desc desc)
Allocates video frame accordig given desc.
codec_t get_codec_from_name(const char *name)
This file contains definition of some common audio types.
static const unsigned char font[]
Definition bitmap_font.h:13
int color_printf(const char *format,...)
#define TRED(x)
Definition color_out.h:75
#define TBOLD(x)
Definition color_out.h:70
void log_msg(int level, const char *format,...)
Definition debug.cpp:130
#define LOG_LEVEL_INFO
normal reporting
Definition debug.h:62
#define LOG_LEVEL_ERROR
general errors
Definition debug.h:59
#define LOG_LEVEL_VERBOSE
Definition debug.h:63
#define MSG(l, fmt,...)
Definition debug.h:96
#define MAX_PATH_SIZE
Definition fs.h:48
#define VIDCAP_INIT_NOERR
state not initialized, other action performed (typically help)
#define VIDCAP_INIT_OK
initialization successful
#define VIDCAP_NO_GENERIC_FPS_INDICATOR
#define VIDEO_CAPTURE_ABI_VERSION
#define VIDCAP_INIT_FAIL
error ocured
int count
Definition hd-rum.c:44
unsigned int audio_capture_channels
Definition host.cpp:163
#define DEFAULT_AUDIO_CAPTURE_CHANNELS
Definition host.h:89
@ LIBRARY_CLASS_VIDEO_CAPTURE
Definition lib_common.h:78
#define REGISTER_MODULE(name, info, lclass, abi)
Registers module to global modules' registry.
Definition lib_common.h:144
#define MIN(a, b)
Definition macros.h:63
#define IS_KEY_PREFIX(tok, key)
expands to true value if <k> from tok in format <k>=<v> is prefix of key
Definition macros.h:138
#define IF_NOT_NULL_ELSE(val, default_val)
Definition macros.h:51
void platform_sem_post(void *semStructure)
void platform_sem_wait(void *semStructure)
void platform_sem_init(void *semStructure, int pshared, int initialValue)
struct used to comunicate with audio capture/playback device
Definition types.h:99
int sample_rate
Definition types.h:101
char * data
Definition types.h:102
int ch_count
Definition types.h:104
int data_len
Definition types.h:103
int bps
Definition types.h:100
char * audio_tone
Definition testcard2.c:138
struct timeval start_time
Definition testcard2.c:132
pthread_cond_t data_consumed_cv
Definition testcard2.c:130
struct timeval t0
Definition testcard2.c:126
char * audio_silence
Definition testcard2.c:138
double seconds_tone_played
Definition testcard2.c:136
unsigned int grab_audio
Definition testcard2.c:139
struct video_desc desc
Definition testcard2.c:127
pthread_t thread_id
Definition testcard2.c:142
pthread_mutex_t lock
Definition testcard2.c:129
volatile bool should_exit
Definition testcard2.c:144
double audio_remained
Definition testcard2.c:135
unsigned char * bg
bars coverted to dest color_spec
Definition testcard2.c:125
struct timeval last_audio_time
Definition testcard2.c:137
struct audio_frame audio
Definition testcard2.c:131
char * data
Raw tile data. Pointer must be at least 4B aligned.
Definition types.h:287
unsigned int tile_count
Definition types.h:185
codec_t color_spec
Definition types.h:182
enum interlacing_t interlacing
Definition types.h:184
double fps
Definition types.h:183
unsigned int width
width of every tile (!)
Definition types.h:179
unsigned int height
height of every tile (!)
Definition types.h:180
void(* data_deleter)(struct video_frame *)
Definition types.h:256
void(* dispose)(struct video_frame *)
Definition types.h:245
Struct video_frame represents a video frame and contains video description.
Definition types.h:305
struct tile tiles[FLEXIBLE_ARRAY_MEMBER]
Definition types.h:345
struct video_frame_callbacks callbacks
Definition types.h:324
#define AUDIO_BUFFER_SIZE
Definition testcard2.c:85
#define FONT_HEIGHT
Definition testcard2.c:94
#define AUDIO_SAMPLE_RATE
Definition testcard2.c:88
static int configure_audio(struct testcard_state2 *s)
Definition testcard2.c:147
#define EPS_PLUS_1
Definition testcard2.c:93
static void vidcap_testcard2_probe(struct device_info **available_devices, int *count, void(**deleter)(void *))
Definition testcard2.c:635
static bool parse_fmt(struct testcard_state2 *s, char *fmt)
Definition testcard2.c:167
#define BANNER_HEIGHT
Definition testcard2.c:89
#define DEFAULT_FORMAT
Definition testcard2.c:92
#define AUDIO_BPS
Definition testcard2.c:87
static void grab_audio(struct testcard_state2 *s)
Definition testcard2.c:572
static int vidcap_testcard2_init(struct vidcap_params *params, void **state)
Definition testcard2.c:210
static struct video_frame * vidcap_testcard2_grab(void *arg, struct audio_frame **audio)
Definition testcard2.c:600
#define MOD_NAME
Definition testcard2.c:95
static const struct video_capture_info vidcap_testcard2_info
Definition testcard2.c:642
static void vidcap_testcard2_done(void *state)
Definition testcard2.c:367
#define BANNER_MARGIN_BOTTOM
Definition testcard2.c:90
void * vidcap_testcard2_thread(void *args)
Definition testcard2.c:394
const uint32_t rect_colors[]
void testcard_show_codec_help(const char *name, bool src_8b_only)
void testcard_fillRect(struct testcard_pixmap *s, struct testcard_rect *r, uint32_t color)
void testcard_convert_buffer(codec_t in_c, codec_t out_c, unsigned char *out, unsigned const char *in, int width, int height)
#define COL_NUM
void set_thread_name(const char *name)
Definition thread.c:72
uint32_t tv_diff_usec(struct timeval curr_time, struct timeval prev_time)
Definition tv.c:109
void tv_add_usec(struct timeval *ts, long long offset) __attribute__((always_inline))
Definition tv.c:135
int tv_gt(struct timeval a, struct timeval b)
Definition tv.c:153
double tv_diff(struct timeval curr_time, struct timeval prev_time)
Definition tv.c:97
This file contains some common data types.
@ PROGRESSIVE
progressive frame
Definition types.h:164
codec_t
Definition types.h:65
@ VIDEO_CODEC_NONE
dummy color spec
Definition types.h:66
@ RGBA
RGBA 8-bit, big-endian.
Definition types.h:70
int usleep(unsigned int usec)
Definition usleep.c:47
static double parse_fps(const char *string, bool interlaced)
Definition video.cpp:253
struct video_desc get_video_desc_from_string(const char *string)
Definition video.cpp:291
This is an umbrella header for video functions.
const char * vidcap_params_get_fmt(const struct vidcap_params *params)
unsigned int vidcap_params_get_flags(const struct vidcap_params *params)
#define VIDCAP_FLAG_AUDIO_EMBEDDED
HD-SDI embedded audio.
double get_bpp(codec_t codec)
size_t vc_get_datalen(unsigned int width, unsigned int height, codec_t codec)
#define MAX_PADDING
Definition video_codec.h:63