Понимание атомов QuickTime

В этой главе рассматриваются атомы QuickTime, базовую структуру для того, чтобы хранить информацию в QuickTime. Это также описывает функции, используемые, чтобы создать, избавиться, читать из, и хранилище к контейнерам атома QuickTime. Атом QT является улучшением существующей структуры данных атома. Большинство структур данных QuickTime (фильмы, дорожки, носители) создается из атомов. Более новые структуры данных QuickTime (дорожки временного кода, спрайты) реализованы с помощью атомов QT.

Структуры Atom и IDs

Контейнер атома QT является структурой основной памяти для того, чтобы хранить информацию в QuickTime. Можно использовать контейнер атома QT для построения произвольно сложных иерархических структур данных. Можно думать о недавно создаваемом контейнере атома QT как о корне древовидной структуры, не содержащей дочерних элементов. Контейнер атома QT содержит атомы QT  (рисунок 7-1). Каждый атом QT содержит или данные или другие атомы. Если атом QT содержит другие атомы, это - родительский атом и атомы, которые это содержит, его дочерние атомы. Если атом QT содержит данные, его вызывают листовым атомом.

Рисунок 7-1  контейнер атома QT с родительскими и дочерними атомами

Каждый атом QT имеет смещение, описывающее позицию атома в контейнере атома QT. Кроме того, каждый атом QT имеет тип и ID. Тип атома описывает вид информации, которую представляет атом. Атом ID используется для дифференциации дочерних атомов того же типа с тем же родителем; ID атома должен быть уникальным для данного родителя и типа. В дополнение к атому ID каждый атом имеет индекс на основе 1, описывающий его порядок относительно других дочерних атомов того же родителя. Можно однозначно определить атом QT тремя способами:

Можно сохранить и получить атомы в контейнере атома QT индексом, ID или обоими. Например, для использования контейнера атома QT в качестве динамического массива или древовидной структуры можно сохранить и получить атомы индексом. Для использования контейнера атома QT в качестве базы данных можно сохранить и получить атомы ID. Можно также создать, сохранить, и получить атомы с помощью и ID и индексировать для создания произвольно комплекса, расширяемой структуры данных.

 Рисунок 7-2 показывает контейнер атома QT, имеющий два дочерних атома. Первый дочерний атом (смещение = 10) является листовым атомом, имеющим тип атома 'abcd', ID 1 000 и индекс 1. Второй дочерний атом (смещение = 20) имеет тип атома 'abcd', ID 900 и индекс 2. Поскольку два дочерних атома имеют тот же тип, у них должен быть различный IDs. Второй дочерний атом является также родительским атомом трех атомов.

Рисунок 7-2  пример контейнера атома QT

Первый дочерний атом (смещение = 30) имеет тип атома 'abcd', ID 100 и индекс 1. Это не имеет никаких дочерних элементов, и при этом это не имеет данных. Второй дочерний атом (смещение = 40) имеет тип атома 'word', ID 100 и индекс 1. Атом имеет данные, таким образом, это - листовой атом. Второй атом (смещение = 40) имеет тот же ID как первый атом (смещение = 30), но различный тип атома. Третий дочерний атом (смещение = 50) имеет тип атома 'abcd', ID 1 000 и индекс 2. Его тип атома и ID совпадают с типом другого атома (смещение = 20) с различным родителем.

Как разработчик, Вы не должны анализировать атомы QT сами. Вместо этого можно использовать функции атома QT, чтобы создать контейнеры атома, добавить атомы к и удалить атомы из контейнеров атома, искать атомы в контейнерах атома и получить данные от атомов в контейнерах атома.

Большинство функций атома QT берет два параметра для указания определенного атома: контейнер атома, содержащий атом и смещение атома в структуре данных контейнера атома. Вы получаете смещение атома путем вызова также QTFindChildByID или QTFindChildByIndex. Смещение атома может быть лишено законной силы, если изменяется контейнер атома QT, содержащий его.

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

Создание и избавление от контейнеров Atom

Прежде чем можно будет добавить атомы к контейнеру атома, необходимо сначала создать контейнер путем вызова QTNewAtomContainer. Пример кода, показанный в вызовах Перечисления 7-1 QTNewAtomContainer создать контейнер атома.

Перечисление 7-1  , Создающее новый контейнер атома

QTAtomContainer spriteData;
OSErr err
// create an atom container to hold a sprite's data
err=QTNewAtomContainer (&spriteData);

Когда Вы закончили использовать контейнер атома, необходимо избавиться от него путем вызова QTDisposeAtomContainer функция. Пример кода, показанный в вызовах Перечисления 7-2 QTDisposeAtomContainer избавляться spriteData контейнер атома.

Перечисление 7-2  , Избавляющееся от контейнера атома

if (spriteData)
    QTDisposeAtomContainer (spriteData);

Создание новых атомов

Можно использовать QTInsertChild функция, чтобы создать новые атомы и вставить их в контейнер атома QT. QTInsertChild функция создает новый дочерний атом для родительского атома. Вызывающая сторона указывает тип атома и атом ID для нового атома. Если Вы указываете значение 0 для атома ID, QTInsertChild присваивает уникальный идентификатор атому.

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

Пример кода в Перечислении 7-3 создает новый контейнер атома QT и вызовы QTInsertChild добавить атом. Получающийся контейнер атома QT показан на рисунке 7-3. Значение смещения 10 возвращается в firstAtom параметр.

Перечисление 7-3  , Создающее новый контейнер атома QT и вызывающее QTInsertChild для добавления атом

QTAtom firstAtom;
QTAtomContainer container;
OSErr err
err = QTNewAtomContainer (&container);
if (!err)
    err = QTInsertChild (container, kParentAtomIsContainer, 'abcd',
        1000, 1, 0, nil, &firstAtom);
Рисунок 7-3  контейнер атома QT после вставки атома

Следующие вызовы примера кода QTInsertChild создать второй дочерний атом. Поскольку значение 1 указано для index параметр, второй атом вставляется перед первым атомом в дочернем списке; индекс первого атома изменяется на 2. Получающийся контейнер атома QT показан на рисунке 7-4.

QTAtom secondAtom;
FailOSErr (QTInsertChild (container, kParentAtomIsContainer, 'abcd',
    2000, 1, 0, nil, &secondAtom));
Рисунок 7-4  контейнер атома QT после вставки второго атома

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

firstAtom = QTFindChildByID (container, kParentAtomIsContainer, 'abcd',
    1000, nil);

Перечисление 7-4 показывает как QTInsertChild функция вставляет листовой атом в контейнер атома sprite. Новый листовой атом содержит индекс изображения спрайта как свои данные.

Перечисление 7-4  , Вставляющее дочерний атом

if ((propertyAtom = QTFindChildByIndex (sprite, kParentAtomIsContainer,
    kSpritePropertyImageIndex, 1, nil)) == 0)
    FailOSErr (QTInsertChild (sprite, kParentAtomIsContainer,
        kSpritePropertyImageIndex, 1, 1, sizeof(short),&imageIndex,
        nil));

Копирование существующих атомов

QuickTime обеспечивает несколько функций для копирования существующих атомов в контейнере атома. QTInsertChildren функция вставляет контейнер атомов как дочерние элементы родительского атома в другом контейнере атома. Рисунок 7-5 показывает двум примерам контейнеры атома QT, A и B.

Рисунок 7-5  Два контейнера атома QT, A и B

Следующие вызовы примера кода QTFindChildByID получать смещение атома в контейнере A. Затем пример кода вызывает QTInsertChildren функционируйте для вставки атомов в контейнер B как дочерние элементы атома в контейнере A. Рисунок 7-6 показывает, какой контейнер взгляды как после атомов от контейнера B были вставлены.

QTAtom targetAtom;
targetAtom = QTFindChildByID (containerA, kParentAtomIsContainer, 'abcd',
    1000, nil);
FailOSErr (QTInsertChildren (containerA, targetAtom, containerB));
Рисунок 7-6  контейнер атома QT после дочерних атомов был вставлен

В перечислении 7-5, QTInsertChild функция вставляет родительский атом в контейнер атома theSample. Затем вызовы кода QTInsertChildren вставить контейнер theSprite в контейнер theSample. Родительский атом newSpriteAtomMovie Типы данных.

Перечисление 7-5  , Вставляющее контейнер в другой контейнер

 
FailOSErr (QTInsertChild (theSample, kParentAtomIsContainer,
    kSpriteAtomType, spriteID, 0, 0, nil, &newSpriteAtom));
FailOSErr (QTInsertChildren (theSample, newSpriteAtom, theSprite));

QuickTime обеспечивает три других функции, которые можно использовать для управления атомами в контейнере атома. QTReplaceAtom функционируйте заменяет атом и его дочерние элементы с различным атомом и его дочерние элементы. Можно вызвать QTSwapAtoms функционируйте для свопинга содержания двух атомов в контейнере атома; после свопинга, ID и индекса каждого атома остается тем же. QTCopyAtom функционируйте копирует атом и его дочерние элементы к новому контейнеру атома.

