Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simple Timeline Example (with linked MXFs) #116

Closed
maptz opened this issue Mar 10, 2023 · 1 comment
Closed

Simple Timeline Example (with linked MXFs) #116

maptz opened this issue Mar 10, 2023 · 1 comment

Comments

@maptz
Copy link

maptz commented Mar 10, 2023

I asked this on the original PYAAF repo by mistake.

I'm hoping to bring in some simple edits into my Avid system using pyaaf2.

I just wondered if you can guide me in creating a very quick sample. I'm bashing my head against a wall.

  • I want to create a sequence with a video track and two audio tracks.
  • I want to link to existing OP-ATOM MXFs
  • Then I want to put subclips of these OP-ATOMs onto the video and audio tracks.

I've got as far as your test_create_sequence.py file and worked out how to link the existing MXF files into that file. I can even put some of the clips on a timeline (after an hour or so - yay!)

What's funky here is that my OP-ATOM files aren't all recognised correctly. My OP-ATOM files are individual tracks of stereo files which are linked together. I think they should be showing up as a single mob with two slots, but in fact they're coming in as 4 mobs (maybe???) with single slots.

image

Anyway, a little help would be fantastic if you've got a second!

from __future__ import (
    unicode_literals,
    absolute_import,
    print_function,
    division,
    )

import aaf2

def create_file():
    mob_count = 0
    components = 0

    source_file = ["Z:\\Avid MediaFiles\\MXF\\SFX_BBC_MXFs\\4Minute_BBA01.5E5D05003B53A.mxf",
               "Z:\\Avid MediaFiles\\MXF\\SFX_BBC_MXFs\\4Minute_BBA02.5E5D05003CA7A.mxf"]
    
    with aaf2.open("output.aaf", "w")  as f:

        #video_rate = " 30000/1001"
        video_rate = " 24000/1001"
        comp_mob = f.create.CompositionMob()
        sequence = f.create.Sequence(media_kind="picture")

        timeline_slot = comp_mob.create_timeline_slot(video_rate)
        timeline_slot.segment= sequence

        sound_slot = comp_mob.create_sound_slot(video_rate) # add a track
        sound_slot2 = comp_mob.create_sound_slot(video_rate) # add a track
        # audio_sequence = f.create.Sequence(media_kind="sound")
        # sound_slot.segment = audio_sequence

        audio_mobs = []
        for path in source_file:
            for mob in f.content.link_external_mxf(path):
                if (mob not in audio_mobs):
                    audio_mobs.append(mob)
                    print(mob.name)
                
        for mob in audio_mobs:
            slot = mob.slots[0]
            sound_slot.segment.components.append(mob.create_source_clip(slot.slot_id, length = 100)) # 100 frames
            sound_slot.segment.components.append(f.create.Filler('sound', 100)) # 100 frames

        for mob in audio_mobs:
            slot = mob.slots[0]
            sound_slot2.segment.components.append(mob.create_source_clip(1, length = 100))
            sound_slot2.segment.components.append(f.create.Filler('sound', 100))
                
                #sound_slot.segment = f.create.Filler('sound', 100)
                # filler = f.create.Filler('sound', 100)
                # sound_slot.segment.components.append(filler)
                # filler = f.create.Filler('sound', 100)
                # audio_sequence.components.append(filler)

                #track1 = file_mob.create_sound_slot(video_rate)
                #track2 = file_mob.create_sound_slot(video_rate)

                # for mob in f.content.mastermobs():
                #     length = 100
                #     start = 0
                #     slot_id = 3
                #     filler = f.create.Filler('sound', length)
                #     audio_clip =  mob.create_source_clip(slot_id, start, length)
                #     track1.segment.components.append(filler)
                #     track1.segment.components.append(audio_clip)

                # timeline_audio_slot = comp_mob.create_timeline_slot(video_rate)
                # timeline_audio_slot.segment= audio_sequence

        f.content.mobs.append(comp_mob)

        fp = 30
        fp = 24
        length = 60 * fp
        filler_len = 100
        timecode_fps = fp
        mob_count += 1

        test_path = "some_path.mov"

        for path in source_file:
            for mob in f.content.link_external_mxf(path):
                print(mob.name)
                # Add this to an audio track here....

        for i in range(10):

            # Make the Tape MOB
            tape_mob = f.create.SourceMob()
            tape_name = "tape_name"
            tape_slot, tape_timecode_slot = tape_mob.create_tape_slots(tape_name, video_rate, timecode_fps)
            tape_slot.segment.length = length

            f.content.mobs.append(tape_mob)
            mob_count += 1
            # Make a FileMob
            file_mob = f.create.SourceMob()

            # Make a locator
            loc = f.create.NetworkLocator()
            loc['URLString'].value = test_path

            file_description = f.create.CDCIDescriptor()
            file_description.locator.append(loc)

            file_description['ComponentWidth'].value = 8
            file_description['HorizontalSubsampling'].value = 4
            file_description['ImageAspectRatio'].value = '16/9'
            file_description['StoredWidth'].value = 1920
            file_description['StoredHeight'].value = 1080
            file_description['FrameLayout'].value = 'FullFrame'
            file_description['VideoLineMap'].value = [42, 0]
            file_description['SampleRate'].value = video_rate
            file_description['Length'].value = 10

            file_mob.descriptor = file_description

            clip = tape_mob.create_source_clip(slot_id=1, length=length)
            slot = file_mob.create_picture_slot(video_rate)

          

            slot.segment.components.append(clip)


            f.content.mobs.append(file_mob)
            mob_count += 1

            # Make the Master MOB
            master_mob = f.create.MasterMob()
            master_mob.name = "Master Mob %i" % i

            master_mob.comments['Test'] = 'Value'
            master_mob.comments.append(f.create.TaggedValue("Test2", 42))

            assert master_mob.comments['Test'] == "Value"
            assert master_mob.comments['Test2'] == 42

            clip = file_mob.create_source_clip(slot_id=1)
            assert clip.length == length
            slot = master_mob.create_picture_slot(video_rate)
            slot.segment.components.append(clip)

            f.content.mobs.append(master_mob)
            mob_count += 1

            # Create a SourceClip
            clip = master_mob.create_source_clip(slot_id=1)
            assert clip.length == length
            sequence.components.append(clip)
            components += 1

            # Create a filler
            comp_fill = f.create.Filler("picture", filler_len)
            sequence.components.append(comp_fill)
            components += 1
