Roku Developer Program

Developers and content creators—a complete solution for growing an audience directly.
cancel
Showing results for 
Search instead for 
Did you mean: 
zig_zag
Level 7

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
0 Kudos
6 Replies
Roku Employee
Roku Employee

Re: Using BIF files

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?
0 Kudos
zig_zag
Level 7

Re: Using BIF files

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
0 Kudos
Roku Employee
Roku Employee

Re: Using BIF files

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
0 Kudos
destruk
Level 10

Re: Using BIF files

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


0 Kudos
destruk
Level 10

Re: Using BIF files

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.
0 Kudos
destruk
Level 10

Re: Using BIF files

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

0 Kudos