Add support for ICE/STUN/TURN in res_rtp_asterisk and chan_sip.
[asterisk/asterisk.git] / res / pjproject / pjmedia / src / pjmedia-videodev / avi_dev.c
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 */
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 */
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 */
192 static 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 */
204 static 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 */
211 static 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 */
218 static 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 */
232 static 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 */
256 static 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 */
294 PJ_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 */
325 PJ_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
355 PJ_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 */
361 PJ_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
508 on_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 */
523 static 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. */
570 static 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 */
583 static 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 */
599 static 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 */
615 static 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                                         frame->size, frame);
632     } else {
633         return pjmedia_port_get_frame(stream->adi->vid, frame);
634     }
635 }
636
637 /* API: Start stream. */
638 static 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. */
650 static 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. */
663 static 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 */