Subtitles SUP file: import PNGs via XML

Qbrick wrote on 9/6/2023, 8:23 AM

Hi,

With bdsup2sub++ I extracted PNGs and XML from a SUP file.

Now I have many PNG and an XML file:

<?xml version="1.0" encoding="UTF-8"?>
<BDN Version="0.93" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="BD-03-006-0093b BDN File Format.xsd">
  <Description>
    <Name Title="Subpictures_20_exp" Content=""/>
    <Language Code="eng"/>
    <Format VideoFormat="576i" FrameRate="25" DropFrame="False"/>
    <Events Type="Graphic" FirstEventInTC="00:02:15:04" LastEventOutTC="01:28:29:23" NumberofEvents="692"/>
  </Description>
  <Events>
    <Event InTC="00:02:15:04" OutTC="00:02:17:05" Forced="False">
      <Graphic Width="360" Height="70" X="180" Y="356">Subpictures_20_exp_0001_0.png</Graphic>
    </Event>
    <Event InTC="00:02:17:13" OutTC="00:02:18:23" Forced="False">
      <Graphic Width="349" Height="26" X="184" Y="399">Subpictures_20_exp_0002_0.png</Graphic>
    </Event>
    <Event InTC="00:02:19:04" OutTC="00:02:20:23" Forced="False">
      <Graphic Width="247" Height="76" X="236" Y="355">Subpictures_20_exp_0003_0.png</Graphic>
    </Event>
    <Event InTC="00:02:21:04" OutTC="00:02:23:11" Forced="False">
      <Graphic Width="274" Height="76" X="222" Y="355">Subpictures_20_exp_0004_0.png</Graphic>
    </Event>
    <Event InTC="00:02:23:19" OutTC="00:02:25:03" Forced="False">
      <Graphic Width="319" Height="25" X="199" Y="400">Subpictures_20_exp_0005_0.png</Graphic>
    </Event>
    <Event InTC="00:02:25:08" OutTC="00:02:27:16" Forced="False">
      <Graphic Width="416" Height="32" X="151" Y="399">Subpictures_20_exp_0006_0.png</Graphic>
    </Event>
    <Event InTC="00:02:49:16" OutTC="00:02:52:05" Forced="False">
      <Graphic Width="250" Height="25" X="233" Y="400">Subpictures_20_exp_0007_0.png</Graphic>
    </Event>
    <Event InTC="00:02:53:02" OutTC="00:02:53:23" Forced="False">
      <Graphic Width="206" Height="32" X="255" Y="399">Subpictures_20_exp_0008_0.png</Graphic>
    </Event>
    <Event InTC="00:02:54:04" OutTC="00:02:54:20" Forced="False">
      <Graphic Width="148" Height="31" X="285" Y="400">Subpictures_20_exp_0009_0.png</Graphic>
    </Event>
...
...
...
   </Events>
</BDN>

How can I import all PNGs in a video track of Vegas?

Thanks!

Comments

Dexcon wrote on 9/6/2023, 8:27 AM

How can I import all PNGs in a video track of Vegas?

Highlight the .png files in Vegas Pro's Explorer window and drag them on to Vegas Pro's timeline.

Cameras: Sony FDR-AX100E; GoPro Hero 11 Black Creator Edition

Installed: Vegas Pro 16, 17, 18, 19, 20 & 21, HitFilm Pro 2021.3, DaVinci Resolve Studio 18.5, BCC 2023.5, Mocha Pro 2023, Ignite Pro, NBFX TotalFX 7, Neat NR, DVD Architect 6.0, MAGIX Travel Maps, Sound Forge Pro 16, SpectraLayers Pro 11, iZotope RX10 Advanced and many other iZ plugins, Vegasaur 4.0

Windows 11

Dell Alienware Aurora 11

10th Gen Intel i9 10900KF - 10 cores (20 threads) - 3.7 to 5.3 GHz

NVIDIA GeForce RTX 2080 SUPER 8GB GDDR6 - liquid cooled

64GB RAM - Dual Channel HyperX FURY DDR4 XMP at 3200MHz

C drive: 2TB Samsung 990 PCIe 4.0 NVMe M.2 PCIe SSD

D: drive: 4TB Samsung 870 SATA SSD (used for media for editing current projects)

