mirror of
https://review.haiku-os.org/haiku
synced 2025-01-31 02:35:03 +01:00
241dbd3785
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@32708 a95241bf-73f2-0310-859d-f6bbb57e9c96
948 lines
26 KiB
C++
948 lines
26 KiB
C++
#include "CodyCam.h"
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
#include <Alert.h>
|
|
#include <Button.h>
|
|
#include <GridLayout.h>
|
|
#include <GroupLayout.h>
|
|
#include <GroupLayoutBuilder.h>
|
|
#include <MediaDefs.h>
|
|
#include <MediaNode.h>
|
|
#include <MediaRoster.h>
|
|
#include <MediaTheme.h>
|
|
#include <Menu.h>
|
|
#include <MenuBar.h>
|
|
#include <MenuItem.h>
|
|
#include <PopUpMenu.h>
|
|
#include <scheduler.h>
|
|
#include <SpaceLayoutItem.h>
|
|
#include <TabView.h>
|
|
#include <TextControl.h>
|
|
#include <TimeSource.h>
|
|
#include <TranslationKit.h>
|
|
|
|
|
|
#define VIDEO_SIZE_X 320
|
|
#define VIDEO_SIZE_Y 240
|
|
|
|
#define WINDOW_SIZE_X (VIDEO_SIZE_X + 80)
|
|
#define WINDOW_SIZE_Y (VIDEO_SIZE_Y + 230)
|
|
|
|
#define WINDOW_OFFSET_X 28
|
|
#define WINDOW_OFFSET_Y 28
|
|
|
|
const int32 kBtnHeight = 20;
|
|
const int32 kBtnWidth = 60;
|
|
const int32 kBtnBuffer = 25;
|
|
const int32 kXBuffer = 10;
|
|
const int32 kYBuffer = 10;
|
|
const int32 kMenuHeight = 15;
|
|
const int32 kButtonHeight = 15;
|
|
const int32 kSliderViewRectHeight = 40;
|
|
|
|
static void ErrorAlert(const char* message, status_t err, BWindow *window);
|
|
static status_t AddTranslationItems(BMenu* intoMenu, uint32 fromType);
|
|
|
|
#define CALL printf
|
|
#define ERROR printf
|
|
#define FTPINFO printf
|
|
#define INFO printf
|
|
|
|
|
|
// Utility functions
|
|
|
|
static void
|
|
ErrorAlert(const char* message, status_t err, BWindow *window = NULL)
|
|
{
|
|
BAlert *alert = new BAlert("", message, "OK");
|
|
if (window != NULL) {
|
|
alert->MoveTo(
|
|
window->Frame().left +
|
|
window->Bounds().right / 2 -
|
|
alert->Bounds().right / 2,
|
|
window->Frame().top +
|
|
window->Bounds().bottom / 2 -
|
|
alert->Bounds().bottom / 2);
|
|
}
|
|
alert->Go();
|
|
|
|
printf("%s\n%s [%lx]", message, strerror(err), err);
|
|
// be_app->PostMessage(B_QUIT_REQUESTED);
|
|
}
|
|
|
|
|
|
status_t
|
|
AddTranslationItems(BMenu* intoMenu, uint32 fromType)
|
|
{
|
|
|
|
BTranslatorRoster* use;
|
|
char* translatorTypeName;
|
|
const char* translatorIdName;
|
|
|
|
use = BTranslatorRoster::Default();
|
|
translatorIdName = "be:translator";
|
|
translatorTypeName = (char *)"be:type";
|
|
translator_id* ids = NULL;
|
|
int32 count = 0;
|
|
|
|
status_t err = use->GetAllTranslators(&ids, &count);
|
|
if (err < B_OK)
|
|
return err;
|
|
|
|
for (int tix = 0; tix < count; tix++) {
|
|
const translation_format* formats = NULL;
|
|
int32 num_formats = 0;
|
|
bool ok = false;
|
|
err = use->GetInputFormats(ids[tix], &formats, &num_formats);
|
|
if (err == B_OK)
|
|
for (int iix = 0; iix < num_formats; iix++) {
|
|
if (formats[iix].type == fromType) {
|
|
ok = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!ok)
|
|
continue;
|
|
|
|
err = use->GetOutputFormats(ids[tix], &formats, &num_formats);
|
|
if (err == B_OK)
|
|
for (int oix = 0; oix < num_formats; oix++) {
|
|
if (formats[oix].type != fromType) {
|
|
BMessage* itemmsg;
|
|
itemmsg = new BMessage(msg_translate);
|
|
itemmsg->AddInt32(translatorIdName, ids[tix]);
|
|
itemmsg->AddInt32(translatorTypeName, formats[oix].type);
|
|
intoMenu->AddItem(new BMenuItem(formats[oix].name, itemmsg));
|
|
}
|
|
}
|
|
}
|
|
delete[] ids;
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
// #pragma mark -
|
|
|
|
|
|
CodyCam::CodyCam()
|
|
: BApplication("application/x-vnd.Haiku.CodyCam"),
|
|
fMediaRoster(NULL),
|
|
fVideoConsumer(NULL),
|
|
fWindow(NULL),
|
|
fPort(0),
|
|
fVideoControlWindow(NULL)
|
|
{
|
|
chdir("/boot/home");
|
|
}
|
|
|
|
|
|
CodyCam::~CodyCam()
|
|
{
|
|
CALL("CodyCam::~CodyCam\n");
|
|
|
|
// release the video consumer node
|
|
// the consumer node cleans up the window
|
|
if (fVideoConsumer) {
|
|
fVideoConsumer->Release();
|
|
fVideoConsumer = NULL;
|
|
}
|
|
|
|
CALL("CodyCam::~CodyCam - EXIT\n");
|
|
}
|
|
|
|
|
|
void
|
|
CodyCam::ReadyToRun()
|
|
{
|
|
/* create the window for the app */
|
|
fWindow = new VideoWindow(BRect(28, 28, 28, 28),
|
|
(const char*) "CodyCam", B_TITLED_WINDOW,
|
|
B_NOT_ZOOMABLE | B_AUTO_UPDATE_SIZE_LIMITS, &fPort);
|
|
|
|
/* set up the node connections */
|
|
status_t status = _SetUpNodes();
|
|
if (status != B_OK) {
|
|
// This error is not needed because _SetUpNodes handles displaying any
|
|
// errors it runs into.
|
|
// ErrorAlert("Error setting up nodes", status);
|
|
return;
|
|
}
|
|
|
|
((VideoWindow*)fWindow)->ApplyControls();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
CodyCam::QuitRequested()
|
|
{
|
|
_TearDownNodes();
|
|
snooze(100000);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
void
|
|
CodyCam::MessageReceived(BMessage *message)
|
|
{
|
|
switch (message->what) {
|
|
case msg_start:
|
|
{
|
|
BTimeSource* timeSource = fMediaRoster->MakeTimeSourceFor(fTimeSourceNode);
|
|
bigtime_t real = BTimeSource::RealTime();
|
|
bigtime_t perf = timeSource->PerformanceTimeFor(real) + 10000;
|
|
status_t status = fMediaRoster->StartNode(fProducerNode, perf);
|
|
if (status != B_OK)
|
|
ERROR("error starting producer!");
|
|
timeSource->Release();
|
|
break;
|
|
}
|
|
|
|
case msg_stop:
|
|
fMediaRoster->StopNode(fProducerNode, 0, true);
|
|
break;
|
|
|
|
case msg_video:
|
|
{
|
|
if (fVideoControlWindow) {
|
|
fVideoControlWindow->Activate();
|
|
break;
|
|
}
|
|
BParameterWeb* web = NULL;
|
|
BView* view = NULL;
|
|
media_node node = fProducerNode;
|
|
status_t err = fMediaRoster->GetParameterWebFor(node, &web);
|
|
if (err >= B_OK && web != NULL) {
|
|
view = BMediaTheme::ViewFor(web);
|
|
fVideoControlWindow = new ControlWindow(
|
|
BRect(2 * WINDOW_OFFSET_X + WINDOW_SIZE_X, WINDOW_OFFSET_Y,
|
|
2 * WINDOW_OFFSET_X + WINDOW_SIZE_X + view->Bounds().right,
|
|
WINDOW_OFFSET_Y + view->Bounds().bottom), view, node);
|
|
fMediaRoster->StartWatching(BMessenger(NULL, fVideoControlWindow), node,
|
|
B_MEDIA_WEB_CHANGED);
|
|
fVideoControlWindow->Show();
|
|
}
|
|
break;
|
|
}
|
|
|
|
case msg_about:
|
|
(new BAlert("About CodyCam", "CodyCam\n\nThe Original BeOS WebCam",
|
|
"Close"))->Go();
|
|
break;
|
|
|
|
case msg_control_win:
|
|
// our control window is being asked to go away
|
|
// set our pointer to NULL
|
|
fVideoControlWindow = NULL;
|
|
break;
|
|
|
|
default:
|
|
BApplication::MessageReceived(message);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
status_t
|
|
CodyCam::_SetUpNodes()
|
|
{
|
|
status_t status = B_OK;
|
|
|
|
/* find the media roster */
|
|
fMediaRoster = BMediaRoster::Roster(&status);
|
|
if (status != B_OK) {
|
|
ErrorAlert("Can't find the media roster", status, fWindow);
|
|
return status;
|
|
}
|
|
|
|
/* find the time source */
|
|
status = fMediaRoster->GetTimeSource(&fTimeSourceNode);
|
|
if (status != B_OK) {
|
|
ErrorAlert("Can't get a time source", status, fWindow);
|
|
return status;
|
|
}
|
|
|
|
/* find a video producer node */
|
|
INFO("CodyCam acquiring VideoInput node\n");
|
|
status = fMediaRoster->GetVideoInput(&fProducerNode);
|
|
if (status != B_OK) {
|
|
ErrorAlert("Can't find a video source. You need a webcam to use CodyCam.", status, fWindow);
|
|
return status;
|
|
}
|
|
|
|
/* create the video consumer node */
|
|
fVideoConsumer = new VideoConsumer("CodyCam", ((VideoWindow*)fWindow)->VideoView(),
|
|
((VideoWindow*)fWindow)->StatusLine(), NULL, 0);
|
|
if (!fVideoConsumer) {
|
|
ErrorAlert("Can't create a video window", B_ERROR, fWindow);
|
|
return B_ERROR;
|
|
}
|
|
|
|
/* register the node */
|
|
status = fMediaRoster->RegisterNode(fVideoConsumer);
|
|
if (status != B_OK) {
|
|
ErrorAlert("Can't register the video window", status, fWindow);
|
|
return status;
|
|
}
|
|
fPort = fVideoConsumer->ControlPort();
|
|
|
|
/* find free producer output */
|
|
int32 cnt = 0;
|
|
status = fMediaRoster->GetFreeOutputsFor(fProducerNode, &fProducerOut, 1, &cnt,
|
|
B_MEDIA_RAW_VIDEO);
|
|
if (status != B_OK || cnt < 1) {
|
|
status = B_RESOURCE_UNAVAILABLE;
|
|
ErrorAlert("Can't find an available video stream", status, fWindow);
|
|
return status;
|
|
}
|
|
|
|
/* find free consumer input */
|
|
cnt = 0;
|
|
status = fMediaRoster->GetFreeInputsFor(fVideoConsumer->Node(), &fConsumerIn, 1,
|
|
&cnt, B_MEDIA_RAW_VIDEO);
|
|
if (status != B_OK || cnt < 1) {
|
|
status = B_RESOURCE_UNAVAILABLE;
|
|
ErrorAlert("Can't find an available connection to the video window", status, fWindow);
|
|
return status;
|
|
}
|
|
|
|
/* Connect The Nodes!!! */
|
|
media_format format;
|
|
format.type = B_MEDIA_RAW_VIDEO;
|
|
media_raw_video_format vid_format = {0, 1, 0, 239, B_VIDEO_TOP_LEFT_RIGHT,
|
|
1, 1, {B_RGB32, VIDEO_SIZE_X, VIDEO_SIZE_Y, VIDEO_SIZE_X * 4, 0, 0}};
|
|
format.u.raw_video = vid_format;
|
|
|
|
/* connect producer to consumer */
|
|
status = fMediaRoster->Connect(fProducerOut.source, fConsumerIn.destination,
|
|
&format, &fProducerOut, &fConsumerIn);
|
|
if (status != B_OK) {
|
|
ErrorAlert("Can't connect the video source to the video window", status);
|
|
return status;
|
|
}
|
|
|
|
|
|
/* set time sources */
|
|
|
|
status = fMediaRoster->SetTimeSourceFor(fProducerNode.node, fTimeSourceNode.node);
|
|
if (status != B_OK) {
|
|
ErrorAlert("Can't set the timesource for the video source", status);
|
|
return status;
|
|
}
|
|
|
|
status = fMediaRoster->SetTimeSourceFor(fVideoConsumer->ID(), fTimeSourceNode.node);
|
|
if (status != B_OK) {
|
|
ErrorAlert("Can't set the timesource for the video window", status);
|
|
return status;
|
|
}
|
|
|
|
/* figure out what recording delay to use */
|
|
bigtime_t latency = 0;
|
|
status = fMediaRoster->GetLatencyFor(fProducerNode, &latency);
|
|
status = fMediaRoster->SetProducerRunModeDelay(fProducerNode, latency);
|
|
|
|
/* start the nodes */
|
|
bigtime_t initLatency = 0;
|
|
status = fMediaRoster->GetInitialLatencyFor(fProducerNode, &initLatency);
|
|
if (status < B_OK) {
|
|
ErrorAlert("error getting initial latency for fCaptureNode", status);
|
|
return status;
|
|
}
|
|
|
|
initLatency += estimate_max_scheduling_latency();
|
|
|
|
BTimeSource* timeSource = fMediaRoster->MakeTimeSourceFor(fProducerNode);
|
|
bool running = timeSource->IsRunning();
|
|
|
|
/* workaround for people without sound cards */
|
|
/* because the system time source won't be running */
|
|
bigtime_t real = BTimeSource::RealTime();
|
|
if (!running) {
|
|
status = fMediaRoster->StartTimeSource(fTimeSourceNode, real);
|
|
if (status != B_OK) {
|
|
timeSource->Release();
|
|
ErrorAlert("cannot start time source!", status);
|
|
return status;
|
|
}
|
|
status = fMediaRoster->SeekTimeSource(fTimeSourceNode, 0, real);
|
|
if (status != B_OK) {
|
|
timeSource->Release();
|
|
ErrorAlert("cannot seek time source!", status);
|
|
return status;
|
|
}
|
|
}
|
|
|
|
bigtime_t perf = timeSource->PerformanceTimeFor(real + latency + initLatency);
|
|
timeSource->Release();
|
|
|
|
/* start the nodes */
|
|
status = fMediaRoster->StartNode(fProducerNode, perf);
|
|
if (status != B_OK) {
|
|
ErrorAlert("Can't start the video source", status);
|
|
return status;
|
|
}
|
|
status = fMediaRoster->StartNode(fVideoConsumer->Node(), perf);
|
|
if (status != B_OK) {
|
|
ErrorAlert("Can't start the video window", status);
|
|
return status;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
void
|
|
CodyCam::_TearDownNodes()
|
|
{
|
|
CALL("CodyCam::_TearDownNodes\n");
|
|
if (!fMediaRoster)
|
|
return;
|
|
|
|
if (fVideoConsumer) {
|
|
/* stop */
|
|
INFO("stopping nodes!\n");
|
|
// fMediaRoster->StopNode(fProducerNode, 0, true);
|
|
fMediaRoster->StopNode(fVideoConsumer->Node(), 0, true);
|
|
|
|
/* disconnect */
|
|
fMediaRoster->Disconnect(fProducerOut.node.node, fProducerOut.source,
|
|
fConsumerIn.node.node, fConsumerIn.destination);
|
|
|
|
if (fProducerNode != media_node::null) {
|
|
INFO("CodyCam releasing fProducerNode\n");
|
|
fMediaRoster->ReleaseNode(fProducerNode);
|
|
fProducerNode = media_node::null;
|
|
}
|
|
fMediaRoster->ReleaseNode(fVideoConsumer->Node());
|
|
fVideoConsumer = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
// #pragma mark - Video Window Class
|
|
|
|
|
|
VideoWindow::VideoWindow (BRect frame, const char* title, window_type type, uint32 flags,
|
|
port_id* consumerPort)
|
|
: BWindow(frame,title,type,flags),
|
|
fPortPtr(consumerPort),
|
|
fView(NULL),
|
|
fVideoView(NULL)
|
|
{
|
|
fFtpInfo.port = 0;
|
|
fFtpInfo.rate = 0x7fffffff;
|
|
fFtpInfo.imageFormat = 0;
|
|
fFtpInfo.translator = 0;
|
|
fFtpInfo.passiveFtp = true;
|
|
fFtpInfo.uploadClient = 0;
|
|
strcpy(fFtpInfo.fileNameText, "filename");
|
|
strcpy(fFtpInfo.serverText, "server");
|
|
strcpy(fFtpInfo.loginText, "login");
|
|
strcpy(fFtpInfo.passwordText, "password");
|
|
strcpy(fFtpInfo.directoryText, "directory");
|
|
|
|
_SetUpSettings("codycam", "");
|
|
|
|
BMenuBar* menuBar = new BMenuBar(BRect(0, 0, 0, 0), "menu bar");
|
|
|
|
BMenuItem* menuItem;
|
|
BMenu* menu = new BMenu("File");
|
|
|
|
menuItem = new BMenuItem("Video Preferences", new BMessage(msg_video), 'P');
|
|
menuItem->SetTarget(be_app);
|
|
menu->AddItem(menuItem);
|
|
|
|
menu->AddSeparatorItem();
|
|
|
|
menuItem = new BMenuItem("Start Video", new BMessage(msg_start), 'A');
|
|
menuItem->SetTarget(be_app);
|
|
menu->AddItem(menuItem);
|
|
|
|
menuItem = new BMenuItem("Stop Video", new BMessage(msg_stop), 'O');
|
|
menuItem->SetTarget(be_app);
|
|
menu->AddItem(menuItem);
|
|
|
|
menu->AddSeparatorItem();
|
|
|
|
menuItem = new BMenuItem("About Codycam", new BMessage(msg_about), 'B');
|
|
menuItem->SetTarget(be_app);
|
|
menu->AddItem(menuItem);
|
|
|
|
menu->AddSeparatorItem();
|
|
|
|
menuItem = new BMenuItem("Quit", new BMessage(B_QUIT_REQUESTED), 'Q');
|
|
menuItem->SetTarget(be_app);
|
|
menu->AddItem(menuItem);
|
|
|
|
menuBar->AddItem(menu);
|
|
|
|
/* give it a gray background view */
|
|
fView = new BView("Background View", B_WILL_DRAW, NULL);
|
|
fView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
|
|
|
/* add some controls */
|
|
_BuildCaptureControls(fView);
|
|
|
|
SetLayout(new BGroupLayout(B_VERTICAL));
|
|
AddChild(menuBar);
|
|
AddChild(fView);
|
|
|
|
Show();
|
|
}
|
|
|
|
|
|
|
|
VideoWindow::~VideoWindow()
|
|
{
|
|
_QuitSettings();
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
VideoWindow::QuitRequested()
|
|
{
|
|
be_app->PostMessage(B_QUIT_REQUESTED);
|
|
return false;
|
|
}
|
|
|
|
|
|
void
|
|
VideoWindow::MessageReceived(BMessage* message)
|
|
{
|
|
BControl* control;
|
|
|
|
control = NULL;
|
|
message->FindPointer((const char*)"source", (void **)&control);
|
|
|
|
switch (message->what) {
|
|
case msg_filename:
|
|
if (control != NULL) {
|
|
strncpy(fFtpInfo.fileNameText, ((BTextControl*)control)->Text(), 63);
|
|
FTPINFO("file is '%s'\n", fFtpInfo.fileNameText);
|
|
}
|
|
break;
|
|
|
|
case msg_rate_15s:
|
|
FTPINFO("fifteen seconds\n");
|
|
fFtpInfo.rate = (bigtime_t)(15 * 1000000);
|
|
break;
|
|
|
|
case msg_rate_30s:
|
|
FTPINFO("thirty seconds\n");
|
|
fFtpInfo.rate = (bigtime_t)(30 * 1000000);
|
|
break;
|
|
|
|
case msg_rate_1m:
|
|
FTPINFO("one minute\n");
|
|
fFtpInfo.rate = (bigtime_t)(1 * 60 * 1000000);
|
|
break;
|
|
|
|
case msg_rate_5m:
|
|
FTPINFO("five minute\n");
|
|
fFtpInfo.rate = (bigtime_t)(5 * 60 * 1000000);
|
|
break;
|
|
|
|
case msg_rate_10m:
|
|
FTPINFO("ten minute\n");
|
|
fFtpInfo.rate = (bigtime_t)(10 * 60 * 1000000);
|
|
break;
|
|
|
|
case msg_rate_15m:
|
|
FTPINFO("fifteen minute\n");
|
|
fFtpInfo.rate = (bigtime_t)(15 * 60 * 1000000);
|
|
break;
|
|
|
|
case msg_rate_30m:
|
|
FTPINFO("thirty minute\n");
|
|
fFtpInfo.rate = (bigtime_t)(30 * 60 * 1000000);
|
|
break;
|
|
|
|
case msg_rate_1h:
|
|
FTPINFO("one hour\n");
|
|
fFtpInfo.rate = (bigtime_t)(60LL * 60LL * 1000000LL);
|
|
break;
|
|
|
|
case msg_rate_2h:
|
|
FTPINFO("two hour\n");
|
|
fFtpInfo.rate = (bigtime_t)(2LL * 60LL * 60LL * 1000000LL);
|
|
break;
|
|
|
|
case msg_rate_4h:
|
|
FTPINFO("four hour\n");
|
|
fFtpInfo.rate = (bigtime_t)(4LL * 60LL * 60LL * 1000000LL);
|
|
break;
|
|
|
|
case msg_rate_8h:
|
|
FTPINFO("eight hour\n");
|
|
fFtpInfo.rate = (bigtime_t)(8LL * 60LL * 60LL * 1000000LL);
|
|
break;
|
|
|
|
case msg_rate_24h:
|
|
FTPINFO("24 hour\n");
|
|
fFtpInfo.rate = (bigtime_t)(24LL * 60LL * 60LL * 1000000LL);
|
|
break;
|
|
|
|
case msg_rate_never:
|
|
FTPINFO("never\n");
|
|
fFtpInfo.rate = (bigtime_t)(B_INFINITE_TIMEOUT);
|
|
break;
|
|
|
|
case msg_translate:
|
|
message->FindInt32("be:type", (int32*)&(fFtpInfo.imageFormat));
|
|
message->FindInt32("be:translator", &(fFtpInfo.translator));
|
|
break;
|
|
|
|
case msg_upl_client:
|
|
if (control != NULL) {
|
|
message->FindInt32("client", &(fFtpInfo.uploadClient));
|
|
FTPINFO("upl client = %ld\n", fFtpInfo.uploadClient);
|
|
}
|
|
break;
|
|
|
|
case msg_server:
|
|
if (control != NULL) {
|
|
strncpy(fFtpInfo.serverText, ((BTextControl*)control)->Text(), 64);
|
|
FTPINFO("server = '%s'\n", fFtpInfo.serverText);
|
|
}
|
|
break;
|
|
|
|
case msg_login:
|
|
if (control != NULL) {
|
|
strncpy(fFtpInfo.loginText, ((BTextControl*)control)->Text(), 64);
|
|
FTPINFO("login = '%s'\n", fFtpInfo.loginText);
|
|
}
|
|
break;
|
|
|
|
case msg_password:
|
|
if (control != NULL) {
|
|
strncpy(fFtpInfo.passwordText, ((BTextControl*)control)->Text(), 64);
|
|
FTPINFO("password = '%s'\n", fFtpInfo.passwordText);
|
|
}
|
|
break;
|
|
|
|
case msg_directory:
|
|
if (control != NULL) {
|
|
strncpy(fFtpInfo.directoryText, ((BTextControl*)control)->Text(), 64);
|
|
FTPINFO("directory = '%s'\n", fFtpInfo.directoryText);
|
|
}
|
|
break;
|
|
|
|
case msg_passiveftp:
|
|
if (control != NULL) {
|
|
fFtpInfo.passiveFtp = ((BCheckBox*)control)->Value();
|
|
if (fFtpInfo.passiveFtp)
|
|
FTPINFO("using passive ftp\n");
|
|
}
|
|
break;
|
|
|
|
default:
|
|
BWindow::MessageReceived(message);
|
|
return;
|
|
}
|
|
|
|
if (*fPortPtr)
|
|
write_port(*fPortPtr, FTP_INFO, (void*)&fFtpInfo, sizeof(ftp_msg_info));
|
|
|
|
}
|
|
|
|
|
|
BView*
|
|
VideoWindow::VideoView()
|
|
{
|
|
return fVideoView;
|
|
}
|
|
|
|
|
|
BStringView*
|
|
VideoWindow::StatusLine()
|
|
{
|
|
return fStatusLine;
|
|
}
|
|
|
|
|
|
void
|
|
VideoWindow::_BuildCaptureControls(BView* theView)
|
|
{
|
|
// a view to hold the video image
|
|
fVideoView = new BView("Video View", B_WILL_DRAW);
|
|
fVideoView->SetExplicitMinSize(BSize(VIDEO_SIZE_X, VIDEO_SIZE_Y));
|
|
fVideoView->SetExplicitMaxSize(BSize(VIDEO_SIZE_X, VIDEO_SIZE_Y));
|
|
|
|
// Capture controls
|
|
fCaptureSetupBox = new BBox("Capture Controls", B_WILL_DRAW);
|
|
fCaptureSetupBox->SetLabel("Capture controls");
|
|
|
|
BGridLayout *controlsLayout = new BGridLayout(kXBuffer, 0);
|
|
controlsLayout->SetInsets(10, 15, 5, 5);
|
|
fCaptureSetupBox->SetLayout(controlsLayout);
|
|
|
|
fFileName = new BTextControl("File Name", "File name:",
|
|
fFilenameSetting->Value(), new BMessage(msg_filename));
|
|
fFileName->SetTarget(BMessenger(NULL, this));
|
|
|
|
fImageFormatMenu = new BPopUpMenu("Image Format Menu");
|
|
AddTranslationItems(fImageFormatMenu, B_TRANSLATOR_BITMAP);
|
|
fImageFormatMenu->SetTargetForItems(this);
|
|
|
|
if (fImageFormatSettings->Value() && fImageFormatMenu->FindItem(fImageFormatSettings->Value()) != NULL)
|
|
fImageFormatMenu->FindItem(fImageFormatSettings->Value())->SetMarked(true);
|
|
else if (fImageFormatMenu->FindItem("JPEG Image") != NULL)
|
|
fImageFormatMenu->FindItem("JPEG Image")->SetMarked(true);
|
|
else if (fImageFormatMenu->FindItem("JPEG image") != NULL)
|
|
fImageFormatMenu->FindItem("JPEG image")->SetMarked(true);
|
|
else
|
|
fImageFormatMenu->ItemAt(0)->SetMarked(true);
|
|
|
|
fImageFormatSelector = new BMenuField("Format", "Format:",
|
|
fImageFormatMenu, NULL);
|
|
|
|
fCaptureRateMenu = new BPopUpMenu("Capture Rate Menu");
|
|
fCaptureRateMenu->AddItem(new BMenuItem("Every 15 seconds", new BMessage(msg_rate_15s)));
|
|
fCaptureRateMenu->AddItem(new BMenuItem("Every 30 seconds", new BMessage(msg_rate_30s)));
|
|
fCaptureRateMenu->AddItem(new BMenuItem("Every minute", new BMessage(msg_rate_1m)));
|
|
fCaptureRateMenu->AddItem(new BMenuItem("Every 5 minutes", new BMessage(msg_rate_5m)));
|
|
fCaptureRateMenu->AddItem(new BMenuItem("Every 10 minutes", new BMessage(msg_rate_10m)));
|
|
fCaptureRateMenu->AddItem(new BMenuItem("Every 15 minutes", new BMessage(msg_rate_15m)));
|
|
fCaptureRateMenu->AddItem(new BMenuItem("Every 30 minutes", new BMessage(msg_rate_30m)));
|
|
fCaptureRateMenu->AddItem(new BMenuItem("Every hour", new BMessage(msg_rate_1h)));
|
|
fCaptureRateMenu->AddItem(new BMenuItem("Every 2 hours", new BMessage(msg_rate_2h)));
|
|
fCaptureRateMenu->AddItem(new BMenuItem("Every 4 hours", new BMessage(msg_rate_4h)));
|
|
fCaptureRateMenu->AddItem(new BMenuItem("Every 8 hours", new BMessage(msg_rate_8h)));
|
|
fCaptureRateMenu->AddItem(new BMenuItem("Every 24 hours", new BMessage(msg_rate_24h)));
|
|
fCaptureRateMenu->AddItem(new BMenuItem("Never", new BMessage(msg_rate_never)));
|
|
fCaptureRateMenu->SetTargetForItems(this);
|
|
fCaptureRateMenu->FindItem(fCaptureRateSetting->Value())->SetMarked(true);
|
|
fCaptureRateSelector = new BMenuField("Rate", "Rate:",
|
|
fCaptureRateMenu, NULL);
|
|
|
|
controlsLayout->AddItem(fFileName->CreateLabelLayoutItem(), 0, 0);
|
|
controlsLayout->AddItem(fFileName->CreateTextViewLayoutItem(), 1, 0);
|
|
controlsLayout->AddItem(fImageFormatSelector->CreateLabelLayoutItem(), 0, 1);
|
|
controlsLayout->AddItem(fImageFormatSelector->CreateMenuBarLayoutItem(), 1, 1);
|
|
controlsLayout->AddItem(fCaptureRateSelector->CreateLabelLayoutItem(), 0, 2);
|
|
controlsLayout->AddItem(fCaptureRateSelector->CreateMenuBarLayoutItem(), 1, 2);
|
|
controlsLayout->AddItem(BSpaceLayoutItem::CreateGlue(), 0, 3, 2);
|
|
|
|
// FTP setup box
|
|
fFtpSetupBox = new BBox("Ftp Setup", B_WILL_DRAW);
|
|
|
|
fUploadClientMenu = new BPopUpMenu("Send to" B_UTF8_ELLIPSIS);
|
|
for (int i = 0; kUploadClient[i]; i++) {
|
|
BMessage *m = new BMessage(msg_upl_client);
|
|
m->AddInt32("client", i);
|
|
fUploadClientMenu->AddItem(new BMenuItem(kUploadClient[i], m));
|
|
}
|
|
fUploadClientMenu->SetTargetForItems(this);
|
|
fUploadClientMenu->FindItem(fUploadClientSetting->Value())->SetMarked(true);
|
|
fUploadClientSelector = new BMenuField("UploadClient", NULL,
|
|
fUploadClientMenu, NULL);
|
|
|
|
fFtpSetupBox->SetLabel("FTP");
|
|
// this doesn't work with the layout manager
|
|
// fFtpSetupBox->SetLabel(fUploadClientSelector);
|
|
fUploadClientSelector->SetLabel("Type:");
|
|
|
|
BGridLayout *ftpLayout = new BGridLayout(kXBuffer, 0);
|
|
ftpLayout->SetInsets(10, 15, 5, 5);
|
|
fFtpSetupBox->SetLayout(ftpLayout);
|
|
|
|
fServerName = new BTextControl("Server", "Server:",
|
|
fServerSetting->Value(), new BMessage(msg_server));
|
|
fServerName->SetTarget(this);
|
|
|
|
fLoginId = new BTextControl("Login", "Login:",
|
|
fLoginSetting->Value(), new BMessage(msg_login));
|
|
fLoginId->SetTarget(this);
|
|
|
|
fPassword = new BTextControl("Password", "Password:",
|
|
fPasswordSetting->Value(), new BMessage(msg_password));
|
|
fPassword->SetTarget(this);
|
|
fPassword->TextView()->HideTyping(true);
|
|
// BeOS HideTyping() seems broken, it empties the text
|
|
fPassword->SetText(fPasswordSetting->Value());
|
|
|
|
fDirectory = new BTextControl("Directory", "Directory:",
|
|
fDirectorySetting->Value(), new BMessage(msg_directory));
|
|
fDirectory->SetTarget(this);
|
|
|
|
fPassiveFtp = new BCheckBox("Passive ftp", "Passive FTP",
|
|
new BMessage(msg_passiveftp));
|
|
fPassiveFtp->SetTarget(this);
|
|
fPassiveFtp->SetValue(fPassiveFtpSetting->Value());
|
|
|
|
ftpLayout->AddItem(fUploadClientSelector->CreateLabelLayoutItem(), 0, 0);
|
|
ftpLayout->AddItem(fUploadClientSelector->CreateMenuBarLayoutItem(), 1, 0);
|
|
ftpLayout->AddItem(fServerName->CreateLabelLayoutItem(), 0, 1);
|
|
ftpLayout->AddItem(fServerName->CreateTextViewLayoutItem(), 1, 1);
|
|
ftpLayout->AddItem(fLoginId->CreateLabelLayoutItem(), 0, 2);
|
|
ftpLayout->AddItem(fLoginId->CreateTextViewLayoutItem(), 1, 2);
|
|
ftpLayout->AddItem(fPassword->CreateLabelLayoutItem(), 0, 3);
|
|
ftpLayout->AddItem(fPassword->CreateTextViewLayoutItem(), 1, 3);
|
|
ftpLayout->AddItem(fDirectory->CreateLabelLayoutItem(), 0, 4);
|
|
ftpLayout->AddItem(fDirectory->CreateTextViewLayoutItem(), 1, 4);
|
|
ftpLayout->AddView(fPassiveFtp, 0, 5, 2);
|
|
|
|
fStatusLine = new BStringView("Status Line", "Waiting" B_UTF8_ELLIPSIS);
|
|
|
|
BGroupLayout *groupLayout = new BGroupLayout(B_VERTICAL);
|
|
groupLayout->SetInsets(kXBuffer, kYBuffer, kXBuffer, kYBuffer);
|
|
|
|
theView->SetLayout(groupLayout);
|
|
|
|
theView->AddChild(BSpaceLayoutItem::CreateVerticalStrut(kYBuffer));
|
|
theView->AddChild(BGroupLayoutBuilder(B_HORIZONTAL)
|
|
.Add(BSpaceLayoutItem::CreateHorizontalStrut(0.0))
|
|
.Add(fVideoView)
|
|
.Add(BSpaceLayoutItem::CreateHorizontalStrut(0.0))
|
|
);
|
|
theView->AddChild(BSpaceLayoutItem::CreateVerticalStrut(kYBuffer));
|
|
theView->AddChild(BGroupLayoutBuilder(B_HORIZONTAL, kXBuffer)
|
|
.Add(fCaptureSetupBox)
|
|
.Add(fFtpSetupBox)
|
|
);
|
|
theView->AddChild(BSpaceLayoutItem::CreateVerticalStrut(kYBuffer));
|
|
theView->AddChild(fStatusLine);
|
|
}
|
|
|
|
|
|
void
|
|
VideoWindow::ApplyControls()
|
|
{
|
|
// apply controls
|
|
fFileName->Invoke();
|
|
PostMessage(fImageFormatMenu->FindMarked()->Message());
|
|
PostMessage(fCaptureRateMenu->FindMarked()->Message());
|
|
PostMessage(fUploadClientMenu->FindMarked()->Message());
|
|
fServerName->Invoke();
|
|
fLoginId->Invoke();
|
|
fPassword->Invoke();
|
|
fDirectory->Invoke();
|
|
fPassiveFtp->Invoke();
|
|
}
|
|
|
|
|
|
void
|
|
VideoWindow::_SetUpSettings(const char* filename, const char* dirname)
|
|
{
|
|
fSettings = new Settings(filename, dirname);
|
|
|
|
fSettings->Add(fServerSetting = new StringValueSetting("Server", "ftp.my.server",
|
|
"server address expected", ""));
|
|
fSettings->Add(fLoginSetting = new StringValueSetting("Login", "loginID",
|
|
"login ID expected", ""));
|
|
fSettings->Add(fPasswordSetting = new StringValueSetting("Password", "password",
|
|
"password expected", ""));
|
|
fSettings->Add(fDirectorySetting = new StringValueSetting("Directory", "web/images",
|
|
"destination directory expected", ""));
|
|
fSettings->Add(fPassiveFtpSetting = new BooleanValueSetting("PassiveFtp", 1));
|
|
fSettings->Add(fFilenameSetting = new StringValueSetting("StillImageFilename",
|
|
"codycam.jpg", "still image filename expected", ""));
|
|
fSettings->Add(fImageFormatSettings = new StringValueSetting("ImageFileFormat",
|
|
"JPEG Image", "image file format expected", ""));
|
|
fSettings->Add(fCaptureRateSetting = new EnumeratedStringValueSetting("CaptureRate",
|
|
"Every 5 minutes", kCaptureRate, "capture rate expected",
|
|
"unrecognized capture rate specified"));
|
|
fSettings->Add(fUploadClientSetting = new EnumeratedStringValueSetting("UploadClient",
|
|
"FTP", kUploadClient, "upload client name expected",
|
|
"unrecognized upload client specified"));
|
|
|
|
fSettings->TryReadingSettings();
|
|
}
|
|
|
|
|
|
void
|
|
VideoWindow::_QuitSettings()
|
|
{
|
|
fServerSetting->ValueChanged(fServerName->Text());
|
|
fLoginSetting->ValueChanged(fLoginId->Text());
|
|
fPasswordSetting->ValueChanged(fFtpInfo.passwordText);
|
|
fDirectorySetting->ValueChanged(fDirectory->Text());
|
|
fPassiveFtpSetting->ValueChanged(fPassiveFtp->Value());
|
|
fFilenameSetting->ValueChanged(fFileName->Text());
|
|
fImageFormatSettings->ValueChanged(fImageFormatMenu->FindMarked()->Label());
|
|
fCaptureRateSetting->ValueChanged(fCaptureRateMenu->FindMarked()->Label());
|
|
fUploadClientSetting->ValueChanged(fUploadClientMenu->FindMarked()->Label());
|
|
|
|
fSettings->SaveSettings();
|
|
delete fSettings;
|
|
}
|
|
|
|
|
|
// #pragma mark -
|
|
|
|
|
|
ControlWindow::ControlWindow(const BRect& frame, BView* controls, media_node node)
|
|
: BWindow(frame, "Video Preferences", B_TITLED_WINDOW, B_ASYNCHRONOUS_CONTROLS)
|
|
{
|
|
fView = controls;
|
|
fNode = node;
|
|
|
|
AddChild(fView);
|
|
}
|
|
|
|
|
|
void
|
|
ControlWindow::MessageReceived(BMessage* message)
|
|
{
|
|
BParameterWeb* web = NULL;
|
|
status_t err;
|
|
|
|
switch (message->what) {
|
|
case B_MEDIA_WEB_CHANGED:
|
|
{
|
|
// If this is a tab view, find out which tab
|
|
// is selected
|
|
BTabView* tabView = dynamic_cast<BTabView*>(fView);
|
|
int32 tabNum = -1;
|
|
if (tabView)
|
|
tabNum = tabView->Selection();
|
|
|
|
RemoveChild(fView);
|
|
delete fView;
|
|
|
|
err = BMediaRoster::Roster()->GetParameterWebFor(fNode, &web);
|
|
|
|
if (err >= B_OK && web != NULL) {
|
|
fView = BMediaTheme::ViewFor(web);
|
|
AddChild(fView);
|
|
|
|
// Another tab view? Restore previous selection
|
|
if (tabNum > 0) {
|
|
BTabView* newTabView = dynamic_cast<BTabView*>(fView);
|
|
if (newTabView)
|
|
newTabView->Select(tabNum);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
BWindow::MessageReceived(message);
|
|
}
|
|
}
|
|
|
|
|
|
bool
|
|
ControlWindow::QuitRequested()
|
|
{
|
|
be_app->PostMessage(msg_control_win);
|
|
return true;
|
|
}
|
|
|
|
|
|
// #pragma mark -
|
|
|
|
|
|
int main() {
|
|
CodyCam app;
|
|
app.Run();
|
|
return 0;
|
|
}
|