119

How can I add text overlay on my video in ffmpeg?

i.e. given a video "video1.flv", how can I add "StackOverflow" text during the whole video, positioned in the middle of the screen, with white text and a border?

Jason Sundram
  • 12,225
  • 19
  • 71
  • 86
Jesper Madsen
  • 1,201
  • 2
  • 10
  • 5
  • **The "ffmpeg" tag is only allowed for programmatic use of the ffmpeg API** - Questions about the command-line use should be asked on Super-user or Video-production. – Top-Master Apr 22 '23 at 07:25

4 Answers4

263

Use the drawtext filter for simple text on video. If you need more complex timing, formatting, or dynamic text see the subtitles filter. This answer focuses on the drawtext filter.

Example

Text centered on video

Print Stack Overflow in white text onto center of video, with black background box of 50% opacity:

ffmpeg -i input.mp4 -vf "drawtext=fontfile=/path/to/font.ttf:text='Stack Overflow':fontcolor=white:fontsize=24:box=1:boxcolor=black@0.5:boxborderw=5:x=(w-text_w)/2:y=(h-text_h)/2" -codec:a copy output.mp4
  • The audio is stream copied in this example (like a copy and paste).
  • @0.5 controls background box opacity. 0.5 is 50%. Remove @0.5 if you do not want any transparency.
  • See the drawtext filter documentation for a complete list and explanations of options.

Preview

You can use ffplay to preview your text without having to wait for a file to encode:

ffplay -vf "drawtext=fontfile=/path/to/font.ttf:text='Stack Overflow':fontcolor=white:fontsize=24:box=1:boxcolor=black@0.5:boxborderw=5:x=(w-text_w)/2:y=(h-text_h)/2" input.mp4

Alternatively you can use mpv but the syntax is slightly different:

mpv --vf="lavfi=[drawtext=fontfile=/path/to/font.ttf:text='Stack Overflow':fontcolor=white:fontsize=24:box=1:boxcolor=black@0.5:boxborderw=5:x=(w-text_w)/2:y=(h-text_h)/2]" input.mp4

Multiple texts

You can chain multiple drawtext filters:

ffmpeg -i input.mp4 -vf "drawtext=fontfile=/path/to/font.ttf:text='Stack Overflow':fontcolor=white:fontsize=24:box=1:boxcolor=black@0.5:boxborderw=5:x=(w-text_w)/2:y=(h-text_h)/2,drawtext=fontfile=/path/to/font.ttf:text='Bottom right text':fontcolor=black:fontsize=14:x=w-tw-10:y=h-th-10" -codec:a copy output.mp4

Position

x and y determine text position:

Position x:y With 10 px padding
Top left x=0:y=0 x=10:y=10
Top center x=(w-text_w)/2:y=0 x=(w-text_w)/2:y=10
Top right x=w-tw:y=0 x=w-tw-10:y=10
Centered x=(w-text_w)/2:y=(h-text_h)/2
Bottom left x=0:y=h-th x=10:y=h-th-10
Bottom center x=(w-text_w)/2:y=h-th x=(w-text_w)/2:y=h-th-10
Bottom right x=w-tw:y=h-th x=w-tw-10:y=h-th-10
Random See this answer

Repositioning text on demand

You can reposition the text with the sendcmd and zmq filters:

Moving / animated / looping / scrolling text

See:

Timing

Use the enable option to control when the text appears.

Show text between 5-10 seconds:

ffmpeg -i input.mp4 -vf "drawtext=fontfile=/path/to/font.ttf:text='Stack Overflow':fontcolor=white:fontsize=24:box=1:boxcolor=black@0.5:boxborderw=5:x=(w-text_w)/2:y=(h-text_h)/2:enable='between(t,5,10)'" -codec:a copy output.mp4

Show text after 3 seconds:

ffmpeg -i input.mp4 -vf "drawtext=fontfile=/path/to/font.ttf:text='Stack Overflow':fontcolor=white:fontsize=24:box=1:boxcolor=black@0.5:boxborderw=5:x=(w-text_w)/2:y=(h-text_h)/2:enable='gte(t,3)'" -codec:a copy output.mp4

Blinking text. For every 10 seconds show text for 5 seconds:

