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
nirhor_roy
Posts: 23
Registered: ‎05-29-2012
My Device: Blackberry Playbook Os 2.0
My Carrier: Robi Axiata Limited
Accepted Solution

Video Recording on Playbook

Prior to the 2.1 beta sdk we did not have any access to camera. Thanks God that is history now. The new camera api has got a lot of functions I admit. However, as I was trying to record video I ran into some problem.

 

1. The camera_start_video function takes a filename as its parameter. Do it write the frames to the file by itself? Or we have to manually write them to file?

2. How to set the image format while recording videos?

3. When I am recording I am getting NV12 frames. How to know what is their size?

4. How to seperate audio data from corresponding video data or how can I capture audio separately?

 

I have written a code that opens the viewfinder and records video. It writes to the file but not in the correct format. As a result file can't be played.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

#include "VideoRecorder.h"

VideoRecorder::VideoRecorder() {
// TODO Auto-generated constructor stub
shutdown = false;
vf_win = NULL;
state = STATE_STARTUP;
handle = CAMERA_HANDLE_INVALID;
shouldmirror = false;
touch = false;
photo_done_domain = -1;
main_bps_chid = -1;
usage = SCREEN_USAGE_NATIVE;
screen_buf = NULL;
rect = { 0, 0, 0, 0 };
//filename = "shared/videos/test.mp4";

 

// 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, "GroupID");
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);
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);
i = APP_ZORDER;
screen_set_window_property_iv(screen_win, SCREEN_PROPERTY_ZORDER, &i);


bps_initialize();
main_bps_chid = bps_channel_get_active();
screen_request_events(screen_ctx);
navigator_request_events(0);

 

// open camera and configure viewfinder
if (init_camera(CAMERA_UNIT_FRONT) == EOK)
{
camera_error_t error = camera_roll_open_video(handle, &fd,filename,sizeof(filename),CAMERA_ROLL_VIDEO_FMT_MP4);

if(error != CAMERA_EOK)
{
fprintf(stderr,"Roll error\n");
err(error);
}

else
fprintf(stderr, "saving: %s\n", filename);
recordVideo();
while(true)
{
handle_event();
}


}

}

VideoRecorder::~VideoRecorder() {
// TODO Auto-generated destructor stub
stopVideo();
screen_stop_events(screen_ctx);
bps_shutdown();
screen_destroy_window(screen_win);
screen_destroy_context(screen_ctx);

}


void VideoRecorder:: 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:
fprintf(stderr,"Touch event\n");
// touch = true;
break;
case SCREEN_EVENT_MTOUCH_MOVE:
fprintf(stderr,"Move event\n");
break;
case SCREEN_EVENT_MTOUCH_RELEASE:
fprintf(stderr,"Release event\n");
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 {
fprintf(stderr,"viewfinder window found!\n");
// 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
i = APP_ZORDER + 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 VideoRecorder:: 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);
}
}
}

 

 

int VideoRecorder::init_camera(camera_unit_t unit)
{
camera_error_t error;
// open the specified camera
error = camera_open(unit,CAMERA_MODE_RW|CAMERA_MODE_ROLL,&handle);
if (error != CAMERA_EOK) {
fprintf(stderr, "camera_open() failed: %d\n", error);
return error;
}

 

error = camera_set_videovf_property( handle,CAMERA_IMGPROP_WIN_GROUPID, "GroupID",CAMERA_IMGPROP_WIN_ID, "WindowID",CAMERA_IMGPROP_WIDTH, 1024, CAMERA_IMGPROP_HEIGHT, 576, CAMERA_IMGPROP_FRAMERATE, (double)30.0 );
if (error != CAMERA_EOK)
{
fprintf(stderr, "camera_set_videovf_property() failed: %d\n", error);
err(error);
}

error = camera_set_video_property( handle,CAMERA_IMGPROP_WIDTH, 1024,CAMERA_IMGPROP_HEIGHT, 576, CAMERA_IMGPROP_ROTATION, 0, CAMERA_IMGPROP_FRAMERATE, (double)30.0);

if (error != CAMERA_EOK)
{
fprintf(stderr, "camera_set_video_property() failed: %d\n", error);
err(error);
}

else
{
error = camera_start_video_viewfinder(handle, NULL,NULL,NULL);
if (error != CAMERA_EOK)
{
fprintf(stderr, "camera_start_video_viewfinder() failed: %d\n", error);
}
else
{
if (unit == CAMERA_UNIT_FRONT)
{
shouldmirror = true;
}
return 0;
}
}
// clean up on error
camera_close(handle);
handle = CAMERA_HANDLE_INVALID;
return error;
}


static void video_callback(camera_handle_t handle,camera_buffer_t* buf, void* file)
{
fprintf(stderr,"Got a frame\n");
int fd = (int)file;
fprintf(stderr,"type:%d",buf->frametype);
if (buf->frametype == CAMERA_FRAMETYPE_NV12)
{
fprintf(stderr, "still image size: %lld\n", buf->framedesc.nv12.width*buf->framedesc.nv12.height);
//int fd;
// if (camera_roll_open_video(handle, &fd,"shared/videos/test.mp4",sizeof("shared/videos/test.mp4"),CAMERA_ROLL_VIDEO_FMT_DEFAULT) == CAMERA_EOK)
{
// fprintf(stderr, "saving: %s\n", "shared/videos/test.mp4");
int index = 0;
while(index < (int)buf->framedesc.nv12.width*buf->framedesc.nv12.height) {
int rc = write(fd, &buf->framebuf[index], (size_t)buf->framedesc.nv12.width*buf->framedesc.nv12.height-index);
fprintf(stderr,"rc:%d",rc);
if (rc > 0)
{
index += rc;
}
else if (rc == -1)
{
if ((errno == EAGAIN) || (errno == EINTR)) continue;
//perror("write");
break;
}
}
//close(fd);
}
}
}

static void status_callback(camera_handle_t, camera_devstatus_t,uint16_t, void*)
{
fprintf(stderr,"Some status\n");
}

 

void VideoRecorder::recordVideo()
{
camera_error_t error;
//camera_start_video(handle,const char *filename,void (*video_callback)(camera_handle_t,camera_buffer_t*, void*),void (*status_callback)(camera_handle_t, camera_devstatus_t,uint16_t, void*),void *arg);
error = camera_start_video(handle, filename, &video_callback,&status_callback, (void*) fd);
if (error != CAMERA_EOK) {
fprintf(stderr, "Error starting video\n");
fprintf(stderr, "%s\n", sys_errlist[errno]);
err(error);

}

}


void VideoRecorder::stopVideo()
{
camera_roll_close_video(fd);
camera_stop_video(handle);
camera_stop_video_viewfinder(handle);
camera_close(handle);
}


void VideoRecorder::err(camera_error_t err)
{
switch (err) {

case CAMERA_EAGAIN:
fprintf(stderr,"The specified camera was not available. Try again.\n");
break;
case CAMERA_EINVAL:
fprintf(stderr,"The camera call failed because of an invalid parameter.\n");
break;
case CAMERA_ENODEV:
fprintf(stderr, "No such camera was found.\n");
break;
case CAMERA_EMFILE:
fprintf(stderr,"The camera called failed because of a file table overflow.\n");
break;

case CAMERA_EBADF:
fprintf(stderr,"Indicates that an invalid handle to a @c camera_handle_t value was used.\n");
break;
case CAMERA_EACCESS:
fprintf(stderr,"Indicates that the necessary permissions to access the camera are not available.\n");
break;

case CAMERA_EBADR:
fprintf(stderr,"Indicates that an invalid file descriptor was used.\n");
break;
case CAMERA_ENOENT:
fprintf(stderr,"Indicates that the access a file or directory that does not exist.\n");
break;

case CAMERA_ENOMEM:
fprintf(stderr, "Indicates that memory allocation failed.\n");
break;
case CAMERA_EOPNOTSUPP:
fprintf(stderr,
"Indicates that the requested operation is not supported.\n");
break;

case CAMERA_ETIMEDOUT:
fprintf(stderr,"Indicates an operation on the camera is already in progress. In addition, this error can indicate that an error could not be completed because i was already completed. For example, if you called the @c camera_stop_video() function but the camera had already stopped recording video, this error code would be returned.\n");
break;

case CAMERA_EALREADY:
fprintf(stderr,
"Indicates an operation on the camera is already in progress. In addition,this error can indicate that an error could not be completed because it was already completed. For example, if you called the @c camera_stop_video() function but the camera had already stopped recording video, this error code would be returned.\n");
break;

case CAMERA_EUNINIT:
fprintf(stderr,"Indicates that the Camera Library is not initialized.\n");
break;
case CAMERA_EREGFAULT:
fprintf(stderr,"Indicates that registration of a callback failed.\n");
break;

case CAMERA_EMICINUSE:
fprintf(stderr,"Indicates that it failed to open because microphone is already in use.\n");
break;

}
}


int main()
{
VideoRecorder *recorder = new VideoRecorder();
}

 

Please use plain text.
BlackBerry Development Advisor
smcveigh
Posts: 668
Registered: ‎11-29-2011
My Device: developer
My Carrier: other

Re: Video Recording on Playbook

I finished a video recording sample last night.  I should be able to publish it next week.

In short, you don't need to manually handle the frames.

 

camera_start_video() will do the video encoding for you and will output to an .mp4 file as specified by the filename argument.  You don't need to worry about video callbacks unless you want to do something with uncompressed video frames (which I don't think you do).

 

 

