PKShortVideo README.md

PKShortVideo


CocoaPods
CocoaPods

CocoaPods
CocoaPods

Support
Support

A video library like WeChat short video for iOS.
Related Articles:iOS仿微信小视频功能开发优化记录

sc1
sc1

Features

  • Short video playback in chat interface, the use of GPUImage-based OpenGL ES hardware accelerated playback video
  • Short video can click to enlarge playback, using the AVPlayer
  • Provide a short video capture, to support custom resolution video capture, has a basic style, and provides the basis of switching cameras, recording, playback, re-recording function, the use of AVCaptureSession + AVCaptureVideoDataOutput and AVCaptureAudioDataOutput direct output video

Installation

Import <YYKit/YYKit.h>.

  1. Add pod 'PKShortVideo' to your Podfile.
  2. Run pod install or pod update.
  3. Import "PKShortVideo.h".

Usage

When Video recording, OutputFilePath parameters for the recording after the completion of the output video file path, OutputSize is the output video resolution.

Use default UI interface to record video (PKRecordShortVideoViewController)

Enter the recording interface

//跳转默认录制视频ViewController
PKRecordShortVideoViewController *viewController = [[PKRecordShortVideoViewController alloc] initWithOutputFilePath:path outputSize:CGSizeMake(320, 240) themeColor:[UIColor colorWithRed:0/255.0 green:153/255.0 blue:255/255.0 alpha:1]];
//通过代理回调
viewController.delegate = self;
[self presentViewController:viewController animated:YES completion:nil];

Record complete callback

#pragma mark - PKRecordShortVideoDelegate
//视频拍摄完成输出图片
- (void)didFinishRecordingToOutputFilePath:(NSString *)outputFilePath {
    //自定义的生成小视频聊天对象方法
    [self.demoData addShortVideoMediaMessageWithVideoPath:outputFilePath];
    //JSQMessagesViewController的完成发送滚动到底端方法
    [self finishSendingMessageAnimated:YES];
}

When you use a custom UI to record video (PKShortVideoRecorder)

Creates a recording object

//创建视频录制对象
self.recorder = [[PKShortVideoRecorder alloc] initWithOutputFilePath:self.outputFilePath outputSize:self.outputSize];
//通过代理回调
self.recorder.delegate = self;
//录制时需要获取预览显示的layer,根据情况设置layer属性,显示在自定义的界面上
AVCaptureVideoPreviewLayer *previewLayer = [self.recorder previewLayer];
previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
previewLayer.frame = CGRectMake(0, 44, kScreenWidth, PKPreviewLayerHeight);
[self.view.layer insertSublayer:previewLayer atIndex:0];

Start preview camera work

//开始预览摄像头工作
[self.recorder startRunning];

swap front and back camera

//切换前后摄像头
[self.recorder swapFrontAndBackCameras];

startRecording

//开始录制视频
[self.recorder startRecording];

stopRecording

//停止录制
[self.recorder stopRecording];

Video recorded successful callback

//视频录制结束回调
- (void)recorder:(PKShortVideoRecorder *)recorder didFinishRecordingToOutputFilePath:(NSString *)outputFilePath error:(NSError *)error {
//录制成功返回路径,录制失败返回错误对象
}

When Video playback, OutputFilePath parameters for the recording is completed after the output video file path, previewImage is a video preview.

Chat interface to play (due to different chat framework, here only JSQMessagesViewController to demonstrate)

Chat object creation

