Create DICOM Files with H264 Video - Console C#

This tutorial shows how to configure the LEADTOOLS DICOM Writer filter to create a dataset with H.264 in MPEG-2 Transport in a C# Window Console application using the LEADTOOLS SDK.

Note

This tutorial encodes HD video through resizing a sample LEADTOOLS media file to create an MPEG-4 AVC/H.264 BD-compatible DICOM file.

Overview  
Summary This tutorial covers how to use the LEADTOOLS DICOM Writer filter to create DICOM files with H.264 compressed video in a C# Windows Console application.
Completion Time 30 minutes
Visual Studio Project Download tutorial project (5 KB)
Platform Windows Console C# Application
IDE Visual Studio 2019, 2022
Development License Download LEADTOOLS

Required Knowledge

Get familiar with the basic steps of creating a project by reviewing the Add References and Set a License tutorial, before working on the Create DICOM Files with H264 Video - Console C# tutorial.

Create the Project and Add LEADTOOLS References

Start with a copy of the project created in the Add References and Set a License tutorial. If you do not have that project, follow the steps in that tutorial to create it.

The references needed depend upon the purpose of the project. References can be added by the use of local DLL references. The following DLLs are needed.

The DLLs are located at <INSTALL_DIR>\LEADTOOLS22\Bin\Dotnet4\x64:

For a complete list of which DLL files are required for your application, refer to Files to be Included in your Application.

Set the License File

The License unlocks the features needed for the project. It must be set before any toolkit function is called. For details, including tutorials for different platforms, refer to Setting a Runtime License.

There are two types of runtime licenses:

Add the Create DICOM File Code

With the project created, the references added, and the license set, coding can begin.

In the Solution Explorer, open Program.cs. Add the following statements to the using block at the top of Program.cs:

C#
using System; 
using System.IO; 
 
using Leadtools; 
using Leadtools.Dicom; 
using Leadtools.Dicom.Common.DataTypes; 
using Leadtools.Dicom.Common.Extensions; 
using Leadtools.Multimedia; 
using LTDicWrtLib; 

Be sure to add the following global variable:

C#
static ConvertCtrl convert; 

Inside the Program class, add a new method named CreateDICOMFile(). Call this method inside the Main() method, as shown below. Also, be sure to indicate that the COM threading model for the application is Single-threaded Apartment (STA) by adding [STAThread].

C#
[STAThread] 
static void Main(string[] args) 
{ 
    SetLicense(); 
    CreateDICOMFile(); 
} 

Add the below code to the CreateDICOMFile() method to encode HD video to create an MPEG-4 AVC/H.264 BD-compatible DICOM file. You can download the .DS temporary file used for this tutorial here.

