Media has stopped working the way it should - codenameone

I have an app which I made over two years ago which has a list of videos. When one of the list buttons is clicked, the media played full screen. This was working perfectly OK on Android (I have't tried other platforms) until I resubmitted it to the build server on 31-07-2016. After this I noticed that the videos were no longer working full screen.
This month, I resubmitted the app to the build server and now there are a couple of things that don't work. The most noticeable feature is that the video is stretched in portrait mode to fill the form (even without setFullScreen()). The other issue I have noticed is that if I click the back button and play another video, I get the new video and the old video still playing at the side / corner of the screen. I have tried pause() and cleanup() but they seem to have no effect. I have tried adding the Media directly to a Container and using MediaPlayer and found the same issues with both.
try {
((com.codename1.ui.layouts.BorderLayout) getLayout()).setCenterBehavior(com.codename1.ui.layouts.BorderLayout.CENTER_BEHAVIOR_CENTER_ABSOLUTE);
Media media = createMedia(currentExternalContent.getIs(), "video/m4v");
Component videoComponent = media.getVideoComponent();
Container videoContainer = new Container(new com.codename1.ui.layouts.BorderLayout());
videoContainer.addComponent(BorderLayout.CENTER, videoComponent);
addComponent(BorderLayout.CENTER, videoContainer);
revalidate();
media.play();
} catch (IOException ex) {
// Dialog.show("Catch", ex.getMessage(), "OK", "Cancel"); // gives 'read failed: EBADF (Bad file descriptor)'
}
}

Related

Playing Audio from a URL source

