You are browsing the archive for Qt framework.

Necessitas: solution for lack of Camera support ( use JNI solution)

April 13, 2012 in C++, Java, JNI, NDK, Qt framework

In this article I will present my solution for using Camera in Necessitas (Qt on Android) projects. In current version of Necessitas (0.3.4) Camera is not supported. I was looking for existing solutions but the only one that I found in a patch for using MultimediaKit (proposed by dr. Juan Manuel Sáez) was related to old versions of Necessitas. I tried to use it but it seemes that old versions are now unstable (NecessitasQtCreator is crashing during building project).

I decided to use JNI to have an acces to Camera (with a little help of Java (-: ) in Qt Application.

I created two classes CameraSupport:

  1. in Java, to get every frame using Android API,
  2. in C++, to get frames from Java and retrieve them.

First class is really simple and doesn’t contains anything special (maybe using additionals buffers is something not typical). To build it we need Android SDK level 11 (or higher). If you prefer use lower levels of SDK, you can simply delete lines containingpreferredPreviewSize.

Second class is little bit more complicated, because:

  1. it’s using JNI to communicate with Java class,
  2. Android SDK is delivering frames in YUV format so I need to decode it to get RGB values,
  3. I’m using Samsung Galaxy Tab 10.1 with two-cores processor, so I wanted to take advantage of it by dividing calculations for converting YUV frame into RGB one using two threads.

I little explained how to communicate C++ and Java classses in previous article. In this article I will use my previous solution.

I was looking for long time an optimal way of decoding YUV image to RGB. I was using formulas which I found at Wikipedia (I chose bitwise version). To make it better I done all calculations before and I put results into arrays but still I was using clamping function. I found nice idea how to make it better in an article Optimizing YUV-RGB Color Space Conversion Using Intel’s SIMD Technology of Étienne Dupuis. He suggested removing clamping function and use instead of it predefined array with proper number of zeros at the beginning and 255s at the end. It was the end of my optimization. If anyone has idea how to make it better, please share it.

I guess the first time in my life I felt a need of threading something (yes, I’m quite young (-: ). The result of my work you can find in C++ class. I created it in this way to work with optimal number of threads. I discovered that because pre-emption one thread is doing its job much longer then other. I invented solution that don’t divide data into 2 exact size portions (in case of 2-cores procesors) but gives each thread smaller portions and if thread finished its job and there is still some data to retrieve, it takes next portion. Of course, I you have better solution or you found some error, please contact me. (-:

I won’t analyse here all my code, I just show you how to use it.

First, copy these files (you can find sources here) to your project (respectively to paths):

  1. PROJECT_NAME/android/src/pl/ekk/mkk/necessitas/CameraSupport.java
  2. PROJECT_NAME/camerasupport.cpp
  3. PROJECT_NAME/camerasupport.h
  4. PROJECT_NAME/JavaClassesLoader.cpp (if you don’t have it already)

Second, add existing files to your Necessitas project.

Third, place this code into your header file of MainWindow class (or other):

#include <QTimer>

class CameraSupport;

#define MILISECONDS_FOR_REFRESH 1
#define WIDTH 640
#define HEIGHT 480

In my case, I use frames with resolution 640 x 480. On my tablet it works with 30 FPS. If you want have another resolution, just change above values. You can find in Application Output in moment of Camera initialization a line like this:

V/CAMERA SUPPORT(30977): Preferred preview size - 1024x768

which says what is preferred size of a frame (remember that you need Android SDK 11 or higher to get this information).

In private section add this code:

    QTimer *timer;
    QImage *frame;

    CameraSupport *cameraSupport;
    bool repaint;

    unsigned int totalFrames;
    unsigned long long *frameTime;
    unsigned int currentFrame;
    unsigned int fps;

    unsigned long long frameCounter;
    clock_t time1, time2;

First, we need QTimer to get frames with a proper frequency. Of course in case of big frames, time of retrieving is so long that time between getting new one can be really small. But still, in case of small images it’s good to set this time longer.

Second, we need QImage to use data frame in Qt application. If you prefer other image containters, if they support loading data from RGBA array, you can use it as well.

Third, we need CameraSupport object to ask it about new frames and if there is one to get it.

To avoid painting the same frame I use repaint flag.

Below repaint variable you can find some diagnostic variables to calculate FPS, count time of execution of parts of code etc.

Now, let’s add into protected section:

    void paintEvent (QPaintEvent *event);

We will use this method for displaying frames.

The last thing that you need to add into your header file is a slot for QTimer:

private slots:
    void updateFrame();

Now, let’s modify cpp file. In place where you want to start using your camera (in my case in constructor) put this code:

    timer = new QTimer (this);
    connect (timer, SIGNAL (timeout ()), this, SLOT (updateFrame ()));
    timer -> start (MILISECONDS_FOR_REFRESH);

    frame = 0;

    cameraSupport = new CameraSupport (WIDTH, HEIGHT);

    repaint = false;

    totalFrames = 1000 / MILISECONDS_FOR_REFRESH;
    frameTime = new unsigned long long[totalFrames];
    for (unsigned int i = 0; i < totalFrames; i++)
        frameTime[i] = 0;
    currentFrame = 0;
    fps = 0;

    frameCounter = 0;
    time1 = time2 = 0;

I guess, this code is quite clear, there is nothing special to explain. So now, let’s define updateFrame () slot:

void MainWindow::updateFrame (){
    clock_t start = clock ();
    bool result = cameraSupport -> UpdateFrame ();
    clock_t stop = clock ();

    if (result){
        if (frame != 0){
            delete frame;
            frame = 0;
        }
        frame = new QImage ((unsigned char *)cameraSupport -> GetRGBA (), WIDTH, HEIGHT, QImage::Format_ARGB32_Premultiplied);
        repaint = true;

        time1 += stop - start;
        update (0, 0, WIDTH, HEIGHT);

        frameTime[currentFrame] = clock();

        fps++;
        while (frameTime[currentFrame] - frameTime[(currentFrame - fps) % totalFrames] > CLOCKS_PER_SEC)
            fps--;

        if (currentFrame < totalFrames - 1)
            currentFrame++;
        else
            currentFrame = 0;
    }
}

Method UpdateFrame () from CameraSupport class returns true if new frame was loaded or false otherwise. To create QImage with new frame we just use method GetRGBA () from CameraSupport class. Notice that I use formatQImage::Format_ARGB32_Premultiplied for my QImage. In my case, I display frames on a screen by using QPainter. Format that I chose makes some QPainter operations faster than QImage::Format_ARGB32.

Now, let’s define painterEvent (.):

void MainWindow::paintEvent (QPaintEvent *event){
    if (!repaint)
        return;
    repaint = false;

    if (frame){
        time2 -= clock ();
        QPoint topLeft = event -> rect ().topLeft ();

        QPainter displayPainter (this);
        displayPainter.drawImage (topLeft, *frame);

        time2 += clock ();

        frameCounter++;
        qDebug () << frameCounter << ": " << time1 / frameCounter << ", " << time2 / frameCounter << ". FPS: " << fps ;
    }
}

We must remember about cleaning up memory that we allocated! In case of my project, you can find in the destructor these lines:

    delete cameraSupport;

    if (frame != 0)
        delete frame;
    frame = 0;

    delete []frameTime;

If you are using JavaClassLoader function from my previous article add these lines:

    {
        const char* className = "pl/ekk/mkk/necessitas/CameraSupport";
        jclass clazz = env -> FindClass (className);
        if (!clazz){
            __android_log_print (ANDROID_LOG_FATAL,"Qt", "Unable to find class '%s'", className);
            return JNI_FALSE;
        }
        jmethodID constr = env -> GetMethodID(clazz, "<init>", "()V");
        if (!constr){
            __android_log_print (ANDROID_LOG_FATAL,"Qt", "Unable to find constructor for class '%s'", className);
            return JNI_FALSE;
        }
        jobject obj = env -> NewObject (clazz, constr);
        cameraSupportClassPointer = env->NewGlobalRef(obj);
    }

Also, add outside the function this line:

jobject cameraSupportClassPointer;

Variable’s name is important because it’s used in CameraSupport class. If you are using another solution to load Java classes, remember to create this object.

Now, your project should work with Camera on Android! But there is still something to do. You can notice that paiting QImage takes lot of time. To make it faster we can take advantage of hardware acceleration by using OpenGL. Simply add to your *.pro file this line:

QT_GRAPHICSSYSTEM = opengl

And that’s all!.

Now, the question is: is it possible to make it better? I guess it is!

First thing which I would change is a way of displaying frames. This inconspicious operation takes a lot of time. I found an article: How to get faster Qt painting on N810 right now which could be helpful for you.

Another idea is to use own version of QPaintEngine. Some clues could be found here: QGLWidget and hardware acceleration?.

I guess that there is not much things that can be done with YUV to RGB conversion. Maybe there exists better algorithm which do less read/write memory operations. I was thinking about setting two pixels in one time (by using unsigned long long int* instead of unsigned int*) but it will be better only in case of 64 bits architectures. You can always write some part of your code in assembler. If you want to look for more thriftiness you can try to find better solution for getting YUV data from Java.

The last night I found some technology which I never used before - OpenCL. Maybe this could be also useful for decreasing time of conversion YUV to RGB or for displaying frame on a screen? Anyone has some experience with this?

The last but not least – quality. If you want better quality of video frames (after conversion YUV to RGB), consider recalculating precalculated arrays. It is really important to notice that lot of algorithms requires that Y will be in range of <16, 235> and U, V will be in range of <16, 240> (YUV / YCbCr color componet data ranges) while what you really get is <0, 255> for all components.  You can read more here: About YUV VIDEO.

If you has some ideas, found some errors or just found this article interesting, please share with me your opinion.

Necessitas Qt for Android x86

April 5, 2012 in Android X86, Qt framework

I am attempting to port an Android Qt (Necessitas) app to x86.  I
figure all I have to do is to build QT from source using the x86
flag.  However, it was not nearly so simple.  After some research, I
found a way to get the build working.  However, it still seems like
something is wrong.  If anyone else here has had success building QT
for x86 and deploying an app, I’d like to solicit your feedback on my
procedure below:

1) git clone git://anongit.kde.org/android-qt.git
# Is this the right repo?  I notice it doesn’t have qt-mobility or qt-
webkit.

2) Remove the following lines from: mkspecs/android-g++/qmake.conf and
mkspecs/features/qt.prf
contains(NDK_ROOT, “.*r6″)|contains(NDK_ROOT, “.*r5.*”)|
contains(NDK_ROOT, “.*r5″) {
!contains(ANDROID_PLATFORM, android-4): !
contains(ANDROID_PLATFORM, android-5): !contains(ANDROID_PLATFORM,
android-8) {
message(“Your NDK-version is out-dated. A work-around is
enabled. Consider updating your NDK (workarounds are required until
r6(a))”)
QMAKE_LFLAGS_SHLIB += $$ANDROID_PLATFORM_PATH/lib/
crtbegin_so.o $$ANDROID_PLATFORM_PATH/lib/crtend_so.o
}
}

3) Edit android/androidconfigbuild.sh
NDK_ROOT=~/necessitas/android-ndk-r6b
NDK_PLATFORM=9
NDK_TOOLCHAIN_PREFIX=”x86″
NDK_TOOLS_PREFIX=”i686-android-linux”
TARGET_ARCH=”x86″
ANDROID_ARCHITECTURE=”x86″

