iOS多张图片合成一个视频


  1. - (void)viewDidLoad  
  2. {  
  3.    [superviewDidLoad];  
  4.     //Do any additional setup after loading the view.  
  5.    imageArr =[[NSMutableArrayalloc]initWithObjects:  
  6.              [UIImageimageNamed:@"1"],[UIImageimageNamed:@"2.jpg"],[UIImageimageNamed:@"3.jpg"],[UIImageimageNamed:@"4.jpg"],[UIImageimageNamed:@"5.jpg"],[UIImageimageNamed:@"6.jpg"],[UIImageimageNamed:@"7.jpg"],[UIImageimageNamed:@"8.jpg"],[UIImageimageNamed:@"9.jpg"],[UIImageimageNamed:@"10.jpg"],[UIImageimageNamed:@"11.jpg"],[UIImageimageNamed:@"12.jpg"],[UIImageimageNamed:@"13.jpg"],[UIImageimageNamed:@"14.jpg"],[UIImageimageNamed:@"15"],[UIImageimageNamed:@"16"],[UIImageimageNamed:@"17"],[UIImageimageNamed:@"18"],[UIImageimageNamed:@"19"],[UIImageimageNamed:@"20"],[UIImageimageNamed:@"21"],[UIImageimageNamed:@"22"],[UIImageimageNamed:@"23"],[UIImageimageNamed:@"24"],[UIImageimageNamed:@"25"],[UIImageimageNamed:@"26"],[UIImageimageNamed:@"27"],[UIImageimageNamed:@"28"],[UIImageimageNamed:@"29"],[UIImageimageNamed:@"30"],[UIImageimageNamed:@"31"],nil];  
  7.      
  8.    UIButton * button =[UIButtonbuttonWithType:UIButtonTypeRoundedRect];  
  9.     [buttonsetFrame:CGRectMake(100,100100,100)];  
  10.    [buttonsetTitle:@"合成"forState:UIControlStateNormal];  
  11.    [buttonaddTarget:selfaction:@selector(testCompressionSession)forControlEvents:UIControlEventTouchUpInside];  
  12.    [self.viewaddSubview:button];  
  13.      
  14.    UIButton * button1 =[UIButtonbuttonWithType:UIButtonTypeRoundedRect];  
  15.     [button1setFrame:CGRectMake(100,200100,100)];  
  16.    [button1setTitle:@"播放"forState:UIControlStateNormal];  
  17.    [button1addTarget:selfaction:@selector(playAction)forControlEvents:UIControlEventTouchUpInside];  
  18.    [self.viewaddSubview:button1];  
  19. }  
  20.   
  21. -(void)testCompressionSession  
  22. {  
  23.    NSLog(@"开始");  
  24.    //NSString *moviePath = [[NSBundle mainBundle]pathForResource:@"Movie" ofType:@"mov"];  
  25.    NSArray *paths =NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);  
  26.    NSString *moviePath =[[pathsobjectAtIndex:0]stringByAppendingPathComponent:[NSStringstringWithFormat:@"%@.mov",@"test"]];  
  27.    self.theVideoPath=moviePath;  
  28.    CGSize size =CGSizeMake(320,400);//定义视频的大小  
  29.      
  30. //    [selfwriteImages:imageArr ToMovieAtPath:moviePath withSize:sizeinDuration:4 byFPS:30];//第2中方法  
  31.   
  32.    NSError *error =nil;  
  33.      
  34.    unlink([moviePathUTF8String]);  
  35.    NSLog(@"path->%@",moviePath);  
  36.    //—-initialize compression engine  
  37.    AVAssetWriter *videoWriter =[[AVAssetWriteralloc]initWithURL:[NSURLfileURLWithPath:moviePath]  
  38.                                                  fileType:AVFileTypeQuickTimeMovie  
  39.                                                    error:&error];  
  40.    NSParameterAssert(videoWriter);  
  41.    if(error)  
  42.       NSLog(@"error =%@", [errorlocalizedDescription]);  
  43.      
  44.    NSDictionary *videoSettings =[NSDictionarydictionaryWithObjectsAndKeys:AVVideoCodecH264,AVVideoCodecKey,  
  45.                              [NSNumbernumberWithInt:size.width],AVVideoWidthKey,  
  46.                              [NSNumbernumberWithInt:size.height],AVVideoHeightKey,nil];  
  47.    AVAssetWriterInput *writerInput =[AVAssetWriterInputassetWriterInputWithMediaType:AVMediaTypeVideooutputSettings:videoSettings];  
  48.      
  49.    NSDictionary*sourcePixelBufferAttributesDictionary =[NSDictionarydictionaryWithObjectsAndKeys:[NSNumbernumberWithInt:kCVPixelFormatType_32ARGB],kCVPixelBufferPixelFormatTypeKey,nil];  
  50.      
  51.    AVAssetWriterInputPixelBufferAdaptor *adaptor =[AVAssetWriterInputPixelBufferAdaptor  
  52.                                             assetWriterInputPixelBufferAdaptorWithAssetWriterInput:writerInputsourcePixelBufferAttributes:sourcePixelBufferAttributesDictionary];  
  53.    NSParameterAssert(writerInput);  
  54.    NSParameterAssert([videoWritercanAddInput:writerInput]);  
  55.      
  56.    if ([videoWritercanAddInput:writerInput])  
  57.       NSLog(@"11111");  
  58.    else  
  59.       NSLog(@"22222");  
  60.      
  61.     [videoWriteraddInput:writerInput];  
  62.      
  63.     [videoWriterstartWriting];  
  64.    [videoWriterstartSessionAtSourceTime:kCMTimeZero];  
  65.      
  66.    //合成多张图片为一个视频文件  
  67.    dispatch_queue_t dispatchQueue =dispatch_queue_create("mediaInputQueue",NULL);  
  68.    int __block frame =0;  
  69.      
  70.    [writerInputrequestMediaDataWhenReadyOnQueue:dispatchQueueusingBlock:^{  
  71.        while([writerInputisReadyForMoreMediaData])  
  72.        {  
  73.           if(++frame >=[imageArrcount]*10)  
  74.            {  
  75.               [writerInputmarkAsFinished];  
  76.               [videoWriterfinishWriting];  
  77. //              [videoWriterfinishWritingWithCompletionHandler:nil];  
  78.              break;  
  79.            }  
  80.             
  81.           CVPixelBufferRef buffer =NULL;  
  82.             
  83.           int idx =frame/10;  
  84.           NSLog(@"idx==%d",idx);  
  85.             
  86.            buffer =(CVPixelBufferRef)[selfpixelBufferFromCGImage:[[imageArrobjectAtIndex:idx]CGImage]size:size];  
  87.             
  88.           if (buffer)  
  89.            {  
  90.              if(![adaptorappendPixelBuffer:bufferwithPresentationTime:CMTimeMake(frame,10)])  
  91.                 NSLog(@"FAIL");  
  92.              else  
  93.                 NSLog(@"OK");  
  94.                 CFRelease(buffer);  
  95.            }  
  96.        }  
  97.     }];  
  98. }  
  99.   
  100. - (CVPixelBufferRef)pixelBufferFromCGImage:(CGImageRef)imagesize:(CGSize)size  
  101. {  
  102.    NSDictionary *options =[NSDictionarydictionaryWithObjectsAndKeys:  
  103.                         [NSNumbernumberWithBool:YES],kCVPixelBufferCGImageCompatibilityKey,  
  104.                         [NSNumbernumberWithBool:YES],kCVPixelBufferCGBitmapContextCompatibilityKey,nil];  
  105.    CVPixelBufferRef pxbuffer =NULL;  
  106.    CVReturn status =CVPixelBufferCreate(kCFAllocatorDefault,size.width,size.height,kCVPixelFormatType_32ARGB,(__bridgeCFDictionaryRef) options,&pxbuffer);  
  107.      
  108.    NSParameterAssert(status ==kCVReturnSuccess && pxbuffer !=NULL);  
  109.      
  110.    CVPixelBufferLockBaseAddress(pxbuffer,0);  
  111.    voidvoid *pxdata =CVPixelBufferGetBaseAddress(pxbuffer);  
  112.    NSParameterAssert(pxdata !=NULL);  
  113.      
  114.    CGColorSpaceRef rgbColorSpace=CGColorSpaceCreateDeviceRGB();  
  115.    CGContextRef context =CGBitmapContextCreate(pxdata,size.width,size.height,8,4*size.width,rgbColorSpace,kCGImageAlphaPremultipliedFirst);  
  116.    NSParameterAssert(context);  
  117.      
  118.    CGContextDrawImage(context,CGRectMake(0,0,CGImageGetWidth(image),CGImageGetHeight(image)), image);  
  119.      
  120.    CGColorSpaceRelease(rgbColorSpace);  
  121.    CGContextRelease(context);   
  122.      
  123.    CVPixelBufferUnlockBaseAddress(pxbuffer,0);   
  124.      
  125.    return pxbuffer;  
  126. }  
  127.   
  128. -(void)playAction  
  129. {  
  130.    MPMoviePlayerViewController *theMovie =[[MPMoviePlayerViewControlleralloc]initWithContentURL:[NSURLfileURLWithPath:self.theVideoPath]];  
  131.    [selfpresentMoviePlayerViewControllerAnimated:theMovie];  
  132.    theMovie.moviePlayer.movieSourceType=MPMovieSourceTypeFile;  
  133.    [theMovie.moviePlayerplay];  
  134. }  
  135.   
  136.   
  137. //第二种方式  
  138. - (void)writeImages:(NSArray *)imagesArrayToMovieAtPath:(NSString *) pathwithSize:(CGSize) size  
  139.         inDuration:(float)durationbyFPS:(int32_t)fps{  
  140.    //Wire the writer:  
  141.    NSError *error =nil;  
  142.    AVAssetWriter *videoWriter =[[AVAssetWriteralloc]initWithURL:[NSURLfileURLWithPath:path]  
  143.                                                   fileType:AVFileTypeQuickTimeMovie  
  144.                                                     error:&error];  
  145.    NSParameterAssert(videoWriter);  
  146.      
  147.    NSDictionary *videoSettings =[NSDictionarydictionaryWithObjectsAndKeys:  
  148.                              AVVideoCodecH264,AVVideoCodecKey,  
  149.                              [NSNumbernumberWithInt:size.width],AVVideoWidthKey,  
  150.                              [NSNumbernumberWithInt:size.height],AVVideoHeightKey,  
  151.                              nil nil];  
  152.      
  153.    AVAssetWriterInput* videoWriterInput =[AVAssetWriterInput  
  154.                                      assetWriterInputWithMediaType:AVMediaTypeVideo  
  155.                                      outputSettings:videoSettings];  
  156.      
  157.      
  158.    AVAssetWriterInputPixelBufferAdaptor *adaptor =[AVAssetWriterInputPixelBufferAdaptor  
  159.                                             assetWriterInputPixelBufferAdaptorWithAssetWriterInput:videoWriterInput  
  160.                                             sourcePixelBufferAttributes:nil];  
  161.    NSParameterAssert(videoWriterInput);  
  162.    NSParameterAssert([videoWritercanAddInput:videoWriterInput]);  
  163.     [videoWriteraddInput:videoWriterInput];  
  164.      
  165.    //Start a session:  
  166.     [videoWriterstartWriting];  
  167.    [videoWriterstartSessionAtSourceTime:kCMTimeZero];  
  168.      
  169.    //Write some samples:  
  170.    CVPixelBufferRef buffer =NULL;  
  171.      
  172.    int frameCount =0;  
  173.      
  174.    int imagesCount = [imagesArraycount];  
  175.    float averageTime =duration/imagesCount;  
  176.    int averageFrame =(int)(averageTime * fps);  
  177.      
  178.    for(UIImage *img in imagesArray)  
  179.     {  
  180.        buffer=[selfpixelBufferFromCGImage:[imgCGImage]size:size];  
  181.        BOOL append_ok =NO;  
  182.        int j =0;  
  183.        while (!append_ok&& j <</b> 30)  
  184.        {  
  185.           if(adaptor.assetWriterInput.readyForMoreMediaData)  
  186.            {  
  187.              printf("appending %d attemp%d\n", frameCount, j);  
  188.                 
  189.              CMTime frameTime =CMTimeMake(frameCount,(int32_t)fps);  
  190.               floatframeSeconds =CMTimeGetSeconds(frameTime);  
  191.              NSLog(@"frameCount:%d,kRecordingFPS:%d,frameSeconds:%f",frameCount,fps,frameSeconds);  
  192.               append_ok = [adaptorappendPixelBuffer:bufferwithPresentationTime:frameTime];  
  193.                 
  194.              if(buffer)  
  195.                  [NSThreadsleepForTimeInterval:0.05];  
  196.            }  
  197.           else  
  198.            {  
  199.              printf("adaptor not ready %d,%d\n", frameCount, j);  
  200.              [NSThreadsleepForTimeInterval:0.1];  
  201.            }  
  202.           j++;  
  203.        }  
  204.        if (!append_ok){  
  205.          printf("error appendingimage %d times %d\n", frameCount, j);  
  206.        }  
  207.          
  208.        frameCount = frameCount + averageFrame;  
  209.     }  
  210.      
  211.    //Finish the session:  
  212.     [videoWriterInputmarkAsFinished];  
  213.     [videoWriterfinishWriting];  
  214.    NSLog(@"finishWriting");  
  215. }  
  216.   
  217. <span style="font-size:18px;color:#ff6600;">推荐一个别人写好的<a target=_blank href="https://github.com/HarrisonJackson/HJImagesToVideo">https://github.com/HarrisonJackson/HJImagesToVideo</a></span>  