E: drive: 2TB Samsung 870 SATA SSD

F: drive: 6TB WD 7200 rpm Black HDD 3.5"

Dell Ultrasharp 32" 4K Color Calibrated Monitor

Qbrick wrote on 9/6/2023, 8:30 AM

How can I import all PNGs in a video track of Vegas?

Highlight the .png files in Vegas Pro's Explorer window and drag them on to Vegas Pro's timeline.

Thanks but I want import PNGs according to their properties :)

Examples:

<Event InTC="00:02:15:04" OutTC="00:02:17:05" Forced="False">       <Graphic Width="360" Height="70" X="180" Y="356">Subpictures_20_exp_0001_0.png</Graphic>

Plan B: convert them via OCR :-( export in SRT e import in Vegas

Dexcon wrote on 9/6/2023, 8:37 AM

In Project Properties, have you got "Adjust source media to better match project or render settings" unchecked? Unchecked, that should import video/stills at their original AR size.

Oh, are these subtitles? If yes, that's another thing that I can't help with mainly because I don't use subtitles.

Last changed by Dexcon on 9/6/2023, 8:40 AM, changed a total of 1 times.

Cameras: Sony FDR-AX100E; GoPro Hero 11 Black Creator Edition

Installed: Vegas Pro 16, 17, 18, 19, 20 & 21, HitFilm Pro 2021.3, DaVinci Resolve Studio 18.5, BCC 2023.5, Mocha Pro 2023, Ignite Pro, NBFX TotalFX 7, Neat NR, DVD Architect 6.0, MAGIX Travel Maps, Sound Forge Pro 16, SpectraLayers Pro 11, iZotope RX10 Advanced and many other iZ plugins, Vegasaur 4.0

Windows 11

Dell Alienware Aurora 11

10th Gen Intel i9 10900KF - 10 cores (20 threads) - 3.7 to 5.3 GHz

NVIDIA GeForce RTX 2080 SUPER 8GB GDDR6 - liquid cooled

64GB RAM - Dual Channel HyperX FURY DDR4 XMP at 3200MHz

C drive: 2TB Samsung 990 PCIe 4.0 NVMe M.2 PCIe SSD

D: drive: 4TB Samsung 870 SATA SSD (used for media for editing current projects)

E: drive: 2TB Samsung 870 SATA SSD

F: drive: 6TB WD 7200 rpm Black HDD 3.5"

Dell Ultrasharp 32" 4K Color Calibrated Monitor

jetdv wrote on 9/6/2023, 8:37 AM

You could modify my current tutorial series (3 parts and third part comes out next week):

Qbrick wrote on 9/6/2023, 8:42 AM

In Project Properties, have you got "Adjust source media to better match project or render settings" unchecked? Unchecked, that should import video/stills at their original AR size.

Oh, are these subtitles? If yes, that's another thing that I can't help with mainly because I don't use subtitles.

Exactly, they are subtitles :)

Qbrick wrote on 9/6/2023, 8:44 AM

You could modify my current tutorial series (3 parts and third part comes out next week):

Hi Jet! Sorry I'm not a progarmmer :)

Are you able to create a script to import the PNGs via one XML like the one I attached before?

Thanks!

jetdv wrote on 9/6/2023, 8:49 AM

Yes, that can be done. Could you create a zip file with the SUP file and the images so I could download them?

Qbrick wrote on 9/6/2023, 8:59 AM

Yes, that can be done. Could you create a zip file with the SUP file and the images so I could download them?

Super!

The file is: https://filetransfer.io/data-package/Cy4aexHJ#link

Anyway BDSup2Sub++ create every time a XML (same format everytime) and many PNGs.

I think there are necessary 2 scripts:

1) import PNGs via XML

2) (after I manually traslated the PNGs on the track) I would export the new XML (with the new timings) so I can recreate a SUP file with BDSup2Sub++

Is it possible? :)

jetdv wrote on 9/7/2023, 4:17 PM

Ok, I have a working script but I'm not sure all is correct. Here's what I got after running the script.

I change the project to 720x480 and got this result which, I think, is more what you are looking for:

jetdv wrote on 9/7/2023, 4:20 PM

@Qbrick But it's a long one and incorporates parts of many of the past tutorials:

using System;
using System.Collections.Generic;
using System.Collections;
using System.IO;
using System.Text;
using System.Windows.Forms;
using System.Globalization;
using System.Drawing;
using System.Runtime;
using System.Xml;
using ScriptPortal.Vegas;

namespace Test_Script
{
    public class Class1
    {
        public Vegas myVegas;
        private NumberFormatInfo myNumberFormat = NumberFormatInfo.InvariantInfo;
        private string[] filenames;
        private string clipitemFile;
        private string basePath;
        Timecode baseStartPosition;
        VideoTrack vTrack;
        AudioTrack aTrack;

        public void Main(Vegas vegas)
        {
            myVegas = vegas;

            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Filter = "Import Files (*.XML)|*.xml|All Files (*.*)|*.*";
            ofd.Multiselect = false;
            ofd.Title = "Select the file to import";
            ofd.InitialDirectory = "D:\\Edward_\\SUP Test"; //Change this to where you want it to look by default
            DialogResult dr = ofd.ShowDialog();
            if (dr == System.Windows.Forms.DialogResult.OK)
            {
                filenames = ofd.FileNames;

                vTrack = new VideoTrack(myVegas.Project, 0, "Subtitles");
                myVegas.Project.Tracks.Add(vTrack);

                foreach (string file in filenames)
                {
                    baseStartPosition = myVegas.Transport.CursorPosition;
                    processImportFile(file);
                    myVegas.UpdateUI();
                }
            }
        }

        private void processImportFile(string myFile)
        {
            basePath = Path.GetDirectoryName(myFile) + Path.DirectorySeparatorChar;

            XmlDocument doc = new XmlDocument();
            doc.Load(myFile);

            XmlElement root = doc.DocumentElement;
            foreach (XmlElement child in root)
            {
                if (child.Name.ToLower() == "events")
                {
                    foreach (XmlElement child2 in child)
                    {
                        if (child2.Name.ToLower() == "event")
                        {
                            processClipItem(child2);
                        }
                    }
                }
            }
        }

        private void processClipItem(XmlElement clipitem)
        {
            string StartTC = clipitem.GetAttribute("InTC");
            string EndTC = clipitem.GetAttribute("OutTC");
            int Width;
            int Height;
            int X;
            int Y;
            string FilePath;

            foreach (XmlElement child in clipitem)
            {
                FilePath = basePath + child.InnerText;
                Width = Convert.ToInt32(child.GetAttribute("Width"));
                Height = Convert.ToInt32(child.GetAttribute("Height"));
                X = Convert.ToInt32(child.GetAttribute("X"));
                Y = Convert.ToInt32(child.GetAttribute("Y"));
                VideoEvent vEvent = addClipToTimeline(FilePath, StartTC, EndTC);
                AdjustEventSizePosition(vEvent, Width, Height, X, Y);
            }
        }

        private VideoEvent addClipToTimeline(string fileName, string StartFrame, string EndFrame)
        {
            Media media = new Media(fileName);

            Timecode startTC = Timecode.FromString(StartFrame);
            Timecode lenTC = Timecode.FromString(EndFrame) - startTC;

            MediaStream stream = media.Streams.GetItemByMediaType(MediaType.Video, 0);
            VideoEvent vEvent = new VideoEvent(startTC, lenTC);
            vTrack.Events.Add(vEvent);
            Take myNewtake = new Take(stream);
            vEvent.Takes.Add(myNewtake);
            return vEvent;
        }

        private void AdjustEventSizePosition(VideoEvent vEvent, int Width, int Height, int X, int Y)
        {
            MatchAspect(vEvent);
            RestoreSize(vEvent);
            VideoMotionKeyframe kf = vEvent.VideoMotion.Keyframes[0];
            PositionImage(kf, (float)X, (float)Y);
        }

        public void PositionImage(VideoMotionKeyframe keyframe, float xPos, float yPos)
        {
            float scrWidth = myVegas.Project.Video.Width;
            float scrHeight = myVegas.Project.Video.Height;

            float xDif = scrWidth / 2 - xPos - keyframe.Center.X;
            float yDif = scrHeight / 2 - yPos - keyframe.Center.Y;

            VideoMotionVertex offset = new VideoMotionVertex(xDif, yDif);
            keyframe.MoveBy(offset);
        }