- (void)addShortVideoMediaMessageWithVideoPath:(NSString *)videoPath  playType:(PKPlayType)type {
    //PKShortVideoItem为遵循JSQMessagesViewController的规范创建的媒体(非文字)类型
    //previewImage参数为视频的预览图片
    
    switch (type) {
        case PKPlayTypeOpenGL: {
            PKShortVideoItem *videoItem = [[PKShortVideoItem alloc] initWithVideoPath:videoPath previewImage:[UIImage pk_previewImageWithVideoURL:[NSURL fileURLWithPath:videoPath]]];
            //创建message对象
            JSQMessage *videoMessage = [JSQMessage messageWithSenderId:kJSQDemoAvatarIdSquires
                                                           displayName:kJSQDemoAvatarDisplayNameSquires
                                                                 media:videoItem];
            //把创建聊天对象加入聊天数组
            [self.messages addObject:videoMessage];
        }
            break;
            
        case PKPlayTypeAVPlayer: {
            PKShortVideoItem2 *videoItem = [[PKShortVideoItem2 alloc] initWithVideoPath:videoPath previewImage:[UIImage pk_previewImageWithVideoURL:[NSURL fileURLWithPath:videoPath]]];
            //创建message对象
            JSQMessage *videoMessage = [JSQMessage messageWithSenderId:kJSQDemoAvatarIdSquires
                                                           displayName:kJSQDemoAvatarDisplayNameSquires
                                                                 media:videoItem];
            //把创建聊天对象加入聊天数组
            [self.messages addObject:videoMessage];
        }
            break;
    }

}

The chat object is attached to the internal implementation of the media object

You can use the PKChatMessagePlayerView based on OpenGL and PKPlayerView based on AVPlayer, because PKChatMessagePlayerView to achieve the realization of OpenGL by reflecting the current is not stable, it is recommended to use PKPlayerView, using the interface exactly the same.

//当前尺寸
CGSize size = [self mediaViewDisplaySize];
//实例化播放view
self.playerView = [[PKPlayerView alloc] initWithFrame:CGRectMake(0, 0, size.width, size.height) videoPath:self.videoPath previewImage:self.image];

If the demand strategy is very complex, need to determine whether the group or friends, a variety of network conditions, whether to download or automatically play, still need to customize the chat object attached media objects, PKChatMessagePlayerView only in the presence of video playback.

//开始播放小视频
- (void)play {
    [self.playerView play];
}
//结束播放视频
- (void)pause {
    [self.playerView stop];
}

Chat interface control to achieve

For performance reasons, the best in the chat interface to do when the display is played, do not show the time to stop playing.

//将要结束显示时停止播放
- (void)collectionView:(UICollectionView *)collectionView didEndDisplayingCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath {
    JSQMessage *message = self.demoData.messages[indexPath.item];
    if ([message.media isKindOfClass:[PKShortVideoItem class]]) {
        PKShortVideoItem *item = (PKShortVideoItem *)message.media;
        [item pause];
    }
}

//将要显示时播放
- (void)collectionView:(UICollectionView *)collectionView willDisplayCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath {
    JSQMessage *message = self.demoData.messages[indexPath.item];
    if ([message.media isKindOfClass:[PKShortVideoItem class]]) {
        PKShortVideoItem *item = (PKShortVideoItem *)message.media;
        [item play];
    }
}

Click to Full Screen play

//点击消息是跳转播放
- (void)collectionView:(JSQMessagesCollectionView *)collectionView didTapMessageBubbleAtIndexPath:(NSIndexPath *)indexPath {
    JSQMessage *message = self.demoData.messages[indexPath.item];
    //判断媒体消息类型
    if ([message.media isKindOfClass:[PKShortVideoItem class]]) {
        PKShortVideoItem *item = (PKShortVideoItem *)message.media;
        //跳转全屏播放小视频界面
        PKFullScreenPlayerViewController *viewController = [[PKFullScreenPlayerViewController alloc] initWithVideoPath:item.videoPath previewImage:[UIImage pk_previewImageWithVideoURL:[NSURL fileURLWithPath:item.videoPath]]];
        [self presentViewController:viewController animated:NO completion:NULL];
    }
}

Requirements

This library requires iOS 7.0 and Xcode 7.0.

License

PKShortVideo is provided under the MIT license. See LICENSE file for details.

Contact

Weibo: @-湛蓝_

Email: pepsikirk@gmail.com

中文介绍