4) ./androidconfigbuild.sh -q 1 -h 0
# -q 1 is for configure/compile
# -h 0 is for static version

5) Wait for the build to finish

6) Copy to ~/necessitas/Android/Qt/480/x86

7) In Qt Creator, Open Project

8) Go to Projects | Build Settings | General | Manage Qt version

9) Add ~/necessitas/Android/Qt/480/x86
#Observe the following error: Qt version is not properly installed,
please run make install

QT Creator version information
Qt Creator 2.3.1
Based on Qt 4.7.4 (32 bit)
Built on Oct 16 2011 at 16:03:12

Thanks for helping me out and I hope this information is useful for
anyone else attempting to do the same

UPDATE

Found the problem.  Forgot to the set install flag (-k 1) in #4 when
executing the build script:

android/androidconfigbuild.sh -q 1 -h 1 -k 1 -i ~/necessitas/Android/
Qt/480/x86

Setting -i <DEST_DIR> also eliminates the need for step 6.

Android look & feel for Qt

March 27, 2012 in Qt framework

Hello folks,

I’d like to share with you current Android look&feel for Qt, because
the images say more than a thousands words, I upload a short movie
here: http://youtu.be/2X8R3lZc4EI .

YouTube Preview Image

How it works now, and how it will work in the end:
Now I create an android application to extract the same look&feel
informations into a json file (these infos are the same infos used by
android to draw the controls). The extraction takes some time  (5-10
seconds), so in the end this code will be integrate within Ministro,
which will extract ONLY ONCE these infos into a central read only
location and it will pass the location path to your application
android platform plugin.
I created a qt style plugin which parse the json file and extract the
need infos to draw the Qt controls, as you may seen they look the same
as android ones! The parsing is fast 50-100ms. In the end the style
plugin will be integrated into android platform plugin and it will be
the default style plugin for android.

