-1

I want to create a Python script that make subtitle (a ticking timecode).

I have an h.264 binary file that has timestamp in each frame. so I want to parse this timestamp and make the subtitle with it.

Here's what I've tried with ffmpeg below.

ffmpeg -y -i video.avi -vf "drawtext=fontfile=C:\Windows\Fonts\consolab.ttf: fontsize=12:fontcolor=yellow: box=1:boxcolor=black@0.4: text='TIME\: %{pts\:gmtime\:1561939200}':x=(w-tw)/2:y=(h-th)/2" test.avi

Output .avi is okay with the timestamp, but, I needed to re-encode the source video file which takes a lot of time. So, I want to use a different way, which is creating subtitles.

Question is, is there any way to make subtitle with frame time? or useful info to fill me in?

The current result:

The expected result:

VC.One
  • 14,790
  • 4
  • 25
  • 57
kylesong
  • 21
  • 3
  • _"I have a h.264 binary file that has timestamp in each frame"_ How do you know that? Since timestamps don't usually exist in H264, only frame rate (FPS) is known. Unless you mean DTS and PTS etc?... – VC.One Aug 30 '19 at 07:32
  • sometimes it exists in the header. – kylesong Aug 31 '19 at 13:27
  • **(1)** Show me some H264 header bytes where you can see a timestamp and I'll check what's going on. You don't mean MP4 having timestamps in header, right? **(2)** Are you able to feed individual H264 frames to your decoder? Can you keep track of "how many frames decoded" numbers? This way you could just calculate the timestamps with `(1000 / FPS) * my_frame_num` . – VC.One Aug 31 '19 at 14:54
  • PS: What do you want to achieve really? **(a)** Just a SMPTE timecode that runs like clock while video plays? Because that's what your FFmpeg command does, it makes text from calculated PTS (like above comment), not reading any H264 timestamps. Do you want same text in Python Or **(b)** must it be exact timestamp of specified frame (means extract from bytes)? At this point are you asking how to read bytes with Python? – VC.One Aug 31 '19 at 15:06
  • With DrawBox option of ffmpeg I'm able to make timestamp displayed on the video. However, if the video gets bigger, re-enconding takes lots of time. So, I don't want to use DrawBox, normally I use video codec copy option(-c:v copy) which is not re-encoding the video. Share you with sample files Current: [link] (https://i.stack.imgur.com/iIvLi.png) Possible Result: [link] (https://i.stack.imgur.com/YUZ54.png) Sample Binary: [link] (https://drive.google.com/open?id=1Csn7RdvUifSGIGjhTFUJbkRru5J2uDFd) – kylesong Sep 03 '19 at 01:06

2 Answers2

1

You can use directly Timecode by defining the starting time :

ffmpeg -i source_file -c:v libx264 -vf drawtext="fontfile=C\\:/Windows/Fonts/arial.ttf:fontsize=45:timecode='10\:00\:00\:00':fontcolor='white':box=1:boxcolor='black':rate=25:x=(w-text_w)/2:y=h/1.2" -c:a aac -f mp4 output_with_TC.mp4

You can also grab timecode from file using ffprobe and use it in a batch file

@echo off

cd C:\bin

set file=%1 

For %%A in ("%file%") do (
    Set Folder=%%~dpA
    Set Name=%%~nA

)

set "CommandLine=ffprobe -i %file% -show_entries format_tags=timecode -of default=noprint_wrappers=1"
setlocal EnableDelayedExpansion
for /F "delims=" %%I in ('!CommandLine!') do set "TC=%%I"

echo.File is: %file%
echo.TC is: %TC%

set hours=%TC:~13,2% 
set minutes=%TC:~16,2% 
set seconds=%TC:~19,2% 
set frames=%TC:~22,2% 

set h=!hours: =!
set m=!minutes: =!
set s=!seconds: =!
set f=!frames: =!

set final_TC=%h%:%m%:%s%:%f%

echo.final_TC is : %final_TC%

ffmpeg -i %file% -c:v libx264 -vf drawtext="fontfile=C\\:/Windows/Fonts/arial.ttf:fontsize=45:timecode=\'%final_TC%\':fontcolor='white':box=1:boxcolor='black@0.4':rate=25:x=1600:y=30" -c:a aac -f mp4 output_%Name%.mp4 -y

endlocal


flenoir
  • 37
  • 6
  • Thank you so much for the reply, but if I use ffmpeg with drawbox, ffmpeg force me to re-encoding the original video to ouput. And If I have many big video files reencoding process takes lots of time. So I need a workaround. – kylesong Aug 28 '19 at 12:20
0

Maybe this code will help you to get a quick solution (I've modified slightly for posting here):

  • Set the fps variable to your own video's FPS.

  • set the myTimeNum var by using a timer to increase some frameNum count every FPS interval.

Logic:

Where example FPS is 10...

FPS= 10; frameNum = 0; myTimeNum = 0

Means for 10 times per second (using a timer) you must...

myTimeNum = (1000 / FPS) * frameNum
timecode = smpte.totc(myTimeNum, fps)
frameNum++

Code to try:

fps = 30
myTimeNum = 50000;
timecode = smpte.totc(myTimeNum, fps)
print timecode


#Converts frames to SMPTE timecode of arbitrary frame rate and back.
#For DF calculations use 29.976 frame rate.
#Igor Ridanovic, igor@HDhead.com


def totc(x, fps):
    """Converts frame count to SMPTE timecode.""" 
    spacer = ':'
    frHour = fps * 3600
    frSec = fps * 60
    hr = int(x // frHour)
    mn = int((x - hr * frHour) // frSec)
    sc = int((x - hr * frHour - mn * frSec) // fps)
    fr = int(round(x -  hr * frHour - mn * frSec - sc * fps))

    return(
    str(hr).zfill(2) + spacer +
    str(mn).zfill(2) + spacer +
    str(sc).zfill(2) + spacer +
    str(fr).zfill(2))
VC.One
  • 14,790
  • 4
  • 25
  • 57