[PYTHON] Korrigieren Sie FLV-Dateien mit seltsamer Wiedergabezeit

Was du machen willst

In einigen FLV-Dateien betrug die Wiedergabezeit mehr als 2 Stunden, obwohl das Video etwa 2 Minuten betrug und das Video nicht gut abgespielt wurde. Korrigieren Sie dies, damit es sauber gespielt werden kann. FLV MetaData Injector scheint kein Problem zu sein, daher möchte ich die Ursache finden und beheben.

Suche nach der Ursache

Verwenden Sie vorerst FLV Extract, um in Videodateien (.264), Audiodateien (.aac) und Zeitcodes (.txt) zu unterteilen. Infolgedessen gab es kein Problem mit Video und Audio, und es schien ein Problem mit der Beschreibung des Zeitcodes zu geben. Wenn ich es öffne, sieht es wie folgt aus.

timecode.txt


# timecode format v2
0
0
70
134
334
609
952
1358
1816
2352
2957

Der Zeitcode, der in Millisekunden zunimmt, schwillt an und wächst. Darüber hinaus wird der numerische Wert manchmal kleiner (der Zeitcode enthält den numerischen Wert der verstrichenen Zeit, sodass er abnimmt = er sollte nicht zurückgespult werden ...).

1305237
1329824
1354481
24718
49511
74372
99290

Errate die Lösung

Nach verschiedenen Berechnungen

Es scheint so (zumindest sah es so aus). Die Berechnung basierend auf diesen Ergebnissen ist wie folgt.

0       -> 0
0       -> 0
70      -> 70
134     -> 134
334     -> 200
609     -> 275
952     -> 343
1358    -> 406
...
1329824 -> 24587
1354481 -> 24657
24718   -> 24718
49511   -> 24793
74372   -> 24861
99290   -> 24918

Es nimmt um ungefähr 66 (Millisekunden) (ungefähr 15 Frames Timecode) zu und sieht korrekt aus.

Code schreiben

Ich habe diese Nummer wie folgt geändert (jede Sprache ist akzeptabel, da es sich nur um Dateieingabe / -ausgabe und einfache Berechnung handelt).

timecode.py


import sys
import os
import datetime

filename =''

if(len(sys.argv) > 1):
	filename = os.path.abspath(sys.argv[1])
else:
    filename = 'timecode.txt'

f = open(filename)

lines = []
header = []

for i,line in enumerate(f.readlines()):
    #Trennen Sie den Zeitcode von der Kopfzeile am Zeilenanfang
    if(line.startswith('#') == False):
        lines.append(int(line))
    else:
        header.append(line)

f.close()

timecodes = []
val = 0

for i,line in enumerate(lines):
 
    #0 bleibt wie es ist
    if(line == 0):
         timecodes.append(line)
 
    #Ein Wert, der kleiner als die Vorderseite ist, wird als der richtige Zeitcode geschätzt. Fügen Sie ihn also so ein, wie er ist
    elif(line < lines[i-1]):
        if(timecodes[i-1] < line):
            timecodes.append(line)

        #Wenn unbestimmt (kleiner als der vorherige Timecode), fügen Sie den vorherigen Timecode unverändert ein
        else:
            timecodes.append(timecodes[i-1])

    else:
        #Wenn Sie den Unterschied zur vorherigen Zeile nehmen, scheint dies der richtige Zeitcode zu sein
        val = line - lines[i-1]

        #Wenn dieselbe Nummer weiterhin verwendet wird, stellen Sie die vorherige Nummer ein
        if(val == 0):
            timecodes.append(timecodes[i-1])
            
        #Wenn die Differenz kleiner als die Vorderseite ist (der ursprüngliche Wert wird als korrekter Zeitcode angenommen), fügen Sie ihn so ein, wie er ist
        elif(timecodes[i-1] > val):
            timecodes.append(line)

        #Wenn nicht, Diff einfügen
        else:
            timecodes.append(val)


#Erstellen Sie eine Zeichenfolgenliste mit einem Zeilenumbruch am Ende
output = [str(v)+'\n' for v in timecodes]


now = datetime.datetime.now()

#Timecode-Header einfügen
header.extend(output)

#Speichern Sie die Datei und beenden Sie sie
if(len(sys.argv) > 1):
    o_file,o_ext = os.path.splitext(os.path.abspath(sys.argv[1]))
    filename = o_file + now.strftime('_%Y%m%d%H%M%S') + o_ext