Получение атомов от контейнера Atom

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

Можно использовать QTCountChildrenOfType и QTGetNextChildType функции для получения информации о типах дочерних элементов атома. QTCountChildrenOfType функционируйте возвращает число дочерних элементов данного типа атома для родительского атома. QTGetNextChildType функционируйте возвращает следующий тип атома в дочернем списке родительского атома.

Можно использовать QTFindChildByIndex, QTFindChildByID, и QTNextChildAnyType функции для получения атома. Вы вызываете QTFindChildByIndex функционируйте, чтобы искать и получить дочерний элемент родительского атома его типом и индексом в том типе.

Перечисление 7-6 показывает функцию примера кода SetSpriteData, который обновляет контейнер атома, описывающий спрайт. Для каждого свойства спрайта, который должен быть обновлен, SetSpriteData вызовы QTFindChildByIndex получать надлежащий атом от контейнера атома. Если атом найден, SetSpriteData вызовы QTSetAtomData заменять данные атома новым значением свойства. Если атом не найден, SetSpriteData вызовы QTInsertChild добавить новый атом для свойства.

Перечисление 7-6  , Находящее дочерний атом индексом

 
OSErr SetSpriteData (QTAtomContainer sprite, Point *location,
    short *visible, short *layer, short *imageIndex)
{
    OSErr err = noErr;
    QTAtom propertyAtom;
    
    // if the sprite's visible property has a new value
    if (visible)
    {
        // retrieve the atom for the visible property --
        // if none exists, insert one
        if ((propertyAtom = QTFindChildByIndex (sprite,
            kParentAtomIsContainer, kSpritePropertyVisible, 1,
            nil)) == 0)
            FailOSErr (QTInsertChild (sprite, kParentAtomIsContainer,
                kSpritePropertyVisible, 1, 1, sizeof(short), visible,
                nil))
        
        // if an atom does exist, update its data
        else
            FailOSErr (QTSetAtomData (sprite, propertyAtom,
                sizeof(short), visible));
    }
    
    // ...
    // handle other sprite properties
    // ...
}

Можно вызвать QTFindChildByID функционируйте, чтобы искать и получить дочерний элемент родительского атома его типом и ID. Функция примера кода AddSpriteToSample, показанный в Перечислении 7-7, добавляет спрайт, представленный контейнером атома, к ключевой выборке, представленной другим контейнером атома. AddSpriteToSample вызовы QTFindChildByID определить ли контейнер атома theSample содержит атом типа kSpriteAtomType с ID spriteIDMovie Типы данных. В противном случае AddSpriteToSample вызовы QTInsertChild вставить атом с тем типом и ID. Значение 0 передается для index параметр, чтобы указать, что атом должен быть вставлен в конце дочернего списка. Значение 0 передается для dataSize параметр, чтобы указать, что атом не имеет никаких данных. Затем AddSpriteToSample вызовы QTInsertChildren вставить атомы в контейнер theSprite как дочерние элементы нового атома. FailIf и FailOSErr макросы, которые выходят из текущей функции, когда происходит ошибка.

Перечисление 7-7  , Находящее дочерний атом ID

OSErr AddSpriteToSample (QTAtomContainer theSample,
    QTAtomContainer theSprite, short spriteID)
{
    OSErr err = noErr;
    QTAtom newSpriteAtom;
    FailIf (QTFindChildByID (theSample, kParentAtomIsContainer,
        kSpriteAtomType, spriteID, nil), paramErr);
    FailOSErr (QTInsertChild (theSample, kParentAtomIsContainer,
        kSpriteAtomType, spriteID, 0, 0, nil, &newSpriteAtom));
    FailOSErr (QTInsertChildren (theSample, newSpriteAtom, theSprite));
}

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

QuickTime также обеспечивает функции для получения типа атома, ID и данных. Можно вызвать QTGetAtomTypeAndID функция для получения типа атома и ID. Можно получить доступ к данным атома одним из трех способов.

Изменение атомов

QuickTime обеспечивает функции, которые можно вызвать для изменения атрибутов или данных, связанных с атомом в контейнере атома. Для изменения ID атома Вы вызываете функцию QTSetAtomIDMovie Типы данных.

