重庆分公司,新征程启航
为企业提供网站建设、域名注册、服务器等服务
MOV格式。
资阳网站建设公司创新互联建站,资阳网站设计制作,有大型网站制作公司丰富经验。已为资阳上1000家提供企业网站建设服务。企业网站搭建\外贸网站制作要多少钱,请找那个售后服务好的资阳做网站的公司定做!
MOV是由Apple公司开发的音频、视频文件格式,同时也是QuickTime影片格式。常用于存储常用数字媒体类型,如音频和视频。MOV格式文件是以轨道的形式组织起来的,一个MOV格式文件结构中可以包含很多轨道。在某些方面它比WMV和RM更优秀,并能被众多的多媒体编辑及视频处理软件所支持。
QuickTime视频文件播放程序,除了播放MP3外,QuickTime还支持MIDI播放。并且可以收听/收网络播放,支持HTTP、RTP和RTSP标准。该软件还支持主要的图像格式,比如:JPEG、BMP、PICT、PNG和GIF。该软件的其他特性还有:支持数字视频文件,包括:MiniDV、DVCPro、DVCam、AVI、AVR、MPEG-1、OpenDML以及MacromediaFlash等。QuickTime用于保存音频和视频信息,现在它被包括AppleMacOS,MicrosoftWindows95/98/NT/2003/XP/VISTA在内的所有主流电脑平台支持。
QuickTime文件格式支持25位彩色,支持领先的集成压缩技术,提供150多种视频效果,并配有提供了200多种MIDI兼容音响和设备的声音装置。它无论是在本地播放还是作为视频流格式在网上传播,都是一种优良的视频编码格式。
基本流程
1.初始化输入设备
2.初始化输出设备
3.创建AVCaptureSession,用来管理视频与数据的捕获
4.创建预览视图
前面介绍了如何通过相机实时获取音视频数据,我们接下来就需要了解获取到的数据到底是什么样的,使用系统提供的接口获取到的音视频数据都保存在CMSampleBufferRef中,这个结构在iOS中表示一帧音频/视频数据,它里面包含了这一帧数据的内容和格式,我们可以把它的内容取出来,提取出/转换成我们想要的数据。
代表视频的CMSampleBufferRef中保存的数据是yuv420格式的视频帧(因为我们在视频输出设置中将输出格式设为:kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange)。
在下面的回调中,可以拿到最终的CMSampleBufferRef数据
视频是由一帧一帧的数据连接而成,而一帧视频数据其实就是一张图片。
yuv是一种图片储存格式,跟RGB格式类似。
RGB格式的图片很好理解,计算机中的大多数图片,都是以RGB格式存储的。
yuv中,y表示亮度,单独只有y数据就可以形成一张图片,只不过这张图片是灰色的。u和v表示色差(u和v也被称为:Cb-蓝色差,Cr-红色差),
为什么要yuv?
有一定历史原因,最早的电视信号,为了兼容黑白电视,采用的就是yuv格式。
一张yuv的图像,去掉uv,只保留y,这张图片就是黑白的。
而且yuv可以通过抛弃色差来进行带宽优化。
比如yuv420格式图像相比RGB来说,要节省一半的字节大小,抛弃相邻的色差对于人眼来说,差别不大。
一张yuv格式的图像,占用字节数为 (width * height + (width * height) / 4 + (width * height) / 4) = (width * height) * 3 / 2
一张RGB格式的图像,占用字节数为(width * height) * 3
在传输上,yuv格式的视频也更灵活(yuv3种数据可分别传输)。
很多视频编码器最初是不支持rgb格式的。但是所有的视频编码器都支持yuv格式。
我们这里使用的就是yuv420格式的视频。
yuv420也包含不同的数据排列格式:I420,NV12,NV21.
其格式分别如下,
I420格式:y,u,v 3个部分分别存储:Y0,Y1...Yn,U0,U1...Un/2,V0,V1...Vn/2
NV12格式:y和uv 2个部分分别存储:Y0,Y1...Yn,U0,V0,U1,V1...Un/2,Vn/2
NV21格式:同NV12,只是U和V的顺序相反。
综合来说,除了存储顺序不同之外,上述格式对于显示来说没有任何区别。
使用哪种视频的格式,取决于初始化相机时设置的视频输出格式。
设置为kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange时,表示输出的视频格式为NV12;
设置为kCVPixelFormatType_420YpCbCr8Planar时,表示使用I420。
设置为kCVPixelFormatType_32RGBA时,表示使用BGRA。
GPUImage设置相机输出数据时,使用的就是NV12.
为了一致,我们这里也选择NV12格式输出视频。
libyuv是Google开源的实现各种YUV与RGB之间相互转换、旋转、缩放的库。它是跨平台的,可在Windows、Linux、Mac、Android等操作系统,x86、x64、arm架构上进行编译运行,支持SSE、AVX、NEON等SIMD指令加速.
导入libyuv库,并设置头文件搜索路径,不然会报错
文章只介绍了使用AVFoundation进行视频采集和使用libyuv进行格式转换,音视频相关的知识还有很多,这里不再做详细介绍了。
视频采集会得到格式为CMSampleBufferRef的视频包,视频推流一般把视频流转换成flv格式
(1)首先将视频流转换成YUV的数据格式
//获取yuv数据
- (NSData*)convertVideoSmapleBufferToYuvData:(CMSampleBufferRef)videoSample {
//通过CMSampleBufferGetImageBuffer方法,获得CVImageBufferRef,里面就包含了YUV420数据的指针
CVImageBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(videoSample);
//锁住格式转换线程,开始转换格式
CVPixelBufferLockBaseAddress(pixelBuffer,0);
//获取图像宽度(像素)
size_t pixelWidth = CVPixelBufferGetWidth(pixelBuffer);
//获取图像高度(像素)
size_t pixelHeight = CVPixelBufferGetHeight(pixelBuffer);
//计算YUV中的Y所占字节数
size_t y_size = pixelWidth * pixelHeight;
//计算YUV中的U和V分别所占的字节数
size_t uv_size = y_size /4;
uint8_t * yuv_frame = aw_alloc(uv_size *2+ y_size);
//获取pixelBuffer中的Y数据
uint8_t * y_frame = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer,0);
memcpy(yuv_frame, y_frame, y_size);
//获取pixelBuffer中的UV数据
uint8_t * uv_frame = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer,1);
memcpy(yuv_frame + y_size, uv_frame, uv_size *2);
//获取到想要的数据,解锁格式转换线程
CVPixelBufferUnlockBaseAddress(pixelBuffer,0);
//yuv格式----nv12格式
NSData * yuvData = [NSData dataWithBytesNoCopy:yuv_frame length:y_size + uv_size *2];
//由于相机偏转,我们需要对的到的视频页面进行旋转
return [self rotateNV12Data:nv12Data];
}
(2)由于相机偏转,我们需要对的到的视频页面进行旋转
- (NSData*)rotateNV12Data:(NSData*)nv12Data {
int degree = 0;
switch(self.videoConfig.orientation) {
case UIInterfaceOrientationLandscapeLeft:
degree = 90;
break;
case UIInterfaceOrientationLandscapeRight:
degree = 270;
break;
default:
//do nothing
break;
}
if(degree !=0) {
uint8_ t * src_nv12_bytes = (uint8_t*)nv12Data.bytes;
uint32_t width = (uint32_t)self.videoConfig.width;
uint32_t height = (uint32_t)self.videoConfig.height;
uint32_t w_x_h = (uint32_t)(self.videoConfig.width*self.videoConfig.height);
uint8_t * rotatedI420Bytes =aw_alloc(nv12Data.length);
NV12ToI420Rotate(src_nv12_bytes, width,
src_nv12_bytes + w_x_h, width,
rotatedI420Bytes, height,
rotatedI420Bytes + w_x_h, height /2,
rotatedI420Bytes + w_x_h + w_x_h /4, height /2,
width, height, (RotationModeEnum)degree);
I420ToNV12(rotatedI420Bytes, height,
rotatedI420Bytes + w_x_h, height /2,
rotatedI420Bytes + w_x_h + w_x_h /4, height /2,
src_nv12_bytes, height, src_nv12_bytes + w_x_h, height,
height, width);
aw_free(rotatedI420Bytes);
}
return nv12Data;
}
(3)将nv12格式的数据合成为flv格式
- (aw_flv_video_tag*)encodeYUVDataToFlvTag:(NSData*)yuvData{
if(!_vEnSession) {
return NULL;
}
OSStatus status = noErr;
//获取视频宽度
size_t pixelWidth = self.videoConfig.pushStreamWidth;
//获取视频高度
size_t pixelHeight = self.videoConfig.pushStreamHeight;
//NV12数据-CVPixelBufferRef中
//硬编码主要调用VTCompressionSessionEncodeFrame函数,此函数处理的是CVPixelBufferRef类型。
CVPixelBufferRef pixelBuf =NULL;
//初始化pixelBuf
CVPixelBufferCreate(NULL, pixelWidth, pixelHeight,kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange,NULL, pixelBuf);
if(CVPixelBufferLockBaseAddress(pixelBuf,0) != kCVReturnSuccess){
NSLog(@"encode video lock base address failed");
return NULL;
}
//将YUV数据填充到CVPixelBufferRef中
size_t y_size = aw_stride(pixelWidth) * pixelHeight;
size_t uv_size = y_size /4;
uint8_t * yuv_frame = (uint8_t*)yuvData.bytes;
//获取y frame
uint8_t * y_frame = CVPixelBufferGetBaseAddressOfPlane(pixelBuf,0);
memcpy(y_frame, yuv_frame, y_size);
//获取uv frame
uint8_t * uv_frame = CVPixelBufferGetBaseAddressOfPlane(pixelBuf,1);
memcpy(uv_frame, yuv_frame + y_size, uv_size *2);
//编码CMSampleBufRef
//获取时间戳,由于视频帧是有顺序的,所以timestamp可以自定义一个累加字段
uint32_t ptsMs = timestamp+1;//self.vFrameCount++ * 1000.f / self.videoConfig.fps;
CMTime pts =CMTimeMake(ptsMs,1000);
//将NV12数据的PixelBuf送到硬编码器中,进行编码。
status = VTCompressionSessionEncodeFrame(_vEnSession, pixelBuf, pts,kCMTimeInvalid,NULL, pixelBuf,NULL);
if(status == noErr) {
dispatch_semaphore_wait(self.vSemaphore,DISPATCH_TIME_FOREVER);
if(_naluData) {
//硬编码成功,_naluData内的数据即为h264视频帧。
//因为是推流,所以需要获取帧长度,转成大端字节序,放到数据的最前面
uint32_t naluLen = (uint32_t)_naluData.length;
//小端转大端。计算机内一般都是小端,而网络和文件中一般都是大端。大端转小端和小端转大端算法一样,就是字节序反转就行了。
uint8_t naluLenArr[4] = {naluLen 240xff, naluLen 160xff, naluLen 80xff, naluLen 0xff};
//数据拼接
NSMutableData * mutableData = [NSMutableData dataWithBytes:naluLenArr length:4];
[mutableData appendData:_naluData];
//h264 - flv tag,合成flvtag之后就可以直接发送到服务端了。
aw_flv_video_tag * video_tag = aw_encoder_create_video_tag((int8_t*)mutableData.bytes, mutableData.length, ptsMs,0,self.isKeyFrame);
//编码完成,释放数据。
_naluData = nil;
_isKeyFrame = NO;
CVPixelBufferUnlockBaseAddress(pixelBuf,0);
CFRelease(pixelBuf);
return video_tag;
}
}else {
NSLog(@"encode video frame error");
}
CVPixelBufferUnlockBaseAddress(pixelBuf,0);
CFRelease(pixelBuf);
return NULL;
}
快进:AVPlayer .rate 1
慢放: 0 AVPlayer .rate 1
快退: AVPlayer .rate 0 (m3u8 不能快退)
MP4:如果快进到了缓存不够的地方:KVC监听 AVPlayerItem .isPlaybackBufferEmpty = yes
快退到头会走通知AVPlayerItemDidPlayToEndTimeNotification
m3u8(静态):快进与MP4格式视频一致,可以10倍 20倍播放。
m3u8(动态):快进到了缓存不够的地方,会走通知AVPlayerItemDidPlayToEndTimeNotification。
备注:使用[AVPlayerItem stepByCount:-24];
将AVPlayerItem 向前或向后移动指定的步数,正数前进,负数后退。 每个步数的大小取决于AVPlayerItem启用的AVPlayerItemTracks对象;
注册监听和通知
比较苹果的ProRes格式是在十多年前开发的,现在支持高达8K的分辨率,对于需要视频编辑的人来说非常实用。 Final Cut Pro经过编码,可高效处理和编辑ProRes内容,并广泛用于专业视频行业中。
iPhone 13 Pro 机型还将首次能够以 ProRes 视频格式进行录制,为专业人士提供更高质量的输出。
苹果手机优点如下:
1、iOS系统
我们知道苹果手机的iOS系统是独有的,只有在苹果手机中才能够体验到这种系统,而这个手机系统是非常流畅的,安卓手机的系统在使用一段时间之后都会有不同程度的卡顿,但是苹果手机的iOS系统依旧非常流畅。
2、应用生态优异
苹果手机对于开发者上传在应用商店的软件有着很严格的审核,像是一些不安全的软件或者是没有质量的软件是不会在应用商店里存在的,对于软件有一个质量上的保障,但是很多的安卓手机并不是这样。
3、iOS系统安全性好
在使用安卓手机的时候,很多软件在打开的时候都会开放很多的运用权限,因为不开的话完全没有办法正常使用,这一点是很容易造成用户信息的泄露,而且在很多的游戏上还有一不小心点到就被扣费。