C#
private static void CreateDICOMFile() 
{ 
    string templateFile = @"FILE PATH TO TEMP Video_Photography.DS FILE"; 
    string inputFile = @"C:\LEADTOOLS22\Resources\Media\DaDa_H264.mp4"; 
    string outputFile = @"FILE PATH TO OUTPUT THE DCM FILE TO"; 
 
    // Create instance of Convert control. 
    convert = new ConvertCtrl(); 
 
    // Set the source and target files 
    convert.SourceFile = inputFile; 
    convert.TargetFile = outputFile; 
 
    // Need to resize sample video to be HD since no HD videos are in the SDK setup 
    convert.SelectedVideoProcessors.Add(convert.VideoProcessors.Resize); 
 
    LMVResizeLib.LMVResize resizeFilter = convert.GetSubObject(ConvertObject.SelVideoProcessor + 0) as LMVResizeLib.LMVResize; 
    resizeFilter.ForceSquarePixelOutput = true; 
    resizeFilter.Height = 1080; 
    resizeFilter.Width = 1920; 
    resizeFilter.OutputAspectRatioMode = LMVResizeLib.OutputAspectRatioModeConstants.OUTPUTASPECTRATIO_16_9; 
    resizeFilter.HeightControlMode = LMVResizeLib.SizeControlModeConstants.SIZECONTROL_FIXED; 
    resizeFilter.WidthControlMode = LMVResizeLib.SizeControlModeConstants.SIZECONTROL_FIXED; 
 
    // Done configuring the resize filter 
    System.Runtime.InteropServices.Marshal.ReleaseComObject(resizeFilter); 
    resizeFilter = null; 
 
    convert.VideoCompressors.H264.Selected = true; 
    convert.AudioCompressors.AAC.Selected = true; 
 
    LMH264EncoderLib.LMH264Encoder h264Encoder = convert.GetSubObject(ConvertObject.VideoCompressor) as LMH264EncoderLib.LMH264Encoder; 
    h264Encoder.EnableRateControl = false; 
    h264Encoder.QualityFactor = 28; 
    h264Encoder.FrameRate = 29.970f; 
    h264Encoder.EncodingSpeed = LMH264EncoderLib.eH264ENCODINGSPEED.H264SPEED_4; 
    h264Encoder.EncodingThreads = LMH264EncoderLib.eH264ENCODINGTHREADS.H264THREAD_AUTO; 
    h264Encoder.IFrameInterval = 11; 
    h264Encoder.PFrameInterval = 1; 
    h264Encoder.OutputFormat = LMH264EncoderLib.eH264OUTPUTFORMAT.H264FORMAT_HIGH_H264; 
 
    // Done configuring the filter 
    System.Runtime.InteropServices.Marshal.ReleaseComObject(h264Encoder); 
    h264Encoder = null; 
 
    // set the format 
    convert.TargetFormat = TargetFormatType.MPEG2TransportDICOM; 
 
    // Get the Dicom writer filter and set some options 
    //NOTE: MPEG-2 Transport is the target filter here 
    //      DICOM writer is the file writer/Sink filter 
    ILTDicWrt2 dicomWriter = (ILTDicWrt2)convert.GetSubObject(ConvertObject.Sink); 
    dicomWriter.DICOMTemplateFile = templateFile; 
 
    dicomWriter.MPEG2DicomCompatibilityOption = MPEG2DicomCompatibilityConstants.MPEG2DICOMCOMP_IGNORE; 
 
 
    // Done configuring the filter 
    System.Runtime.InteropServices.Marshal.ReleaseComObject(dicomWriter); 
    dicomWriter = null; 
 
    // Add some event handlers 
    convert.Progress += new ProgressEventHandler(convert_Progress); 
    convert.Complete += new EventHandler(convert_Complete); 
 
    Console.WriteLine(string.Format("Starting to Convert {0}", convert.TargetFile)); 
    convert.StartConvert(); 
 
    while (convert.State != ConvertState.Stopped) 
    { 
        System.Windows.Forms.Application.DoEvents(); 
    } 
 
    DicomEngine.Startup(); 
 
    DicomDataSet ds = new DicomDataSet(); 
    ds.Load(convert.TargetFile, DicomDataSetLoadFlags.LoadAndClose); 
    PatientBase patientBase = ds.Get<PatientBase>(); 
    patientBase.PatientName = new PersonName("Smith^John"); 
    patientBase.PatientSex = PatientSex.Male; 
    patientBase.PatientID = "1234567890"; 
    patientBase.PatientBirthDate = DateTime.Parse("09/18/1970"); 
    patientBase.PatientBirthTime = DateTime.Parse(DateTime.Now.ToShortTimeString()); 
    ds.Set(patientBase); 
 
 
    DicomElement element; 
    element = ds.FindFirstElement(null, DicomTag.SOPInstanceUID, true); 
    if (element != null) 
        ds.SetValue(element, Leadtools.DicomDemos.Utils.GenerateDicomUniqueIdentifier()); 
 
    GenerateUidTag(ds, DicomTag.StudyInstanceUID); 
    GenerateUidTag(ds, DicomTag.SeriesInstanceUID); 
    GenerateUidTag(ds, DicomTag.SOPInstanceUID); 
 
    ds.Save(convert.TargetFile, DicomDataSetSaveFlags.None); 
 
    DicomEngine.Shutdown(); 
 
    Console.WriteLine("Patient information updated and new UIDs generated."); 
} 

Inside the Program class, add a new method named GenerateUidTag(DicomDataSet dicom, long UidTag). This method will be called inside the CreateDICOMFile() method, as shown above, to create unique identifiers.

