debugly/ijkplayer

可以提供一个实时获取AVFrame 或者 CVPixelBufferRef 的代理么

Closed this issue · 26 comments

如图,这样我可以获取到播放画面,并做进一步的处理

甚至实时的UIimage 也是可以的

图呢?
你这个需求,当然可以满足。

没有图,写错了,我是说如标题所示,我希望播放器能有个代理函数能 给一个播放的当前帧。

比如在IJKMediaPlayback.h 提供一个代理可以让我获取到当前播放的帧

比如系统的AVPlayerItemVideoOutput 可以获取avplayer 播放的当前帧,我希望ijk也有这个功能

1、创建一个View实现 IJKVideoRenderingProtocol 协议;假设名字叫 MyRenderView
2、渲染这块不用自己去写,仍旧交给 IJK 负责,需要创建一个渲染View: UIView<IJKVideoRenderingProtocol> *render = [IJKInternalRenderView createMetalRenderView];
把 render当作 MyRenderView的属性
3、实现 - (BOOL)displayAttach:(IJKOverlayAttach *)attach; 方法

- (BOOL)displayAttach:(IJKOverlayAttach *)attach{
//你需要的当前画面:attach.videoPicture
[self.render displayAttach:attach];
}

其中 IJKOverlayAttach 里的CVPixelBufferRef videoPicture; 属性就是你想要的当前播放帧,可以做进一步的处理。

4、创建播放器时使用 - (id)initWithMoreContent:(NSURL *)aUrl withOptions:(IJKFFOptions *)options withGLView:(UIView<IJKVideoRenderingProtocol> *)glView; 这个方法将 MyRenderView 传进去

你回复哪去了,有收到邮件,但是打开issue后看不到你的回复

我删掉了,我看到 IJKFFMoviePlayerController 里有一个 UIView* _glView; 我可以设法获得他的视频图片吗???我刚刚创建了一个 IJKVideoRenderingProtocol 的视图,但是运行的时候崩溃了,因为没有context;

_glView 实际上内部自动创建的,除非调用 - (id)initWithMoreContent:(NSURL *)aUrl withOptions:(IJKFFOptions *)options withGLView:(UIView *)glView 方法传进来。
你按照我说的步骤,指定可以的。

context 崩溃解决方法:

- (id)context 
{
    return nil;
}
  • (UIImage*)uiImageFromPixelBuffer:(CVPixelBufferRef)pixelBufferRef {
    if(pixelBufferRef== NULL)
    return nil;
    CVPixelBufferLockBaseAddress(pixelBufferRef, 0);
    CIImage* ciImage = [CIImage imageWithCVPixelBuffer : pixelBufferRef];

    CIContext* context = [CIContext contextWithOptions : @{kCIContextUseSoftwareRenderer : @(YES)}];

    CGRect rect = CGRectMake(0, 0, CVPixelBufferGetWidth(pixelBufferRef), CVPixelBufferGetHeight(pixelBufferRef));

    CGImageRef videoImage = [context createCGImage : ciImage fromRect : rect];
    CVPixelBufferUnlockBaseAddress(pixelBufferRef, 0);
    UIImage* image = [UIImage imageWithCGImage : videoImage];

    CGImageRelease(videoImage);

    return image;

}

我在demo里拖动进度条后 CVPixelBufferLockBaseAddress(pixelBufferRef, 0);报了Thread 1: EXC_BAD_ACCESS (code=1, address=0x8e7b78b50)的错误,但是pixelBufferRef又不是空的

这是野指针错误,你有必要管理好 pixelBufferRef 的内存,在处理前 Retain ,处理完毕 Release。

CVPixelBufferUnlockBaseAddress(pixelBufferRef, 0);
CVPixelBufferRelease(pixelBufferRef);  我这边调用释放的话,ff_play.c里int send = avcodec_send_packet(d->avctx, d->pkt); 就报错了

处理前调用 CVPixelBufferRetain 了吗

  • (UIImage*)uiImageFromPixelBuffer:(CVPixelBufferRef)pixelBufferRef {

    CVPixelBufferRef p = CVPixelBufferRetain(pixelBufferRef);
    if(p== nil)
    return nil;
    CVPixelBufferLockBaseAddress(p, 0);
    CIImage* ciImage = [CIImage imageWithCVPixelBuffer : p];

    CIContext* context = [CIContext contextWithOptions : @{kCIContextUseSoftwareRenderer : @(YES)}];

    CGRect rect = CGRectMake(0, 0, CVPixelBufferGetWidth(p), CVPixelBufferGetHeight(p));

    CGImageRef videoImage = [context createCGImage : ciImage fromRect : rect];
    CVPixelBufferUnlockBaseAddress(p, 0);

    UIImage* image = [UIImage imageWithCGImage : videoImage];

    CGImageRelease(videoImage);

    return image;

}. 如果是这么写的话,不会每次都崩溃,而是偶尔,反正还是有概率出现

我自己retain 概率崩溃,多次拉进度才可能出现,如果是retain 用完后release的话,第一次拉进度条就崩溃了。 不知道该如何了

我用avplayer 得到的CVPixelBufferRef ,不会有崩溃的情况,我觉得是不是ijk播放器输出前,你那边要处理下或者什么

提供个简易demo,我看下

我明天尝试给你一个demo 看看吧,原来的是在你的demo上做的实验

https://github.com/climlove/OPENGLDemo 这demo ijk库需要自己添加,你试下

我这运行时出错了:

image

直接把三个NO 改为NO_EXPOSURE_COMPENSATOR = 0 就可以了

运行起来了,可是你的demo里只是创建了playerView,没有按照我说的去做啊。ijk可以正常播放,你想让我看什么呢?

渲染是我这边渲染的,但是拖动进度条后有时候会崩溃

播放的视频是全景视频,所以我需要自己做渲染,播放器解码的话想使用ijk,但是拖动进度条的时候,有可能会崩溃。就是在处理CVPixelBufferRef的时候

1、当前环境复杂,崩溃不一定是IJK导致的,使用我的demo,改成你的全景视频拖动进度条是否崩溃?
2、将cvpixelbuffer 一通转换到opencv的image效率低,你确定播放时不卡顿?avplayer output跟opencv已经串起来了?

1.一开始就是在你的demo上 修改的,然后发现拖动进度条 会出现偶尔崩溃的情况,具体就在报错就在cvpixelbuffer的使用上面。2.将cvpixelbuffer 转成image 再转为cv:Mat 是目前无奈之举,如果能获取avframe 来转换效率应该更高,可是目前拿不到。