- (void)viewDidLoad
{
   [superviewDidLoad];
    //Do any additional setup after loading the view.
   imageArr =[[NSMutableArrayalloc]initWithObjects:
             [UIImageimageNamed:@"1"],[UIImageimageNamed:@"2.jpg"],[UIImageimageNamed:@"3.jpg"],[UIImageimageNamed:@"4.jpg"],[UIImageimageNamed:@"5.jpg"],[UIImageimageNamed:@"6.jpg"],[UIImageimageNamed:@"7.jpg"],[UIImageimageNamed:@"8.jpg"],[UIImageimageNamed:@"9.jpg"],[UIImageimageNamed:@"10.jpg"],[UIImageimageNamed:@"11.jpg"],[UIImageimageNamed:@"12.jpg"],[UIImageimageNamed:@"13.jpg"],[UIImageimageNamed:@"14.jpg"],[UIImageimageNamed:@"15"],[UIImageimageNamed:@"16"],[UIImageimageNamed:@"17"],[UIImageimageNamed:@"18"],[UIImageimageNamed:@"19"],[UIImageimageNamed:@"20"],[UIImageimageNamed:@"21"],[UIImageimageNamed:@"22"],[UIImageimageNamed:@"23"],[UIImageimageNamed:@"24"],[UIImageimageNamed:@"25"],[UIImageimageNamed:@"26"],[UIImageimageNamed:@"27"],[UIImageimageNamed:@"28"],[UIImageimageNamed:@"29"],[UIImageimageNamed:@"30"],[UIImageimageNamed:@"31"],nil];
   
   UIButton * button =[UIButtonbuttonWithType:UIButtonTypeRoundedRect];
    [buttonsetFrame:CGRectMake(100,100, 100,100)];
   [buttonsetTitle:@"合成"forState:UIControlStateNormal];
   [buttonaddTarget:selfaction:@selector(testCompressionSession)forControlEvents:UIControlEventTouchUpInside];
   [self.viewaddSubview:button];
   
   UIButton * button1 =[UIButtonbuttonWithType:UIButtonTypeRoundedRect];
    [button1setFrame:CGRectMake(100,200, 100,100)];
   [button1setTitle:@"播放"forState:UIControlStateNormal];
   [button1addTarget:selfaction:@selector(playAction)forControlEvents:UIControlEventTouchUpInside];
   [self.viewaddSubview:button1];
}

