[iOS]關於視頻方向的若干問題,ios若干問題

來源:互聯網
上載者:User

[iOS]關於視頻方向的若干問題,ios若干問題
一、MOV/MP4視頻檔案中的Rotation中繼資料iOS上內建相機應用錄製的mov/mp4視頻可能產生一個Rotation中繼資料,表示錄製視頻時網路攝影機旋轉到了多少角度。其值一般為這四個:0、90、180或270。類似於圖片檔案的Exif資訊中的Orientation中繼資料。Rotation中繼資料用於播放器確定渲染視頻的方向,但有的播放器會對其視而不見。稍後會測試幾種常見的播放器/播放控制項對Rotation中繼資料的支援。

註:實際上視頻檔案的Rotation中繼資料並不是儲存的角度值,不過如果只關心角度問題而不是映像展開之類的,可以這樣簡單理解。關於如何擷取Rotation中繼資料角度值,有興趣的可以參看vlc的源碼。
 下面用MediaInfo看看用iPhone相機應用使用後置網路攝影機錄製的兩個視頻,觀察其Rotation中繼資料。請留意檔案名稱分別為IMG_1427.MOV和IMG_1428.MOV,後文也會用這兩個檔案做對比。1、使用後置網路攝影機在Portrait(豎屏,Home鍵在下邊)模式時錄製的視頻,其Rotation值為90。(圖一:Rotation值為90) 2、使用後置網路攝影機在LandscapeRigth(橫屏,Home鍵在右邊)模式時錄製的視頻,則無Rotation中繼資料,或者說Rotation值為0。(圖二:無Rotation值或者說Rotation值為0)  關於Rotation的0、90、180和270這四個角度值可以這樣理解:LandscapeRigth為0度;以Home鍵或網路攝影機為圓心,順時針旋轉到Portrait為90度;旋轉到LandscapeLeft為180度;旋轉到PortraitUpsideDown為270度。 這裡先在OS X 10.10.4和Windows 8上看看這兩個視頻檔案的屬性:1、將手機裡的視頻檔案匯出到OS X,並在Finder中看預覽,兩個檔案的顯示方向都是正確的。再查看Rotation值為90的IMG_1427.MOV視頻檔案的屬性。顯示其尺寸為1080*1920,而不是1920*1080。但不要被這個假象欺騙了,視頻的實際尺寸還是1920*1080。最後看沒有Rotation值或者說Rotation值為0的IMG_1428.MOV視頻檔案,顯示其尺寸為1920*1080,一切正常。使用QuickTime播放,能正確識別出兩個視頻的方向。 (圖三) 2、在Windows資源管理員中看預覽,IMG_1427.MOV和IMG_1428.MOV的顯示方向都是正確的;再查看兩個檔案的屬性,尺寸都顯示為1920*1080;使用Windows Media Player播放,能正確識別出兩個視頻的方向。 二、常見視頻播放器對方向的識別iOS相簿調出的播放器和Win8上的Windows Media Player能夠正確識別出MOV/MP4的方向,即實際尺寸為1920*1080的、Rotation值為90的IMG_1427.MOV視頻能夠按1080*1920的尺寸並調整方向進行渲染;沒有Rotation值或者說Rotation值為0的IMG_1428.MOV視頻按1920*1080的尺寸並按實際方向進行渲染。Andriod也存在類似情況。VLC for OS X(why?)和iOS的MPMoviePlayerViewControlle對Rotation沒有識別,它們總是按實際尺寸和預設方向進行渲染。對於MPMoviePlayerViewControlle下面有解決方案。Safari瀏覽器調出的播放器應該也是MPMoviePlayerViewController,所以也無法正確識別方向。  三、MPMoviePlayerViewController控制視頻方向需要額外的參數來確定視頻的方向,然後旋轉播放器,達到各種視頻——mov/mp4/m3u8等——都可以正確播放的目的。  1 //…... 2 NSString * url = @"http://www.yourdomain.com/Videos/1.m3u8"; 3 MPMoviePlayerViewController * vc = [[MPMoviePlayerViewController alloc] init]; 4 vc.moviePlayer.contentURL = [NSURL URLWithString:url]; 5 // 這裡播放一個Rotation為90的視頻,即Home鍵在下錄製的視頻 6 [self rotateVideoView:vc degrees:90]; 7 [self presentMoviePlayerViewControllerAnimated:vc]; 8 [vc.moviePlayer play]; 9 10 //…...11 - (void)rotateVideoView:(MPMoviePlayerViewController *)movePlayerViewController degrees:(NSInteger)degrees12 {13 if(degrees==0||degrees==360) return;14 if(degrees<0) degrees = (degrees % 360) + 360;15 if(degrees>360) degrees = degrees % 360;16 // MPVideoView在iOS8中Tag為1002,不排除蘋果以後更改的可能性。參考遞迴查看View階層的lldb命令: (lldb) po [movePlayerViewController.view recursiveDescription]17 UIView *videoView = [movePlayerViewController.view viewWithTag:1002];18 if ([videoView isKindOfClass:NSClassFromString(@"MPVideoView")]) {19 videoView.transform = CGAffineTransformMakeRotation(M_PI * degrees / 180.0);20 videoView.frame = movePlayerViewController.view.bounds;21 }22 }View Code

改為Category:

 1 #import "MPMoviePlayerViewController+Rotation.h" 2  3 @implementation MPMoviePlayerViewController (Rotation) 4  5 - (void)rotateVideoViewWithDegrees:(NSInteger)degrees 6 { 7     if(degrees==0||degrees==360) return; 8     if(degrees<0) degrees = (degrees % 360) + 360; 9     if(degrees>360) degrees = degrees % 360;10    11     // MPVideoView在iOS8中Tag為1002,不排除蘋果以後更改的可能性。參考遞迴查看View階層的lldb命令: (lldb) po [movePlayerViewController.view recursiveDescription]12     UIView *videoView = [self.view viewWithTag:1002];13     if ([videoView isKindOfClass:NSClassFromString(@"MPVideoView")]) {14         videoView.transform = CGAffineTransformMakeRotation(M_PI * degrees / 180.0);15         videoView.frame = self.view.bounds;16     }17 }18 19 @end
四、HTML5控制視頻方向 在video標籤中增加 style="-webkit-transform: rotate(90deg);” ,不過控制項也被旋轉了。這就需要將預設播放控制項隱藏了並且自繪控制項,此略。 五、使用ffmpeg寫入Rotation中繼資料 對於沒有Rotation中繼資料的mp4檔案,可通過ffmpeg等工具寫入。比如視頻需要順時針旋轉90度顯示: ffmpeg -i input.mp4 -c copy -metadata:s:v:0 rotate=90 output.mp4 
註:如果願意,寫入非0、180或270的值,比如45之類的也是可以的。 
六、擷取視頻方向(角度) 
+ (NSUInteger)degressFromVideoFileWithURL:(NSURL *)url{    NSUInteger degress = 0;       AVAsset *asset = [AVAsset assetWithURL:url];    NSArray *tracks = [asset tracksWithMediaType:AVMediaTypeVideo];    if([tracks count] > 0) {        AVAssetTrack *videoTrack = [tracks objectAtIndex:0];        CGAffineTransform t = videoTrack.preferredTransform;               if(t.a == 0 && t.b == 1.0 && t.c == -1.0 && t.d == 0){            // Portrait            degress = 90;        }else if(t.a == 0 && t.b == -1.0 && t.c == 1.0 && t.d == 0){            // PortraitUpsideDown            degress = 270;        }else if(t.a == 1.0 && t.b == 0 && t.c == 0 && t.d == 1.0){            // LandscapeRight            degress = 0;        }else if(t.a == -1.0 && t.b == 0 && t.c == 0 && t.d == -1.0){            // LandscapeLeft            degress = 180;        }    }       return degress;}
七、按正確方向對視頻進行關鍵點是將AVAssetImageGrnerator對象的appliesPreferredTrackTransform屬性設定為YES。 
 1 + (UIImage *)extractImageFromVideoFileWithUrl:(NSURL *)url 2 { 3     NSDictionary *opts = @{AVURLAssetPreferPreciseDurationAndTimingKey:@(NO)}; 4     AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:url options:opts]; 5     AVAssetImageGenerator *gen = [[AVAssetImageGenerator alloc] initWithAsset:asset]; 6     // 應用方向 7     gen.appliesPreferredTrackTransform = YES; 8     CMTime time = CMTimeMakeWithSeconds(1, 60); 9     NSError *error = nil;10     CMTime actualTime;11     CGImageRef image = [gen copyCGImageAtTime:time actualTime:&actualTime error:&error];12     if(error)13     {14         DLog(@"%@ %@",__FUNCTION_FILE_LINE__,error);15         return nil;16     }17     UIImage *thumb = [[UIImage alloc] initWithCGImage:image];18     CGImageRelease(image);19    20     return thumb;21 } 
八、即時視頻的方向處理使用AVFoundation製作自訂相機時,採集出來的視訊框架儲存在CMSampleBufferRef結構中,色彩空間可以設定為RGB或YUV。進行一些記憶體操作就可實現旋轉。以下代碼是針對YUV的。 
註:這種涉及大量記憶體拷貝的操作,實際應用中要權衡其利弊。
1、RGB24旋轉90度   1 // RGB24旋轉90度 2 void RGB24Rotate90(int8_t *des, const int8_t *src, int width, int height) 3 { 4 if(!des || !src) return; 5 6 int n = 0; 7 int linesize = width * 3; 8 int i, j; 9 // 逆時針旋轉10 for (j = width; j > 0; j--) {11 for (i = 0; i < height; i++) {12 memccpy(&des[n], &src[linesize * i + j * 3 - 3], 0, 3);13 n += 3;14 }15 }16 /*17 // 順時針旋轉18 for (j = 0 ; j < width; j++) {19 for (i = height; i > 0; i--) {20 memccpy(&des[n], &src[linesize * (i - 1) + j * 3 - 3], 0, 3);21 n += 3;22 }23 }24 */25 }View Code

 2、RGB24旋轉90度   1 // YUV420旋轉90度 2 void YUV420Rotate90(int8_t *des, const int8_t *src, int width, int height) 3 { 4 int i = 0, j = 0, n = 0; 5 int hw = width / 2, hh = height / 2; 6 7 const int8_t *ptmp = src; 8 for (j = width; j > 0; j--) { 9 for (i = 0; i < height; i++) {10 des[n++] = ptmp[width * i + j];11 }12 }13 14 ptmp = src + width * height;15 for (j = hw; j > 0; j--) {16 for (i = 0; i < hh; i++) {17 des[n++] = ptmp[hw * i + j];18 }19 }20 21 ptmp = src + width * height * 5 / 4;22 for (j = hw; j > 0; j--) {23 for (i = 0; i < hh; i++) {24 des[n++] = ptmp[hw * i + j];25 }26 }27 }View Code

或:

1 int8_t[] rotateYUV420Degree90(int8_t[] data, int imageWidth, int imageHeight) 2 { 3 int8_t [] yuv = new int8_t[imageWidth*imageHeight*3/2]; 4 // Rotate the Y luma 5 int i = 0; 6 for(int x = 0;x < imageWidth;x++) 7 { 8 for(int y = imageHeight-1;y >= 0;y--) 9 {10 yuv[i] = data[y*imageWidth+x];11 i++;12 }13 }14 // Rotate the U and V color components15 i = imageWidth*imageHeight*3/2-1;16 for(int x = imageWidth-1;x > 0;x=x-2)17 {18 for(int y = 0;y < imageHeight/2;y++)19 {20 yuv[i] = data[(imageWidth*imageHeight)+(y*imageWidth)+x];21 i--;22 yuv[i] = data[(imageWidth*imageHeight)+(y*imageWidth)+(x-1)];23 i--;24 }25 }26 return yuv;27 }View Code 九、參考資料: http://www.rosoo.net/a/201006/9689.htmlhttp://stackoverflow.com/questions/14167976/rotate-an-yuv-byte-array-on-android  

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.