Создавание приложения движения остановки QTKit

Выполнение шагов обрисовало в общих чертах в этой главе, Вы создаете простое приложение устройства записи движения остановки, позволяющее Вам получить живой видео канал, захватить кадры по одному с большой точностью, и затем записать вывод тех кадров к фильму в формате QuickTime. Вы выполняете это меньше чем с 100 строками кода Objective C, создавая выборку, поскольку Вы сделали в предыдущих главах в Xcode 3.2 и Интерфейсном Разработчике 3.2.

В создавании Вашего приложения устройства записи движения остановки Вы работаете со следующими тремя классами QTKit:

Пример кода, описанный в этой главе, не поддерживает ввод от камер DV, имеющих тип QTMediaTypeMuxed, вместо QTMediaTypeVideo. Для добавления поддержки камер DV считайте главу, Расширяющую Приложение Медиапроигрывателя.

Моделируйте приложение устройства записи движения остановки

Так же, как Вы сделали в разделе Prototype the Recorder, запустите путем создания грубого эскиза приложения устройства записи движения остановки QTKit. Думайте, снова, того, какие элементы дизайна Вы хотите включить в приложение.

Prototype sketch of QTKit stop motion recorder application

В этом прототипе проекта Вы запускаете с трех простых объектов: представление получения, представление фильма в формате QuickTime и единственная кнопка для добавления кадров. Они будут стандартными блоками для Вашего приложения. Можно добавить больше сложности к проекту позже. После того, как Вы изобразили схематически свой прототип, думайте, как поднять трубку объекты в Интерфейсном Разработчике и что кодирует Вас потребность в Вашем проекте XCode заставить это произойти. Обратите внимание на то, что необходимо добавить контроллер фильма к QTMovieView объект на иллюстрации выше.

Создайте проект Используя Xcode 3.2

Для создания проекта выполните эти шаги, как в предыдущих главах:

  1. Xcode 3.2 запуска и выбирает File> New Project.

  2. Когда новое окно проекта появится, выберите Cocoa Document-based Application и нажмите Choose.

  3. Назовите проект StopMotion и перейдите к расположению, где Вы хотите, чтобы приложение XCode создало папку проекта.

    • Окно проекта XCode появляется.

    The StopMotion Xcode project windowThe StopMotion Xcode project window
  4. Из Меню действий в Вашем проекте XCode выберите Add> Add to Existing Frameworks.

    Добавьте платформу QTKit к Вашему StopMotion проект, находящийся в /System/Library/Frameworks каталог.

  5. Теперь добавьте Кварцевую платформу Ядра к своему проекту, также находящемуся в /System/Library/Frameworks каталог.

    • Выбрать QuartzCore.framework, и нажмите Add, когда появится окно Add To Targets.

    Это завершает первую последовательность шагов в Вашем проекте. В следующей последовательности Вы определяете действия и выходы в XCode прежде, чем работать с Интерфейсным Разработчиком.

    Поскольку Вы уже моделировали свое приложение устройства записи движения остановки QTKit, по крайней мере в грубой форме с ясно определенной моделью данных, можно теперь определить, какие действия и выходы должны быть реализованы. В этом случае у Вас есть a QTCaptureView объект, который является подклассом NSView, a QTMovieView возразите для отображения полученных кадров и одной кнопки, чтобы записать полученный мультимедийный контент и добавить каждый единственный кадр к выводу фильма в формате QuickTime.

Импортируйте заголовки QTKit и установите Ваш файл реализации

  1. Откройтесь MyDocument.h файл объявления в Вашем проекте XCode.

    В файле удалите оператора импорта Какао и замените его оператором импорта QTKit.

    #import <QTKit/QTKit.h>
  2. Откройтесь MyDocument.m файл реализации в Вашем проекте. Удалите содержание файла за исключением следующих строк кода:

    #import "MyDocument.h"
    @implementation MyDocument
    - (NSString *)windowNibName
    {
        return @"MyDocument";
    }
    @end
  3. Сохраните свой файл.

Определите действия и выходы, которые Вы хотите

Теперь начните добавлять выходы и действия.

  1. В Вашем MyDocument.h файл, добавляют переменные экземпляра mCaptureView и mMovieView.

    IBOutlet QTCaptureView *mCaptureView;
    IBOutlet QTMovieView   *mMovieView;
  2. Добавьте addFrame: метод действия.

    - (IBAction)addFrame:(id)sender;
  3. Сохраните свой файл.

  4. Теперь откройте Ваш MyDocument.m файл и добавляет тот же метод действия, сопровождаемый фигурными скобками для кода, который Вы добавляете позже для реализации этого действия.

    - (IBAction)addFrame:(id)sender
    {
    }