else:
    filename = 'timecode_change' + now.strftime('_%Y%m%d%H%M%S') + '.txt'

with open(filename, mode='w') as f:
    f.writelines(header)

Erstellen Sie eine Videodatei, die den korrigierten Zeitcode widerspiegelt

Ich habe MKVToolNix verwendet, um den geänderten Zeitcode mit dem ersten Video / Audio zu kombinieren. Als ich die fertige mkv-Datei abgespielt habe, hat sie sich wunderbar abgespielt.

Machen Sie es zu einer ausführbaren Datei

Verwenden Sie pyinstaller, um eine ausführbare Datei zu erstellen, damit sie von Personen verwendet werden kann, auf denen Python nicht installiert ist. Wenn Sie die Datei in die fertige timecode.exe ziehen und dort ablegen, wird die geänderte Timecode-Datei im selben Ordner generiert.

$ pyinstaller --onefile timecode.py

Rezension

** 1. Fügen Sie die FLV-Zieldatei in FLV Extract ein und teilen Sie sie in Video- / Audio- / Zeitcodedateien auf. 2. Bestimmen Sie die Korrekturlogik 3. Wenden Sie den obigen Korrekturprozess auf die Timecode-Datei an 4. Fügen Sie den geänderten Zeitcode und die geteilte Video- / Audiodatei in MKVToolNix ein und kombinieren Sie sie, um eine mkv-Datei zu erstellen. 5. Spiel **

Da es praktisch ist, 1 bis 4 zusammen verarbeiten zu können, habe ich es dem obigen Code hinzugefügt und es wurde wie folgt.

timecode.py


###################################################################################################
#
#Die Wiedergabezeit von FLV ist also seltsam
#Skript zum Ändern der aus FLV Extractor extrahierten Zeitcodedatei
#In Kombination mit Video- und Audiodateien mit MKV Toolnix unter Verwendung des geänderten Timecodes
#Wenn der Zeitcode dieser Regel entspricht, handelt es sich um eine MKV-Datei, die ordnungsgemäß abgespielt werden kann.
#Installieren Sie FLV Extract und MKV ToolNix und fügen Sie die ausführbare Datei in den Pfad ein.
#
###################################################################################################

import sys
import os
import datetime
import subprocess
import tempfile
import shutil

#===================================================================================================
#Timecode-Extraktion mit FLV-Extrakt
#===================================================================================================
def flvExtract(flvFilename,outputDir):

    cmd = [
        'flvextractcl',
        '-t',
        '-v',
        '-a',
        '-d',
        outputDir,
        flvFilename,
   ]
    print(flvFilename)
    subprocess.call(cmd)

#===================================================================================================
#Lesen und ändern Sie die Timecode-Datei
#===================================================================================================
def repairTimecode(timecodeFilename):

    f = open(timecodeFilename)

    lines = []
    header = []

    for i,line in enumerate(f.readlines()):
        #Trennen Sie den Zeitcode von der Kopfzeile am Zeilenanfang
        if(line.startswith('#') == False):
            lines.append(int(line))
        else:
            header.append(line)

    f.close()

    timecodes = []
    val = 0

    for i,line in enumerate(lines):
    
        #0 bleibt wie es ist
        if(line == 0):
            timecodes.append(line)
    
        #Ein Wert, der kleiner als die Vorderseite ist, wird als der richtige Zeitcode geschätzt. Fügen Sie ihn also so ein, wie er ist
        elif(line < lines[i-1]):
            if(timecodes[i-1] < line):
                timecodes.append(line)

            #Wenn unbestimmt (kleiner als der vorherige Timecode), fügen Sie den vorherigen Timecode unverändert ein
            else:
                timecodes.append(timecodes[i-1])

        else:
            #Wenn Sie den Unterschied zur vorherigen Zeile nehmen, scheint dies der richtige Zeitcode zu sein
            val = line - lines[i-1]

            #Wenn dieselbe Nummer weiterhin verwendet wird, stellen Sie die vorherige Nummer ein
            if(val == 0):
                timecodes.append(timecodes[i-1])
            
            #Wenn die Differenz kleiner als die Vorderseite ist (der ursprüngliche Wert wird als korrekter Zeitcode angenommen), fügen Sie ihn so ein, wie er ist
            elif(timecodes[i-1] > val):
                timecodes.append(line)

            #Wenn nicht, Diff einfügen
            else:
                timecodes.append(val)
        
        if(i > 0 and timecodes[i] < timecodes[i-1]):
            print(timecodes[i-1])
            print(timecodes[i])
            print('\n')

    #Erstellen Sie eine Zeichenfolgenliste mit einem Zeilenumbruch am Ende
    output = [str(v)+'\n' for v in timecodes]

    #Timecode-Header einfügen
    header.extend(output)

    #Datei durch Überschreiben speichern
    with open(timecodeFilename, mode='w') as f:
        f.writelines(header)

    return

