VideoPlayer on a Texture

This is a sidekick project of mine.
This is based on JME-JFX libs.
It took me a bit to set the equipment complete, so here is what i had to do, to get the original sample work:

It is using JavaFX, so you have to setup your JDK Platform to 1.8
Additionally you need
JME-JFX

Furthermore you need the MovieShader. I also added 2 small testmovies to test my code

This was nice. I could play a video in the background of my gui and it looked very nice.
I just installed me a dropbox seconds before to support this thread with what’s needed to start, so if the link doesn’t work, there maybe something wrong with my dropbox settings. Ashes on my head, we’ll get it, if it’s wrong.
MyDropBox

Back to the code. I wanted it to play several video files, so i had to do two things. First is to make the MediaPlayer capable to change a MediaSource, which is done by the MediaView and secondly i needed to refresh the TextureMovie somehow, so i made it a Node, which i just reinstantiate, if MediaPlayer does so.

Least was the currently solved problem on what to do, when the Runnable of MediaPlayer wants to do some useful things, since the video file finished.
Lately i added the housework to a Callback into the applications enqueue.

To show my work i have broken down my Class into its vital functionality. In this example i changed the List, which is used to play to a simple ArrayList, so in my final approach a small thing differs, but i will tell about that at the end of this article.

So - enough talked - here is the code:

/*
 * Copyright (c) 2015 Yves Tanas
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 * * Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 *
 * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
 *   may be used to endorse or promote products derived from this software
 *   without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package mygame.mediaManager;

import com.jme3.app.SimpleApplication;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.shape.Quad;
import com.jme3x.jfx.media.TextureMovie;
import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.concurrent.Callable;

import javafx.scene.media.MediaPlayer;
import javafx.scene.media.MediaView;
import javafx.scene.media.Media;

/** A simple media manager to play a list of videos
 * @author Yves Tanas
 */
public class SimpleMediaManager extends Node{
    
    SimpleApplication app;
    MediaPlayer mp;
    ArrayList<String> aryLst;
    
    public void init(SimpleApplication app){
        this.app = app;
        aryLst = new ArrayList<String>();
        aryLst.add("assets/Interface/vids/test2.mp4");  
        aryLst.add("assets/Interface/vids/test1.mp4");
        
        MediaView mediaView = new MediaView();
        
        MediaPlayer mp = initMediaPlayer(mediaView, aryLst.iterator());
        TextureNode node = new TextureNode("mediaManagerTextureNode");
        node.init(app, mp);
        attachChild(node);
    }

    private MediaPlayer initMediaPlayer(final MediaView mediaView, final Iterator<String> urls){   
        if (urls.hasNext()){
            mp = new MediaPlayer(new Media(new File(urls.next()).toURI().toASCIIString()));
            mp.setAutoPlay(true);
            mp.setOnEndOfMedia(new Runnable() {
                @Override public void run() {
                    app.enqueue(
                    new Callable<Boolean>() {
                        public Boolean call() throws Exception {
                            mp.stop();
                            initMediaPlayer(mediaView, urls);
                            detachChildNamed("mediaManagerTextureNode");
                            TextureNode node = new TextureNode("mediaManagerTextureNode");
                            node.init(app, mp);
                            attachChild(node);
                            return true;
                        }
                    });
                }
            });
            mediaView.setMediaPlayer(mp);
            return mp;
        } else return initMediaPlayer(mediaView, aryLst.iterator());
    }
    
    class TextureNode extends Node{

        private TextureMovie tex;

        public void init(SimpleApplication app,MediaPlayer mp){
            this.tex = new TextureMovie(app, mp, TextureMovie.LetterboxMode.VALID_LETTERBOX);
            this.tex.setLetterboxColor(ColorRGBA.Black);

            final Geometry videoScreen = new Geometry("videoScreen", new Quad(10,10));
            videoScreen.setLocalTranslation(-5, -5, 0);

            final Material s1mat = new Material(app.getAssetManager(), "Interface/MovieShader.j3md");
            s1mat.setTexture("ColorMap", this.tex.getTexture());
            s1mat.setInt("SwizzleMode", tex.useShaderSwizzle());
            videoScreen.setMaterial(s1mat);
            attachChild(videoScreen);        
        }

        public TextureNode(String name){
            super(name);
        }
    }    
     
}

