blob: 699c8d11290d475f8df4227db1fdee259348aa52 [file] [log] [blame]
Tristan Matthews0a329cc2013-07-17 13:20:14 -04001/* $Id$ */
2/*
3 * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19#include <pjmedia-videodev/videodev_imp.h>
20#include <pj/assert.h>
21#include <pj/log.h>
22#include <pj/os.h>
23#include <pj/rand.h>
24
25
26#if defined(PJMEDIA_VIDEO_DEV_HAS_CBAR_SRC) && \
27 PJMEDIA_VIDEO_DEV_HAS_CBAR_SRC != 0
28
29
30#define THIS_FILE "colorbar_dev.c"
31#define DEFAULT_CLOCK_RATE 90000
32#define DEFAULT_WIDTH 352 //640
33#define DEFAULT_HEIGHT 288 //480
34#define DEFAULT_FPS 25
35
36/* cbar_ device info */
37struct cbar_dev_info
38{
39 pjmedia_vid_dev_info info;
40};
41
42/* cbar_ factory */
43struct cbar_factory
44{
45 pjmedia_vid_dev_factory base;
46 pj_pool_t *pool;
47 pj_pool_factory *pf;
48
49 unsigned dev_count;
50 struct cbar_dev_info *dev_info;
51};
52
53struct cbar_fmt_info {
54 pjmedia_format_id fmt_id; /* Format ID */
55
56 /* Info for packed formats. */
57 unsigned c_offset[3]; /* Color component offset,
58 in bytes */
59 unsigned c_stride[3]; /* Color component stride,
60 or distance between two
61 consecutive same color
62 components, in bytes */
63};
64
65/* Colorbar video source supports */
66static struct cbar_fmt_info cbar_fmts[] =
67{
68 /* Packed formats */
69 { PJMEDIA_FORMAT_YUY2, {0, 1, 3}, {2, 4, 4} },
70 { PJMEDIA_FORMAT_UYVY, {1, 0, 2}, {2, 4, 4} },
71 { PJMEDIA_FORMAT_YVYU, {0, 3, 1}, {2, 4, 4} },
72 { PJMEDIA_FORMAT_RGBA, {0, 1, 2}, {4, 4, 4} },
73 { PJMEDIA_FORMAT_RGB24, {0, 1, 2}, {3, 3, 3} },
74 { PJMEDIA_FORMAT_BGRA, {2, 1, 0}, {4, 4, 4} },
75
76 /* Planar formats */
77 { PJMEDIA_FORMAT_YV12 },
78 { PJMEDIA_FORMAT_I420 },
79 { PJMEDIA_FORMAT_I422 },
80 { PJMEDIA_FORMAT_I420JPEG },
81 { PJMEDIA_FORMAT_I422JPEG },
82};
83
84/* Video stream. */
85struct cbar_stream
86{
87 pjmedia_vid_dev_stream base; /**< Base stream */
88 pjmedia_vid_dev_param param; /**< Settings */
89 pj_pool_t *pool; /**< Memory pool. */
90
91 pjmedia_vid_dev_cb vid_cb; /**< Stream callback. */
92 void *user_data; /**< Application data. */
93
94 const struct cbar_fmt_info *cbfi;
95 const pjmedia_video_format_info *vfi;
96 pjmedia_video_apply_fmt_param vafp;
97 pj_uint8_t *first_line[PJMEDIA_MAX_VIDEO_PLANES];
98 pj_timestamp ts;
99 unsigned ts_inc;
100};
101
102
103/* Prototypes */
104static pj_status_t cbar_factory_init(pjmedia_vid_dev_factory *f);
105static pj_status_t cbar_factory_destroy(pjmedia_vid_dev_factory *f);
106static pj_status_t cbar_factory_refresh(pjmedia_vid_dev_factory *f);
107static unsigned cbar_factory_get_dev_count(pjmedia_vid_dev_factory *f);
108static pj_status_t cbar_factory_get_dev_info(pjmedia_vid_dev_factory *f,
109 unsigned index,
110 pjmedia_vid_dev_info *info);
111static pj_status_t cbar_factory_default_param(pj_pool_t *pool,
112 pjmedia_vid_dev_factory *f,
113 unsigned index,
114 pjmedia_vid_dev_param *param);
115static pj_status_t cbar_factory_create_stream(
116 pjmedia_vid_dev_factory *f,
117 pjmedia_vid_dev_param *param,
118 const pjmedia_vid_dev_cb *cb,
119 void *user_data,
120 pjmedia_vid_dev_stream **p_vid_strm);
121
122static pj_status_t cbar_stream_get_param(pjmedia_vid_dev_stream *strm,
123 pjmedia_vid_dev_param *param);
124static pj_status_t cbar_stream_get_cap(pjmedia_vid_dev_stream *strm,
125 pjmedia_vid_dev_cap cap,
126 void *value);
127static pj_status_t cbar_stream_set_cap(pjmedia_vid_dev_stream *strm,
128 pjmedia_vid_dev_cap cap,
129 const void *value);
130static pj_status_t cbar_stream_get_frame(pjmedia_vid_dev_stream *strm,
131 pjmedia_frame *frame);
132static pj_status_t cbar_stream_start(pjmedia_vid_dev_stream *strm);
133static pj_status_t cbar_stream_stop(pjmedia_vid_dev_stream *strm);
134static pj_status_t cbar_stream_destroy(pjmedia_vid_dev_stream *strm);
135
136/* Operations */
137static pjmedia_vid_dev_factory_op factory_op =
138{
139 &cbar_factory_init,
140 &cbar_factory_destroy,
141 &cbar_factory_get_dev_count,
142 &cbar_factory_get_dev_info,
143 &cbar_factory_default_param,
144 &cbar_factory_create_stream,
145 &cbar_factory_refresh
146};
147
148static pjmedia_vid_dev_stream_op stream_op =
149{
150 &cbar_stream_get_param,
151 &cbar_stream_get_cap,
152 &cbar_stream_set_cap,
153 &cbar_stream_start,
154 &cbar_stream_get_frame,
155 NULL,
156 &cbar_stream_stop,
157 &cbar_stream_destroy
158};
159
160
161/****************************************************************************
162 * Factory operations
163 */
164/*
165 * Init cbar_ video driver.
166 */
167pjmedia_vid_dev_factory* pjmedia_cbar_factory(pj_pool_factory *pf)
168{
169 struct cbar_factory *f;
170 pj_pool_t *pool;
171
172 pool = pj_pool_create(pf, "cbar video", 512, 512, NULL);
173 f = PJ_POOL_ZALLOC_T(pool, struct cbar_factory);
174 f->pf = pf;
175 f->pool = pool;
176 f->base.op = &factory_op;
177
178 return &f->base;
179}
180
181
182/* API: init factory */
183static pj_status_t cbar_factory_init(pjmedia_vid_dev_factory *f)
184{
185 struct cbar_factory *cf = (struct cbar_factory*)f;
186 struct cbar_dev_info *ddi;
187 unsigned i;
188
189 cf->dev_count = 1;
190 cf->dev_info = (struct cbar_dev_info*)
191 pj_pool_calloc(cf->pool, cf->dev_count,
192 sizeof(struct cbar_dev_info));
193
194 ddi = &cf->dev_info[0];
195 pj_bzero(ddi, sizeof(*ddi));
196 pj_ansi_strncpy(ddi->info.name, "Colorbar generator",
197 sizeof(ddi->info.name));
198 ddi->info.driver[sizeof(ddi->info.driver)-1] = '\0';
199 pj_ansi_strncpy(ddi->info.driver, "Colorbar", sizeof(ddi->info.driver));
200 ddi->info.driver[sizeof(ddi->info.driver)-1] = '\0';
201 ddi->info.dir = PJMEDIA_DIR_CAPTURE;
202 ddi->info.has_callback = PJ_FALSE;
203
204 ddi->info.caps = PJMEDIA_VID_DEV_CAP_FORMAT;
205 ddi->info.fmt_cnt = sizeof(cbar_fmts)/sizeof(cbar_fmts[0]);
206 for (i = 0; i < ddi->info.fmt_cnt; i++) {
207 pjmedia_format *fmt = &ddi->info.fmt[i];
208 pjmedia_format_init_video(fmt, cbar_fmts[i].fmt_id,
209 DEFAULT_WIDTH, DEFAULT_HEIGHT,
210 DEFAULT_FPS, 1);
211 }
212
213 PJ_LOG(4, (THIS_FILE, "Colorbar video src initialized with %d device(s):",
214 cf->dev_count));
215 for (i = 0; i < cf->dev_count; i++) {
216 PJ_LOG(4, (THIS_FILE, "%2d: %s", i, cf->dev_info[i].info.name));
217 }
218
219 return PJ_SUCCESS;
220}
221
222/* API: destroy factory */
223static pj_status_t cbar_factory_destroy(pjmedia_vid_dev_factory *f)
224{
225 struct cbar_factory *cf = (struct cbar_factory*)f;
226 pj_pool_t *pool = cf->pool;
227
228 cf->pool = NULL;
229 pj_pool_release(pool);
230
231 return PJ_SUCCESS;
232}
233
234/* API: refresh the list of devices */
235static pj_status_t cbar_factory_refresh(pjmedia_vid_dev_factory *f)
236{
237 PJ_UNUSED_ARG(f);
238 return PJ_SUCCESS;
239}
240
241/* API: get number of devices */
242static unsigned cbar_factory_get_dev_count(pjmedia_vid_dev_factory *f)
243{
244 struct cbar_factory *cf = (struct cbar_factory*)f;
245 return cf->dev_count;
246}
247
248/* API: get device info */
249static pj_status_t cbar_factory_get_dev_info(pjmedia_vid_dev_factory *f,
250 unsigned index,
251 pjmedia_vid_dev_info *info)
252{
253 struct cbar_factory *cf = (struct cbar_factory*)f;
254
255 PJ_ASSERT_RETURN(index < cf->dev_count, PJMEDIA_EVID_INVDEV);
256
257 pj_memcpy(info, &cf->dev_info[index].info, sizeof(*info));
258
259 return PJ_SUCCESS;
260}
261
262/* API: create default device parameter */
263static pj_status_t cbar_factory_default_param(pj_pool_t *pool,
264 pjmedia_vid_dev_factory *f,
265 unsigned index,
266 pjmedia_vid_dev_param *param)
267{
268 struct cbar_factory *cf = (struct cbar_factory*)f;
269 struct cbar_dev_info *di = &cf->dev_info[index];
270
271 PJ_ASSERT_RETURN(index < cf->dev_count, PJMEDIA_EVID_INVDEV);
272
273 PJ_UNUSED_ARG(pool);
274
275 pj_bzero(param, sizeof(*param));
276 param->dir = PJMEDIA_DIR_CAPTURE;
277 param->cap_id = index;
278 param->rend_id = PJMEDIA_VID_INVALID_DEV;
279 param->flags = PJMEDIA_VID_DEV_CAP_FORMAT;
280 param->clock_rate = DEFAULT_CLOCK_RATE;
281 pj_memcpy(&param->fmt, &di->info.fmt[0], sizeof(param->fmt));
282
283 return PJ_SUCCESS;
284}
285
286static const struct cbar_fmt_info* get_cbar_fmt_info(pjmedia_format_id id)
287{
288 unsigned i;
289
290 for (i = 0; i < sizeof(cbar_fmts)/sizeof(cbar_fmts[0]); i++) {
291 if (cbar_fmts[i].fmt_id == id)
292 return &cbar_fmts[i];
293 }
294
295 return NULL;
296}
297
298static void fill_first_line(pj_uint8_t *first_lines[],
299 const struct cbar_fmt_info *cbfi,
300 const pjmedia_video_format_info *vfi,
301 const pjmedia_video_apply_fmt_param *vafp)
302{
303 typedef pj_uint8_t color_comp_t[3];
304 color_comp_t rgb_colors[] =
305 {
306 {255,255,255}, {255,255,0}, {0,255,255}, {0,255,0},
307 {255,0,255}, {255,0,0}, {0,0,255}, {0,0,0}
308 };
309 color_comp_t yuv_colors[] =
310 {
311 //{235,128,128}, {162,44,142}, {131,156,44}, {112,72,58},
312 //{84,184,198}, {65,100,212}, {35,212,114}, {16,128,128}
313 {235,128,128}, {210,16,146}, {170,166,16}, {145,54,34},
314 {106,202,222}, {81,90,240}, {41,240,110}, {16,128,128}
315 };
316
317 unsigned i, j, k;
318
319 if (vfi->plane_cnt == 1) {
320 /* Packed */
321
322 for (i = 0; i < 8; ++i) {
323 /* iterate bars */
324 for (j = 0; j < 3; ++j) {
325 /* iterate color components */
326 pj_uint8_t *p = NULL, c;
327 unsigned bar_width, inc_p;
328
329 if (vfi->color_model == PJMEDIA_COLOR_MODEL_RGB)
330 c = rgb_colors[i][j];
331 else
332 c = yuv_colors[i][j];
333
334 bar_width = vafp->size.w/8;
335 bar_width /= (cbfi->c_stride[j] * 8 / vfi->bpp);
336 inc_p = cbfi->c_stride[j];
337 p = first_lines[0] + bar_width*i*inc_p + cbfi->c_offset[j];
338
339 /* draw this color */
340 for (k = 0; k < bar_width; ++k) {
341 *p = c;
342 p += inc_p;
343 }
344 }
345 }
346
347 } else if (vfi->plane_cnt == 3) {
348
349 for (i = 0; i < 8; ++i) {
350 /* iterate bars */
351 for (j = 0; j < 3; ++j) {
352 /* iterate planes/color components */
353 pj_uint8_t *p = NULL, c;
354 unsigned bar_width;
355
356 if (vfi->color_model == PJMEDIA_COLOR_MODEL_RGB)
357 c = rgb_colors[i][j];
358 else {
359 if (vfi->id == PJMEDIA_FORMAT_YV12 && j > 0)
360 c = yuv_colors[i][3-j];
361 else
362 c = yuv_colors[i][j];
363 }
364
365 bar_width = vafp->strides[j]/8;
366 p = first_lines[j] + bar_width*i;
367
368 /* draw this plane/color */
369 for (k = 0; k < bar_width; ++k)
370 *p++ = c;
371 }
372 }
373 }
374}
375
376/* API: create stream */
377static pj_status_t cbar_factory_create_stream(
378 pjmedia_vid_dev_factory *f,
379 pjmedia_vid_dev_param *param,
380 const pjmedia_vid_dev_cb *cb,
381 void *user_data,
382 pjmedia_vid_dev_stream **p_vid_strm)
383{
384 struct cbar_factory *cf = (struct cbar_factory*)f;
385 pj_pool_t *pool;
386 struct cbar_stream *strm;
387 const pjmedia_video_format_detail *vfd;
388 const pjmedia_video_format_info *vfi;
389 pjmedia_video_apply_fmt_param vafp;
390 const struct cbar_fmt_info *cbfi;
391 unsigned i;
392
393 PJ_ASSERT_RETURN(f && param && p_vid_strm, PJ_EINVAL);
394 PJ_ASSERT_RETURN(param->fmt.type == PJMEDIA_TYPE_VIDEO &&
395 param->fmt.detail_type == PJMEDIA_FORMAT_DETAIL_VIDEO &&
396 param->dir == PJMEDIA_DIR_CAPTURE,
397 PJ_EINVAL);
398
399 pj_bzero(&vafp, sizeof(vafp));
400
401 vfd = pjmedia_format_get_video_format_detail(&param->fmt, PJ_TRUE);
402 vfi = pjmedia_get_video_format_info(NULL, param->fmt.id);
403 cbfi = get_cbar_fmt_info(param->fmt.id);
404 if (!vfi || !cbfi)
405 return PJMEDIA_EVID_BADFORMAT;
406
407 vafp.size = param->fmt.det.vid.size;
408 if (vfi->apply_fmt(vfi, &vafp) != PJ_SUCCESS)
409 return PJMEDIA_EVID_BADFORMAT;
410
411 /* Create and Initialize stream descriptor */
412 pool = pj_pool_create(cf->pf, "cbar-dev", 512, 512, NULL);
413 PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);
414
415 strm = PJ_POOL_ZALLOC_T(pool, struct cbar_stream);
416 pj_memcpy(&strm->param, param, sizeof(*param));
417 strm->pool = pool;
418 pj_memcpy(&strm->vid_cb, cb, sizeof(*cb));
419 strm->user_data = user_data;
420 strm->vfi = vfi;
421 strm->cbfi = cbfi;
422 pj_memcpy(&strm->vafp, &vafp, sizeof(vafp));
423 strm->ts_inc = PJMEDIA_SPF2(param->clock_rate, &vfd->fps, 1);
424
425 for (i = 0; i < vfi->plane_cnt; ++i) {
426 strm->first_line[i] = pj_pool_alloc(pool, vafp.strides[i]);
427 pj_memset(strm->first_line[i], 255, vafp.strides[i]);
428 }
429
430 fill_first_line(strm->first_line, strm->cbfi, vfi, &strm->vafp);
431
432 /* Apply the remaining settings */
433/* if (param->flags & PJMEDIA_VID_DEV_CAP_INPUT_SCALE) {
434 cbar_stream_set_cap(&strm->base,
435 PJMEDIA_VID_DEV_CAP_INPUT_SCALE,
436 &param->fmt);
437 }
438*/
439 /* Done */
440 strm->base.op = &stream_op;
441 *p_vid_strm = &strm->base;
442
443 return PJ_SUCCESS;
444}
445
446/* API: Get stream info. */
447static pj_status_t cbar_stream_get_param(pjmedia_vid_dev_stream *s,
448 pjmedia_vid_dev_param *pi)
449{
450 struct cbar_stream *strm = (struct cbar_stream*)s;
451
452 PJ_ASSERT_RETURN(strm && pi, PJ_EINVAL);
453
454 pj_memcpy(pi, &strm->param, sizeof(*pi));
455
456/* if (cbar_stream_get_cap(s, PJMEDIA_VID_DEV_CAP_INPUT_SCALE,
457 &pi->fmt.info_size) == PJ_SUCCESS)
458 {
459 pi->flags |= PJMEDIA_VID_DEV_CAP_INPUT_SCALE;
460 }
461*/
462 return PJ_SUCCESS;
463}
464
465/* API: get capability */
466static pj_status_t cbar_stream_get_cap(pjmedia_vid_dev_stream *s,
467 pjmedia_vid_dev_cap cap,
468 void *pval)
469{
470 struct cbar_stream *strm = (struct cbar_stream*)s;
471
472 PJ_UNUSED_ARG(strm);
473
474 PJ_ASSERT_RETURN(s && pval, PJ_EINVAL);
475
476 if (cap==PJMEDIA_VID_DEV_CAP_INPUT_SCALE)
477 {
478 return PJMEDIA_EVID_INVCAP;
479// return PJ_SUCCESS;
480 } else {
481 return PJMEDIA_EVID_INVCAP;
482 }
483}
484
485/* API: set capability */
486static pj_status_t cbar_stream_set_cap(pjmedia_vid_dev_stream *s,
487 pjmedia_vid_dev_cap cap,
488 const void *pval)
489{
490 struct cbar_stream *strm = (struct cbar_stream*)s;
491
492 PJ_UNUSED_ARG(strm);
493
494 PJ_ASSERT_RETURN(s && pval, PJ_EINVAL);
495
496 if (cap==PJMEDIA_VID_DEV_CAP_INPUT_SCALE)
497 {
498 return PJ_SUCCESS;
499 }
500
501 return PJMEDIA_EVID_INVCAP;
502}
503
504static pj_status_t spectrum_run(struct cbar_stream *d, pj_uint8_t *p,
505 pj_size_t size)
506{
507 unsigned i;
508 pj_uint8_t *ptr = p;
509 pj_time_val tv;
510
511 PJ_UNUSED_ARG(size);
512
513 /* Subsequent lines */
514 for (i=0; i<d->vfi->plane_cnt; ++i) {
515 pj_uint8_t *plane_end;
516
517 plane_end = ptr + d->vafp.plane_bytes[i];
518 while (ptr < plane_end) {
519 pj_memcpy(ptr, d->first_line[i], d->vafp.strides[i]);
520 ptr += d->vafp.strides[i];
521 }
522 }
523
524 /* blinking dot */
525 pj_gettimeofday(&tv);
526 if (tv.msec < 660) {
527 enum { DOT_SIZE = 8 };
528 pj_uint8_t dot_clr_rgb[3] = {255, 255, 255};
529 pj_uint8_t dot_clr_yuv[3] = {235, 128, 128};
530
531 if (d->vfi->plane_cnt == 1) {
532 for (i = 0; i < 3; ++i) {
533 pj_uint8_t *ptr;
534 unsigned j, k, inc_ptr;
535 pj_size_t dot_size = DOT_SIZE;
536
537 dot_size /= (d->cbfi->c_stride[i] * 8 / d->vfi->bpp);
538 inc_ptr = d->cbfi->c_stride[i];
539 for (j = 0; j < dot_size; ++j) {
540 ptr = p + d->vafp.strides[0]*(dot_size+j+1) -
541 2*dot_size*inc_ptr + d->cbfi->c_offset[i];
542 for (k = 0; k < dot_size; ++k) {
543 if (d->vfi->color_model == PJMEDIA_COLOR_MODEL_RGB)
544 *ptr = dot_clr_rgb[i];
545 else
546 *ptr = dot_clr_yuv[i];
547 ptr += inc_ptr;
548 }
549 }
550 }
551 } else {
552 pj_size_t offset_p = 0;
553
554 for (i = 0; i < 3; ++i) {
555 pj_uint8_t *ptr, c;
556 unsigned j;
557 pj_size_t dot_size = DOT_SIZE;
558
559 if (d->vfi->color_model == PJMEDIA_COLOR_MODEL_RGB)
560 c = dot_clr_rgb[i];
561 else
562 c = dot_clr_yuv[i];
563
564 dot_size /= (d->vafp.size.w / d->vafp.strides[i]);
565 ptr = p + offset_p + d->vafp.strides[i]*(dot_size+1) -
566 2*dot_size;
567 for (j = 0; j < dot_size; ++j) {
568 pj_memset(ptr, c, dot_size);
569 ptr += d->vafp.strides[i];
570 }
571 offset_p += d->vafp.plane_bytes[i];
572 }
573 }
574 }
575
576 return PJ_SUCCESS;
577}
578
579/* API: Get frame from stream */
580static pj_status_t cbar_stream_get_frame(pjmedia_vid_dev_stream *strm,
581 pjmedia_frame *frame)
582{
583 struct cbar_stream *stream = (struct cbar_stream*)strm;
584
585 frame->type = PJMEDIA_FRAME_TYPE_VIDEO;
586 frame->bit_info = 0;
587 frame->timestamp = stream->ts;
588 stream->ts.u64 += stream->ts_inc;
589 return spectrum_run(stream, frame->buf, frame->size);
590}
591
592/* API: Start stream. */
593static pj_status_t cbar_stream_start(pjmedia_vid_dev_stream *strm)
594{
595 struct cbar_stream *stream = (struct cbar_stream*)strm;
596
597 PJ_UNUSED_ARG(stream);
598
599 PJ_LOG(4, (THIS_FILE, "Starting cbar video stream"));
600
601 return PJ_SUCCESS;
602}
603
604/* API: Stop stream. */
605static pj_status_t cbar_stream_stop(pjmedia_vid_dev_stream *strm)
606{
607 struct cbar_stream *stream = (struct cbar_stream*)strm;
608
609 PJ_UNUSED_ARG(stream);
610
611 PJ_LOG(4, (THIS_FILE, "Stopping cbar video stream"));
612
613 return PJ_SUCCESS;
614}
615
616
617/* API: Destroy stream. */
618static pj_status_t cbar_stream_destroy(pjmedia_vid_dev_stream *strm)
619{
620 struct cbar_stream *stream = (struct cbar_stream*)strm;
621
622 PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL);
623
624 cbar_stream_stop(strm);
625
626 pj_pool_release(stream->pool);
627
628 return PJ_SUCCESS;
629}
630
631#endif /* PJMEDIA_VIDEO_DEV_HAS_CBAR_SRC */