Это завершает второй этап Вашего проекта. Теперь Вы работаете с Интерфейсным Разработчиком 3.2 для построения пользовательского интерфейса для проекта. Убедитесь, что Вы сохранили и свое объявление и файлы реализации, так, чтобы действия и выходы, которые Вы объявили, были синхронно обновлены в Вашем Интерфейсном пере Разработчика.

Создайте пользовательский интерфейс

В следующей фазе Вашего проекта Вы создаете пользовательский интерфейс для своего проекта.

  1. Откройте Interface Builder 3.2 и щелкните MyDocument.xib файл в Вашем окне проекта XCode.

  2. В Интерфейсном Разработчике 3.2, выберите Tools> Library для открытия библиотеки объектов.

    • Прокрутите вниз к объекту представления получения QuickTime.

    The QuickTime capture view object in the library

    QTCaptureView объект предоставляет Вам экземпляр подкласса представления для отображения предварительного просмотра видеовыхода, полученного сеансом получения.

    • Перетащите QTCaptureView возразите в свое окно и измените размеры объекта соответствовать окну, предусмотрев пространство в нижней части для Вашей кнопки Add Frame (уже показанный на иллюстрации ниже) и вправо для Вашего QTMovieView возразите в своем приложении устройства записи движения остановки QTKit.

    • Выберите Tools> Inspector. В панели Identity выберите информацию («я») значок. Щелкните в поле Class и Вашем QTCaptureView объект появляется.

      The QTCaptureView window and Class Identity in the InspectorThe QTCaptureView window and Class Identity in the Inspector
    • Установите автокалибровку для объекта в панели Capture View Size.

      Setting the autosizing for your QTCaptureView objectSetting the autosizing for your QTCaptureView object
  3. Теперь повторите ту же последовательность, описанную на Шаге № 2 для добавления Вашего QTMovieView возразите против своего окна (уже показанный выше).

    • Прокрутите к QTMovieView объект.

    • Выберите QTMovieView объект (символизируемый синим Q) и перетаскивает его в Ваше Окно рядом с QTCaptureView объект, показанный ниже.

    • Выберите Tools> Inspector. В Инспекторе Идентификационных данных выберите информацию («я») значок. Щелкните в поле Class и Вашем QTMovieView объект появляется.

      The QTMovieView object defined in the field ClassThe QTMovieView object defined in the field Class
    • Установите автокалибровку для Вашего QTMovieView объект, как Вы сделали для QTCaptureView объект на шагах выше.

  4. Теперь укажите атрибуты окна в Вашем MyDocument.xib файл.

    • Выберите объект окна в своем пере.

    • Щелкните по значку атрибутов в панели.

  5. Определите размер окна, который Вы хотите в Вашем MyDocument.xib путем выбора значка размера (символизируемый желтой линейкой) в панели Window Size.

    Defining the size of the Window
  6. Укажите соединения розетки делегата Владельца Файла в панели Window Connections.

    ../Art/wiring_window_delegate.jpg../Art/wiring_window_delegate.jpg
  7. В Библиотеке выберите Кнопочное управление и перетащите его к окну.

    • Введите текст Add Frame.

    • Установите автокалибровку для кнопки в центре и прямо вне угла, оставив внутренние распорки нетронутыми, как показано на иллюстрации.

    Specifying the autosizing for the Add Frame button
  8. Выберите MyDocument.xib файл и нажимает Connections Inspector.

    • Теперь обеспечьте электричеством выходы и полученные действия.

    • Перетащите управление каждую переменную экземпляра выхода к объекту Владельца Файла.

    Specifiying the actions and outlet connections in MyDocument.xib
  9. Выберите объект Владельца Файла в Вашем MyDocument.xib файл.

    • Щелкните по значку Class Identity в Интерфейсном Инспекторе Разработчика.

    • Обратите внимание на то, что зеленый свет в левом углу Вашего StopMotion.xcodeproj включен, указав, что XCode и Интерфейсный Разработчик синхронизировали действия и выходы в Вашем проекте.

  10. Сохраните свой Интерфейсный файл Разработчика.

Подготовьте получать видео Единственного Кадра

