Welcome!

Welcome to the official BlackBerry Support Community Forums.

This is your resource to discuss support topics with your peers, and learn from each other.

inside custom component

Native Development

Reply
Contributor
Posts: 34
Registered: ‎10-08-2012
My Device: developer
My Carrier: ??

Open playbook camera in Qt project

Hello,

 

I have been trying to create a form in Qt with a button that has to open the camera.

But for some reason it is not working.

 

I tried to do this by making a class which is basically a copy of the nativecamera app.

When I copy the native app directly it works without a problem.

But when I make a class of it and call that class from the main class it shows the view but it crashes as soon as I try to take a picture.

And when I call the same method pushing a button it doesn't show the view at all but my app just freezes.

 

Is there anyone who has tried to do something similar and can help me?

Or someone who knows what might be wrong with my approach?

New Developer
Posts: 88
Registered: ‎06-16-2012
My Device: N950/E7/N808/N9/X7/BB10 Alpha
My Carrier: Kievstar

Re: Open playbook camera in Qt project

probably it makes sense to post some code here otherwise its hard to say something

Qt/Symbian/Meego/BB10/Cascades developer
Contributor
Posts: 34
Registered: ‎10-08-2012
My Device: developer
My Carrier: ??

Re: Open playbook camera in Qt project

as my code is basicly a copy of nativecamera app(see: https://github.com/blackberry/Cascades-Community-Samples/blob/master/NativeCamera/src/main.c) i didn't think it would add much of value.

 

but this is the code I use to start the camera(classname = cameraStart)

#include <assert.h>
#include <bps/bps.h>
#include <bps/event.h>
#include <bps/navigator.h>
#include <bps/screen.h>
#include <fcntl.h>
#include <screen/screen.h>
#include <camera/camera_api.h>
#include <bps/soundplayer.h>
#include "camerastart.h"

typedef enum {
    STATE_STARTUP = 0,
    STATE_VIEWFINDER,
    STATE_TAKINGPHOTO
} state_t;


static bool shutdown = false;
static screen_context_t screen_ctx;
static screen_window_t vf_win = NULL;
static const char vf_group[] = "viewfinder_window_group";
static state_t state = STATE_STARTUP;
static camera_handle_t handle = CAMERA_HANDLE_INVALID;
static bool shouldmirror = false;
static bool touch = false;
static int photo_done_domain = -1;
static int main_bps_chid = -1;

cameraStart::cameraStart()
{
}

void cameraStart::start()
{
    const int usage = SCREEN_USAGE_NATIVE;

    screen_window_t screen_win;
    screen_buffer_t screen_buf = NULL;
    int rect[4] = { 0, 0, 0, 0 };

    // create an application window which will just act as a background
    screen_create_context(&screen_ctx, 0);
    screen_create_window(&screen_win, screen_ctx);
    screen_create_window_group(screen_win, vf_group);
    screen_set_window_property_iv(screen_win, SCREEN_PROPERTY_USAGE, &usage);
    screen_create_window_buffers(screen_win, 1);
    screen_get_window_property_pv(screen_win, SCREEN_PROPERTY_RENDER_BUFFERS, (void **)&screen_buf);
    screen_get_window_property_iv(screen_win, SCREEN_PROPERTY_BUFFER_SIZE, rect+2);

    // fill the window with black
    int attribs[] = { SCREEN_BLIT_COLOR, 0x00000000, SCREEN_BLIT_END };
    screen_fill(screen_ctx, screen_buf, attribs);
    screen_post_window(screen_win, screen_buf, 1, rect, 0);

    // Signal bps library that navigator and screen events will be requested
    bps_initialize();
    main_bps_chid = bps_channel_get_active();
    screen_request_events(screen_ctx);
    navigator_request_events(0);

    // create a custom BPS event that we can use in to let our main thread know
    // that photo-taking is finished
    photo_done_domain = bps_register_domain();

    // open camera and configure viewfinder
    if (init_camera(CAMERA_UNIT_REAR) == EOK) {
        // our main loop just runs a state machine and handles input
        while (!shutdown) {
            run_state_machine();
            // Handle user input
            handle_event();
        }

        if (state == STATE_TAKINGPHOTO) {
            // wait for picture-taking to finish? TBD
            state = STATE_VIEWFINDER;
        }
        if (state == STATE_VIEWFINDER) {
            // clean up camera
            camera_stop_photo_viewfinder(handle);
            camera_close(handle);
        }
    }

    // Clean up
    screen_stop_events(screen_ctx);
    bps_shutdown();
    screen_destroy_window(screen_win);
    screen_destroy_context(screen_ctx);
}

void cameraStart::handle_screen_event(bps_event_t *event)
{
    int screen_val;
    screen_event_t screen_event = screen_event_get_event(event);
    screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_TYPE, &screen_val);

    switch (screen_val) {
    case SCREEN_EVENT_MTOUCH_TOUCH:
        touch = true;
        break;
    case SCREEN_EVENT_MTOUCH_MOVE:
        break;
    case SCREEN_EVENT_MTOUCH_RELEASE:
        break;
    case SCREEN_EVENT_CREATE:
        if (screen_get_event_property_pv(screen_event, SCREEN_PROPERTY_WINDOW, (void **)&vf_win) == -1) {
            perror("screen_get_event_property_pv(SCREEN_PROPERTY_WINDOW)");
        } else {
            // mirror viewfinder if this is the front-facing camera
            int i = (shouldmirror?1:0);
            screen_set_window_property_iv(vf_win, SCREEN_PROPERTY_MIRROR, &i);
            // place viewfinder in front of the black application background window
            // child window z-orders are relative to their parent, not absolute.
            i = +1;
            screen_set_window_property_iv(vf_win, SCREEN_PROPERTY_ZORDER, &i);
            // make viewfinder window visible
            i = 1;
            screen_set_window_property_iv(vf_win, SCREEN_PROPERTY_VISIBLE, &i);
            screen_flush_context(screen_ctx, 0);
            // we should now have a visible viewfinder
            touch = false;
            state = STATE_VIEWFINDER;
        }
        break;
    default:
        break;
    }
}


