[IOS] several questions about video direction and ios
I. Rotation metadata in MOV/MP4 video filesThe mov/mp4 video recorded by the built-in camera app on iOS may produce a Rotation metadata, which indicates how many angles the camera rotates during video recording. The value is generally the four: 0, 90, 180 or 270. Similar to the Orientation metadata in the Exif information of an image file. The Rotation metadata is used by the player to determine the direction of the rendered video, but some players will turn a blind eye to it. Later, we will test the support of several common player/playback controls for the Rotation metadata.
Note: in fact, the Rotation metadata of a video file is not the saved angle value. However, if you only care about the angle, not image stretching, you can simply understand it. For more information about how to obtain the Rotation metadata angle value, see the source code of vlc.
The following uses MediaInfo to view the two videos recorded by the iPhone Camera app using the rear camera and observe its Rotation metadata. Please note that the file names are IMG_1427.MOV and IMG_1428.MOV respectively, and these two files will be used for comparison later. 1. The Rotation value of the video recorded in Portrait (Portrait screen with the Home Key below) mode is 90. (Figure 1: The Rotation value is 90) 2. If you use the video recorded by the rear camera in LandscapeRigth (horizontal screen, Home key on the right) mode, no Rotation metadata is available, or the Rotation value is 0. (Figure 2: There is no Rotation value or the Rotation value is 0) The four angle values of Rotation 0, 90, 180, and 270 can be understood as follows: LandscapeRigth is 0 degrees; take the Home key or camera as the center, rotate clockwise to Portrait for 90 degrees, rotate to LandscapeLeft for 180 degrees, and rotate to PortraitUpsideDown for 270 degrees. Here we will first look at the attributes of these two video files on OS x 10.10.4 and Windows 8: 1. Export the video files on the mobile phone to OS X and preview them in the Finder, both files are correctly displayed. View the attributes of the IMG_1427.MOV video file whose Rotation value is 90. The size is 1080*1920 instead of 1920*1080. But don't be fooled by this illusion. The actual video size is 1920*1080. Finally, the IMG_1428.MOV video file with no Rotation value or 0 Rotation value shows that its size is 1920*1080, and everything is normal. You can use QuickTime to correctly identify the two video directions. (Figure 3) 2. In Windows Resource Manager, check that the display direction of IMG_1427.MOV and IMG_1428.MOV is correct. Then, check the attributes of the two files. The sizes are 1920*1080; you can use Windows Media Player to correctly identify the two video directions.
2. Recognition of the direction of common video playersIOS album Player and Windows Media Player on Win8 can correctly identify the direction of MOV/MP4, that is, an IMG_1427.MOV video with an actual size of 1920*1080 and a Rotation value of 90 can be rendered at a size of 1080*1920 and adjusted in the direction; video IMG_1428.MOV without a Rotation value or with a Rotation value of 0 is rendered in 1920*1080 and in the actual direction. A similar situation exists in Andriod. VLC for OS X (why ?) And iOS MPMoviePlayerViewControlle do not recognize Rotation, they are always rendered in the actual size and default direction. There is a solution for MPMoviePlayerViewControlle. The player that the Safari browser calls out should also be MPMoviePlayerViewController, so it cannot identify the direction correctly.
3. MPMoviePlayerViewController controls the video directionYou need additional parameters to determine the video direction, and then rotate the player to play all the videos-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 // here, a video with a Rotation of 90 is played, that is, the video with the Home key being recorded 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 // The Tag of MPVideoView in ios8, it does not rule out the possibility of future changes from Apple. Refer to the recursive lldb command for viewing the View hierarchy: (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
Change to 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 // The Tag of MPVideoView in iOS8 is 1002, which does not rule out the possibility of future modification by Apple. Refer to the recursive lldb command for viewing the View hierarchy: (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
Iv. HTML5 video direction controlAdd style = "-webkit-transform: rotate (90deg);" to the video tag, but the control is also rotated. This requires that the default playback control is hidden and the Self-painted control is omitted.
5. Use ffmpeg to write Rotation metadataMp4 files without Rotation metadata can be written using tools such as ffmpeg. For example, the video needs to rotate 90 degrees clockwise: ffmpeg-I input.mp4-c copy-metadata: s: v: 0 rotate = 90 output.mp4
Note: If you want to write a non-0, 180, or 270 value, such as 45, you can also.
6. Obtain the video direction (angle)
+ (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;}
7. Video OrientationThe key point is to set the appliesPreferredTrackTransform attribute of the AVAssetImageGrnerator object to 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 // application direction 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}
8. Real-Time Video ProcessingWhen you use AVFoundation to create a custom camera, the captured video frames are saved in the CMSampleBufferRef structure, and the color space can be set to RGB or YUV. Perform some memory operations to achieve rotation. The following code is for YUV.
Note: in practice, the advantages and disadvantages of this operation involving a large number of memory copies must be weighed.
1. RGB24 rotation 90 degrees 1 // RGB24 rotation 90 degrees 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 // rotate 10 for (j = width; j> 0; j --) {11 for (I = 0; I
2. RGB24 Rotate 90 degrees 1 // YUV420 Rotate 90 degrees 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 Or:
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
IX. References:Http://www.rosoo.net/a/201006/9689.htmlhttp://stackoverflow.com/questions/14167976/rotate-an-yuv-byte-array-on-android