Video Cutscenes

Discussion in 'NDS - Emulation and Homebrew' started by loco365, Dec 21, 2011.

Dec 21, 2011

Video Cutscenes by loco365 at 4:35 PM (2,264 Views / 0 Likes) 46 replies

  1. loco365
    OP

    Member loco365 GBAtemp Guru

    Joined:
    Sep 1, 2010
    Messages:
    5,459
    Of course we all want to have video cutscenes in our games. It makes them more professional looking. But, has anyone managed to do it with an AVI file just yet? I'm curious to know this because I was doing a bit of research into that last night (At 2 AM to boot) and I found an interesting piece of homebrew. Well, two of them, but they both revolve around the same idea. First, to see what I am getting at, visit this page and download either the nyands or rickroll nds files and watch them. Yes, I'm serious. Watch them. The reason for that is the way they create a video effect is shown in the source (Which is also provided on that page!) and how well it works. The only downside to their app is the .nds file is very large. But, how they did it was displaying a bunch of .raw image files at a fast enough of a speed to emulate a video, then played the audio alongside it to simulate a video effect.

    Is there a better alternative, because I'd like to make a video cutscene (The video I want to use is 50 seconds long and has 755 frames- that'd make a huge NDS file!) but I'd rather make the task simple and not have to use frame-by-frame image playback as it'd be inefficient to use. Or is a video library for devkitpro in development?
     


  2. coolness

    Banned coolness PSN: Dutch_DarkLord

    Joined:
    Jun 14, 2009
    Messages:
    2,016
    Location:
    Rotterdam Bitches!!
    Country:
    Netherlands
    so its plays video`s directly from the nds rom?
     
  3. loco365
    OP

    Member loco365 GBAtemp Guru

    Joined:
    Sep 1, 2010
    Messages:
    5,459
    It's not a video. It's a large sequence of raw images that play in a way that represents a video. In the 30 second Rickroll video, there is 330 frames to make the video. Watch the NDS images in NO$GBA, Desmume seems to not like them.
     
  4. spinal_cord

    Member spinal_cord Knows his stuff

    Joined:
    Jul 21, 2007
    Messages:
    2,871
    Location:
    somewhere
    Country:
    United Kingdom
    The best solution is to use a collection of jpg images, rather than raw images. this solution is similar to the mjpeg video codec.
     
  5. loco365
    OP

    Member loco365 GBAtemp Guru

    Joined:
    Sep 1, 2010
    Messages:
    5,459
    I'm curious to see code for this. The only issue I'd have now is making it load. I'd need to decide on FAT access or embedding it in the ROM. And since I'm only starting to learn, this will be a lot of fun.

    But hey - We all start somewhere!
     
  6. Dirbaio

    Member Dirbaio GBAtemp Regular

    Joined:
    Sep 26, 2010
    Messages:
    158
    Location:
    Spain
    Country:
    Spain
    You can take a look at what I coded for Fireworlds.
    It plays a video format I made myself, that features a really simple compression scheme. The compression ratio is not good (I'd say 3-4 times smaller than just storing the raw 16bpp 256x192 frames) but on the other hand it's efficient enough to play back at 30fps. It could get even more efficient if it was coded in ASM, though getting to 60fps is impossible. Videos in Fireworlds are 20fps though.
    Also, the VRAM is double-buffered so there's no tearing.

    http://code.google.com/p/fireworlds/source/browse/trunk/fireworlds-game/arm9/source/video.itcm.cpp

    There's also the encoder for the format, here. Made in java, it's REALLY slow.

    http://code.google.com/p/fireworlds/source/browse/#svn%2Ftrunk%2Fvds-encoder
     
  7. loco365
    OP

    Member loco365 GBAtemp Guru

    Joined:
    Sep 1, 2010
    Messages:
    5,459
    This looks good. I'll look and see what I can do with it and I'll also have to figure out how to add it. Plus, I averaged the video to approximately 15 FPS, so it should play at near-full speed!

    ...I hate having to learn this.
     
  8. Dirbaio

    Member Dirbaio GBAtemp Regular

    Joined:
    Sep 26, 2010
    Messages:
    158
    Location:
    Spain
    Country:
    Spain
    Nice :)

    If you have any questions about it, just ask me and I'll see what I can do!

    You'll probably need it with the video encoder, it's in a really primitive state :(
     
  9. loco365
    OP

    Member loco365 GBAtemp Guru

    Joined:
    Sep 1, 2010
    Messages:
    5,459
    Yeah. I try to convert stuff and only get a 1 byte-sized file. I'm guessing that it's looking for the sequences of .jpg files? Or does it want the .avi?

    Edit: Got it. Now it's doing stuff. Now if I could find some way to quickly load it so I can see how fast it plays.

    Edit 2: To make it really quick, I copied it to Fireworlds and loaded it because I don't want to have to type out the code to play it. But, the video conversion is really nice! The only issue I have is that it plays too fast, about 20 seconds too fast.The video in it's avi form is, as stated, 50 seconds. The .vds is 30 seconds. I'm guessing though, that you can change that when you add the ability to play video in the source code, how fast it plays (FPS)?

    Edit 3: I did some math and it seems that your videos play at 25 FPS and mine plays at 15. I would assume there is a parameter for that, though?
     
  10. Dirbaio

    Member Dirbaio GBAtemp Regular

    Joined:
    Sep 26, 2010
    Messages:
    158
    Location:
    Spain
    Country:
    Spain
    Yes, it's in video.itcm.cpp, line 87. Change that 20 to whatever you want, it's in frames per second.

    Also, in case you want to put the video decoder in your own project, this is the only code you need. (besides initializing FAT, of course)
    main.itcm.cpp line 347
    http://code.google.com/p/fireworlds/source/browse/trunk/fireworlds-game/arm9/source/main.itcm.cpp#347
     
  11. loco365
    OP

    Member loco365 GBAtemp Guru

    Joined:
    Sep 1, 2010
    Messages:
    5,459
    I will definitely use it. It looks really good and it will work for what I need it. Thank you so much.

    I might have some more questions as I'm still playing with the code and getting it to work, like button presses and whatnot so it'll be touch and go from here on.
     
  12. Dirbaio

    Member Dirbaio GBAtemp Regular

    Joined:
    Sep 26, 2010
    Messages:
    158
    Location:
    Spain
    Country:
    Spain
    Great!
    Glad it helps :)
     
  13. LeRodeur

    Member LeRodeur GBAtemp Regular

    Joined:
    Dec 12, 2009
    Messages:
    162
    Country:
    France
    Looks interesting, I might give it a shot
     
  14. loco365
    OP

    Member loco365 GBAtemp Guru

    Joined:
    Sep 1, 2010
    Messages:
    5,459
    Well, once I get my button presses figured out, I'll have to see how you call the video up. First, I need to get to that point. And I'm already having issues. I guess I'll have to keep trying until I get an expected result.
     
  15. loco365
    OP

    Member loco365 GBAtemp Guru

    Joined:
    Sep 1, 2010
    Messages:
    5,459
    Ok yeah. I can't get button presses working. At all.

    Code:
    
    -------------------------------------------------
    
    NightFox's Lib Template
    Ejemplo carga de fondos en 16bits (modo BITMAP)
    
    Requiere DevkitARM
    Requiere NightFox's Lib
    
    Codigo por NightFox
    http://www.nightfoxandco.com
    Inicio 10 de Octubre del 2009
    
    (c)2009 - 2011 NightFox & Co.
    
    -------------------------------------------------
    -------------------------------------------------
    Includes
    -------------------------------------------------
    */
    
    // Includes C
    #include 
    #include 
    #include 
    
    // Includes propietarios NDS
    #include 
    
    // Includes librerias propias
    #include 
    
    /*
    -------------------------------------------------
    Main() - Bloque general del programa (Mod by TF)
    -------------------------------------------------
    */
    
    int main(int argc, char **argv) {
    
    // Pantalla de espera inicializando NitroFS
    NF_Set2D(0, 0);
    NF_Set2D(1, 0);
    consoleDemoInit();
    iprintf("Initiating FAT... Please Wait.\n\nIf you are stuck here, try\nrestarting your DS.\n\nIf that does not fix\nthe issue, try \nre-patching DLDI if your\ncard doesn't support\nit.");
    int count = 300;
    while(count--) swiWaitForVBlank;
    u16 keys = 0;
    
    // Define el ROOT e inicializa el sistema de archivos
    NF_SetRootFolder("Crazy_Moto"); // Define la carpeta ROOT para usar NITROFS
    
    // Inicializa el motor 2D en modo BITMAP
    NF_Set2D(0, 5); // Modo 2D_5 en ambas pantallas
    NF_Set2D(1, 5);
    
    // Inicializa los fondos en modo "BITMAP"
    NF_InitBitmapBgSys(0, 1);
    NF_InitBitmapBgSys(1, 1);
    consoleClear(); //Clears text console.
    
    // Inicializa los buffers para guardar fondos en formato BITMAP
    NF_Init16bitsBgBuffers();
    
    // Carga el archivo BITMAP de imagen en formato RAW a la RAM
    NF_Load16bitsBg("bmp/top_intro_1", 0);
    NF_Load16bitsBg("bmp/touch_intro_1", 1);
    // Tranfiere la imagen a la VRAM de ambas pantallas
    NF_Copy16bitsBuffer(0, 0, 0);
    NF_Copy16bitsBuffer(1, 0, 1);
    iprintf("Nothing else to see.");
    
    // Si no es necesario usarla mas, borrala de la RAM
    NF_Unload16bitsBg(0);
    NF_Unload16bitsBg(1);
    
    while(1) {
    scanKeys();
    if(!(keysHeld() & KEY_A)) {
    NF_Load16bitsBg("bmp/top_intro_2", 0);
    NF_Load16bitsBg("bmp/touch_intro_2", 1);
    NF_Copy16bitsBuffer(0, 0, 0);
    NF_Copy16bitsBuffer(1, 0, 1);
    NF_Unload16bitsBg(0);
    NF_Unload16bitsBg(1);
    while (1) {
    swiWaitForVBlank();
    if (!(keysHeld() & KEY_A)) systemShutDown();
    }
    }
    else (swiWaitForVBlank());
    }
    
    return 0;
    
    }
    
    
    I'm building off NightFox's 16bgbitsload example, but I can't get button A to unload top/touch_intro_1 and load top/touch_intro_2 to the screen. All this does is display an image for a split second before shutting off. Once I can get that to work, then I'll figure out where to put the video code, but I want to sort this out first. What in the world am I doing wrong?
     
  16. LeRodeur

    Member LeRodeur GBAtemp Regular

    Joined:
    Dec 12, 2009
    Messages:
    162
    Country:
    France
    I dont really know nflib but.. With your code if A isn't pressed it loads the bg, unloads it and automatically power off because you have the same condition for the shutdown.. Plus I don't really understand what you want to do
    edit: plus when program reaches the second while, keys are not refreshed in the loop anymore and the else swiwait is useless (will be called two times so your fps will drop to 30)
     
  17. loco365
    OP

    Member loco365 GBAtemp Guru

    Joined:
    Sep 1, 2010
    Messages:
    5,459
    Well, I should have mentioned that. *headdesk*

    I need it to display top/touch_intro_1 and wait for button A before unloading it and loading top/touch_intro_2. Once that has happened, I want A to shut off the DS until I can get more code in there to program the cutscene and see how this lib works.
     
  18. LeRodeur

    Member LeRodeur GBAtemp Regular

    Joined:
    Dec 12, 2009
    Messages:
    162
    Country:
    France
    Then you should do this

    load the first bg;
    while( !(keysHeld() & KEY_A)) { scanKeys();}
    Load second;
    scankeys();
    while( !(keysnewpress() & KEY_A)) { scanKeys();}
    Unload second;
    shutdown;
     
  19. loco365
    OP

    Member loco365 GBAtemp Guru

    Joined:
    Sep 1, 2010
    Messages:
    5,459
    Ok. So I now have this:
    Code:
    // Carga el archivo BITMAP de imagen en formato RAW a la RAM
    NF_Load16bitsBg("bmp/top_intro_1", 0);
    NF_Load16bitsBg("bmp/touch_intro_1", 1);
    // Tranfiere la imagen a la VRAM de ambas pantallas
    NF_Copy16bitsBuffer(0, 0, 0);
    NF_Copy16bitsBuffer(1, 0, 1);
    
    // Si no es necesario usarla mas, borrala de la RAM
    while( !(keysHeld() & KEY_A)) { scanKeys();}
    NF_Unload16bitsBg(0);
    NF_Unload16bitsBg(1);
    NF_Reset16bitsBgBuffers(); //This just resets the buffers and clears out RAM for the next image.
    NF_Load16bitsBg("bmp/top_intro_2", 0);
    NF_Load16bitsBg("bmp/touch_intro_2", 1);
    NF_Copy16bitsBuffer(0, 0, 0);
    NF_Copy16bitsBuffer(1, 0, 1);
    while( !(keysHeld() & KEY_A)) { scanKeys();}
    NF_Unload16bitsBg(0);
    NF_Unload16bitsBg(1);
    NF_Reset16bitsBgBuffers();
    systemShutDown();
    Pressing A just shuts it off. Here is the makefile process:
    Code:
    main.c
    arm-eabi-gcc -MMD -MP -MF /c/devkitPro/examples/graphics/bg16bitsload/build/main
    .d -g -Wall -O2 -march=armv5te -mtune=arm946e-s -fomit-frame-pointer -ffast-math
    -mthumb -mthumb-interwork -iquote /c/devkitPro/examples/graphics/bg16bitsload/i
    nclude -I/c/devkitPro/libnds/include -I/c/devkitPro/examples/graphics/bg16bitslo
    ad/nflib/include -I/c/devkitPro/examples/graphics/bg16bitsload/build -DARM9 -c /
    c/devkitPro/examples/graphics/bg16bitsload/source/main.c -o main.o
    c:/devkitPro/examples/graphics/bg16bitsload/source/main.c: In function 'main':
    c:/devkitPro/examples/graphics/bg16bitsload/source/main.c:47:17: warning: statem
    ent with no effect [-Wunused-value]
    c:/devkitPro/examples/graphics/bg16bitsload/source/main.c:48:6: warning: unused
    variable 'keys' [-Wunused-variable]
    linking bg16bitsload.elf
    Nintendo DS rom tool 1.50 - Oct 15 2011
    by Rafael Vuijk, Dave Murphy, Alexei Karpenko
    built ... bg16bitsload.nds
    Press any key to continue . . .
    
     
  20. Dirbaio

    Member Dirbaio GBAtemp Regular

    Joined:
    Sep 26, 2010
    Messages:
    158
    Location:
    Spain
    Country:
    Spain
    Oh, I think I know what's going on :)

    The DS waits in the first loop for A to be pressed. When you press it, it loads the other BG and proceeds to do the second loop. BUT when it arrives there the button A is still pressed (the DS loads the BG faster than you can press and release the button). Then it doesn't even wait for another button press, and proceeds to shut down :)

    To fix it you could use keysDown() instead of keysHeld():

    keysHeld returns true when the button is pressed, but keysDown only returns true if the button was just pressed since the last key read.
     

Share This Page