В последней фазе Вашего проекта, после добавления и завершения кода реализации, Вы готовы получить видео единственного кадра, с помощью приложения устройства записи движения остановки, как показано ниже.

Preparing to capture single video frames and outputting those frames to a QuickTime moviePreparing to capture single video frames and outputting those frames to a QuickTime movie

Завершите реализацию класса MyDocument в XCode

Для завершения реализации класса MyDocument Вы определяете переменные экземпляра, указывающие на сеанс получения, а также на ввод устройства и распакованные объекты видеовыхода.

  1. В Вашем проекте XCode добавьте переменные экземпляра к объявлению интерфейса.

    Включите эти строки кода Ваш MyDocument.h файл объявления:

    @interface MyDocument : NSDocument
    {
       QTMovie                                *mMovie;
       QTCaptureSession                       *mCaptureSession;
       QTCaptureDeviceInput                   *mCaptureDeviceInput;
       QTCaptureDecompressedVideoOutput       *mCaptureDecompressedVideoOutput;
    }

    mMovie переменная экземпляра указывает на QTMovie объект, и mCaptureSession переменная экземпляра указывает на QTCaptureSession объект. Аналогично, *mCaptureDeviceInput переменная экземпляра указывает на QTCaptureDeviceInput объект и следующая строка объявляют что mCaptureDecompressedVideoOutput переменная экземпляра указывает на QTCaptureDecompressedVideoOutput объект.

  2. Объявите mCurrentImageBuffer переменная экземпляра.

     CVImageBufferRef                    mCurrentImageBuffer;

    Эта переменная экземпляра хранит новый кадр, который Вы захватили в a CVImageBufferRef.

    Это завершает код, который необходимо добавить к Вашему MyDocument.h файл.

  3. Откройте Ваш MyDocument.m файл и выполняет эти шаги.

  4. Создайте пустой фильм, пишущий в непостоянные данные в памяти, с помощью initToWritableData: метод.

    - (void)windowControllerDidLoadNib:(NSWindowController *) aController
    {
        NSError *error = nil;
        [super windowControllerDidLoadNib:aController];
        [[aController window] setDelegate:self];
        if (!mMovie) {
            mMovie = [[QTMovie alloc] initToWritableData:[NSMutableData data] error:&error];
            if (!mMovie) {
                [[NSAlert alertWithError:error] runModal];
                return;
            }
        }
  5. Установите сеанс получения, выводящий необработанные кадры, которые Вы хотите захватить.

        [mMovieView setMovie:mMovie];
        if (!mCaptureSession) {
            BOOL success;
            mCaptureSession = [[QTCaptureSession alloc] init];
  6. Найдите видеоустройство и добавьте ввод устройства для того устройства к сеансу получения.

            QTCaptureDevice *device = [QTCaptureDevice defaultInputDeviceWithMediaType:QTMediaTypeVideo];
            success = [device open:&error];
            if (!success) {
                [[NSAlert alertWithError:error] runModal];
                return;
            }
            mCaptureDeviceInput = [[QTCaptureDeviceInput alloc] initWithDevice:device];
            success = [mCaptureSession addInput:mCaptureDeviceInput error:&error];
            if (!success) {
                [[NSAlert alertWithError:error] runModal];
                return;
            }
  7. Добавьте распакованный видеовыход, возвращающий необработанные кадры, которые Вы захватили к сеансу, и затем предварительно просматривает видео от сеанса в окне документа.

            mCaptureDecompressedVideoOutput = [[QTCaptureDecompressedVideoOutput alloc] init];
            [mCaptureDecompressedVideoOutput setDelegate:self];
            success = [mCaptureSession addOutput:mCaptureDecompressedVideoOutput error:&error];
            if (!success) {
                [[NSAlert alertWithError:error] runModal];
                return;
            }
  8. Предварительно просмотрите видео от сеанса в окне документа.

            [mCaptureView setCaptureSession:mCaptureSession];
  9. Запустите сеанс, с помощью startRunning метод Вы использовали ранее в MyRecorder пример кода.

            [mCaptureSession startRunning];
        }
    }
  10. Реализуйте метод делегата это QTCaptureDecompressedVideoOutput вызовы каждый раз, когда это принимает кадр.

     - (void)captureOutput:(QTCaptureOutput *)captureOutput didOutputVideoFrame:(CVImageBufferRef)videoFrame withSampleBuffer:(QTSampleBuffer *)sampleBuffer fromConnection:(QTCaptureConnection *)connection
  11. Сохраните последний кадр. Сделайте это в a @synchronized блокируйте, потому что метод делегата не вызывают на основном потоке.

        CVImageBufferRef imageBufferToRelease;
     
        CVBufferRetain(videoFrame);
     
        @synchronized (self) {
            imageBufferToRelease = mCurrentImageBuffer;
            mCurrentImageBuffer = videoFrame;
        }
        CVBufferRelease(imageBufferToRelease);
    }
  12. Окно дескриптора заключительные уведомления для Вашего ввода устройства и остановки сеанс получения.

    - (void)windowWillClose:(NSNotification *)notification
    {
        [mCaptureSession stopRunning];
        QTCaptureDevice *device = [mCaptureDeviceInput device];
        if ([device isOpen])
            [device close];
    }
  13. Освободите память для своих объектов получения.

    - (void)dealloc
    {
        [mMovie release];
        [mCaptureSession release];
        [mCaptureDeviceInput release];
        [mCaptureDecompressedVideoOutput release];
        [super dealloc];
    }
  14. Укажите выходное место назначения для своих носителей с записанными данными, в этом случае доступный для редактирования фильм в формате QuickTime.

    - (BOOL)readFromURL:(NSURL *)absoluteURL ofType:(NSString *)typeName error:(NSError **)outError
    {
        QTMovie *newMovie = [[QTMovie alloc] initWithURL:absoluteURL error:outError];
        if (newMovie) {
            [newMovie setAttribute:[NSNumber numberWithBool:YES] forKey:QTMovieEditableAttribute];
            [mMovie release];
            mMovie = newMovie;
        }
        return (newMovie != nil);
    }
    - (BOOL)writeToURL:(NSURL *)absoluteURL ofType:(NSString *)typeName error:(NSError **)outError
    {
        return [mMovie writeToFile:[absoluteURL path] withAttributes:[NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:QTMovieFlatten] error:outError];
    }
  15. Добавьте addFrame: метод действия, который Вы указали ранее в Вашем файле реализации. Это позволяет Вам получить новый кадр, который Вы захватили. Сделайте это в a @synchronized блокируйте, потому что метод делегата, устанавливающий новый кадр, не вызывают на основном потоке. Обратите внимание на то, что Вы обертываете a CVImageBufferRef объект в NSImage. После создания NSImage, можно тогда добавить его к фильму.

    - (IBAction)addFrame:(id)sender
    {
        CVImageBufferRef imageBuffer;
        @synchronized (self) {
            imageBuffer = CVBufferRetain(mCurrentImageBuffer);
        }
        if (imageBuffer) {
            NSCIImageRep *imageRep = [NSCIImageRep imageRepWithCIImage:[CIImage imageWithCVImageBuffer:imageBuffer]];
            NSImage *image = [[[NSImage alloc] initWithSize:[imageRep size]] autorelease];
            [image addRepresentation:imageRep];
            CVBufferRelease(imageBuffer);
            [mMovie addImage:image forDuration:QTMakeTime(1, 10) withAttributes:[NSDictionary dictionaryWithObjectsAndKeys:
    @"jpeg", QTAddImageCodecType, nil]];
            [mMovie setCurrentTime:[mMovie duration]];
            [mMovieView setNeedsDisplay:YES];
            [self updateChangeCount:NSChangeDone];
        }
    }

Создайте и скомпилируйте свое приложение устройства записи движения остановки

После сохранения проекта нажмите Build и Go. После компиляции нажмите кнопку Add Frame, чтобы записать каждый полученный кадр и вывести тот кадр к фильму в формате QuickTime. Вывод Вашего полученного сеанса сохраняется как фильм в формате QuickTime.

Теперь можно начать получать и записывать с приложением устройства записи движения остановки QTKit. Как правило, можно записать любое число кадров, иллюстрирующих перемещение или действие, с помощью объектов глины или рисунков линиями, например, который, когда объединено и зарегистрировано, создаст иллюзию движения в фильме или анимированной последовательности. Метод распространен в работе с различными неодушевленными объектами, которые могут быть собраны в определенную историю или рассказ.

Сводка

В этой главе Вы фокусировались на создании приложения устройства записи движения остановки с помощью трех объектов получения: QTCaptureSession, QTCaptureDecompressedVideoOutput и QTCaptureDeviceInput. Они были существенными стандартными блоками для Вашего проекта. Вы учились как: