2014年4月24日木曜日

10fpsで動画を作成

- (void)writeImagesAsMovie:(NSArray *)images
                    toPath:(NSString *)path
{
    NSParameterAssert(images);
    NSParameterAssert(path);
    NSAssert((images.count > 0), @"Set least one image.");
    
    NSFileManager *fileManager = [NSFileManager defaultManager];
    
    // 既にファイルがある場合は削除する
    if ([fileManager fileExistsAtPath:path]) {
        [fileManager removeItemAtPath:path error:nil];
    }
    
    // 最初の画像から動画のサイズ指定する
    CGSize size = ((UIImage *)images[0]).size;
    
    NSError *error = nil;
    
    self.videoWriter = [[AVAssetWriter alloc] initWithURL:[NSURL fileURLWithPath:path]
                                                 fileType:AVFileTypeQuickTimeMovie
                                                    error:&error];
    
    if (error) {
        NSLog(@"%@", [error localizedDescription]);
        return;
    }
    
    NSDictionary *outputSettings =
    @{
      AVVideoCodecKey  : AVVideoCodecH264,
      AVVideoWidthKey  : @(size.width),
      AVVideoHeightKey : @(size.height),
      };
    
    AVAssetWriterInput *writerInput = [AVAssetWriterInput
                                       assetWriterInputWithMediaType:AVMediaTypeVideo
                                       outputSettings:outputSettings];
    
    [self.videoWriter addInput:writerInput];
    
    NSDictionary *sourcePixelBufferAttributes =
    @{
      (NSString *)kCVPixelBufferPixelFormatTypeKey : @(kCVPixelFormatType_32ARGB),
      (NSString *)kCVPixelBufferWidthKey           : @(size.width),
      (NSString *)kCVPixelBufferHeightKey          : @(size.height),
      };
    
    AVAssetWriterInputPixelBufferAdaptor *adaptor = [AVAssetWriterInputPixelBufferAdaptor
                                                     assetWriterInputPixelBufferAdaptorWithAssetWriterInput:writerInput
                                                     sourcePixelBufferAttributes:sourcePixelBufferAttributes];
    
    writerInput.expectsMediaDataInRealTime = YES;
    
    // 動画生成開始
    if (![self.videoWriter startWriting]) {
        NSLog(@"Failed to start writing.");
        return;
    }
    
    [self.videoWriter startSessionAtSourceTime:kCMTimeZero];
    
    CVPixelBufferRef buffer = NULL;
    
    int frameCount = 0;
    double durationForEachImage = 0.05;
    int32_t fps = 20;
    
    for (UIImage *image in images) {
        if (adaptor.assetWriterInput.readyForMoreMediaData) {
            //CMTime frameTime = CMTimeMake((int64_t)frameCount * fps * durationForEachImage, fps);
            //CMTime frameTime = CMTimeMake((int64_t)frameCount * 60, 600);
            CMTime frameTime = CMTimeMake(1, 10);
            CMTime lastTime=CMTimeMake(frameCount, 10);
            CMTime presentTime=CMTimeAdd(lastTime, frameTime);

            buffer = [self pixelBufferFromCGImage:image.CGImage];
            
            if (![adaptor appendPixelBuffer:buffer withPresentationTime:presentTime]) {
                NSLog(@"Failed to append buffer. [image : %@]", image);
            }
            
            if(buffer) {
                CVBufferRelease(buffer);
            }
            
            frameCount++;
            NSLog(@"%d",frameCount);
        }
    }
    
    // 動画生成終了
    [writerInput markAsFinished];
    [self.videoWriter finishWritingWithCompletionHandler:^{
        NSLog(@"Finish writing!");
        NSURL *url = [NSURL URLWithString:path];
        
        if ([library videoAtPathIsCompatibleWithSavedPhotosAlbum:url])
        {
            [library writeVideoAtPathToSavedPhotosAlbum:url
                                        completionBlock:^(NSURL *assetURL, NSError *assetError)
             {
                 if (assetError) { }
             }];
        }
    }];
    CVPixelBufferPoolRelease(adaptor.pixelBufferPool);
    
}

- (CVPixelBufferRef)pixelBufferFromCGImage:(CGImageRef)image
{
    NSDictionary *options = @{
                              (NSString *)kCVPixelBufferCGImageCompatibilityKey : @(YES),
                              (NSString *)kCVPixelBufferCGBitmapContextCompatibilityKey: @(YES),
                              };
    
    CVPixelBufferRef pxbuffer = NULL;
    
    CVPixelBufferCreate(kCFAllocatorDefault,
                        CGImageGetWidth(image),
                        CGImageGetHeight(image),
                        kCVPixelFormatType_32ARGB,
                        (__bridge CFDictionaryRef)options,
                        &pxbuffer);
    
    CVPixelBufferLockBaseAddress(pxbuffer, 0);
    void *pxdata = CVPixelBufferGetBaseAddress(pxbuffer);
    
    CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef context = CGBitmapContextCreate(pxdata,
                                                 CGImageGetWidth(image),
                                                 CGImageGetHeight(image),
                                                 8,
                                                 4 * CGImageGetWidth(image),
                                                 rgbColorSpace,
                                                 (CGBitmapInfo)kCGImageAlphaNoneSkipFirst);
    
    CGContextConcatCTM(context, CGAffineTransformMakeRotation(0));
    
    CGAffineTransform flipVertical = CGAffineTransformMake(1, 0, 0, -1, 0, CGImageGetHeight(image));
    
    CGContextConcatCTM(context, flipVertical);
    
    CGAffineTransform flipHorizontal = CGAffineTransformMake(-1.0, 0.0, 0.0, 1.0, CGImageGetWidth(image), 0.0);
    
    CGContextConcatCTM(context, flipHorizontal);
    
    CGContextDrawImage(context, CGRectMake(0, 0, CGImageGetWidth(image), CGImageGetHeight(image)), image);
    CGColorSpaceRelease(rgbColorSpace);
    CGContextRelease(context);
    
    CVPixelBufferUnlockBaseAddress(pxbuffer, 0);
    
    return pxbuffer;

}