The style plugin is *NOT* finished yet, only a few controls are
supported, is a very slow and painful process to add a control. First
you have to check how Android draws the control, extract the needed
information, store it into the json file, then use it to paint the
controls. I hope in a few days to cleanup the code, and to push it
into a new branch (“style-plugin”). If anyone wants to help, just send
me a mail.

I hope this plugin will be used also by QML components to draw the
controls, this way Qt applications will look&feel the same as any
ordinary Android apps, no matter if they are made using QML controls
or classic QtWidgets.

Thank you for your time !

Full thread on android-qt group

Calligra Office on Android

March 27, 2012 in News, Qt framework

As most of you are probably well aware, since quite a while it is not very hard to write Qt applications to run on Android devices. A couple of weeks ago we at KO GmbH decided to look into how hard it would be to get KDE applications to run, and more specifically, if it would be possible to run Calligra with one of its mobile UI’s on an android device.

So after some (sometimes frustrating) hacking, I’ve got the first results: Calligra Mobile running on an android tablet. There are still lots of rough edges, and not everything works correctly, but as you can see in these screenshots, it does actually run and work. To get to this point I had to make some rather ugly hacks though to work around some of the android limitations.

Qt Android (Necessitas) soft-keys control volume

March 1, 2012 in C++, Programming, Qt framework, Tutorials

