Forum Discussion

zig_zag's avatar
zig_zag
Visitor
9 years ago

Using BIF files

Hello!

How can i use my ".bif" file, to show the fast forward/backward list of thumbnails, if i disabled trick play?
e.g.: "m.video.enableTrickPlay = false"

Thank you!
- Gabriel

9 Replies

  • RokuTomC's avatar
    RokuTomC
    Community Moderator
    Can you elaborate on your request, please? You've created your .bif file but don't want to implement trickplay? In what way are you hoping to display your images?
  • Hi Tom! 

    Sorry for sharing not enough information. I want to know if is possible to use from trick play, only the "bif images feature". I've created a custom player, with a custom seekbar, and other views above the video as title, time spent, etc.  But i can't find how to decode a ".bif" file into a RowList or to create a custom TrickPlayBar node.

    Thanks!
    - Gabriel
  • RokuTomC's avatar
    RokuTomC
    Community Moderator
    Thanks for clarifying, Gabriel. Unfortunately, you can not create a custom TrickPlayBar node. There's no way to extract the images from a .bif file
    • gomad's avatar
      gomad
      Roku Guru

      Hi RokuTomC ,

      reopening this old ticket, is there any plan to enable BIF thumbnails for a custom player on SceneGraph?

      Or atleast API to parse a sprite image for the player?

      regards

      GM

      • JesUltra's avatar
        JesUltra
        Streaming Star

        I have the same concern.  I want to implement a custom seek bar, to match the visual theme of the rest of my channel, but I would hate to lose the thumbnail pictures (and keeping them is a requirement for channel certification.)

        Ideally, the Video node would provide a way to obtain the thumbnail images, irrespective of whether they come from BIF or from "standard" HLS/DASH.

  • destruk's avatar
    destruk
    Streaming Star
    Actually there is, but it is a lot of work.

    Something like this works in SDK 3.

    	episode.HDBifUrl="http://server/filename.bif"

    m.ThumbsExist=TRUE 'Default to true
    UT=CreateObject("roUrlTransfer")
    UT.SetPort(port)
    UT.SetUrl(episode.HDBifUrl)

    result=UT.GetToFile("tmp:/biffile.bif") 'download bif file
    If result<>200
    m.ThumbsExist=FALSE
    Print"BIF File not found!"
    m.TimestampMultiplier=10000
    m.TotalFrameCount=INT(episode.runtime/10)+1
    End If

    If m.ThumbsExist=TRUE
    m.dataset=CreateObject("roByteArray")
    m.headerset=CreateObject("roAssociativeArray")
    m.dataset.ReadFile("tmp:/biffile.bif")
    m.BifVersion=-1
    If m.dataset.Count()>0
    'verify filetype
    '0-7=magic number unique file identifier=offset
    If m.dataset[0]=&h89 And m.dataset[1]=&h42 And m.dataset[2]=&h49 And m.dataset[3]=&h46 And m.dataset[4]=&h0d And m.dataset[5]=&h0a And m.dataset[6]=&h1a And m.dataset[7]=&h0a
    Print "valid BIF File Identifier"
    '8-11=bif file format version number
    If m.dataset[8]=0 And m.dataset[9]=0 And m.dataset[10]=0 And m.dataset[11]=0
    Print"Using Version 0 descrambler"
    m.BifVersion=0
    Else
    Print"unknown version format"
    End If
    Else
    Print"Invalid BIF File"
    End If
    Else
    Print"Empty File or File doesn't exist"
    End If

    If m.BifVersion=0
    '12-15=total number of bif file images
    m.TotalFrameCount=(m.dataset[12]+m.dataset[13]*256+m.dataset[14]*256*256+m.dataset[15]*256*256*256)
    Print "Total Frames= "+itostr(m.TotalFrameCount)

    '16-19=timestamp multiplier
    m.TimestampMultiplier=(m.dataset[16]+m.dataset[17]*256+m.dataset[18]*256*256+m.dataset[19]*256*256*256)
    If m.TimestampMultiplier=0 Then m.TimestampMultiplier=1000 'if 0, BIF specification treats it as 1000ms
    Print"Timestamp Multiplier= "+itostr(m.TimestampMultiplier)+" ms"

    '20-63=reserved for future expansion - all 00 bytes

    'frame index table repeats until all frames are accounted for
    '64-67=frame 0 index timestamp
    '68-71=frame 0 absolute offset of frame
    'last index frame
    '0xffffffff
    'followed by last byte of data +1

    m.Offset=64 'initialize byte number counter
    m.TimeIndexTable=[]
    m.OffsetTable=[]
    For X=0 To m.TotalFrameCount-1 'run through entire index table
    T1=(m.dataset[m.Offset]+m.dataset[m.Offset+1]*256+m.dataset[m.OffSet+2]*256*256+m.dataset[m.OffSet+3]*256*256*256)
    T2=(m.dataset[m.Offset+4]+m.dataset[m.Offset+5]*256+m.dataset[m.Offset+6]*256*256+m.dataset[m.Offset+7]*256*256*256)
    m.TimeIndexTable.Push(T1)
    m.OffsetTable.Push(T2)
    m.Offset=m.Offset+8
    Next
    Print "Start of Last Frame= "+itostr(T2)
    m.EndOfFileMarker=(m.dataset[m.Offset+4]+m.dataset[m.Offset+5]*256+m.dataset[m.Offset+6]*256*256+m.dataset[m.Offset+7]*256*256*256)
    Print "Last byte of file= "+itostr(m.EndOfFileMarker)

    'DATA Section follows with JPG files
    m.Frames=[] 'create fromes array for image0/1/2 display - 3 frames possible at 160 width for 480 pixels
    '5 frames will not fit without making thumbnails in bif file smaller
    End If
    End If


  • destruk's avatar
    destruk
    Streaming Star
    Once you have the frames[] array then you can draw them as a bitmap, canvas, screen, or anything you like -- but as those features are going to be stripped out of the roku, I'm not sure how you would display them with scenegraph.
  • destruk's avatar
    destruk
    Streaming Star
    I had to do this for a 3D channel - so it was years ago - here's the draw code - note, that everything is doubled horizontally as it's intended for a 3D TV.  So you'd need to edit this to get it back to single screen/2D.

    Sub DrawPauseScreen(Episode As Object)
    m.canvas.Clear(&h000000FF)
    If m.ThumbsExist=TRUE
    If INT(m.position/(m.TimestampMultiplier/1000))>0
    m.Frames[0]=INT(m.position/(m.TimestampMultiplier/1000))-1
    Else
    m.Frames[0]=-1
    End If
    m.Frames[1]=INT(m.position/(m.TimestampMultiplier/1000))
    If INT(m.position/(m.TimestampMultiplier/1000))<m.TotalFrameCount-1
    m.Frames[2]=m.Frames[1]+1
    Else
    m.Frames[2]=-1
    End If

    FrameBorderSides=CreateObject("roBitmap","pkg:/assets/square.png")
    FrameMask=CreateObject("roBitmap",{width:180,height:200,alphaenable:false})
    FrameMask.Clear(&hFFFFFF00)

    'DRAW SCREEN
    If m.Frames[0]>-1
    m.dataset.WriteFile("tmp:/frame"+itostr(m.Frames[0])+".png",m.OffsetTable[m.Frames[0]],m.OffsetTable[m.Frames[0]+1]-m.OffsetTable[m.Frames[0]])
    FBMP0=CreateObject("roBitmap","tmp:/frame"+itostr(m.Frames[0])+".png")
    SourceBMP0Left=CreateObject("roRegion",FBMP0,0,0,160,180)
    SourceBMP0Right=CreateObject("roRegion",FBMP0,160,0,160,180)
    m.canvas.DrawObject(26,270,SourceBMP0Left)
    m.canvas.DrawObject(16,260,FrameBorderSides)

    m.canvas.DrawObject(666,270,SourceBMP0Right)
    m.canvas.DrawObject(656,260,FrameBorderSides)
    Else
    m.canvas.DrawObject(16,260,FrameMask)
    m.canvas.DrawObject(656,260,FrameMask)
    End If
    If m.Frames[2]>-1 
    If m.Frames[2]<m.TotalFrameCount-1
    m.dataset.WriteFile("tmp:/frame"+itostr(m.Frames[1])+".png",m.OffsetTable[m.Frames[1]],m.OffsetTable[m.Frames[1]+1]-m.OffsetTable[m.Frames[1]])
    FBMP1=CreateObject("roBitmap","tmp:/frame"+itostr(m.Frames[1])+".png")
    SourceBMP1Left=CreateObject("roRegion",FBMP1,0,0,160,180)
    SourceBMP1Right=CreateObject("roRegion",FBMP1,160,0,160,180)
    m.canvas.DrawScaledObject(218,252,1.25,1.25,SourceBMP1Left)
    m.canvas.DrawScaledObject(206,240,1.24,1.24,FrameBorderSides)

    m.canvas.DrawScaledObject(858,252,1.25,1.25,SourceBMP1Right)
    m.canvas.DrawScaledObject(846,240,1.24,1.24,FrameBorderSides)

    m.dataset.WriteFile("tmp:/frame"+itostr(m.Frames[2])+".png",m.OffsetTable[m.Frames[2]],m.OffsetTable[m.Frames[2]+1]-m.OffsetTable[m.Frames[2]])
    FBMP2=CreateObject("roBitmap","tmp:/frame"+itostr(m.Frames[2])+".png")
    SourceBMP2Left=CreateObject("roRegion",FBMP2,0,0,160,180)
    SourceBMP2Right=CreateObject("roRegion",FBMP2,160,0,160,180)
    m.canvas.DrawObject(450,270,SourceBMP2Left)
    m.canvas.DrawObject(440,260,FrameBorderSides)

    m.canvas.DrawObject(1090,270,SourceBMP2Right)
    m.canvas.DrawObject(1080,260,FrameBorderSides)
    Else
    m.dataset.WriteFile("tmp:/frame"+itostr(m.Frames[1])+".png",m.OffsetTable[m.Frames[1]],m.OffsetTable[m.Frames[1]+1]-m.OffsetTable[m.Frames[1]])
    FBMP1=CreateObject("roBitmap","tmp:/frame"+itostr(m.Frames[1])+".png")
    SourceBMP1Left=CreateObject("roRegion",FBMP1,0,0,160,180)
    SourceBMP1Right=CreateObject("roRegion",FBMP1,160,0,160,180)
    m.canvas.DrawScaledObject(218,252,1.24,1.24,SourceBMP1Left)
    m.canvas.DrawScaledObject(206,240,1.24,1.24,FrameBorderSides)

    m.canvas.DrawScaledObject(858,252,1.24,1.24,SourceBMP1Right)
    m.canvas.DrawScaledObject(846,240,1.24,1.24,FrameBorderSides)

    m.dataset.WriteFile("tmp:/frame"+itostr(m.Frames[2])+".png",m.OffsetTable[m.Frames[2]],m.EndOfFileMarker+1-m.OffsetTable[m.Frames[2]])
    FBMP2=CreateObject("roBitmap","tmp:/frame"+itostr(m.Frames[2])+".png")
    SourceBMP2Left=CreateObject("roRegion",FBMP2,0,0,160,180)
    SourceBMP2Right=CreateObject("roRegion",FBMP2,160,0,160,180)
    m.canvas.DrawObject(450,270,SourceBMP2Left)
    m.canvas.DrawObject(440,260,FrameBorderSides)

    m.canvas.DrawObject(1090,270,SourceBMP2Right)
    m.canvas.DrawObject(1080,260,FrameBorderSides)
    End If
    Else
    m.canvas.DrawObject(440,260,FrameMask)
    m.canvas.DrawObject(1080,260,FrameMask)

    m.dataset.WriteFile("tmp:/frame"+itostr(m.Frames[1])+".png",m.OffsetTable[m.Frames[1]],m.EndOfFileMarker+1-m.OffsetTable[m.Frames[1]])
    FBMP1=CreateObject("roBitmap","tmp:/frame"+itostr(m.Frames[1])+".png")
    SourceBMP1Left=CreateObject("roRegion",FBMP1,0,0,160,180)
    SourceBMP1Right=CreateObject("roRegion",FBMP1,160,0,160,180)
    m.canvas.DrawScaledObject(218,252,1.25,1.25,SourceBMP1Left)
    m.canvas.DrawScaledObject(206,240,1.24,1.24,FrameBorderSides)

    m.canvas.DrawScaledObject(858,252,1.25,1.25,SourceBMP1Right)
    m.canvas.DrawScaledObject(846,240,1.24,1.24,FrameBorderSides)
    End If

    End If
    'END OF THUMBS IF THEY EXISTED - now draw progress bar and button indicator graphic/speed
    ProgressBar=CreateObject("roBitmap","pkg:/assets/playerprogressbar.png")
    ProgressMarker=CreateObject("roBitmap","pkg:/assets/playerprogressmarker.png")
    ProgressMarkerArrow=CreateObject("roBitmap","pkg:/assets/playerprogressmarkerbottom.png")  '************************** needs to be utilized - X is the same as progressmarker, y is +62
    PauseIcon=CreateObject("roBitmap","pkg:/assets/playerpaused.png")
    FSlowIcon=CreateObject("roBitmap","pkg:/assets/playerfslow.png")
    RSlowIcon=CreateObject("roBitmap","pkg:/assets/playerrslow.png")

    FFastIcon1=CreateObject("roBitmap","pkg:/assets/playerffast1.png")
    FFastIcon2=CreateObject("roBitmap","pkg:/assets/playerffast2.png")
    FFastIcon3=CreateObject("roBitmap","pkg:/assets/playerffast3.png")
    RFastIcon1=CreateObject("roBitmap","pkg:/assets/playerrfast1.png")
    RFastIcon2=CreateObject("roBitmap","pkg:/assets/playerrfast2.png")
    RFastIcon3=CreateObject("roBitmap","pkg:/assets/playerrfast3.png")

    If m.stepspeed=-6
    m.canvas.DrawObject(291,520,RFastIcon3) '509 to center between the top of the progress indicator and the bottom of the center thumbnail frame
    m.canvas.DrawObject(931,520,RFastIcon3) '520 to center between the top of the horizontal progress bar itself and the bottom of the center thumbnail frame
    End If
    If m.stepspeed=-4
    m.canvas.DrawObject(291,520,RFastIcon2) '509 to center between the top of the progress indicator and the bottom of the center thumbnail frame
    m.canvas.DrawObject(931,520,RFastIcon2) '520 to center between the top of the horizontal progress bar itself and the bottom of the center thumbnail frame
    End If
    If m.stepspeed=-2
    m.canvas.DrawObject(291,520,RFastIcon1) '509 to center between the top of the progress indicator and the bottom of the center thumbnail frame
    m.canvas.DrawObject(931,520,RFastIcon1) '520 to center between the top of the horizontal progress bar itself and the bottom of the center thumbnail frame
    End If
    If m.stepspeed=-1
    m.canvas.DrawObject(291,520,RSlowIcon) '509 to center between the top of the progress indicator and the bottom of the center thumbnail frame
    m.canvas.DrawObject(931,520,RSlowIcon) '520 to center between the top of the horizontal progress bar itself and the bottom of the center thumbnail frame
    End If
    If m.stepspeed=0
    m.canvas.DrawObject(291,520,PauseIcon) '509 to center between the top of the progress indicator and the bottom of the center thumbnail frame
    m.canvas.DrawObject(931,520,PauseIcon) '520 to center between the top of the horizontal progress bar itself and the bottom of the center thumbnail frame
    End If
    If m.stepspeed=1
    m.canvas.DrawObject(291,520,FSlowIcon) '509 to center between the top of the progress indicator and the bottom of the center thumbnail frame
    m.canvas.DrawObject(931,520,FSlowIcon) '520 to center between the top of the horizontal progress bar itself and the bottom of the center thumbnail frame
    End If
    If m.stepspeed=2
    m.canvas.DrawObject(291,520,FFastIcon1) '509 to center between the top of the progress indicator and the bottom of the center thumbnail frame
    m.canvas.DrawObject(931,520,FFastIcon1) '520 to center between the top of the horizontal progress bar itself and the bottom of the center thumbnail frame
    End If
    If m.stepspeed=4
    m.canvas.DrawObject(291,520,FFastIcon2) '509 to center between the top of the progress indicator and the bottom of the center thumbnail frame
    m.canvas.DrawObject(931,520,FFastIcon2) '520 to center between the top of the horizontal progress bar itself and the bottom of the center thumbnail frame
    End If
    If m.stepspeed=6
    m.canvas.DrawObject(291,520,FFastIcon3) '509 to center between the top of the progress indicator and the bottom of the center thumbnail frame
    m.canvas.DrawObject(931,520,FFastIcon3) '520 to center between the top of the horizontal progress bar itself and the bottom of the center thumbnail frame
    End If
    m.canvas.DrawObject(80,574,ProgressBar)
    m.canvas.DrawObject(720,574,ProgressBar)

    'Draw initial position information graphical data
    m.canvas.DrawObject(152+INT(300*(m.initialposition/episode.Runtime)),574+62,ProgressMarkerArrow) 'offset +62 Y location from main marker
    m.canvas.DrawObject(792+INT(300*(m.initialposition/episode.Runtime)),574+62,ProgressMarkerArrow) 'offset +62 Y location from main marker
    'Draw initial position SHADED/COLORED PROGRESS BAR
    temporarywidth=INT(300*(m.initialposition/episode.Runtime))
    If temporarywidth>0
    ShadedBar=CreateObject("roBitmap",{width:temporarywidth,height:18,alphaenable:false})
    ShadedBar.Clear(&hFFFF) 'Blue
    m.canvas.DrawObject(172,605,ShadedBar)
    m.canvas.DrawObject(812,605,ShadedBar)
    End If

    m.canvas.DrawObject(152+INT(300*(m.Position/episode.Runtime)),574,ProgressMarker) 'progress marker is drawn on top
    m.canvas.DrawObject(792+INT(300*(m.Position/episode.Runtime)),574,ProgressMarker)

    P1=""
    P2=""
    'Draw Right side total runtime length of episode
    If episode.hours>0 P1=itostr(episode.hours)+"h "
    If episode.minutes<10
    P2="0"+itostr(episode.minutes)+"m"
    Else
    P2=itostr(episode.minutes)+"m"
    End If
    m.canvas.DrawText(P1+P2,486,598,&h0000FFFF,m.Font)
    m.canvas.DrawText(P1+P2,1126,598,&h0000FFFF,m.Font)

    'Draw Left side current position as hours and minutes
    CHours=0
    CMinutes=0
    CSeconds=m.Position
    CHours=INT(CSeconds/3600) '60seconds*60minutes
    CMinutes=INT((CSeconds-CHours*3600)/60)
    P3=""
    P4=""
    If CHours>0 P3=itostr(CHours)+"h "
    If CMinutes<10
    P4="0"+itostr(CMinutes)+"m"
    Else
    P4=itostr(CMinutes)+"m"
    End If
    m.SizeResult=m.FontMetrics.Size(P3+P4) 'determine size of string
    m.canvas.DrawText(P3+P4,140-m.SizeResult.W,598,&hFF0000FF,m.Font) 'right-justify text string
    m.canvas.DrawText(P3+P4,140-m.SizeResult.W+640,598,&hFF0000FF,m.Font)

    m.canvas.SwapBuffers()
    End Sub