iPhone: Программное сжатие записанного видео для совместного использования?

#iphone

#iPhone

Вопрос:

Я реализовал режим наложения при вызове режима просмотра с камеры перед записью видео.

 pickerController.cameraOverlayView =myOverlay;
  

Запись видео и сохранение видео в альбом после записи видео и обмена по электронной почте и т.д. все работает нормально.

Если я использую качество видео как «Высокое качество», то записанное видео приобретает огромный размер. Например, если я записываю видео в течение 30 секунд с высоким качеством, объем записанного видео составляет около 30-40 мб.

 pickerController.videoQuality = UIImagePickerControllerQualityTypeHigh;
  

Как мне запрограммировать сжатие высококачественного записанного видео перед его совместным использованием, например, как это делает Apple со встроенным видеомагнитофоном?

Пожалуйста, помогите мне решить эту проблему.

Спасибо!

ОБНОВЛЕНО:

Это то, что я пытаюсь недавно, но по-прежнему безуспешно: я хочу сжать записанное видео, которое поступает в didFinishPickingMediaWithInfo, и сохранить в том же фотоальбоме сам путь к видео, а не где-либо еще. Я тестировал, что одно и то же видео сжимается до очень маленького размера, когда я выбираю из библиотеки фотографий, но то же видео, снятое с камеры и переданное через didFinishPickingMediaWithInfo, не сжимается, хотя я использовал приведенный ниже код AVAssetExportSession.

 - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{

    NSString *mediaType = [info objectForKey:UIImagePickerControllerMediaType];


if ([mediaType isEqualToString:(NSString *)kUTTypeMovie])
{

    NSURL *videoURL = [info objectForKey:UIImagePickerControllerMediaURL];
    NSString *urlPath = [videoURL path];

    if ([[urlPath lastPathComponent] isEqualToString:@"capturedvideo.MOV"])
    {
        if (UIVideoAtPathIsCompatibleWithSavedPhotosAlbum (urlPath))
        {
            [self copyTempVideoToMediaLibrary :urlPath];


        }
        else
        {
            NSLog(@"Video Capture Error: Captured video cannot be saved...didFinishPickingMediaWithInfo()");                
        }
    }       
    else
    {
        NSLog(@"Processing soon to saved photos album...else loop of lastPathComponent..didFinishPickingMediaWithInfo()");
    }
}    
[self dismissModalViewControllerAnimated:YES];
}

- (void)copyTempVideoToMediaLibrary :(NSString *)videoURL {

        dispatch_queue_t mainQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

dispatch_async(mainQueue, ^{

    ALAssetsLibrary *library = [[[ALAssetsLibrary alloc] init] autorelease];

    ALAssetsLibraryWriteVideoCompletionBlock completionBlock = ^(NSURL *assetURL, NSError *error) {
        NSLog(@"Saved URL: %@", assetURL);
        NSLog(@"Error: %@", error);

        if (assetURL != nil) {

            AVURLAsset *theAsset = [AVURLAsset URLAssetWithURL:[NSURL URLWithString:videoURL] options:nil];

            NSArray *compatiblePresets = [AVAssetExportSession exportPresetsCompatibleWithAsset:theAsset];

            AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:theAsset presetName:AVAssetExportPresetLowQuality];

            [exportSession setOutputURL:[NSURL URLWithString:videoURL]];
            [exportSession setOutputFileType:AVFileTypeQuickTimeMovie];

            [exportSession exportAsynchronouslyWithCompletionHandler:^ {
                switch ([exportSession status]) {
                    case AVAssetExportSessionStatusFailed:
                        NSLog(@"Export session faied with error: %@", [exportSession error]);
                        break;
                    default:
                        //[self mediaIsReady];
                        break;
                }
            }];
        }
    };

    [library writeVideoAtPathToSavedPhotosAlbum:[NSURL URLWithString:videoURL] completionBlock:completionBlock];
});
}
  

Комментарии:

1. В чем разница между снижением качества видео и его сжатием? Или вы имеете в виду сжатие, подобное архивированию?

Ответ №1:

Если вы хотите сжать видео для удаленного совместного использования и сохранить исходное качество для локального хранения на iPhone, вам следует обратиться к AVAssetExportSession или AVAssetWriter.

Также прочитайте о том, как iOS управляет ресурсами.

 - (void)convertVideoToLowQuailtyWithInputURL:(NSURL*)inputURL 
                                   outputURL:(NSURL*)outputURL 
                                     handler:(void (^)(AVAssetExportSession*))handler
{
    [[NSFileManager defaultManager] removeItemAtURL:outputURL error:nil];
    AVURLAsset *asset = [AVURLAsset URLAssetWithURL:inputURL options:nil];
    AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:asset presetName:AVAssetExportPresetLowQuality];
    exportSession.outputURL = outputURL;
    exportSession.outputFileType = AVFileTypeQuickTimeMovie;
    [exportSession exportAsynchronouslyWithCompletionHandler:^(void) 
    {
        handler(exportSession);
        [exportSession release];
    }];
}

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info