        public void RestoreSize(VideoEvent videoEvent)
        {
            float scrWidth = myVegas.Project.Video.Width;
            float scrHeight = myVegas.Project.Video.Height;

            VideoMotionKeyframes keyframes = videoEvent.VideoMotion.Keyframes;
            int cKeyframes = keyframes.Count;
            for (int jj = cKeyframes - 1; jj >= 0; jj--)
            {
                VideoMotionKeyframe thisKeyframe = keyframes[jj] as VideoMotionKeyframe;

                float dWidth = Math.Abs(thisKeyframe.TopRight.X - thisKeyframe.TopLeft.X);
                float dHeight = Math.Abs(thisKeyframe.BottomLeft.Y - thisKeyframe.TopLeft.Y); ;

                MediaStream mediaStream = GetActiveMediaStream(videoEvent);
                VideoStream videoStream = mediaStream as VideoStream;
                VideoOutputRotation vRotation = videoStream.Rotation;

                float dFullHeight = videoStream.Height;
                float dFullWidth = videoStream.Width;
                if ((vRotation == VideoOutputRotation.QuarterTurnClockwise) || (vRotation == VideoOutputRotation.QuarterTurnCounterclockwise))
                {
                    dFullHeight = videoStream.Width;
                    dFullWidth = videoStream.Height;
                }

                float pwid = 0.0F;
                float wpwid = 0.0F;

                if (dFullHeight > scrHeight)
                {
                    pwid = dFullHeight / dHeight * 100;
                }
                else
                {
                    pwid = dHeight / scrHeight * 100;
                }

                if (dFullWidth > scrWidth)
                {
                    wpwid = dFullWidth / dWidth * 100;
                }

                if (wpwid > pwid)
                {
                    pwid = wpwid;
                }

                ScaleKeyframe(thisKeyframe, pwid, 0);
            }

        }

        public void MatchAspect(TrackEvent trackEvent)
        {
            float dWidthProject = myVegas.Project.Video.Width;
            float dHeightProject = myVegas.Project.Video.Height;
            double dPixelAspect = myVegas.Project.Video.PixelAspectRatio;
            double dAspect = dPixelAspect * dWidthProject / dHeightProject;

            MediaStream mediaStream = GetActiveMediaStream(trackEvent);
            if (!(mediaStream == null))
            {
                VideoStream videoStream = mediaStream as VideoStream;

                double dMediaPixelAspect = videoStream.PixelAspectRatio;
                VideoEvent videoEvent = trackEvent as VideoEvent;
                VideoMotionKeyframes keyframes = videoEvent.VideoMotion.Keyframes; ;

                int cKeyframes = keyframes.Count;

                for (int jj = cKeyframes - 1; jj >= 0; jj--)
                {
                    VideoMotionKeyframe thisKeyframe = keyframes[jj] as VideoMotionKeyframe;
                    MatchOutputAspect(thisKeyframe, dMediaPixelAspect, dAspect);
                }
            }
            myVegas.UpdateUI();
        }

        public MediaStream GetActiveMediaStream(TrackEvent trackEvent)
        {
            try
            {
                if (!(trackEvent.ActiveTake.IsValid()))
                {
                    throw new ArgumentException("empty or invalid take");
                }

                Media media = myVegas.Project.MediaPool.Find(trackEvent.ActiveTake.MediaPath);
                if (null == media)
                {
                    MessageBox.Show("missing media");
                    throw new ArgumentException("missing media");
                }

                MediaStream mediaStream = media.Streams.GetItemByMediaType(MediaType.Video, trackEvent.ActiveTake.StreamIndex);
                return mediaStream;
            }
            catch (Exception e)
            {
                MessageBox.Show("{0}", e.Message);
                return null;
            }
        }