#===================================================================================================
#Kombinieren Sie Video, Audio und geänderten Zeitcode mit MKVToolNIX
#===================================================================================================
def mkvMerge(video,audio,timecode,outputDir):

    now = datetime.datetime.now()
    basename = os.path.splitext(os.path.abspath(video))[0]
    mkv = basename + now.strftime('_%Y%m%d%H%M%S') + '.mkv'

    #Verwenden Sie mkvmerge
    #Erstellen Sie mkv, indem Sie verschiedene Dateien muxen
    cmd = [
        'mkvmerge',
        '-o',
        mkv,
        '--timecodes',
        '0:' + timecode,
        video,
        audio
    ]

    subprocess.call(cmd)

    #Ausgabe in das angegebene Verzeichnis
    shutil.move(mkv,outputDir)

    return

#===================================================================================================
#Hauptverarbeitung
#===================================================================================================
def main():

    flvFilename = ''

    #Dateinamen abrufen
    if(len(sys.argv) > 1):
        flvFilename = os.path.abspath(sys.argv[1])
    else:
        flvFilename = os.path.join(os.getcwd(),'test.flv')

    #Bereiten Sie drei Dateinamen vor: Video, Audio und Zeitcode
    o_file = os.path.splitext(os.path.basename(flvFilename))[0]
    outputDir = os.path.dirname(os.path.abspath(flvFilename))

    #Erstellen Sie ein temporäres Verzeichnis für die Arbeit
    with tempfile.TemporaryDirectory() as tmpDir:

        print(tmpDir+'\n')

        #Mit FLV-Extrakt extrahieren
        flvExtract(flvFilename,tmpDir)

        timecodeFilename = os.path.join(tmpDir,o_file + '.txt')
        videoFilename = os.path.join(tmpDir,o_file + '.264')
        audioFilename =os.path.join(tmpDir,o_file + '.aac')

        #Timecode-Reparatur und MKV-Erstellung, wenn Video- / Audio- / Timecode-Dateien vorhanden sind
        if(os.path.exists(timecodeFilename) and os.path.exists(videoFilename) and os.path.exists(audioFilename)):

            repairTimecode(timecodeFilename)
            mkvMerge(videoFilename,audioFilename,timecodeFilename,outputDir)
 

            #Fügen Sie für die zur Verarbeitung verwendete FLV-Datei dem Dateinamen einen Zeitstempel hinzu und verschieben Sie ihn in das FLV-Verzeichnis direkt darunter.
            os.makedirs(os.path.join(outputDir,'flv'),exist_ok=True)

            flv = datetime.datetime.now().strftime('%Y%m%d%H%M%S') + '_' + os.path.splitext(os.path.basename(flvFilename))[0] + '.flv'
            shutil.move(flvFilename,os.path.join(os.path.join(outputDir,'flv'),flv))
 

main()

abschließend

Dies war eine gute Sache, und ich konnte sie überhaupt nicht lösen, und es gab einige Dinge, denen ich nicht helfen konnte, weil der Zeitcode alle 0 war. (Es ist möglich, die Länge aus der Länge der Audiodatei zu berechnen, durch die Anzahl der Videobilder zu dividieren und einen vorläufigen Zeitcode auszugeben, aber die Klanglücke ist natürlich sehr groß.)

Wenn Sie jedoch in derselben Situation ein Problem haben, wird empfohlen, vorerst den Zeitcode zu überprüfen.

Recommended Posts

Korrigieren Sie FLV-Dateien mit seltsamer Wiedergabezeit
So messen Sie die Wiedergabezeit von MP3-Dateien mit Python
Laden Sie Dateien mit Django hoch
Korrigieren Sie die Datenbank mit pytest-docker