To control application volume from Necessitas the following changes are required into QtActivity.java file

import android.media.AudioManager;

public class QtActivity extends Activity
{
private AudioManager audio;
……..
}

and add into public boolean onKeyDown(int keyCode, KeyEvent event) following code:

public boolean onKeyDown(int keyCode, KeyEvent event)
{
switch (keyCode)
{
case KeyEvent.KEYCODE_VOLUME_UP:
audio.adjustStreamVolume(AudioManager.STREAM_MUSIC, AudioManager.ADJUST_RAISE, AudioManager.FLAG_SHOW_UI);
return true;

case KeyEvent.KEYCODE_VOLUME_DOWN:
audio.adjustStreamVolume(AudioManager.STREAM_MUSIC, AudioManager.ADJUST_LOWER, AudioManager.FLAG_SHOW_UI);
return true;
}

…………
}

Source: here

How to use Java from Qt/C++ in Necessitas

March 1, 2012 in C++, Java, Qt framework, Tutorials

This steps are valid for Necessitas Alpha 3 Update 4
Add your java class inside org.kde.necessitas.origo (i will refer in this article as JavaManager.Java)
Edit qtmain_android.cpp

Replace

static JavaVM *m_javaVM = NULL;
static JNIEnv *m_env = NULL;
static jobject objptr;

with

JavaVM *m_javaVM = NULL;
static JNIEnv *m_env = NULL;
jobject objptr;

//new pointer to my Java class
jobject customClassPtr;

//my class
static const char * const customClass = “org/kde/necessitas/origo/JavaManager”;

Add next lines to your file

static int registerNativeMethodsCustom(JNIEnv* env, const char* className, JNINativeMethod* gMethods, int numMethods)
{
jclass clazz=env->FindClass(className);
if (clazz == NULL)
{
__android_log_print(ANDROID_LOG_FATAL,”Qt”, “Custom Native registration unable to find class ‘%s’”, className);
return JNI_FALSE;
}

jmethodID constr = env->GetMethodID(clazz, “”, “()V”);
if(!constr) {
__android_log_print(ANDROID_LOG_FATAL,”Qt”, “Custom Native registration unable to find constructor for class ‘%s’”, className);
return JNI_FALSE;
}

jobject obj = env->NewObject(clazz, constr);
customClassPtr = env->NewGlobalRef(obj);
// if (env->RegisterNatives(clazz, gMethods, numMethods) < 0)
// {
// __android_log_print(ANDROID_LOG_FATAL,”Qt”, “Custom RegisterNatives failed for ‘%s’”, className);
// return JNI_FALSE;
// }
return JNI_TRUE;
}

static int registerNativesCustom(JNIEnv* env)
{
if (!registerNativeMethodsCustom(env, customClass, methods, sizeof(methods) / sizeof(methods[0])))
return JNI_FALSE;
return JNI_TRUE;
}

Add next lines to Q_DECL_EXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* /*reserved*/)

if (!registerNativesCustom(m_env))
{
__android_log_print(ANDROID_LOG_FATAL, “Qt”, “Custom registerNatives failed”);
return -1;
}

Prepare and call your java class from your file. Prepare your C++ class adding next lines:

extern JavaVM *m_javaVM;
extern jobject objptr;
extern jobject customClassPtr;

Now, in your method call the Java method:

JNIEnv* env;
if (m_javaVM->AttachCurrentThread(&env, NULL)<0)
{
qCritical()<    return;
}

jclass applicationClass = env->GetObjectClass(customClassPtr);

qDebug()<
if (applicationClass) {
jmethodID playMediaFileMethodID = env->GetMethodID(applicationClass,”playMediaFile”, “(Ljava/lang/String;)V”);
jstring path = env->NewStringUTF(“my song”);
env->CallStaticVoidMethod(applicationClass, playMediaFileMethodID, path);
}