{   
    NSURL *videoURL = [info objectForKey:UIImagePickerControllerMediaURL];
    NSURL *outputURL = [NSURL fileURLWithPath:@"/Users/josh/Desktop/output.mov"];
    [self convertVideoToLowQuailtyWithInputURL:videoURL outputURL:outputURL handler:^(AVAssetExportSession *exportSession)
     {
         if (exportSession.status == AVAssetExportSessionStatusCompleted)
         {
             printf("completedn");
         }
         else
         {
             printf("errorn");

         }
     }];

}
  

Комментарии:

1. Привет, Джоджаба, я все еще борюсь с этим. Я использую UIImagePickerController для съемки видео / выбора из библиотеки фотографий, при съемке видео из библиотеки фотографий видео сжимается (сообщение также отображается как сжатие ..), когда нажимаю «Выбрать», но если я разрешаю снимать видео с камеры, а затем нажимаю «Использовать», это не приводит к сжатию снятого видео. Возможно ли сжать видео при нажатии на «Использовать»? Почему это не работает по умолчанию, когда я использую API UIImagePickerController?

2. Привет, спасибо. Я уже пробовал то же самое, но безуспешно. пожалуйста, проверьте мой обновленный код выше и дайте мне знать, что я делаю не так. Пожалуйста, помогите с этим.

3. Привет, я обнаружил, что если мы уменьшаем качество до более низкого, то фактическое записанное видео в формате HD (720p) становится более низкого качества, что не является фактическим видео в формате HD. Мое требование заключается в том, как сохранить видео с тем же размером (720p), но уменьшить размер видео перед загрузкой (отправкой) на мой сервер.

4. Вы пользовались приложением «Фотографии»? Если вы используете кнопку «Поделиться на Youtube», Apple, похоже, может сжимать видео в формате 720p, при этом результирующий файл сохраняет относительно высокое качество, а размер файла уменьшается. Как они это делают?

5. @etayluz По моему опыту, AVAssetWriter предназначен для специализированного мультиплексирования видео и аудио. Например, если у вас есть видео в формате h264 и аудио в формате raw 16-битного файла PCM, вы можете сжать аудио AAC, а затем использовать AVAssetWriter для объединения h264 AAC в файл, совместимый с MPEG4 или Quicktime. С другой стороны, AVAssetExportSession полезен для извлечения уже отформатированного файла MPEG4 / Quicktime и повторного сжатия для уменьшения битрейта.

Ответ №2:

Я предполагаю, что видео уже сжато кодеком h264. Но вы можете попробовать использовать AVFoundation для захвата видеофайлов с камеры. Но я подозреваю, что в итоге вы получите файлы того же размера.

Вот некоторые статистические данные для 10-секундного видеофайла, записанного на iPhone 4 с разным качеством нажатия.

 high (1280х720) = ~14MB = ~11Mbit/s
640 (640х480) = ~4MB = ~3.2Mbit/s
medium (360х480) = ~1MB = ~820Kbit/s
low (144х192) = ~208KB = ~170Kbit/s
  

Комментарии:

1. Спасибо за эту информацию. Прямо здесь вы можете увидеть проблему … 14 МБ — это слишком много для 10-секундного видео. и в результате падение до 480p значительно снижает качество

2. Примечание: Это не относится к более новым моделям iPhone — например, iPhone 5,5 s и т.д.

Ответ №3:

 pickerController.videoQuality = UIImagePickerControllerQualityTypeMedium;
  

Это все значения, которые вы можете выбрать.

 UIImagePickerControllerQualityTypeHigh    = 0,
UIImagePickerControllerQualityType640x480 = 3,
UIImagePickerControllerQualityTypeMedium  = 1,  // default value
UIImagePickerControllerQualityTypeLow     = 2
  

Комментарии:

1. Не уверен, что у кого-нибудь еще есть эта проблема, но когда я меняю качество выбора (показано выше), это не меняет размер моего файла =

Ответ №4:

Программное сжатие видео с использованием swift

И не забыл добавить — импортировать AssetsLibrary

 func convertVideoWithMediumQuality(inputURL : NSURL){

            let VideoFilePath = NSURL(fileURLWithPath: NSTemporaryDirectory()).URLByAppendingPathComponent("mergeVideo(arc4random()%1000)d").URLByAppendingPathExtension("mp4").absoluteString
            if NSFileManager.defaultManager().fileExistsAtPath(VideoFilePath) {
                do {
                    try NSFileManager.defaultManager().removeItemAtPath(VideoFilePath)
                } catch { }
            } 

            let savePathUrl =  NSURL(string: VideoFilePath)!

            let sourceAsset = AVURLAsset(URL: inputURL, options: nil)

            let assetExport: AVAssetExportSession = AVAssetExportSession(asset: sourceAsset, presetName: AVAssetExportPresetMediumQuality)!
            assetExport.outputFileType = AVFileTypeQuickTimeMovie
            assetExport.outputURL = savePathUrl
            assetExport.exportAsynchronouslyWithCompletionHandler { () -> Void in

                switch assetExport.status {
                case AVAssetExportSessionStatus.Completed:
                    dispatch_async(dispatch_get_main_queue(), {
                        do {
                            let videoData = try NSData(contentsOfURL: savePathUrl, options: NSDataReadingOptions())
                            print("MB - (videoData.length / (1024 * 1024))")
                        } catch {
                            print(error)
                        }

                    })
                case  AVAssetExportSessionStatus.Failed:
                    self.hideActivityIndicator(self.view)
                    print("failed (assetExport.error)")
                case AVAssetExportSessionStatus.Cancelled:
                    self.hideActivityIndicator(self.view)
                    print("cancelled (assetExport.error)")
                default:
                    self.hideActivityIndicator(self.view)
                    print("complete")
                }
            }

        }
  

