Get output image from FFMPEG by pipe

Just starting out? Need help? Post your questions and find answers here.
Seymour Clufley
Addict
Addict
Posts: 1233
Joined: Wed Feb 28, 2007 9:13 am
Location: London

Get output image from FFMPEG by pipe

Post by Seymour Clufley »

I'm trying to adapt this code and this code in order to convert PSDs to transparent PNGs. I'm testing it by creating a transparent PNG, saving it to file, and trying to retrieve the image through FFMPEG. Clearly I'm doing something wrong, but can anyone help out?

Code: Select all

Procedure RAIM(raw_img.i,bgcolour.i=#PB_Ignore,title.s="Report alpha image")
  
  If bgcolour=#PB_Ignore
    bgcolour = RGB(17,17,17)
  EndIf
  
  iw.d = ImageWidth(raw_img)
  ih.d = ImageHeight(raw_img)
  
  aimg.i = CreateImage(#PB_Any,iw,ih,32,bgcolour)
  StartDrawing(ImageOutput(aimg))
  DrawAlphaImage(ImageID(raw_img),0,0)
  StopDrawing()
  
  If Not title="" : title = "Report alpha image" : EndIf
  win = OpenWindow(#PB_Any,0,0,iw,ih,title,#PB_Window_BorderLess|#PB_Window_ScreenCentered)
  imgad = ImageGadget(#PB_Any,0,0,iw,ih,ImageID(aimg))
  escapekey = 1
  spacekey = 2
  returnkey = 3
  AddKeyboardShortcut(win,#PB_Shortcut_Escape,escapekey)
  AddKeyboardShortcut(win,#PB_Shortcut_Space,spacekey)
  AddKeyboardShortcut(win,#PB_Shortcut_Return,returnkey)
  Repeat
    we = WindowEvent()
    If we
      If we=#PB_Event_Menu
        Break
      EndIf
    Else
      Delay(10)
    EndIf
  ForEver
  CloseWindow(win)
  
  FreeImage(aimg)
  
EndProcedure


#FFMPEG = "P:\ffmpeg.exe"  you will need to set location of ffmpeg.exe
folder.s = "P:\test4\"  this will need to be a working folder


#IMAGE_WIDTH = 576
#IMAGE_HEIGHT = 432


; create a transparent 32-bit image, save it to file, discard it
img = CreateImage(#PB_Any,#IMAGE_WIDTH,#IMAGE_HEIGHT,32,#PB_Image_Transparent)
StartDrawing(ImageOutput(img))
DrawingMode(#PB_2DDrawing_AlphaBlend)
For a = 1 To 20
  Box(Random(#IMAGE_WIDTH-50),Random(#IMAGE_HEIGHT-50),50,50,RGBA(Random(255),Random(255),Random(255),255))
Next a
StopDrawing()
RAIM(img)
fn.s = folder+"input.png"
UsePNGImageEncoder()
SaveImage(img,fn,#PB_ImagePlugin_PNG)
FreeImage(img)




; now try to get the image through FFMPEG...
#VIDEO_COLOR = 4
numpixels = #IMAGE_WIDTH * #IMAGE_HEIGHT
img = CreateImage(#PB_Any,#IMAGE_WIDTH,#IMAGE_HEIGHT,32,#PB_Image_Transparent)
dataSize = #IMAGE_WIDTH * #IMAGE_HEIGHT * #VIDEO_COLOR
Dim frame.a(dataSize)

param.s = "-i "+Chr(34)+fn+Chr(34)+" -c:v png -pix_fmt rgba -f image2 - -report"
prog.i = RunProgram(#FFMPEG,param,folder,#PB_Program_Open | #PB_Program_Read)
ReadProgramData(prog, @frame(0), dataSize)
CloseProgram(prog)

*pntr = @frame(0)

If StartDrawing(ImageOutput(img))
  DrawingMode(#PB_2DDrawing_AlphaBlend)
  
  For ycoord = 0 To #IMAGE_HEIGHT - 1
    For x = 0 To #IMAGE_WIDTH - 1
      
      rf.a = PeekA(*pntr)
      gf.a = frame((yCoord / 2) * (#IMAGE_WIDTH / 2) + (x / 2) + numpixels)
      bf.a = frame((yCoord / 2) * (#IMAGE_WIDTH / 2) + (x / 2) + numpixels + (numpixels / 4))
      af.a = frame((yCoord / 2) * (#IMAGE_WIDTH / 2) + (x / 2) + numpixels + (numpixels / 4) + (numpixels / 4))
      
      If rf > 255: rf = 255: ElseIf rf < 0: rf = 0:EndIf
      If gf > 255: gf = 255: ElseIf gf < 0: gf = 0:EndIf
      If bf > 255: bf = 255: ElseIf bf < 0: bf = 0:EndIf
      If af > 255: af = 255: ElseIf af < 0: af = 0:EndIf
      
      Plot (x, ycoord, RGBA(rf,gf,bf,af))
      
      *pntr + 1
      
    Next
  Next
  
  StopDrawing()
  RAIM(img)
EndIf
JACK WEBB: "Coding in C is like sculpting a statue using only sandpaper. You can do it, but the result wouldn't be any better. So why bother? Just use the right tools and get the job done."
infratec
Always Here
Always Here
Posts: 6817
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Get output image from FFMPEG by pipe

Post by infratec »

You create a png image with ffmpeg and not rgb data.
So you can use CatchImage() / UsePNGDecoder()

If you want rgb data, you need

Code: Select all

param = "-i " + #DQUOTE$ + fn + #DQUOTE$ + " -c:v rawvideo -pix_fmt rgba -f image2 - -report"
infratec
Always Here
Always Here
Posts: 6817
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Get output image from FFMPEG by pipe

Post by infratec »

And with the right structure as array ...

Code: Select all

EnableExplicit


#FFMPEG = "h:\PureBASIC\ffmpeg\ffmpeg.exe"
#Folder = "c:\tmp\PureBasic\"

#IMAGE_WIDTH = 576
#IMAGE_HEIGHT = 432






Procedure RAIM(raw_img.i,bgcolour.i=#PB_Ignore,title.s="Report alpha image")
  
  Protected.i aimg, win, imgad, escapekey, spacekey, returnkey, we
  Protected.d iw, ih
  
  
  If bgcolour=#PB_Ignore
    bgcolour = RGB(17,17,17)
  EndIf
  
  iw = ImageWidth(raw_img)
  ih = ImageHeight(raw_img)
  
  aimg = CreateImage(#PB_Any,iw,ih,32,bgcolour)
  StartDrawing(ImageOutput(aimg))
  DrawAlphaImage(ImageID(raw_img),0,0)
  StopDrawing()
  
  If Not title="" : title = "Report alpha image" : EndIf
  win = OpenWindow(#PB_Any,0,0,iw,ih,title,#PB_Window_BorderLess|#PB_Window_ScreenCentered)
  imgad = ImageGadget(#PB_Any,0,0,iw,ih,ImageID(aimg))
  escapekey = 1
  spacekey = 2
  returnkey = 3
  AddKeyboardShortcut(win,#PB_Shortcut_Escape,escapekey)
  AddKeyboardShortcut(win,#PB_Shortcut_Space,spacekey)
  AddKeyboardShortcut(win,#PB_Shortcut_Return,returnkey)
  Repeat
    we = WindowEvent()
    If we
      If we=#PB_Event_Menu
        Break
      EndIf
    Else
      Delay(10)
    EndIf
  ForEver
  CloseWindow(win)
  
  FreeImage(aimg)
  
EndProcedure



Structure RGBAStructure
  R.a
  G.a
  B.a
  A.a
EndStructure



Define.a rf, gf, bf, af
Define.i img, a, numpixels, dataSize, prog, ycoord, x, Bytes, i
Define fn.s, param.s


; create a transparent 32-bit image, save it to file, discard it
img = CreateImage(#PB_Any,#IMAGE_WIDTH,#IMAGE_HEIGHT,32,#PB_Image_Transparent)
StartDrawing(ImageOutput(img))
DrawingMode(#PB_2DDrawing_AlphaBlend)
For a = 1 To 20
  Box(Random(#IMAGE_WIDTH-50),Random(#IMAGE_HEIGHT-50),50,50,RGBA(Random(255),Random(255),Random(255),255))
Next a
StopDrawing()
RAIM(img)
fn = #Folder + "input.png"
UsePNGImageEncoder()
UsePNGImageDecoder()
SaveImage(img,fn,#PB_ImagePlugin_PNG)
FreeImage(img)




; now try to get the image through FFMPEG...
#VIDEO_COLOR = 4
numpixels = #IMAGE_WIDTH * #IMAGE_HEIGHT
img = CreateImage(#PB_Any,#IMAGE_WIDTH,#IMAGE_HEIGHT,32,#PB_Image_Transparent)
dataSize = #IMAGE_WIDTH * #IMAGE_HEIGHT * #VIDEO_COLOR

Debug dataSize

Dim frame.RGBAStructure(numpixels)

;param = "-i " + #DQUOTE$ + fn + #DQUOTE$ + " -c:v png -pix_fmt rgba -f image2 - -report"
param = "-i " + #DQUOTE$ + fn + #DQUOTE$ + " -c:v rawvideo -pix_fmt rgba -f image2 - -report"
Debug param
prog = RunProgram(#FFMPEG,param,#Folder,#PB_Program_Open | #PB_Program_Read)
If prog
  If ProgramRunning(prog)
    Debug "123"
    Bytes = ReadProgramData(prog, @frame(0), dataSize)
    
    ShowMemoryViewer(@frame(0), dataSize)
    
    Debug Bytes
  EndIf
  CloseProgram(prog)
EndIf


If StartDrawing(ImageOutput(img))
  DrawingMode(#PB_2DDrawing_AlphaBlend)
  
  i = 0
  For ycoord = 0 To #IMAGE_HEIGHT - 1
    For x = 0 To #IMAGE_WIDTH - 1
      Plot (x, ycoord, RGBA(Frame(i)\R, Frame(i)\G, Frame(i)\B, Frame(i)\A))
      i + 1
    Next
  Next
  
  StopDrawing()

;img = CatchImage(#PB_Any, *pntr)
;If IsImage(img)
  RAIM(img)
EndIf
Seymour Clufley
Addict
Addict
Posts: 1233
Joined: Wed Feb 28, 2007 9:13 am
Location: London

Re: Get output image from FFMPEG by pipe

Post by Seymour Clufley »

Thank you, Infratec.

My next question is... could it be made to work without knowing in advance the dimensions of the image?
JACK WEBB: "Coding in C is like sculpting a statue using only sandpaper. You can do it, but the result wouldn't be any better. So why bother? Just use the right tools and get the job done."
infratec
Always Here
Always Here
Posts: 6817
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Get output image from FFMPEG by pipe

Post by infratec »

Code: Select all

EnableExplicit


#FFMPEG = "h:\PureBASIC\ffmpeg\ffmpeg.exe"
#Folder = "c:\tmp\PureBasic\"

#IMAGE_WIDTH = 576
#IMAGE_HEIGHT = 432






Procedure RAIM(raw_img.i,bgcolour.i=#PB_Ignore,title.s="Report alpha image")
  
  Protected.i aimg, win, imgad, escapekey, spacekey, returnkey, we
  Protected.d iw, ih
  
  
  If bgcolour=#PB_Ignore
    bgcolour = RGB(17,17,17)
  EndIf
  
  iw = ImageWidth(raw_img)
  ih = ImageHeight(raw_img)
  
  aimg = CreateImage(#PB_Any,iw,ih,32,bgcolour)
  StartDrawing(ImageOutput(aimg))
  DrawAlphaImage(ImageID(raw_img),0,0)
  StopDrawing()
  
  If Not title="" : title = "Report alpha image" : EndIf
  win = OpenWindow(#PB_Any,0,0,iw,ih,title,#PB_Window_BorderLess|#PB_Window_ScreenCentered)
  imgad = ImageGadget(#PB_Any,0,0,iw,ih,ImageID(aimg))
  escapekey = 1
  spacekey = 2
  returnkey = 3
  AddKeyboardShortcut(win,#PB_Shortcut_Escape,escapekey)
  AddKeyboardShortcut(win,#PB_Shortcut_Space,spacekey)
  AddKeyboardShortcut(win,#PB_Shortcut_Return,returnkey)
  Repeat
    we = WindowEvent()
    If we
      If we=#PB_Event_Menu
        Break
      EndIf
    Else
      Delay(10)
    EndIf
  ForEver
  CloseWindow(win)
  
  FreeImage(aimg)
  
EndProcedure



Structure RGBAStructure
  R.a
  G.a
  B.a
  A.a
EndStructure



Define.a rf, gf, bf, af
Define.i img, a, numpixels, dataSize, prog, ycoord, x, Bytes, i
Define fn.s, param.s
Define *Buffer


; create a transparent 32-bit image, save it to file, discard it
img = CreateImage(#PB_Any,#IMAGE_WIDTH,#IMAGE_HEIGHT,32,#PB_Image_Transparent)
StartDrawing(ImageOutput(img))
DrawingMode(#PB_2DDrawing_AlphaBlend)
For a = 1 To 20
  Box(Random(#IMAGE_WIDTH-50),Random(#IMAGE_HEIGHT-50),50,50,RGBA(Random(255),Random(255),Random(255),255))
Next a
StopDrawing()
RAIM(img)
fn = #Folder + "input.png"
UsePNGImageEncoder()
UsePNGImageDecoder()
SaveImage(img,fn,#PB_ImagePlugin_PNG)
FreeImage(img)




; now try to get the image through FFMPEG...


*Buffer = AllocateMemory(1000000)
If *Buffer

param = "-i " + #DQUOTE$ + fn + #DQUOTE$ + " -c:v png -pix_fmt rgba -f image2 - -report"
;param = "-i " + #DQUOTE$ + fn + #DQUOTE$ + " -c:v rawvideo -pix_fmt rgba -f image2 - -report"
Debug param
prog = RunProgram(#FFMPEG,param,#Folder,#PB_Program_Open | #PB_Program_Read)
If prog
  If ProgramRunning(prog)
    Bytes = ReadProgramData(prog, *Buffer, MemorySize(*Buffer))
    Debug Bytes
    ;ShowMemoryViewer(*Buffer, Bytes)
    
  EndIf
  CloseProgram(prog)
EndIf


img = CatchImage(#PB_Any, *Buffer)
If IsImage(img)
  RAIM(img)
EndIf
FreeMemory(*Buffer)
EndIf
Or you have to read the error output of ffmpeg and find the size.

And the buffer size needs to be large enough.
Seymour Clufley
Addict
Addict
Posts: 1233
Joined: Wed Feb 28, 2007 9:13 am
Location: London

Re: Get output image from FFMPEG by pipe

Post by Seymour Clufley »

Thank you so much, Infratec. :)

So a procedure that would reliably load Photoshop PSD files (in a flattened but transparent form) would be this:

Code: Select all

Procedure.i LoadPSD(imgnum.i,fn.s)
  If FileSize(fn)=-1
    ProcedureReturn 0
  EndIf
  
  #FFMPEG = "" ; set this
  #FFMPEGWorkingFolder = "" ; set this
  
  *Buffer = AllocateMemory(10000000)
  If *Buffer
    param.s = "-i " + #DQUOTE$ + fn + #DQUOTE$ + " -c:v png -f image2 -"
    prog.i = RunProgram(#FFMPEG,param,#FFMPEGWorkingFolder,#PB_Program_Open | #PB_Program_Read | #PB_Program_Hide)
    If prog
      While ProgramRunning(prog)
        Delay(50)
        Bytes = AvailableProgramOutput(prog)
        If Bytes
          Bytes = ReadProgramData(prog, *Buffer, MemorySize(*Buffer))
          UsePNGImageDecoder()
          img = CatchImage(imgnum, *Buffer)
          FreeMemory(*Buffer)
          Break
        EndIf
      Wend
      CloseProgram(prog)
    EndIf
  EndIf
  
  If imgnum=#PB_Any
    imgnum = img
  EndIf
  If IsImage(imgnum)
    ProcedureReturn imgnum
  Else
    ProcedureReturn 0
  EndIf
  
EndProcedure
JACK WEBB: "Coding in C is like sculpting a statue using only sandpaper. You can do it, but the result wouldn't be any better. So why bother? Just use the right tools and get the job done."
infratec
Always Here
Always Here
Posts: 6817
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Get output image from FFMPEG by pipe

Post by infratec »

No, that's not reliable.

You did some mistakes.

1. You call UsePNGImageDecoder() in a loop. Not good.
2. If you do it in a loop, then you need to increase the pointer to the memory by the received bytes, else you overwrite the buffer.
And first if the program is terminated you can try CatchImage()
Seymour Clufley
Addict
Addict
Posts: 1233
Joined: Wed Feb 28, 2007 9:13 am
Location: London

Re: Get output image from FFMPEG by pipe

Post by Seymour Clufley »

1. I thought that was simply a signal to the compiler that it should include the PNG decoder?

2. Noted
JACK WEBB: "Coding in C is like sculpting a statue using only sandpaper. You can do it, but the result wouldn't be any better. So why bother? Just use the right tools and get the job done."
Post Reply