Changeset 5793


Ignore:
Timestamp:
May 18, 2018 2:29:04 AM (6 years ago)
Author:
ming
Message:

Fixed #2114: Reset VideoToolbox? on iOS when app switches from background to active

File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjmedia/src/pjmedia-codec/vid_toolbox.m

    r5625 r5793  
    3535 
    3636#if (defined(PJ_DARWINOS) && PJ_DARWINOS != 0 && TARGET_OS_IPHONE) 
     37#import <UIKit/UIKit.h> 
     38 
    3739#  define DEFAULT_WIDTH         352 
    3840#  define DEFAULT_HEIGHT        288 
     
    480482} 
    481483 
    482 static pj_status_t vtool_codec_open(pjmedia_vid_codec *codec, 
    483                                     pjmedia_vid_codec_param *codec_param ) 
    484 { 
    485     vtool_codec_data            *vtool_data; 
    486     pjmedia_vid_codec_param     *param; 
    487     pjmedia_h264_packetizer_cfg  pktz_cfg; 
    488     pjmedia_vid_codec_h264_fmtp  h264_fmtp; 
    489     pj_status_t                  status; 
    490     CMVideoCodecType             codec_type; 
     484 
     485static OSStatus create_encoder(vtool_codec_data *vtool_data) 
     486{ 
     487    pjmedia_vid_codec_param     *param = vtool_data->prm; 
    491488    CFDictionaryRef              supported_prop; 
    492489    OSStatus                     ret; 
    493490 
    494     PJ_ASSERT_RETURN(codec && codec_param, PJ_EINVAL); 
    495  
    496     PJ_LOG(5,(THIS_FILE, "Opening codec..")); 
    497  
    498     vtool_data = (vtool_codec_data*) codec->codec_data; 
    499     vtool_data->prm = pjmedia_vid_codec_param_clone( vtool_data->pool, 
    500                                                      codec_param); 
    501     param = vtool_data->prm; 
    502  
    503     /* Parse remote fmtp */ 
    504     pj_bzero(&h264_fmtp, sizeof(h264_fmtp)); 
    505     status = pjmedia_vid_codec_h264_parse_fmtp(&param->enc_fmtp, &h264_fmtp); 
    506     if (status != PJ_SUCCESS) 
    507         return status; 
    508  
    509     /* Apply SDP fmtp to format in codec param */ 
    510     if (!param->ignore_fmtp) { 
    511         status = pjmedia_vid_codec_h264_apply_fmtp(param); 
    512         if (status != PJ_SUCCESS) 
    513             return status; 
    514     } 
    515  
    516     pj_bzero(&pktz_cfg, sizeof(pktz_cfg)); 
    517     pktz_cfg.mtu = param->enc_mtu; 
    518     pktz_cfg.unpack_nal_start = 4; 
    519     /* Packetization mode */ 
    520     if (h264_fmtp.packetization_mode == 0) 
    521         pktz_cfg.mode = PJMEDIA_H264_PACKETIZER_MODE_SINGLE_NAL; 
    522     else if (h264_fmtp.packetization_mode == 1) 
    523         pktz_cfg.mode = PJMEDIA_H264_PACKETIZER_MODE_NON_INTERLEAVED; 
    524     else 
    525         return PJ_ENOTSUP; 
    526     /* Video Toolbox encoder doesn't support setting maximum slice size, 
    527      * so we cannot use single NAL mode since the NAL size likely 
    528      * exceeds the MTU. 
    529      */ 
    530     pktz_cfg.mode = PJMEDIA_H264_PACKETIZER_MODE_NON_INTERLEAVED; 
    531  
    532     status = pjmedia_h264_packetizer_create(vtool_data->pool, &pktz_cfg, 
    533                                             &vtool_data->pktz); 
    534     if (status != PJ_SUCCESS) 
    535         return status; 
    536  
    537     vtool_data->whole = (param->packing == PJMEDIA_VID_PACKING_WHOLE); 
    538     if (1) { 
    539         /* Init format info and apply-param of encoder */ 
    540         const pjmedia_video_format_info *enc_vfi; 
    541         pjmedia_video_apply_fmt_param    enc_vafp; 
    542  
    543         enc_vfi = pjmedia_get_video_format_info(NULL,codec_param->dec_fmt.id); 
    544         if (!enc_vfi) 
    545             return PJ_EINVAL; 
    546      
    547         pj_bzero(&enc_vafp, sizeof(enc_vafp)); 
    548         enc_vafp.size = codec_param->enc_fmt.det.vid.size; 
    549         enc_vafp.buffer = NULL; 
    550         status = (*enc_vfi->apply_fmt)(enc_vfi, &enc_vafp); 
    551         if (status != PJ_SUCCESS) 
    552             return status; 
    553  
    554         vtool_data->enc_wxh = codec_param->enc_fmt.det.vid.size.w * 
    555                               codec_param->enc_fmt.det.vid.size.h; 
    556         vtool_data->enc_input_size = enc_vafp.framebytes; 
    557         if (!vtool_data->whole) { 
    558             vtool_data->enc_buf_size = (unsigned)enc_vafp.framebytes; 
    559             vtool_data->enc_buf = pj_pool_alloc(vtool_data->pool, 
    560                                                 vtool_data->enc_buf_size); 
    561         } 
     491    /* Destroy if initialized before */ 
     492    if (vtool_data->enc) { 
     493        VTCompressionSessionInvalidate(vtool_data->enc); 
     494        CFRelease(vtool_data->enc); 
     495        vtool_data->enc = NULL; 
    562496    } 
    563497 
    564498    /* Create encoder session */ 
    565     codec_type = kCMVideoCodecType_H264; 
    566499    ret = VTCompressionSessionCreate(NULL, (int)param->enc_fmt.det.vid.size.w, 
    567500                                     (int)param->enc_fmt.det.vid.size.h,  
     
    571504    if (ret != noErr) { 
    572505        PJ_LOG(4,(THIS_FILE, "VTCompressionCreate failed, ret=%d", ret)); 
    573         return PJMEDIA_CODEC_EFAILED; 
     506        return ret; 
    574507    } 
    575508 
     
    626559 
    627560    VTCompressionSessionPrepareToEncodeFrames(vtool_data->enc); 
    628      
     561 
     562    return ret; 
     563} 
     564 
     565 
     566static pj_status_t vtool_codec_open(pjmedia_vid_codec *codec, 
     567                                    pjmedia_vid_codec_param *codec_param ) 
     568{ 
     569    vtool_codec_data            *vtool_data; 
     570    pjmedia_vid_codec_param     *param; 
     571    pjmedia_h264_packetizer_cfg  pktz_cfg; 
     572    pjmedia_vid_codec_h264_fmtp  h264_fmtp; 
     573    pj_status_t                  status; 
     574    OSStatus                     ret; 
     575 
     576    PJ_ASSERT_RETURN(codec && codec_param, PJ_EINVAL); 
     577 
     578    PJ_LOG(5,(THIS_FILE, "Opening codec..")); 
     579 
     580    vtool_data = (vtool_codec_data*) codec->codec_data; 
     581    vtool_data->prm = pjmedia_vid_codec_param_clone( vtool_data->pool, 
     582                                                     codec_param); 
     583    param = vtool_data->prm; 
     584 
     585    /* Parse remote fmtp */ 
     586    pj_bzero(&h264_fmtp, sizeof(h264_fmtp)); 
     587    status = pjmedia_vid_codec_h264_parse_fmtp(&param->enc_fmtp, &h264_fmtp); 
     588    if (status != PJ_SUCCESS) 
     589        return status; 
     590 
     591    /* Apply SDP fmtp to format in codec param */ 
     592    if (!param->ignore_fmtp) { 
     593        status = pjmedia_vid_codec_h264_apply_fmtp(param); 
     594        if (status != PJ_SUCCESS) 
     595            return status; 
     596    } 
     597 
     598    pj_bzero(&pktz_cfg, sizeof(pktz_cfg)); 
     599    pktz_cfg.mtu = param->enc_mtu; 
     600    pktz_cfg.unpack_nal_start = 4; 
     601    /* Packetization mode */ 
     602    if (h264_fmtp.packetization_mode == 0) 
     603        pktz_cfg.mode = PJMEDIA_H264_PACKETIZER_MODE_SINGLE_NAL; 
     604    else if (h264_fmtp.packetization_mode == 1) 
     605        pktz_cfg.mode = PJMEDIA_H264_PACKETIZER_MODE_NON_INTERLEAVED; 
     606    else 
     607        return PJ_ENOTSUP; 
     608    /* Video Toolbox encoder doesn't support setting maximum slice size, 
     609     * so we cannot use single NAL mode since the NAL size likely 
     610     * exceeds the MTU. 
     611     */ 
     612    pktz_cfg.mode = PJMEDIA_H264_PACKETIZER_MODE_NON_INTERLEAVED; 
     613 
     614    status = pjmedia_h264_packetizer_create(vtool_data->pool, &pktz_cfg, 
     615                                            &vtool_data->pktz); 
     616    if (status != PJ_SUCCESS) 
     617        return status; 
     618 
     619    vtool_data->whole = (param->packing == PJMEDIA_VID_PACKING_WHOLE); 
     620    if (1) { 
     621        /* Init format info and apply-param of encoder */ 
     622        const pjmedia_video_format_info *enc_vfi; 
     623        pjmedia_video_apply_fmt_param    enc_vafp; 
     624 
     625        enc_vfi = pjmedia_get_video_format_info(NULL,codec_param->dec_fmt.id); 
     626        if (!enc_vfi) 
     627            return PJ_EINVAL; 
     628     
     629        pj_bzero(&enc_vafp, sizeof(enc_vafp)); 
     630        enc_vafp.size = codec_param->enc_fmt.det.vid.size; 
     631        enc_vafp.buffer = NULL; 
     632        status = (*enc_vfi->apply_fmt)(enc_vfi, &enc_vafp); 
     633        if (status != PJ_SUCCESS) 
     634            return status; 
     635 
     636        vtool_data->enc_wxh = codec_param->enc_fmt.det.vid.size.w * 
     637                              codec_param->enc_fmt.det.vid.size.h; 
     638        vtool_data->enc_input_size = enc_vafp.framebytes; 
     639        if (!vtool_data->whole) { 
     640            vtool_data->enc_buf_size = (unsigned)enc_vafp.framebytes; 
     641            vtool_data->enc_buf = pj_pool_alloc(vtool_data->pool, 
     642                                                vtool_data->enc_buf_size); 
     643        } 
     644    } 
     645 
     646    /* Create encoder */ 
     647    ret = create_encoder(vtool_data); 
     648    if (ret != noErr) 
     649        return PJMEDIA_CODEC_EFAILED; 
     650 
    629651    /* If available, use the "sprop-parameter-sets" fmtp from remote SDP 
    630652     * to create the decoder. 
     
    737759    NSDictionary *frm_prop = NULL; 
    738760    OSStatus ret; 
     761#if TARGET_OS_IPHONE 
     762    UIApplicationState state; 
     763#endif 
    739764  
    740765    PJ_ASSERT_RETURN(codec && input && out_size && output && has_more, 
    741766                     PJ_EINVAL); 
     767 
     768#if TARGET_OS_IPHONE 
     769    /* Skip encoding if app is not active, i.e. in the bg. */ 
     770    state = [UIApplication sharedApplication].applicationState; 
     771    if (state != UIApplicationStateActive) { 
     772        *has_more = PJ_FALSE; 
     773        output->size = 0; 
     774        output->type = PJMEDIA_FRAME_TYPE_NONE; 
     775 
     776        return PJ_SUCCESS; 
     777    } 
     778#endif 
    742779 
    743780    vtool_data = (vtool_codec_data*) codec->codec_data; 
     
    810847                                          (__bridge CFDictionaryRef)frm_prop, 
    811848                                          NULL, NULL); 
     849    if (ret == kVTInvalidSessionErr) { 
     850        /* Reset compression session */ 
     851        ret = create_encoder(vtool_data); 
     852        PJ_LOG(3,(THIS_FILE, "Encoder needs to be reset [1]: %s (%d)", 
     853                  (ret == noErr? "success": "fail"), ret)); 
     854        if (ret == noErr) { 
     855            /* Retry encoding the frame after successful encoder reset. */ 
     856            ret = VTCompressionSessionEncodeFrame(vtool_data->enc, image_buf, 
     857                                                  ts, dur, 
     858                                                  (__bridge CFDictionaryRef) 
     859                                                  frm_prop, 
     860                                                  NULL, NULL); 
     861        } 
     862    } 
     863 
    812864    if (ret != noErr) { 
    813865        PJ_LOG(4,(THIS_FILE, "Failed to encode frame %d", ret)); 
     
    819871    ts.flags = kCMTimeFlags_Indefinite; 
    820872    ret = VTCompressionSessionCompleteFrames(vtool_data->enc, ts); 
     873    if (ret == kVTInvalidSessionErr) { 
     874        /* Reset compression session */ 
     875        ret = create_encoder(vtool_data); 
     876        PJ_LOG(3,(THIS_FILE, "Encoder needs to be reset [2]: %s (%d)", 
     877                  (ret == noErr? "success": "fail"), ret)); 
     878        if (ret == PJ_SUCCESS) { 
     879            /* Retry finishing the encoding after successful encoder reset. */ 
     880            ret = VTCompressionSessionCompleteFrames(vtool_data->enc, ts); 
     881        } 
     882    } 
     883 
    821884    if (ret != noErr) { 
    822885        PJ_LOG(4,(THIS_FILE, "Failed to complete encoding %d", ret)); 
     
    9901053     } 
    9911054 
    992     if (!vtool_data->dec || 
     1055    if (!vtool_data->dec || !vtool_data->dec_format || 
    9931056        !CMFormatDescriptionEqual(dec_format, vtool_data->dec_format)) 
    9941057    { 
     
    10491112    pj_bool_t decode_whole = DECODE_WHOLE; 
    10501113    OSStatus ret; 
     1114#if TARGET_OS_IPHONE 
     1115    UIApplicationState state; 
     1116#endif 
    10511117 
    10521118    PJ_ASSERT_RETURN(codec && count && packets && out_size && output, 
    10531119                     PJ_EINVAL); 
    10541120    PJ_ASSERT_RETURN(output->buf, PJ_EINVAL); 
     1121 
     1122#if TARGET_OS_IPHONE 
     1123    /* Skip decoding if app is not active, i.e. in the bg. */ 
     1124    state = [UIApplication sharedApplication].applicationState; 
     1125    if (state != UIApplicationStateActive) { 
     1126        output->type = PJMEDIA_FRAME_TYPE_NONE; 
     1127        output->size = 0; 
     1128        output->timestamp = packets[0].timestamp; 
     1129        return PJ_SUCCESS; 
     1130    } 
     1131#endif 
    10551132 
    10561133    vtool_data = (vtool_codec_data*) codec->codec_data; 
     
    12001277                          vtool_data->dec, sample_buf, 0, 
    12011278                          NULL, NULL); 
     1279                if (ret == kVTInvalidSessionErr) { 
     1280                    if (vtool_data->dec_format) 
     1281                        CFRelease(vtool_data->dec_format); 
     1282                    vtool_data->dec_format = NULL; 
     1283                    ret = create_decoder(vtool_data); 
     1284                    PJ_LOG(3,(THIS_FILE, "Decoder needs to be reset: %s (%d)", 
     1285                              (ret == noErr? "success": "fail"), ret)); 
     1286 
     1287                    if (ret == noErr) { 
     1288                        /* Retry decoding the frame after successful reset */ 
     1289                        ret = VTDecompressionSessionDecodeFrame( 
     1290                                  vtool_data->dec, sample_buf, 0, 
     1291                                  NULL, NULL); 
     1292                    } 
     1293                } 
     1294 
    12021295                if (ret != noErr) { 
    12031296                    PJ_LOG(5,(THIS_FILE, "Failed to decode frame %d of size " 
Note: See TracChangeset for help on using the changeset viewer.