m_javaVM->DetachCurrentThread();

WARNING
1. The qtmain_android.cpp cand be changed by any Necessitas updates
2. You must change the qtmain_android.coo in both armabi and armabi-v7a
3. Any suggestions and/or questions are welcome.

Source: here.

Necessitas alpha 3 update 4 #android #qt

February 23, 2012 in Android X86, C++, JNI, NDK, News, OpenGL, Qt framework, Uncategorized

This release brings the followings fixes:

Qt Framework:
- As I already said, thanks to Marijn Kruisselbrink java part is fixed !
- Fix Black screen thanks goes to Chris Browet
- I fixed software keyboard forces caps on

Qt Creator:
- it will automatically update your java files !
- fix signing packages.

SDK:
- windows & mac build kindly provided by Ray Donnelly

Cheers,
BogDan.

 

ED: one cool stuff is that now android x86 is supported if you look on TODO list

Also you can consult what is DONE in the alpha3

Necessitas alpha 3 update 2

December 13, 2011 in Android X86, Applications, C++, Frameworks, News, Qt framework

Hello folks,

I’m honored to announce the second update of Necessitas alpha 3 release [1].
This release brings a new keyboard implementation which I announce it early this month [2]. As I said before there are a few small things which are still missing (I’d like to mention the selection which is not the best in town), but, overall I can say that all Qt users will enjoy a first class experience when it comes to input support. Also I tied to make it a little bit smarter:

  • If the input widget is bigger than 2/3 of the screen size your window will be resized.
  • Else the window will be moved in order to ensure widget visibility.

Yours sincerely,
BogDan.

[1] http://groups.google.com/group/android-qt/browse_thread/thread/1d729d895b0379ed
[2] http://groups.google.com/group/android-qt/browse_thread/thread/3be1cba871e7e51c

[Ed:The sdk files from sourceforge are the same  for example i have downloaded for linux and ran  ./necessitas-0.3-online-sdk-installer-linux and it will download the new release ,If you have the sdk already installed you should upgrade from the menu Help-Start-Updater ]

Android Development liked this post

Hedgeroid update!

November 26, 2011 in C++, Games, JNI, NDK, Qt framework

[ED: interesting concept for a game Frontend in qt C++ , engine in pascal and lua

you can check the code here ]

Hello,

today a new version of Hedgewars for Android hit the Market!

https://market.android.com/details?id=org.hedgewars.hedgeroid

For users who are updating: please download the additional package again. (Hit download and click on Full data Package)

The last version had a lot of crashes while in the game, the reason for this was because we used 22khz sounds, and sdl didn’t go well with that, I’m still trying to find out exactly why. To prevent the game from crashing that ofter I’ve gone back and used 44khz.

I’ve also changed the way you can download new content, right now only two packages are on there but there might be more soon enough :)

Plus there were some tweaks in the UI mostly hardly noticable.

Xeli

PySide for Android (using Necessitas)

July 9, 2011 in Qt framework, Uncategorized

I’ve been working on getting PySide (LGPL’d Python bindings to Qt, see http://pyside.org/) to work on Android this week, using the Py4A project and Necessitas. I’ve collected the results on this page:
http://thp.io/2011/pyside-android/

PySide for Android lets you write Qt or QML UIs for Android – all in pure Python. The projects on which PySide for Android builds upon are:

pyside android

Some remarks/problems that I ran into:

  • Qt Creator does not allow me to put libraries into libs.xml – they get overwritten (and deleted) when building the project (I’ve manually fixed this by editing libs.xml by hand and copying the shared libraries in there after having built the project, and then rebuilding the APK without Qt Creator using “ant install” in the “android/” folder of my project)
  • The libraries downloaded by Ministro are different from the libraries in the Necessitas SDK (the dynamic linker in the emulator had problems that were fixed when I overwrote the Ministro libraries with the (stripped) libraries from the Necessitas SDK) – is this a known problem and will it be fixed?
  • If the library downloads in Ministro are interrupted/incomplete for some reason, it will act as if the library was downloaded (but applications trying to use the libraries will fail) – manually deleting the affected incomplete files fixes the problem and causes Ministro to redownload the files
  • QtGui on Android does not support QSound (at least I had problems when building PySide) – is this a known problem?
  • Also QtOpenGL does not seem to be properly supported – is this being worked on, or is this out of scope?

Looking forward to your feedback and suggestions. I’d also be happy to hear your opinion about the current way of packaging, and if it could be made easier, etc..

Thomas Perl announced it on android-qt group