ffmpeg -i input.mp4 -vf "drawtext=fontfile=/path/to/font.ttf:text='Stack Overflow':fontcolor=white:fontsize=24:box=1:boxcolor=black@0.5:boxborderw=5:x=(w-text_w)/2:y=(h-text_h)/2:enable='lt(mod(t,10),5)'" -codec:a copy output.mp4

Random position every 30 seconds:

See ffmpeg - Dynamic letters and random position watermark to video?

Changing / updating text

Add the textfile and reload options for drawtext:

ffmpeg -i input.mp4 -vf "drawtext=fontfile=/path/to/font.ttf:textfile=text.txt:reload=1:fontcolor=white:fontsize=24:box=1:boxcolor=black@0.5:boxborderw=5:x=(w-text_w)/2:y=(h-text_h)/2" -codec:a copy output.mp4
  • Update text.txt every time you want the text to change.
  • Important: You must update the text file atomically or it may fail. You can do this with the mv command on Linux or macOS.
  • If you have many text changes, such as making subtitles, it is easier to make a subtitle file (such as an .ass file via Aegisub) and using the subtitles filter.

Font family instead of font file

You can declare the font family, such as Times New Roman, instead of having to point to a font file. See How to include font in FFMPEG command without using the fontfile option?

Requirements

The drawtext filter requires ffmpeg to be compiled with --enable-libfreetype. If you get No such filter: 'drawtext' it is missing --enable-libfreetype. Most of the ffmpeg static builds available support this: see the FFmpeg Download page for links.

llogan
  • 121,796
  • 28
  • 232
  • 243
  • Thank you. This produces text that is static. Other than date/time features, is there a way to produce an overlay of text that changes (such as a ticker tape at the bottom of the screen) or input from a text stream? – Noah Ternullo Apr 24 '14 at 16:47
  • 1
    @NoahTernullo there's also strftime options and "pts" variable you can use. In terms of making it ticker along the bottom, you can probably use some function for x variable value changes based on pts or frame number. – rogerdpack May 12 '15 at 19:45
  • @LordNeckbeard see my question here :http://stackoverflow.com/q/37404476/6127411. And please help me if you can. – Janki Gadhiya May 24 '16 at 04:37
  • Thanks for answering. But I have faced some problem. How to add special character in my watermark text? Here I posted question. Please answer me - http://stackoverflow.com/questions/38266469/ffmpeg-utf-8-special-character-not-working-in-video-watermark-text – Chinmay235 Jul 08 '16 at 12:37
  • 2
    fyi, for those installing with brew, you can pass that flag `--with-libefreetype` to the install command. – chovy Aug 01 '16 at 21:00
  • Have tryed on Armbian: ffmpeg -i rtsp://mpv.cdn3.bigCDN.com:554/bigCDN/definst/mp4:bigbuckbunnyiphone_400.mp4 -vf drawtext="fontfile=/home/projekt/StreamTest/DejaVuSans.ttf: \ text='Stack Overflow': fontcolor=white: fontsize=36: box=1: boxcolor=black@0.5: \ boxborderw=5: x=(w-text_w)/2: y=(h-text_h)/2" -codec:a copy http://localhost:8090/monitoring1.ffm but I don't get any text in my stream.. also th --enable-libfreetype is present when i run ffmpeg – Ferguson Feb 18 '17 at 20:52
  • @Ferguson Provide a link to a pastebin that shows the complete `ffmpeg` console output. Does it work if you output to a local file such as `output.mp4`? I know nothing of FFM (FFserver live feed), so I won't be helpful for anything to do with `ffserver`. – llogan Feb 18 '17 at 21:54
  • 7
    @chovy I think the homebrew option you mentioned should be `--with-freetype` – Rico Picone Feb 19 '17 at 02:25
  • @LordNeckbeard can you please look into this [thread](https://stackoverflow.com/questions/51018082/error-initializing-filter-drawtext-with-args-in-android) – Kishore Jethava Jun 25 '18 at 09:58
  • @Eftekhari I believe [RTL is problematic with libfreetype](https://stackoverflow.com/questions/47931448/ffmpeg-drawtext-how-to-set-direction-right-to-left) (the library used by drawtext). You may have better results using the [subtitles](https://ffmpeg.org/ffmpeg-filters.html#subtitles) filter with ASS files. – llogan Feb 11 '19 at 18:30
  • 2
    add `:enable='between(t,00:00:15,00:00:20)` to specify the text duration, something like `ffmpeg -i part02.mp4 -vf drawtext="text='Stack Overflow': fontcolor=white: fontsize=24: box=1: boxcolor=black@0.5: \ boxborderw=5: x=(w-text_w)/2: y=(h-text_h)/2: enable='between(t,00:00:15,00:00:20)" -codec:a copy output.mp4` – deFreitas May 02 '20 at 16:49
  • I have created pastebin account and posted code there,check out it - https://pastebin.com/iupjh8Cx – Vivek Thummar Aug 04 '20 at 07:39
  • 1
    @VivekThummar It needs to be in the form of `-vf "scale=1920:1080,drawtext=..."` Notice the comma (`,`) connecting the filters. The comma is missing in your command being executed. This is a problem with your implementation of the ffmpeg command in android. – llogan Aug 05 '20 at 17:32
  • Warning: This will re-encode your video and thus degrade quality. If you don't to lose quality on the re-encode you'll have to set additional parameters. – Raleigh L. Oct 14 '22 at 06:05
  • If you want to include a literal single quote `'` in your text, escape it “the CSV way”, by preceding it with another single quote: `text='I don''t know'` – BallpointBen Jun 26 '23 at 22:49
5

Here is the cheat sheet for overlay transition in all 4 direction...

************************* Text **********************

1) left to right given x=41 position 

ffmpeg -y -i 'https://player.vimeo.com/external/181545195.sd.mp4?s=176d502710df829442a83565bb79efbe3c9c0b93&profile_id=164' -vf "[in]drawtext=fontfile=/usr/share/fonts/truetype/freefont/FreeSerif.ttf: text='Hi': y=53.48 :x=min(t*250-2*250\,41): fontsize=35: fontcolor=yellow: enable='between(t,2,10)', drawtext=fontfile=/usr/share/fonts/truetype/freefont/FreeSerif.ttf: text='Ajeet': y=53.48 :x=min(t*250-3*250\,90): fontsize=35: fontcolor=yellow: enable='between(t,3,10)' [out]" -t 11 leftToRight.mp4




2) right to left given x=41 position