void cameraStart::handle_navigator_event(bps_event_t *event) {
    switch (bps_event_get_code(event)) {
    case NAVIGATOR_SWIPE_DOWN:
        break;
    case NAVIGATOR_EXIT:
        shutdown = true;
        break;
    default:
        break;
    }
}


void cameraStart::handle_photo_done_event(bps_event_t *event) {
    // re-arm the viewfinder state
    touch = false;
    state = STATE_VIEWFINDER;
}


void cameraStart::handle_event()
{
    int rc, domain;

    bps_event_t *event = NULL;
    rc = bps_get_event(&event, -1);
    assert(rc == BPS_SUCCESS);
    if (event) {
        domain = bps_event_get_domain(event);
        if (domain == navigator_get_domain()) {
            handle_navigator_event(event);
        } else if (domain == screen_get_domain()) {
            handle_screen_event(event);
        } else if (domain == photo_done_domain) {
            handle_photo_done_event(event);
        }
    }
}


void cameraStart::shutter_callback(camera_handle_t handle, void* arg)
{
    // THE CAMERA SERVICE DOES NOT PLAY SOUNDS WHEN PICTURES ARE TAKEN OR
    // VIDEOS ARE RECORDED. IT IS THE APP DEVELOPER'S RESPONSIBILITY TO
    // PLAY AN AUDIBLE SHUTTER SOUND WHEN A PICTURE IS TAKEN AND WHEN VIDEO
    // RECORDING STARTS AND STOPS. NOTE THAT WHILE YOU MAY CHOOSE TO MUTE
    // SUCH SOUNDS, YOU MUST ENSURE THAT YOUR APP ADHERES TO ALL LOCAL LAWS
    // OF REGIONS WHERE IT IS DISTRIBUTED. FOR EXAMPLE, IT IS ILLEGAL TO
    // MUTE OR MODIFY THE SHUTTER SOUND OF A CAMERA APPLICATION IN JAPAN OR
    // KOREA.
    // TBD:
    // RIM will be providing clarification of this policy as part of the
    // NDK developer agreement and App World guidelines. A link will
    // be provided when the policy is publicly available.
    fprintf(stderr, "sound");
    soundplayer_play_sound("event_camera_shutter");
}