I am trying to play an audio file from a remote URL. The code works alright but the problem is when I tap on the play button, the app hangs for sometime before the audio plays. My code is shown below. How can I optimise this for a better experience.
if(!isDraft)
{
toPlay = URL+"/getFile/"+code+"_audioFile";
}
final Media mp = MediaManager.createMedia(toPlay, false);
f.addComponent("Center", new MediaPlayer(mp));
mp.play();
f.getToolbar().setBackCommand("", ed -> {
mp.pause();
mp.cleanup();
caseForm.showBack();

Codename One - Zoom, center and crop a video to force it to occupy all the screen

I have an intro video in the center of a BorderLayout with the option BorderLayout.CENTER_BEHAVIOR_TOTAL_BELOW. In the top I have a logo, in the south I have login buttons.
I write code similar to the following one, that chooses the right video according the rotation of the device. I tested that the video will be automatically zoomed to the available space: in the smartphones that I tested (Android and iPhone models), the video covers all the screen area (because the video length and height are proportional to the screen length and height). That's good, it's exactly what I want.
However, probably there are smartphones with different screen size ratio from the ones that I tested. Moreover, all the tablets have different screen size ratio from the smartphones.
I need that the video will ALWAYS occupy all the screen area. If necessary, it should be automatically zoomed, centered and cropped to occupy all the screen.
I didn't find in the Codename One API what I need to implement this use case. What code can I use? My target devices are Android and iOS devices (smartphones and tablets).
Example of code:
Form hi = new Form("Hi World", new BorderLayout(BorderLayout.CENTER_BEHAVIOR_TOTAL_BELOW));
disableToolbar(hi);
introVideoMP4 = "/intro-landscape.mp4";
if (Display.getInstance().isPortrait()) {
introVideoMP4 = "/intro-portrait.mp4";
}
MediaPlayer introVideo = new MediaPlayer();
try {
InputStream videoInputStream = Display.getInstance().getResourceAsStream(getClass(), introVideoMP4);
introVideo.setDataSource(videoInputStream, "video/mp4", () -> {
introVideo.getMedia().setTime(0);
introVideo.getMedia().play();
});
introVideo.setHideNativeVideoControls(true);
introVideo.hideControls();
introVideo.setAutoplay(true);
hi.add(BorderLayout.CENTER, introVideo);
} catch (Exception err) {
Log.e(err);
}
hi.addOrientationListener(l -> {
introVideoMP4 = "/intro-landscape.mp4";
if (Display.getInstance().isPortrait()) {
introVideoMP4 = "/intro-portrait.mp4";
}
try {
InputStream videoInputStream = Display.getInstance().getResourceAsStream(getClass(), introVideoMP4);
introVideo.setDataSource(videoInputStream, "video/mp4", () -> {
introVideo.getMedia().setTime(0);
introVideo.getMedia().play();
});
} catch (Exception err) {
Log.e(err);
}
});
hi.add(BorderLayout.NORTH, new Label("My App"));
Button myButton = new Button("Tap me!");
myButton.addActionListener(l -> {
Log.p("myButton tapped");
});
hi.add(BorderLayout.SOUTH, myButton);
hi.show();
Usually sites generate video downloads/streams based on the device proportions on the server (using tools such as ffmpeg. Then deliver a video with the right aspect ratio, bitrate & format.
There is no builtin functionality for cropping the video similar to "fit" scale in Codename One.
However, if you are OK with the sides or top being cropped then you can probably create your own layout manager for the video component and position/size it based on your knowledge of the video dimensions and screen dimensions. Creating a layout manager is really easy, it's mostly just the work of implementing the layoutContainer method where you can set the X/Y/Width/Height of the component. See https://www.codenameone.com/blog/map-layout-update.html

Video/3gpp in MediaPlayer on device

I am building a chat app. I am trying to add support for videos.
the URL for the video is https://api.twilio.com/2010-04-01/Accounts/AC5c869939f6863233a73ac697207c3697/Messages/MMf01fb40e39c41feafbc0967590f161e8/Media/MEbd3e3d9a0c2be95e01de341889e8cfbb
Container container = new Container(new BorderLayout());
Media video = com.codename1.media.MediaManager.createMedia(url, true); // url is the url above
video.setNativePlayerMode(true);
MediaPlayer mp = new MediaPlayer(video);
//place the media player in the container
container.add(BorderLayout.CENTER, mp);
Component component = Container.encloseIn(new FlowLayout(Container.RIGHT), container);
When I make a debug build and put this on my iPhone, I just get a black box where I would expect the video player to be.
In the simulator, I got playback controls, but no video either.
What am I doing incorrectly?
Something like this should work on the device although the simulator might be a bit flaky:
Form hi = new Form("Player", new BorderLayout());
try {
Media video = MediaManager.createMedia("https://api.twilio.com/2010-04-01/Accounts/AC5c869939f6863233a73ac697207c3697/Messages/MMf01fb40e39c41feafbc0967590f161e8/Media/MEbd3e3d9a0c2be95e01de341889e8cfbb", true);
hi.add(CENTER, video.getVideoComponent());
video.setNativePlayerMode(true);
hi.show();
hi.addShowListener(e -> video.play());
} catch(IOException err) {
Log.e(err);
hi.add(CENTER, "Failed to load video");
hi.show();
}
Notice a few things:
the simulator doesn't support HTTPS URL's for media due to limitations of JavaFX. It doesn't support some video stream types and might not support 3gp properly
iOS requires an HTTPS URL
I placed the video component in the center of the border layout in a form. This forces a specific size for the video which is important.
3gp is not supported. I convert the video to mp4 and supply the url to that file to the Media Manager and it works fine.

Streaming Live audio using Codename One

I am trying to convince a friend of mine to use CN1 as his dev platform for mobile apps. One of the challenges he has brought up is the ability to stream live audio from a radio station using a CN1 app.
I have had a look at the docs and I can see examples of loading media files that are already on the phone, but I cannot see an example of where you point it at a URL and stream live audio.
As you have probably guessed he is interested in developing radio apps for remote radio stations that don't already have their own
Is it possible to do this in CN1?
That's quite possible with CN1 and number of developers have done that in the past.
You can use MediaManager and point it to your remote streaming URL.
Below works for playing an audio file from remote URL and could work for streaming:
Form radio = new Form(new BorderLayout());
Display.getInstance().scheduleBackgroundTask(() -> {
try {
Media audio = MediaManager.createMedia(streamingUrl, false);
audio.prepare();
Display.getInstance().callSerially(() -> {
final MediaPlayer player = new MediaPlayer(audio);
player.setAutoplay(true);
audio.setNativePlayerMode(false);
radio.add(BorderLayout.CENTER, player);
radio.revalidate();
});
} catch (IOException err) {
Log.e(err);
ToastBar.showErrorMessage("Error streaming audio: " + err);
}
});
radio.show();
To avoid this error "Video Playing is not supported on this platform", you have to put true to isVidio parameter like this when handling video stream.
Media audio = MediaManager.createMedia(streamingUrl, true);

Video having problems on my phone in Codename One

I have created an app for video demonstration using Codename one. I'm Facing some challenges when I'm running the app on my Google Android Phone as it does not allow a full screen view and also after the video is done playing, it does not go back or restart the video again. Another problem was that I had a button at the bottom at the borderlayout and each time I click the button, it corrupts the video and the video won't play anymore. These are codes used for my demonstration app Demonstration App 1, Demonstration App2 .
#Override
protected void postMain1(Form f) {
final MediaPlayer mp = findMpPresent();
try {
InputStream is = Display.getInstance().getResourceAsStream(getClass(), "/sbuda.mp4");
if (is != null) {
mp.setDataSource(is, "video/mp4", null);
} else {
}
} catch (IOException ex) {
ex.getMessage();
}
}
This is a bit unclear since I can't see the stop/start etc with a GUI builder application.
You can use native on-device controls for playback using setFullScreen. Notice that this works nicely on the device but has no equivalent on the simulator.
Once playback is finished the media no longer exists as your input stream has been depleted. You will need to create a new Media object. You can use the completion callback (the Runnable argument) to detect the end of the media.

Resources