In real scenario i change The iterator to a String value, because i have my own representation of that list, so it then looks like this:

    private void initMediaPlayer(final MediaView mediaView, final String url){   
        mp = new MediaPlayer(new Media(new File(url).toURI().toASCIIString()));
        mp.setAutoPlay(true);

        mp.setOnEndOfMedia(new Runnable() {
            @Override public void run() {
                app.enqueue(
                new Callable<Boolean>() {
                    public Boolean call() throws Exception {
                        mp.stop();
                        initMediaPlayer(mediaView, actualList.getPath()+actualList.getMediaLocation());
                        detachChild(node);
                        node = new TextureNode2("mediaManagerTextureNode");
                        node.init(app, mp);
                        attachChild(node);

                        return true;
                    }
                });
            }
        });
        mediaView.setMediaPlayer(mp);
    }

Have a nice sunday ! :wink:

Ah ! Since i forgot about that. A possibility why video isn’t playing could be, that the video decoding was not fitted to streaming video, so i had to find an decoding setup which is usable.
This is, why i attached those two small testmovies to the vids.rar. They are very small (1MB), very short and ready to use.

Hi,

What is the differences with TextureMovie provided by JME3-JFX ?

It’s my own basic adaptation of that and i am free to share it over to JME3-JFX, i have no trouble with that.
If you ask. Most difference is the soluted housework done for the none-experienced guy with taking away that code.
If i used TestMovie, which is the original one, no question about that, i can only repeat that movie over and over again. changing the source media file makes it a little bit more tricky, so i worked on this. The given List is changeable and everytime the movie finishes, it has to reconstruct itself to play the next movie.
This was not possible by just taking away the TestMovie code as it is.

If you just ask: Feel free to download the vids.rar with test1.mp4 and test2.mp4 and try it yourself.

In my own approach i have my own List, which is handling itself, so i don’t need that silly arraylist and just give over a string to that method.

Most difference is the MediaView handling the resources for the MediaPlayer and those two are dancing with the scenegraph, who tries to have the correct TextureMovie to show that.

Thanks for the response.