create_file()
@maptz
Copy link
Author

maptz commented Mar 11, 2023

Ok, I've done some digging into this and have solved my own issue. I can create a sequence linked to source clips. Here's my code below:

from __future__ import (
    unicode_literals,
    absolute_import,
    print_function,
    division,
    )
import dumper
import inspect
import aaf2
import os


os.system('cls') # for mac and linux os.system('clear')


source_files = ["Z:\\Avid MediaFiles\\MXF\\SFX_BBC_MXFs\\4Minute_BBA01.5E5D05003B53A.mxf",
               "Z:\\Avid MediaFiles\\MXF\\SFX_BBC_MXFs\\4Minute_BBA02.5E5D05003CA7A.mxf"]

with aaf2.open("output.aaf", "w")  as f:
    # Firstly, add links to existing MXF OP-Atom files
    # This creates mobs for each file, along with a MasterMob which links the individual stereo files.
    print("Adding MXF files")
    for source_file_path in source_files:
        f.content.link_external_mxf(source_file_path)

    # Get the MasterMob, so that we can use it.
    master_mob = next(mob for mob in f.content.mobs if isinstance(mob, aaf2.mobs.MasterMob))

    print("Creating a sequence")
    # Create a new 24 fps timeline.
    video_rate = " 24000/1001"
    # A timeline is a CompositionMob with TimelineMobSlots per track (video and audio)
    comp_mob = f.create.CompositionMob() # A sequence in Avid terminology
    comp_mob.name = "Test sequence"
    f.content.mobs.append(comp_mob)

    v1_timeline = comp_mob.create_timeline_slot(video_rate) #TimelineMobSlot, a track on a sequence
    a1_timeline = comp_mob.create_timeline_slot(video_rate)
    a2_timeline = comp_mob.create_timeline_slot(video_rate)

    # Each TimelineMobSlot has a segment property. This can hold a variety of different kinds of object, but the simplest
    # is a Sequence, which just represents a Sequence of sequential elements.
    v1_sequence = f.create.Sequence(media_kind="picture") #Sequence of elements
    a1_sequence = f.create.Sequence(media_kind="sound") #Sequence of elements
    a2_sequence = f.create.Sequence(media_kind="sound") #Sequence of elements

    v1_timeline.segment = v1_sequence
    a1_timeline.segment = a1_sequence
    a2_timeline.segment = a2_sequence

    # Now let's create 10 clips, and 10 spaces on each timeline
    for i in range(10):
        v1_clip = f.create.Filler('picture', 200)
        v1_sequence.components.append(v1_clip)
        
        # NOTE, a clip doesn't have a start timecode, and they are just placed sequentially.
        v1_clip = f.create.Filler('picture', 100)
        v1_sequence.components.append(v1_clip)
        
        a1_clip = master_mob.create_source_clip(slot_id=1) #get the first track from the master_mob, and create a source clip from it.
        a1_clip.start = 20 # Note, this is 20 edit_units in sequence units
        a1_clip.length = 200 # Note, if you want the full clip, have to get the length
        a1_sequence.components.append(a1_clip)

        a1_clip_2 = f.create.Filler('sound', 100)
        a1_sequence.components.append(a1_clip_2)
        
        a2_clip = master_mob.create_source_clip(slot_id=2) 
        a2_clip.length = 200
        a2_sequence.components.append(a2_clip)

        a2_clip_2 = f.create.Filler('sound', 100)
        a2_sequence.components.append(a2_clip_2)

    print("---")

print("MXF File written")

@maptz maptz closed this as completed Mar 11, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant