DVD file converter and combiner

Share your advanced PureBasic knowledge/code with the community.
User avatar
RichAlgeni
Addict
Addict
Posts: 914
Joined: Wed Sep 22, 2010 1:50 am
Location: Bradenton, FL

DVD file converter and combiner

Post by RichAlgeni »

I wrote this to convert family videos to mp4 files. It uses VLC, which is a fantastic open source converter and combiner. My code creates the command line needed to automate the procedure.

Code: Select all

EnableExplicit

#ProgramName    = "vlc_combiner"
#ProgramTitle   = "Windows VLC DVD Converter and Combiner"
#ProgramVersion = "1.0.01a." + #PB_Editor_BuildCount

Declare.i FormatNumberAsString(*numberString, decimalPlaces.i, useLeadingZeros.i, decimalGroupingNumber.i, negativeFormat.i, *bufferReturn, lenBufferReturn.i)

Define result.i
Define fileName.s
Define fileSize.i
Define thisLine.s
Define fileCount.i
Define totalSize.f
Define fileNumber.i
Define backSlashCt.i
Define newFileSize.f
Define programName.s
Define selectedDir.s
Define commandParam.s
Define newDirectory.s
Define baseFileName.s
Define fileSizeReturn.s
Define fileSizeString.s
Define directoryNumber.i
Define dvdPath.s    = "S:\VIDEO_TS\"
Define titleName.s  = "VLC Combiner"
Define initialDir.  = "d:\"

Structure fileNameSize
    fileNameLine.s
    fileSizeLine.i
EndStructure

Define NewList fileListName.fileNameSize()

; select a directory to write the mp4 and text file to

selectedDir = PathRequester(titleName, initialDir)

; loop thru the entries in a directory

If selectedDir > ""
    backSlashCt = CountString(selectedDir, "\")
    If backSlashCt < 2
        MessageRequester(titleName, "Cannot select the root of a disk")
        End
    EndIf

; extract the file name we will use to create the ,p4 file

    baseFileName = StringField(selectedDir, backSlashCt, "\")

; examine the dvd path directory, and get the VOB files needed

    directoryNumber = ExamineDirectory(#PB_Any, dvdPath, "*.vob")
    While NextDirectoryEntry(directoryNumber)
        If DirectoryEntryType(directoryNumber) = #PB_DirectoryEntry_File
            fileName = DirectoryEntryName(directoryNumber)
            fileSize = FileSize(dvdPath + fileName)
            If fileSize > 999999
                AddElement(fileListName())
                fileListName()\fileNameLine = dvdPath + fileName
                fileListName()\fileSizeLine = fileSize
                fileCount + 1
                totalSize + fileSize
            EndIf
        EndIf
    Wend

    FinishDirectory(directoryNumber)
EndIf

; if no files were found, end the process

If fileCount = 0
    MessageRequester(titleName, "No files found for combining")
    End
EndIf

; sort the files by name, so they are in the right order

SortList(fileListName(), #PB_Sort_Ascending | #PB_Sort_NoCase)

; now create the program command, and add the files needed

programName = #DOUBLEQUOTE$ + "C:\Program Files\VideoLAN\VLC\vlc.exe" + #DOUBLEQUOTE$
ForEach fileListName()
    fileName = fileListName()\fileNameLine
    commandParam + #DOUBLEQUOTE$ + fileName + #DOUBLEQUOTE$ + " "
Next

; now create the program parameters needed

commandParam + "--sout " + #DOUBLEQUOTE$ + "#gather:std{access=file,dst="
commandParam + baseFileName + ".mp4}" + #DOUBLEQUOTE$ + " --sout-keep vlc://quit"

; now write the command, paramaters and output params to a text file for verification

fileNumber = CreateFile(#PB_Any, selectedDir + baseFileName + ".txt", #PB_UTF8)
If fileNumber
    WriteStringN(fileNumber, programName, #PB_UTF8)
    WriteStringN(fileNumber, commandParam, #PB_UTF8)

    ForEach fileListName()
        fileName = fileListName()\fileNameLine
        fileSize = fileListName()\fileSizeLine

        fileSizeReturn = Space(20)
        fileSizeString = Str(fileSize)

        FormatNumberAsString(@fileSizeString, 0, 0, 3, 1, @fileSizeReturn, 20)

        thisLine = LSet(fileName, 40, " ") + RSet(fileSizeReturn, 20, " ")
        WriteStringN(fileNumber, thisLine, #PB_UTF8)
    Next

    CloseFile(fileNumber)
Else
    MessageRequester(titleName, "Unable to create '" + selectedDir + baseFileName + ".txt'")
EndIf

; run the program, and wait for it to end

RunProgram(programName, commandParam, selectedDir, #PB_Program_Wait)

; check the size of the new file, to make sure we have all files needed

newFileSize    = FileSize(selectedDir + baseFileName + ".mp4")
totalSize      = totalSize * 0.9
If newFileSize > totalSize
    MessageRequester(titleName, "Completed successfully")
Else
    MessageRequester(titleName, "Process was not successful")
EndIf

; **********************************************************************************
; this procedure formats a string number into the desired output
; **********************************************************************************

; numberString.s     - Number To format, sent as a string, because we don't know if it is am integer or float!
; decimalPlaces.i    - number of decimal places
; decimalSeparator.s - Decimal separator character
; groupSeparator.s   - Group separator Character
; negativeFormat.i    - Format negNumberative values
;                      0 = (000)
;                      1 = -000
;                      2 = - 000
;                      3 = 000-
;                      4 = 000 -

; set useLeadingZeros to 1 to pad with leading zeros
; set decimalGroupingNumber 0 or 3

Procedure.i FormatNumberAsString(*numberString, decimalPlaces.i, useLeadingZeros.i, decimalGroupingNumber.i, negativeFormat.i, *bufferReturn, lenBufferReturn.i)

    Protected numberFormat.NUMBERFMT
    Protected decimalSeparator.s{1} = "."
    Protected groupSeparator.s{1}   = ","
    Protected numberString.s        = PeekS(*numberString)

    numberFormat\NumDigits     = decimalPlaces
    numberFormat\LeadingZero   = useLeadingZeros
    numberFormat\Grouping      = decimalGroupingNumber
    numberFormat\lpDecimalSep  = @decimalSeparator
    numberFormat\lpThousandSep = @groupSeparator
    numberFormat\NegativeOrder = negativeFormat

    GetNumberFormat_(0, 0, numberString, numberFormat, *bufferReturn, lenBufferReturn)

EndProcedure