这是一个类似微信小视频功能的框架。
相关文章介绍:iOS仿微信小视频功能开发优化记录

sc1
sc1

特性

  • 小视频聊天界面播放,使用基于 GPUImage 的 OpenGL ES 硬件加速播放视频
  • 小视频可以点击放大播放,使用了 AVPlayer
  • 提供小视频拍摄,能够支持自定义分辨率视频拍摄,有着基础样式,并提供了基础的切换摄像头、录制、播放、重新录制的功能,使用了 AVCaptureSession + AVCaptureVideoDataOutput和AVCaptureAudioDataOutput直接输出视频

安装

  1. 在 Podfile 中添加 pod 'PKShortVideo'。
  2. 执行 pod install 或 pod update。
  3. 导入 #import "PKShortVideo.h"。

简单用法

视频录制时,OutputFilePath参数为录制完成后输出的视频文件路径,OutputSize是输出视频的分辨率

简单使用自带UI界面时,录制视频(PKRecordShortVideoViewController)

进入录制界面

//跳转默认录制视频ViewController
PKRecordShortVideoViewController *viewController = [[PKRecordShortVideoViewController alloc] initWithOutputFilePath:path outputSize:CGSizeMake(320, 240) themeColor:[UIColor colorWithRed:0/255.0 green:153/255.0 blue:255/255.0 alpha:1]];
//通过代理回调
viewController.delegate = self;
[self presentViewController:viewController animated:YES completion:nil];

录制完成回调

#pragma mark - PKRecordShortVideoDelegate
//视频拍摄完成输出图片
- (void)didFinishRecordingToOutputFilePath:(NSString *)outputFilePath {
    //自定义的生成小视频聊天对象方法
    [self.demoData addShortVideoMediaMessageWithVideoPath:outputFilePath];
    //JSQMessagesViewController的完成发送滚动到底端方法
    [self finishSendingMessageAnimated:YES];
}

自定义UI时录制时,录制视频(PKShortVideoRecorder)

创建录制对象

//创建视频录制对象
self.recorder = [[PKShortVideoRecorder alloc] initWithOutputFilePath:self.outputFilePath outputSize:self.outputSize];
//通过代理回调
self.recorder.delegate = self;
//录制时需要获取预览显示的layer,根据情况设置layer属性,显示在自定义的界面上
AVCaptureVideoPreviewLayer *previewLayer = [self.recorder previewLayer];
previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
previewLayer.frame = CGRectMake(0, 44, kScreenWidth, PKPreviewLayerHeight);
[self.view.layer insertSublayer:previewLayer atIndex:0];

开始预览摄像头工作

//开始预览摄像头工作
[self.recorder startRunning];

切换前后摄像头

//切换前后摄像头
[self.recorder swapFrontAndBackCameras];

开始录制

//开始录制视频
[self.recorder startRecording];

停止录制

//停止录制
[self.recorder stopRecording];

视频录制成功回调

//视频录制结束回调
- (void)recorder:(PKShortVideoRecorder *)recorder didFinishRecordingToOutputFilePath:(NSString *)outputFilePath error:(NSError *)error {
//录制成功返回路径,录制失败返回错误对象
}

视频播放时,OutputFilePath参数为录制完成后输出的视频文件路径,previewImage是视频预览图

聊天界面播放(由于聊天框架不同,这里只用JSQMessagesViewController进行示范)

聊天对象创建

