Fixed native iOS preview issue (#3350)

This commit is contained in:
sauwming 2023-02-22 13:04:26 +08:00
parent 43c745789d
commit f1e6313389
3 changed files with 74 additions and 59 deletions

View File

@ -36,13 +36,8 @@
#define THIS_FILE "darwin_dev.m"
#define DEFAULT_CLOCK_RATE 90000
#if TARGET_OS_IPHONE
#define DEFAULT_WIDTH 352
#define DEFAULT_HEIGHT 288
#else
#define DEFAULT_WIDTH 1280
#define DEFAULT_HEIGHT 720
#endif
#define DEFAULT_WIDTH 640
#define DEFAULT_HEIGHT 480
#define DEFAULT_FPS 15
/* Define whether we should maintain the aspect ratio when rotating the image.
@ -144,7 +139,6 @@ struct darwin_stream
AVCaptureVideoDataOutput *video_output;
VOutDelegate *vout_delegate;
dispatch_queue_t queue;
AVCaptureVideoPreviewLayer *prev_layer;
pj_bool_t is_running;
#if TARGET_OS_IPHONE
@ -153,6 +147,8 @@ struct darwin_stream
pj_size_t render_buf_size;
CGDataProviderRef render_data_provider;
UIView *render_view;
AVCaptureVideoPreviewLayer *prev_layer;
UIView *prev_view;
#endif
pj_timestamp frame_ts;
@ -236,6 +232,7 @@ static void set_preset_str()
#endif
}
#if TARGET_OS_IPHONE
static void dispatch_sync_on_main_queue(void (^block)(void))
{
if ([NSThread isMainThread]) {
@ -244,6 +241,7 @@ static void dispatch_sync_on_main_queue(void (^block)(void))
dispatch_sync(dispatch_get_main_queue(), block);
}
}
#endif
/****************************************************************************
* Factory operations
@ -1018,11 +1016,18 @@ static pj_status_t darwin_stream_get_cap(pjmedia_vid_dev_stream *s,
switch (cap) {
#if TARGET_OS_IPHONE
case PJMEDIA_VID_DEV_CAP_INPUT_PREVIEW:
{
pjmedia_vid_dev_hwnd *hwnd = (pjmedia_vid_dev_hwnd *) pval;
hwnd->type = PJMEDIA_VID_DEV_HWND_TYPE_IOS;
hwnd->info.ios.window = (void *)strm->prev_view;
return PJ_SUCCESS;
}
case PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW:
{
pjmedia_vid_dev_hwnd *hwnd = (pjmedia_vid_dev_hwnd*) pval;
hwnd->type = PJMEDIA_VID_DEV_HWND_TYPE_NONE;
hwnd->info.ios.window = (void*)strm->render_view;
pjmedia_vid_dev_hwnd *hwnd = (pjmedia_vid_dev_hwnd *) pval;
hwnd->type = PJMEDIA_VID_DEV_HWND_TYPE_IOS;
hwnd->info.ios.window = (void *)strm->render_view;
return PJ_SUCCESS;
}
#endif /* TARGET_OS_IPHONE */
@ -1043,6 +1048,7 @@ static pj_status_t darwin_stream_set_cap(pjmedia_vid_dev_stream *s,
PJ_ASSERT_RETURN(s && pval, PJ_EINVAL);
switch (cap) {
#if TARGET_OS_IPHONE
/* Native preview */
case PJMEDIA_VID_DEV_CAP_INPUT_PREVIEW:
{
@ -1053,7 +1059,8 @@ static pj_status_t darwin_stream_set_cap(pjmedia_vid_dev_stream *s,
if (strm->prev_layer) {
CALayer *prev_layer = strm->prev_layer;
dispatch_sync_on_main_queue(^{
[prev_layer removeFromSuperlayer];
if ([prev_layer superlayer])
[prev_layer removeFromSuperlayer];
[prev_layer release];
});
strm->prev_layer = nil;
@ -1072,29 +1079,34 @@ static pj_status_t darwin_stream_set_cap(pjmedia_vid_dev_stream *s,
if (!strm->cap_session)
return PJ_EINVALIDOP;
#if TARGET_OS_IPHONE
/* Preview layer instantiation should be in main thread! */
dispatch_sync_on_main_queue(^{
/* Create view, if none */
if (!strm->render_view)
darwin_init_view(strm);
/* Create preview layer */
AVCaptureVideoPreviewLayer *prev_layer =
[[AVCaptureVideoPreviewLayer alloc]
initWithSession:strm->cap_session];
/* Attach preview layer to a UIView */
prev_layer.videoGravity = AVLayerVideoGravityResize;
prev_layer.frame = strm->render_view.bounds;
[strm->render_view.layer addSublayer:prev_layer];
strm->prev_layer = prev_layer;
strm->prev_layer = [[AVCaptureVideoPreviewLayer alloc]
initWithSession:strm->cap_session];
strm->prev_layer.videoGravity =
AVLayerVideoGravityResizeAspectFill;
/* Create preview view and init it at smaller size than
* the actual video.
*/
if (!strm->prev_view) {
CGRect rect;
rect = CGRectMake(0, 0, strm->param.fmt.det.vid.size.w/2,
strm->param.fmt.det.vid.size.h/2);
strm->prev_view = [[UIView alloc] initWithFrame:rect];
}
/* Add the preview layer as sublayer */
strm->prev_layer.frame = strm->prev_view.bounds;
[strm->prev_view.layer addSublayer:strm->prev_layer];
});
PJ_LOG(4, (THIS_FILE, "Native preview initialized"));
#endif
return PJ_SUCCESS;
}
#endif
/* Fast switch */
case PJMEDIA_VID_DEV_CAP_SWITCH:
@ -1198,8 +1210,6 @@ static pj_status_t darwin_stream_set_cap(pjmedia_vid_dev_stream *s,
r.size = CGSizeMake(strm->param.disp_size.w,
strm->param.disp_size.h);
strm->render_view.bounds = r;
if (strm->prev_layer)
strm->prev_layer.frame = r;
});
return PJ_SUCCESS;
}
@ -1450,6 +1460,15 @@ static pj_status_t darwin_stream_destroy(pjmedia_vid_dev_stream *strm)
[stream->render_view release];
stream->render_view = nil;
}
if (stream->prev_view) {
[stream->prev_view
performSelectorOnMainThread:@selector(removeFromSuperview)
withObject:nil waitUntilDone:YES];
[stream->prev_view release];
stream->prev_view = nil;
}
if (stream->render_data_provider) {
CGDataProviderRelease(stream->render_data_provider);

View File

@ -354,37 +354,30 @@ void displayWindow(pjsua_vid_win_id wid)
for (;i < last; ++i) {
pjsua_vid_win_info wi;
if (pjsua_vid_win_get_info(i, &wi) == PJ_SUCCESS) {
if (pjsua_vid_win_get_info(i, &wi) == PJ_SUCCESS &&
wi.hwnd.info.ios.window)
{
dispatch_async(dispatch_get_main_queue(), ^{
UIView *parent = app.viewController.view;
UIView *view = (__bridge UIView *)wi.hwnd.info.ios.window;
if (view) {
/* Add the video window as subview */
if (![view isDescendantOfView:parent])
[parent addSubview:view];
if (!wi.is_native) {
/* Resize it to fit width */
view.bounds = CGRectMake(0, 0, parent.bounds.size.width,
(parent.bounds.size.height *
1.0*parent.bounds.size.width/
view.bounds.size.width));
/* Center it horizontally */
view.center = CGPointMake(parent.bounds.size.width/2.0,
view.bounds.size.height/2.0);
} else {
/* Preview window, move it to the bottom */
view.center = CGPointMake(parent.bounds.size.width/2.0,
parent.bounds.size.height-
view.bounds.size.height/2.0);
}
if (![view isDescendantOfView:parent])
[parent addSubview:view];
if (!wi.is_native) {
/* Video window */
view.contentMode = UIViewContentModeScaleAspectFit;
view.center = parent.center;
view.frame = parent.bounds;
} else {
/* Preview window */
view.contentMode = UIViewContentModeBottomLeft;
view.frame = CGRectMake(0, parent.frame.size.height - view.frame.size.height,
view.frame.size.width, view.frame.size.height);
}
});
}
}
#endif
}

View File

@ -705,11 +705,14 @@ static pj_status_t create_vid_win(pjsua_vid_win_type type,
}
}
status = pjsua_vid_conf_connect(w->cap_slot, w->rend_slot, NULL);
if (status != PJ_SUCCESS) {
PJ_PERROR(4, (THIS_FILE, status,
"Ignored error on connecting video ports "
"on wid=%d", wid));
if (!w->is_native) {
status = pjsua_vid_conf_connect(w->cap_slot, w->rend_slot,
NULL);
if (status != PJ_SUCCESS) {
PJ_PERROR(4, (THIS_FILE, status,
"Ignored error on connecting video ports "
"on wid=%d", wid));
}
}
/* Done */
@ -1700,7 +1703,7 @@ PJ_DEF(pj_status_t) pjsua_vid_win_get_info( pjsua_vid_win_id wid,
if (w->is_native) {
pjmedia_vid_dev_stream *cap_strm;
pjmedia_vid_dev_cap cap = PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW;
pjmedia_vid_dev_cap cap = PJMEDIA_VID_DEV_CAP_INPUT_PREVIEW;
if (!w->vp_cap) {
status = PJ_EINVAL;