        public void MatchOutputAspect(VideoMotionKeyframe keyframe, double dMediaPixelAspect, double dAspectOut)
        {
            VideoMotionKeyframe keyframeSave = keyframe;

            try
            {
                double rotation = keyframe.Rotation;
                keyframe.RotateBy(-rotation);

                float dWidth = Math.Abs(keyframe.TopRight.X - keyframe.TopLeft.X);
                float dHeight = Math.Abs(keyframe.BottomLeft.Y - keyframe.TopLeft.Y);
                double dCurrentAspect = dMediaPixelAspect * dWidth / dHeight;
                float centerY = keyframe.Center.Y;
                float centerX = keyframe.Center.X;
                double dFactor;

                VideoMotionBounds bounds = new VideoMotionBounds(keyframe.TopLeft, keyframe.TopRight, keyframe.BottomRight, keyframe.BottomLeft);
                if (dCurrentAspect < dAspectOut)
                {
                    // alter y coords            
                    dFactor = dCurrentAspect / dAspectOut;

                    bounds.TopLeft.Y = (bounds.TopLeft.Y - centerY) * (float)dFactor + centerY;
                    bounds.TopRight.Y = (bounds.TopRight.Y - centerY) * (float)dFactor + centerY;
                    bounds.BottomLeft.Y = (bounds.BottomLeft.Y - centerY) * (float)dFactor + centerY;
                    bounds.BottomRight.Y = (bounds.BottomRight.Y - centerY) * (float)dFactor + centerY;
                }
                else
                {
                    // alter x coords
                    dFactor = dAspectOut / dCurrentAspect;

                    bounds.TopLeft.X = (bounds.TopLeft.X - centerX) * (float)dFactor + centerX;
                    bounds.TopRight.X = (bounds.TopRight.X - centerX) * (float)dFactor + centerX;
                    bounds.BottomLeft.X = (bounds.BottomLeft.X - centerX) * (float)dFactor + centerX;
                    bounds.BottomRight.X = (bounds.BottomRight.X - centerX) * (float)dFactor + centerX;
                }

                // set it to new bounds
                keyframe.Bounds = bounds;

                // restore rotation.        
                keyframe.RotateBy(rotation);
            }
            catch
            {
                // restore original settings on error
                keyframe = keyframeSave;
            }
        }

        public void ScaleKeyframe(VideoMotionKeyframe keyframe, float szChange, float rotAngle)
        {
            float cWidth = (1 / (szChange / 100));
            float cHeight = (1 / (szChange / 100));

            if (szChange > 100)
            {
                cWidth = (szChange / 100);
                cHeight = (szChange / 100);
            }

            VideoMotionVertex bounds = new VideoMotionVertex(cWidth, cHeight);

            keyframe.ScaleBy(bounds);
            keyframe.RotateBy((rotAngle * (Math.PI / 180)));
        }
    }
}

public class EntryPoint
{
    public void FromVegas(Vegas vegas)
    {
        Test_Script.Class1 test = new Test_Script.Class1();
        test.Main(vegas);
    }
}

 

jetdv wrote on 9/7/2023, 4:33 PM

Also, the script assumes all of the images are in the same folder as the XML file. The script will also create a new track at the top to place all of the subtitle images.

Qbrick wrote on 9/8/2023, 1:25 AM

Also, the script assumes all of the images are in the same folder as the XML file. The script will also create a new track at the top to place all of the subtitle images.