Вы используете QTSetAtomData функционируйте для обновления данных, связанных с листовым атомом в контейнере атома. QTSetAtomData функционируйте заменяет листовые данные атома новыми данными. Пример кода в вызовах Перечисления 7-8 QTFindChildByIndex определить, содержит ли контейнер атома видимое свойство спрайта. Если так, демонстрационные вызовы QTSetAtomData заменять данные атома новым видимым свойством.

Перечисление 7-8  , Изменяющее данные атома

QTAtom propertyAtom;
// if the atom isn't in the container, add it
if ((propertyAtom = QTFindChildByIndex (sprite, kParentAtomIsContainer,
    kSpritePropertyVisible, 1, nil)) == 0)
    FailOSErr (QTInsertChild (sprite, kParentAtomIsContainer,
        kSpritePropertyVisible, 1, 0, sizeof(short), visible, nil))
// if the atom is in the container, replace its data
else
    FailOSErr (QTSetAtomData (sprite, propertyAtom, sizeof(short),
        visible));

Удаление атомов от контейнера Atom

Для удаления атомов из контейнера атома можно использовать QTRemoveAtom и QTRemoveChildren функции. QTRemoveAtom функция удаляет атом и его дочерние элементы, если таковые имеются, от контейнера. QTRemoveChildren функция удаляет дочерние элементы атома из контейнера, но не удаляет сам атом. Можно также использовать QTRemoveChildren удалить все атомы в контейнере атома. Для этого необходимо передать константу kParentAtomIsContainer для atom параметр.

Пример кода, показанный в Перечислении 7-9, добавляет выборки переопределения к дорожке спрайта для анимации спрайтов в дорожке спрайта. sample и spriteData переменные являются контейнерами атома. spriteData контейнер атома содержит атомы, описывающие единственный спрайт. sample контейнер атома содержит атомы, который описывает выборку переопределения.

Каждая итерация for вызовы цикла QTRemoveChildren удалить все атомы от обоих sample и spriteData контейнеры. Пример кода обновляет индекс изображения, которое будет использоваться для спрайта и расположения спрайта и вызовов SetSpriteData, который добавляет надлежащие атомы к spriteData контейнер атома. Затем вызовы примера кода AddSpriteToSample добавить spriteData контейнер атома к sample контейнер атома. Наконец, когда все спрайты были обновлены, вызовы примера кода AddSpriteSampleToMedia добавить выборку переопределения к дорожке спрайта.

Перечисление 7-9  , Удаляющее атомы из контейнера

QTAtomContainer sample, spriteData;
// ...
// add the sprite key sample
// ...
// add override samples to make the sprites spin and move
for (i = 1; i <= kNumOverrideSamples; i++)
{
    QTRemoveChildren (sample, kParentAtomIsContainer);
    QTRemoveChildren (spriteData, kParentAtomIsContainer);
    
    // ...
    // update the sprite:
    // - update the imageIndex
    // - update the location
    // ...
    // add atoms to spriteData atom container
    SetSpriteData (spriteData, &location, nil, nil, &imageIndex);
    // add the spriteData atom container to sample
    err = AddSpriteToSample (sample, spriteData, 2);
    // ...
    // update other sprites
    // ...
    // add the sample to the media
    err = AddSpriteSampleToMedia (newMedia, sample,
        kSpriteMediaFrameDuration, false);
}

Создание и изменение контейнеров Atom QT

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

Получение атомов и данных Atom

Это после функций может использоваться для получения Атомов QT и данных атома. Каждый атом QT содержит или данные или другие атомы.

Константы для функций Atom QT

Можно передать kParentAtomIsContainer постоянный к функциям атома QT, берущим контейнер атома и родительский атом как параметры. Когда передано вместо родительского атома, эта константа указывает, что родительский атом является самим контейнером атома.

enum {
    kParentAtomIsContainer  = 0
};

Atom QT

QTAtom тип данных представляет смещение атома в контейнере атома.

typedef long QTAtom;

Тип Atom QT и ID

QTAtomType тип данных представляет тип атома QT. Чтобы быть допустимым, тип атома QT должен иметь ненулевое значение.

typedef long QTAtomType;

QTAtomID тип данных представляет ID атома QT. Чтобы быть допустимым, атом QT, ID должен иметь ненулевое значение.

typedef long QTAtomID;

Контейнер Atom QT

QTAtomContainer тип данных является дескриптором к контейнеру атома QT. Ваше приложение никогда не изменяет содержание контейнера атома QT непосредственно. Вместо этого Вы используете функции, предоставленные QuickTime для создания и управления контейнерами атома QT.

typedef Handle QTAtomContainer;