- (void)addShortVideoMediaMessageWithVideoPath:(NSString *)videoPath  playType:(PKPlayType)type {
    //PKShortVideoItem为遵循JSQMessagesViewController的规范创建的媒体(非文字)类型
    //previewImage参数为视频的预览图片
    
    switch (type) {
        case PKPlayTypeOpenGL: {
            PKShortVideoItem *videoItem = [[PKShortVideoItem alloc] initWithVideoPath:videoPath previewImage:[UIImage pk_previewImageWithVideoURL:[NSURL fileURLWithPath:videoPath]]];
            //创建message对象
            JSQMessage *videoMessage = [JSQMessage messageWithSenderId:kJSQDemoAvatarIdSquires
                                                           displayName:kJSQDemoAvatarDisplayNameSquires
                                                                 media:videoItem];
            //把创建聊天对象加入聊天数组
            [self.messages addObject:videoMessage];
        }
            break;
            
        case PKPlayTypeAVPlayer: {
            PKShortVideoItem2 *videoItem = [[PKShortVideoItem2 alloc] initWithVideoPath:videoPath previewImage:[UIImage pk_previewImageWithVideoURL:[NSURL fileURLWithPath:videoPath]]];
            //创建message对象
            JSQMessage *videoMessage = [JSQMessage messageWithSenderId:kJSQDemoAvatarIdSquires
                                                           displayName:kJSQDemoAvatarDisplayNameSquires
                                                                 media:videoItem];
            //把创建聊天对象加入聊天数组
            [self.messages addObject:videoMessage];
        }
            break;
    }

}

聊天对象附属的媒体对象内部实现

可以使用基于 OpenGL 的 PKChatMessagePlayerView 和基于 AVPlayer 的 PKPlayerView ,由于 PKChatMessagePlayerView 实现的 OpenGL 的实现通过反映目前并不稳定,推荐使用 PKPlayerView ,使用接口完全一致。

//当前尺寸
CGSize size = [self mediaViewDisplaySize];
//实例化播放view
self.playerView = [[PKPlayerView alloc] initWithFrame:CGRectMake(0, 0, size.width, size.height) videoPath:self.videoPath previewImage:self.image];

如果需求策略非常复杂,如需判断是群还是好友、各种网络情况下,是否下载或者自动播放,仍然需要自定义聊天对象附属媒体对象,PKChatMessagePlayerView仅可在视频存在情况下播放使用

//开始播放小视频
- (void)play {
    [self.playerView play];
}
//结束播放视频
- (void)pause {
    [self.playerView stop];
}

聊天界面控制实现

出于性能考虑,最好在聊天界面处理做到显示的时候才播放,不显示的时候停止播放

//将要结束显示时停止播放
- (void)collectionView:(UICollectionView *)collectionView didEndDisplayingCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath {
    JSQMessage *message = self.demoData.messages[indexPath.item];
    if ([message.media isKindOfClass:[PKShortVideoItem class]]) {
        PKShortVideoItem *item = (PKShortVideoItem *)message.media;
        [item pause];
    }
}

//将要显示时播放
- (void)collectionView:(UICollectionView *)collectionView willDisplayCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath {
    JSQMessage *message = self.demoData.messages[indexPath.item];
    if ([message.media isKindOfClass:[PKShortVideoItem class]]) {
        PKShortVideoItem *item = (PKShortVideoItem *)message.media;
        [item play];
    }
}

点击全屏播放

//点击消息是跳转播放
- (void)collectionView:(JSQMessagesCollectionView *)collectionView didTapMessageBubbleAtIndexPath:(NSIndexPath *)indexPath {
    JSQMessage *message = self.demoData.messages[indexPath.item];
    //判断媒体消息类型
    if ([message.media isKindOfClass:[PKShortVideoItem class]]) {
        PKShortVideoItem *item = (PKShortVideoItem *)message.media;
        //跳转全屏播放小视频界面
        PKFullScreenPlayerViewController *viewController = [[PKFullScreenPlayerViewController alloc] initWithVideoPath:item.videoPath previewImage:[UIImage pk_previewImageWithVideoURL:[NSURL fileURLWithPath:item.videoPath]]];
        [self presentViewController:viewController animated:NO completion:NULL];
    }
}

要求

本框架最低支持 iOS 7.0Xcode 7.0

许可证

PKShortVideo 使用 MIT 许可证,详情见 LICENSE 文件。

联系方式

Weibo: @-湛蓝_

Email: pepsikirk@gmail.com

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容