1 /* $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 <pjmedia-videodev/avi_dev.h>
21 #include <pj/assert.h>
22 #include <pj/log.h>
23 #include <pj/os.h>
24 #include <pj/rand.h>
25 #include <pjmedia/vid_codec.h>
26
27 #if defined(PJMEDIA_VIDEO_DEV_HAS_AVI) && PJMEDIA_VIDEO_DEV_HAS_AVI != 0 && \
28 defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
29
30 #define THIS_FILE "avi_dev.c"
31 #define DRIVER_NAME "AVIDev"
32 #define DEFAULT_CLOCK_RATE 90000
33 #define DEFAULT_WIDTH 640
34 #define DEFAULT_HEIGHT 480
35 #define DEFAULT_FPS 25
36
37 typedef struct avi_dev_strm avi_dev_strm;
38
39 /* avi_ device info */
40 struct avi_dev_info
41 {
42 pjmedia_vid_dev_info info;
43
44 pj_pool_t *pool;
45 pj_str_t fpath;
46 pj_str_t title;
47 pjmedia_avi_streams *avi;
48 pjmedia_port *vid;
49 avi_dev_strm *strm;
50 pjmedia_vid_codec *codec;
51 pj_uint8_t *enc_buf;
52 pj_size_t enc_buf_size;
53 };
54
55 /* avi_ factory */
56 struct avi_factory
57 {
58 pjmedia_vid_dev_factory base;
59 pj_pool_t *pool;
60 pj_pool_factory *pf;
61
62 unsigned dev_count;
63 struct avi_dev_info *dev_info;
64 };
65
66 /* Video stream. */
67 struct avi_dev_strm
68 {
69 pjmedia_vid_dev_stream base; /**< Base stream */
70 pjmedia_vid_dev_param param; /**< Settings */
71 pj_pool_t *pool; /**< Memory pool. */
72 struct avi_dev_info *adi;
73
74 pjmedia_vid_dev_cb vid_cb; /**< Stream callback. */
75 void *user_data; /**< Application data. */
76 };
77
78
79 /* Prototypes */
80 static pj_status_t avi_factory_init(pjmedia_vid_dev_factory *f);
81 static pj_status_t avi_factory_destroy(pjmedia_vid_dev_factory *f);
82 static pj_status_t avi_factory_refresh(pjmedia_vid_dev_factory *f);
83 static unsigned avi_factory_get_dev_count(pjmedia_vid_dev_factory *f);
84 static pj_status_t avi_factory_get_dev_info(pjmedia_vid_dev_factory *f,
85 unsigned index,
86 pjmedia_vid_dev_info *info);
87 static pj_status_t avi_factory_default_param(pj_pool_t *pool,
88 pjmedia_vid_dev_factory *f,
89 unsigned index,
90 pjmedia_vid_dev_param *param);
91 static pj_status_t avi_factory_create_stream(
92 pjmedia_vid_dev_factory *f,
93 pjmedia_vid_dev_param *param,
94 const pjmedia_vid_dev_cb *cb,
95 void *user_data,
96 pjmedia_vid_dev_stream **p_vid_strm);
97
98 static pj_status_t avi_dev_strm_get_param(pjmedia_vid_dev_stream *strm,
99 pjmedia_vid_dev_param *param);
100 static pj_status_t avi_dev_strm_get_cap(pjmedia_vid_dev_stream *strm,
101 pjmedia_vid_dev_cap cap,
102 void *value);
103 static pj_status_t avi_dev_strm_set_cap(pjmedia_vid_dev_stream *strm,
104 pjmedia_vid_dev_cap cap,
105 const void *value);
106 static pj_status_t avi_dev_strm_get_frame(pjmedia_vid_dev_stream *strm,
107 pjmedia_frame *frame);
108 static pj_status_t avi_dev_strm_start(pjmedia_vid_dev_stream *strm);
109 static pj_status_t avi_dev_strm_stop(pjmedia_vid_dev_stream *strm);
110 static pj_status_t avi_dev_strm_destroy(pjmedia_vid_dev_stream *strm);
111
112 static void reset_dev_info(struct avi_dev_info *adi);
113
114 /* Operations */
115 static pjmedia_vid_dev_factory_op factory_op =
116 {
117 &avi_factory_init,
118 &avi_factory_destroy,
119 &avi_factory_get_dev_count,
120 &avi_factory_get_dev_info,
121 &avi_factory_default_param,
122 &avi_factory_create_stream,
123 &avi_factory_refresh
124 };
125
126 static pjmedia_vid_dev_stream_op stream_op =
127 {
128 &avi_dev_strm_get_param,
129 &avi_dev_strm_get_cap,
130 &avi_dev_strm_set_cap,
131 &avi_dev_strm_start,
132 &avi_dev_strm_get_frame,
133 NULL,
134 &avi_dev_strm_stop,
135 &avi_dev_strm_destroy
136 };
137
138
139 /****************************************************************************
140 * Factory operations
141 */
142
143 /* API */
pjmedia_avi_dev_create_factory(pj_pool_factory * pf,unsigned max_dev,pjmedia_vid_dev_factory ** p_ret)144 PJ_DEF(pj_status_t) pjmedia_avi_dev_create_factory(
145 pj_pool_factory *pf,
146 unsigned max_dev,
147 pjmedia_vid_dev_factory **p_ret)
148 {
149 struct avi_factory *cf;
150 pj_pool_t *pool;
151 pj_status_t status;
152
153 pool = pj_pool_create(pf, "avidevfc%p", 512, 512, NULL);
154 cf = PJ_POOL_ZALLOC_T(pool, struct avi_factory);
155 cf->pf = pf;
156 cf->pool = pool;
157 cf->dev_count = max_dev;
158 cf->base.op = &factory_op;
159
160 cf->dev_info = (struct avi_dev_info*)
161 pj_pool_calloc(cf->pool, cf->dev_count,
162 sizeof(struct avi_dev_info));
163
164 if (p_ret) {
165 *p_ret = &cf->base;
166 }
167
168 status = pjmedia_vid_register_factory(NULL, &cf->base);
169 if (status != PJ_SUCCESS)
170 return status;
171
172 PJ_LOG(4, (THIS_FILE, "AVI dev factory created with %d virtual device(s)",
173 cf->dev_count));
174
175 return PJ_SUCCESS;
176 }
177
178 /* API: init factory */
avi_factory_init(pjmedia_vid_dev_factory * f)179 static pj_status_t avi_factory_init(pjmedia_vid_dev_factory *f)
180 {
181 struct avi_factory *cf = (struct avi_factory*)f;
182 unsigned i;
183
184 for (i=0; i<cf->dev_count; ++i) {
185 reset_dev_info(&cf->dev_info[i]);
186 }
187
188 return PJ_SUCCESS;
189 }
190
191 /* API: destroy factory */
avi_factory_destroy(pjmedia_vid_dev_factory * f)192 static pj_status_t avi_factory_destroy(pjmedia_vid_dev_factory *f)
193 {
194 struct avi_factory *cf = (struct avi_factory*)f;
195
196 pj_pool_safe_release(&cf->pool);
197
198 return PJ_SUCCESS;
199 }
200
201 /* API: refresh the list of devices */
avi_factory_refresh(pjmedia_vid_dev_factory * f)202 static pj_status_t avi_factory_refresh(pjmedia_vid_dev_factory *f)
203 {
204 PJ_UNUSED_ARG(f);
205 return PJ_SUCCESS;
206 }
207
208 /* API: get number of devices */
avi_factory_get_dev_count(pjmedia_vid_dev_factory * f)209 static unsigned avi_factory_get_dev_count(pjmedia_vid_dev_factory *f)
210 {
211 struct avi_factory *cf = (struct avi_factory*)f;
212 return cf->dev_count;
213 }
214
215 /* API: get device info */
avi_factory_get_dev_info(pjmedia_vid_dev_factory * f,unsigned index,pjmedia_vid_dev_info * info)216 static pj_status_t avi_factory_get_dev_info(pjmedia_vid_dev_factory *f,
217 unsigned index,
218 pjmedia_vid_dev_info *info)
219 {
220 struct avi_factory *cf = (struct avi_factory*)f;
221
222 PJ_ASSERT_RETURN(index < cf->dev_count, PJMEDIA_EVID_INVDEV);
223
224 pj_memcpy(info, &cf->dev_info[index].info, sizeof(*info));
225
226 return PJ_SUCCESS;
227 }
228
229 /* API: create default device parameter */
avi_factory_default_param(pj_pool_t * pool,pjmedia_vid_dev_factory * f,unsigned index,pjmedia_vid_dev_param * param)230 static pj_status_t avi_factory_default_param(pj_pool_t *pool,
231 pjmedia_vid_dev_factory *f,
232 unsigned index,
233 pjmedia_vid_dev_param *param)
234 {
235 struct avi_factory *cf = (struct avi_factory*)f;
236 struct avi_dev_info *di = &cf->dev_info[index];
237
238 PJ_ASSERT_RETURN(index < cf->dev_count, PJMEDIA_EVID_INVDEV);
239
240 PJ_UNUSED_ARG(pool);
241
242 pj_bzero(param, sizeof(*param));
243 param->dir = PJMEDIA_DIR_CAPTURE;
244 param->cap_id = index;
245 param->rend_id = PJMEDIA_VID_INVALID_DEV;
246 param->flags = PJMEDIA_VID_DEV_CAP_FORMAT;
247 param->clock_rate = DEFAULT_CLOCK_RATE;
248 pj_memcpy(¶m->fmt, &di->info.fmt[0], sizeof(param->fmt));
249
250 return PJ_SUCCESS;
251 }
252
253 /* reset dev info */
reset_dev_info(struct avi_dev_info * adi)254 static void reset_dev_info(struct avi_dev_info *adi)
255 {
256 /* Close avi streams */
257 if (adi->avi) {
258 unsigned i, cnt;
259
260 cnt = pjmedia_avi_streams_get_num_streams(adi->avi);
261 for (i=0; i<cnt; ++i) {
262 pjmedia_avi_stream *as;
263
264 as = pjmedia_avi_streams_get_stream(adi->avi, i);
265 if (as) {
266 pjmedia_port *port;
267 port = pjmedia_avi_stream_get_port(as);
268 pjmedia_port_destroy(port);
269 }
270 }
271 adi->avi = NULL;
272 }
273
274 if (adi->codec) {
275 pjmedia_vid_codec_close(adi->codec);
276 adi->codec = NULL;
277 }
278
279 if (adi->pool)
280 pj_pool_release(adi->pool);
281
282 pj_bzero(adi, sizeof(*adi));
283
284 /* Fill up with *dummy" device info */
285 pj_ansi_strncpy(adi->info.name, "AVI Player", sizeof(adi->info.name)-1);
286 pj_ansi_strncpy(adi->info.driver, DRIVER_NAME, sizeof(adi->info.driver)-1);
287 adi->info.dir = PJMEDIA_DIR_CAPTURE;
288 adi->info.has_callback = PJ_FALSE;
289 }
290
291 /* API: release resources */
pjmedia_avi_dev_free(pjmedia_vid_dev_index id)292 PJ_DEF(pj_status_t) pjmedia_avi_dev_free(pjmedia_vid_dev_index id)
293 {
294 pjmedia_vid_dev_factory *f;
295 struct avi_factory *cf;
296 unsigned local_idx;
297 struct avi_dev_info *adi;
298 pj_status_t status;
299
300 /* Lookup the factory and local device index */
301 status = pjmedia_vid_dev_get_local_index(id, &f, &local_idx);
302 if (status != PJ_SUCCESS)
303 return status;
304
305 /* The factory must be AVI factory */
306 PJ_ASSERT_RETURN(f->op->init == &avi_factory_init, PJMEDIA_EVID_INVDEV);
307 cf = (struct avi_factory*)f;
308
309 /* Device index should be valid */
310 PJ_ASSERT_RETURN(local_idx <= cf->dev_count, PJ_EBUG);
311 adi = &cf->dev_info[local_idx];
312
313 /* Cannot configure if stream is running */
314 if (adi->strm)
315 return PJ_EBUSY;
316
317 /* Reset */
318 reset_dev_info(adi);
319 return PJ_SUCCESS;
320 }
321
322 /* API: get param */
pjmedia_avi_dev_get_param(pjmedia_vid_dev_index id,pjmedia_avi_dev_param * prm)323 PJ_DEF(pj_status_t) pjmedia_avi_dev_get_param(pjmedia_vid_dev_index id,
324 pjmedia_avi_dev_param *prm)
325 {
326 pjmedia_vid_dev_factory *f;
327 struct avi_factory *cf;
328 unsigned local_idx;
329 struct avi_dev_info *adi;
330 pj_status_t status;
331
332 /* Lookup the factory and local device index */
333 status = pjmedia_vid_dev_get_local_index(id, &f, &local_idx);
334 if (status != PJ_SUCCESS)
335 return status;
336
337 /* The factory must be factory */
338 PJ_ASSERT_RETURN(f->op->init == &avi_factory_init, PJMEDIA_EVID_INVDEV);
339 cf = (struct avi_factory*)f;
340
341 /* Device index should be valid */
342 PJ_ASSERT_RETURN(local_idx <= cf->dev_count, PJ_EBUG);
343 adi = &cf->dev_info[local_idx];
344
345 pj_bzero(prm, sizeof(*prm));
346 prm->path = adi->fpath;
347 prm->title = adi->title;
348 prm->avi_streams = adi->avi;
349
350 return PJ_SUCCESS;
351 }
352
pjmedia_avi_dev_param_default(pjmedia_avi_dev_param * p)353 PJ_DEF(void) pjmedia_avi_dev_param_default(pjmedia_avi_dev_param *p)
354 {
355 pj_bzero(p, sizeof(*p));
356 }
357
358 /* API: configure the AVI */
pjmedia_avi_dev_alloc(pjmedia_vid_dev_factory * f,pjmedia_avi_dev_param * p,pjmedia_vid_dev_index * p_id)359 PJ_DEF(pj_status_t) pjmedia_avi_dev_alloc( pjmedia_vid_dev_factory *f,
360 pjmedia_avi_dev_param *p,
361 pjmedia_vid_dev_index *p_id)
362 {
363 pjmedia_vid_dev_index id;
364 struct avi_factory *cf = (struct avi_factory*)f;
365 unsigned local_idx;
366 struct avi_dev_info *adi = NULL;
367 pjmedia_format avi_fmt;
368 const pjmedia_video_format_info *vfi;
369 pj_status_t status;
370
371 PJ_ASSERT_RETURN(f && p && p_id, PJ_EINVAL);
372
373 if (p_id)
374 *p_id = PJMEDIA_VID_INVALID_DEV;
375
376 /* Get a free dev */
377 for (local_idx=0; local_idx<cf->dev_count; ++local_idx) {
378 if (cf->dev_info[local_idx].avi == NULL) {
379 adi = &cf->dev_info[local_idx];
380 break;
381 }
382 }
383
384 if (!adi)
385 return PJ_ETOOMANY;
386
387 /* Convert local ID to global id */
388 status = pjmedia_vid_dev_get_global_index(&cf->base, local_idx, &id);
389 if (status != PJ_SUCCESS)
390 return status;
391
392 /* Reset */
393 if (adi->pool) {
394 pj_pool_release(adi->pool);
395 }
396 pj_bzero(adi, sizeof(*adi));
397
398 /* Reinit */
399 PJ_ASSERT_RETURN(p->path.slen, PJ_EINVAL);
400 adi->pool = pj_pool_create(cf->pf, "avidi%p", 512, 512, NULL);
401
402
403 /* Open the AVI */
404 pj_strdup_with_null(adi->pool, &adi->fpath, &p->path);
405 status = pjmedia_avi_player_create_streams(adi->pool, adi->fpath.ptr, 0,
406 &adi->avi);
407 if (status != PJ_SUCCESS) {
408 goto on_error;
409 }
410
411 adi->vid = pjmedia_avi_streams_get_stream_by_media(adi->avi, 0,
412 PJMEDIA_TYPE_VIDEO);
413 if (!adi->vid) {
414 status = PJMEDIA_EVID_BADFORMAT;
415 PJ_LOG(4,(THIS_FILE, "Error: cannot find video in AVI %s",
416 adi->fpath.ptr));
417 goto on_error;
418 }
419
420 pjmedia_format_copy(&avi_fmt, &adi->vid->info.fmt);
421 vfi = pjmedia_get_video_format_info(NULL, avi_fmt.id);
422 /* Check whether the frame is encoded. */
423 if (!vfi || vfi->bpp == 0) {
424 /* Yes, prepare codec */
425 const pjmedia_vid_codec_info *codec_info;
426 pjmedia_vid_codec_param codec_param;
427 pjmedia_video_apply_fmt_param vafp;
428
429 /* Lookup codec */
430 status = pjmedia_vid_codec_mgr_get_codec_info2(NULL,
431 avi_fmt.id,
432 &codec_info);
433 if (status != PJ_SUCCESS || !codec_info)
434 goto on_error;
435
436 status = pjmedia_vid_codec_mgr_get_default_param(NULL, codec_info,
437 &codec_param);
438 if (status != PJ_SUCCESS)
439 goto on_error;
440
441 /* Open codec */
442 status = pjmedia_vid_codec_mgr_alloc_codec(NULL, codec_info,
443 &adi->codec);
444 if (status != PJ_SUCCESS)
445 goto on_error;
446
447 status = pjmedia_vid_codec_init(adi->codec, adi->pool);
448 if (status != PJ_SUCCESS)
449 goto on_error;
450
451 codec_param.dir = PJMEDIA_DIR_DECODING;
452 codec_param.packing = PJMEDIA_VID_PACKING_WHOLE;
453 status = pjmedia_vid_codec_open(adi->codec, &codec_param);
454 if (status != PJ_SUCCESS)
455 goto on_error;
456
457 /* Allocate buffer */
458 avi_fmt.id = codec_info->dec_fmt_id[0];
459 vfi = pjmedia_get_video_format_info(NULL, avi_fmt.id);
460 pj_bzero(&vafp, sizeof(vafp));
461 vafp.size = avi_fmt.det.vid.size;
462 status = vfi->apply_fmt(vfi, &vafp);
463 if (status != PJ_SUCCESS)
464 goto on_error;
465
466 adi->enc_buf = pj_pool_alloc(adi->pool, vafp.framebytes);
467 adi->enc_buf_size = vafp.framebytes;
468 }
469
470 /* Calculate title */
471 if (p->title.slen) {
472 pj_strdup_with_null(adi->pool, &adi->title, &p->title);
473 } else {
474 char *start = p->path.ptr + p->path.slen;
475 pj_str_t tmp;
476
477 while (start >= p->path.ptr) {
478 if (*start == '/' || *start == '\\')
479 break;
480 --start;
481 }
482 tmp.ptr = start + 1;
483 tmp.slen = p->path.ptr + p->path.slen - tmp.ptr;
484 pj_strdup_with_null(adi->pool, &adi->title, &tmp);
485 }
486
487 /* Init device info */
488 pj_ansi_strncpy(adi->info.name, adi->title.ptr, sizeof(adi->info.name)-1);
489 pj_ansi_strncpy(adi->info.driver, DRIVER_NAME, sizeof(adi->info.driver)-1);
490 adi->info.dir = PJMEDIA_DIR_CAPTURE;
491 adi->info.has_callback = PJ_FALSE;
492
493 adi->info.caps = PJMEDIA_VID_DEV_CAP_FORMAT;
494 adi->info.fmt_cnt = 1;
495 pjmedia_format_copy(&adi->info.fmt[0], &avi_fmt);
496
497 /* Set out vars */
498 if (p_id)
499 *p_id = id;
500 p->avi_streams = adi->avi;
501 if (p->title.slen == 0)
502 p->title = adi->title;
503
504 return PJ_SUCCESS;
505
506 on_error:
507 if (adi->codec) {
508 pjmedia_vid_codec_close(adi->codec);
509 adi->codec = NULL;
510 }
511 if (adi->pool) {
512 pj_pool_release(adi->pool);
513 adi->pool = NULL;
514 }
515 pjmedia_avi_dev_free(id);
516 return status;
517 }
518
519
520 /* API: create stream */
avi_factory_create_stream(pjmedia_vid_dev_factory * f,pjmedia_vid_dev_param * param,const pjmedia_vid_dev_cb * cb,void * user_data,pjmedia_vid_dev_stream ** p_vid_strm)521 static pj_status_t avi_factory_create_stream(
522 pjmedia_vid_dev_factory *f,
523 pjmedia_vid_dev_param *param,
524 const pjmedia_vid_dev_cb *cb,
525 void *user_data,
526 pjmedia_vid_dev_stream **p_vid_strm)
527 {
528 struct avi_factory *cf = (struct avi_factory*)f;
529 pj_pool_t *pool = NULL;
530 struct avi_dev_info *adi;
531 struct avi_dev_strm *strm;
532
533 PJ_ASSERT_RETURN(f && param && p_vid_strm, PJ_EINVAL);
534 PJ_ASSERT_RETURN(param->fmt.type == PJMEDIA_TYPE_VIDEO &&
535 param->fmt.detail_type == PJMEDIA_FORMAT_DETAIL_VIDEO &&
536 param->dir == PJMEDIA_DIR_CAPTURE,
537 PJ_EINVAL);
538
539 /* Device must have been configured with pjmedia_avi_dev_set_param() */
540 adi = &cf->dev_info[param->cap_id];
541 PJ_ASSERT_RETURN(adi->avi != NULL, PJ_EINVALIDOP);
542
543 /* Cannot create while stream is already active */
544 PJ_ASSERT_RETURN(adi->strm==NULL, PJ_EINVALIDOP);
545
546 /* Create and initialize basic stream descriptor */
547 pool = pj_pool_create(cf->pf, "avidev%p", 512, 512, NULL);
548 PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);
549
550 strm = PJ_POOL_ZALLOC_T(pool, struct avi_dev_strm);
551 pj_memcpy(&strm->param, param, sizeof(*param));
552 strm->pool = pool;
553 pj_memcpy(&strm->vid_cb, cb, sizeof(*cb));
554 strm->user_data = user_data;
555 strm->adi = adi;
556
557 pjmedia_format_copy(¶m->fmt, &adi->info.fmt[0]);
558
559 /* Done */
560 strm->base.op = &stream_op;
561 adi->strm = strm;
562 *p_vid_strm = &strm->base;
563
564 return PJ_SUCCESS;
565 }
566
567 /* API: Get stream info. */
avi_dev_strm_get_param(pjmedia_vid_dev_stream * s,pjmedia_vid_dev_param * pi)568 static pj_status_t avi_dev_strm_get_param(pjmedia_vid_dev_stream *s,
569 pjmedia_vid_dev_param *pi)
570 {
571 struct avi_dev_strm *strm = (struct avi_dev_strm*)s;
572
573 PJ_ASSERT_RETURN(strm && pi, PJ_EINVAL);
574
575 pj_memcpy(pi, &strm->param, sizeof(*pi));
576
577 return PJ_SUCCESS;
578 }
579
580 /* API: get capability */
avi_dev_strm_get_cap(pjmedia_vid_dev_stream * s,pjmedia_vid_dev_cap cap,void * pval)581 static pj_status_t avi_dev_strm_get_cap(pjmedia_vid_dev_stream *s,
582 pjmedia_vid_dev_cap cap,
583 void *pval)
584 {
585 struct avi_dev_strm *strm = (struct avi_dev_strm*)s;
586
587 PJ_UNUSED_ARG(strm);
588 PJ_UNUSED_ARG(cap);
589 PJ_UNUSED_ARG(pval);
590
591 PJ_ASSERT_RETURN(s && pval, PJ_EINVAL);
592
593 return PJMEDIA_EVID_INVCAP;
594 }
595
596 /* API: set capability */
avi_dev_strm_set_cap(pjmedia_vid_dev_stream * s,pjmedia_vid_dev_cap cap,const void * pval)597 static pj_status_t avi_dev_strm_set_cap(pjmedia_vid_dev_stream *s,
598 pjmedia_vid_dev_cap cap,
599 const void *pval)
600 {
601 struct avi_dev_strm *strm = (struct avi_dev_strm*)s;
602
603 PJ_UNUSED_ARG(strm);
604 PJ_UNUSED_ARG(cap);
605 PJ_UNUSED_ARG(pval);
606
607 PJ_ASSERT_RETURN(s && pval, PJ_EINVAL);
608
609 return PJMEDIA_EVID_INVCAP;
610 }
611
612 /* API: Get frame from stream */
avi_dev_strm_get_frame(pjmedia_vid_dev_stream * strm,pjmedia_frame * frame)613 static pj_status_t avi_dev_strm_get_frame(pjmedia_vid_dev_stream *strm,
614 pjmedia_frame *frame)
615 {
616 struct avi_dev_strm *stream = (struct avi_dev_strm*)strm;
617
618 if (stream->adi->codec) {
619 pjmedia_frame enc_frame;
620 pj_status_t status;
621
622 enc_frame.buf = stream->adi->enc_buf;
623 enc_frame.size = stream->adi->enc_buf_size;
624 status = pjmedia_port_get_frame(stream->adi->vid, &enc_frame);
625 if (status != PJ_SUCCESS)
626 return status;
627
628 return pjmedia_vid_codec_decode(stream->adi->codec, 1, &enc_frame,
629 (unsigned)frame->size, frame);
630 } else {
631 return pjmedia_port_get_frame(stream->adi->vid, frame);
632 }
633 }
634
635 /* API: Start stream. */
avi_dev_strm_start(pjmedia_vid_dev_stream * strm)636 static pj_status_t avi_dev_strm_start(pjmedia_vid_dev_stream *strm)
637 {
638 struct avi_dev_strm *stream = (struct avi_dev_strm*)strm;
639
640 PJ_UNUSED_ARG(stream);
641
642 PJ_LOG(4, (THIS_FILE, "Starting avi video stream"));
643
644 return PJ_SUCCESS;
645 }
646
647 /* API: Stop stream. */
avi_dev_strm_stop(pjmedia_vid_dev_stream * strm)648 static pj_status_t avi_dev_strm_stop(pjmedia_vid_dev_stream *strm)
649 {
650 struct avi_dev_strm *stream = (struct avi_dev_strm*)strm;
651
652 PJ_UNUSED_ARG(stream);
653
654 PJ_LOG(4, (THIS_FILE, "Stopping avi video stream"));
655
656 return PJ_SUCCESS;
657 }
658
659
660 /* API: Destroy stream. */
avi_dev_strm_destroy(pjmedia_vid_dev_stream * strm)661 static pj_status_t avi_dev_strm_destroy(pjmedia_vid_dev_stream *strm)
662 {
663 struct avi_dev_strm *stream = (struct avi_dev_strm*)strm;
664
665 PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL);
666
667 avi_dev_strm_stop(strm);
668
669 stream->adi->strm = NULL;
670 stream->adi = NULL;
671 pj_pool_release(stream->pool);
672
673 return PJ_SUCCESS;
674 }
675
676 #endif /* PJMEDIA_VIDEO_DEV_HAS_AVI */
677