summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLiong Sauw Ming <ming@teluu.com>2015-04-08 10:09:37 +0000
committerLiong Sauw Ming <ming@teluu.com>2015-04-08 10:09:37 +0000
commit845c2292d93a2432e4a82aab34f2ad876d7b9c9c (patch)
treee70e2938acbf60b9a944ab2160d53c448db76e50
parent4145e2473a1fcd68fa3351ca2a9f10de31277e35 (diff)
Re #1837: Fix dispatch queue problem in iOS capture device (crash in enc_clock_cb)
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@5054 74dad513-b988-da41-8d7b-12977e46ad98
-rw-r--r--pjmedia/src/pjmedia-videodev/ios_dev.m76
1 files changed, 45 insertions, 31 deletions
diff --git a/pjmedia/src/pjmedia-videodev/ios_dev.m b/pjmedia/src/pjmedia-videodev/ios_dev.m
index d116681b..79ece95a 100644
--- a/pjmedia/src/pjmedia-videodev/ios_dev.m
+++ b/pjmedia/src/pjmedia-videodev/ios_dev.m
@@ -106,13 +106,14 @@ struct ios_stream
unsigned bytes_per_row;
unsigned frame_size; /**< Frame size (bytes)*/
pj_bool_t is_planar;
+ NSLock *frame_lock;
+ void *capture_buf;
AVCaptureSession *cap_session;
AVCaptureDeviceInput *dev_input;
AVCaptureVideoDataOutput *video_output;
VOutDelegate *vout_delegate;
dispatch_queue_t queue;
- void *capture_buf;
AVCaptureVideoPreviewLayer *prev_layer;
void *render_buf;
@@ -122,10 +123,6 @@ struct ios_stream
pj_timestamp frame_ts;
unsigned ts_inc;
-
- pj_bool_t thread_initialized;
- pj_thread_desc thread_desc;
- pj_thread_t *thread;
};
@@ -157,6 +154,8 @@ static pj_status_t ios_stream_set_cap(pjmedia_vid_dev_stream *strm,
pjmedia_vid_dev_cap cap,
const void *value);
static pj_status_t ios_stream_start(pjmedia_vid_dev_stream *strm);
+static pj_status_t ios_stream_get_frame(pjmedia_vid_dev_stream *strm,
+ pjmedia_frame *frame);
static pj_status_t ios_stream_put_frame(pjmedia_vid_dev_stream *strm,
const pjmedia_frame *frame);
static pj_status_t ios_stream_stop(pjmedia_vid_dev_stream *strm);
@@ -180,7 +179,7 @@ static pjmedia_vid_dev_stream_op stream_op =
&ios_stream_get_cap,
&ios_stream_set_cap,
&ios_stream_start,
- NULL,
+ &ios_stream_get_frame,
&ios_stream_put_frame,
&ios_stream_stop,
&ios_stream_destroy
@@ -261,7 +260,7 @@ static pj_status_t ios_factory_init(pjmedia_vid_dev_factory *f)
sizeof(qdi->info.name));
pj_ansi_strncpy(qdi->info.driver, "iOS", sizeof(qdi->info.driver));
qdi->info.dir = PJMEDIA_DIR_CAPTURE;
- qdi->info.has_callback = PJ_TRUE;
+ qdi->info.has_callback = PJ_FALSE;
qdi->info.caps = PJMEDIA_VID_DEV_CAP_INPUT_PREVIEW |
PJMEDIA_VID_DEV_CAP_SWITCH;
qdi->dev = device;
@@ -435,9 +434,15 @@ static pj_status_t ios_factory_default_param(pj_pool_t *pool,
didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
fromConnection:(AVCaptureConnection *)connection
{
- pjmedia_frame frame = {0};
CVImageBufferRef img;
+ /* Refrain from calling pjlib functions which require thread registration
+ * here, since according to the doc, dispatch queue cannot guarantee
+ * the reliability of underlying functions required by PJSIP to perform
+ * the registration, such as pthread_self() and pthread_getspecific()/
+ * pthread_setspecific().
+ */
+
if (!sampleBuffer)
return;
@@ -447,10 +452,8 @@ static pj_status_t ios_factory_default_param(pj_pool_t *pool,
/* Lock the base address of the pixel buffer */
CVPixelBufferLockBaseAddress(img, kCVPixelBufferLock_ReadOnly);
- frame.type = PJMEDIA_FRAME_TYPE_VIDEO;
- frame.size = stream->frame_size;
- frame.timestamp.u64 = stream->frame_ts.u64;
-
+
+ [stream->frame_lock lock];
if (stream->is_planar && stream->capture_buf) {
if (stream->param.fmt.id == PJMEDIA_FORMAT_I420) {
/* kCVPixelFormatType_420YpCbCr8BiPlanar* is NV12 */
@@ -498,32 +501,39 @@ static pj_status_t ios_factory_default_param(pj_pool_t *pool,
p += (stride - stream->size.w);
}
}
-
- frame.buf = stream->capture_buf;
}
} else {
- frame.buf = CVPixelBufferGetBaseAddress(img);
- }
-
- if (stream->vid_cb.capture_cb) {
- if (stream->thread_initialized == 0 || !pj_thread_is_registered())
- {
- pj_bzero(stream->thread_desc, sizeof(pj_thread_desc));
- pj_thread_register("ios_vdev", stream->thread_desc,
- &stream->thread);
- stream->thread_initialized = 1;
- }
-
- (*stream->vid_cb.capture_cb)(&stream->base, stream->user_data, &frame);
+ pj_memcpy(stream->capture_buf, CVPixelBufferGetBaseAddress(img),
+ stream->frame_size);
}
stream->frame_ts.u64 += stream->ts_inc;
+ [stream->frame_lock unlock];
/* Unlock the pixel buffer */
CVPixelBufferUnlockBaseAddress(img, kCVPixelBufferLock_ReadOnly);
}
@end
+static pj_status_t ios_stream_get_frame(pjmedia_vid_dev_stream *strm,
+ pjmedia_frame *frame)
+{
+ struct ios_stream *stream = (struct ios_stream *)strm;
+
+ frame->type = PJMEDIA_FRAME_TYPE_VIDEO;
+ frame->bit_info = 0;
+ pj_assert(frame->size >= stream->frame_size);
+ frame->size = stream->frame_size;
+ frame->timestamp.u64 = stream->frame_ts.u64;
+
+ [stream->frame_lock lock];
+ pj_memcpy(frame->buf, stream->capture_buf, stream->frame_size);
+ [stream->frame_lock unlock];
+
+ return PJ_SUCCESS;
+}
+
+
static ios_fmt_info* get_ios_format_info(pjmedia_format_id id)
{
unsigned i;
@@ -712,10 +722,9 @@ static pj_status_t ios_factory_create_stream(
goto on_error;
}
- /* Prepare capture buffer if it's planar format */
- if (strm->is_planar)
- strm->capture_buf = pj_pool_alloc(strm->pool, strm->frame_size);
-
+ strm->capture_buf = pj_pool_alloc(strm->pool, strm->frame_size);
+ strm->frame_lock = [[NSLock alloc]init];
+
/* Native preview */
if (param->flags & PJMEDIA_VID_DEV_CAP_INPUT_PREVIEW) {
ios_stream_set_cap(&strm->base, PJMEDIA_VID_DEV_CAP_INPUT_PREVIEW,
@@ -1126,6 +1135,11 @@ static pj_status_t ios_stream_destroy(pjmedia_vid_dev_stream *strm)
dispatch_release(stream->queue);
stream->queue = nil;
}
+
+ if (stream->frame_lock) {
+ [stream->frame_lock release];
+ stream->frame_lock = nil;
+ }
pj_pool_release(stream->pool);