Here's a snippet of my setup.  It's a Cascades sample, but you can see how the viewfinder is started:

    if (camera_open(mCameraUnit,
                    CAMERA_MODE_RW | CAMERA_MODE_ROLL,
                    &mCameraHandle) != CAMERA_EOK) {
        qDebug() << "could not open camera";
        return EIO;
    }
    qDebug() << "camera opened";
    if (camera_set_videovf_property(mCameraHandle,
                                    CAMERA_IMGPROP_WIN_GROUPID, group.toStdString().c_str(),
                                    CAMERA_IMGPROP_WIN_ID, id.toStdString().c_str()) == CAMERA_EOK) {
        qDebug() << "viewfinder configured";
        if (camera_start_video_viewfinder(mCameraHandle, NULL, NULL, NULL) == CAMERA_EOK) {

 

And here's a snippet of how I start a recording in the same app.. note you can just specify filename="/accounts/1000/shared/misc/testfile.mp4" or similar.  I'm using the camera-roll filename generator though.

            char filename[CAMERA_ROLL_NAMELEN];
            if (camera_roll_open_video(mCameraHandle,
                                       &mVideoFileDescriptor,
                                       filename,
                                       sizeof(filename),
                                       CAMERA_ROLL_VIDEO_FMT_DEFAULT) == CAMERA_EOK) {
                qDebug() << "opened " << filename;
                if (camera_start_video(mCameraHandle,
                                       filename,
                                       NULL,
                                       NULL,
                                       NULL) == CAMERA_EOK) {
                    qDebug() << "started recording";
                    return;
                }
                qDebug() << "failed to start recording";
                camera_roll_close_video(mVideoFileDescriptor);
                mVideoFileDescriptor = -1;
            }

 

And that's it.

When done, just call camera_stop_video() and then camera_roll_close_video() if you opened the file as I did above.

 

Note that the above is using all default image properties.  Once you have that working, you can look at changing image size, etc.   I will be writing a "best practices" sample some time soon which shows how to configure everything from scratch, query available settings, handle rotation, respond correctly to status events, etc.  The existing samples only illustrate how to get started.

 

Cheers,

Sean

Please use plain text.
BlackBerry Development Advisor
smcveigh
Posts: 668
Registered: ‎11-29-2011
My Device: developer
My Carrier: other

Re: Video Recording on Playbook

Also, make sure you have the following capabilities defined in your bar descriptor:

    <action>use_camera</action>
    <action>access_shared</action>
    <action>record_audio</action>


Please use plain text.
Contributor
nirhor_roy
Posts: 23
Registered: ‎05-29-2012
My Device: Blackberry Playbook Os 2.0
My Carrier: Robi Axiata Limited

Re: Video Recording on Playbook

First of all thanks a lot for the help. However question no 4 I asked is the most important of all. How can I separate the audio from video. I want the audio in some other format not in the default aac format. Is there any possible way to do that.

Please use plain text.
BlackBerry Development Advisor
smcveigh
Posts: 668
Registered: ‎11-29-2011
My Device: developer
My Carrier: other

Re: Video Recording on Playbook

GOOD NEWS EVERYONE!!!

 

Video recording sample code:

https://github.com/blackberry/Cascades-Community-Samples/tree/master/HelloVideoCamera

 

Cheers,

Sean

 

 

Please use plain text.
BlackBerry Development Advisor
smcveigh
Posts: 668
Registered: ‎11-29-2011
My Device: developer
My Carrier: other

Re: Video Recording on Playbook


nirhor_roy wrote:

First of all thanks a lot for the help. However question no 4 I asked is the most important of all. How can I separate the audio from video. I want the audio in some other format not in the default aac format. Is there any possible way to do that.


If your end goal is to record an mpeg-4 video file (H.264) with non-AAC audio, this is not possible today.

 

A future API update will bring support to capture compressed video without writing to disk.  At that point, I plan to make audio support optional and/or configurable.  You should have enough CPU horsepower to do your own audio encoding if we do not support the format you want to use.

 

Today, the only available Camera API for encoded video is to write the file to disk with the default audio format.

 

Cheers,

Sean

Please use plain text.
Trusted Contributor
sucroid
Posts: 195
Registered: ‎03-12-2012
My Device: PlayBook
My Carrier: None

Re: Video Recording on Playbook

How does one go about processing the frames (in real time) before they are written to disk?  For example, adding a watermark or date and time or filter effects.  Is this possible?

Sucroid.com
Sweet Apps for the Fans
Please use plain text.
Contributor
nirhor_roy
Posts: 23
Registered: ‎05-29-2012
My Device: Blackberry Playbook Os 2.0
My Carrier: Robi Axiata Limited

Re: Video Recording on Playbook

@smcveigh Actually I am trying to make an application that does video call. So with current camera_api is it possible to create a video call application? The default bandwidth requirement is just too high.

 

Is there some way in which I can only record video and not audio? If the recorder is not started by the video recorder, I can start my own recorder and that solves the  problem.

Please use plain text.
Contributor
nirhor_roy
Posts: 23
Registered: ‎05-29-2012
My Device: Blackberry Playbook Os 2.0
My Carrier: Robi Axiata Limited

Re: Video Recording on Playbook

Just to find out this what I can find from the uncompressed video frame? Does it contain audio as well? If it does how can I separate the audio from video? Please help!! :Helpsmilie:

Please use plain text.
BlackBerry Development Advisor
smcveigh
Posts: 668
Registered: ‎11-29-2011
My Device: developer
My Carrier: other

Re: Video Recording on Playbook


sucroid wrote:

How does one go about processing the frames (in real time) before they are written to disk?  For example, adding a watermark or date and time or filter effects.  Is this possible?


This is not doable in the 10.0.4 NDK.  It will be doable in the next release.

 

Cheers,

Sean

Please use plain text.