In some FLV files, the playback time was more than 2 hours even though the video was about 2 minutes, and the video did not play well. Fix this so that it can be played cleanly. FLV MetaData Injector doesn't seem to be a problem, so I'd like to find the cause and fix it.
For the time being, use FLV Extract to divide into video files (.264), audio files (.aac), and time code (.txt). As a result, there was no problem with the video and audio, and there seemed to be a problem with the time code description. When I open it, it looks like the following.
timecode.txt
# timecode format v2
0
0
70
134
334
609
952
1358
1816
2352
2957
Timecode, which increases in milliseconds, swells and grows. Moreover, the numerical value sometimes becomes smaller (the time code contains the numerical value of the elapsed time, so it decreases = it should not rewind ...).
1305237
1329824
1354481
24718
49511
74372
99290
After doing various calculations,
It seems that (at least it looked like that). The calculation based on these results is as follows.
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
It's increasing by about 66 (milliseconds) (about 15 frames of timecode) and looks correct.
I modified this number as follows (any language is acceptable as it is only file input / output and simple calculation)
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()):
#Separate the header and timecode at the beginning of the line
if(line.startswith('#') == False):
lines.append(int(line))
else:
header.append(line)
f.close()
timecodes = []
val = 0
for i,line in enumerate(lines):
#0 remains as it is
if(line == 0):
timecodes.append(line)
#A value smaller than the front is estimated to be the correct timecode, so insert it as it is
elif(line < lines[i-1]):
if(timecodes[i-1] < line):
timecodes.append(line)
#If indefinite (smaller than the previous timecode), insert the previous timecode as is
else:
timecodes.append(timecodes[i-1])
else:
#If you take the difference from the previous line, it seems to be the correct timecode
val = line - lines[i-1]
#If the same number continues, set the previous number
if(val == 0):
timecodes.append(timecodes[i-1])
#If the difference is smaller than the front (the original value is assumed to be the correct timecode), insert it as it is.
elif(timecodes[i-1] > val):
timecodes.append(line)
#If not, insert diff
else:
timecodes.append(val)
#Make a string list with a line break at the end
output = [str(v)+'\n' for v in timecodes]
now = datetime.datetime.now()
#Insert timecode header
header.extend(output)
#Save the file and exit
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)
MKVToolNix was used to combine the modified time code with the video / audio that was divided first. When I played the completed mkv file, it played cleanly.
Use pyinstaller to make it an executable file so that it can be used by people who do not have python installed. If you drag and drop the file to the completed timecode.exe, the modified timecode file will be generated in the same folder.
$ pyinstaller --onefile timecode.py
** 1. Put the target FLV file in FLV Extract and divide it into video / audio / timecode files. 2. Determine the correction logic 3. Apply the above correction process to the time code file 4. Put the modified time code and the divided video / audio file in MKVToolNix and combine them to create an mkv file. 5. Play **
Since it is convenient to be able to process 1 to 4 together, I added it to the above code and it became as follows.
timecode.py
###################################################################################################
#
#The playback time of FLV is strange, so
#Script to modify timecode file extracted from FLV Extractor
#If you use the modified timecode and combine it with video and audio files with MKV toolnix
#If the time code follows this rule, it will be an mkv file that can be played properly.
#Install FLV Extract and MKV ToolNix, and put the executable file in the PATH.
#
###################################################################################################
import sys
import os
import datetime
import subprocess
import tempfile
import shutil
#===================================================================================================
#Timecode extraction with flv extract
#===================================================================================================
def flvExtract(flvFilename,outputDir):
cmd = [
'flvextractcl',
'-t',
'-v',
'-a',
'-d',
outputDir,
flvFilename,
]
print(flvFilename)
subprocess.call(cmd)
#===================================================================================================
#Read and modify the timecode file
#===================================================================================================
def repairTimecode(timecodeFilename):
f = open(timecodeFilename)
lines = []
header = []
for i,line in enumerate(f.readlines()):
#Separate the header and timecode at the beginning of the line
if(line.startswith('#') == False):
lines.append(int(line))
else:
header.append(line)
f.close()
timecodes = []
val = 0
for i,line in enumerate(lines):
#0 remains as it is
if(line == 0):
timecodes.append(line)
#A value smaller than the front is estimated to be the correct timecode, so insert it as it is
elif(line < lines[i-1]):
if(timecodes[i-1] < line):
timecodes.append(line)
#If indefinite (smaller than the previous timecode), insert the previous timecode as is
else:
timecodes.append(timecodes[i-1])
else:
#If you take the difference from the previous line, it seems to be the correct timecode
val = line - lines[i-1]
#If the same number continues, set the previous number
if(val == 0):
timecodes.append(timecodes[i-1])
#If the difference is smaller than the front (the original value is assumed to be the correct timecode), insert it as it is.
elif(timecodes[i-1] > val):
timecodes.append(line)
#If not, insert diff
else:
timecodes.append(val)
if(i > 0 and timecodes[i] < timecodes[i-1]):
print(timecodes[i-1])
print(timecodes[i])
print('\n')
#Make a string list with a line break at the end
output = [str(v)+'\n' for v in timecodes]
#Insert timecode header
header.extend(output)
#Save file by overwriting
with open(timecodeFilename, mode='w') as f:
f.writelines(header)
return
#===================================================================================================
#Combine video, audio, and modified timecode with 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'
#Use mkvmerge
#Create mkv by muxing various files
cmd = [
'mkvmerge',
'-o',
mkv,
'--timecodes',
'0:' + timecode,
video,
audio
]
subprocess.call(cmd)
#Output to the specified directory
shutil.move(mkv,outputDir)
return
#===================================================================================================
#Main processing
#===================================================================================================
def main():
flvFilename = ''
#Get file name
if(len(sys.argv) > 1):
flvFilename = os.path.abspath(sys.argv[1])
else:
flvFilename = os.path.join(os.getcwd(),'test.flv')
#Prepare three file names: video, audio, and time code
o_file = os.path.splitext(os.path.basename(flvFilename))[0]
outputDir = os.path.dirname(os.path.abspath(flvFilename))
#Create temporary directory for work
with tempfile.TemporaryDirectory() as tmpDir:
print(tmpDir+'\n')
#Extract with FLV Extract
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 repair and MKV creation if video / audio / timecode files exist
if(os.path.exists(timecodeFilename) and os.path.exists(videoFilename) and os.path.exists(audioFilename)):
repairTimecode(timecodeFilename)
mkvMerge(videoFilename,audioFilename,timecodeFilename,outputDir)
#For the FLV file used for processing, add a time stamp to the file name and move it to the FLV directory directly under it.
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()
This worked well, and I couldn't solve it in the first place, and there were times when the timecode was all 0 and there was nothing I could do about it. (It is possible to calculate the length from the length of the audio file, divide it by the number of video frames, and output a provisional time code, but of course the sound gap will be severe.)
However, if you have a problem in the same situation, it is recommended to look at the time code for the time being.