Changeset 3736


Ignore:
Timestamp:
Aug 29, 2011 8:36:59 AM (8 years ago)
Author:
ming
Message:

Fixed #1353: memory leak in qt_dev

File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjmedia/src/pjmedia-videodev/qt_dev.m

    r3722 r3736  
    6666}; 
    6767 
    68 @interface VOutDelegate: NSObject 
     68struct qt_stream; 
     69typedef void (*func_ptr)(struct qt_stream *strm); 
     70 
     71@interface QTDelegate: NSObject 
    6972{ 
    7073@public 
    71     struct qt_stream *stream; 
    72 } 
     74    struct qt_stream *strm; 
     75    func_ptr          func; 
     76} 
     77 
     78- (void)run_func; 
    7379@end 
    7480 
     
    9197    pj_thread_t            *cap_thread; 
    9298     
    93     NSAutoreleasePool                   *apool; 
     99    struct qt_factory      *qf; 
     100    pj_status_t             status; 
     101    pj_bool_t               is_running; 
     102    pj_bool_t               cap_exited; 
     103     
    94104    QTCaptureSession                    *cap_session; 
    95105    QTCaptureDeviceInput                *dev_input; 
    96106    QTCaptureDecompressedVideoOutput    *video_output; 
    97     VOutDelegate                        *vout_delegate; 
     107    QTDelegate                          *qt_delegate; 
    98108}; 
    99109 
     
    325335} 
    326336 
    327 @implementation VOutDelegate 
     337static qt_fmt_info* get_qt_format_info(pjmedia_format_id id) 
     338{ 
     339    unsigned i; 
     340     
     341    for (i = 0; i < PJ_ARRAY_SIZE(qt_fmts); i++) { 
     342        if (qt_fmts[i].pjmedia_format == id) 
     343            return &qt_fmts[i]; 
     344    } 
     345     
     346    return NULL; 
     347} 
     348 
     349@implementation QTDelegate 
    328350- (void)captureOutput:(QTCaptureOutput *)captureOutput 
    329351                      didOutputVideoFrame:(CVImageBufferRef)videoFrame 
     
    334356    pjmedia_frame frame; 
    335357 
    336     if (stream->cap_thread_initialized == 0 || !pj_thread_is_registered()) 
     358    if (!strm->is_running) { 
     359        strm->cap_exited = PJ_TRUE; 
     360        return; 
     361    } 
     362     
     363    if (strm->cap_thread_initialized == 0 || !pj_thread_is_registered()) 
    337364    { 
    338         pj_thread_register("qt_cap", stream->cap_thread_desc, 
    339                            &stream->cap_thread); 
    340         stream->cap_thread_initialized = 1; 
     365        pj_thread_register("qt_cap", strm->cap_thread_desc, 
     366                           &strm->cap_thread); 
     367        strm->cap_thread_initialized = 1; 
    341368        PJ_LOG(5,(THIS_FILE, "Capture thread started")); 
    342369    } 
     
    349376    frame.size = size; 
    350377    frame.bit_info = 0; 
    351     frame.timestamp.u64 = stream->cap_frame_ts.u64; 
    352      
    353     if (stream->vid_cb.capture_cb) 
    354         (*stream->vid_cb.capture_cb)(&stream->base, stream->user_data, 
    355                                      &frame); 
    356      
    357     stream->cap_frame_ts.u64 += stream->cap_ts_inc; 
    358 } 
     378    frame.timestamp.u64 = strm->cap_frame_ts.u64; 
     379     
     380    if (strm->vid_cb.capture_cb) 
     381        (*strm->vid_cb.capture_cb)(&strm->base, strm->user_data, &frame); 
     382     
     383    strm->cap_frame_ts.u64 += strm->cap_ts_inc; 
     384} 
     385 
     386- (void)run_func 
     387{ 
     388    (*func)(strm); 
     389} 
     390 
    359391@end 
    360392 
    361 static qt_fmt_info* get_qt_format_info(pjmedia_format_id id) 
    362 { 
    363     unsigned i; 
    364      
    365     for (i = 0; i < PJ_ARRAY_SIZE(qt_fmts); i++) { 
    366         if (qt_fmts[i].pjmedia_format == id) 
    367             return &qt_fmts[i]; 
    368     } 
    369      
    370     return NULL; 
     393static void init_qt(struct qt_stream *strm) 
     394{ 
     395    const pjmedia_video_format_detail *vfd; 
     396    qt_fmt_info *qfi = get_qt_format_info(strm->param.fmt.id); 
     397    BOOL success = NO; 
     398    NSError *error; 
     399     
     400    if (!qfi) { 
     401        strm->status = PJMEDIA_EVID_BADFORMAT; 
     402        return; 
     403    } 
     404     
     405    strm->cap_session = [[QTCaptureSession alloc] init]; 
     406    if (!strm->cap_session) { 
     407        strm->status = PJ_ENOMEM; 
     408        return; 
     409    } 
     410     
     411    /* Open video device */ 
     412    QTCaptureDevice *videoDevice =  
     413        [QTCaptureDevice deviceWithUniqueID: 
     414                         [NSString stringWithCString: 
     415                                   strm->qf->dev_info[strm->param.cap_id].dev_id 
     416                                   encoding: 
     417                                   [NSString defaultCStringEncoding]]]; 
     418    if (!videoDevice || ![videoDevice open:&error]) { 
     419        strm->status = PJMEDIA_EVID_SYSERR; 
     420        return; 
     421    } 
     422     
     423    /* Add the video device to the session as a device input */  
     424    strm->dev_input = [[QTCaptureDeviceInput alloc]  
     425                       initWithDevice:videoDevice]; 
     426    success = [strm->cap_session addInput:strm->dev_input error:&error]; 
     427    if (!success) { 
     428        strm->status = PJMEDIA_EVID_SYSERR; 
     429        return; 
     430    } 
     431     
     432    strm->video_output = [[QTCaptureDecompressedVideoOutput alloc] init]; 
     433    success = [strm->cap_session addOutput:strm->video_output 
     434                                 error:&error]; 
     435    if (!success) { 
     436        strm->status = PJMEDIA_EVID_SYSERR; 
     437        return; 
     438    } 
     439     
     440    vfd = pjmedia_format_get_video_format_detail(&strm->param.fmt, 
     441                                                 PJ_TRUE); 
     442    [strm->video_output setPixelBufferAttributes: 
     443                        [NSDictionary dictionaryWithObjectsAndKeys: 
     444                                      [NSNumber numberWithInt:qfi->qt_format], 
     445                                      kCVPixelBufferPixelFormatTypeKey, 
     446                                      [NSNumber numberWithInt:vfd->size.w], 
     447                                      kCVPixelBufferWidthKey, 
     448                                      [NSNumber numberWithInt:vfd->size.h], 
     449                                      kCVPixelBufferHeightKey, nil]]; 
     450     
     451    pj_assert(vfd->fps.num); 
     452    strm->cap_ts_inc = PJMEDIA_SPF2(strm->param.clock_rate, &vfd->fps, 1); 
     453     
     454    if ([strm->video_output 
     455         respondsToSelector:@selector(setMinimumVideoFrameInterval)]) 
     456    { 
     457        [strm->video_output setMinimumVideoFrameInterval: 
     458                            (1.0f * vfd->fps.denum / (double)vfd->fps.num)]; 
     459    } 
     460     
     461    strm->qt_delegate = [[QTDelegate alloc]init]; 
     462    strm->qt_delegate->strm = strm; 
     463    [strm->video_output setDelegate:strm->qt_delegate]; 
     464}     
     465 
     466static void run_func_on_main_thread(struct qt_stream *strm, func_ptr func) 
     467{ 
     468    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 
     469    QTDelegate *delg = [[QTDelegate alloc] init]; 
     470     
     471    delg->strm = strm; 
     472    delg->func = func; 
     473    [delg performSelectorOnMainThread:@selector(run_func) 
     474                           withObject:nil waitUntilDone:YES]; 
     475     
     476    CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, false); 
     477 
     478    [delg release]; 
     479    [pool release];     
    371480} 
    372481 
     
    384493    const pjmedia_video_format_info *vfi; 
    385494    pj_status_t status = PJ_SUCCESS; 
    386     BOOL success = NO; 
    387     NSError *error;     
    388495 
    389496    PJ_ASSERT_RETURN(f && param && p_vid_strm, PJ_EINVAL); 
     
    406513    pj_memcpy(&strm->vid_cb, cb, sizeof(*cb)); 
    407514    strm->user_data = user_data; 
    408     strm->apool = [[NSAutoreleasePool alloc]init]; 
    409     pjmedia_event_publisher_init(&strm->base.epub, PJMEDIA_SIG_VID_DEV_COLORBAR); 
     515    strm->qf = qf; 
     516    pjmedia_event_publisher_init(&strm->base.epub, PJMEDIA_SIG_VID_DEV_QT); 
    410517 
    411518    /* Create capture stream here */ 
    412     if (param->dir & PJMEDIA_DIR_CAPTURE) { 
    413         const pjmedia_video_format_detail *vfd; 
    414         qt_fmt_info *qfi = get_qt_format_info(param->fmt.id); 
    415          
    416         if (!qfi) { 
    417             status = PJMEDIA_EVID_BADFORMAT; 
    418             goto on_error; 
    419         } 
    420  
    421         strm->cap_session = [[QTCaptureSession alloc] init]; 
    422         if (!strm->cap_session) { 
    423             status = PJ_ENOMEM; 
    424             goto on_error; 
    425         } 
    426          
    427         /* Open video device */ 
    428         QTCaptureDevice *videoDevice =  
    429             [QTCaptureDevice deviceWithUniqueID: 
    430                              [NSString stringWithCString: 
    431                                        qf->dev_info[param->cap_id].dev_id 
    432                                        encoding: 
    433                                        [NSString defaultCStringEncoding]]]; 
    434         if (!videoDevice || ![videoDevice open:&error]) { 
    435             status = PJMEDIA_EVID_SYSERR; 
    436             goto on_error; 
    437         } 
    438          
    439         /* Add the video device to the session as a device input */      
    440         strm->dev_input = [[QTCaptureDeviceInput alloc]  
    441                            initWithDevice:videoDevice]; 
    442         success = [strm->cap_session addInput:strm->dev_input error:&error]; 
    443         if (!success) { 
    444             status = PJMEDIA_EVID_SYSERR; 
    445             goto on_error; 
    446         } 
    447          
    448         strm->video_output = [[QTCaptureDecompressedVideoOutput alloc] init]; 
    449         success = [strm->cap_session addOutput:strm->video_output 
    450                                      error:&error]; 
    451         if (!success) { 
    452             status = PJMEDIA_EVID_SYSERR; 
    453             goto on_error; 
    454         } 
    455          
    456         vfd = pjmedia_format_get_video_format_detail(&strm->param.fmt, 
    457                                                      PJ_TRUE); 
    458         [strm->video_output setPixelBufferAttributes: 
    459                             [NSDictionary dictionaryWithObjectsAndKeys: 
    460                                           [NSNumber numberWithInt: 
    461                                                     qfi->qt_format], 
    462                                           kCVPixelBufferPixelFormatTypeKey, 
    463                                           [NSNumber numberWithInt: 
    464                                                     vfd->size.w], 
    465                                           kCVPixelBufferWidthKey, 
    466                                           [NSNumber numberWithInt: 
    467                                                     vfd->size.h], 
    468                                           kCVPixelBufferHeightKey, nil]]; 
    469  
    470         pj_assert(vfd->fps.num); 
    471         strm->cap_ts_inc = PJMEDIA_SPF2(strm->param.clock_rate, &vfd->fps, 1); 
    472          
    473         if ([strm->video_output 
    474              respondsToSelector:@selector(setMinimumVideoFrameInterval)]) 
    475         { 
    476             [strm->video_output setMinimumVideoFrameInterval: 
    477                                 (1.0f * vfd->fps.denum / 
    478                                  (double)vfd->fps.num)]; 
    479         } 
    480          
    481         strm->vout_delegate = [[VOutDelegate alloc]init]; 
    482         strm->vout_delegate->stream = strm; 
    483         [strm->video_output setDelegate:strm->vout_delegate]; 
     519    if (param->dir & PJMEDIA_DIR_CAPTURE) {         
     520        strm->status = PJ_SUCCESS; 
     521        run_func_on_main_thread(strm, init_qt); 
     522        if ((status = strm->status) != PJ_SUCCESS) 
     523            goto on_error; 
    484524    } 
    485525     
     
    562602} 
    563603 
     604static void start_qt(struct qt_stream *strm) 
     605{ 
     606    [strm->cap_session startRunning]; 
     607} 
     608 
     609static void stop_qt(struct qt_stream *strm) 
     610{ 
     611    [strm->cap_session stopRunning]; 
     612} 
     613 
    564614/* API: Start stream. */ 
    565615static pj_status_t qt_stream_start(pjmedia_vid_dev_stream *strm) 
     
    572622 
    573623    if (stream->cap_session) { 
    574         [stream->cap_session startRunning]; 
     624        run_func_on_main_thread(stream, start_qt); 
    575625     
    576626        if (![stream->cap_session isRunning]) 
    577             return PJ_EUNKNOWN; 
    578          
    579         CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, false); 
     627            return PJMEDIA_EVID_NOTREADY; 
     628         
     629        stream->is_running = PJ_TRUE; 
    580630    } 
    581631 
     
    592642    PJ_LOG(4, (THIS_FILE, "Stopping qt video stream")); 
    593643 
    594     if (stream->cap_session && [stream->cap_session isRunning]) 
    595         [stream->cap_session stopRunning]; 
    596      
    597     CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, false); 
    598      
    599     return PJ_SUCCESS; 
    600 } 
    601  
     644    if (stream->cap_session && [stream->cap_session isRunning]) { 
     645        int i; 
     646         
     647        stream->cap_exited = PJ_FALSE; 
     648        run_func_on_main_thread(stream, stop_qt); 
     649         
     650        stream->is_running = PJ_FALSE; 
     651        for (i = 50; i >= 0 && !stream->cap_exited; i--) { 
     652            pj_thread_sleep(10); 
     653        } 
     654    } 
     655     
     656    return PJ_SUCCESS; 
     657} 
     658 
     659static void destroy_qt(struct qt_stream *strm) 
     660{ 
     661    if (strm->dev_input && [[strm->dev_input device] isOpen]) 
     662        [[strm->dev_input device] close]; 
     663     
     664    if (strm->cap_session) { 
     665        [strm->cap_session release]; 
     666        strm->cap_session = NULL; 
     667    } 
     668    if (strm->dev_input) { 
     669        [strm->dev_input release]; 
     670        strm->dev_input = NULL; 
     671    } 
     672    if (strm->qt_delegate) { 
     673        [strm->qt_delegate release]; 
     674        strm->qt_delegate = NULL; 
     675    } 
     676    if (strm->video_output) { 
     677        [strm->video_output release]; 
     678        strm->video_output = NULL; 
     679    } 
     680} 
    602681 
    603682/* API: Destroy stream. */ 
     
    609688 
    610689    qt_stream_stop(strm); 
    611      
    612     if (stream->dev_input && [[stream->dev_input device] isOpen]) 
    613         [[stream->dev_input device] close]; 
    614      
    615     if (stream->cap_session) { 
    616         [stream->cap_session release]; 
    617         stream->cap_session = NULL; 
    618     } 
    619     if (stream->dev_input) { 
    620         [stream->dev_input release]; 
    621         stream->dev_input = NULL; 
    622     } 
    623     if (stream->vout_delegate) { 
    624         [stream->vout_delegate release]; 
    625         stream->vout_delegate = NULL; 
    626     } 
    627     if (stream->video_output) { 
    628         [stream->video_output release]; 
    629         stream->video_output = NULL; 
    630     } 
    631  
    632 //    [stream->apool release]; 
     690 
     691    run_func_on_main_thread(stream, destroy_qt); 
     692     
    633693    pj_pool_release(stream->pool); 
    634694 
Note: See TracChangeset for help on using the changeset viewer.