反色實現(xiàn)過程
一、 實現(xiàn)過程
1、 獲取硬件設備實時返回的圖片
- 通過獲取的圖片轉(zhuǎn)換成視頻顯示贤徒。
- 視頻幀率硬件返回是25幀 硬件的分辯率為 192 * 256 默認的。通過返回拿到每一幀YUV圖片數(shù)據(jù) 然后轉(zhuǎn)換成為RGBA 格式的圖片胃惜。
重點泞莉,需要理解YUV和RGBA的區(qū)別哪雕,才能正確轉(zhuǎn)換船殉。
(1)yuv是一種圖片儲存格式,跟RGB格式類似斯嚎。yuv中利虫,y表示亮度,單獨只有y數(shù)據(jù)就可以形成一張圖片堡僻,只不過這張圖片是灰色的糠惫。u和v表示色差(u和v也被稱為:Cb-藍色差,Cr-紅色差)钉疫,
- 為什么要yuv硼讽?
有一定歷史原因,最早的電視信號牲阁,為了兼容黑白電視固阁,采用的就是yuv格式。
一張yuv的圖像城菊,去掉uv备燃,只保留y,這張圖片就是黑白的凌唬。
而且yuv可以通過拋棄色差來進行帶寬優(yōu)化并齐。
比如yuv420格式圖像相比RGB來說,要節(jié)省一半的字節(jié)大小,拋棄相鄰的色差對于人眼來說况褪,差別不大撕贞。
一張yuv格式的圖像,占用字節(jié)數(shù)為 (width * height + (width * height) / 4 + (width * height) /4) = (width * height) * 3 / 2
一張RGB格式的圖像窝剖,占用字節(jié)數(shù)為(width * height) * 3
有興趣 可以了解一下 YU V存儲方式和格式麻掸、采樣方式、數(shù)據(jù)量計算赐纱、YUV裁剪
- RGB 三個字?分別代表了 紅(Red)脊奋、綠(Green)、藍(Blue)疙描,這三種顏?稱為 三原?诚隙,將它們以不同的?例相加,可以產(chǎn)?多種多樣的顏?起胰。
?張1280 * 720 ??的圖?久又,就代表著它有1280 * 720 個像素點。其中每?個像素點的顏?顯示都采?RGB 編碼?法效五,將RGB 分別取不同的值地消,就會展示不同的顏?。
RGB 轉(zhuǎn)YUV
RGB 到Y(jié)UV 的轉(zhuǎn)換畏妖,就是將圖像所有像素點的R脉执、G、B 分量轉(zhuǎn)換到Y(jié)戒劫、U半夷、V 分量。
Y = 0.299 * R + 0.587 * G + 0.114 * B
U = -0.147 * R - 0.289 * G + 0.436 * B
V = 0.615 * R - 0.515 * G - 0.100 * B
R = Y + 1.14 * V
G = Y - 0.39 * U - 0.58 * V
B = Y + 2.03 * U
1迅细、常規(guī)轉(zhuǎn)換標準:
2巫橄、BT.601 標準:(SD TV)
3、BT.709 標準:(HD TV)
YUV轉(zhuǎn)RGB
轉(zhuǎn)換有幾個標準
1茵典、常規(guī)轉(zhuǎn)換標準:
2湘换、BT.601 標準:(SD TV)
3、BT.709 標準:(HD TV)
2统阿、通過轉(zhuǎn)換成RGBA后 的同時 根據(jù)條件 改變指定的像素色值彩倚。得到RGBA相應的圖片數(shù)據(jù),在渲染顯示出來砂吞。
實時錄制技術處理
- 說一下過程
1署恍、拿到每一幀圖片數(shù)據(jù)后,需要轉(zhuǎn)換成視頻流數(shù)據(jù)
- (CVPixelBufferRef)pixelBufferFromCGImage:(CGImageRef)image size:(CGSize)size {
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES],kCVPixelBufferCGImageCompatibilityKey,
[NSNumber numberWithBool:YES],kCVPixelBufferCGBitmapContextCompatibilityKey,nil];
CVPixelBufferRef pxbuffer = NULL;
CVReturn status = CVPixelBufferCreate(kCFAllocatorDefault,size.width,size.height,kCVPixelFormatType_32ARGB,(__bridge CFDictionaryRef) options,&pxbuffer);
NSParameterAssert(status == kCVReturnSuccess && pxbuffer != NULL);
CVPixelBufferLockBaseAddress(pxbuffer,0);
void *pxdata = CVPixelBufferGetBaseAddress(pxbuffer);
NSParameterAssert(pxdata !=NULL);
CGColorSpaceRef rgbColorSpace=CGColorSpaceCreateDeviceRGB();
// 當你調(diào)用這個函數(shù)的時候蜻直,Quartz創(chuàng)建一個位圖繪制環(huán)境盯质,也就是位圖上下文袁串。當你向上下文中繪制信息時,Quartz把你要繪制的信息作為位圖數(shù)據(jù)繪制到指定的內(nèi)存塊呼巷。一個新的位圖上下文的像素格式由三個參數(shù)決定:每個組件的位數(shù)囱修,顏色空間,alpha選項
CGContextRef context = CGBitmapContextCreate(pxdata,size.width,size.height,8,4*size.width,rgbColorSpace,kCGImageAlphaPremultipliedFirst);
NSParameterAssert(context);
CGContextDrawImage(context,CGRectMake(0,0,CGImageGetWidth(image),CGImageGetHeight(image)), image);
// 釋放色彩空間
CGColorSpaceRelease(rgbColorSpace);
// 釋放context
CGContextRelease(context);
// 解鎖pixel buffer
CVPixelBufferUnlockBaseAddress(pxbuffer,0);
return pxbuffer;
}
2王悍、首先創(chuàng)建好一個視頻文件破镰,設置好視頻的 分辯率,文件格式压储、幀率鲜漩、文件大小
重點:
//mp4的格式設置 編碼格式 寬度 高度
NSDictionary *videoSettings = [NSDictionary dictionaryWithObjectsAndKeys:AVVideoCodecTypeH264, AVVideoCodecKey,
[NSNumber numberWithInt:size.width], AVVideoWidthKey,
[NSNumber numberWithInt:size.height], AVVideoHeightKey, nil];
AVAssetWriterInput *writerInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:videoSettings];
NSDictionary *sourcePixelBufferAttributesDictionary = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:kCVPixelFormatType_32ARGB],kCVPixelBufferPixelFormatTypeKey,nil];
// AVAssetWriterInputPixelBufferAdaptor提供CVPixelBufferPool實例,
// 可以使用分配像素緩沖區(qū)寫入輸出文件。使用提供的像素為緩沖池分配通常
// 是更有效的比添加像素緩沖區(qū)分配使用一個單獨的池
AVAssetWriterInputPixelBufferAdaptor *adaptor = [AVAssetWriterInputPixelBufferAdaptor assetWriterInputPixelBufferAdaptorWithAssetWriterInput:writerInput sourcePixelBufferAttributes:sourcePixelBufferAttributesDictionary];
NSParameterAssert(writerInput);
NSParameterAssert([videoWriter canAddInput:writerInput]);
if([videoWriter canAddInput:writerInput]){
NSLog(@"11111");
}else{
NSLog(@"22222");
}
[videoWriter addInput:writerInput];
[videoWriter startWriting];
[videoWriter startSessionAtSourceTime:kCMTimeZero];
2集惋、就是一幀一幀 往視頻文件中添加幀數(shù)據(jù)了
dispatch_queue_t dispatchQueue = dispatch_queue_create("mediaInputQueue", NULL);
int __block frame = 0;
__weak typeof(self)weakSelf = self;
//開始寫視頻幀
[writerInput requestMediaDataWhenReadyOnQueue:dispatchQueue usingBlock:^{
while ([writerInput isReadyForMoreMediaData]) {
if (_end) { //結(jié)束標記
[writerInput markAsFinished];
if (videoWriter.status == AVAssetWriterStatusWriting) {
NSCondition *cond = [[NSCondition alloc]init];
[videoWriter finishWritingWithCompletionHandler:^{
[cond lock];
[cond signal];
[cond unlock];
}];
[cond wait];
[cond unlock];
if (weakSelf.videoUrl) {
weakSelf.videoUrl(weakSelf.theVideoPath);
}//保存視頻方法
}
break;
}
dispatch_semaphore_wait(_seam, DISPATCH_TIME_FOREVER);
if (_imageBuffer) {
//寫入視頻幀數(shù)據(jù)
if (![adaptor appendPixelBuffer:_imageBuffer withPresentationTime:CMTimeMake(frame, 25)]) {
NSLog(@"success視頻數(shù)據(jù)寫入失敗");
}else{
NSLog(@"success視頻數(shù)據(jù)寫入成功");
frame++;
}
NSLog(@"--------->寫入數(shù)據(jù)");
//釋放buffer
CVPixelBufferRelease(_imageBuffer);
CVPixelBufferRelease(_imgBuffer);
_imgBuffer = NULL;
_imageBuffer = NULL;
}
}
}];
寫放幀數(shù)據(jù) 必須保證一幀一幀 寫入視頻文件中去孕似,所以我這里使用了加鎖 和信號量來進行控制
最重要的是 分辯率 和 碼率 的設置。必須要設置合適大小 不然對視頻效果有很大影響
分辨率是以橫向和縱向的像素數(shù)量來衡量的刮刑,表示平面圖像的精細程度喉祭。視頻精細程度并不只取決于視頻分辨率,還取決于屏幕分辨率雷绢。
碼率是數(shù)據(jù)傳輸時單位時間傳送的數(shù)據(jù)位數(shù)泛烙,單位千位每秒,通俗理解為取樣率翘紊,單位時間內(nèi)取樣率越大蔽氨,精度就越高,處理出來的文件就越接近原始 霞溪,一般計算:碼率(kbps)= 文件大蟹踔汀(kb)/ 時長(s)
下菜樣:當 1080P 的視頻在 720P 屏幕上播放時中捆,需要將圖像縮小鸯匹,縮小操作也叫下采樣。
“下采樣”的定義為:對于一個樣值序列泄伪,間隔幾個樣值取樣一次殴蓬,得到新序列。
對于一幅分辨率為 MxN 的圖像蟋滴,對其進行 s 倍下采樣染厅,即得到 (M/s)x(N/s) 分辨率的圖像(s 應為 M、N 的公約數(shù))津函,就是把原始圖像 sxs 窗口內(nèi)的圖像變成一個像素肖粮,這個像素點的值就是窗口內(nèi)所有像素的均值。
最佳體驗為屏幕與視頻分辨率相同且全屏播放尔苦,視頻分辨率過高的話屏幕沒有能力去呈現(xiàn)涩馆,視頻分辨率過低的話無法發(fā)揮屏幕的能力行施。
上采樣:當 720P 的視頻在 1080P 屏幕上播放時,需要將圖像放大魂那,放大操作也叫上采樣蛾号。
“上采樣”幾乎都是采用內(nèi)插值方法,即在原有圖像的像素點之間采用合適的插值算法插入新的元素涯雅,所以圖像放大也稱為圖像插值鲜结。
常見插值算法技術原理:
1)鄰插值算法:將四個像素(放大一倍)用原圖一個像素的顏色填充,較簡單易實現(xiàn)活逆,早期的時候應用比較普遍精刷,但會產(chǎn)生明顯的鋸齒邊緣和馬賽克現(xiàn)象;
2)雙線性插值法:是對鄰插值法的一種改進蔗候,先對兩水平方向進行一階線性插值贬养,再在垂直方向上進行一階線性插值。能有效地彌補鄰插值算法的不足琴庵,但還存在鋸齒現(xiàn)象并會導致一些不期望的細節(jié)柔化误算;
3)雙三次插值法:是對雙線性插值法的改進,它不僅考慮到周圍四個直接相鄰像素點灰度值的影響迷殿,還考慮到它們灰度值變化率的影響儿礼,使插值生成的像素灰度值延續(xù)原圖像灰度變化的連續(xù)性,從而使放大圖像濃淡變化自然平滑
視頻編碼
通過特定的壓縮技術庆寺,將某個視頻格式的文件轉(zhuǎn)換成另一種視頻格式
如:H264 :它是一種面向塊蚊夫,基于運動補償?shù)囊曨l編碼標準
1、可以在低碼率情況下提供高質(zhì)量的視頻圖像懦尝,相比 H.263 可節(jié)省 50% 的碼率
2知纷、H.264 可以根據(jù)不同的環(huán)境使用不同的傳輸和播放速率,并且提供了豐富的錯誤處理工具陵霉,可以很好的控制或消除丟包和誤碼琅轧。
3、H.264 性能的改進是以增加復雜性為代價而獲得的踊挠,H.264 編碼的計算復雜度大約相當于 H.263 的 3 倍乍桂,解碼復雜度大約相當于 H.263 的 2 倍。
H.264 協(xié)議中定義了三種幀效床,分別為 I 幀睹酌、P 幀以及 B 幀:
(1)I 幀:I幀即幀內(nèi)編碼幀、關鍵幀剩檀,可以理解為一幀畫面的完整保留憋沿,解碼時只需要本幀數(shù)據(jù)就可以完成,不需要參考其他畫面沪猴,數(shù)據(jù)量比較大辐啄;
(2)P 幀:P幀即前向預測編碼幀甥绿,記錄當前幀跟上一關鍵幀(或P幀)的差別,解碼時依賴之前緩存的畫面则披,疊加上本幀定義的差別共缕,才能生成最終畫面,數(shù)據(jù)量較 I 幀小很多士复;
(3)B 幀:B幀即雙向預測編碼幀图谷,記錄當前幀跟前后幀的差別,解碼時依賴前面的I幀(或P幀)和后面的P幀阱洪,數(shù)據(jù)量比I幀和P幀小很多便贵。
數(shù)據(jù)壓縮比大約為:I幀:P幀:B幀 = 7:20:50,可見 P 幀和 B 幀極大的節(jié)省了數(shù)據(jù)量冗荸,節(jié)省出來的空間可以用來多保存一些 I 幀承璃,以實現(xiàn)在相同碼率下,提供更好的畫質(zhì)蚌本。
音視頻直播 主要就是以下幾個步驟
音頻
音頻處理我們首要需要知道的參數(shù):
1盔粹、音調(diào):泛指聲音的頻率信息,人耳的主觀感受為聲音的低沉(低音)或者尖銳(高音)程癌。
2舷嗡、響度:聲音的強弱
3、采樣率:聲音信息在由模擬信號轉(zhuǎn)化為數(shù)字信號過程中的精確程度嵌莉,采樣率越高进萄,聲音信息保留的越多。
4锐峭、采樣精度:聲音信息在由模擬信號轉(zhuǎn)化為數(shù)字信號過程中中鼠,表示每一個采樣點所需要的字節(jié)數(shù),一般為16bit(雙字節(jié))表示一個采樣點沿癞。
5援雇、聲道數(shù):相關的幾路聲音數(shù)量,常見的如單聲道抛寝、雙聲道熊杨、5.1聲道
6曙旭、音頻幀長:音頻處理或者壓縮所操作的一段音頻信息盗舰,常見的是10ms,20ms桂躏,30ms钻趋。
音頻常見的幾個問題處理
1、噪聲抑制:手機等設備采集的原始聲音往往包含了背景噪聲剂习,影響聽眾的主觀體驗蛮位,降低音頻壓縮效率较沪,可以適當解決這樣的問題。
2失仁、回聲消除:在視頻或者音頻通話過程中尸曼,本地的聲音傳輸?shù)綄Χ瞬シ胖螅曇魰粚Χ说柠溈孙L采集萄焦,混合著對端人聲一起傳輸?shù)奖镜夭シ趴亟危@樣本地播放的聲音包含了本地原來采集的聲音,造成主觀感覺聽到了自己的回聲拂封。
3茬射、自動增益控制:手機等設備采集的音頻數(shù)據(jù)往往有時候響度偏高,有時候響度偏低冒签,造成聲音忽大忽小在抛,影響聽眾的主觀感受。自動增益控制算法根據(jù)預先配置的參數(shù)對輸入聲音進行正向/負向調(diào)節(jié)萧恕,使得輸出的聲音適宜人耳的主觀感受刚梭。
4:靜音檢測:靜音檢測的基本原理:計算音頻的功率譜密度,如果功率譜密度小于閾值則認為是靜音票唆,否則認為是聲音望浩。靜音檢測廣泛應用于音頻編碼、AGC惰说、AECM等磨德。
5:舒適噪聲產(chǎn)生:舒適噪聲產(chǎn)生的基本原理:根據(jù)噪聲的功率譜密度,人為構(gòu)造噪聲吆视。廣泛適用于音頻編解碼器典挑。在編碼端計算靜音時的白噪聲功率譜密度,將靜音時段和功率譜密度信息編碼啦吧。在解碼端您觉,根據(jù)時間信息和功率譜密度信息,重建隨機白噪聲授滓。
它的應用場景:完全靜音時琳水,為了創(chuàng)造舒適的通話體驗,在音頻后處理階段添加隨機白噪聲般堆。
一般我比較喜歡使用VideoToolbox 進行視頻數(shù)據(jù)處理
在iOS平臺上對視頻數(shù)據(jù)進行H.264編碼有兩種方式:
軟件編碼:用ffmpeg等開源庫進行編碼在孝,他是用cpu進行相關計算的,效率比較低淮摔,但是比較通用私沮,是跨平臺的。
硬件編碼:用VideoToolbox今天編碼和橙,他是用GPU進行相關計算的仔燕,效率很高造垛。
在熟悉H.264的過程中,為更好的了解H.264晰搀,嘗試用VideoToolbox硬編碼與硬解碼H.264的原始碼流五辽。
今天我們主要來看看使用VideoToolbox硬編碼H.264。
用VideoToolbox硬編碼H.264步驟如下:
1.初始化攝像頭外恕,output設定的時候奔脐,需要設置delegate和輸出隊列。在delegate方法吁讨,處理采集好的圖像髓迎。
2.初始化VideoToolbox,設置各種屬性建丧。
3.獲取每一幀數(shù)并編碼排龄。
4.每一幀數(shù)據(jù)編碼完成后,在回調(diào)方法中判斷是不是關鍵幀翎朱,如果是關鍵幀需要用CMSampleBufferGetFormatDescription獲取CMFormatDescriptionRef橄维,然后用
CMVideoFormatDescriptionGetH264ParameterSetAtIndex取得PPS和SPS;最后把每一幀的所有NALU數(shù)據(jù)前四個字節(jié)變成0x00 00 00 01之后再寫入文件拴曲。
5.循環(huán)步驟3步驟4争舞。
6.調(diào)用VTCompressionSessionCompleteFrames完成編碼,然后銷毀session:VTCompressionSessionInvalidate澈灼,釋放session竞川。
事實上,使用 VideoToolbox 硬編碼的用途大多是推流編碼后的 NAL Unit 而不是寫入到本地一個 H.264 文件// 如果你想保存到本地叁熔,使用 AVAssetWriter 是一個更好的選擇委乌,它內(nèi)部也是會硬編碼的。