Login [Register]
Don't have an account? Register now to chat, post, use our tools, and much more.
Some people might remember a really old iteration of this project for the TI-84+(SE) monochrome calculator, which itself was an iteration of an older idea of getting the popular Bad Apple video onto the calculator.

I wanted Bad Apple to run on the CE and now that I know enough to do it, I did... well. Something.

What I created was a video playback program that accepts specially-formatted videos split across multiple files with an accompanying ASM stub for decoding. My first attempt was an encoding scheme which did pixel tripling to expand a 96 by ** video to better fit the screen, done in 1bpp mode at 30fps. I don't have a (good) screenshot of that because I never finished writing the timing code to actually play the 30fps video at 30fps. It would play closer to 60fps.

The second attempt was to do much the same except in 2bpp mode with a palette of grays. This is the result, using the One Punch Man opening scene as the test video.
OPM Opening - 2bpp animated .gif

The third attempt was to do the same except in 4bpp mode. This time, I added color but used this fixed palette during encoding:

Code:
        palette = [0,0,0, 128,0,0, 0,128,0, 0,0,128,
                   128,128,0, 0,128,128, 128,0,128, 128,128,128,
                   128,128,128, 255,0,0, 0,255,0, 0,0,255,
                   255,255,0, 0,255,255, 255,0,255, 255,255,255]
Yes, I know there's a duplicate value in there. I intend to fix that by changing the first to a lighter gray and the other to a darker gray. I'm also using the One Punch Man opening scene in this one and here's the result of that:
OPM Opening - 4bpp fixed palette

The fourth attempt, which I worked on at the same time as the third due to encoding difficulties, was to go back to 1bpp mode, but have no zooming in order to accept a higher resolution video. Finally, it's a Bad Apple video that's not all that blocky.
Bad Apple - 1bpp improved (from 94x72) res

I intend to release source once I'm finished having fun with writing stuff.
EDIT: The color OPM video is about 1.7MB on-calc while the Bad Apple video is about 2.3MB
EDIT2: The .gif files were shot at 12-16 fps using an external .gif capture tool since CEmu leaves too many artifacts when I use its built-in capture.
TODO: fix crash-on-exit problem with 4bpp decoder
EDIT3: Changed embedded images to links to prevent performance problems when viewing this thread using a potato low end machine.
Super cool! Maybe you can try dithering to make it have acceptable quality frames for black and white. Rather inexpensive too!
Val wrote:
Super cool! Maybe you can try dithering to make it have acceptable quality frames for black and white. Rather inexpensive too!


Dithering would, as of now, increase the resulting file size as the compression would be quite poor. The last time I tried doing it, it tripled the file size. Which might be acceptable depending on whether or not the video still fits on the calculator. Dithering is an option in the encoder, though. Just pass in the -d flag to the build script to make the magic happen.
Maybe try something like this if the CE allows the refresh rate it requires. https://www.youtube.com/watch?v=IehwV2K60r8

Go to about 2:22 to see what I mean but the methods are quite cool
xMarminq_ wrote:
Maybe try something like this if the CE allows the refresh rate it requires. https://www.youtube.com/watch?v=IehwV2K60r8

Go to about 2:22 to see what I mean but the methods are quite cool

That does look interesting, especially the vertical dithering part. Wished I could give that one a try but I haven't quite figured out how to get PIL (Python Imaging Library) to do that one yet, or if I'll have to write my own code to do the job. And then there's the whole 60fps thing where I'd have to do horizontal offsetting to produce that dither pattern. I'm not exactly sure how I'd accomplish that one when I'm only writing out frames at 30Hz when the screen's refresh rate is about 64Hz. Any suggestions on how to do this without interrupts (since the newer calculators lack IM2) ?

----

For now, I tried to do some stuff with adaptive palettes. The conversion I did on each frame gives me the "best" 15 colors for that frame and I pack that data with each frame. The result seems to look nice but the ZX7 compression utility didn't work very well. The entire video wouldn't fit (1846 of 2660 frames) but this is what I have so far:

OPM Opening (partial) - 4bpp adaptive palette

I've noticed that there's some spots where the color is completely wrong in some of the frames. I used the following Python code to do the conversion:

Code:
img.convert("P",palette=Image.ADAPTIVE,colors=15)

Is this about as good as I'm going to get or is there something else I could do?

Also, I was told that I could improve compression by averaging out palette data, but that would result in a terrible "average" if the scene changes that contain radically different colors. Or would it? Any ideas on how to address that particular issue, or do you think it would be a non-issue and I should try it anyway?

NOTE: 15 colors instead of 16 because one color has to remain fixed to keep the black border from strobing like crazy.

EDIT: Changed embedded images to links to prevent performance problems when viewing this thread using a potato low end machine.
I was looking thinking that some adaptive palette techniques could work well only to scroll down to see it in action, it looks very nice!

Do you have any test files available?
I've organized and collected all my build tools here on GitHub.

It's not quite ready for general use yet since I forgot to document that you'll need to install Python 2.7, and with it, PIL/Pillow, ffmpy, and ffmpeg. I'll also need someone to help test these procedures since I did stuff to get the paths for Python just right but can't remember what it was because it doesn't do it out of the box, so I can outline clear steps that should work out of the box if the user doesn't have anything installed yet.

I'm also still working on the adaptive palette encoder/decoder so don't expect that to stay the way it is.

Apart from that, have fun with what I have so far.
Could there be a download for the OPM intro, or it it too big?

BTW, how's compression going so far?
Questions
________
Does it play Gifs or it can play movies too?
and if it does play movie you should add a pause and resume button and
a video compressor to make the video smaller so it can be play on the calc

and if u wanted it to play at a higher farm rate would the video be slow

Contact
______
if it cant be done please PM me

Comments
_________

Looking good so far hope to see more
xMarminq_ wrote:
Could there be a download for the OPM intro, or it it too big?

BTW, how's compression going so far?

I got the source video from Youtube using one of the many video download services, so I didn't see any sense in providing that.

Eliminating duplicate palette entries after stripping out the lower 3 bits on each color channel (since those gets chopped off anyway) helped compression out a bit (saved 640kb) but not quite enough to fit the entire video on the calculator (still need 320kb). Sorting the palette entries via HSV harmed the compression ratio (by about 64KB). I've yet to try sorting by RGB.

Alvajoy123 wrote:
Questions
________
Does it play Gifs or it can play movies too?
and if it does play movie you should add a pause and resume button and
a video compressor to make the video smaller so it can be play on the calc

and if u wanted it to play at a higher farm rate would the video be slow
[...]


Neither. The encoder converts any input video files to a special format which the on-calculator player then plays. There is compression already being done on the input video stream so unless I do something fancy (which I might not have enough CPU cycles for) or I find something else that's computationally cheap to do (which is something I'm trying right now), this is about as good as it's going to get. As far as playback controls go, I don't want to deal with that right now. I just want to make something play.
You made me look. It turns out ffmpeg (which is our primary converter) accepts .gif as input. Things go very wrong very fast if you try to shove in an image with an aspect ratio any less than 1.2, though

The playback is also already at 30fps. I was actually thinking of reducing the frame rate to save some space but for videos with lots of action (such as the One Punch Man opening) that option is undesirable.

EDIT: As a point of comparison, the One Punch Man opening that I chose contains 2660 frames. I converted it to 96x54 frames (which is upscaled by 3x on-calc) at 4bpp. Adding in a palette of 15 (2 bytes each), that's 2622 bytes per frame. The final output would have been 6.97mb. Using ZX7 to compress batches of frames (10 frames a batch), I come up with about 3.47mb. This sort of decompression is fairly cheap so I can (mostly) keep playback at 30fps. I sorta cheat a little and use one of the xtal timers so when frames start lagging behind due to decompression delay, it fast-forwards at 64fps until it can catch up, tho I think this is hardly noticeable.
Please put it up as a download if you can. Smile
First of all, congratulations on making this program work so well.
EDIT: I had not updated to the latest C Libraries, which is why i was getting the first error, but the next error still pops up.
EDIT2: And I fixed the next problem by creating an empty 'bin' folder. I now that GitHub won't allow the inclusion of empty directories in its uploads, so it may be necessary to include a check for the presence of a bin folder in your .bat file.
I've gotten the encoder to work just fine on my computer, but I have issues building the decoder and player programs.

The following is the result of running 'make' in the CEVPLAY folder

Code:
Linking...
-FORMAT=INTEL32 -map -maxhexlen=64 -quiet -warnoverlap -xref -unresolved=fatal -sort ADDRESS=ascending -warn -NOdebug -NOigcase define __copy_code_to_ram = 0 range rom $000000 : $3FFFFF range ram $D00000 : $FFFFFF range bss $ : $ change code is ram change data is ram change text is ram change strsect is text define __low_bss = base of bss define __len_bss = length of bss define __heaptop = (highaddr of bss) define __heapbot = (top of bss)+1 define __stack = $ locate .header at $ locate .icon at (top of .header)+1 locate .launcher at (top of .icon)+1 locate .libs at (top of .launcher)+1 locate .graphx_header at (top of .libs)+1 locate .graphx at (top of .graphx_header)+1 locate .keypadc_header at (top of .graphx+1) locate .keypadc at (top of .keypadc_header)+1 locate .fileioc_header at (top of .keypadc+1) locate .fileioc at (top of .fileioc_header)+1 locate .startup at (top of .fileioc)+1 locate code at (top of .startup)+1 locate data at (top of code)+1 locate text at (top of data)+1 bin/.hex = obj\cstartup.obj,obj\libheader.obj,obj\main.obj,obj\graphx_header.obj,obj\keypadc_header.obj,obj\fileioc_header.obj,C:\CEdev\lib\cce.lib,C:\CEdev\lib\cshared.lib,C:\CEdev\lib\clinked.lib,C:\CEdev\lib\graphx.lib,C:\CEdev\lib\keypadc.lib,C:\CEdev\lib\fileioc.lib

FATAL ERROR (1053) --> unrecognized command token.

Input File: .hex
Output File: .8xp
[err] Unable to open input file.
make: *** [bin/] Error 1


And this is when I double-click build.bat in CEVDECODER

Code:
###############################################################################
Pass one...
Pass two...
Initial field size: 239
Main field size: 226

exporter: error SE001: Could not find the file 'bin\DECODR01.8xv'
Pass one...
Pass two...
Initial field size: 326
Main field size: 173

exporter: error SE001: Could not find the file 'bin\DECODR02.8xv'
Pass one...
Pass two...
Initial field size: 330
Main field size: 158

exporter: error SE001: Could not find the file 'bin\DECODR03.8xv'
Pass one...
Pass two...
Initial field size: 368
Main field size: 182

exporter: error SE001: Could not find the file 'bin\DECODR04.8xv'
Pass one...
Pass two...
Initial field size: 329
Main field size: 214

exporter: error SE001: Could not find the file 'bin\DECODR05.8xv'
Press any key to continue . . .

Is it just possible that you forgot to commit certain files?
I had a few errors while trying to use this, some probably caused because I am on Windows and using a newer library version. However, the main issue that I had was also experienced by others: a filesystem error (13) which seemed to be caused by how frequently the files tin and tout were being used. I was able to fix this by making tin and tout directories, and telling changing tfo and tfc to use a file in these directories with the segment index:

Code:
if not framedata and self.frame_buffer:
            tfo = np(TEMP_DIR+"/tin/"+str(self.cur_segment))
            tfc = np(TEMP_DIR+"/tout/"+str(self.cur_segment))
            if os.path.exists(tfo): os.remove(tfo)
            if os.path.exists(tfc): os.remove(tfc)
            while os.path.exists(tfo): time.sleep(1)
            writeFile(tfo,self.frame_buffer)
            while os.path.exists(tfc): time.sleep(1)
            #FNULL = open("NUL","w")
            subprocess.call([np(cwd+"/tools/zx7.exe"),tfo,tfc]) #,stdout=FNULL)
            while not os.path.exists(tfc): time.sleep(1)
            self.cmpr_arr.append(CmprSeg(self.cur_segment,readFile(tfc)))
            if os.path.exists(tfo): os.remove(tfo)
            if os.path.exists(tfc): os.remove(tfc)
            self.raw_len += len(self.frame_buffer)
            self.cmpr_len += self.cmpr_arr[-1].size
            sys.stdout.write("Output seg "+str(self.cur_segment)+" size "+str(self.cmpr_arr[-1].size)+"      \r")
            self.frame_buffer = []
            self.cur_frame = 0
            self.cur_segment += 1

Also, you seem to be using a version of the toolchain that does not complain about interrupts. In order for the player to compile on my computer, #define FORCE_INTERRUPTS 1 needed to be added above the includes.
EDIT: Mateo showed me that it was not interrupts causing the problem, but #include <intce.h>. The program will compile if that line is removed.
The decoder build.bat needs to create a empty bin folder, as ordelore mentioned:

Code:
if not exist bin\ mkdir bin

Also, it would be nice if you could exit the player while a video is playing.
If I remember tomorrow, I will submit a pull request, but it is getting late and I should probably sleep.
Ah I kinda made many of those fixes before reading the thread's latest posts. Oops.

I also fixed a few other outstanding issues, one of which was a pretty serious one in all the decoders involving writing outside of VRAM and in user memory. I also gave up on a particular change in the adaptive palette decoder so now they work.

I'll also consider adding controls in the playback. I'm too lazy to figure out how to draw the controls but putting in hotkeys should be doable.
The following has been changed/added since the last post:

* Added (Experimental) playback controls.
* Added 4bpp grayscale codec
* Changed 4bpp encoding method (yet again)
* (possibly) fixed compatibility with versions of PIL that lack a tobytes() method for its Image class

The playback controls allows you to pause (2nd), stop (mode), rewind (left), and fast-forward (right). These have only been tested in the 4bpp adaptive decoder so I know that works. I don't have any idea yet as to whether or not my changes will work on the other decoders since it takes a while to encode anything for testing.

I will not consider rendering any graphics for control purposes. Far too much work for something that just isn't interesting.
-----OPM download pls----- Razz (From Nov 13)

Nice progress! Glad to see this program is getting a little love again.
Since the last post, MateoC suggested to me the idea of extracting a subframe between two frames in which the content has changed and draw only that data when decoded. The space savings in doing this is remarkable. This allowed me to fit the entire One Punch Man intro scene and have space to spare. Where before it would've wanted 3.6MB, the video now takes 2.2MB.

The playback isn't quite perfect but... well. Judge for yourself.
Full OPM Introduction - 4bpp adaptive

I also tried to encode the opening sequence to Ghost in the Shell: Stand Alone Complex but it wouldn't fit. It nearly did (went over by about 74KB). It did before I put in a palette fix. Guess there's more work to be done.

EDIT: Changed embedded images to links to prevent performance problems when viewing this thread using a potato low end machine.
Since the last post I've been working on, in addition to a 8x8px grid differencing mode, I've been trying to pull together as many of the codecs as possible into a single file instead of requiring a decoder for every bpp and color mode. I've merged 1bpp b/w, 2bpp gs, 4bpp gs, 4bpp color, and 4bpp adaptive at 3x zoom into a single decoder. I've also did the same with 2x zoom which allows a higher resolution. Sort of. I hadn't quite tested the 4bpp yet. 1bpp was tested and it was hell trying to get 2bpp working

Oh speaking of higher resolution, here's an example of 2bpp grayscale video shot at 144x82. You can almost tell the text-like blobs are text.
This, btw, is an animated .png file. Firefox might not honor timing information but it works using IrfanView.
Full One Punch Man Opening - 2bpp grayscale (144x82px resolution, 2x zoom)

EDIT: This one is in 4bpp fixed palette color.
  
Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

» Go to Registration page
Page 1 of 1
» All times are GMT - 5 Hours
 
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

 

Advertisement