Комментарии:

1. Прохладный. Однако зачем использовать случайное имя файла? Это выглядит подозрительно. Если вы вызывали это несколько раз и хотите избежать конфликтов имен, использование случайного имени файла не всегда будет работать и приведет к проблемам. Если вы вызываете это только по одному за раз, вам не нужно случайное имя файла. Я рекомендую использовать более детерминированную схему именования (счетчики и т.д.)

2. Эта строка является основной, где размер сжатия видео является дескриптором пусть assetExport: AVAssetExportSession = AVAssetExportSession(ресурс: исходный код, предустановленное имя: AVAssetExportPresetMediumQuality)!

Ответ №5:

Попробуйте эти несколько строк :

     [[NSFileManager defaultManager] removeItemAtURL:outputURL error:nil];
    AVURLAsset *urlAsset = [AVURLAsset URLAssetWithURL:inputURL options:nil];
    AVAssetExportSession *session = [[AVAssetExportSession alloc] initWithAsset: urlAsset presetName:AVAssetExportPresetLowQuality];
    session.outputURL = outputURL;
    session.outputFileType = AVFileTypeQuickTimeMovie;
    [session exportAsynchronouslyWithCompletionHandler:^(void) 
    {
        handler(session);

    }];
  

Ответ №6:

Я нашел отличный пользовательский класс (SDAVAssetExportSession) для сжатия видео. Вы можете загрузить его по этой ссылке.

После загрузки добавьте SDAVAssetExportSession.добавьте файлы h и SDAVAssetExportSession.m в ваш проект, тогда приведенный ниже код поможет выполнить сжатие. В приведенном ниже коде вы можете сжимать видео, указывая разрешение и битрейт

 #import "SDAVAssetExportSession.h"


- (void)compressVideoWithInputVideoUrl:(NSURL *) inputVideoUrl
{
    /* Create Output File Url */

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSString *finalVideoURLString = [documentsDirectory stringByAppendingPathComponent:@"compressedVideo.mp4"];
    NSURL *outputVideoUrl = ([[NSURL URLWithString:finalVideoURLString] isFileURL] == 1)?([NSURL URLWithString:finalVideoURLString]):([NSURL fileURLWithPath:finalVideoURLString]); // Url Should be a file Url, so here we check and convert it into a file Url


    SDAVAssetExportSession *compressionEncoder = [SDAVAssetExportSession.alloc initWithAsset:[AVAsset assetWithURL:inputVideoUrl]]; // provide inputVideo Url Here
    compressionEncoder.outputFileType = AVFileTypeMPEG4;
    compressionEncoder.outputURL = outputVideoUrl; //Provide output video Url here
    compressionEncoder.videoSettings = @
    {
    AVVideoCodecKey: AVVideoCodecH264,
    AVVideoWidthKey: @800,   //Set your resolution width here
    AVVideoHeightKey: @600,  //set your resolution height here
    AVVideoCompressionPropertiesKey: @
        {
        AVVideoAverageBitRateKey: @45000, // Give your bitrate here for lower size give low values
        AVVideoProfileLevelKey: AVVideoProfileLevelH264High40,
        },
    };
    compressionEncoder.audioSettings = @
    {
    AVFormatIDKey: @(kAudioFormatMPEG4AAC),
    AVNumberOfChannelsKey: @2,
    AVSampleRateKey: @44100,
    AVEncoderBitRateKey: @128000,
    };

    [compressionEncoder exportAsynchronouslyWithCompletionHandler:^
     {
         if (compressionEncoder.status == AVAssetExportSessionStatusCompleted)
         {
            NSLog(@"Compression Export Completed Successfully");
         }
         else if (compressionEncoder.status == AVAssetExportSessionStatusCancelled)
         {
             NSLog(@"Compression Export Canceled");
         }
         else
         {
              NSLog(@"Compression Failed");

         }
     }];

}
  

Чтобы отменить сжатие, используйте приведенную ниже строку кода

  [compressionEncoder cancelExport]; //Video compression cancel
  

Комментарии:

1. Я получаю ошибку как -[AVAssetWriter startSessionAtSourceTime:] недопустимый параметр, не удовлетворяющий: CMTIME_IS_NUMERIC (startTime) при использовании sdavexportsession

Ответ №7:

Я взломал это.

Использовать exportSession.fileLengthLimit = 1048576 * 10 //10 MB

10 МБ — это жестко заданное число. Используйте в соответствии с требуемым вами битрейтом.