[
  {
    "path": "MediaHandleDemo/AppDelegate.h",
    "content": "//\n//  AppDelegate.h\n//  MediaHandleDemo\n//\n//  Created by Shelin on 15/11/25.\n//  Copyright © 2015年 GreatGate. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n\n@interface AppDelegate : UIResponder <UIApplicationDelegate>\n\n@property (strong, nonatomic) UIWindow *window;\n\n\n@end\n\n"
  },
  {
    "path": "MediaHandleDemo/AppDelegate.m",
    "content": "//\n//  AppDelegate.m\n//  MediaHandleDemo\n//\n//  Created by Shelin on 15/11/25.\n//  Copyright © 2015年 GreatGate. All rights reserved.\n//\n\n#import \"AppDelegate.h\"\n#import \"ViewController.h\"\n@interface AppDelegate ()\n\n@end\n\n@implementation AppDelegate\n\n\n- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {\n    // Override point for customization after application launch.\n    self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];\n    \n    [self.window makeKeyAndVisible];\n    UIStoryboard *board = [UIStoryboard storyboardWithName:@\"Main\" bundle:nil];\n    ViewController *vc = [board instantiateViewControllerWithIdentifier: @\"vc\"];\n    \n    UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:vc];\n    \n    self.window.rootViewController = nav;\n    return YES;\n}\n\n- (void)applicationWillResignActive:(UIApplication *)application {\n    // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.\n    // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.\n}\n\n- (void)applicationDidEnterBackground:(UIApplication *)application {\n    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.\n    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.\n}\n\n- (void)applicationWillEnterForeground:(UIApplication *)application {\n    // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.\n}\n\n- (void)applicationDidBecomeActive:(UIApplication *)application {\n    // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.\n}\n\n- (void)applicationWillTerminate:(UIApplication *)application {\n    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.\n}\n\n@end\n"
  },
  {
    "path": "MediaHandleDemo/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "MediaHandleDemo/Base.lproj/LaunchScreen.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"9059\" systemVersion=\"14F27\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" launchScreen=\"YES\" useTraitCollections=\"YES\" initialViewController=\"01J-lp-oVM\">\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"9049\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"EHf-IW-A2E\">\n            <objects>\n                <viewController id=\"01J-lp-oVM\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"Llm-lL-Icb\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"xb3-aO-Qok\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"Ze5-6b-2t3\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"600\" height=\"600\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <animations/>\n                        <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"calibratedWhite\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"iYj-Kq-Ea1\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"53\" y=\"375\"/>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "MediaHandleDemo/Base.lproj/Main.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"9059\" systemVersion=\"14F27\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" initialViewController=\"BYZ-38-t0r\">\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"9049\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"tne-QT-ifu\">\n            <objects>\n                <viewController storyboardIdentifier=\"vc\" id=\"BYZ-38-t0r\" customClass=\"ViewController\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"y3c-jy-aDJ\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"wfy-db-euE\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"8bC-Xf-vdC\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"600\" height=\"600\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" lineBreakMode=\"middleTruncation\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"vvd-ac-Gvi\">\n                                <rect key=\"frame\" x=\"228.5\" y=\"90\" width=\"143\" height=\"61\"/>\n                                <color key=\"backgroundColor\" red=\"1\" green=\"0.5\" blue=\"0.0\" alpha=\"1\" colorSpace=\"calibratedRGB\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"width\" constant=\"143\" id=\"Lmd-DM-40f\"/>\n                                    <constraint firstAttribute=\"height\" constant=\"61\" id=\"Msh-70-rSt\"/>\n                                </constraints>\n                                <state key=\"normal\" title=\"选择视频\"/>\n                                <connections>\n                                    <action selector=\"selectVideo:\" destination=\"BYZ-38-t0r\" eventType=\"touchUpInside\" id=\"GCH-fs-B4C\"/>\n                                </connections>\n                            </button>\n                            <button opaque=\"NO\" contentMode=\"scaleToFill\" ambiguous=\"YES\" misplaced=\"YES\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" lineBreakMode=\"middleTruncation\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"2Q3-To-Djc\">\n                                <rect key=\"frame\" x=\"229\" y=\"313\" width=\"143\" height=\"61\"/>\n                                <color key=\"backgroundColor\" red=\"1\" green=\"0.5\" blue=\"0.0\" alpha=\"1\" colorSpace=\"calibratedRGB\"/>\n                                <state key=\"normal\" title=\"截取并添加背景音乐\"/>\n                                <connections>\n                                    <action selector=\"addBackgroundmusic:\" destination=\"BYZ-38-t0r\" eventType=\"touchUpInside\" id=\"6bb-NS-zPc\"/>\n                                </connections>\n                            </button>\n                            <textField opaque=\"NO\" clipsSubviews=\"YES\" contentMode=\"scaleToFill\" fixedFrame=\"YES\" contentHorizontalAlignment=\"left\" contentVerticalAlignment=\"center\" borderStyle=\"roundedRect\" placeholder=\"输入截取结束时间\" textAlignment=\"natural\" minimumFontSize=\"17\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"adi-kL-aJ0\">\n                                <rect key=\"frame\" x=\"172\" y=\"218\" width=\"128\" height=\"30\"/>\n                                <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"14\"/>\n                                <textInputTraits key=\"textInputTraits\" keyboardType=\"numberPad\"/>\n                            </textField>\n                            <button opaque=\"NO\" contentMode=\"scaleToFill\" ambiguous=\"YES\" misplaced=\"YES\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" lineBreakMode=\"middleTruncation\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"w40-iG-es2\">\n                                <rect key=\"frame\" x=\"228.5\" y=\"425\" width=\"143\" height=\"61\"/>\n                                <color key=\"backgroundColor\" red=\"1\" green=\"0.5\" blue=\"0.0\" alpha=\"1\" colorSpace=\"calibratedRGB\"/>\n                                <state key=\"normal\" title=\"播放视频\"/>\n                                <connections>\n                                    <action selector=\"videoPlay:\" destination=\"BYZ-38-t0r\" eventType=\"touchUpInside\" id=\"Rp1-XO-iqR\"/>\n                                </connections>\n                            </button>\n                            <textField opaque=\"NO\" clipsSubviews=\"YES\" contentMode=\"scaleToFill\" fixedFrame=\"YES\" contentHorizontalAlignment=\"left\" contentVerticalAlignment=\"center\" borderStyle=\"roundedRect\" placeholder=\"输入截取起始时间\" textAlignment=\"natural\" minimumFontSize=\"17\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"yqT-Gt-QPl\">\n                                <rect key=\"frame\" x=\"29\" y=\"218\" width=\"128\" height=\"30\"/>\n                                <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"14\"/>\n                                <textInputTraits key=\"textInputTraits\" keyboardType=\"numberPad\"/>\n                            </textField>\n                        </subviews>\n                        <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"calibratedWhite\"/>\n                        <constraints>\n                            <constraint firstItem=\"vvd-ac-Gvi\" firstAttribute=\"top\" secondItem=\"y3c-jy-aDJ\" secondAttribute=\"bottom\" constant=\"70\" id=\"CsZ-Pn-mGh\"/>\n                            <constraint firstItem=\"w40-iG-es2\" firstAttribute=\"top\" secondItem=\"2Q3-To-Djc\" secondAttribute=\"bottom\" constant=\"51\" id=\"GKF-k6-vNT\"/>\n                            <constraint firstItem=\"2Q3-To-Djc\" firstAttribute=\"width\" secondItem=\"vvd-ac-Gvi\" secondAttribute=\"width\" id=\"J7e-JA-ysF\"/>\n                            <constraint firstItem=\"2Q3-To-Djc\" firstAttribute=\"height\" secondItem=\"vvd-ac-Gvi\" secondAttribute=\"height\" id=\"M76-kM-mW8\"/>\n                            <constraint firstItem=\"vvd-ac-Gvi\" firstAttribute=\"centerX\" secondItem=\"8bC-Xf-vdC\" secondAttribute=\"centerX\" id=\"TdQ-yZ-nsn\"/>\n                            <constraint firstItem=\"w40-iG-es2\" firstAttribute=\"width\" secondItem=\"2Q3-To-Djc\" secondAttribute=\"width\" id=\"Y9K-Ol-kMB\"/>\n                            <constraint firstItem=\"w40-iG-es2\" firstAttribute=\"height\" secondItem=\"2Q3-To-Djc\" secondAttribute=\"height\" id=\"bLg-16-5XY\"/>\n                            <constraint firstItem=\"2Q3-To-Djc\" firstAttribute=\"centerX\" secondItem=\"vvd-ac-Gvi\" secondAttribute=\"centerX\" id=\"fjI-df-luj\"/>\n                            <constraint firstItem=\"w40-iG-es2\" firstAttribute=\"centerX\" secondItem=\"2Q3-To-Djc\" secondAttribute=\"centerX\" id=\"yUj-ON-XKh\"/>\n                        </constraints>\n                    </view>\n                    <connections>\n                        <outlet property=\"endTextField\" destination=\"adi-kL-aJ0\" id=\"FIr-aM-Y8M\"/>\n                        <outlet property=\"startTextField\" destination=\"yqT-Gt-QPl\" id=\"RcM-CA-0Ce\"/>\n                    </connections>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"dkx-z0-nzr\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"105\" y=\"49\"/>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "MediaHandleDemo/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleSignature</key>\n\t<string>????</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n\t<key>LSRequiresIPhoneOS</key>\n\t<true/>\n\t<key>UILaunchStoryboardName</key>\n\t<string>LaunchScreen</string>\n\t<key>UIMainStoryboardFile</key>\n\t<string>Main</string>\n\t<key>UIRequiredDeviceCapabilities</key>\n\t<array>\n\t\t<string>armv7</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n</dict>\n</plist>\n"
  },
  {
    "path": "MediaHandleDemo/MediaManager.h",
    "content": "//\n//  MediaManager.h\n//  AddBackgroundMusic\n//\n//  Created by Shelin on 15/11/25.\n//  Copyright © 2015年 GreatGate. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n#import <UIKit/UIKit.h>\n/**\n 添加音乐完成回调的block\n */\ntypedef void (^MixcompletionBlock)(void);\n@interface MediaManager : NSObject\n/**\n 截取视频并添加背景音乐\n */\n+ (void)addBackgroundMiusicWithVideoUrlStr:(NSURL *)videoUrl audioUrl:(NSURL *)audioUrl andCaptureVideoWithRange:(NSRange)videoRange completion:(MixcompletionBlock)completionHandle;\n\n/**\n 获取多媒体时长\n */\n+ (CGFloat)getMediaDurationWithMediaUrl:(NSString *)mediaUrlStr;\n\n/**\n 获取合并后的多媒体文件路径\n */\n+ (NSString *)getMediaFilePath;\n@end\n"
  },
  {
    "path": "MediaHandleDemo/MediaManager.m",
    "content": "//\n//  MediaManager.m\n//  AddBackgroundMusic\n//\n//  Created by Shelin on 15/11/25.\n//  Copyright © 2015年 GreatGate. All rights reserved.\n//\n\n#import \"MediaManager.h\"\n#import <AVFoundation/AVFoundation.h>\n\n#define MediaFileName @\"MixVideo.mov\"\n\n\n@implementation MediaManager\n\n+ (void)addBackgroundMiusicWithVideoUrlStr:(NSURL *)videoUrl audioUrl:(NSURL *)audioUrl andCaptureVideoWithRange:(NSRange)videoRange completion:(MixcompletionBlock)completionHandle {\n\n    //AVURLAsset此类主要用于获取媒体信息，包括视频、声音等\n    AVURLAsset* audioAsset = [[AVURLAsset alloc] initWithURL:audioUrl options:nil];\n    AVURLAsset* videoAsset = [[AVURLAsset alloc] initWithURL:videoUrl options:nil];\n    \n    //创建AVMutableComposition对象来添加视频音频资源的AVMutableCompositionTrack\n    AVMutableComposition* mixComposition = [AVMutableComposition composition];\n    \n    //CMTimeRangeMake(start, duration),start起始时间，duration时长，都是CMTime类型\n    //CMTimeMake(int64_t value, int32_t timescale)，返回CMTime，value视频的一个总帧数，timescale是指每秒视频播放的帧数，视频播放速率，（value / timescale）才是视频实际的秒数时长，timescale一般情况下不改变，截取视频长度通过改变value的值\n    //CMTimeMakeWithSeconds(Float64 seconds, int32_t preferredTimeScale)，返回CMTime，seconds截取时长（单位秒），preferredTimeScale每秒帧数\n    \n    //开始位置startTime\n    CMTime startTime = CMTimeMakeWithSeconds(videoRange.location, videoAsset.duration.timescale);\n    //截取长度videoDuration\n    CMTime videoDuration = CMTimeMakeWithSeconds(videoRange.length, videoAsset.duration.timescale);\n    \n    CMTimeRange videoTimeRange = CMTimeRangeMake(startTime, videoDuration);\n    \n    //视频采集compositionVideoTrack\n    AVMutableCompositionTrack *compositionVideoTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];\n    \n#warning 避免数组越界 tracksWithMediaType 找不到对应的文件时候返回空数组\n    //TimeRange截取的范围长度\n    //ofTrack来源\n    //atTime插放在视频的时间位置\n    [compositionVideoTrack insertTimeRange:videoTimeRange ofTrack:([videoAsset tracksWithMediaType:AVMediaTypeVideo].count>0) ? [videoAsset tracksWithMediaType:AVMediaTypeVideo].firstObject : nil atTime:kCMTimeZero error:nil];\n    \n    /*\n     //视频声音采集(也可不执行这段代码不采集视频音轨，合并后的视频文件将没有视频原来的声音)\n     \n     AVMutableCompositionTrack *compositionVoiceTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];\n     \n     [compositionVoiceTrack insertTimeRange:videoTimeRange ofTrack:([videoAsset tracksWithMediaType:AVMediaTypeAudio].count>0)?[videoAsset tracksWithMediaType:AVMediaTypeAudio].firstObject:nil atTime:kCMTimeZero error:nil];\n     \n     */\n    \n    \n    //声音长度截取范围==视频长度\n    CMTimeRange audioTimeRange = CMTimeRangeMake(kCMTimeZero, videoDuration);\n    \n    //音频采集compositionCommentaryTrack\n    AVMutableCompositionTrack *compositionAudioTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];\n    \n    [compositionAudioTrack insertTimeRange:audioTimeRange ofTrack:([audioAsset tracksWithMediaType:AVMediaTypeAudio].count > 0) ? [audioAsset tracksWithMediaType:AVMediaTypeAudio].firstObject : nil atTime:kCMTimeZero error:nil];\n    \n    //AVAssetExportSession用于合并文件，导出合并后文件，presetName文件的输出类型\n    AVAssetExportSession *assetExportSession = [[AVAssetExportSession alloc] initWithAsset:mixComposition presetName:AVAssetExportPresetPassthrough];\n    \n    NSString *outPutPath = [NSTemporaryDirectory() stringByAppendingPathComponent:MediaFileName];\n    //混合后的视频输出路径\n    NSURL *outPutUrl = [NSURL fileURLWithPath:outPutPath];\n    \n    if ([[NSFileManager defaultManager] fileExistsAtPath:outPutPath])\n    {\n        [[NSFileManager defaultManager] removeItemAtPath:outPutPath error:nil];\n    }\n    \n    //输出视频格式 AVFileTypeMPEG4 AVFileTypeQuickTimeMovie...\n    assetExportSession.outputFileType = AVFileTypeQuickTimeMovie;\n//    NSArray *fileTypes = assetExportSession.\n    \n    assetExportSession.outputURL = outPutUrl;\n    //输出文件是否网络优化\n    assetExportSession.shouldOptimizeForNetworkUse = YES;\n    \n    [assetExportSession exportAsynchronouslyWithCompletionHandler:^{\n        completionHandle();\n    }];\n}\n\n+ (CGFloat)getMediaDurationWithMediaUrl:(NSString *)mediaUrlStr {\n    \n    NSURL *mediaUrl = [NSURL URLWithString:mediaUrlStr];\n    AVURLAsset *mediaAsset = [[AVURLAsset alloc] initWithURL:mediaUrl options:nil];\n    CMTime duration = mediaAsset.duration;\n    \n    return duration.value / duration.timescale;    \n}\n\n+ (NSString *)getMediaFilePath {\n    \n    return [NSTemporaryDirectory() stringByAppendingPathComponent:MediaFileName];\n    \n}\n\n@end\n"
  },
  {
    "path": "MediaHandleDemo/PlayViewController.h",
    "content": "//\n//  PlayViewController.h\n//  MediaHandleDemo\n//\n//  Created by Shelin on 15/11/25.\n//  Copyright © 2015年 GreatGate. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n\n@interface PlayViewController : UIViewController\n\n@property (nonatomic, strong) NSURL *videoUrl;\n\n\n@end\n"
  },
  {
    "path": "MediaHandleDemo/PlayViewController.m",
    "content": "//\n//  PlayViewController.m\n//  MediaHandleDemo\n//\n//  Created by Shelin on 15/11/25.\n//  Copyright © 2015年 GreatGate. All rights reserved.\n//\n\n#import \"PlayViewController.h\"\n#import <MediaPlayer/MediaPlayer.h>\n#import <MobileCoreServices/MobileCoreServices.h>\n@interface PlayViewController ()\n{\n    MPMoviePlayerController *_moviePlayer;\n}\n@end\n\n@implementation PlayViewController\n\n- (void)viewDidLoad {\n    [super viewDidLoad];\n    // Do any additional setup after loading the view.\n    self.view.backgroundColor = [UIColor whiteColor];\n    \n    NSString* videoName = @\"export.mov\";\n    \n    NSString *exportPath = [NSTemporaryDirectory() stringByAppendingPathComponent:videoName];\n//    NSLog(@\"-------%@\",exportPath);\n    \n    _moviePlayer = [[MPMoviePlayerController alloc] init];\n    \n    _moviePlayer.view.frame = self.view.bounds;\n    _moviePlayer.view.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;\n    [self.view addSubview:_moviePlayer.view];\n    _moviePlayer.contentURL = [NSURL fileURLWithPath:exportPath];\n    [_moviePlayer play];\n}\n\n\n- (void)didReceiveMemoryWarning {\n    [super didReceiveMemoryWarning];\n    // Dispose of any resources that can be recreated.\n}\n\n/*\n#pragma mark - Navigation\n\n// In a storyboard-based application, you will often want to do a little preparation before navigation\n- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {\n    // Get the new view controller using [segue destinationViewController].\n    // Pass the selected object to the new view controller.\n}\n*/\n\n@end\n"
  },
  {
    "path": "MediaHandleDemo/ViewController.h",
    "content": "//\n//  ViewController.h\n//  MediaHandleDemo\n//\n//  Created by Shelin on 15/11/25.\n//  Copyright © 2015年 GreatGate. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n\n@interface ViewController : UIViewController\n\n\n@end\n\n"
  },
  {
    "path": "MediaHandleDemo/ViewController.m",
    "content": "//\n//  ViewController.m\n//  MediaHandleDemo\n//\n//  Created by Shelin on 15/11/25.\n//  Copyright © 2015年 GreatGate. All rights reserved.\n//\n\n#import \"ViewController.h\"\n#import \"MediaManager.h\"\n#import \"PlayViewController.h\"\n#import <MediaPlayer/MediaPlayer.h>\n#import <MobileCoreServices/MobileCoreServices.h>\n#define AUDIO_URL [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@\"月半弯\" ofType:@\"mp3\"]]\n\n@interface ViewController ()<UIImagePickerControllerDelegate,UINavigationControllerDelegate>\n{\n    UIImagePickerController *_imagePickerController;\n    NSURL *_videoUrl;\n    NSURL *_audioUrl;\n}\n\n\n@property (weak, nonatomic) IBOutlet UITextField *startTextField;\n@property (weak, nonatomic) IBOutlet UITextField *endTextField;\n\n\n@end\n\n@implementation ViewController\n\n- (void)viewDidLoad {\n    [super viewDidLoad];\n    // Do any additional setup after loading the view, typically from a nib.\n    _imagePickerController = [[UIImagePickerController alloc] init];\n    _imagePickerController.delegate = self;\n    _imagePickerController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;\n    _imagePickerController.allowsEditing = YES;\n\n    _audioUrl = AUDIO_URL;\n}\n\n- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event\n{\n    [self.view endEditing:YES];\n}\n\n- (IBAction)addBackgroundmusic:(id)sender {\n    \n    if (_videoUrl && _audioUrl && self.endTextField.text && self.startTextField.text) {\n        \n        [MediaManager addBackgroundMiusicWithVideoUrlStr:_videoUrl audioUrl:_audioUrl andCaptureVideoWithRange:NSMakeRange([self.startTextField.text floatValue], [self.endTextField.text floatValue] - [self.startTextField.text floatValue]) completion:^{\n            \n            NSLog(@\"视频合并完成\");\n        }];\n    }\n}\n\n- (IBAction)videoPlay:(id)sender {\n    \n    PlayViewController *pvc = [[PlayViewController alloc] init];\n    \n    [self.navigationController pushViewController:pvc animated:YES];\n}\n\n- (IBAction)selectVideo:(id)sender {\n    \n    UIAlertController *alertVc = [UIAlertController alertControllerWithTitle:@\"选择图片来源\" message:@\"\" preferredStyle:UIAlertControllerStyleAlert];\n    \n    UIAlertAction *cameraAction = [UIAlertAction actionWithTitle:@\"相机\" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {\n        [self selectImageFromCamera];\n        \n    }];\n    UIAlertAction *photoAction = [UIAlertAction actionWithTitle:@\"相册\" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {\n        [self selectImageFromAlbum];\n    }];\n    \n    UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@\"取消\" style:UIAlertActionStyleCancel handler:nil];\n    [alertVc addAction:cameraAction];\n    [alertVc addAction:photoAction];\n    [alertVc addAction:cancelAction];\n    [self presentViewController:alertVc animated:YES completion:nil];\n}\n\n#pragma mark 从摄像头获取图片或视频\n- (void)selectImageFromCamera\n{\n    //NSLog(@\"相机\");\n    _imagePickerController.sourceType = UIImagePickerControllerSourceTypeCamera;\n    //录制视频时长，默认10s\n    _imagePickerController.videoMaximumDuration = 15;\n    //相机类型（拍照、录像...）\n    _imagePickerController.mediaTypes = @[(NSString *)kUTTypeMovie,(NSString *)kUTTypeImage];\n    //视频上传质量\n    _imagePickerController.videoQuality = UIImagePickerControllerQualityTypeHigh;\n    //设置摄像头模式（拍照，录制视频）\n    _imagePickerController.cameraCaptureMode = UIImagePickerControllerCameraCaptureModeVideo;\n    \n    [self presentViewController:_imagePickerController animated:YES completion:nil];\n}\n\n#pragma mark 从相册获取图片或视频\n- (void)selectImageFromAlbum\n{\n    //NSLog(@\"相册\");\n    _imagePickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;\n    \n    [self presentViewController:_imagePickerController animated:YES completion:nil];\n}\n\n#pragma mark UIImagePickerControllerDelegate\n- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info{\n    NSString *mediaType=[info objectForKey:UIImagePickerControllerMediaType];\n    \n    if ([mediaType isEqualToString:(NSString *)kUTTypeImage]){\n        \n    }else{\n        //如果是视频\n        NSURL *url = info[UIImagePickerControllerMediaURL];\n        //播放视频\n        \n        _videoUrl = url;\n        //保存视频至相册（异步线程）\n        NSString *urlStr = [url path];\n        \n        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{\n            if (UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(urlStr)) {\n                \n                UISaveVideoAtPathToSavedPhotosAlbum(urlStr, self, @selector(video:didFinishSavingWithError:contextInfo:), nil);\n            }\n        });\n    }\n    [self dismissViewControllerAnimated:YES completion:nil];\n}\n\n#pragma mark 图片保存完毕的回调\n- (void) image: (UIImage *) image didFinishSavingWithError:(NSError *) error contextInfo: (void *)contextIn {\n    \n}\n\n#pragma mark 视频保存完毕的回调\n- (void)video:(NSString *)videoPath didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextIn {\n    if (error) {\n        NSLog(@\"保存视频过程中发生错误，错误信息:%@\",error.localizedDescription);\n    }else{\n        NSLog(@\"视频保存成功.\");\n    }\n}\n\n@end\n"
  },
  {
    "path": "MediaHandleDemo/main.m",
    "content": "//\n//  main.m\n//  MediaHandleDemo\n//\n//  Created by Shelin on 15/11/25.\n//  Copyright © 2015年 GreatGate. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n#import \"AppDelegate.h\"\n\nint main(int argc, char * argv[]) {\n    @autoreleasepool {\n        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));\n    }\n}\n"
  },
  {
    "path": "MediaHandleDemo.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\tFD5A96701C05A78A008386F4 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = FD5A966F1C05A78A008386F4 /* main.m */; };\n\t\tFD5A96731C05A78A008386F4 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = FD5A96721C05A78A008386F4 /* AppDelegate.m */; };\n\t\tFD5A96761C05A78A008386F4 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FD5A96751C05A78A008386F4 /* ViewController.m */; };\n\t\tFD5A96791C05A78A008386F4 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = FD5A96771C05A78A008386F4 /* Main.storyboard */; };\n\t\tFD5A967B1C05A78A008386F4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = FD5A967A1C05A78A008386F4 /* Assets.xcassets */; };\n\t\tFD5A967E1C05A78A008386F4 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = FD5A967C1C05A78A008386F4 /* LaunchScreen.storyboard */; };\n\t\tFD5A96891C05A78A008386F4 /* MediaHandleDemoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = FD5A96881C05A78A008386F4 /* MediaHandleDemoTests.m */; };\n\t\tFD5A96941C05A78A008386F4 /* MediaHandleDemoUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = FD5A96931C05A78A008386F4 /* MediaHandleDemoUITests.m */; };\n\t\tFD5A96A31C05A7A2008386F4 /* MediaManager.m in Sources */ = {isa = PBXBuildFile; fileRef = FD5A96A21C05A7A2008386F4 /* MediaManager.m */; };\n\t\tFD5A96A71C05A7AF008386F4 /* 月半弯.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = FD5A96A51C05A7AF008386F4 /* 月半弯.mp3 */; };\n\t\tFD5A96AA1C05B077008386F4 /* PlayViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FD5A96A91C05B077008386F4 /* PlayViewController.m */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXContainerItemProxy section */\n\t\tFD5A96851C05A78A008386F4 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = FD5A96631C05A789008386F4 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = FD5A966A1C05A789008386F4;\n\t\t\tremoteInfo = MediaHandleDemo;\n\t\t};\n\t\tFD5A96901C05A78A008386F4 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = FD5A96631C05A789008386F4 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = FD5A966A1C05A789008386F4;\n\t\t\tremoteInfo = MediaHandleDemo;\n\t\t};\n/* End PBXContainerItemProxy section */\n\n/* Begin PBXFileReference section */\n\t\tFD5A966B1C05A789008386F4 /* MediaHandleDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MediaHandleDemo.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tFD5A966F1C05A78A008386F4 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = \"<group>\"; };\n\t\tFD5A96711C05A78A008386F4 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = \"<group>\"; };\n\t\tFD5A96721C05A78A008386F4 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = \"<group>\"; };\n\t\tFD5A96741C05A78A008386F4 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = \"<group>\"; };\n\t\tFD5A96751C05A78A008386F4 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = \"<group>\"; };\n\t\tFD5A96781C05A78A008386F4 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = \"<group>\"; };\n\t\tFD5A967A1C05A78A008386F4 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = \"<group>\"; };\n\t\tFD5A967D1C05A78A008386F4 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = \"<group>\"; };\n\t\tFD5A967F1C05A78A008386F4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\tFD5A96841C05A78A008386F4 /* MediaHandleDemoTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MediaHandleDemoTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tFD5A96881C05A78A008386F4 /* MediaHandleDemoTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MediaHandleDemoTests.m; sourceTree = \"<group>\"; };\n\t\tFD5A968A1C05A78A008386F4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\tFD5A968F1C05A78A008386F4 /* MediaHandleDemoUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MediaHandleDemoUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tFD5A96931C05A78A008386F4 /* MediaHandleDemoUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MediaHandleDemoUITests.m; sourceTree = \"<group>\"; };\n\t\tFD5A96951C05A78A008386F4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\tFD5A96A11C05A7A2008386F4 /* MediaManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MediaManager.h; sourceTree = \"<group>\"; };\n\t\tFD5A96A21C05A7A2008386F4 /* MediaManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MediaManager.m; sourceTree = \"<group>\"; };\n\t\tFD5A96A51C05A7AF008386F4 /* 月半弯.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; path = \"月半弯.mp3\"; sourceTree = \"<group>\"; };\n\t\tFD5A96A81C05B077008386F4 /* PlayViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PlayViewController.h; sourceTree = \"<group>\"; };\n\t\tFD5A96A91C05B077008386F4 /* PlayViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PlayViewController.m; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\tFD5A96681C05A789008386F4 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tFD5A96811C05A78A008386F4 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tFD5A968C1C05A78A008386F4 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\tFD5A96621C05A789008386F4 = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tFD5A966D1C05A78A008386F4 /* MediaHandleDemo */,\n\t\t\t\tFD5A96871C05A78A008386F4 /* MediaHandleDemoTests */,\n\t\t\t\tFD5A96921C05A78A008386F4 /* MediaHandleDemoUITests */,\n\t\t\t\tFD5A966C1C05A789008386F4 /* Products */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tFD5A966C1C05A789008386F4 /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tFD5A966B1C05A789008386F4 /* MediaHandleDemo.app */,\n\t\t\t\tFD5A96841C05A78A008386F4 /* MediaHandleDemoTests.xctest */,\n\t\t\t\tFD5A968F1C05A78A008386F4 /* MediaHandleDemoUITests.xctest */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tFD5A966D1C05A78A008386F4 /* MediaHandleDemo */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tFD5A96A51C05A7AF008386F4 /* 月半弯.mp3 */,\n\t\t\t\tFD5A96A11C05A7A2008386F4 /* MediaManager.h */,\n\t\t\t\tFD5A96A21C05A7A2008386F4 /* MediaManager.m */,\n\t\t\t\tFD5A96711C05A78A008386F4 /* AppDelegate.h */,\n\t\t\t\tFD5A96721C05A78A008386F4 /* AppDelegate.m */,\n\t\t\t\tFD5A96741C05A78A008386F4 /* ViewController.h */,\n\t\t\t\tFD5A96751C05A78A008386F4 /* ViewController.m */,\n\t\t\t\tFD5A96A81C05B077008386F4 /* PlayViewController.h */,\n\t\t\t\tFD5A96A91C05B077008386F4 /* PlayViewController.m */,\n\t\t\t\tFD5A96771C05A78A008386F4 /* Main.storyboard */,\n\t\t\t\tFD5A967A1C05A78A008386F4 /* Assets.xcassets */,\n\t\t\t\tFD5A967C1C05A78A008386F4 /* LaunchScreen.storyboard */,\n\t\t\t\tFD5A967F1C05A78A008386F4 /* Info.plist */,\n\t\t\t\tFD5A966E1C05A78A008386F4 /* Supporting Files */,\n\t\t\t);\n\t\t\tpath = MediaHandleDemo;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tFD5A966E1C05A78A008386F4 /* Supporting Files */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tFD5A966F1C05A78A008386F4 /* main.m */,\n\t\t\t);\n\t\t\tname = \"Supporting Files\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tFD5A96871C05A78A008386F4 /* MediaHandleDemoTests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tFD5A96881C05A78A008386F4 /* MediaHandleDemoTests.m */,\n\t\t\t\tFD5A968A1C05A78A008386F4 /* Info.plist */,\n\t\t\t);\n\t\t\tpath = MediaHandleDemoTests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tFD5A96921C05A78A008386F4 /* MediaHandleDemoUITests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tFD5A96931C05A78A008386F4 /* MediaHandleDemoUITests.m */,\n\t\t\t\tFD5A96951C05A78A008386F4 /* Info.plist */,\n\t\t\t);\n\t\t\tpath = MediaHandleDemoUITests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\tFD5A966A1C05A789008386F4 /* MediaHandleDemo */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = FD5A96981C05A78A008386F4 /* Build configuration list for PBXNativeTarget \"MediaHandleDemo\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tFD5A96671C05A789008386F4 /* Sources */,\n\t\t\t\tFD5A96681C05A789008386F4 /* Frameworks */,\n\t\t\t\tFD5A96691C05A789008386F4 /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = MediaHandleDemo;\n\t\t\tproductName = MediaHandleDemo;\n\t\t\tproductReference = FD5A966B1C05A789008386F4 /* MediaHandleDemo.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n\t\tFD5A96831C05A78A008386F4 /* MediaHandleDemoTests */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = FD5A969B1C05A78A008386F4 /* Build configuration list for PBXNativeTarget \"MediaHandleDemoTests\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tFD5A96801C05A78A008386F4 /* Sources */,\n\t\t\t\tFD5A96811C05A78A008386F4 /* Frameworks */,\n\t\t\t\tFD5A96821C05A78A008386F4 /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\tFD5A96861C05A78A008386F4 /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = MediaHandleDemoTests;\n\t\t\tproductName = MediaHandleDemoTests;\n\t\t\tproductReference = FD5A96841C05A78A008386F4 /* MediaHandleDemoTests.xctest */;\n\t\t\tproductType = \"com.apple.product-type.bundle.unit-test\";\n\t\t};\n\t\tFD5A968E1C05A78A008386F4 /* MediaHandleDemoUITests */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = FD5A969E1C05A78A008386F4 /* Build configuration list for PBXNativeTarget \"MediaHandleDemoUITests\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tFD5A968B1C05A78A008386F4 /* Sources */,\n\t\t\t\tFD5A968C1C05A78A008386F4 /* Frameworks */,\n\t\t\t\tFD5A968D1C05A78A008386F4 /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\tFD5A96911C05A78A008386F4 /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = MediaHandleDemoUITests;\n\t\t\tproductName = MediaHandleDemoUITests;\n\t\t\tproductReference = FD5A968F1C05A78A008386F4 /* MediaHandleDemoUITests.xctest */;\n\t\t\tproductType = \"com.apple.product-type.bundle.ui-testing\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\tFD5A96631C05A789008386F4 /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastUpgradeCheck = 0710;\n\t\t\t\tORGANIZATIONNAME = GreatGate;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\tFD5A966A1C05A789008386F4 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 7.1;\n\t\t\t\t\t\tDevelopmentTeam = 6J2XGE456D;\n\t\t\t\t\t};\n\t\t\t\t\tFD5A96831C05A78A008386F4 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 7.1;\n\t\t\t\t\t\tDevelopmentTeam = 6J2XGE456D;\n\t\t\t\t\t\tTestTargetID = FD5A966A1C05A789008386F4;\n\t\t\t\t\t};\n\t\t\t\t\tFD5A968E1C05A78A008386F4 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 7.1;\n\t\t\t\t\t\tDevelopmentTeam = 6J2XGE456D;\n\t\t\t\t\t\tTestTargetID = FD5A966A1C05A789008386F4;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = FD5A96661C05A789008386F4 /* Build configuration list for PBXProject \"MediaHandleDemo\" */;\n\t\t\tcompatibilityVersion = \"Xcode 3.2\";\n\t\t\tdevelopmentRegion = English;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = FD5A96621C05A789008386F4;\n\t\t\tproductRefGroup = FD5A966C1C05A789008386F4 /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\tFD5A966A1C05A789008386F4 /* MediaHandleDemo */,\n\t\t\t\tFD5A96831C05A78A008386F4 /* MediaHandleDemoTests */,\n\t\t\t\tFD5A968E1C05A78A008386F4 /* MediaHandleDemoUITests */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\tFD5A96691C05A789008386F4 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tFD5A967E1C05A78A008386F4 /* LaunchScreen.storyboard in Resources */,\n\t\t\t\tFD5A967B1C05A78A008386F4 /* Assets.xcassets in Resources */,\n\t\t\t\tFD5A96A71C05A7AF008386F4 /* 月半弯.mp3 in Resources */,\n\t\t\t\tFD5A96791C05A78A008386F4 /* Main.storyboard in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tFD5A96821C05A78A008386F4 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tFD5A968D1C05A78A008386F4 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\tFD5A96671C05A789008386F4 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tFD5A96A31C05A7A2008386F4 /* MediaManager.m in Sources */,\n\t\t\t\tFD5A96761C05A78A008386F4 /* ViewController.m in Sources */,\n\t\t\t\tFD5A96731C05A78A008386F4 /* AppDelegate.m in Sources */,\n\t\t\t\tFD5A96AA1C05B077008386F4 /* PlayViewController.m in Sources */,\n\t\t\t\tFD5A96701C05A78A008386F4 /* main.m in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tFD5A96801C05A78A008386F4 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tFD5A96891C05A78A008386F4 /* MediaHandleDemoTests.m in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tFD5A968B1C05A78A008386F4 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tFD5A96941C05A78A008386F4 /* MediaHandleDemoUITests.m in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXTargetDependency section */\n\t\tFD5A96861C05A78A008386F4 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = FD5A966A1C05A789008386F4 /* MediaHandleDemo */;\n\t\t\ttargetProxy = FD5A96851C05A78A008386F4 /* PBXContainerItemProxy */;\n\t\t};\n\t\tFD5A96911C05A78A008386F4 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = FD5A966A1C05A789008386F4 /* MediaHandleDemo */;\n\t\t\ttargetProxy = FD5A96901C05A78A008386F4 /* PBXContainerItemProxy */;\n\t\t};\n/* End PBXTargetDependency section */\n\n/* Begin PBXVariantGroup section */\n\t\tFD5A96771C05A78A008386F4 /* Main.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tFD5A96781C05A78A008386F4 /* Base */,\n\t\t\t);\n\t\t\tname = Main.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tFD5A967C1C05A78A008386F4 /* LaunchScreen.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tFD5A967D1C05A78A008386F4 /* Base */,\n\t\t\t);\n\t\t\tname = LaunchScreen.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXVariantGroup section */\n\n/* Begin XCBuildConfiguration section */\n\t\tFD5A96961C05A78A008386F4 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 9.1;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tFD5A96971C05A78A008386F4 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 9.1;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tFD5A96991C05A78A008386F4 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tINFOPLIST_FILE = MediaHandleDemo/Info.plist;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 8.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.happypool.Push;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tFD5A969A1C05A78A008386F4 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tINFOPLIST_FILE = MediaHandleDemo/Info.plist;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 8.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.happypool.Push;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tFD5A969C1C05A78A008386F4 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tBUNDLE_LOADER = \"$(TEST_HOST)\";\n\t\t\t\tINFOPLIST_FILE = MediaHandleDemoTests/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks @loader_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.happypool.MediaHandleDemoTests;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tTEST_HOST = \"$(BUILT_PRODUCTS_DIR)/MediaHandleDemo.app/MediaHandleDemo\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tFD5A969D1C05A78A008386F4 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tBUNDLE_LOADER = \"$(TEST_HOST)\";\n\t\t\t\tINFOPLIST_FILE = MediaHandleDemoTests/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks @loader_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.happypool.MediaHandleDemoTests;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tTEST_HOST = \"$(BUILT_PRODUCTS_DIR)/MediaHandleDemo.app/MediaHandleDemo\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tFD5A969F1C05A78A008386F4 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tINFOPLIST_FILE = MediaHandleDemoUITests/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks @loader_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.happypool.MediaHandleDemoUITests;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tTEST_TARGET_NAME = MediaHandleDemo;\n\t\t\t\tUSES_XCTRUNNER = YES;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tFD5A96A01C05A78A008386F4 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tINFOPLIST_FILE = MediaHandleDemoUITests/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks @loader_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.happypool.MediaHandleDemoUITests;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tTEST_TARGET_NAME = MediaHandleDemo;\n\t\t\t\tUSES_XCTRUNNER = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\tFD5A96661C05A789008386F4 /* Build configuration list for PBXProject \"MediaHandleDemo\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tFD5A96961C05A78A008386F4 /* Debug */,\n\t\t\t\tFD5A96971C05A78A008386F4 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tFD5A96981C05A78A008386F4 /* Build configuration list for PBXNativeTarget \"MediaHandleDemo\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tFD5A96991C05A78A008386F4 /* Debug */,\n\t\t\t\tFD5A969A1C05A78A008386F4 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t};\n\t\tFD5A969B1C05A78A008386F4 /* Build configuration list for PBXNativeTarget \"MediaHandleDemoTests\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tFD5A969C1C05A78A008386F4 /* Debug */,\n\t\t\t\tFD5A969D1C05A78A008386F4 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t};\n\t\tFD5A969E1C05A78A008386F4 /* Build configuration list for PBXNativeTarget \"MediaHandleDemoUITests\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tFD5A969F1C05A78A008386F4 /* Debug */,\n\t\t\t\tFD5A96A01C05A78A008386F4 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = FD5A96631C05A789008386F4 /* Project object */;\n}\n"
  },
  {
    "path": "MediaHandleDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"self:MediaHandleDemo.xcodeproj\">\n   </FileRef>\n</Workspace>\n"
  },
  {
    "path": "MediaHandleDemo.xcodeproj/xcuserdata/shelin.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Bucket\n   type = \"1\"\n   version = \"2.0\">\n</Bucket>\n"
  },
  {
    "path": "MediaHandleDemo.xcodeproj/xcuserdata/shelin.xcuserdatad/xcschemes/MediaHandleDemo.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"0710\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"FD5A966A1C05A789008386F4\"\n               BuildableName = \"MediaHandleDemo.app\"\n               BlueprintName = \"MediaHandleDemo\"\n               ReferencedContainer = \"container:MediaHandleDemo.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <Testables>\n         <TestableReference\n            skipped = \"NO\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"FD5A96831C05A78A008386F4\"\n               BuildableName = \"MediaHandleDemoTests.xctest\"\n               BlueprintName = \"MediaHandleDemoTests\"\n               ReferencedContainer = \"container:MediaHandleDemo.xcodeproj\">\n            </BuildableReference>\n         </TestableReference>\n         <TestableReference\n            skipped = \"NO\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"FD5A968E1C05A78A008386F4\"\n               BuildableName = \"MediaHandleDemoUITests.xctest\"\n               BlueprintName = \"MediaHandleDemoUITests\"\n               ReferencedContainer = \"container:MediaHandleDemo.xcodeproj\">\n            </BuildableReference>\n         </TestableReference>\n      </Testables>\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"FD5A966A1C05A789008386F4\"\n            BuildableName = \"MediaHandleDemo.app\"\n            BlueprintName = \"MediaHandleDemo\"\n            ReferencedContainer = \"container:MediaHandleDemo.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Release\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"FD5A966A1C05A789008386F4\"\n            BuildableName = \"MediaHandleDemo.app\"\n            BlueprintName = \"MediaHandleDemo\"\n            ReferencedContainer = \"container:MediaHandleDemo.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"FD5A966A1C05A789008386F4\"\n            BuildableName = \"MediaHandleDemo.app\"\n            BlueprintName = \"MediaHandleDemo\"\n            ReferencedContainer = \"container:MediaHandleDemo.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "MediaHandleDemo.xcodeproj/xcuserdata/shelin.xcuserdatad/xcschemes/xcschememanagement.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>SchemeUserState</key>\n\t<dict>\n\t\t<key>MediaHandleDemo.xcscheme</key>\n\t\t<dict>\n\t\t\t<key>orderHint</key>\n\t\t\t<integer>0</integer>\n\t\t</dict>\n\t</dict>\n\t<key>SuppressBuildableAutocreation</key>\n\t<dict>\n\t\t<key>FD5A966A1C05A789008386F4</key>\n\t\t<dict>\n\t\t\t<key>primary</key>\n\t\t\t<true/>\n\t\t</dict>\n\t\t<key>FD5A96831C05A78A008386F4</key>\n\t\t<dict>\n\t\t\t<key>primary</key>\n\t\t\t<true/>\n\t\t</dict>\n\t\t<key>FD5A968E1C05A78A008386F4</key>\n\t\t<dict>\n\t\t\t<key>primary</key>\n\t\t\t<true/>\n\t\t</dict>\n\t</dict>\n</dict>\n</plist>\n"
  },
  {
    "path": "MediaHandleDemoTests/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>BNDL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleSignature</key>\n\t<string>????</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "MediaHandleDemoTests/MediaHandleDemoTests.m",
    "content": "//\n//  MediaHandleDemoTests.m\n//  MediaHandleDemoTests\n//\n//  Created by Shelin on 15/11/25.\n//  Copyright © 2015年 GreatGate. All rights reserved.\n//\n\n#import <XCTest/XCTest.h>\n\n@interface MediaHandleDemoTests : XCTestCase\n\n@end\n\n@implementation MediaHandleDemoTests\n\n- (void)setUp {\n    [super setUp];\n    // Put setup code here. This method is called before the invocation of each test method in the class.\n}\n\n- (void)tearDown {\n    // Put teardown code here. This method is called after the invocation of each test method in the class.\n    [super tearDown];\n}\n\n- (void)testExample {\n    // This is an example of a functional test case.\n    // Use XCTAssert and related functions to verify your tests produce the correct results.\n}\n\n- (void)testPerformanceExample {\n    // This is an example of a performance test case.\n    [self measureBlock:^{\n        // Put the code you want to measure the time of here.\n    }];\n}\n\n@end\n"
  },
  {
    "path": "MediaHandleDemoUITests/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>BNDL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleSignature</key>\n\t<string>????</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "MediaHandleDemoUITests/MediaHandleDemoUITests.m",
    "content": "//\n//  MediaHandleDemoUITests.m\n//  MediaHandleDemoUITests\n//\n//  Created by Shelin on 15/11/25.\n//  Copyright © 2015年 GreatGate. All rights reserved.\n//\n\n#import <XCTest/XCTest.h>\n\n@interface MediaHandleDemoUITests : XCTestCase\n\n@end\n\n@implementation MediaHandleDemoUITests\n\n- (void)setUp {\n    [super setUp];\n    \n    // Put setup code here. This method is called before the invocation of each test method in the class.\n    \n    // In UI tests it is usually best to stop immediately when a failure occurs.\n    self.continueAfterFailure = NO;\n    // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method.\n    [[[XCUIApplication alloc] init] launch];\n    \n    // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.\n}\n\n- (void)tearDown {\n    // Put teardown code here. This method is called after the invocation of each test method in the class.\n    [super tearDown];\n}\n\n- (void)testExample {\n    // Use recording to get started writing UI tests.\n    // Use XCTAssert and related functions to verify your tests produce the correct results.\n}\n\n@end\n"
  },
  {
    "path": "README.md",
    "content": "# VideoEditing\n视频处理之视频截取及添加背景音乐\nVideo processing of the video capture and add background music\n\n这段时间由于工作需要，了解了一些关于iOS中视频处理功能，发现AVFoundation功能强大，今天聊一聊视频截取和添加背景音乐的一些功能，这里面涉及到得一些类类名和方法都比较长，但是用法还是相对简单，主要是能理解多媒体的一些概念，先来介绍一下常用到的几个AVFoundation下得类：\n- AVURLAsset：AVAsset的子类，此类主要用于获取多媒体的信息，包括视频、音频的类型、时长、每秒帧数，其实还可以用来获取视频的指定位置的缩略图。\n- AVMutableCompositionTrack：视频和音频的采集都需要通过这个类，我觉得可以理解为采集的一个视频或音频资源对应一个track对象。\n- AVMutableComposition：这个类点进去你会发现其实它也是AVAsset的子类，对应有一个方法[AVMutableComposition composition]，返回一个nil的AVMutableComposition对象。\n- CMTime：这个时间并不是平时我们说到的分秒的时间，后面用到的时候会再说。\n- AVAssetExportSession：用于合并你采集的视频和音频，最终会保存为一个新文件，可以设置文件的输出类型、路径，以及合并的一个状态AVAssetExportSessionStatus。\n\n这里单独创建了一个工具类MediaManager来做操作\n#####下面是MediaManager.h的方法接口：\n```\n#import <Foundation/Foundation.h>\n#import <UIKit/UIKit.h>\n/**\n 添加音乐完成回调的block\n */\ntypedef void (^MixcompletionBlock)(void);\n@interface MediaManager : NSObject\n/**\n 截取视频并添加背景音乐\n */\n+ (void)addBackgroundMiusicWithVideoUrlStr:(NSURL *)videoUrl audioUrl:(NSURL *)audioUrl andCaptureVideoWithRange:(NSRange)videoRange completion:(MixcompletionBlock)completionHandle;\n\n/**\n 获取多媒体时长\n */\n+ (CGFloat)getMediaDurationWithMediaUrl:(NSString *)mediaUrlStr;\n\n/**\n 获取合并后的多媒体文件路径\n */\n+ (NSString *)getMediaFilePath;\n@end\n\n```\n#####MediaManager.m中方法实现：\n在添加背景音乐的方法中先创建视频和音频对应的AVURLAsset对象\n```\n//AVURLAsset此类主要用于获取媒体信息，包括视频、声音等\n    AVURLAsset* audioAsset = [[AVURLAsset alloc] initWithURL:audioUrl options:nil];\n    AVURLAsset* videoAsset = [[AVURLAsset alloc] initWithURL:videoUrl options:nil];\n    \n    //创建AVMutableComposition对象来添加视频音频资源的AVMutableCompositionTrack\n    AVMutableComposition* mixComposition = [AVMutableComposition composition];\n```\n我们要截取一段视频就一定涉及到截取的时间点和长度，下面来具体介绍一下CMTime和CMTimeRange。\n- CMTime一个用于描述多媒体帧数和播放速率的结构体，可以通过  CMTimeMake(int64_t value, int32_t timescale)  来生成一个CMTime变量，value视频的总帧数，timescale是指每秒视频播放的帧数，视频播放速率，（value / timescale）才是视频实际的秒数时长，timescale一般情况下不改变，截取视频长度通过改变value的值。\n或者通过 CMTimeMakeWithSeconds(Float64 seconds, int32_t preferredTimeScale)  方法也可以，这里的seconds对应的是平时说的秒数，preferredTimeScale是每秒播放的帧数。\n- CMTimeRange有点类似NSRange，只不过它对应的是视频的起始时间点和视频的长度，可以通过方法CMTimeRangeMake(start, duration)创建变量，start起始时间，duration时长，都是CMTime类型。方法中我直接传入NSRange，在内部做了一些转换。\n\n了解完这些就可以开始采集视频音频了，下面是对视频的采集，如果需要也可以去获取视频原有的音轨。\n这里经常会遇到到tracksWithMediaType方法返回empty的数组，导致程序奔溃，我从Stack Overflow弄下来的一段解释：\n\n![屏幕快照 2015-12-02 下午2.25.17.png](http://upload-images.jianshu.io/upload_images/1121012-00e5015d6fb4431c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)\n\n```\n//开始位置startTime\n    CMTime startTime = CMTimeMakeWithSeconds(videoRange.location, videoAsset.duration.timescale);\n    //截取长度videoDuration\n    CMTime videoDuration = CMTimeMakeWithSeconds(videoRange.length, videoAsset.duration.timescale);\n    CMTimeRange videoTimeRange = CMTimeRangeMake(startTime, videoDuration);\n    //视频采集compositionVideoTrack\n    AVMutableCompositionTrack *compositionVideoTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];\n\n#warning 避免数组越界 tracksWithMediaType 找不到对应的文件时候返回空数组\n    //TimeRange截取的范围长度\n    //ofTrack来源\n    //atTime插放在视频的时间位置\n    [compositionVideoTrack insertTimeRange:videoTimeRange ofTrack:([videoAsset tracksWithMediaType:AVMediaTypeVideo].count>0) ? [videoAsset tracksWithMediaType:AVMediaTypeVideo].firstObject : nil atTime:kCMTimeZero error:nil];\n```\n对背景音频的采集\n```\n//声音长度截取范围==视频长度\n    CMTimeRange audioTimeRange = CMTimeRangeMake(kCMTimeZero, videoDuration);\n    \n    //音频采集compositionCommentaryTrack\n    AVMutableCompositionTrack *compositionAudioTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];\n    \n    [compositionAudioTrack insertTimeRange:audioTimeRange ofTrack:([audioAsset tracksWithMediaType:AVMediaTypeAudio].count > 0) ? [audioAsset tracksWithMediaType:AVMediaTypeAudio].firstObject : nil atTime:kCMTimeZero error:nil];\n\n```\n然后就是合并获取的视频和背景音频，这里需要对输出的文件设置保存路径以及文件类型。\n```\n//AVAssetExportSession用于合并文件，导出合并后文件，presetName文件的输出类型\n    AVAssetExportSession *assetExportSession = [[AVAssetExportSession alloc] initWithAsset:mixComposition presetName:AVAssetExportPresetPassthrough];\n    \n    NSString *outPutPath = [NSTemporaryDirectory() stringByAppendingPathComponent:MediaFileName];\n    //混合后的视频输出路径\n    NSURL *outPutPath = [NSURL fileURLWithPath:outPutPath];\n    \n    if ([[NSFileManager defaultManager] fileExistsAtPath:outPutPath])\n    {\n        [[NSFileManager defaultManager] removeItemAtPath:outPutPath error:nil];\n    }\n    \n    //输出视频格式 AVFileTypeMPEG4 AVFileTypeQuickTimeMovie...\n    assetExportSession.outputFileType = AVFileTypeQuickTimeMovie;\n//    NSArray *fileTypes = assetExportSession.\n    \n    assetExportSession.outputURL = outPutPath;\n    //输出文件是否网络优化\n    assetExportSession.shouldOptimizeForNetworkUse = YES;\n    \n    [assetExportSession exportAsynchronouslyWithCompletionHandler:^{\n        completionHandle();\n    }];\n```\n这是获取多媒体文件时长的方法实现。\n```\n+ (CGFloat)getMediaDurationWithMediaUrl:(NSString *)mediaUrlStr {\n    \n    NSURL *mediaUrl = [NSURL URLWithString:mediaUrlStr];\n    AVURLAsset *mediaAsset = [[AVURLAsset alloc] initWithURL:mediaUrl options:nil];\n    CMTime duration = mediaAsset.duration;\n    \n    return duration.value / duration.timescale;    \n}\n```\n最后只要在外部添加背景音乐的方法简单的调用即可。\n\n```\n- (IBAction)addBackgroundmusic:(id)sender {\n    \n    if (_videoUrl && _audioUrl && self.endTextField.text && self.startTextField.text) {\n        \n        [MediaManager addBackgroundMiusicWithVideoUrlStr:_videoUrl audioUrl:_audioUrl andCaptureVideoWithRange:NSMakeRange([self.startTextField.text floatValue], [self.endTextField.text floatValue] - [self.startTextField.text floatValue]) completion:^{\n            NSLog(@\"视频合并完成\");\n        }];\n    }\n}\n```\n"
  }
]