1
/* $Id: avi_dev.c 4086 2012-04-26 02:44:41Z ming $ */
3
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
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.
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.
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
19
#include <pjmedia-videodev/videodev_imp.h>
20
#include <pjmedia-videodev/avi_dev.h>
21
#include <pj/assert.h>
25
#include <pjmedia/vid_codec.h>
27
#if defined(PJMEDIA_VIDEO_DEV_HAS_AVI) && PJMEDIA_VIDEO_DEV_HAS_AVI != 0 && \
28
defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
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
37
typedef struct avi_dev_strm avi_dev_strm;
39
/* avi_ device info */
42
pjmedia_vid_dev_info info;
47
pjmedia_avi_streams *avi;
50
pjmedia_vid_codec *codec;
52
pj_size_t enc_buf_size;
58
pjmedia_vid_dev_factory base;
63
struct avi_dev_info *dev_info;
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;
74
pjmedia_vid_dev_cb vid_cb; /**< Stream callback. */
75
void *user_data; /**< Application data. */
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,
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,
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,
96
pjmedia_vid_dev_stream **p_vid_strm);
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,
103
static pj_status_t avi_dev_strm_set_cap(pjmedia_vid_dev_stream *strm,
104
pjmedia_vid_dev_cap cap,
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);
112
static void reset_dev_info(struct avi_dev_info *adi);
115
static pjmedia_vid_dev_factory_op factory_op =
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,
126
static pjmedia_vid_dev_stream_op stream_op =
128
&avi_dev_strm_get_param,
129
&avi_dev_strm_get_cap,
130
&avi_dev_strm_set_cap,
132
&avi_dev_strm_get_frame,
135
&avi_dev_strm_destroy
139
/****************************************************************************
144
PJ_DEF(pj_status_t) pjmedia_avi_dev_create_factory(
147
pjmedia_vid_dev_factory **p_ret)
149
struct avi_factory *cf;
153
pool = pj_pool_create(pf, "avidevfc%p", 512, 512, NULL);
154
cf = PJ_POOL_ZALLOC_T(pool, struct avi_factory);
157
cf->dev_count = max_dev;
158
cf->base.op = &factory_op;
160
cf->dev_info = (struct avi_dev_info*)
161
pj_pool_calloc(cf->pool, cf->dev_count,
162
sizeof(struct avi_dev_info));
168
status = pjmedia_vid_register_factory(NULL, &cf->base);
169
if (status != PJ_SUCCESS)
172
PJ_LOG(4, (THIS_FILE, "AVI dev factory created with %d virtual device(s)",
178
/* API: init factory */
179
static pj_status_t avi_factory_init(pjmedia_vid_dev_factory *f)
181
struct avi_factory *cf = (struct avi_factory*)f;
184
for (i=0; i<cf->dev_count; ++i) {
185
reset_dev_info(&cf->dev_info[i]);
191
/* API: destroy factory */
192
static pj_status_t avi_factory_destroy(pjmedia_vid_dev_factory *f)
194
struct avi_factory *cf = (struct avi_factory*)f;
195
pj_pool_t *pool = cf->pool;
198
pj_pool_release(pool);
203
/* API: refresh the list of devices */
204
static pj_status_t avi_factory_refresh(pjmedia_vid_dev_factory *f)
210
/* API: get number of devices */
211
static unsigned avi_factory_get_dev_count(pjmedia_vid_dev_factory *f)
213
struct avi_factory *cf = (struct avi_factory*)f;
214
return cf->dev_count;
217
/* API: get device info */
218
static pj_status_t avi_factory_get_dev_info(pjmedia_vid_dev_factory *f,
220
pjmedia_vid_dev_info *info)
222
struct avi_factory *cf = (struct avi_factory*)f;
224
PJ_ASSERT_RETURN(index < cf->dev_count, PJMEDIA_EVID_INVDEV);
226
pj_memcpy(info, &cf->dev_info[index].info, sizeof(*info));
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,
235
pjmedia_vid_dev_param *param)
237
struct avi_factory *cf = (struct avi_factory*)f;
238
struct avi_dev_info *di = &cf->dev_info[index];
240
PJ_ASSERT_RETURN(index < cf->dev_count, PJMEDIA_EVID_INVDEV);
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(¶m->fmt, &di->info.fmt[0], sizeof(param->fmt));
256
static void reset_dev_info(struct avi_dev_info *adi)
258
/* Close avi streams */
262
cnt = pjmedia_avi_streams_get_num_streams(adi->avi);
263
for (i=0; i<cnt; ++i) {
264
pjmedia_avi_stream *as;
266
as = pjmedia_avi_streams_get_stream(adi->avi, i);
269
port = pjmedia_avi_stream_get_port(as);
270
pjmedia_port_destroy(port);
277
pjmedia_vid_codec_close(adi->codec);
282
pj_pool_release(adi->pool);
284
pj_bzero(adi, sizeof(*adi));
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;
293
/* API: release resources */
294
PJ_DEF(pj_status_t) pjmedia_avi_dev_free(pjmedia_vid_dev_index id)
296
pjmedia_vid_dev_factory *f;
297
struct avi_factory *cf;
299
struct avi_dev_info *adi;
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)
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;
311
/* Device index should be valid */
312
PJ_ASSERT_RETURN(local_idx <= cf->dev_count, PJ_EBUG);
313
adi = &cf->dev_info[local_idx];
315
/* Cannot configure if stream is running */
325
PJ_DEF(pj_status_t) pjmedia_avi_dev_get_param(pjmedia_vid_dev_index id,
326
pjmedia_avi_dev_param *prm)
328
pjmedia_vid_dev_factory *f;
329
struct avi_factory *cf;
331
struct avi_dev_info *adi;
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)
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;
343
/* Device index should be valid */
344
PJ_ASSERT_RETURN(local_idx <= cf->dev_count, PJ_EBUG);
345
adi = &cf->dev_info[local_idx];
347
pj_bzero(prm, sizeof(*prm));
348
prm->path = adi->fpath;
349
prm->title = adi->title;
350
prm->avi_streams = adi->avi;
355
PJ_DEF(void) pjmedia_avi_dev_param_default(pjmedia_avi_dev_param *p)
357
pj_bzero(p, sizeof(*p));
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)
365
pjmedia_vid_dev_index id;
366
struct avi_factory *cf = (struct avi_factory*)f;
368
struct avi_dev_info *adi = NULL;
369
pjmedia_format avi_fmt;
370
const pjmedia_video_format_info *vfi;
373
PJ_ASSERT_RETURN(f && p && p_id, PJ_EINVAL);
376
*p_id = PJMEDIA_VID_INVALID_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];
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)
396
pj_pool_release(adi->pool);
398
pj_bzero(adi, sizeof(*adi));
401
PJ_ASSERT_RETURN(p->path.slen, PJ_EINVAL);
402
adi->pool = pj_pool_create(cf->pf, "avidi%p", 512, 512, NULL);
406
pj_strdup_with_null(adi->pool, &adi->fpath, &p->path);
407
status = pjmedia_avi_player_create_streams(adi->pool, adi->fpath.ptr, 0,
409
if (status != PJ_SUCCESS) {
413
adi->vid = pjmedia_avi_streams_get_stream_by_media(adi->avi, 0,
416
status = PJMEDIA_EVID_BADFORMAT;
417
PJ_LOG(4,(THIS_FILE, "Error: cannot find video in AVI %s",
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;
432
status = pjmedia_vid_codec_mgr_get_codec_info2(NULL,
435
if (status != PJ_SUCCESS || !codec_info)
438
status = pjmedia_vid_codec_mgr_get_default_param(NULL, codec_info,
440
if (status != PJ_SUCCESS)
444
status = pjmedia_vid_codec_mgr_alloc_codec(NULL, codec_info,
446
if (status != PJ_SUCCESS)
449
status = pjmedia_vid_codec_init(adi->codec, adi->pool);
450
if (status != PJ_SUCCESS)
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)
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)
468
adi->enc_buf = pj_pool_alloc(adi->pool, vafp.framebytes);
469
adi->enc_buf_size = vafp.framebytes;
472
/* Calculate title */
474
pj_strdup_with_null(adi->pool, &adi->title, &p->title);
476
char *start = p->path.ptr + p->path.slen;
479
while (start >= p->path.ptr) {
480
if (*start == '/' || *start == '\\')
485
tmp.slen = p->path.ptr + p->path.slen - tmp.ptr;
486
pj_strdup_with_null(adi->pool, &adi->title, &tmp);
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;
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);
502
p->avi_streams = adi->avi;
503
if (p->title.slen == 0)
504
p->title = adi->title;
510
pjmedia_vid_codec_close(adi->codec);
514
pj_pool_release(adi->pool);
517
pjmedia_avi_dev_free(id);
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,
528
pjmedia_vid_dev_stream **p_vid_strm)
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;
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,
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);
545
/* Cannot create while stream is already active */
546
PJ_ASSERT_RETURN(adi->strm==NULL, PJ_EINVALIDOP);
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);
552
strm = PJ_POOL_ZALLOC_T(pool, struct avi_dev_strm);
553
pj_memcpy(&strm->param, param, sizeof(*param));
555
pj_memcpy(&strm->vid_cb, cb, sizeof(*cb));
556
strm->user_data = user_data;
559
pjmedia_format_copy(¶m->fmt, &adi->info.fmt[0]);
562
strm->base.op = &stream_op;
564
*p_vid_strm = &strm->base;
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)
573
struct avi_dev_strm *strm = (struct avi_dev_strm*)s;
575
PJ_ASSERT_RETURN(strm && pi, PJ_EINVAL);
577
pj_memcpy(pi, &strm->param, sizeof(*pi));
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,
587
struct avi_dev_strm *strm = (struct avi_dev_strm*)s;
593
PJ_ASSERT_RETURN(s && pval, PJ_EINVAL);
595
return PJMEDIA_EVID_INVCAP;
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,
603
struct avi_dev_strm *strm = (struct avi_dev_strm*)s;
609
PJ_ASSERT_RETURN(s && pval, PJ_EINVAL);
611
return PJMEDIA_EVID_INVCAP;
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)
618
struct avi_dev_strm *stream = (struct avi_dev_strm*)strm;
620
if (stream->adi->codec) {
621
pjmedia_frame enc_frame;
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)
630
return pjmedia_vid_codec_decode(stream->adi->codec, 1, &enc_frame,
633
return pjmedia_port_get_frame(stream->adi->vid, frame);
637
/* API: Start stream. */
638
static pj_status_t avi_dev_strm_start(pjmedia_vid_dev_stream *strm)
640
struct avi_dev_strm *stream = (struct avi_dev_strm*)strm;
642
PJ_UNUSED_ARG(stream);
644
PJ_LOG(4, (THIS_FILE, "Starting avi video stream"));
649
/* API: Stop stream. */
650
static pj_status_t avi_dev_strm_stop(pjmedia_vid_dev_stream *strm)
652
struct avi_dev_strm *stream = (struct avi_dev_strm*)strm;
654
PJ_UNUSED_ARG(stream);
656
PJ_LOG(4, (THIS_FILE, "Stopping avi video stream"));
662
/* API: Destroy stream. */
663
static pj_status_t avi_dev_strm_destroy(pjmedia_vid_dev_stream *strm)
665
struct avi_dev_strm *stream = (struct avi_dev_strm*)strm;
667
PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL);
669
avi_dev_strm_stop(strm);
671
stream->adi->strm = NULL;
673
pj_pool_release(stream->pool);
678
#endif /* PJMEDIA_VIDEO_DEV_HAS_AVI */