ffmpeg -y -i 'https://player.vimeo.com/external/181545195.sd.mp4?s=176d502710df829442a83565bb79efbe3c9c0b93&profile_id=164' -vf "[in]drawtext=fontfile=/usr/share/fonts/truetype/freefont/FreeSerif.ttf: text='Hi': y=53.48 :x=w-min(t*250-2*250\,(w\-41)): fontsize=35: fontcolor=yellow: enable='between(t,2,10)', drawtext=fontfile=/usr/share/fonts/truetype/freefont/FreeSerif.ttf: text='Ajeet': y=53.48 :x=w-min(t*250-3*250\,(w\-90)): fontsize=35: fontcolor=yellow: enable='between(t,3,10)' [out]" -t 11 rightToLeft.mp4




3) top to bottom given y=58 position 

ffmpeg -y -i 'https://player.vimeo.com/external/181545195.sd.mp4?s=176d502710df829442a83565bb79efbe3c9c0b93&profile_id=164' -vf "[in]drawtext=fontfile=/usr/share/fonts/truetype/freefont/FreeSerif.ttf: text='Hi': x=41 :y=min(t*250-2*250\,53.48): fontsize=35: fontcolor=yellow: enable='between(t,2,10)', drawtext=fontfile=/usr/share/fonts/truetype/freefont/FreeSerif.ttf: text='Ajeet': x=90 :y=min(t*250-3*250\,53.48): fontsize=35: fontcolor=yellow: enable='between(t,3,10)' [out]" -t 11 topToBottom.mp4




4) bottom to up given y=90 position

ffmpeg -y -i 'https://player.vimeo.com/external/181545195.sd.mp4?s=176d502710df829442a83565bb79efbe3c9c0b93&profile_id=164' -vf "[in]drawtext=fontfile=/usr/share/fonts/truetype/freefont/FreeSerif.ttf: text='Hi': x=41 :y=h-min(t*250-2*250\,(h\-53.48)): fontsize=35: fontcolor=yellow: enable='between(t,2,10)', drawtext=fontfile=/usr/share/fonts/truetype/freefont/FreeSerif.ttf: text='Ajeet': x=90 :y=h-min(t*250-3*250\,(h\-53.48)): fontsize=35: fontcolor=yellow: enable='between(t,3,10)' [out]" -t 11 bottomToTop.mp4

