Search code examples
ffmpegsubtitleffmpeg-pythonvideo-subtitlespyffmpeg

Coordinates with file format .ASS


I'm grabbing my text coordinates that I want to use for the file format .ASS and for centering on a 1080 by 1920 video, I have an application that displays where the text is on the video and can retrieve the position, an example of centered position is 310 by 800. When I try to set the position of the text inside the .ASS with those positions it doesn't write the caption where is meant to be. Could some explain how a .ASS positioning works. If use 200 px by 200 px as positioning it places it way further than the center even though the video its a 1080x1920 video, shouldn't it be placed before the center position of the video?

This is how my .ASS file looks like, I'm using ffmpeg to write the subtitles into the video:

[Script Info]
Title: Video Subtitles
ScriptType: v4.00+
Collisions: Normal
PlayDepth: 0
PlayResX: 1080
PlayResY: 1920


[V4+ Styles]
Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BorderStyle, Encoding
Style: Default, Segoe UI,9,&H00FFFFFF,&HFFFF00,&H00FFFFFF,0,0
Style: Background, Segoe UI,9,&H00FFFFFF,&H000000FF,&H00000000,3,0

[Events]
Format: Start, End, Style, MarginL, MarginR, MarginV, Text
Dialogue: 0:00:00.00,0:00:05.00,Default,0,0,0,{\pos(275,876)} {\bord5\3c&H000000&\fs90}LISTEN IN {\r}

  • Edit: I've added the playresx and y, but the text is still not where its meant to be. To add a bit more context, I have a scene in PyQT that uses a coordinates system to place text over videos, for this text its saying that its at the x axis of 275 and y axis of 876. When I use those coordinates for the .ASS text it doesn't show the same position. Also the scene in which the video and the text is in, its 1080 by 1920, this images show what I want and what I'm getting:

What I'm trying to achieve

what I'm getting


Solution

  • FFmpeg uses Libass as the ASS subtitle renderer. If there are no PlayResX and PlayResY headers, it assumes a resolution of 384x288 pixels (I believe this is also the case for other renderers such as VSFilter and its variations like xyVSFilter). Since your ASS file is missing these headers, the actual center would be at 192 pixels on the x-axis and 144 pixels on the y-axis. (So it would be \pos(192,144)

    But it's just best to set those headers instead of calculating on 384x288 basis by including them to [Script Info]:

    PlayResX: 1080
    PlayResY: 1920
    

    However, the text still won't be exactly centered because the anchor point (alignment) is placed at the bottom left corner of the subtitle text. Therefore, your styles should account for this, like so:

    [V4+ Styles]
    Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BorderStyle, Encoding, Alignment
    Style: Default,Segoe UI,45,&HFFB0B0,&HFFFF00,&H998877,0,0,2
    Style: Background,Segoe UI,45,&H00FFFFFF,&H000000FF,&H00000000,3,0,2
    

    An alternative way to set the alignment is by using the \an override tag like (in your case \an2) and possible values are:

    \an override tag

    Those alignment numbers 1-9 applies in the same way in Alignment header field, so this is where the 2 in the styles comes from.

    So your ASS file's content should look like this:

    [Script Info]
    Title: Video Subtitles
    ScriptType: v4.00+
    Collisions: Normal
    PlayDepth: 0
    PlayResX: 1080
    PlayResY: 1920
    
    [V4+ Styles]
    Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BorderStyle, Encoding, Alignment
    Style: Default,Segoe UI,45,&HFFB0B0,&HFFFF00,&H998877,0,0,2
    Style: Background,Segoe UI,45,&H00FFFFFF,&H000000FF,&H00000000,3,0,2
    
    [Events]
    Format: Start, End, Style, MarginL, MarginR, MarginV, Text
    Dialogue: 0:00:00.00,0:00:05.00,Default,0,0,0,{\pos(540,800)}LISTEN IN
    

    Edit:

    Based on your comments you seem to be under impression that you can't use both alignment and position, while it is in fact solution to your problem, because they're vastly different things (and thus can be used both at the same time), so to center a text you need both \pos(max_x/2,any_y) and alignment (\an) of 2 (center-bottom), 5 (center-center) or 8 (top-center) and I recommend going there with value 2. And same applies if you want put it anywhere on screen for example {\an2\pos(200,200)}text will be centered while anchoring to pixel at (200,200).