I don’t yet try your code. But I have another comments :wink: :
“Extending Spatial, Node,… is often a bad practice” (see http://wiki.jmonkeyengine.org/doku.php/jme3:intermediate:best_practices). In your case I don’t see the need to extends Node, a “factory” or configure method can do the job.

What is the role Aurellem jmeCapture ?

call it unexpierency.
since now it was easy to me to communicate with these objects by just simply asking the rootNode to give it to me and do the housework.
as this is just a feature on a special state of my game in my shown scene i called it a node, so i can attach it to that scene. i don’t need to do math in there, but it’s quite handy to take it from the node, call a method and forget about that. It’s a node out of seperating context, so i don’t have a 5000 lines long main application source code, seperating this and treat it like an object i can use frequently anywhere. Same to the TextureNode… Making both a Node, i can attach it to the rootNode and change the TextureNode as i want, because i can attach and detach it whenever i want.

you are right ^^ aurellem isn’t needed ! i remove that. that’s some leftover from my search…

A small showcase on what’s going on right now with this.
Yeah, i can switch to any video i want and use it in my menu and learning section frequently.

3 Likes

Btw. It’s still not generalized yet, because i am missing some things right now, but it’s working well as you could see and it is now an AppState.
What i didn’t get rid of is putting the TextureMovie on some Node i attach to the localRootNode.
I tried to make the Geometry videoscreen a possible object variable of MediaManagerAppState, but that didn’t work, so i let it be as it is now.
I will make changes in the management of the update of this player, but loading, playing, stopping, detaching and attaching is fine now:

import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.jme3.app.Application;
import com.jme3.app.SimpleApplication;
import com.jme3.app.state.AppStateManager;
import com.jme3.audio.AudioNode;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.shape.Quad;
import de.wwcto.application.appstates.definitions.AppState;
import de.wwcto.definitions.mediaManager.Audio;
import de.wwcto.definitions.mediaManager.AudioList;
import de.wwcto.definitions.mediaManager.Video;
import de.wwcto.definitions.mediaManager.VideoList;
import java.util.HashMap;
import javafx.scene.media.MediaPlayer;
import javafx.scene.media.MediaView;
import com.jme3x.jfx.media.TextureMovie;
import de.wwcto.application.controller.AbstractLoadingScreenController;
import de.wwcto.definitions.exceptions.MediaManagerException;
import de.wwcto.definitions.exceptions.mediamanager.CouldntDetachVideoNodeException;
import de.wwcto.definitions.exceptions.mediamanager.CouldntFindMenuItemException;
import de.wwcto.definitions.exceptions.mediamanager.CouldntInitMediaViewException;
import de.wwcto.definitions.exceptions.mediamanager.CouldntInitVideoException;
import de.wwcto.definitions.exceptions.mediamanager.CouldntStartVideoException;
import de.wwcto.definitions.exceptions.mediamanager.CouldntStopVideoException;
import de.wwcto.definitions.exceptions.mediamanager.IndexTooHighException;
import de.wwcto.definitions.exceptions.mediamanager.NoVideoFoundException;
import de.wwcto.definitions.exceptions.mediamanager.NoVideoListFoundException;
import de.wwcto.definitions.exceptions.mediamanager.NoVideoPlayerFoundException;
import java.io.File;
import java.util.concurrent.Callable;
import javafx.scene.media.Media;
/**
 * MediaManager as AppState
 * @author Yves Tanas
 */
public class MediaManagerAppState extends AppState{

       /** MediaPlayer from javafx to show video*/
    private MediaPlayer videoPlayer;
    /** MediaPlayer from javafx to show audio*/
    private MediaPlayer audioPlayer;    
    
    /** HashMap of video Playlists */
    HashMap<String, VideoList> videoPlayLists = new HashMap<String, VideoList>();
    /** HashMap of audio Playlists */
    HashMap<String, AudioList> audioPlayLists = new HashMap<String, AudioList>();
    
    /** actual used video playlist */
    VideoList actualVideoList;
    /** actual used audio playlist */
    AudioList actualAudioList;
    /** actual video playing */
    Video actualVideo;  
    /** actual audio playing */
    Audio actualAudio;
    
    /** The managing MediaView for multiple videos */
    MediaView video;
    
    /** An audio Node for playing music */
    @Deprecated
    AudioNode music;
    
    /** switch to false, if we are outside the start screen */
    private boolean isInStartScreen = true;

    /** index count of intro video */
    private int index = 0;
    /** the menu we are currently in */
    private String currentMenuScreen = "menuVideo";      
    
    /** identifier to choose the correct list */
    private String listIdentifier = "intros";
    /** identifier to choose the correct movie from list */
    private String movieIdentifier = "intro1";
    
    /** switch for playing intro video vs. menu video */
    private boolean isPlayingIntroVideo = true;   
    
    /** A node to attach the TextureMovie */
    private TextureNode textureNode;
    
    @Override
    public void initialize(AppStateManager stateManager, Application app) {
        super.initialize(stateManager, app); 
    }
    
     /** Inits a new MediaManager*/
    public void build(){
        
        videoPlayLists = buildVideoPlayLists(videoPlayLists);
        
        actualVideoList = videoPlayLists.get("test");
                
        try{
            actualVideo = (Video)actualVideoList.getElementFromIndex(0);
            
        } catch (IndexTooHighException ex){
            ex.printStackTrace();
            System.out.println("index too high");
        }
        
        video = createVideoMediaView();
        try{
            textureNode = new TextureNode("mediaManagerTextureNode");
            localRootNode.attachChild(textureNode);      
            loadVideo(listIdentifier, movieIdentifier);
            initVideo();
        } catch (MediaManagerException ex){
            System.out.println("Something went wrong - l.97");
        }
        
        audioPlayLists = buildAudioPlayLists(audioPlayLists);
        
        actualAudioList = audioPlayLists.get("menu");
        actualAudio = (Audio) actualAudioList.get("mainTheme");
        
        createAudioMediaView();
    }
    /** attaches the MediaManager to the rootNode if it is not attached */
        public void attachToRootNode(){
        if(!rootNode.hasChild(localRootNode))
            rootNode.attachChild(localRootNode);
    }
    /** detaches the MediaManager to the rootNode if it is attached */
    public void detachFromRootNode(){
        if(rootNode.hasChild(localRootNode))
            rootNode.detachChild(localRootNode);
    }
        
    /** returns the current menu screen string */
    public String getCurrentMenuScreen() {
        return currentMenuScreen;
    }

    /** sets the current menu screen string */
    public void setCurrentMenuScreen(String currentMenuScreen) {
        this.currentMenuScreen = currentMenuScreen;
    }    
    
    /** closing method */
    public void destroy() {
        this.videoPlayer.stop();
        this.audioPlayer.stop();
    }
    /** closing method */
    public void stop(){
        destroy();
    }
    /** cycle in menu section.
     * should be generalized later
     * @return true if it worked
     * @throws MediaManagerException 
     */
    public boolean cyclePlayer() throws MediaManagerException{       
        if(isPlayingIntroVideo)
        {
            // if we are playing now an intro video
            listIdentifier = "intros";
            // watchout for index problems
            if(index <= actualVideoList.getObjectListSize())
                index++;
            else
                index = 0;  
            // get the actual wanted list
            actualVideoList = videoPlayLists.get(listIdentifier);        
            // lookup which video is next
            movieIdentifier = actualVideoList.getOrderElement(index);
        }else{
            // if we are now playing a menu related video
            listIdentifier = "menu";    
            // get the actual wanted list
            actualVideoList = videoPlayLists.get(listIdentifier);        
            // lookup which video is next
            movieIdentifier = currentMenuScreen;
            
            createAudioMediaView();
            audioPlayer.play();
        }
        // get the wanted video file
        loadVideo(movieIdentifier);

        onOffVideoAlgorithm();
        
        return true;
    }

    /** small portion of work on menu change.
     * stop video, init new video, attach it and start it 
     * @throws MediaManagerException 
     */
    private void onOffVideoAlgorithm() throws MediaManagerException{
        // stop current video
        if(!stopVideo()||videoPlayer == null)
            throw new CouldntStopVideoException();
        // init new video player instance
        if(!initVideo()||videoPlayer == null)
            throw new CouldntInitVideoException();
        // start Video
        if(!startVideo()||videoPlayer == null)
            throw new CouldntStartVideoException();        
    }
    
    /** if menu changed */
    public boolean onMenuChange(String menuItem) throws MediaManagerException{
        if(!videoPlayLists.get("menu").contains(menuItem)) throw new CouldntFindMenuItemException();
        if(!isPlayingIntroVideo)
        {
            if(!loadVideo("menu", menuItem)) throw new MediaManagerException();            
            onOffVideoAlgorithm();
        } 
        currentMenuScreen = menuItem;
        return true;
    }
    
    /** Loads a video given by the listName and its title index  setupVideo
     * @param listName String name of the playlist, the video is in
     * @param title String of the title of the Video
     * @return boolean if succeeded
     * @throws MediaManagerException several scenarios of failure added
     */
    public boolean loadVideo(String listName, String title) throws MediaManagerException{
        if(!videoPlayLists.containsKey(listName))
            throw new NoVideoListFoundException();
        actualVideoList = videoPlayLists.get(listName);
        if(!actualVideoList.contains(title))
            throw new NoVideoFoundException();
        actualVideo = (Video) actualVideoList.get(title);
        return true;
    }
    
    /** Loads a video given by the listName and its title index
     * @param listName String name of the playlist, the video is in
     * @param title String of the title of the Video
     * @return boolean if succeeded
     * @throws MediaManagerException several scenarios of failure added
     */
    private boolean loadVideo(String title) throws MediaManagerException{
        if(!actualVideoList.contains(title))
            throw new NoVideoFoundException();
        actualVideo = (Video) actualVideoList.get(title);
        return true;
    }    
    
    /** stops the current video */
    public boolean stopVideo() throws MediaManagerException{
        if(videoPlayer == null) throw new NoVideoPlayerFoundException();
        videoPlayer.stop();
        return true;
    }
    
    /** starts the actual video */
    public boolean startVideo() throws CouldntStartVideoException{
        if(videoPlayer == null) throw new CouldntStartVideoException();
        videoPlayer.play();
        return true;
    }
    
    /** inits a video MediaView and a new Texture Node
     * @return if succeeded
     * @throws MediaManagerException if node==null or MediaView couldn't be created
     */
    private boolean initVideo() throws MediaManagerException{
        MediaView view = createVideoMediaView();
        if(view == null) throw new CouldntInitMediaViewException();
        if(textureNode == null) throw new CouldntDetachVideoNodeException();       
        localRootNode.detachChild(textureNode);                        
        textureNode = new TextureNode("mediaManagerTextureNode");
        textureNode.init(app, videoPlayer);
        localRootNode.attachChild(textureNode);                        
        return true;
    }

    /** Creates a new videoMediaView */
    private MediaView createVideoMediaView(){
        MediaView videoMediaView = new MediaView();
        initVideoMediaPlayer(videoMediaView, actualVideoList.getPath()+actualVideo.getBasicInformation());
        return videoMediaView;
    }
     
    /** inits a given media view to play video 
     * @param mediaView MediaView instance
     * @param url String to the media file
     */
    private void initVideoMediaPlayer(MediaView videoMediaView, String url){         
        videoPlayer = new MediaPlayer(new Media(new File(url).toURI().toASCIIString()));
        videoPlayer.setOnEndOfMedia(new Runnable() {
            @Override public void run() {
                app.enqueue(
                new Callable<Boolean>() {
                    public Boolean call() throws Exception {
                        isPlayingIntroVideo = !isPlayingIntroVideo;
                        cyclePlayer();
                        return true;
                    }
                });
            }
        });
        videoMediaView.setMediaPlayer(videoPlayer);
    }

    /** Creates a new videoMediaView */
    private MediaView createAudioMediaView(){
        MediaView mediaView = new MediaView();
        initAudioMediaPlayer(mediaView, actualAudioList.getPath()+actualAudio.getBasicInformation());
        return mediaView;
    }
     
    /** inits a given media view to play video 
     * @param mediaView MediaView instance
     * @param url String to the media file
     */
    private void initAudioMediaPlayer(final MediaView mediaView, final String url){   
        audioPlayer = new MediaPlayer(new Media(new File(url).toURI().toASCIIString()));
        audioPlayer.setOnEndOfMedia(new Runnable() {
            @Override public void run() {
                app.enqueue(
                new Callable<Boolean>() {
                    public Boolean call() throws Exception {
                        isPlayingIntroVideo = !isPlayingIntroVideo;
                        cyclePlayer();
                        return true;
                    }
                });
            }
        });
        mediaView.setMediaPlayer(audioPlayer);
    }
    
    /** inner class to attach the TextureMovie */
    class TextureNode extends Node{
        /** TextureMovie*/
        private TextureMovie tex;

        /** Inits the Texture Movie, builds a videoScreen and sets
         * the material, afterwards it attaches it to the node.
         * @param app SimpleApplication Used to communicate with the MediaPlayer
         * @param mp  MediaPlayer the MediaPlayer playing the movie
         */
        public void init(SimpleApplication app,MediaPlayer mp){
            this.tex = new TextureMovie(app, mp, TextureMovie.LetterboxMode.VALID_LETTERBOX);
            this.tex.setLetterboxColor(ColorRGBA.Black);

            final Geometry videoScreen = new Geometry("videoScreen", new Quad(10,10));
            videoScreen.setLocalTranslation(-5, -5, 0);

            final Material s1mat = new Material(app.getAssetManager(), "Shaders/MovieShader/MovieShader.j3md");
            s1mat.setTexture("ColorMap", this.tex.getTexture());
            s1mat.setInt("SwizzleMode", tex.useShaderSwizzle());
            videoScreen.setMaterial(s1mat);
            attachChild(videoScreen);        
        }

        public TextureNode(String name){
            super(name);
        }
    }
        
    public MediaManagerAppState(SimpleApplication app) {
        super(app);
    }
    
    /** builds the video playlist out of the resource movieCollection.json */
    public HashMap<String, VideoList> buildVideoPlayLists(HashMap<String, VideoList> videoPlayList){
        
        // This is weird so i frequently reuse that silly two objects !
        JsonArray settingsList = (JsonArray)assetManager.loadAsset("InitialValues/movieCollection.json");
        JsonObject settings = settingsList.get(0).getAsJsonObject().get("movieCollection").getAsJsonObject(); 
        app.getStateManager().getState(AbstractLoadingScreenController.class).setProgress(.15f, "Loading movie lists");   
        String path = settings.get("path").getAsString();        
        JsonArray settingsList2 = settings.get("playLists").getAsJsonArray();
        float factor = .8f / settingsList2.size();
        for(int i = 0; i < settingsList2.size(); i++){
            settings = settingsList2.get(i).getAsJsonObject();
            VideoList list = new VideoList(settings.get("name").getAsString(), path);
                        JsonArray order = settings.get("order").getAsJsonArray();
            app.getStateManager().getState(AbstractLoadingScreenController.class).setProgress(.15f+(factor*i), "List "+list.getIndex()+" added");
            String orderString[] = new String[order.size()];
            for(int j = 0; j < order.size(); j++){ 
                JsonObject orderElement =  order.get(j).getAsJsonObject();
                orderString[j] = orderElement.get("name").getAsString();
            }
            app.getStateManager().getState(AbstractLoadingScreenController.class).setProgress(.15f+(factor*i)+.0005f, "List "+list.getIndex()+" ordered");
            list.setOrder(orderString);
            videoPlayList.put(list.getIndex(), list);
            settingsList = settings.get("list").getAsJsonArray();
            float factor2 = settingsList.size();
            for(int j = 0; j < settingsList.size(); j++){ 
                JsonObject object = settingsList.get(j).getAsJsonObject();
                
                Video title = new Video(object.get("index").getAsString(), object.get("filename").getAsString());
                title.setTitle(object.get("title").getAsString());
                app.getStateManager().getState(AbstractLoadingScreenController.class).setProgress(.15f+(factor*i)+(factor/factor2*j), "Movie "+title.getTitle()+" added to "+list.getIndex());
                list.add(title);
                app.getStateManager().getState(AbstractLoadingScreenController.class).setProgress(.15f+(factor*i)+j*factor/factor2, "Movie "+title.getTitle()+" added");
            }
        }
        return videoPlayList;
    }
    
    /** builds the video playlist out of the resource movieCollection.json */
    public HashMap<String, AudioList> buildAudioPlayLists(HashMap<String, AudioList> audioPlayList){
        
        // This is weird so i frequently reuse that silly two objects !
        JsonArray settingsList = (JsonArray)assetManager.loadAsset("InitialValues/audioCollection.json");
        JsonObject settings = settingsList.get(0).getAsJsonObject().get("audioCollection").getAsJsonObject(); 
        app.getStateManager().getState(AbstractLoadingScreenController.class).setProgress(.15f, "Loading movie lists");   
        String path = settings.get("path").getAsString();        
        JsonArray settingsList2 = settings.get("playLists").getAsJsonArray();
        float factor = .8f / settingsList2.size();
        for(int i = 0; i < settingsList2.size(); i++){
            settings = settingsList2.get(i).getAsJsonObject();
            AudioList list = new AudioList(settings.get("name").getAsString(), path);
                        JsonArray order = settings.get("order").getAsJsonArray();
            app.getStateManager().getState(AbstractLoadingScreenController.class).setProgress(.15f+(factor*i), "List "+list.getIndex()+" added");
            String orderString[] = new String[order.size()];
            for(int j = 0; j < order.size(); j++){ 
                JsonObject orderElement =  order.get(j).getAsJsonObject();
                orderString[j] = orderElement.get("name").getAsString();
            }
            app.getStateManager().getState(AbstractLoadingScreenController.class).setProgress(.15f+(factor*i)+.0005f, "List "+list.getIndex()+" ordered");
            list.setOrder(orderString);
            audioPlayList.put(list.getIndex(), list);
            settingsList = settings.get("list").getAsJsonArray();
            float factor2 = settingsList.size();
            for(int j = 0; j < settingsList.size(); j++){ 
                JsonObject object = settingsList.get(j).getAsJsonObject();
                
                Audio title = new Audio(object.get("index").getAsString(), object.get("filename").getAsString());
                app.getStateManager().getState(AbstractLoadingScreenController.class).setProgress(.15f+(factor*i)+(factor/factor2*j), "Movie "+title.getTitle()+" added to "+list.getIndex());
                list.add(title);
                app.getStateManager().getState(AbstractLoadingScreenController.class).setProgress(.15f+(factor*i)+j*factor/factor2, "Movie "+title.getTitle()+" added");
            }
        }
        return audioPlayList;
    }    
}

Hello,
I am follow what you are saying but I am not able to do it. Can you make a tutorial explaining all the steps?