-(void)testCompressionSession
{
   NSLog(@"开始");
   //NSString *moviePath = [[NSBundle mainBundle]pathForResource:@"Movie" ofType:@"mov"];
   NSArray *paths =NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
   NSString *moviePath =[[pathsobjectAtIndex:0]stringByAppendingPathComponent:[NSStringstringWithFormat:@"%@.mov",@"test"]];
   self.theVideoPath=moviePath;
   CGSize size =CGSizeMake(320,400);//定义视频的大小
   
//    [selfwriteImages:imageArr ToMovieAtPath:moviePath withSize:sizeinDuration:4 byFPS:30];//第2中方法

   NSError *error =nil;
   
   unlink([moviePathUTF8String]);
   NSLog(@"path->%@",moviePath);
   //—-initialize compression engine
   AVAssetWriter *videoWriter =[[AVAssetWriteralloc]initWithURL:[NSURLfileURLWithPath:moviePath]
                                                 fileType:AVFileTypeQuickTimeMovie
                                                   error:&error];
   NSParameterAssert(videoWriter);
   if(error)
      NSLog(@"error =%@", [errorlocalizedDescription]);
   
   NSDictionary *videoSettings =[NSDictionarydictionaryWithObjectsAndKeys:AVVideoCodecH264,AVVideoCodecKey,
                             [NSNumbernumberWithInt:size.width],AVVideoWidthKey,
                             [NSNumbernumberWithInt:size.height],AVVideoHeightKey,nil];
   AVAssetWriterInput *writerInput =[AVAssetWriterInputassetWriterInputWithMediaType:AVMediaTypeVideooutputSettings:videoSettings];
   
   NSDictionary*sourcePixelBufferAttributesDictionary =[NSDictionarydictionaryWithObjectsAndKeys:[NSNumbernumberWithInt:kCVPixelFormatType_32ARGB],kCVPixelBufferPixelFormatTypeKey,nil];
   
   AVAssetWriterInputPixelBufferAdaptor *adaptor =[AVAssetWriterInputPixelBufferAdaptor
                                            assetWriterInputPixelBufferAdaptorWithAssetWriterInput:writerInputsourcePixelBufferAttributes:sourcePixelBufferAttributesDictionary];
   NSParameterAssert(writerInput);
   NSParameterAssert([videoWritercanAddInput:writerInput]);
   
   if ([videoWritercanAddInput:writerInput])
      NSLog(@"11111");
   else
      NSLog(@"22222");
   
    [videoWriteraddInput:writerInput];
   
    [videoWriterstartWriting];
   [videoWriterstartSessionAtSourceTime:kCMTimeZero];
   
   //合成多张图片为一个视频文件
   dispatch_queue_t dispatchQueue =dispatch_queue_create("mediaInputQueue",NULL);
   int __block frame =0;
   
   [writerInputrequestMediaDataWhenReadyOnQueue:dispatchQueueusingBlock:^{
       while([writerInputisReadyForMoreMediaData])
       {
          if(++frame >=[imageArrcount]*10)
           {
              [writerInputmarkAsFinished];
              [videoWriterfinishWriting];
//              [videoWriterfinishWritingWithCompletionHandler:nil];
             break;
           }
          
          CVPixelBufferRef buffer =NULL;
          
          int idx =frame/10;
          NSLog(@"idx==%d",idx);
          
           buffer =(CVPixelBufferRef)[selfpixelBufferFromCGImage:[[imageArrobjectAtIndex:idx]CGImage]size:size];
          
          if (buffer)
           {
             if(![adaptorappendPixelBuffer:bufferwithPresentationTime:CMTimeMake(frame,10)])
                NSLog(@"FAIL");
             else
                NSLog(@"OK");
                CFRelease(buffer);
           }
       }
    }];
}

