可以提供一个实时获取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库需要自己添加,你试下
直接把三个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 来转换效率应该更高,可是目前拿不到。