void cameraStart::still_callback(camera_handle_t handle,
               camera_buffer_t* buf,
               void* arg)
{
    if (buf->frametype == CAMERA_FRAMETYPE_JPEG) {
        fprintf(stderr, "start callback");
        int fd;
        char filename[CAMERA_ROLL_NAMELEN];
        if (camera_roll_open_photo(handle,
                                   &fd,
                                   filename,
                                   sizeof(filename),
                                   CAMERA_ROLL_PHOTO_FMT_JPG) == CAMERA_EOK) {
            int index = 0;
            while(index < (int)buf->framedesc.jpeg.bufsize) {
                int rc = write(fd, &buf->framebuf[index], buf->framedesc.jpeg.bufsize-index);
                if (rc > 0) {
                    index += rc;
                } else if (rc == -1) {
                    if ((errno == EAGAIN) || (errno == EINTR)) continue;
                    perror("write");
                    break;
                }
            }
            close(fd);
        }
    }
    // picture-taking is done, so wake up the main thread again via bps.
    // note that we are using the void* arg here as the bps channel to deliver
    // the event on. this is just to demonstrate data passing between
    // camera_take_photo() and the various callback functions.
    bps_event_t* photo_done_event;
    bps_event_create(&photo_done_event, photo_done_domain, 0, NULL, NULL);
    bps_channel_push_event((int)arg, photo_done_event);
}


void cameraStart::run_state_machine()
{
    camera_error_t err;
    // this simple state machine just runs us through starting a viewfinder and taking pictures
    switch(state) {
    case STATE_STARTUP:
        // waiting for viewfinder...
        break;
    case STATE_VIEWFINDER:
        // viewfinder is visible.
        // if the user touches the screen anywhere, take a picture.
        // note, we are passing main_bps_chid as the void* arg which will then
        // be delivered to all callbacks. main_bps_chid is already a global variable,
        // so this isn't necessary, but is just done here to illustrate the convention.
        if (touch) {
            touch = false;
            fprintf(stderr, "try taking photo\n");
            err = camera_take_photo(handle,
                                    (void(*)(camera_handle_t,void*))&cameraStart::shutter_callback,
                                    NULL,
                                    NULL,
                                    (void(*)(camera_handle_t, camera_buffer_t*,void*))&cameraStart::still_callback,
                                    (void*)main_bps_chid,
                                    false);
            fprintf(stderr, "done taking photo\n");
            if (err != CAMERA_EOK) {
                fprintf(stderr, "taking photo failed\n");
            } else {
                fprintf(stderr, "taking photo succesfull\n");
                state = STATE_TAKINGPHOTO;
            }
        }
        break;
    default:
        break;
    }
}


int cameraStart::init_camera(camera_unit_t unit)
{
    camera_error_t err;
    // open the specified camera
    err = camera_open(unit,
                      CAMERA_MODE_RW | CAMERA_MODE_ROLL,
                      &handle);
    if (err != CAMERA_EOK) {
        return err;
    }
    err = camera_set_photovf_property(handle,
                                      CAMERA_IMGPROP_WIN_GROUPID, vf_group,
                                      CAMERA_IMGPROP_WIN_ID, "my_viewfinder");
    if (err != CAMERA_EOK) {
    } else {
        err = camera_start_photo_viewfinder(handle,
                                            NULL,
                                            NULL,
                                            NULL);
        if (err != CAMERA_EOK) {
        } else {
            // successfully started viewfinder
            // if it's a front-facing camera, we should mirror the viewfinder once
            // we receive it.
            if (unit == CAMERA_UNIT_FRONT) {
                shouldmirror = true;
            }
            return 0;
        }
    }
    // clean up on error
    camera_close(handle);
    handle = CAMERA_HANDLE_INVALID;
    return err;
}

 and then i call this from the main using the following code:

int main(int argc, char *argv[])
{
    cameraStart *cam = new cameraStart();
    cam->start();
    return 7734;
}

 

Developer
Posts: 1,068
Registered: ‎11-24-2011
My Device: PlayBook
My Carrier: x

Re: Open playbook camera in Qt project

Where is Qt code here?

Developer
Posts: 671
Registered: ‎03-21-2012
My Device: BlackBerry PlayBook 16GB
My Carrier: Vip

Re: Open playbook camera in Qt project

Hmmm, first explain us what you're truing to achieve.
Contributor
Posts: 34
Registered: ‎10-08-2012
My Device: developer
My Carrier: ??

Re: Open playbook camera in Qt project

there is no Qt code here yet because i first want to be able to make this work before I try to connect it to a button.

 

and i am trying to create a camera that starts when i push a button.

but at the moment it stops working when i toutch the screen to take a photo.

Developer
Posts: 671
Registered: ‎03-21-2012
My Device: BlackBerry PlayBook 16GB
My Carrier: Vip

Re: Open playbook camera in Qt project

You're using cascades camera api on playbook. I don't know if that will work. Try to use playbook Native camera sample.
Contributor
Posts: 34
Registered: ‎10-08-2012
My Device: developer
My Carrier: ??

Re: Open playbook camera in Qt project

if i just follow the example and put it in the main class it works fine.

 

but if you could point me to the playbook camera example that would be great.

BlackBerry Development Advisor
Posts: 683
Registered: ‎11-29-2011
My Device: PRIV
My Carrier: Rogers

Re: Open playbook camera in Qt project

[ Edited ]

borceg wrote:
You're using cascades camera api on playbook. I don't know if that will work. Try to use playbook Native camera sample.

no, his code looks like the Native C camera sample.  it's unfortunately published in Cascades-Community-Samples, but only because there is currently no equivalent Native-Community-Samples repository.

 

As to why it's not working in Qt, I can't really speculate, as I don't have a Qt environment set up.  Off the top of my head though, I would suspect that it's probably due to one of these:

1. you are creating an application window using screen_create_window() when Qt probably already has an application window.  I don't think Navigator will like this, as there is only supposed to be one application window per app.

2. screen_request_events() and associated code.  The native sample is written with the assumption that it is the sole consumer of screen and bps events.  I suspect Qt is already consuming some of these events for you, so you likely have a race on your hands.

 

are all of your methods static?  When dealing with callbacks in C++, it's usually convention to pass a "this" pointer around as the void* argument so that you can find your class instance again, etc.

 

In short, this sample was written with the assumption that no other framework is present, so it will need some modification to co-exist with the Qt framework.  If Qt provides signals for native screen events, then you will probably want to hook into those instead.  The only real difference between the C camera examle (NativeCamera) and the Cascades camera sample (HelloCamera) is how you acquire a window handle for the created viewfinder.  Both samples create the viewfinder as a child in the application window's window group - in C, this group is expliclty known, but in Cascades, we have to query this info from the ForeignWindowControl, which gets it from the global Cascades UI window.  And both samples ultimately get a screen_window_t returned via some mechanism -- in C, this is via waiting for SCREEN_EVENT_CREATE, and in Cascades, this event is handled by the framework and is then emitted as a signal from the ForeignWindowControl.  You will have to determine what is the appropriate way to perform these 2 operations in plain old Qt.  After that, the rest is framework-agnostic.

 

Cheers,

Sean

Contributor
Posts: 34
Registered: ‎10-08-2012
My Device: developer
My Carrier: ??

Re: Open playbook camera in Qt project

so if i understand this correctly all i have to do is find a way to replace the black backgroundwindow with my Qt window and link everything to that one?

 

only one thing i still don't understand:

why does it work if it is a main class, but not if it is in a separate class which i call directly from the main?(like in the code i posted)

everytime i start it that way it will open the viewfinder(asuming that is the screen that lets me see what the camera is pointed at) but as soon as i tap the schreen to take a picture it will crash.