- (CVPixelBufferRef)pixelBufferFromCGImage:(CGImageRef)imagesize:(CGSize)size
{
   NSDictionary *options =[NSDictionarydictionaryWithObjectsAndKeys:
                        [NSNumbernumberWithBool:YES],kCVPixelBufferCGImageCompatibilityKey,
                        [NSNumbernumberWithBool:YES],kCVPixelBufferCGBitmapContextCompatibilityKey,nil];
   CVPixelBufferRef pxbuffer =NULL;
   CVReturn status =CVPixelBufferCreate(kCFAllocatorDefault,size.width,size.height,kCVPixelFormatType_32ARGB,(__bridgeCFDictionaryRef) options,&pxbuffer);
   
   NSParameterAssert(status ==kCVReturnSuccess && pxbuffer !=NULL);
   
   CVPixelBufferLockBaseAddress(pxbuffer,0);
   void *pxdata =CVPixelBufferGetBaseAddress(pxbuffer);
   NSParameterAssert(pxdata !=NULL);
   
   CGColorSpaceRef rgbColorSpace=CGColorSpaceCreateDeviceRGB();
   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);
   CGContextRelease(context); 
   
   CVPixelBufferUnlockBaseAddress(pxbuffer,0); 
   
   return pxbuffer;
}

-(void)playAction
{
   MPMoviePlayerViewController *theMovie =[[MPMoviePlayerViewControlleralloc]initWithContentURL:[NSURLfileURLWithPath:self.theVideoPath]];
   [selfpresentMoviePlayerViewControllerAnimated:theMovie];
   theMovie.moviePlayer.movieSourceType=MPMovieSourceTypeFile;
   [theMovie.moviePlayerplay];
}


