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