5フレームごとにUIImageを取り出す

if(saveMode){
        if([images count] < 50){
            if(saveTime == 0){
                [images addObject:[self createImage]];
            }
            saveTime++;
            if (saveTime == 3)saveTime = 0;
            NSLog(@"%d",[images count]);
        }else{
            saveMode = false;
            NSString *documentPath = (NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0]);
            NSString *moviePath = [documentPath stringByAppendingPathComponent:@"movie.mov"];
            
            [self writeImagesAsMovie:(NSArray *)images
                              toPath:moviePath];
        }

    }

OpenGLの描画内容を画像にする

-(UIImage *)createImage{
    int backingWidth = self.view.bounds.size.width;   // OpenGLのバッファの幅
    int backingHeight = self.view.bounds.size.height;   // OpenGLのバッファの高さ
    
    NSInteger myDataLength = backingWidth * backingHeight * 4;
    GLubyte *buffer = (GLubyte *) malloc(myDataLength);
    glReadPixels(0, 0, backingWidth, backingHeight, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
    
    // FIXME:上下をひっくり返す。この処理が勿体ない。
    GLubyte *buffer2 = (GLubyte *) malloc(myDataLength);
    for(int y = 0; y <backingHeight; y++)
    {
        memcpy(&buffer2[((backingHeight-1) - y) * backingWidth * 4], &buffer[y * 4 * backingWidth], sizeof(GLubyte) * backingWidth * 4);
    }
    free(buffer);
    
    CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, buffer, myDataLength, NULL);
    CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
    CGImageRef imageRef = CGImageCreate(backingWidth, backingHeight, 8, 32, 4 * backingWidth, colorSpaceRef, kCGBitmapByteOrderDefault, provider, NULL, NO, kCGRenderingIntentDefault);
    UIImage *image = [UIImage imageWithCGImage:imageRef];
    return image;


}

カメラロールに保存

[library writeImageToSavedPhotosAlbum:image.CGImage
                              orientation:(ALAssetOrientation)image.imageOrientation
                          completionBlock:
     ^(NSURL *assetURL, NSError *error){
         NSLog(@"URL:%@", assetURL);
         NSLog(@"error:%@", error);
         
         ALAuthorizationStatus status = [ALAssetsLibrary authorizationStatus];
         
         if (status == ALAuthorizationStatusDenied) {
             UIAlertView *alertView = [[UIAlertView alloc]
                                       initWithTitle:@"エラー"
                                       message:@"写真へのアクセスが許可されていません。\n設定 > 一般 > 機能制限で許可してください。"
                                       delegate:nil
                                       cancelButtonTitle:@"OK"
                                       otherButtonTitles:nil];
             [alertView show];
         } else {
             UIAlertView *alertView = [[UIAlertView alloc]
                                       initWithTitle:@""
                                       message:@"フォトアルバムへ保存しました。"
                                       delegate:nil
                                       cancelButtonTitle:@"OK"
                                       otherButtonTitles:nil];
             [alertView show];
         }

     }];

2014年3月12日水曜日

似非マウス回転

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(eye.fovy, (float)eye.width/(float)eye.height, 0.1, 100000);

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(eye.eye[0], eye.eye[1], eye.eye[2],
eye.center[0], eye.center[1], eye.center[2],
eye.up[0], eye.up[1], eye.up[2]);

eye.calcuratePosition(beforePoint,beforeMouse[0],beforeMouse[1]);
eye.calcuratePosition(nowPoint,x,y);
eye.rotateEye(beforePoint,nowPoint);

void Eye::calcuratePosition(double result[3],int x,int y)
{
x -= this->width/2;
y -= this->height/2;
printf("%d,%d\n",x,y);
double rate =  (2.0 * 50.0 * tan(PI/180*this->fovy/2))/height;

printf("%lf\n",rate);
double rateX = x * rate;
double rateY = y * rate;

for (int i = 0;i < 3; i++){
result[i] = 50.0 * this->center[i] + rateX * this->left[i] + rateY * this->up[i];
}
}

