Отображение диалогового окна экспорта компонентов MPEG-4 - PullRequest
1 голос
/ 09 января 2010

Ниже приведен мой код для приложения QTKit на основе документов, которое экспортируется в фиксированные форматы устройств Apple с помощью всплывающего окна, отображающего три варианта устройства. Опция [NSNumberWithLong: mpg4 '] также работает нормально, но в ней отсутствуют пользовательские настройки вывода. Я хочу интегрировать знакомое диалоговое окно компонента экспорта QT MPEG-4, чтобы пользователь мог настраивать параметры вывода mpeg-4.

Может кто-нибудь объяснить, как это сделать?

спасибо.

-Поль.

- (void)exportPanelDidEnd:(NSSavePanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
{
int which = [mExportTypePopUpButton indexOfSelectedItem];
int                 selectedItem;
NSMutableDictionary *settings = nil;
static NSArray      *exportTypes = nil;

// init
if (exportTypes == nil)
{
    exportTypes = [[NSArray arrayWithObjects:

                    //[NSNumber numberWithLong:'mpg4'],   ///MPEG-4

                    [NSNumber numberWithLong:'M4VH'],   ///Apple Tv
                    [NSNumber numberWithLong:'M4VP'],   ///iPhone
                    [NSNumber numberWithLong:'M4V '],   ///iPod

                    nil] retain];
}





if (returnCode == NSOKButton)
{
    // init
    selectedItem = [mExportTypePopUpButton indexOfSelectedItem];
    settings = [NSMutableDictionary dictionaryWithCapacity:2];
    [settings setObject:[NSNumber numberWithBool:YES] forKey:QTMovieExport];



    if ((selectedItem >= 0) && (selectedItem < [exportTypes count]))
        [settings setObject:[exportTypes objectAtIndex:selectedItem] forKey:QTMovieExportType];

    if (which==0)

        [mReceiver setStringValue:@"Apple Tv"];


    if (which==1)

        [mReceiver setStringValue:@"iPhone"];


    if (which==2)

        [mReceiver setStringValue:@"iPod"];





    /
    if (![mMovie writeToFile:[sheet filename] withAttributes:settings])
        NSRunAlertPanel(@"Cancel", @"Export terminated.", nil, nil, nil);



}

}

1 Ответ

0 голосов
/ 08 января 2013

Вот стандартный диалог настроек экспорта компонента Quicktime, который мы собираемся использовать:

enter image description here

Диалог доступен только в среде Quicktime (не путать с QTKit), отсюда и ограничения:

  1. Только 32-битная сборка
  2. Нет интеграции с iOS.

Первое, что вам нужно сделать, это связать ваше приложение с платформой Quiktime, убедитесь, что вы собрали его в 32-битной архитектуре Intel, и включена опция Build Active Architecture Only.

Цель - открыть диалоговое окно, установить необходимые параметры экспорта и использовать их для экспорта фильма.

Я предоставлю фрагменты кода в обратном порядке, начиная с фактического вызова диалога, возвращаясь к использованию требуемых структур. Мы должны использовать много кода, поэтому нужно немного терпения.

Для диалога требуется компонент Quicktime. На нашем примере мы будем использовать компонент MPEG4. Предоставляем компонент, ранее сохраненные настройки и открываем диалоговое окно:

#import <QuickTime/QuickTimeComponents.h>

- (void)editExportSetting:(JSMovieExportSetting*)setting
{
    MovieExportComponent exporter = OpenComponent(_MPEG4Component.component);
    Boolean canceled;
    [self updateMovieExportComponent:exporter withExportSetting:setting];
    ComponentResult err = MovieExportDoUserDialog(exporter, NULL, NULL, 0, 0, &canceled);
    if (!canceled)
    {
        if (err == 0)
        {
            [self updateExportSetting:setting withMovieExportComponent:exporter];
        }
    }
    CloseComponent(exporter);   
}

Когда пользователь закончит редактирование и нажмет кнопку ОК, мы сохраняем настройки для последующего использования. Для функции OpenComponent требуется тип данных Component. Для этого я создал оболочку вспомогательного класса, см. Листинг ниже.

Теперь нам нужно получить компонент MPEG4:

- (JSQTComponent*)MPEG4Component
{
    /*
     MPEG-4
     */
    ComponentDescription description;
    description.componentType = 1936746868;
    description.componentSubType = 1836082996;
    description.componentManufacturer = 1634758764;
    description.componentFlags = 269058096;
    description.componentFlagsMask = 66207;

    return [self componentWithDescription:description];
}

- (JSQTComponent*)componentWithDescription:(ComponentDescription)description
{
    JSQTComponent* result = nil;
    for (JSQTComponent* component in [self components])
    {
        if ([component isEqualToComponentDescription:description])
        {
            result = component;
            break;
        }
    }
    return result;
}

- (NSArray*)components
{
    if (_components == nil)
    {
        _components = [NSMutableArray new];
        QTAtomContainer resources = NULL;
        OSErr err = GetComponentPublicResourceList(kQTPresetsListResourceType, 1, 0, &_componentDescription, nil, nil, &resources);

        if (err != noErr)
        {
            NSLog(@"JSQTComponentDataModel error: %d", err);
        }
        else if (resources != NULL)
        {
            QTAtom currChild = 0;
            QTAtom nextChild = 0;
            OSErr err;
            unsigned atomsCount = QTCountChildrenOfType(resources, kParentAtomIsContainer, 0);
            for (UInt16 i=0; i < atomsCount; i++)
            {
                QTAtom compAtomId = 0;
                if (QTFindChildByIndex(resources, kParentAtomIsContainer, kQTMetaDataCommonKeyComposer, i+1, &compAtomId))
                {
                    Component component = (Component)compAtomId;
                    err = QTNextChildAnyType(resources, kParentAtomIsContainer, currChild, &nextChild);
                    if (err == noErr && nextChild)
                    {
                        [_components addObject:[[[JSQTComponent alloc] initWithComponent:component] autorelease]];
                    } 
                    else
                    {
                        NSLog(@"Error %d getting item %d\n", err, i);
                    }
                    currChild = nextChild;
                }
            }
            QTDisposeAtomContainer(resources);
        }
    }
    return _components;
}

В основном мы ищем компонент с описанием, которое нам нужно в списке. Список был составлен так, чтобы получать компоненты определенного типа, потому что у Quicktime было множество разных когда-то.

Нас интересуют только те, которые когда-то были созданы для экспорта фильмов.

ComponentDescription _componentDescription;

_componentDescription.componentType = MovieExportType;
_componentDescription.componentSubType = kAnyComponentSubType;
_componentDescription.componentManufacturer = kAnyComponentManufacturer;
_componentDescription.componentFlags = canMovieExportFiles;
_componentDescription.componentFlagsMask = canMovieExportFiles;

Список кешируется для дальнейшего использования, не забудьте опубликовать его в вашем dealloc.

Пока все идет хорошо. Мы получили компонентный объект MPEG4, получили структуру Component. Теперь нам нужно применить настройки, которые мы сохранили в прошлый раз, к компоненту.

- (void)updateMovieExportComponent:(MovieExportComponent)component withExportSetting:(JSMovieExportSetting*)movieExportSetting
{
    NSData* presetSettings = movieExportSetting.exportSettings;
    Handle settings = NewHandleClear([presetSettings length]);
    if (settings)
    {
        memcpy(*settings, [presetSettings bytes], GetHandleSize(settings));
        // Set movie export settings from the settings QTAtomContainer
        MovieExportSetSettingsFromAtomContainer(component, (QTAtomContainer)settings);
        DisposeHandle(settings);
    }
}

Если вы используете компонент в первый раз без каких-либо настроек, диалоговое окно покажет значение по умолчанию один раз.

После того, как пользователь закончил редактирование и нажал OK, нам нужно сохранить настройки:

- (void)updateExportSetting:(JSMovieExportSetting*)movieExportSetting withMovieExportComponent:(MovieExportComponent)component
{
    QTAtomContainer settings;
    ComponentResult err = MovieExportGetSettingsAsAtomContainer(component, &settings);
    if (err == 0)
    {
        NSData* exportSettings = [NSData dataWithBytes:*settings length:GetHandleSize(settings)];
        movieExportSetting.exportSettings = exportSettings;
    }
}

JSMovieExportSetting - это оболочка, см. Список ниже. Вы можете легко преобразовать его в файл для сохранения настроек.

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

QTMovie* movie = [QTMovie movieWithFile:sourceFilePath error:outError];

NSDictionary* settings = [movieExportSetting movieAttributes];

[movie writeToFile:outputFilePath withAttributes:settings error:outError]

Установите делегат фильма и внедрите movie: shouldContinueOperation: withPhase: atPercent: withAttributes:, чтобы увидеть прогресс при необходимости.

Ниже вы можете найти списки используемых классов. Надеюсь, это поможет.

JSQTComponent

@interface JSQTComponent : NSObject
{
    Component _component;
    ComponentDescription _componentDescription;
    NSString* _name;
    NSString* _info;
    NSString* _icon;
}

- (id)initWithComponent:(Component)component;

@property (nonatomic, readonly) Component component;
@property (nonatomic, readonly) ComponentDescription componentDescription;
@property (nonatomic, retain) NSString* name;
@property (nonatomic, retain) NSString* info;
@property (nonatomic, retain) NSString* icon;

- (BOOL)isEqualToComponentDescription:(ComponentDescription)anotherComponentDescription;

@end

@ реализация JSQTComponent

@ synthesize component = _component; @synthesize componentDescription = _componentDescription; @synthesize name = _name; @synthesize info = _info; @synthesize icon = _icon;

  • (идентификатор) initWithComponent: (Компонент) Компонент { self = [super init]; if (self! = nil) { _component = компонент; [self getDescription]; } вернуть себя; }

  • (аннулируются) dealloc { [_name release]; [_информационный выпуск]; [_icon release]; [супер сделка]; }

  • (аннулируются) getDescription { OSErr err; Handle aName = NewHandleClear (255); Handle anInfo = NewHandleClear (255); Handle anIcon = NewHandleClear (255); Обрабатывать iconSuite = NULL;

    err = GetComponentInfo (_component, & _componentDescription, aName, anInfo, anIcon); если (err == 0) { self.name = [NSString stringWithPStringHandle: aName]; self.info = [NSString stringWithPStringHandle: anInfo]; self.icon = [NSString stringWithPStringHandle: anIcon];
    // err = GetComponentIconSuite (aComponent, & iconSuite); } DisposeHandle (aName); DisposeHandle (anInfo); DisposeHandle (anIcon); DisposeHandle (iconSuite); }

  • (BOOL) isEqualToComponentDescription: (ComponentDescription) anotherComponentDescription { return (_componentDescription.componentType == anotherComponentDescription.componentType) &&(_componentDescription.componentSubType == anotherComponentDescription.componentSubType) && (_componentDescription.componentManufacturer == anotherComponentDescription.componentManufacturer); }

@ конец

JSMovieExportSetting

@interface JSMovieExportSetting : NSObject <NSCoding>
{
    NSString* _name;
    NSNumber* _componentSubType;
    NSNumber* _componentManufacturer;
    NSData* _exportSettings;

    NSDictionary* _movieAttributes;
}

- (id)initWithName:(NSString*)name attributes:(NSDictionary*)attributes;

@property (nonatomic, retain) NSString* name;
@property (nonatomic, retain) NSNumber* componentSubType;
@property (nonatomic, retain) NSNumber* componentManufacturer;
@property (nonatomic, retain) NSData* exportSettings;
@property (nonatomic, readonly) NSDictionary* movieAttributes;

@end


@implementation JSMovieExportSetting

...

- (NSDictionary*)movieAttributes
{
    if (_movieAttributes == nil)
        _movieAttributes = [[NSDictionary dictionaryWithObjectsAndKeys:
                            [NSNumber numberWithBool:YES], QTMovieExport,
                            _componentSubType, QTMovieExportType,
                            _componentManufacturer, QTMovieExportManufacturer,
                            _exportSettings, QTMovieExportSettings, nil] retain];
    return _movieAttributes;
}

- (void)setExportSettings:(NSData*)exportSettings
{
    if (_exportSettings != exportSettings)
    {
        [_exportSettings release];
        _exportSettings = [exportSettings retain];

        [_movieAttributes release];
        _movieAttributes = nil;
    }
}

...

@end
...