PlaybackService | Video Player Module

PlaybackService

PlaybackService is a video playing module that will play videos based on these three values:
Frames,FPS, and ImageLabel/Button

Here are the two functions included in this module:
GenerateFrames() | Generate a table of frames from a table of image IDs

PlayVideo() | Play a set of frames at a custom FPS and in a custom ImageLabel using GenerateFrames()

How to use

Require the service like this:
require(module_path)

Create a new table with IDs in your script:
(E.G)

local FrameIDs = {
		6060496209,
		6060496895,
		6060497961,
		6060499848,
		6060501095,
		6060501718,
		6060502881,
		6060503657,
		6060504204,
		6060504916,
		6060505505,
		6060506233,
		6060506685,
		6060507074,
		6060507596
	}

Next, use the GenerateFrames() function to set up your frames:

local FrameTable = PlaybackService:GenerateFrames(FrameIDs)

Finally, play the video:

    local FPS = 30
	local Container = script.Parent --Your ImageLabel or ImageButton

	local video = PlaybackService:PlayVideo(FrameTable,FPS,Container)

MODULE:

local PlaybackService = {}

function PlaybackService:GenerateFrames(IDTable)
	if typeof(IDTable) == "table" then
		local frames = {}
		for i,v in pairs(IDTable) do
			if typeof(v) == "number" then
				local id_prefix = "rbxassetid://"
				local id = id_prefix..v
				table.insert(frames,id)
			end
		end
		return frames
	else
		warn("The value defined is not a table | PlaybackService")
		return nil
	end
end

function PlaybackService:PlayVideo(FrameTable,FPS,Container)
	local contentprov = game:GetService("ContentProvider")
	local frames = table.maxn(FrameTable)
	local FPS_Time = 1/FPS
	local CurrentFrame = 1
	local ContentHolder = Container
	contentprov:PreloadAsync({"rbxassetid://2300836745"})
	ContentHolder.Image = "rbxassetid://2300836745"
	contentprov:PreloadAsync(FrameTable)
	if FPS > 5 then
		local video = {
			Frames = FrameTable,
			FramesPerSecond = FPS,
			Container = ContentHolder,
			Finished = false
		}
		local images = {}
		for i=1,frames do
			local img = Instance.new("ImageLabel")
			img.ZIndex = Container.ZIndex-i
			img.Name = i
			Container.Visible = false
			img.Size = Container.Size
			img.Position = Container.Position
			img.Image = FrameTable[i]
			img.Visible = true
			img.Parent = Container.Parent
			table.insert(images,i,img)
		end
		task.wait(frames*0.049019607843137254)
		for i,v in pairs(images) do
			wait(FPS_Time)
			v.Visible = false
		end
		--[[repeat
			ContentHolder.Image = FrameTable[CurrentFrame]
			CurrentFrame = CurrentFrame+1
			wait(FPS_Time)
		until CurrentFrame == frames]]
		--video.Finished = true
		return video
	end
end

return PlaybackService

EXAMPLE GUI:

VideoExample.rbxm (6.4 KB)

Video:

UPDATES

April 15th:
Added smooth playback

6 Likes

seems pretty cool and useful, but it feels incomplete. You could add more functions like StopVideo, PauseVideo, ResumeVideo, etc. Additionally, you can also add events like VideoFinished, VideoResumed and properties, like Loop. If you were to add that stuff you’d also need to take a more OOP approach, but I guess it’s worth it.

Lastly I guess you could add support for decals and textures aswell, but overall, good work!

I wish I could make some sort of function to upload multiple images using the StudioService and Zip files.

EDIT:
image

2 Likes

This plays my games intro:

local IDTable = {
		13119427184,
		13119426457,
		13119426352,
		13119426164,
		13119425972,
		13119425703,
		13119425521,
		13119425394,
		13119425257,
		13119425148,
		13119424896,
		13119424787,
		13119424714,
		13119424616,
		13119424524,
		13119424397,
		13119424266,
		13119424049,
		13119423916,
		13119423795,
		13119423635,
		13119423444,
		13119423315,
		13119423180,
		13119423053,
		13119422947,
		13119422861,
		13119422747,
		13119422657,
		13119422548,
		13119422411,
		13119422242,
		13119422117,
		13119421935,
		13119421810,
		13119421691,
		13119421568,
		13119421461,
		13119421257,
		13119421087,
		13119420917,
		13119420802,
		13119420664,
		13119420514,
		13119420365,
		13119420219,
		13119420038,
		13119419923,
		13119419765,
		13119419563,
		13119418583,
		13119418473,
		13119418344,
		13119418226,
		13119418053,
		13119417848,
		13119417705,
		13119417562,
		13119417454,
		13119417341,
		13119417239,
		13119417138,
		13119417000,
		13119416803,
		13119416611,
		13119416459,
		13119416326,
		13119416190,
		13119433446,
		13119416023,
		13119415890,
		13119415725,
		13119415599,
		13119415484,
		13119415398,
		13119415316,
		13119415211,
		13119415066,
		13119414937,
		13119414852,
		13119414640,
		13119414487,
		13119414385,
		13119414275,
		13119414123,
		13119413988,
		13119413864,
		13119413723,
		13119413484,
		13119413379,
		13119413270,
		13119413149,
		13119413007,
		13119412834,
		13119412626,
		13119436633,
		13119412481,
		13119412338,
		13119412139,
		13119411705,
		13119411590,
		13119411385
	}

I’m working on smooth 60 fps playback

1 Like

that looks long and painful, tho I haven’t checked it out. What do you think about my suggestions? I see you haven’t responded appropriately lol

I added when the video is finished, now I’m getting smooth 60 fps to work.

1 Like

I GOT 60 FPS TO FINALLY WORK!
It uses another method if the fps is higher than 5

1 Like

I’ll add video stopping and pausing tomorrow

1 Like

Will be there an option in future to use Spritesheet instead of uploading each frame manually in roblox?

(Example)
image

ArtStation - Mage Sprite Sheet

It allows you to import all frame into 1 image (more optimize) kinda

2 Likes

It seems you use an interesting method of preloading the assets, mind detailing it? I would like to complete my video without unloaded images:

I made a new function for the module today, I won’t be able to release it for a few hours. But how the new one that is a perfect 60 fps with no unloaded frames, it it has two tables, one for the image IDs, and on that has all the loaded images. It makes a new image label identical to the original container, and will subtract the index of the image in the table from the original zindex. The only thing keeping from all going at once is a a task.wait(1/desired FPS).

CurrentFrame = CurrentFrame+1
to
CurrentFrame += 1

wait(x) to task.wait(x)

u dont need new variable for storing video only so instead just return it, like this
return {
Frames = FrameTable,
FramesPerSecond = FPS,
Container = ContentHolder
}

1 Like

I rewrote that whole part earlier. I’ll get it released later.

1 Like

But… why not use VideoFrames. Oh yeah…

Seems like a good resource, but it’s not very useful without a way to bulk upload images.

You can bulk upload images, you have to go into the asset manager:

Yeah, but it’s hard to put those IDs into a table efficiently.