void Eye::rotateEye(double start[3],double end[3])
{
double axis[3];
double radius;
vectorNormarise(start);
vectorNormarise(end);

exteriorProduct(start ,end, axis);
vectorNormarise(axis);
radius = acos(innerrProduct(start ,end));

printf("%lf,%lf,%lf\n",start[0],start[1],start[2]);
printf("%lf,%lf,%lf\n",end[0],end[1],end[2]);
printf("%lf,%lf,%lf,%lf\n",axis[0],axis[1],axis[2],radius);

rotateVector(axis,radius,center);
rotateVector(axis,radius,up);
rotateVector(axis,radius,left);
}
void Eye::rotateBy(double axis[3],double radius)
{
rotateVector(axis,radius,center);
rotateVector(axis,radius,up);
rotateVector(axis,radius,left);
printf("%lf,%lf,%lf\n",center[0],center[1],center[2]);
printf("%lf,%lf,%lf\n",up[0],up[1],up[2]);

printf("%lf,%lf,%lf\n",up[0],up[1],up[2]);
}

void exteriorProduct(double vec1[3],double vec2[3],double resullt[3])
{
resullt[0] = vec1[1] * vec2[2] - vec1[2] * vec2[1];
resullt[1] = vec1[2] * vec2[0] - vec1[0] * vec2[2];
resullt[2] = vec1[0] * vec2[1] - vec1[1] * vec2[0];
}
double vectorSize(double vec[3])
{
return sqrt(vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]);
}
void vectorNormarise(double vec1[3])
{
double size = vectorSize(vec1);
vec1[0] /= size;
vec1[1] /= size;
vec1[2] /= size;
}

double innerrProduct(double vec1[3],double vec2[3])
{
return vec1[0]*vec2[0]+vec1[1]*vec2[1]+vec1[2]*vec2[2];
}

void rotateVector(double axis[3],double radius, double vec[3])
{
double matrix[3][3];
matrix[0][0] = axis[0] * axis[0] * (1 - cos(radius)) + cos(radius);
matrix[0][1] = axis[0] * axis[1] * (1 - cos(radius)) - axis[2] * sin(radius);
matrix[0][2] = axis[2] * axis[0] * (1 - cos(radius)) + axis[1] * sin(radius);


matrix[1][0] = axis[0] * axis[1] * (1 - cos(radius)) + axis[2] * sin(radius);
matrix[1][1] = axis[1] * axis[1] * (1 - cos(radius)) + cos(radius);
matrix[1][2] = axis[1] * axis[2] * (1 - cos(radius)) - axis[0] * sin(radius);

matrix[2][0] = axis[2] * axis[0] * (1 - cos(radius)) - axis[1] * sin(radius);
matrix[2][1] = axis[1] * axis[2] * (1 - cos(radius)) + axis[0] * sin(radius);
matrix[2][2] = axis[2] * axis[2] * (1 - cos(radius)) + cos(radius);

double tmp[3];
for (int i = 0;i < 3;i++){
tmp[i] = vec[i];
}
for (int i = 0;i < 3;i++){
vec[i] = tmp[0] * matrix[i][0] + tmp[1] * matrix[i][1] + tmp[2] * matrix[i][2];
}
}

三角形分割

   for(int i=0;i<this->target.size();i++){
  this->points[i]->x = this->target[i]->x;
  this->points[i]->y = this->target[i]->y;
   }
   count = this->target.size();

   for(int i=0;i<this->target.size();i++){
  this->target[i]->calcuRad(&startPoint,
  this->target[this->target[i]->prevNum],
  this->target[this->target[i]->nextNum]);
  if(this->target[i]->radian == 0.0){
  this->target[i]->life =false;
  this->target[this->target[i]->prevNum]->nextNum = this->target[i]->nextNum;
  this->target[this->target[i]->nextNum]->prevNum = this->target[i]->prevNum;
  count--;
  }
  //fprintf(hoge,"%d,%d\n",(int)this->target[i]->x,(int)this->target[i]->y);
   }
   //fclose(hoge);
   int peke;
 
   while(count>2){
  for(int i=0;i<this->target.size();i++){
  if(this->target[i]->radian > 0 && this->target[i]->life){
  Teto *teto = this->createFrom(i);
  if (this->tetoOK(teto) && !this->otherPointsInTeto(teto))
  {
  this->tetos.push_back(teto);
  this->drawTeto(teto,tetosImg);
  this->target[this->target[i]->nextNum]->prevNum = this->target[i]->prevNum;
  this->target[this->target[i]->nextNum]->calcuRad(&startPoint,
this->target[this->target[this->target[i]->nextNum]->prevNum],
this->target[this->target[this->target[i]->nextNum]->nextNum]);
  this->target[this->target[i]->prevNum]->nextNum = this->target[i]->nextNum;
  this->target[this->target[i]->prevNum]->calcuRad(&startPoint,
this->target[this->target[this->target[i]->prevNum]->prevNum],
this->target[this->target[this->target[i]->prevNum]->nextNum]);
  this->target[i]->life = false;
  count--;
  char c = (char)cvWaitKey ( 1 );
  cvShowImage("tetosImg",tetosImg);
  i++;
  }
  }
  }
   }