@Jetdv your script is super! It avoids SRT/OCR (when you don't need modify the text) 😀

I created a cs file named "SUP - Import.cs" inside "C:\Users\***\Documents\Vegas Script Menu"

Now I chose the first subtitle and translate some seconds before and lengthen it of some seconds.

How can I export/create the new "Subpictures_20_exp.xml" to "Subpictures_20_exp (1).xml" ?

I think I need a new script please😬

jetdv wrote on 9/8/2023, 6:24 AM

@Qbrick So now you want it to create a new file based on the length changes you made to the timeline? It would be easier to get you an entire set of new images at full size to create the new file as the old file names are not saved anywhere and it would be difficult to reverse engineer the position information. If the full sized images could be exported too, this wouldn't be too bad to do.

Qbrick wrote on 9/8/2023, 6:33 AM

@jetdv: plan B --> could you parse all PNG on track (obtaining name, start position, end position for each one) and save a new XML file with the same structure as the original. Is too difficult ? 🙃

PS 1

I don't care about size/resize of PNG because I can do directly when I import on BDSup2Sub

PS 2
sorry for my poor english. Your is much better 😬

jetdv wrote on 9/8/2023, 1:03 PM

I can duplicate this:

<Event InTC="00:02:21:04" OutTC="00:02:23:11" Forced="False">
       <Graphic Width="274" Height="76" X="222" Y="355">Subpictures_20_exp_0004_0.png</Graphic>
</Event>

with modified InTC, OutTC with all other information exactly the same EXCEPT the "X" and "Y" values which is why I was saying it might be better to create an entirely new set of images that all had X/Y of 0/0 as they are all full screen in size.

Qbrick wrote on 9/8/2023, 1:09 PM

I can duplicate this:

<Event InTC="00:02:21:04" OutTC="00:02:23:11" Forced="False">
       <Graphic Width="274" Height="76" X="222" Y="355">Subpictures_20_exp_0004_0.png</Graphic>
</Event>

with modified InTC, OutTC with all other information exactly the same EXCEPT the "X" and "Y" values which is why I was saying it might be better to create an entirely new set of images that all had X/Y of 0/0 as they are all full screen in size.

Please don't modify coordinates because I need only intc and outtc. 😉

Parsing Is necessary because of I have to delete some PNG on timeline...

jetdv wrote on 9/8/2023, 1:26 PM

I don't know the original X/Y values after the import is completed. So that information would have to be saved somewhere/someway on the original import. Short answer, yes it can be done. But it will take some more work to save the original information - especially since you are deleting items from the timeline.

I'll look into additional changes to this script as well as an exporting script but it certainly won't be this week. At least, for now, you have something that *WILL* import correctly!

Qbrick wrote on 9/8/2023, 1:36 PM

I don't know the original X/Y values after the import is completed. So that information would have to be saved somewhere/someway on the original import. Short answer, yes it can be done. But it will take some more work to save the original information - especially since you are deleting items from the timeline.

I'll look into additional changes to this script as well as an exporting script but it certainly won't be this week. At least, for now, you have something that *WILL* import correctly!

Thanks for your support!

Take your time 😉

 

jetdv wrote on 9/13/2023, 3:54 PM

@Qbrick, will this always be the same?

<Format VideoFormat="576i" FrameRate="25" DropFrame="False"/>

576i seems odd... In searching, it appears that is the "number of scan lines" so it would be a 720x576 project. At least initially, I'm assuming that line could just be hard coded in.

Qbrick wrote on 9/13/2023, 4:01 PM

@Qbrick, will this always be the same?

<Format VideoFormat="576i" FrameRate="25" DropFrame="False"se/>

576i seems odd... In searching, it appears that is the "number of scan lines" so it would be a 720x576 project. At least initially, I'm assuming that line could just be hard coded in.

Not worry about that :)

The important thing Is to be able move subtitles on timeline and change their duration. Then export them on the XML with these new values.

Nothing more :)

Thanks

 

jetdv wrote on 9/15/2023, 12:49 PM

@Qbrick It would be best if you choose the same folder for export. The title names are NOT changed so if you import again, it will assume that the files are in the same folder as this output file. Just give the output file a different name. But this does seem to provide all of the correct information so give it a try...
 

using System;
using System.Collections.Generic;
using System.Collections;
using System.IO;
using System.Text;
using System.Windows.Forms;
using System.Globalization;
using System.Drawing;
using System.Runtime;
using System.Xml;
using ScriptPortal.Vegas;

namespace Test_Script
{
    public class Class1
    {
        public Vegas myVegas;
        private static System.Text.Encoding myCharacterEncoding = System.Text.Encoding.UTF8;

        public void Main(Vegas vegas)
        {
            myVegas = vegas;

            SaveFileDialog svd = new SaveFileDialog();
            svd.InitialDirectory = "D:\\Edward_\\SUP Test"; //Change this to where you want it to look by default;
            svd.Filter = "Save Files (*.XML)|*.xml|All Files (*.*)|*.*"; ;
            svd.FilterIndex = 1;
            svd.RestoreDirectory = true;
            if (svd.ShowDialog() == DialogResult.OK)
            {
                foreach (Track myTrack in myVegas.Project.Tracks)
                {
                    if (myTrack.Selected && myTrack.IsVideo())
                    {
                        ExportXML(svd.FileName, myTrack);
                        break;
                    }
                }
            }
        }

