0

对不起,这有点罗嗦,但我想确保我清楚!;-)

我有一个使用 FFMPEG 流式传输 RTSP 的 iOS 应用程序。我使用 NSOperationQueue 对 FFMPEG 进行了多线程处理,因此除了将图像绘制到屏幕之外,它的大部分工作当然都发生在后台线程中。效果很好!...除了 NSOperationQueue 创建的线程永远不会死的事实!

我在类的 init 方法中初始化队列:

self->opQ = [[NSOperationQueue alloc] init];
[self->opQ setMaxConcurrentOperationCount:1];

我使用块向队列添加方法:

[self->opQ addOperationWithBlock:^{
        [self haveConnectedSuccessfullyOperation];
}];

或者

[self->opQ addOperationWithBlock:^{
        if (SOME_CONDITION) {
            [self performSelectorOnMainThread:@selector(DO_SOME_CRAP) withObject:nil waitUntilDone:NO];
        }
    }];

后来,当我需要拆掉RTSP流时,除了告诉FFMPEG关闭外,我调用:

[self->opQ cancelAllOperations];

这确实阻止了线程做任何工作,但从未真正破坏它们。下面,您将看到一个根本不做任何事情的线程的屏幕截图。这是我的线程在多次启动/停止 FFMPEG 后的样子。

坏线程

我似乎记得在 Apple 的文档中读到 NSOperations 和它们运行的​​线程一旦执行完毕就会被销毁,除非另有说明。情况似乎并非如此。

我是否只需要销毁 NSOperationQueue,然后在需要再次启动 FFMPEG 时重新初始化它(我才意识到我没有尝试过这个)?任何人都知道我需要如何杀死这些额外的线程?

谢谢!

4

1 回答 1

1

我通过创建NSBlockOperations 来解决这个问题,这样我就可以监控isCancelled状态,同时也让新NSBlockOperation的 s 的内容更加智能,这样我就简化了将操作添加到队列的例程。

...另外,我犯了一个 NSOperationQueue n00b 错误:我在循环的基础上向队列添加操作,每秒触发高达 30 次(与视频的帧速率匹配)。但是,现在,操作只添加到队列中一次,并且循环行为包含操作中,而不是让循环将操作添加到队列中。

以前,我有这样的东西(伪代码,因为我没有这个项目):

NSTimer *frameRateTimeout = [NSTimer scheduledTimerWithTimeInterval:1/DESIRED_FRAMES_PER_SECOND target:self selector:@selector(ADD_OPERATION_TO_QUEUE_METHOD:) userInfo:nil repeats:YES];

-(void)ADD_OPERATION_TO_QUEUE_METHOD:(NSTimer *)timer {
   [opQ addOperation:displayFrame];
}

效果很好,因为操作系统可以正确管理队列,但效率不高,并且让这些线程永远活着。

现在,它更像是:

-(id)init {
   self = [super init];
   if (self) {
      // alloc/init operation queue
      ...
      // alloc/init 'displayFrame' 
      displayFrame = [NSBlockOperation blockOperationWithBlock:^{
         while (SOME_CONDITION && ![displayFrame isCancelled]) {
            if (playVideo) {
               // DO STUFF 
               [NSThread sleepForTimeInterval:FRAME_RATE];
            } 
            else {  // teardown stream
               // DO STUFF
               break;
            }
         }
      }]; 
   }

   return self;
}

- (void)Some_method_called_after_getting_video_ready_to_play {
   [opQ addOperation:displayFrame];
}

感谢 Jacob Relkin 回复我的帖子。
如果有人需要进一步澄清,请告诉我,一旦我再次掌握该项目,我将发布更好的代码。

于 2013-07-23T13:13:07.427 回答