//第二种方式
- (void)writeImages:(NSArray *)imagesArrayToMovieAtPath:(NSString *) pathwithSize:(CGSize) size
        inDuration:(float)durationbyFPS:(int32_t)fps{
   //Wire the writer:
   NSError *error =nil;
   AVAssetWriter *videoWriter =[[AVAssetWriteralloc]initWithURL:[NSURLfileURLWithPath:path]
                                                  fileType:AVFileTypeQuickTimeMovie
                                                    error:&error];
   NSParameterAssert(videoWriter);
   
   NSDictionary *videoSettings =[NSDictionarydictionaryWithObjectsAndKeys:
                             AVVideoCodecH264,AVVideoCodecKey,
                             [NSNumbernumberWithInt:size.width],AVVideoWidthKey,
                             [NSNumbernumberWithInt:size.height],AVVideoHeightKey,
                             nil];
   
   AVAssetWriterInput* videoWriterInput =[AVAssetWriterInput
                                     assetWriterInputWithMediaType:AVMediaTypeVideo
                                     outputSettings:videoSettings];
   
   
   AVAssetWriterInputPixelBufferAdaptor *adaptor =[AVAssetWriterInputPixelBufferAdaptor
                                            assetWriterInputPixelBufferAdaptorWithAssetWriterInput:videoWriterInput
                                            sourcePixelBufferAttributes:nil];
   NSParameterAssert(videoWriterInput);
   NSParameterAssert([videoWritercanAddInput:videoWriterInput]);
    [videoWriteraddInput:videoWriterInput];
   
   //Start a session:
    [videoWriterstartWriting];
   [videoWriterstartSessionAtSourceTime:kCMTimeZero];
   
   //Write some samples:
   CVPixelBufferRef buffer =NULL;
   
   int frameCount =0;
   
   int imagesCount = [imagesArraycount];
   float averageTime =duration/imagesCount;
   int averageFrame =(int)(averageTime * fps);
   
   for(UIImage *img in imagesArray)
    {
       buffer=[selfpixelBufferFromCGImage:[imgCGImage]size:size];
       BOOL append_ok =NO;
       int j =0;
       while (!append_ok&& j <</b> 30)
       {
          if(adaptor.assetWriterInput.readyForMoreMediaData)
           {
             printf("appending %d attemp%d\n", frameCount, j);
              
             CMTime frameTime =CMTimeMake(frameCount,(int32_t)fps);
              floatframeSeconds =CMTimeGetSeconds(frameTime);
             NSLog(@"frameCount:%d,kRecordingFPS:%d,frameSeconds:%f",frameCount,fps,frameSeconds);
              append_ok = [adaptorappendPixelBuffer:bufferwithPresentationTime:frameTime];
              
             if(buffer)
                 [NSThreadsleepForTimeInterval:0.05];
           }
          else
           {
             printf("adaptor not ready %d,%d\n", frameCount, j);
             [NSThreadsleepForTimeInterval:0.1];
           }
          j++;
       }
       if (!append_ok){
         printf("error appendingimage %d times %d\n", frameCount, j);
       }
       
       frameCount = frameCount + averageFrame;
    }
   
   //Finish the session:
    [videoWriterInputmarkAsFinished];
    [videoWriterfinishWriting];
   NSLog(@"finishWriting");
}

<span style="font-size:18px;color:#ff6600;">推荐一个别人写好的<a target=_blank href="https://github.com/HarrisonJackson/HJImagesToVideo">https://github.com/HarrisonJackson/HJImagesToVideo</a></span>


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值