************************ Image *********************

1) single left to right given x=41 position

ffmpeg -y -i 'https://player.vimeo.com/external/181545195.sd.mp4?s=176d502710df829442a83565bb79efbe3c9c0b93&profile_id=164' -loop 1 -i image.png -filter_complex "[1:v]scale=-2:100[png];[0:v][png]overlay=x=min(t*250-2*250\,41):y=60:shortest=1:enable='between(t,2,10)'" -t 11 imageLeftToRight1.mp4

ffmpeg -y -i 'https://player.vimeo.com/external/181472383.sd.mp4?s=103f42915141758d95a118f070d08190845bdf73&profile_id=164' -loop 1 -i image.png -filter_complex "[1:v]scale=-2:100[png];[0:v][png]overlay=x=min(t*250-2*250\,41):y=60:shortest=1:enable='between(t,2,10)'" -t 11 imageLeftToRight.mp4




2) Already added text then added single image left to right

ffmpeg -y -i leftToRight.mp4 -loop 1 -i image.png -filter_complex "[1:v]scale=-2:100[png];[0:v][png]overlay=x=min(t*250-2*250\,41):y=200:shortest=1:enable='between(t,2,10)'" -t 11 imageTextLeftToRight.mp4




3) 2 images left to right given x=41, x=100 position

ffmpeg -y -i 'https://player.vimeo.com/external/181545195.sd.mp4?s=176d502710df829442a83565bb79efbe3c9c0b93&profile_id=164' -loop 1 -i image.png -loop 1 -i image2.png -filter_complex "[1]scale=-2:100[img1];[2]scale=-2:100[img2];[0][img1]overlay=x=min(t*250-2*250\,41):y=60:enable='between(t,2,10)':shortest=1[o1];[o1][img2]overlay=x=min(t*250-3*250\,100):y=200:enable='between(t,3,10)':shortest=1" -t 11  multiImageLeftToRight.mp4




4) 3 images left to right given x=41, x=100, x=300 position

ffmpeg -y -i 'https://player.vimeo.com/external/181545195.sd.mp4?s=176d502710df829442a83565bb79efbe3c9c0b93&profile_id=164' -loop 1 -i image.png -loop 1 -i image2.png -loop 1 -i image3.png -filter_complex "[1]scale=-2:100[img1];[2]scale=-2:100[img2];[3]scale=-2:100[img3];[0][img1]overlay=x=min(t*250-2*250\,41):y=60:enable='between(t,2,10)':shortest=1[o1];[o1][img2]overlay=x=min(t*250-3*250\,130):y=130:enable='between(t,3,10)':shortest=1[o2];[o2][img3]overlay=x=min(t*250-4*250\,260):y=190:enable='between(t,4,10)':shortest=1" -t 11  threeImageLeftToRight.mp4




5) 3 images right to left given x=41, x=100, x=300 position

ffmpeg -y -i 'https://player.vimeo.com/external/181545195.sd.mp4?s=176d502710df829442a83565bb79efbe3c9c0b93&profile_id=164' -loop 1 -i image.png -loop 1 -i image2.png -loop 1 -i image3.png -filter_complex "[1]scale=-2:100[img1];[2]scale=-2:100[img2];[3]scale=-2:100[img3];[0][img1]overlay=x=W-min(t*250-2*250\,(W\-41)):y=60:enable='between(t,2,10)':shortest=1[o1];[o1][img2]overlay=x=W-min(t*250-3*250\,(W\-130)):y=130:enable='between(t,3,10)':shortest=1[o2];[o2][img3]overlay=x=W-min(t*250-4*250\,(W\-260)):y=190:enable='between(t,4,10)':shortest=1" -t 11  threeImageRightToLeft.mp4




6) 3 images top to bottom given y=41, y=100, y=300 position

ffmpeg -y -i 'https://player.vimeo.com/external/181545195.sd.mp4?s=176d502710df829442a83565bb79efbe3c9c0b93&profile_id=164' -loop 1 -i image.png -loop 1 -i image2.png -loop 1 -i image3.png -filter_complex "[1]scale=-2:100[img1];[2]scale=-2:100[img2];[3]scale=-2:100[img3];[0][img1]overlay=x=41:y=min(t*250-2*250\,60):enable='between(t,2,10)':shortest=1[o1];[o1][img2]overlay=x=130:y=min(t*250-3*250\,130):enable='between(t,3,10)':shortest=1[o2];[o2][img3]overlay=x=260:y=min(t*250-4*250\,190):enable='between(t,4,10)':shortest=1" -t 11  threeImageTopToBottom.mp4




7) 3 images bottom to top given y=41, y=100, y=300 position

ffmpeg -y -i 'https://player.vimeo.com/external/181545195.sd.mp4?s=176d502710df829442a83565bb79efbe3c9c0b93&profile_id=164' -loop 1 -i image.png -loop 1 -i image2.png -loop 1 -i image3.png -filter_complex "[1]scale=-2:100[img1];[2]scale=-2:100[img2];[3]scale=-2:100[img3];[0][img1]overlay=x=41:y=H-min(t*250-2*250\,(H\-60)):enable='between(t,2,10)':shortest=1[o1];[o1][img2]overlay=x=130:y=H-min(t*250-3*250\,(H\-130)):enable='between(t,3,10)':shortest=1[o2];[o2][img3]overlay=x=260:y=H-min(t*250-4*250\,(H\-190)):enable='between(t,4,10)':shortest=1" -t 11  threeImageBottomToTop.mp4

************************ GIF *********************

1) single left to right given x=41 position

ffmpeg -y -i 'https://player.vimeo.com/external/181545195.sd.mp4?s=176d502710df829442a83565bb79efbe3c9c0b93&profile_id=164' -ignore_loop 0 -i gif1.gif -filter_complex "[1:v]scale=-2:100[ovrl];[0:v][ovrl]overlay=x=min(t*250-2*250\,41):y=60:enable='between(t,2,10)'" -t 11 gifLeftToRight.mp4




2) double left to right given x=41 position

ffmpeg -y -i 'https://player.vimeo.com/external/181545195.sd.mp4?s=176d502710df829442a83565bb79efbe3c9c0b93&profile_id=164' -ignore_loop 0 -i gif1.gif -ignore_loop 0 -i gif2.gif -ignore_loop 0 -i gif3.gif -filter_complex "[1]scale=-2:100[gif1];[2]scale=-2:100[gif2];[0][gif1]overlay=x=min(t*250-2*250\,41):y=60:enable='between(t,2,10)':shortest=1[o1];[o1][gif2]overlay=x=min(t*250-3*250\,150):y=170:enable='between(t,3,10)':shortest=1" -t 11 doubleGifLeftToRight.mp4




3) three left to right given x=41 position

ffmpeg -y -i 'https://player.vimeo.com/external/181545195.sd.mp4?s=176d502710df829442a83565bb79efbe3c9c0b93&profile_id=164' -ignore_loop 0 -i gif1.gif -ignore_loop 0 -i gif2.gif -ignore_loop 0 -i gif3.gif -filter_complex "[1]scale=-2:100[gif1];[2]scale=-2:100[gif2];[3]scale=-2:100[gif3];[0][gif1]overlay=x=min(t*250-2*250\,41):y=60:enable='between(t,2,10)':shortest=1[o1];[o1][gif2]overlay=x=min(t*250-3*250\,150):y=170:enable='between(t,3,10)':shortest=1[o2];[o2][gif3]overlay=x=min(t*250-4*250\,240):y=240:enable='between(t,4,10)':shortest=1" -t 11 threeGifLeftToRight.mp4



3) three right to left given x=41 position

ffmpeg -y -i 'https://player.vimeo.com/external/181545195.sd.mp4?s=176d502710df829442a83565bb79efbe3c9c0b93&profile_id=164' -ignore_loop 0 -i gif1.gif -ignore_loop 0 -i gif2.gif -ignore_loop 0 -i gif3.gif -filter_complex "[1]scale=-2:100[gif1];[2]scale=-2:100[gif2];[3]scale=-2:100[gif3];[0][gif1]overlay=x=W-min(t*250-2*250\,(W\-41)):y=60:enable='between(t,2,10)':shortest=1[o1];[o1][gif2]overlay=x=W-min(t*250-3*250\,(W\-150)):y=170:enable='between(t,3,10)':shortest=1[o2];[o2][gif3]overlay=x=W-min(t*250-4*250\,(W\-240)):y=240:enable='between(t,4,10)':shortest=1" -t 11 threeGifRightToLeft.mp4




3) three top to bottom given x=41 position

ffmpeg -y -i 'https://player.vimeo.com/external/181545195.sd.mp4?s=176d502710df829442a83565bb79efbe3c9c0b93&profile_id=164' -ignore_loop 0 -i gif1.gif -ignore_loop 0 -i gif2.gif -ignore_loop 0 -i gif3.gif -filter_complex "[1]scale=-2:100[gif1];[2]scale=-2:100[gif2];[3]scale=-2:100[gif3];[0][gif1]overlay=x=41:y=min(t*250-2*250\,60):enable='between(t,2,10)':shortest=1[o1];[o1][gif2]overlay=x=150:y=min(t*250-3*250\,170):enable='between(t,3,10)':shortest=1[o2];[o2][gif3]overlay=x=240:y=min(t*250-4*250\,240):enable='between(t,4,10)':shortest=1" -t 11 threeGifTopToBottom.mp4




3) three bottom to top given x=41 position

ffmpeg -y -i 'https://player.vimeo.com/external/181545195.sd.mp4?s=176d502710df829442a83565bb79efbe3c9c0b93&profile_id=164' -ignore_loop 0 -i gif1.gif -ignore_loop 0 -i gif2.gif -ignore_loop 0 -i gif3.gif -filter_complex "[1]scale=-2:100[gif1];[2]scale=-2:100[gif2];[3]scale=-2:100[gif3];[0][gif1]overlay=x=41:y=H-min(t*250-2*250\,(H\-60)):enable='between(t,2,10)':shortest=1[o1];[o1][gif2]overlay=x=150:y=H-min(t*250-3*250\,(H\-170)):enable='between(t,3,10)':shortest=1[o2];[o2][gif3]overlay=x=240:y=H-min(t*250-4*250\,(H\-240)):enable='between(t,4,10)':shortest=1" -t 11 threeGifBottomToTop.mp4
3

On macOS with enable='between(t,0,10)'

On macOS the syntax of enable='between(t,start_second, end_seconds)' is different. Input should be in seconds, not in hh:mm:ss.

My ffmpeg version 4.3.1

ffmpeg -i input.mp4 -vf "drawtext=text='My Text':enable='between(t,20,120)': x=(w-text_h)/2: y=(h-text_h)/2: fontsize=32: fontcolor=white: box=1: boxcolor=black@0.5: boxborderw=5:" -c:a copy output.mp4
Chadly M.
  • 330
  • 3
  • 6
0

For Android, If you are using ffmpeg-kit. Use Gpl libarary for "libx264"

 implementation 'com.arthenica:ffmpeg-kit-full-gpl:5.1'

For position

    var POSITION_BOTTOM_RIGHT = "x=w-tw-10:y=h-th-10"
    var POSITION_TOP_RIGHT = "x=w-tw-10:y=10"
    var POSITION_TOP_LEFT = "x=10:y=10"
    var POSITION_BOTTOM_LEFT = "x=10:h-th-10"
    var POSITION_CENTER_BOTTOM = "x=(main_w/2-text_w/2):y=main_h-(text_h*2)"
    var POSITION_CENTER_ALLIGN = "x=(w-text_w)/2:y=(h-text_h)/3"

Then

  val command = StringBuilder()
                .append("-y") //overWrite
                .append(" -i ").append(videoFile!!.path)  // video
                .append(" -vf ").append("drawtext=").append("text=").append(text)
                .append(":fontcolor=").append(color).append(":").append("fontsize=")
                .append(size + border).append(":").append(position)
                .append(":fontfile=").append(font!!.path)
                .append(" -c:v libx264 ").append(" -c:a copy  -movflags +faststart ")
                .append(outputFile.path)

Run the ffmpeg

     val session = FFmpegKit.execute(command.toString())

     if (ReturnCode.isSuccess(session.returnCode)) {

           callback!!.onFinish()


            // SUCCESS
       } else if (ReturnCode.isCancel(session.returnCode)) {
                   
            callback!!.onFailure("CANCELLED")


       } else {

            callback!!.onFailure("FAILED "+  String.format(
                        "Command failed with state %s and rc %s.%s",
                        session.state,
                        session.returnCode,
                        session.failStackTrace
      ))}
Rohaitas Tanoli
  • 624
  • 4
  • 16