首页 > 解决方案 > GStreamer iOS - 返回到相应的 UITabBarController 选项卡时可能出现流式传输和 glimagesink 阻塞问题

问题描述

在连接到 iPhone 8+ 13.5.1 GST Ver: 1.16.1 的 Mac Catalina 10.15.6 上运行 XCode 12.0 beta 6

我已经创建了一个应用程序,它使用 rtsp 视频流作为 GStreamer 管道在动态创建的 UI 的选项卡视图上显示流的功能之一。当切换到流选项卡并第一次启动流时,它会启动,gstreamer 和 ios 很好,流是可见的。在切换到 UI 视图和窗口句柄失焦的另一个选项卡后,我将来自解码器的样本丢弃到管道中的 appsink 元素(下面将详细介绍)。

切换回流式传输选项卡,我恢复流式传输,我可以看出有视频数据进入(如下所述),但没有显示。

整个流有 2 个管道,分别由 appsink 和 appsrc 分隔。我可以告诉视频数据在切换回选项卡后进入,因为我注册的应用程序“新样本”回调被调用。此外,在回调中,使用 gst_app_src_push_sample(...) 将样本推送到 appsrc 元素会返回而不会出错。

这是管道外观的示例:

rtspsrc 名称=rtspsrc01 位置=rtsp://192.168.0.25:7768/流延迟=25 !rtph264depay!h264解析!解码器!视频转换!视频框左=0 右=0 上=0 下=0 !三通名称=t2_01!队列 !视频缩放!glimagesink 名称=thumb_sink01 t2_01。!应用程序名称 = appsink01 同步 = 假

应用程序名称=appsrc01 最大延迟=10 !视频缩放!glimagesink 名称=viewer_sink01 同步=false

名为“thumb_sink01”的 glimagesink 元素是选项卡上显示的流的缩略图视图,“appsink01”转到“new-sample”回调。
第二个管道上的“appsrc01”元素正在从 gst_app_src_push_sample(...) 调用接收样本,并转到同一选项卡上更大的 UIImageView 窗口。

在切换回流选项卡后,我可以看到内存消耗也在增加,因此第二个管道上的元素之一似乎由于某种原因而阻塞。我已经验证了两个管道也都处于 GST_STATE_PLAYING 状态。

我已经尝试了很多其他的事情,例如验证 GStreamer 正在渲染的视图是否有效,甚至在切换回流选项卡并恢复流时这段代码:

    gst_video_overlay_set_window_handle(GST_VIDEO_OVERLAY(self->video_sink), (guintptr) (id)  self->ui_video_view);
    gst_video_overlay_set_window_handle(GST_VIDEO_OVERLAY(self->thumb_sinks[0]), (guintptr) (id)  self->ui_thumb_views[0]);
    gst_video_overlay_prepare_window_handle(GST_VIDEO_OVERLAY(self->thumb_sinks[0]));
    gst_video_overlay_expose(GST_VIDEO_OVERLAY(self->thumb_sinks[0]));
    gst_video_overlay_prepare_window_handle(GST_VIDEO_OVERLAY(self->video_sink));
    gst_video_overlay_expose(GST_VIDEO_OVERLAY(self->video_sink));

我一直假设问题出在 glimagesink 元素中,因为推送样本返回,这向我表明 appsrc 接受了它,并且没有迹象表明缓冲区用完或丢弃样本。我觉得videoscale也不太可能是罪魁祸首,但我以前错了。

也许 glimagesink name=thumb_sink01 元素发生了一些愚蠢的事情。?.? 我还没有真正看过那个。

感谢任何人的任何反馈。

标签: iosgstreamer

解决方案


我对删除 glimagesink 并直接写入窗口句柄的最后评论看起来像是要走的路,而且总体上看起来效果更好。

从“new-sample”回调中接收到的 appsink 示例内存缓冲区中获取原始 RGB 解码帧,并从中创建一个 UIImage 并将 UIImageView.image 设置为 UIImage 作品。

如果对其他人有用,则可以使用一些伪代码示例进行转换(尽管在线提供了大量示例):

// Create this once before passing any image frames.
CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB);
data->img_ctx = CGBitmapContextCreate(img_buff, width, height, 8, width * 4, colorSpace, kCGImageAlphaPremultipliedLast);
CGColorSpaceRelease(colorSpace);


// Use this for converting decoded RGB image frames to UIImage's 
dispatch_async(dispatch_get_main_queue(), ^{
    CGImageRef imgRef = CGBitmapContextCreateImage(data->img_ctx);
    data->the_img = [[UIImage alloc] initWithCGImage: imgRef];
    CGImageRelease(imgRef);
    [data->ui_video_view setMyImage: (UIImage *)data->the_img];
    [data->ui_video_view setNeedsDisplay];
}); 

// Edit: had problems with subclassing between Objective-C & Swift, so had to create this setter function to work around it.
-(void) setMyImage: (UIImage *) img {
    super.image = img;
}

推荐阅读