C#
private static void GenerateUidTag(DicomDataSet dicom, long UidTag) 
{ 
    DicomElement element; 
    element = dicom.FindFirstElement(null, UidTag, true); 
    if (element != null) 
        dicom.SetValue(element, Leadtools.DicomDemos.Utils.GenerateDicomUniqueIdentifier()); 
} 

Add two new event handlers inside the Program class named convert_Complete(object sender, EventArgs e) and convert_Progress(object sender, ProgressEventArgs e). These will be used inside the CreateDICOMFile() method as shown above and will serve the purpose of printing out the application progress to the console. These are optional.

C#
private static void convert_Complete(object sender, EventArgs e) 
{ 
    Console.WriteLine(string.Format("\nConversion of \"{0}\" complete!", convert.TargetFile)); 
} 
 
private static void convert_Progress(object sender, ProgressEventArgs e) 
{ 
    Console.Write(string.Format("\rConversion progress: {0}%", e.percent)); 
} 

Add the Utils Helper Class

Right-click on <PROJECT_NAME>.csproj in the Solution Explorer and select Add -> New Item.... Select the Class option and name the file Utils.cs.

Add the following statements to the using block at the top of Utils.cs:

C#
using System; 
using System.Text; 
using System.Diagnostics; 

Inside the Utils class, add the following variables.

C#
private static String _prevTime; 
private static String _leadRoot = null; 
private static Object _lock = new object(); 
private static int _count = 0; 
private const int _maxCount = int.MaxValue; 

Add a new method to the Utils class named GenerateDicomUniqueIdentifier(). Add the code below to generate the UIDs.

C#
public static string GenerateDicomUniqueIdentifier() 
{ 
    try 
    { 
        lock (_lock) 
        { 
            // yyyy     four digit year 
            // MM       month from 01 to 12 
            // dd       01 to 31 
            // HH       hours using a 24-hour clock form 00 to 23 
            // mm       minute 00 to 59 
            // ss       second 00 to 59 
            // fffffff  ten millionths of a second 
            const string dateFormatString = "yyyyMMdd.HHmmss.fffffff"; 
 
            string sUidRet = ""; 
            if (_leadRoot == null) 
            { 
                StringBuilder sb = new StringBuilder(); 
 
                sb.Append("1.2.840.114257.1.1"); 
 
                // Process Id 
                sb.AppendFormat(".{0}", (uint)Process.GetCurrentProcess().Id); 
 
                _leadRoot = sb.ToString(); 
 
                _prevTime = DateTime.UtcNow.ToString(dateFormatString); 
            } 
 
            StringBuilder uid = new StringBuilder(); 
            uid.Append(_leadRoot); 
 
            String time = DateTime.UtcNow.ToString(dateFormatString); 
            if (time.Equals(_prevTime)) 
            { 
                if (_count == _maxCount) 
                    throw new Exception("GenerateDicomUniqueIdentifier error -- max count reached."); 
 
                _count++; 
            } 
            else 
            { 
                _count = 1; 
                _prevTime = time; 
            } 
 
            uid.AppendFormat(".{0}.{1}", time, _count); 
 
            sUidRet = uid.ToString(); 
 
            // This should not happen 
            if (sUidRet.Length > 64) 
                sUidRet = sUidRet.Substring(0, 64); 
 
            return sUidRet; 
        } 
    } 
    catch (Exception ex) 
    { 
        throw ex; 
    } 
} 

Run the Project

Run the project by pressing F5, or by selecting Debug -> Start Debugging.

If the steps were followed correctly, the application runs and creates a dataset with H.264 in MPEG-2 Transport. You can find the expected output DCM and AVI files here.

Wrap-up

This tutorial showed how to use the LEADTOOLS DICOM Writer filter to create a dataset with H.264 in MPEG-2 Transport. It also covered how to use the DicomElement class, DicomDataSet class, ConvertCtrl class, and the ILTDicWrt2 interface.

See Also

Help Version 22.0.2024.3.20
Products | Support | Contact Us | Intellectual Property Notices
© 1991-2023 LEAD Technologies, Inc. All Rights Reserved.

Products | Support | Contact Us | Intellectual Property Notices
© 1991-2023 LEAD Technologies, Inc. All Rights Reserved.