【问题标题】:Display MPEG-4 Export Component Dialog显示 MPEG-4 导出组件对话框
【发布时间】:2010-01-09 03:28:51
【问题描述】:

以下是我的基于文档的 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);



}

}

【问题讨论】:

  • 您是否仍然感兴趣,或者回答问题为时已晚?

标签: cocoa export quicktime mpeg-4


【解决方案1】:

这是我们将要使用的标准 Quicktime 组件导出设置对话框:

该对话框仅在 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);
    }
}

如果您第一次使用该组件而没有任何设置,对话框将显示一次默认值。

用户完成编辑并按下确定后,我们需要存储设置:

- (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: 以查看进度(如果需要)。

您可以在下面找到所用类的列表。我希望这会有所帮助。

JSQT组件

@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

@implementation JSQTComponent

@synthesize 组件 = _component; @synthesize componentDescription = _componentDescription; @synthesize name = _name; @synthesize info = _info; @synthesize 图标 = _icon;

  • (id)initWithComponent:(组件)组件 { self = [超级初始化]; 如果(自我!=零) { _component = 组件; [自我获取描述]; } 回归自我; }

  • (void)dealloc { [_名称释放]; [_信息发布]; [_icon 发布]; [超级释放]; }

  • (void)getDescription { OSErr 错误; 句柄 aName = NewHandleClear(255); 句柄 anInfo = NewHandleClear(255); 处理 anIcon = NewHandleClear(255); 处理 iconSuite = NULL;

    err = GetComponentInfo(_component, &_componentDescription, aName, anInfo, anIcon); 如果(错误 == 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

【讨论】:

    猜你喜欢
    • 2015-11-21
    • 1970-01-01
    • 2015-03-28
    • 2011-01-25
    • 1970-01-01
    • 2017-12-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多