Fixed #1183
* QT capture device for Mac * iOS device for iOS (capture device only works for iOS 4.0 or above) * Add NSAutoReleasePool for sdl_dev (Mac) * Add NSAutoReleasePool for vid_dev_test (Mac) * build system for compilation of Obj-C files (.m) git-svn-id: https://svn.pjsip.org/repos/pjproject/branches/projects/2.0-dev@3395 74dad513-b988-da41-8d7b-12977e46ad98
This commit is contained in:
parent
e43ee729d4
commit
6e6c215f70
12529
aconfigure
12529
aconfigure
File diff suppressed because it is too large
Load Diff
|
@ -581,6 +581,37 @@ else
|
|||
esac
|
||||
fi
|
||||
|
||||
AC_SUBST(ac_pjmedia_video)
|
||||
if test "$enable_video" = "no"; then
|
||||
true;
|
||||
else
|
||||
case $target in
|
||||
arm-apple-darwin*)
|
||||
ac_pjmedia_video=iphone_os
|
||||
AC_SUBST(ac_ios_cflags)
|
||||
ac_ios_cflags="-DPJMEDIA_VIDEO_DEV_HAS_IOS=1"
|
||||
LIBS="$LIBS -framework AVFoundation -framework UIKit -framework CoreGraphics -framework QuartzCore -framework CoreVideo -framework CoreMedia"
|
||||
AC_MSG_RESULT([Checking video device backend... AVFoundation])
|
||||
;;
|
||||
*darwin*)
|
||||
ac_pjmedia_video=mac_os
|
||||
AC_SUBST(ac_pjmedia_video_has_qt)
|
||||
AC_SUBST(ac_qt_cflags)
|
||||
SAVED_LIBS="$LIBS"
|
||||
LIBS="-framework QTKit"
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [])],[ac_pjmedia_video_has_qt=yes],[ac_pjmedia_video_has_qt=no])
|
||||
LIBS="$SAVED_LIBS"
|
||||
if test "$ac_pjmedia_video_has_qt" = "yes"; then
|
||||
ac_qt_cflags="-DPJMEDIA_VIDEO_DEV_HAS_QT=1"
|
||||
LIBS="$LIBS -framework QTKit -framework Foundation -framework AppKit -framework QuartzCore"
|
||||
AC_MSG_RESULT([Checking if QTKit framework is available... yes])
|
||||
else
|
||||
AC_MSG_RESULT([Checking if QTKit framework is available... no])
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE(ext_sound,
|
||||
AC_HELP_STRING([--enable-ext-sound],
|
||||
[PJMEDIA will not provide any sound device backend]),
|
||||
|
|
|
@ -39,7 +39,7 @@ OBJDIRS := $(sort $(dir $(OBJS)))
|
|||
#
|
||||
# FULL_SRCS is ../src/app/file1.c ../src/app/file1.S
|
||||
#
|
||||
FULL_SRCS = $(foreach file, $($(APP)_OBJS), $(SRCDIR)/$(basename $(file)).c $(SRCDIR)/$(basename $(file)).cpp $(SRCDIR)/$(basename $(file)).S)
|
||||
FULL_SRCS = $(foreach file, $($(APP)_OBJS), $(SRCDIR)/$(basename $(file)).m $(SRCDIR)/$(basename $(file)).c $(SRCDIR)/$(basename $(file)).cpp $(SRCDIR)/$(basename $(file)).S)
|
||||
|
||||
#
|
||||
# When generating dependency (gcc -MM), ideally we use only either
|
||||
|
@ -115,6 +115,11 @@ $(OBJDIR)/$(app).ko: $(OBJDIR)/$(app).o
|
|||
../lib/$(app).ko: $(LIB) $(OBJDIR)/$(app).ko
|
||||
cp $(OBJDIR)/$(app).ko ../lib
|
||||
|
||||
$(OBJDIR)/%$(OBJEXT): $(SRCDIR)/%.m
|
||||
$(CC) $($(APP)_CFLAGS) \
|
||||
$(CC_OUT)$(subst /,$(HOST_PSEP),$@) \
|
||||
$(subst /,$(HOST_PSEP),$<)
|
||||
|
||||
$(OBJDIR)/%$(OBJEXT): $(SRCDIR)/%.c
|
||||
$(CC) $($(APP)_CFLAGS) \
|
||||
$(CC_OUT)$(subst /,$(HOST_PSEP),$@) \
|
||||
|
|
|
@ -77,7 +77,7 @@ if test "${CC}" = ""; then
|
|||
gccpath="${DEVPATH}/usr/bin/${archname}-gcc-${gccver}"
|
||||
if test -e ${gccpath}; then
|
||||
export CC="${gccpath}"
|
||||
break
|
||||
# break
|
||||
fi
|
||||
done
|
||||
if test ! "${CC}" = ""; then
|
||||
|
|
|
@ -86,7 +86,7 @@ export PJMEDIA_AUDIODEV_CFLAGS += $(_CFLAGS)
|
|||
# Defines for building PJMEDIA-VIDEODEV library
|
||||
#
|
||||
export PJMEDIA_VIDEODEV_SRCDIR = ../src/pjmedia-videodev
|
||||
export PJMEDIA_VIDEODEV_OBJS += videodev.o ffmpeg_dev.o sdl_dev.o colorbar_dev.o \
|
||||
export PJMEDIA_VIDEODEV_OBJS += videodev.o ffmpeg_dev.o colorbar_dev.o \
|
||||
v4l2_dev.o
|
||||
export PJMEDIA_VIDEODEV_CFLAGS += $(_CFLAGS)
|
||||
|
||||
|
@ -119,7 +119,7 @@ export PJMEDIA_CODEC_CFLAGS += $(_CFLAGS) $(GSM_CFLAGS) $(SPEEX_CFLAGS) \
|
|||
#
|
||||
export PJMEDIA_TEST_SRCDIR = ../src/test
|
||||
export PJMEDIA_TEST_OBJS += codec_vectors.o jbuf_test.o main.o mips_test.o \
|
||||
vid_dev_test.o vid_codec_test.o rtp_test.o test.o
|
||||
vid_codec_test.o rtp_test.o test.o
|
||||
export PJMEDIA_TEST_OBJS += sdp_neg_test.o
|
||||
export PJMEDIA_TEST_CFLAGS += $(_CFLAGS)
|
||||
export PJMEDIA_TEST_LDFLAGS += $(_LDFLAGS)
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
# @configure_input@
|
||||
|
||||
# Define the desired video device backend
|
||||
# Valid values are:
|
||||
# - mac_os
|
||||
# - iphone_os
|
||||
AC_PJMEDIA_VIDEO = @ac_pjmedia_video@
|
||||
|
||||
# SDL flags
|
||||
SDL_CFLAGS = @ac_sdl_cflags@
|
||||
SDL_LDFLAGS = @ac_sdl_ldflags@
|
||||
|
@ -12,9 +18,17 @@ FFMPEG_LDFLAGS = @ac_ffmpeg_ldflags@
|
|||
V4L2_CFLAGS = @ac_v4l2_cflags@
|
||||
V4L2_LDFLAGS = @ac_v4l2_ldflags@
|
||||
|
||||
# QT
|
||||
AC_PJMEDIA_VIDEO_HAS_QT = @ac_pjmedia_video_has_qt@
|
||||
QT_CFLAGS = @ac_qt_cflags@
|
||||
|
||||
# iOS
|
||||
IOS_CFLAGS = @ac_ios_cflags@
|
||||
|
||||
# PJMEDIA features exclusion
|
||||
export CFLAGS += @ac_no_small_filter@ @ac_no_large_filter@ @ac_no_speex_aec@ \
|
||||
$(SDL_CFLAGS) $(FFMPEG_CFLAGS) $(V4L2_CFLAGS)
|
||||
$(SDL_CFLAGS) $(FFMPEG_CFLAGS) $(V4L2_CFLAGS) $(QT_CFLAGS) \
|
||||
$(IOS_CFLAGS)
|
||||
export LDFLAGS += $(SDL_LDFLAGS) $(FFMPEG_LDFLAGS) $(V4L2_LDFLAGS)
|
||||
|
||||
# Define the desired sound device backend
|
||||
|
@ -132,4 +146,29 @@ ifeq ($(AC_PJMEDIA_SND),external)
|
|||
export CFLAGS += -DPJMEDIA_AUDIO_DEV_HAS_PORTAUDIO=0 -DPJMEDIA_AUDIO_DEV_HAS_WMME=0
|
||||
endif
|
||||
|
||||
#
|
||||
# QT video device
|
||||
#
|
||||
ifeq ($(AC_PJMEDIA_VIDEO_HAS_QT),yes)
|
||||
export PJMEDIA_VIDEODEV_OBJS += qt_dev.o
|
||||
endif
|
||||
|
||||
#
|
||||
# iOS video device
|
||||
#
|
||||
ifeq ($(AC_PJMEDIA_VIDEO),iphone_os)
|
||||
export PJMEDIA_VIDEODEV_OBJS += ios_dev.o
|
||||
endif
|
||||
|
||||
#
|
||||
# Determine whether we should compile the obj-c version of a particular source code
|
||||
#
|
||||
ifeq ($(AC_PJMEDIA_VIDEO),mac_os)
|
||||
# Mac OS specific, use obj-c
|
||||
export PJMEDIA_VIDEODEV_OBJS += sdl_dev_m.o
|
||||
export PJMEDIA_TEST_OBJS += vid_dev_test_m.o
|
||||
else
|
||||
# Other platforms, compile .c
|
||||
export PJMEDIA_VIDEODEV_OBJS += sdl_dev.o
|
||||
export PJMEDIA_TEST_OBJS += vid_dev_test.o
|
||||
endif
|
||||
|
|
|
@ -51,6 +51,26 @@ PJ_BEGIN_DECL
|
|||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* This setting controls whether QT support should be included.
|
||||
*
|
||||
* Default: 0 (or detected by configure)
|
||||
*/
|
||||
#ifndef PJMEDIA_VIDEO_DEV_HAS_QT
|
||||
# define PJMEDIA_VIDEO_DEV_HAS_QT 0
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* This setting controls whether IOS support should be included.
|
||||
*
|
||||
* Default: 0 (or detected by configure)
|
||||
*/
|
||||
#ifndef PJMEDIA_VIDEO_DEV_HAS_IOS
|
||||
# define PJMEDIA_VIDEO_DEV_HAS_IOS 0
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* This setting controls whether Direct Show support should be included.
|
||||
*
|
||||
|
|
|
@ -0,0 +1,669 @@
|
|||
/* $Id$ */
|
||||
/*
|
||||
* Copyright (C) 2008-2010 Teluu Inc. (http://www.teluu.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include <pjmedia-videodev/videodev_imp.h>
|
||||
#include <pj/assert.h>
|
||||
#include <pj/log.h>
|
||||
#include <pj/os.h>
|
||||
|
||||
#if PJMEDIA_VIDEO_DEV_HAS_IOS
|
||||
#include "Availability.h"
|
||||
#ifdef __IPHONE_4_0
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
|
||||
#define THIS_FILE "ios_dev.c"
|
||||
#define DEFAULT_CLOCK_RATE 9000
|
||||
#define DEFAULT_WIDTH 480
|
||||
#define DEFAULT_HEIGHT 360
|
||||
#define DEFAULT_FPS 15
|
||||
|
||||
typedef struct ios_fmt_info
|
||||
{
|
||||
pjmedia_format_id pjmedia_format;
|
||||
UInt32 ios_format;
|
||||
} ios_fmt_info;
|
||||
|
||||
static ios_fmt_info ios_fmts[] =
|
||||
{
|
||||
{PJMEDIA_FORMAT_BGRA, kCVPixelFormatType_32BGRA} ,
|
||||
};
|
||||
|
||||
/* qt device info */
|
||||
struct ios_dev_info
|
||||
{
|
||||
pjmedia_vid_dev_info info;
|
||||
};
|
||||
|
||||
/* qt factory */
|
||||
struct ios_factory
|
||||
{
|
||||
pjmedia_vid_dev_factory base;
|
||||
pj_pool_t *pool;
|
||||
pj_pool_factory *pf;
|
||||
|
||||
unsigned dev_count;
|
||||
struct ios_dev_info *dev_info;
|
||||
};
|
||||
|
||||
@interface VOutDelegate: NSObject
|
||||
<AVCaptureVideoDataOutputSampleBufferDelegate>
|
||||
{
|
||||
@public
|
||||
struct ios_stream *stream;
|
||||
}
|
||||
@end
|
||||
|
||||
/* Video stream. */
|
||||
struct ios_stream
|
||||
{
|
||||
pjmedia_vid_stream base; /**< Base stream */
|
||||
pjmedia_vid_param param; /**< Settings */
|
||||
pj_pool_t *pool; /**< Memory pool. */
|
||||
|
||||
pjmedia_vid_cb vid_cb; /**< Stream callback. */
|
||||
void *user_data; /**< Application data. */
|
||||
|
||||
pjmedia_rect_size size;
|
||||
pj_uint8_t bpp;
|
||||
unsigned bytes_per_row;
|
||||
unsigned frame_size;
|
||||
|
||||
AVCaptureSession *cap_session;
|
||||
AVCaptureDeviceInput *dev_input;
|
||||
AVCaptureVideoDataOutput *video_output;
|
||||
VOutDelegate *vout_delegate;
|
||||
|
||||
UIImageView *imgView;
|
||||
void *buf;
|
||||
};
|
||||
|
||||
|
||||
/* Prototypes */
|
||||
static pj_status_t ios_factory_init(pjmedia_vid_dev_factory *f);
|
||||
static pj_status_t ios_factory_destroy(pjmedia_vid_dev_factory *f);
|
||||
static unsigned ios_factory_get_dev_count(pjmedia_vid_dev_factory *f);
|
||||
static pj_status_t ios_factory_get_dev_info(pjmedia_vid_dev_factory *f,
|
||||
unsigned index,
|
||||
pjmedia_vid_dev_info *info);
|
||||
static pj_status_t ios_factory_default_param(pj_pool_t *pool,
|
||||
pjmedia_vid_dev_factory *f,
|
||||
unsigned index,
|
||||
pjmedia_vid_param *param);
|
||||
static pj_status_t ios_factory_create_stream(pjmedia_vid_dev_factory *f,
|
||||
const pjmedia_vid_param *param,
|
||||
const pjmedia_vid_cb *cb,
|
||||
void *user_data,
|
||||
pjmedia_vid_stream **p_vid_strm);
|
||||
|
||||
static pj_status_t ios_stream_get_param(pjmedia_vid_stream *strm,
|
||||
pjmedia_vid_param *param);
|
||||
static pj_status_t ios_stream_get_cap(pjmedia_vid_stream *strm,
|
||||
pjmedia_vid_dev_cap cap,
|
||||
void *value);
|
||||
static pj_status_t ios_stream_set_cap(pjmedia_vid_stream *strm,
|
||||
pjmedia_vid_dev_cap cap,
|
||||
const void *value);
|
||||
static pj_status_t ios_stream_start(pjmedia_vid_stream *strm);
|
||||
static pj_status_t ios_stream_put_frame(pjmedia_vid_stream *strm,
|
||||
const pjmedia_frame *frame);
|
||||
static pj_status_t ios_stream_stop(pjmedia_vid_stream *strm);
|
||||
static pj_status_t ios_stream_destroy(pjmedia_vid_stream *strm);
|
||||
|
||||
/* Operations */
|
||||
static pjmedia_vid_dev_factory_op factory_op =
|
||||
{
|
||||
&ios_factory_init,
|
||||
&ios_factory_destroy,
|
||||
&ios_factory_get_dev_count,
|
||||
&ios_factory_get_dev_info,
|
||||
&ios_factory_default_param,
|
||||
&ios_factory_create_stream
|
||||
};
|
||||
|
||||
static pjmedia_vid_stream_op stream_op =
|
||||
{
|
||||
&ios_stream_get_param,
|
||||
&ios_stream_get_cap,
|
||||
&ios_stream_set_cap,
|
||||
&ios_stream_start,
|
||||
NULL,
|
||||
&ios_stream_put_frame,
|
||||
&ios_stream_stop,
|
||||
&ios_stream_destroy
|
||||
};
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* Factory operations
|
||||
*/
|
||||
/*
|
||||
* Init ios_ video driver.
|
||||
*/
|
||||
pjmedia_vid_dev_factory* pjmedia_ios_factory(pj_pool_factory *pf)
|
||||
{
|
||||
struct ios_factory *f;
|
||||
pj_pool_t *pool;
|
||||
|
||||
pool = pj_pool_create(pf, "ios video", 512, 512, NULL);
|
||||
f = PJ_POOL_ZALLOC_T(pool, struct ios_factory);
|
||||
f->pf = pf;
|
||||
f->pool = pool;
|
||||
f->base.op = &factory_op;
|
||||
|
||||
return &f->base;
|
||||
}
|
||||
|
||||
|
||||
/* API: init factory */
|
||||
static pj_status_t ios_factory_init(pjmedia_vid_dev_factory *f)
|
||||
{
|
||||
struct ios_factory *qf = (struct ios_factory*)f;
|
||||
struct ios_dev_info *qdi;
|
||||
unsigned i, l;
|
||||
|
||||
/* Initialize input and output devices here */
|
||||
qf->dev_info = (struct ios_dev_info*)
|
||||
pj_pool_calloc(qf->pool, 2,
|
||||
sizeof(struct ios_dev_info));
|
||||
|
||||
qf->dev_count = 0;
|
||||
qdi = &qf->dev_info[qf->dev_count++];
|
||||
pj_bzero(qdi, sizeof(*qdi));
|
||||
strcpy(qdi->info.name, "iOS UIView");
|
||||
strcpy(qdi->info.driver, "iOS");
|
||||
qdi->info.dir = PJMEDIA_DIR_RENDER;
|
||||
qdi->info.has_callback = PJ_FALSE;
|
||||
|
||||
if (NSClassFromString(@"AVCaptureSession")) {
|
||||
qdi = &qf->dev_info[qf->dev_count++];
|
||||
pj_bzero(qdi, sizeof(*qdi));
|
||||
strcpy(qdi->info.name, "iOS AVCapture");
|
||||
strcpy(qdi->info.driver, "iOS");
|
||||
qdi->info.dir = PJMEDIA_DIR_CAPTURE;
|
||||
qdi->info.has_callback = PJ_TRUE;
|
||||
}
|
||||
|
||||
for (i = 0; i < qf->dev_count; i++) {
|
||||
qdi = &qf->dev_info[i];
|
||||
qdi->info.fmt_cnt = PJ_ARRAY_SIZE(ios_fmts);
|
||||
qdi->info.caps = PJMEDIA_VID_DEV_CAP_FORMAT;
|
||||
qdi->info.fmt = (pjmedia_format*)
|
||||
pj_pool_calloc(qf->pool, qdi->info.fmt_cnt,
|
||||
sizeof(pjmedia_format));
|
||||
|
||||
for (l = 0; l < PJ_ARRAY_SIZE(ios_fmts); l++) {
|
||||
pjmedia_format *fmt = &qdi->info.fmt[l];
|
||||
pjmedia_format_init_video(fmt,
|
||||
ios_fmts[l].pjmedia_format,
|
||||
DEFAULT_WIDTH,
|
||||
DEFAULT_HEIGHT,
|
||||
DEFAULT_FPS, 1);
|
||||
}
|
||||
}
|
||||
|
||||
PJ_LOG(4, (THIS_FILE, "iOS video initialized with %d devices",
|
||||
qf->dev_count));
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
/* API: destroy factory */
|
||||
static pj_status_t ios_factory_destroy(pjmedia_vid_dev_factory *f)
|
||||
{
|
||||
struct ios_factory *qf = (struct ios_factory*)f;
|
||||
pj_pool_t *pool = qf->pool;
|
||||
|
||||
qf->pool = NULL;
|
||||
pj_pool_release(pool);
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
/* API: get number of devices */
|
||||
static unsigned ios_factory_get_dev_count(pjmedia_vid_dev_factory *f)
|
||||
{
|
||||
struct ios_factory *qf = (struct ios_factory*)f;
|
||||
return qf->dev_count;
|
||||
}
|
||||
|
||||
/* API: get device info */
|
||||
static pj_status_t ios_factory_get_dev_info(pjmedia_vid_dev_factory *f,
|
||||
unsigned index,
|
||||
pjmedia_vid_dev_info *info)
|
||||
{
|
||||
struct ios_factory *qf = (struct ios_factory*)f;
|
||||
|
||||
PJ_ASSERT_RETURN(index < qf->dev_count, PJMEDIA_EVID_INVDEV);
|
||||
|
||||
pj_memcpy(info, &qf->dev_info[index].info, sizeof(*info));
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
/* API: create default device parameter */
|
||||
static pj_status_t ios_factory_default_param(pj_pool_t *pool,
|
||||
pjmedia_vid_dev_factory *f,
|
||||
unsigned index,
|
||||
pjmedia_vid_param *param)
|
||||
{
|
||||
struct ios_factory *qf = (struct ios_factory*)f;
|
||||
struct ios_dev_info *di = &qf->dev_info[index];
|
||||
|
||||
PJ_ASSERT_RETURN(index < qf->dev_count, PJMEDIA_EVID_INVDEV);
|
||||
|
||||
PJ_UNUSED_ARG(pool);
|
||||
|
||||
pj_bzero(param, sizeof(*param));
|
||||
if (di->info.dir & PJMEDIA_DIR_CAPTURE_RENDER) {
|
||||
param->dir = PJMEDIA_DIR_CAPTURE_RENDER;
|
||||
param->cap_id = index;
|
||||
param->rend_id = index;
|
||||
} else if (di->info.dir & PJMEDIA_DIR_CAPTURE) {
|
||||
param->dir = PJMEDIA_DIR_CAPTURE;
|
||||
param->cap_id = index;
|
||||
param->rend_id = PJMEDIA_VID_INVALID_DEV;
|
||||
} else if (di->info.dir & PJMEDIA_DIR_RENDER) {
|
||||
param->dir = PJMEDIA_DIR_RENDER;
|
||||
param->rend_id = index;
|
||||
param->cap_id = PJMEDIA_VID_INVALID_DEV;
|
||||
} else {
|
||||
return PJMEDIA_EVID_INVDEV;
|
||||
}
|
||||
|
||||
param->flags = PJMEDIA_VID_DEV_CAP_FORMAT;
|
||||
param->clock_rate = DEFAULT_CLOCK_RATE;
|
||||
param->frame_rate.num = DEFAULT_FPS;
|
||||
param->frame_rate.denum = 1;
|
||||
pj_memcpy(¶m->fmt, &di->info.fmt[0], sizeof(param->fmt));
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
@implementation VOutDelegate
|
||||
- (void)update_image
|
||||
{
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
/* Create a device-dependent RGB color space */
|
||||
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
||||
|
||||
/* Create a bitmap graphics context with the sample buffer data */
|
||||
CGContextRef context =
|
||||
CGBitmapContextCreate(stream->buf, stream->size.w, stream->size.h, 8,
|
||||
stream->bytes_per_row, colorSpace,
|
||||
kCGBitmapByteOrder32Little |
|
||||
kCGImageAlphaPremultipliedFirst);
|
||||
|
||||
/**
|
||||
* Create a Quartz image from the pixel data in the bitmap graphics
|
||||
* context
|
||||
*/
|
||||
CGImageRef quartzImage = CGBitmapContextCreateImage(context);
|
||||
|
||||
/* Free up the context and color space */
|
||||
CGContextRelease(context);
|
||||
CGColorSpaceRelease(colorSpace);
|
||||
|
||||
/* Create an image object from the Quartz image */
|
||||
UIImage *image = [UIImage imageWithCGImage:quartzImage scale:1.0
|
||||
orientation:UIImageOrientationRight];
|
||||
|
||||
/* Release the Quartz image */
|
||||
CGImageRelease(quartzImage);
|
||||
|
||||
[stream->imgView setImage:image];
|
||||
|
||||
[pool release];
|
||||
}
|
||||
|
||||
- (void)captureOutput:(AVCaptureOutput *)captureOutput
|
||||
didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
|
||||
fromConnection:(AVCaptureConnection *)connection
|
||||
{
|
||||
pjmedia_frame frame;
|
||||
CVImageBufferRef imageBuffer;
|
||||
|
||||
if (!sampleBuffer)
|
||||
return;
|
||||
|
||||
/* Get a CMSampleBuffer's Core Video image buffer for the media data */
|
||||
imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
|
||||
|
||||
/* Lock the base address of the pixel buffer */
|
||||
CVPixelBufferLockBaseAddress(imageBuffer, 0);
|
||||
|
||||
frame.type = PJMEDIA_TYPE_VIDEO;
|
||||
frame.buf = CVPixelBufferGetBaseAddress(imageBuffer);
|
||||
frame.size = stream->frame_size;
|
||||
frame.bit_info = 0;
|
||||
if (stream->vid_cb.capture_cb)
|
||||
(*stream->vid_cb.capture_cb)(&stream->base, stream->user_data, &frame);
|
||||
|
||||
/* Unlock the pixel buffer */
|
||||
CVPixelBufferUnlockBaseAddress(imageBuffer,0);
|
||||
}
|
||||
@end
|
||||
|
||||
static ios_fmt_info* get_ios_format_info(pjmedia_format_id id)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < PJ_ARRAY_SIZE(ios_fmts); i++) {
|
||||
if (ios_fmts[i].pjmedia_format == id)
|
||||
return &ios_fmts[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* API: create stream */
|
||||
static pj_status_t ios_factory_create_stream(pjmedia_vid_dev_factory *f,
|
||||
const pjmedia_vid_param *param,
|
||||
const pjmedia_vid_cb *cb,
|
||||
void *user_data,
|
||||
pjmedia_vid_stream **p_vid_strm)
|
||||
{
|
||||
struct ios_factory *qf = (struct ios_factory*)f;
|
||||
pj_pool_t *pool;
|
||||
struct ios_stream *strm;
|
||||
pjmedia_video_format_detail *vfd;
|
||||
const pjmedia_video_format_info *vfi;
|
||||
pj_status_t status = PJ_SUCCESS;
|
||||
ios_fmt_info *ifi = get_ios_format_info(param->fmt.id);
|
||||
NSError *error;
|
||||
|
||||
PJ_ASSERT_RETURN(f && param && p_vid_strm, PJ_EINVAL);
|
||||
PJ_ASSERT_RETURN(param->fmt.type == PJMEDIA_TYPE_VIDEO &&
|
||||
param->fmt.detail_type == PJMEDIA_FORMAT_DETAIL_VIDEO,
|
||||
PJ_EINVAL);
|
||||
|
||||
if (!(ifi = get_ios_format_info(param->fmt.id)))
|
||||
return PJMEDIA_EVID_BADFORMAT;
|
||||
|
||||
vfi = pjmedia_get_video_format_info(NULL, param->fmt.id);
|
||||
if (!vfi)
|
||||
return PJMEDIA_EVID_BADFORMAT;
|
||||
|
||||
/* Create and Initialize stream descriptor */
|
||||
pool = pj_pool_create(qf->pf, "ios-dev", 4000, 4000, NULL);
|
||||
PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);
|
||||
|
||||
strm = PJ_POOL_ZALLOC_T(pool, struct ios_stream);
|
||||
pj_memcpy(&strm->param, param, sizeof(*param));
|
||||
strm->pool = pool;
|
||||
pj_memcpy(&strm->vid_cb, cb, sizeof(*cb));
|
||||
strm->user_data = user_data;
|
||||
|
||||
vfd = pjmedia_format_get_video_format_detail(&strm->param.fmt, PJ_TRUE);
|
||||
pj_memcpy(&strm->size, &vfd->size, sizeof(vfd->size));
|
||||
strm->bpp = vfi->bpp;
|
||||
strm->bytes_per_row = strm->size.w * strm->bpp / 8;
|
||||
strm->frame_size = strm->bytes_per_row * strm->size.h;
|
||||
|
||||
/* Create capture stream here */
|
||||
if (param->dir & PJMEDIA_DIR_CAPTURE) {
|
||||
strm->cap_session = [[AVCaptureSession alloc] init];
|
||||
if (!strm->cap_session) {
|
||||
status = PJ_ENOMEM;
|
||||
goto on_error;
|
||||
}
|
||||
strm->cap_session.sessionPreset = AVCaptureSessionPresetMedium;
|
||||
|
||||
/* Open video device */
|
||||
AVCaptureDevice *videoDevice =
|
||||
[AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
|
||||
if (!videoDevice) {
|
||||
status = PJMEDIA_EVID_SYSERR;
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
/* Add the video device to the session as a device input */
|
||||
strm->dev_input = [AVCaptureDeviceInput
|
||||
deviceInputWithDevice:videoDevice
|
||||
error: &error];
|
||||
if (!strm->dev_input) {
|
||||
status = PJMEDIA_EVID_SYSERR;
|
||||
goto on_error;
|
||||
}
|
||||
[strm->cap_session addInput:strm->dev_input];
|
||||
|
||||
strm->video_output = [[[AVCaptureVideoDataOutput alloc] init]
|
||||
autorelease];
|
||||
if (!strm->video_output) {
|
||||
status = PJMEDIA_EVID_SYSERR;
|
||||
goto on_error;
|
||||
}
|
||||
[strm->cap_session addOutput:strm->video_output];
|
||||
|
||||
// Configure your output.
|
||||
strm->vout_delegate = [VOutDelegate alloc];
|
||||
strm->vout_delegate->stream = strm;
|
||||
dispatch_queue_t queue = dispatch_queue_create("myQueue", NULL);
|
||||
[strm->video_output setSampleBufferDelegate:strm->vout_delegate
|
||||
queue:queue];
|
||||
dispatch_release(queue);
|
||||
|
||||
strm->video_output.videoSettings =
|
||||
[NSDictionary dictionaryWithObjectsAndKeys:
|
||||
[NSNumber numberWithInt:ifi->ios_format],
|
||||
kCVPixelBufferPixelFormatTypeKey,
|
||||
[NSNumber numberWithInt: vfd->size.w],
|
||||
kCVPixelBufferWidthKey,
|
||||
[NSNumber numberWithInt: vfd->size.h],
|
||||
kCVPixelBufferHeightKey, nil];
|
||||
strm->video_output.minFrameDuration = CMTimeMake(vfd->fps.denum,
|
||||
vfd->fps.num);
|
||||
}
|
||||
|
||||
/* Create renderer stream here */
|
||||
if (param->dir & PJMEDIA_DIR_RENDER) {
|
||||
/* Get the main window */
|
||||
UIWindow *window = [[UIApplication sharedApplication] keyWindow];
|
||||
|
||||
pj_assert(window);
|
||||
strm->imgView = [[UIImageView alloc] initWithFrame:[window bounds]];
|
||||
if (!strm->imgView) {
|
||||
status = PJ_ENOMEM;
|
||||
goto on_error;
|
||||
}
|
||||
[window addSubview:strm->imgView];
|
||||
|
||||
if (!strm->vout_delegate) {
|
||||
strm->vout_delegate = [VOutDelegate alloc];
|
||||
strm->vout_delegate->stream = strm;
|
||||
}
|
||||
|
||||
strm->buf = pj_pool_alloc(pool, strm->frame_size);
|
||||
}
|
||||
|
||||
/* Apply the remaining settings */
|
||||
/*
|
||||
if (param->flags & PJMEDIA_VID_DEV_CAP_INPUT_SCALE) {
|
||||
ios_stream_set_cap(&strm->base,
|
||||
PJMEDIA_VID_DEV_CAP_INPUT_SCALE,
|
||||
¶m->fmt);
|
||||
}
|
||||
*/
|
||||
/* Done */
|
||||
strm->base.op = &stream_op;
|
||||
*p_vid_strm = &strm->base;
|
||||
|
||||
return PJ_SUCCESS;
|
||||
|
||||
on_error:
|
||||
ios_stream_destroy((pjmedia_vid_stream *)strm);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* API: Get stream info. */
|
||||
static pj_status_t ios_stream_get_param(pjmedia_vid_stream *s,
|
||||
pjmedia_vid_param *pi)
|
||||
{
|
||||
struct ios_stream *strm = (struct ios_stream*)s;
|
||||
|
||||
PJ_ASSERT_RETURN(strm && pi, PJ_EINVAL);
|
||||
|
||||
pj_memcpy(pi, &strm->param, sizeof(*pi));
|
||||
|
||||
/* if (ios_stream_get_cap(s, PJMEDIA_VID_DEV_CAP_INPUT_SCALE,
|
||||
&pi->fmt.info_size) == PJ_SUCCESS)
|
||||
{
|
||||
pi->flags |= PJMEDIA_VID_DEV_CAP_INPUT_SCALE;
|
||||
}
|
||||
*/
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
/* API: get capability */
|
||||
static pj_status_t ios_stream_get_cap(pjmedia_vid_stream *s,
|
||||
pjmedia_vid_dev_cap cap,
|
||||
void *pval)
|
||||
{
|
||||
struct ios_stream *strm = (struct ios_stream*)s;
|
||||
|
||||
PJ_UNUSED_ARG(strm);
|
||||
|
||||
PJ_ASSERT_RETURN(s && pval, PJ_EINVAL);
|
||||
|
||||
if (cap==PJMEDIA_VID_DEV_CAP_INPUT_SCALE)
|
||||
{
|
||||
return PJMEDIA_EVID_INVCAP;
|
||||
// return PJ_SUCCESS;
|
||||
} else {
|
||||
return PJMEDIA_EVID_INVCAP;
|
||||
}
|
||||
}
|
||||
|
||||
/* API: set capability */
|
||||
static pj_status_t ios_stream_set_cap(pjmedia_vid_stream *s,
|
||||
pjmedia_vid_dev_cap cap,
|
||||
const void *pval)
|
||||
{
|
||||
struct ios_stream *strm = (struct ios_stream*)s;
|
||||
|
||||
PJ_UNUSED_ARG(strm);
|
||||
|
||||
PJ_ASSERT_RETURN(s && pval, PJ_EINVAL);
|
||||
|
||||
if (cap==PJMEDIA_VID_DEV_CAP_INPUT_SCALE)
|
||||
{
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
return PJMEDIA_EVID_INVCAP;
|
||||
}
|
||||
|
||||
/* API: Start stream. */
|
||||
static pj_status_t ios_stream_start(pjmedia_vid_stream *strm)
|
||||
{
|
||||
struct ios_stream *stream = (struct ios_stream*)strm;
|
||||
|
||||
PJ_UNUSED_ARG(stream);
|
||||
|
||||
PJ_LOG(4, (THIS_FILE, "Starting qt video stream"));
|
||||
|
||||
if (stream->cap_session) {
|
||||
[stream->cap_session startRunning];
|
||||
|
||||
if (![stream->cap_session isRunning])
|
||||
return PJ_EUNKNOWN;
|
||||
}
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/* API: Put frame from stream */
|
||||
static pj_status_t ios_stream_put_frame(pjmedia_vid_stream *strm,
|
||||
const pjmedia_frame *frame)
|
||||
{
|
||||
struct ios_stream *stream = (struct ios_stream*)strm;
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
pj_assert(stream->frame_size >= frame->size);
|
||||
pj_memcpy(stream->buf, frame->buf, frame->size);
|
||||
/* Perform video display in a background thread */
|
||||
// [stream->vout_delegate update_image];
|
||||
[NSThread detachNewThreadSelector:@selector(update_image)
|
||||
toTarget:stream->vout_delegate withObject:nil];
|
||||
|
||||
[pool release];
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
/* API: Stop stream. */
|
||||
static pj_status_t ios_stream_stop(pjmedia_vid_stream *strm)
|
||||
{
|
||||
struct ios_stream *stream = (struct ios_stream*)strm;
|
||||
|
||||
PJ_UNUSED_ARG(stream);
|
||||
|
||||
PJ_LOG(4, (THIS_FILE, "Stopping qt video stream"));
|
||||
|
||||
if (stream->cap_session && [stream->cap_session isRunning])
|
||||
[stream->cap_session stopRunning];
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/* API: Destroy stream. */
|
||||
static pj_status_t ios_stream_destroy(pjmedia_vid_stream *strm)
|
||||
{
|
||||
struct ios_stream *stream = (struct ios_stream*)strm;
|
||||
|
||||
PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL);
|
||||
|
||||
ios_stream_stop(strm);
|
||||
|
||||
if (stream->imgView) {
|
||||
[stream->imgView removeFromSuperview];
|
||||
[stream->imgView release];
|
||||
stream->imgView = NULL;
|
||||
}
|
||||
|
||||
if (stream->cap_session) {
|
||||
[stream->cap_session release];
|
||||
stream->cap_session = NULL;
|
||||
}
|
||||
/* if (stream->dev_input) {
|
||||
[stream->dev_input release];
|
||||
stream->dev_input = NULL;
|
||||
}
|
||||
*/
|
||||
if (stream->vout_delegate) {
|
||||
[stream->vout_delegate release];
|
||||
stream->vout_delegate = NULL;
|
||||
}
|
||||
/* if (stream->video_output) {
|
||||
[stream->video_output release];
|
||||
stream->video_output = NULL;
|
||||
}
|
||||
*/
|
||||
|
||||
pj_pool_release(stream->pool);
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif /* PJMEDIA_VIDEO_DEV_HAS_IOS */
|
|
@ -0,0 +1,595 @@
|
|||
/* $Id$ */
|
||||
/*
|
||||
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include <pjmedia-videodev/videodev_imp.h>
|
||||
#include <pj/assert.h>
|
||||
#include <pj/log.h>
|
||||
#include <pj/os.h>
|
||||
|
||||
#if PJMEDIA_VIDEO_DEV_HAS_QT
|
||||
|
||||
#include <QTKit/QTKit.h>
|
||||
|
||||
#define THIS_FILE "qt_dev.c"
|
||||
#define DEFAULT_CLOCK_RATE 9000
|
||||
#define DEFAULT_WIDTH 640
|
||||
#define DEFAULT_HEIGHT 480
|
||||
#define DEFAULT_FPS 15
|
||||
|
||||
#define kCVPixelFormatType_422YpCbCr8_yuvs 'yuvs'
|
||||
|
||||
typedef struct qt_fmt_info
|
||||
{
|
||||
pjmedia_format_id pjmedia_format;
|
||||
unsigned qt_format;
|
||||
} qt_fmt_info;
|
||||
|
||||
static qt_fmt_info qt_fmts[] =
|
||||
{
|
||||
{PJMEDIA_FORMAT_YUY2, kCVPixelFormatType_422YpCbCr8_yuvs} ,
|
||||
};
|
||||
|
||||
/* qt device info */
|
||||
struct qt_dev_info
|
||||
{
|
||||
pjmedia_vid_dev_info info;
|
||||
char dev_id[192];
|
||||
};
|
||||
|
||||
/* qt factory */
|
||||
struct qt_factory
|
||||
{
|
||||
pjmedia_vid_dev_factory base;
|
||||
pj_pool_t *pool;
|
||||
pj_pool_factory *pf;
|
||||
|
||||
unsigned dev_count;
|
||||
struct qt_dev_info *dev_info;
|
||||
};
|
||||
|
||||
@interface VOutDelegate: NSObject
|
||||
{
|
||||
@public
|
||||
struct qt_stream *stream;
|
||||
}
|
||||
@end
|
||||
|
||||
/* Video stream. */
|
||||
struct qt_stream
|
||||
{
|
||||
pjmedia_vid_stream base; /**< Base stream */
|
||||
pjmedia_vid_param param; /**< Settings */
|
||||
pj_pool_t *pool; /**< Memory pool. */
|
||||
|
||||
pjmedia_vid_cb vid_cb; /**< Stream callback. */
|
||||
void *user_data; /**< Application data. */
|
||||
|
||||
QTCaptureSession *cap_session;
|
||||
QTCaptureDeviceInput *dev_input;
|
||||
QTCaptureDecompressedVideoOutput *video_output;
|
||||
VOutDelegate *vout_delegate;
|
||||
};
|
||||
|
||||
|
||||
/* Prototypes */
|
||||
static pj_status_t qt_factory_init(pjmedia_vid_dev_factory *f);
|
||||
static pj_status_t qt_factory_destroy(pjmedia_vid_dev_factory *f);
|
||||
static unsigned qt_factory_get_dev_count(pjmedia_vid_dev_factory *f);
|
||||
static pj_status_t qt_factory_get_dev_info(pjmedia_vid_dev_factory *f,
|
||||
unsigned index,
|
||||
pjmedia_vid_dev_info *info);
|
||||
static pj_status_t qt_factory_default_param(pj_pool_t *pool,
|
||||
pjmedia_vid_dev_factory *f,
|
||||
unsigned index,
|
||||
pjmedia_vid_param *param);
|
||||
static pj_status_t qt_factory_create_stream(pjmedia_vid_dev_factory *f,
|
||||
const pjmedia_vid_param *param,
|
||||
const pjmedia_vid_cb *cb,
|
||||
void *user_data,
|
||||
pjmedia_vid_stream **p_vid_strm);
|
||||
|
||||
static pj_status_t qt_stream_get_param(pjmedia_vid_stream *strm,
|
||||
pjmedia_vid_param *param);
|
||||
static pj_status_t qt_stream_get_cap(pjmedia_vid_stream *strm,
|
||||
pjmedia_vid_dev_cap cap,
|
||||
void *value);
|
||||
static pj_status_t qt_stream_set_cap(pjmedia_vid_stream *strm,
|
||||
pjmedia_vid_dev_cap cap,
|
||||
const void *value);
|
||||
static pj_status_t qt_stream_start(pjmedia_vid_stream *strm);
|
||||
static pj_status_t qt_stream_stop(pjmedia_vid_stream *strm);
|
||||
static pj_status_t qt_stream_destroy(pjmedia_vid_stream *strm);
|
||||
|
||||
/* Operations */
|
||||
static pjmedia_vid_dev_factory_op factory_op =
|
||||
{
|
||||
&qt_factory_init,
|
||||
&qt_factory_destroy,
|
||||
&qt_factory_get_dev_count,
|
||||
&qt_factory_get_dev_info,
|
||||
&qt_factory_default_param,
|
||||
&qt_factory_create_stream
|
||||
};
|
||||
|
||||
static pjmedia_vid_stream_op stream_op =
|
||||
{
|
||||
&qt_stream_get_param,
|
||||
&qt_stream_get_cap,
|
||||
&qt_stream_set_cap,
|
||||
&qt_stream_start,
|
||||
NULL,
|
||||
NULL,
|
||||
&qt_stream_stop,
|
||||
&qt_stream_destroy
|
||||
};
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* Factory operations
|
||||
*/
|
||||
/*
|
||||
* Init qt_ video driver.
|
||||
*/
|
||||
pjmedia_vid_dev_factory* pjmedia_qt_factory(pj_pool_factory *pf)
|
||||
{
|
||||
struct qt_factory *f;
|
||||
pj_pool_t *pool;
|
||||
|
||||
pool = pj_pool_create(pf, "qt video", 4000, 4000, NULL);
|
||||
f = PJ_POOL_ZALLOC_T(pool, struct qt_factory);
|
||||
f->pf = pf;
|
||||
f->pool = pool;
|
||||
f->base.op = &factory_op;
|
||||
|
||||
return &f->base;
|
||||
}
|
||||
|
||||
|
||||
/* API: init factory */
|
||||
static pj_status_t qt_factory_init(pjmedia_vid_dev_factory *f)
|
||||
{
|
||||
struct qt_factory *qf = (struct qt_factory*)f;
|
||||
struct qt_dev_info *qdi;
|
||||
unsigned i, dev_count = 0;
|
||||
NSArray *dev_array;
|
||||
|
||||
dev_array = [QTCaptureDevice inputDevices];
|
||||
for (i = 0; i < [dev_array count]; i++) {
|
||||
QTCaptureDevice *dev = [dev_array objectAtIndex:i];
|
||||
if ([dev hasMediaType:QTMediaTypeVideo] ||
|
||||
[dev hasMediaType:QTMediaTypeMuxed])
|
||||
{
|
||||
dev_count++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialize input and output devices here */
|
||||
qf->dev_count = 0;
|
||||
qf->dev_info = (struct qt_dev_info*)
|
||||
pj_pool_calloc(qf->pool, dev_count,
|
||||
sizeof(struct qt_dev_info));
|
||||
for (i = 0; i < [dev_array count]; i++) {
|
||||
QTCaptureDevice *dev = [dev_array objectAtIndex:i];
|
||||
if ([dev hasMediaType:QTMediaTypeVideo] ||
|
||||
[dev hasMediaType:QTMediaTypeMuxed])
|
||||
{
|
||||
unsigned j, k;
|
||||
|
||||
qdi = &qf->dev_info[qf->dev_count++];
|
||||
pj_bzero(qdi, sizeof(*qdi));
|
||||
[[dev localizedDisplayName] getCString:qdi->info.name
|
||||
maxLength:sizeof(qdi->info.name)
|
||||
encoding:
|
||||
[NSString defaultCStringEncoding]];
|
||||
[[dev uniqueID] getCString:qdi->dev_id
|
||||
maxLength:sizeof(qdi->dev_id)
|
||||
encoding:[NSString defaultCStringEncoding]];
|
||||
strcpy(qdi->info.driver, "QT");
|
||||
qdi->info.dir = PJMEDIA_DIR_CAPTURE;
|
||||
qdi->info.has_callback = PJ_TRUE;
|
||||
|
||||
qdi->info.fmt_cnt = 0;
|
||||
for (k = 0; k < [[dev formatDescriptions] count]; k++) {
|
||||
QTFormatDescription *desc = [[dev formatDescriptions]
|
||||
objectAtIndex:k];
|
||||
for (j = 0; j < PJ_ARRAY_SIZE(qt_fmts); j++) {
|
||||
if ([desc formatType] == qt_fmts[j].qt_format) {
|
||||
qdi->info.fmt_cnt++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
qdi->info.caps = PJMEDIA_VID_DEV_CAP_FORMAT;
|
||||
qdi->info.fmt = (pjmedia_format*)
|
||||
pj_pool_calloc(qf->pool, qdi->info.fmt_cnt,
|
||||
sizeof(pjmedia_format));
|
||||
for (j = k = 0; k < [[dev formatDescriptions] count]; k++) {
|
||||
unsigned l;
|
||||
QTFormatDescription *desc = [[dev formatDescriptions]
|
||||
objectAtIndex:k];
|
||||
for (l = 0; l < PJ_ARRAY_SIZE(qt_fmts); l++) {
|
||||
if ([desc formatType] == qt_fmts[j].qt_format) {
|
||||
pjmedia_format *fmt = &qdi->info.fmt[j++];
|
||||
pjmedia_format_init_video(fmt,
|
||||
qt_fmts[l].pjmedia_format,
|
||||
DEFAULT_WIDTH,
|
||||
DEFAULT_HEIGHT,
|
||||
DEFAULT_FPS, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PJ_LOG(4, (THIS_FILE, " dev_id %d: %s", i, qdi->info.name));
|
||||
}
|
||||
}
|
||||
|
||||
PJ_LOG(4, (THIS_FILE, "qt video initialized with %d devices",
|
||||
qf->dev_count));
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
/* API: destroy factory */
|
||||
static pj_status_t qt_factory_destroy(pjmedia_vid_dev_factory *f)
|
||||
{
|
||||
struct qt_factory *qf = (struct qt_factory*)f;
|
||||
pj_pool_t *pool = qf->pool;
|
||||
|
||||
qf->pool = NULL;
|
||||
pj_pool_release(pool);
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
/* API: get number of devices */
|
||||
static unsigned qt_factory_get_dev_count(pjmedia_vid_dev_factory *f)
|
||||
{
|
||||
struct qt_factory *qf = (struct qt_factory*)f;
|
||||
return qf->dev_count;
|
||||
}
|
||||
|
||||
/* API: get device info */
|
||||
static pj_status_t qt_factory_get_dev_info(pjmedia_vid_dev_factory *f,
|
||||
unsigned index,
|
||||
pjmedia_vid_dev_info *info)
|
||||
{
|
||||
struct qt_factory *qf = (struct qt_factory*)f;
|
||||
|
||||
PJ_ASSERT_RETURN(index < qf->dev_count, PJMEDIA_EVID_INVDEV);
|
||||
|
||||
pj_memcpy(info, &qf->dev_info[index].info, sizeof(*info));
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
/* API: create default device parameter */
|
||||
static pj_status_t qt_factory_default_param(pj_pool_t *pool,
|
||||
pjmedia_vid_dev_factory *f,
|
||||
unsigned index,
|
||||
pjmedia_vid_param *param)
|
||||
{
|
||||
struct qt_factory *qf = (struct qt_factory*)f;
|
||||
struct qt_dev_info *di = &qf->dev_info[index];
|
||||
|
||||
PJ_ASSERT_RETURN(index < qf->dev_count, PJMEDIA_EVID_INVDEV);
|
||||
|
||||
PJ_UNUSED_ARG(pool);
|
||||
|
||||
pj_bzero(param, sizeof(*param));
|
||||
param->dir = PJMEDIA_DIR_CAPTURE;
|
||||
param->cap_id = index;
|
||||
param->rend_id = PJMEDIA_VID_INVALID_DEV;
|
||||
param->flags = PJMEDIA_VID_DEV_CAP_FORMAT;
|
||||
param->clock_rate = DEFAULT_CLOCK_RATE;
|
||||
param->frame_rate.num = DEFAULT_FPS;
|
||||
param->frame_rate.denum = 1;
|
||||
pj_memcpy(¶m->fmt, &di->info.fmt[0], sizeof(param->fmt));
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
@implementation VOutDelegate
|
||||
- (void)captureOutput:(QTCaptureOutput *)captureOutput
|
||||
didOutputVideoFrame:(CVImageBufferRef)videoFrame
|
||||
withSampleBuffer:(QTSampleBuffer *)sampleBuffer
|
||||
fromConnection:(QTCaptureConnection *)connection
|
||||
{
|
||||
unsigned size = [sampleBuffer lengthForAllSamples];
|
||||
pjmedia_frame frame;
|
||||
|
||||
if (!videoFrame)
|
||||
return;
|
||||
|
||||
frame.type = PJMEDIA_TYPE_VIDEO;
|
||||
frame.buf = [sampleBuffer bytesForAllSamples];
|
||||
frame.size = size;
|
||||
frame.bit_info = 0;
|
||||
if (stream->vid_cb.capture_cb)
|
||||
(*stream->vid_cb.capture_cb)(&stream->base, stream->user_data,
|
||||
&frame);
|
||||
}
|
||||
@end
|
||||
|
||||
static qt_fmt_info* get_qt_format_info(pjmedia_format_id id)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < PJ_ARRAY_SIZE(qt_fmts); i++) {
|
||||
if (qt_fmts[i].pjmedia_format == id)
|
||||
return &qt_fmts[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* API: create stream */
|
||||
static pj_status_t qt_factory_create_stream(pjmedia_vid_dev_factory *f,
|
||||
const pjmedia_vid_param *param,
|
||||
const pjmedia_vid_cb *cb,
|
||||
void *user_data,
|
||||
pjmedia_vid_stream **p_vid_strm)
|
||||
{
|
||||
struct qt_factory *qf = (struct qt_factory*)f;
|
||||
pj_pool_t *pool;
|
||||
struct qt_stream *strm;
|
||||
const pjmedia_video_format_info *vfi;
|
||||
pj_status_t status = PJ_SUCCESS;
|
||||
BOOL success = NO;
|
||||
NSError *error;
|
||||
|
||||
PJ_ASSERT_RETURN(f && param && p_vid_strm, PJ_EINVAL);
|
||||
PJ_ASSERT_RETURN(param->fmt.type == PJMEDIA_TYPE_VIDEO &&
|
||||
param->fmt.detail_type == PJMEDIA_FORMAT_DETAIL_VIDEO,
|
||||
PJ_EINVAL);
|
||||
|
||||
vfi = pjmedia_get_video_format_info(NULL, param->fmt.id);
|
||||
if (!vfi)
|
||||
return PJMEDIA_EVID_BADFORMAT;
|
||||
|
||||
/* Create and Initialize stream descriptor */
|
||||
pool = pj_pool_create(qf->pf, "qt-dev", 4000, 4000, NULL);
|
||||
PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);
|
||||
|
||||
strm = PJ_POOL_ZALLOC_T(pool, struct qt_stream);
|
||||
pj_memcpy(&strm->param, param, sizeof(*param));
|
||||
strm->pool = pool;
|
||||
pj_memcpy(&strm->vid_cb, cb, sizeof(*cb));
|
||||
strm->user_data = user_data;
|
||||
|
||||
/* Create player stream here */
|
||||
if (param->dir & PJMEDIA_DIR_PLAYBACK) {
|
||||
}
|
||||
|
||||
/* Create capture stream here */
|
||||
if (param->dir & PJMEDIA_DIR_CAPTURE) {
|
||||
pjmedia_video_format_detail *vfd;
|
||||
qt_fmt_info *qfi = get_qt_format_info(param->fmt.id);
|
||||
|
||||
if (!qfi) {
|
||||
status = PJMEDIA_EVID_BADFORMAT;
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
strm->cap_session = [[QTCaptureSession alloc] init];
|
||||
if (!strm->cap_session) {
|
||||
status = PJ_ENOMEM;
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
/* Open video device */
|
||||
QTCaptureDevice *videoDevice =
|
||||
[QTCaptureDevice deviceWithUniqueID:
|
||||
[NSString stringWithCString:
|
||||
qf->dev_info[param->cap_id].dev_id
|
||||
encoding:
|
||||
[NSString defaultCStringEncoding]]];
|
||||
if (!videoDevice || ![videoDevice open:&error]) {
|
||||
status = PJMEDIA_EVID_SYSERR;
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
/* Add the video device to the session as a device input */
|
||||
strm->dev_input = [[QTCaptureDeviceInput alloc]
|
||||
initWithDevice:videoDevice];
|
||||
success = [strm->cap_session addInput:strm->dev_input error:&error];
|
||||
if (!success) {
|
||||
status = PJMEDIA_EVID_SYSERR;
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
strm->video_output = [[QTCaptureDecompressedVideoOutput alloc] init];
|
||||
success = [strm->cap_session addOutput:strm->video_output
|
||||
error:&error];
|
||||
if (!success) {
|
||||
status = PJMEDIA_EVID_SYSERR;
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
vfd = pjmedia_format_get_video_format_detail(&strm->param.fmt,
|
||||
PJ_TRUE);
|
||||
[strm->video_output setPixelBufferAttributes:
|
||||
[NSDictionary dictionaryWithObjectsAndKeys:
|
||||
[NSNumber numberWithInt:
|
||||
qfi->qt_format],
|
||||
kCVPixelBufferPixelFormatTypeKey,
|
||||
[NSNumber numberWithInt:
|
||||
vfd->size.w],
|
||||
kCVPixelBufferWidthKey,
|
||||
[NSNumber numberWithInt:
|
||||
vfd->size.h],
|
||||
kCVPixelBufferHeightKey, nil]];
|
||||
|
||||
pj_assert(vfd->fps.num);
|
||||
[strm->video_output setMinimumVideoFrameInterval:
|
||||
(1.0f * vfd->fps.denum / (double)vfd->fps.num)];
|
||||
|
||||
strm->vout_delegate = [VOutDelegate alloc];
|
||||
strm->vout_delegate->stream = strm;
|
||||
[strm->video_output setDelegate:strm->vout_delegate];
|
||||
}
|
||||
|
||||
/* Apply the remaining settings */
|
||||
/*
|
||||
if (param->flags & PJMEDIA_VID_DEV_CAP_INPUT_SCALE) {
|
||||
qt_stream_set_cap(&strm->base,
|
||||
PJMEDIA_VID_DEV_CAP_INPUT_SCALE,
|
||||
¶m->fmt);
|
||||
}
|
||||
*/
|
||||
/* Done */
|
||||
strm->base.op = &stream_op;
|
||||
*p_vid_strm = &strm->base;
|
||||
|
||||
return PJ_SUCCESS;
|
||||
|
||||
on_error:
|
||||
qt_stream_destroy((pjmedia_vid_stream *)strm);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* API: Get stream info. */
|
||||
static pj_status_t qt_stream_get_param(pjmedia_vid_stream *s,
|
||||
pjmedia_vid_param *pi)
|
||||
{
|
||||
struct qt_stream *strm = (struct qt_stream*)s;
|
||||
|
||||
PJ_ASSERT_RETURN(strm && pi, PJ_EINVAL);
|
||||
|
||||
pj_memcpy(pi, &strm->param, sizeof(*pi));
|
||||
|
||||
/* if (qt_stream_get_cap(s, PJMEDIA_VID_DEV_CAP_INPUT_SCALE,
|
||||
&pi->fmt.info_size) == PJ_SUCCESS)
|
||||
{
|
||||
pi->flags |= PJMEDIA_VID_DEV_CAP_INPUT_SCALE;
|
||||
}
|
||||
*/
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
/* API: get capability */
|
||||
static pj_status_t qt_stream_get_cap(pjmedia_vid_stream *s,
|
||||
pjmedia_vid_dev_cap cap,
|
||||
void *pval)
|
||||
{
|
||||
struct qt_stream *strm = (struct qt_stream*)s;
|
||||
|
||||
PJ_UNUSED_ARG(strm);
|
||||
|
||||
PJ_ASSERT_RETURN(s && pval, PJ_EINVAL);
|
||||
|
||||
if (cap==PJMEDIA_VID_DEV_CAP_INPUT_SCALE)
|
||||
{
|
||||
return PJMEDIA_EVID_INVCAP;
|
||||
// return PJ_SUCCESS;
|
||||
} else {
|
||||
return PJMEDIA_EVID_INVCAP;
|
||||
}
|
||||
}
|
||||
|
||||
/* API: set capability */
|
||||
static pj_status_t qt_stream_set_cap(pjmedia_vid_stream *s,
|
||||
pjmedia_vid_dev_cap cap,
|
||||
const void *pval)
|
||||
{
|
||||
struct qt_stream *strm = (struct qt_stream*)s;
|
||||
|
||||
PJ_UNUSED_ARG(strm);
|
||||
|
||||
PJ_ASSERT_RETURN(s && pval, PJ_EINVAL);
|
||||
|
||||
if (cap==PJMEDIA_VID_DEV_CAP_INPUT_SCALE)
|
||||
{
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
return PJMEDIA_EVID_INVCAP;
|
||||
}
|
||||
|
||||
/* API: Start stream. */
|
||||
static pj_status_t qt_stream_start(pjmedia_vid_stream *strm)
|
||||
{
|
||||
struct qt_stream *stream = (struct qt_stream*)strm;
|
||||
|
||||
PJ_UNUSED_ARG(stream);
|
||||
|
||||
PJ_LOG(4, (THIS_FILE, "Starting qt video stream"));
|
||||
|
||||
if (stream->cap_session) {
|
||||
[stream->cap_session startRunning];
|
||||
|
||||
if (![stream->cap_session isRunning])
|
||||
return PJ_EUNKNOWN;
|
||||
}
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
/* API: Stop stream. */
|
||||
static pj_status_t qt_stream_stop(pjmedia_vid_stream *strm)
|
||||
{
|
||||
struct qt_stream *stream = (struct qt_stream*)strm;
|
||||
|
||||
PJ_UNUSED_ARG(stream);
|
||||
|
||||
PJ_LOG(4, (THIS_FILE, "Stopping qt video stream"));
|
||||
|
||||
if (stream->cap_session && [stream->cap_session isRunning])
|
||||
[stream->cap_session stopRunning];
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/* API: Destroy stream. */
|
||||
static pj_status_t qt_stream_destroy(pjmedia_vid_stream *strm)
|
||||
{
|
||||
struct qt_stream *stream = (struct qt_stream*)strm;
|
||||
|
||||
PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL);
|
||||
|
||||
qt_stream_stop(strm);
|
||||
|
||||
if (stream->dev_input && [[stream->dev_input device] isOpen])
|
||||
[[stream->dev_input device] close];
|
||||
|
||||
if (stream->cap_session) {
|
||||
[stream->cap_session release];
|
||||
stream->cap_session = NULL;
|
||||
}
|
||||
if (stream->dev_input) {
|
||||
[stream->dev_input release];
|
||||
stream->dev_input = NULL;
|
||||
}
|
||||
if (stream->vout_delegate) {
|
||||
[stream->vout_delegate release];
|
||||
stream->vout_delegate = NULL;
|
||||
}
|
||||
if (stream->video_output) {
|
||||
[stream->video_output release];
|
||||
stream->video_output = NULL;
|
||||
}
|
||||
|
||||
pj_pool_release(stream->pool);
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
#endif /* PJMEDIA_VIDEO_DEV_HAS_QT */
|
|
@ -24,6 +24,10 @@
|
|||
|
||||
#if PJMEDIA_VIDEO_DEV_HAS_SDL
|
||||
|
||||
#if defined(PJ_DARWINOS) && PJ_DARWINOS!=0
|
||||
# include <Foundation/NSAutoreleasePool.h>
|
||||
#endif
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#define THIS_FILE "sdl_dev.c"
|
||||
|
@ -323,25 +327,29 @@ static int create_sdl_thread(void * data)
|
|||
const pjmedia_video_format_info *vfi;
|
||||
pjmedia_video_format_detail *vfd;
|
||||
|
||||
#if defined(PJ_DARWINOS) && PJ_DARWINOS!=0
|
||||
NSAutoreleasePool *apool = [[NSAutoreleasePool alloc] init];
|
||||
#endif
|
||||
|
||||
vfi = pjmedia_get_video_format_info(pjmedia_video_format_mgr_instance(),
|
||||
strm->param.fmt.id);
|
||||
if (!vfi || !sdl_info) {
|
||||
strm->status = PJMEDIA_EVID_BADFORMAT;
|
||||
return strm->status;
|
||||
goto on_return;
|
||||
}
|
||||
|
||||
strm->vafp.size = strm->param.fmt.det.vid.size;
|
||||
strm->vafp.buffer = NULL;
|
||||
if (vfi->apply_fmt(vfi, &strm->vafp) != PJ_SUCCESS) {
|
||||
strm->status = PJMEDIA_EVID_BADFORMAT;
|
||||
return strm->status;
|
||||
goto on_return;
|
||||
}
|
||||
|
||||
/* Initialize the SDL library */
|
||||
if (SDL_Init(SDL_INIT_VIDEO)) {
|
||||
PJ_LOG(4, (THIS_FILE, "Cannot initialize SDL"));
|
||||
strm->status = PJMEDIA_EVID_INIT;
|
||||
return strm->status;
|
||||
goto on_return;
|
||||
}
|
||||
|
||||
vfd = pjmedia_format_get_video_format_detail(&strm->param.fmt, PJ_TRUE);
|
||||
|
@ -354,7 +362,7 @@ static int create_sdl_thread(void * data)
|
|||
0, SDL_RESIZABLE | SDL_SWSURFACE);
|
||||
if (strm->screen == NULL) {
|
||||
strm->status = PJMEDIA_EVID_SYSERR;
|
||||
return strm->status;
|
||||
goto on_return;
|
||||
}
|
||||
SDL_WM_SetCaption("pjmedia-SDL video", NULL);
|
||||
|
||||
|
@ -368,7 +376,7 @@ static int create_sdl_thread(void * data)
|
|||
sdl_info->Amask);
|
||||
if (strm->surf == NULL) {
|
||||
strm->status = PJMEDIA_EVID_SYSERR;
|
||||
return strm->status;
|
||||
goto on_return;
|
||||
}
|
||||
} else if (vfi->color_model == PJMEDIA_COLOR_MODEL_YUV) {
|
||||
strm->overlay = SDL_CreateYUVOverlay(strm->rect.w, strm->rect.h,
|
||||
|
@ -376,7 +384,7 @@ static int create_sdl_thread(void * data)
|
|||
strm->screen);
|
||||
if (strm->overlay == NULL) {
|
||||
strm->status = PJMEDIA_EVID_SYSERR;
|
||||
return strm->status;
|
||||
goto on_return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -389,7 +397,7 @@ static int create_sdl_thread(void * data)
|
|||
|
||||
switch(sevent.type) {
|
||||
case SDL_USEREVENT:
|
||||
return 0;
|
||||
goto on_return;
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
pevent.event_type = PJMEDIA_EVENT_MOUSEBUTTONDOWN;
|
||||
if (strm->vid_cb.on_event_cb)
|
||||
|
@ -448,7 +456,7 @@ static int create_sdl_thread(void * data)
|
|||
|
||||
/* Destroy the stream */
|
||||
sdl_stream_destroy(&strm->base);
|
||||
return 0;
|
||||
goto on_return;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -460,7 +468,7 @@ static int create_sdl_thread(void * data)
|
|||
sdl_stream_stop(&strm->base);
|
||||
SDL_Quit();
|
||||
strm->screen = NULL;
|
||||
return 0;
|
||||
goto on_return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -468,7 +476,12 @@ static int create_sdl_thread(void * data)
|
|||
|
||||
}
|
||||
|
||||
return 0;
|
||||
on_return:
|
||||
#if defined(PJ_DARWINOS) && PJ_DARWINOS!=0
|
||||
[apool release];
|
||||
#endif
|
||||
|
||||
return strm->status;
|
||||
}
|
||||
|
||||
/* API: create stream */
|
||||
|
@ -598,17 +611,22 @@ static pj_status_t sdl_stream_put_frame(pjmedia_vid_stream *strm,
|
|||
const pjmedia_frame *frame)
|
||||
{
|
||||
struct sdl_stream *stream = (struct sdl_stream*)strm;
|
||||
|
||||
pj_status_t status = PJ_SUCCESS;
|
||||
#if defined(PJ_DARWINOS) && PJ_DARWINOS!=0
|
||||
NSAutoreleasePool *apool = [[NSAutoreleasePool alloc] init];
|
||||
#endif
|
||||
|
||||
if (!stream->is_running) {
|
||||
stream->render_exited = PJ_TRUE;
|
||||
return PJ_SUCCESS;
|
||||
goto on_return;
|
||||
}
|
||||
|
||||
if (stream->surf) {
|
||||
if (SDL_MUSTLOCK(stream->surf)) {
|
||||
if (SDL_LockSurface(stream->surf) < 0) {
|
||||
PJ_LOG(3, (THIS_FILE, "Unable to lock SDL surface"));
|
||||
return PJMEDIA_EVID_NOTREADY;
|
||||
status = PJMEDIA_EVID_NOTREADY;
|
||||
goto on_return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -624,7 +642,8 @@ static pj_status_t sdl_stream_put_frame(pjmedia_vid_stream *strm,
|
|||
|
||||
if (SDL_LockYUVOverlay(stream->overlay) < 0) {
|
||||
PJ_LOG(3, (THIS_FILE, "Unable to lock SDL overlay"));
|
||||
return PJMEDIA_EVID_NOTREADY;
|
||||
status = PJMEDIA_EVID_NOTREADY;
|
||||
goto on_return;
|
||||
}
|
||||
|
||||
for (i = 0, offset = 0; i < stream->overlay->planes; i++) {
|
||||
|
@ -638,7 +657,12 @@ static pj_status_t sdl_stream_put_frame(pjmedia_vid_stream *strm,
|
|||
SDL_DisplayYUVOverlay(stream->overlay, &stream->rect);
|
||||
}
|
||||
|
||||
return PJ_SUCCESS;
|
||||
on_return:
|
||||
#if defined(PJ_DARWINOS) && PJ_DARWINOS!=0
|
||||
[apool release];
|
||||
#endif
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* API: Start stream. */
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
/* $Id$ */
|
||||
/*
|
||||
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "sdl_dev.c"
|
|
@ -78,6 +78,14 @@ pjmedia_vid_dev_factory* pjmedia_ffmpeg_factory(pj_pool_factory *pf);
|
|||
pjmedia_vid_dev_factory* pjmedia_v4l2_factory(pj_pool_factory *pf);
|
||||
#endif
|
||||
|
||||
#if PJMEDIA_VIDEO_DEV_HAS_QT
|
||||
pjmedia_vid_dev_factory* pjmedia_qt_factory(pj_pool_factory *pf);
|
||||
#endif
|
||||
|
||||
#if PJMEDIA_VIDEO_DEV_HAS_IOS
|
||||
pjmedia_vid_dev_factory* pjmedia_ios_factory(pj_pool_factory *pf);
|
||||
#endif
|
||||
|
||||
#define MAX_DRIVERS 16
|
||||
#define MAX_DEVS 64
|
||||
|
||||
|
@ -327,6 +335,12 @@ PJ_DEF(pj_status_t) pjmedia_vid_subsys_init(pj_pool_factory *pf)
|
|||
#if PJMEDIA_VIDEO_DEV_HAS_V4L2
|
||||
vid_subsys.drv[vid_subsys.drv_cnt++].create = &pjmedia_v4l2_factory;
|
||||
#endif
|
||||
#if PJMEDIA_VIDEO_DEV_HAS_QT
|
||||
vid_subsys.drv[vid_subsys.drv_cnt++].create = &pjmedia_qt_factory;
|
||||
#endif
|
||||
#if PJMEDIA_VIDEO_DEV_HAS_IOS
|
||||
vid_subsys.drv[vid_subsys.drv_cnt++].create = &pjmedia_ios_factory;
|
||||
#endif
|
||||
#if PJMEDIA_VIDEO_DEV_HAS_DSHOW
|
||||
vid_subsys.drv[vid_subsys.drv_cnt++].create = &pjmedia_dshow_factory;
|
||||
#endif
|
||||
|
|
|
@ -47,15 +47,21 @@ int test_main(void)
|
|||
{
|
||||
int rc = 0;
|
||||
pj_caching_pool caching_pool;
|
||||
pj_pool_t *pool;
|
||||
|
||||
pj_init();
|
||||
pj_caching_pool_init(&caching_pool, &pj_pool_factory_default_policy, 0);
|
||||
|
||||
pool = pj_pool_create(&caching_pool.factory, "test", 1000, 512, NULL);
|
||||
|
||||
pj_log_set_decor(PJ_LOG_HAS_NEWLINE);
|
||||
pj_log_set_level(3);
|
||||
|
||||
mem = &caching_pool.factory;
|
||||
|
||||
pjmedia_video_format_mgr_create(pool, 64, 0, NULL);
|
||||
pjmedia_converter_mgr_create(pool, NULL);
|
||||
pjmedia_vid_codec_mgr_create(pool, NULL);
|
||||
|
||||
#if HAS_VID_DEV_TEST
|
||||
DO_TEST(vid_dev_test());
|
||||
#endif
|
||||
|
@ -89,6 +95,11 @@ on_return:
|
|||
PJ_LOG(3,(THIS_FILE,"Looks like everything is okay!"));
|
||||
}
|
||||
|
||||
pjmedia_video_format_mgr_destroy(pjmedia_video_format_mgr_instance());
|
||||
pjmedia_converter_mgr_destroy(pjmedia_converter_mgr_instance());
|
||||
pjmedia_vid_codec_mgr_destroy(pjmedia_vid_codec_mgr_instance());
|
||||
|
||||
pj_pool_release(pool);
|
||||
pj_caching_pool_destroy(&caching_pool);
|
||||
|
||||
return rc;
|
||||
|
|
|
@ -23,6 +23,18 @@
|
|||
#include <pjmedia/vid_codec.h>
|
||||
#include <pjmedia_videodev.h>
|
||||
|
||||
#if defined(PJ_DARWINOS) && PJ_DARWINOS!=0
|
||||
# include "TargetConditionals.h"
|
||||
# if !TARGET_OS_IPHONE
|
||||
# define VID_DEV_TEST_MAC_OS 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if VID_DEV_TEST_MAC_OS
|
||||
# include <Foundation/NSAutoreleasePool.h>
|
||||
# include <AppKit/NSApplication.h>
|
||||
#endif
|
||||
|
||||
#define THIS_FILE "vid_dev_test.c"
|
||||
|
||||
pj_status_t pjmedia_libswscale_converter_init(pjmedia_converter_mgr *mgr,
|
||||
|
@ -386,6 +398,10 @@ static int aviplay_test(pj_pool_t *pool)
|
|||
}
|
||||
}
|
||||
|
||||
#if VID_DEV_TEST_MAC_OS
|
||||
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, false);
|
||||
#endif
|
||||
|
||||
pj_thread_sleep(150000);
|
||||
|
||||
on_return:
|
||||
|
@ -472,6 +488,10 @@ static int loopback_test(pj_pool_t *pool)
|
|||
rc = 160; goto on_return;
|
||||
}
|
||||
|
||||
#if VID_DEV_TEST_MAC_OS
|
||||
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, false);
|
||||
#endif
|
||||
|
||||
/* Sleep while the webcam is being displayed... */
|
||||
pj_thread_sleep(20000);
|
||||
|
||||
|
@ -491,6 +511,12 @@ int vid_dev_test(void)
|
|||
int rc = 0;
|
||||
pj_status_t status;
|
||||
|
||||
#if VID_DEV_TEST_MAC_OS
|
||||
NSAutoreleasePool *apool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
[NSApplication sharedApplication];
|
||||
#endif
|
||||
|
||||
PJ_LOG(3, (THIS_FILE, "Video device tests.."));
|
||||
|
||||
pool = pj_pool_create(mem, "Viddev test", 256, 256, 0);
|
||||
|
@ -523,6 +549,10 @@ on_return:
|
|||
pjmedia_vid_subsys_shutdown();
|
||||
pj_pool_release(pool);
|
||||
|
||||
#if VID_DEV_TEST_MAC_OS
|
||||
[apool release];
|
||||
#endif
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
/* $Id$ */
|
||||
/*
|
||||
* Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
|
||||
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "vid_dev_test.c"
|
Loading…
Reference in New Issue