        private void ExportXML(string myFile, Track myTrack)
        {

            XmlDocument doc = new XmlDocument();
            XmlProcessingInstruction xmlPI = doc.CreateProcessingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\"");
            doc.AppendChild(xmlPI);

            var root = doc.CreateElement("BDN");
            root.SetAttribute("Version", "0.93");
            //root.SetAttribute("xmlns", "http://www/org/2007");
            root.SetAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
            root.SetAttribute("noNamespaceSchemaLocation", "http://www.w3.org/2001/XMLSchema-instance", "BD-03-006-0093b BDN File Format.xsd");
            doc.AppendChild(root);

            //Description section
            XmlElement desc = AddChild(root, "Description");
            XmlElement name = AddChild(desc, "Name");
            name.SetAttribute("Title", Path.GetFileNameWithoutExtension(myFile));
            name.SetAttribute("Content", "");
            XmlElement lang = AddChild(desc, "Language");
            lang.SetAttribute("Code", "eng");
            XmlElement format = AddChild(desc, "Format");
            format.SetAttribute("VideoFormat", "576i");
            format.SetAttribute("FrameRate", "25");
            format.SetAttribute("DropFrame", "False");

            XmlElement ev1 = AddChild(desc, "Events");
            ev1.SetAttribute("Type", "Graphic");
            ev1.SetAttribute("FirstEventInTC", myTrack.Events[0].Start.ToString());
            ev1.SetAttribute("LastEventOutTC", myTrack.Events[myTrack.Events.Count - 1].End.ToString());
            ev1.SetAttribute("NumberofEvents", myTrack.Events.Count.ToString());

            //All Events
            XmlElement ev2 = AddChild(root, "Events");
            foreach(VideoEvent evnt in myTrack.Events)
            {
                XmlElement oneev = AddChild(ev2, "Event");
                oneev.SetAttribute("InTC", evnt.Start.ToString());
                oneev.SetAttribute("OutTC", evnt.End.ToString());
                oneev.SetAttribute("Forced", "False");

                XmlElement graphic = ChildString(oneev, "Graphic", Path.GetFileName(evnt.ActiveTake.Media.FilePath));
                VideoStream vs = evnt.ActiveTake.Media.GetVideoStreamByIndex(0);
                graphic.SetAttribute("Width", vs.Width.ToString());
                graphic.SetAttribute("Height", vs.Height.ToString());

                VideoMotionKeyframe kf = evnt.VideoMotion.Keyframes[0];
                float X = myVegas.Project.Video.Width / 2 - kf.Center.X;
                float Y = myVegas.Project.Video.Height / 2 - kf.Center.Y;
                graphic.SetAttribute("X", X.ToString());
                graphic.SetAttribute("Y", Y.ToString());
            }


            XmlTextWriter writer = new XmlTextWriter(myFile, myCharacterEncoding);
            writer.Formatting = Formatting.Indented;
            writer.Indentation = 2;
            writer.IndentChar = ' ';
            doc.WriteTo(writer);
            writer.Close();


        }

        private static XmlElement AddChild(XmlElement parent, String childName)
        {
            return ChildString(parent, childName, null);
        }

        private static XmlElement ChildString(XmlElement parent, String childName, String childValue)
        {
            XmlElement child = parent.OwnerDocument.CreateElement(childName);
            parent.AppendChild(child);
            if (null != childValue)
                child.InnerText = childValue.ToString();
            return child;
        }

    }
}

public class EntryPoint
{
    public void FromVegas(Vegas vegas)
    {
        Test_Script.Class1 test = new Test_Script.Class1();
        test.Main(vegas);
    }
}

 

Qbrick wrote on 9/15/2023, 2:55 PM

@jetdv I think is perfect at 99,9% :D

When I export the new XML, there are these differences. Can you fix it please ? :)

jetdv wrote on 9/15/2023, 3:05 PM

@Qbrick What differences? My sample looked spot on and I don't see anything listed in your last response showing differences.

jetdv wrote on 9/15/2023, 3:10 PM

@Qbrick the only difference I'm really seeing is my timecodes have ":" as the final separator and yours has ";". I'm just using the VEGAS ".ToString()" to convert it so I really have no control over which ":" vs ";" is used but it shouldn't make any difference in usage. Otherwise, the exported information looks spot-on.