CodyCam from the BeOS Sample Code License

git-svn-id: file:///srv/svn/repos/haiku/trunk/current@2774 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Phil Greenway 2003-02-20 03:05:31 +00:00
parent 8c714454f0
commit be9a82893a
12 changed files with 3876 additions and 0 deletions

View File

@ -0,0 +1,921 @@
#include "CodyCam.h"
#include <Alert.h>
#include <stdio.h>
#include <string.h>
#include <Button.h>
#include <TabView.h>
#include <Menu.h>
#include <MenuItem.h>
#include <MenuBar.h>
#include <PopUpMenu.h>
#include <MediaDefs.h>
#include <MediaNode.h>
#include <scheduler.h>
#include <MediaTheme.h>
#include <TimeSource.h>
#include <MediaRoster.h>
#include <TextControl.h>
#include <TranslationKit.h>
#include <unistd.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;
const rgb_color kViewGray = { 216, 216, 216, 255};
static void ErrorAlert(const char * message, status_t err);
static status_t AddTranslationItems( BMenu * intoMenu, uint32 from_type);
#define CALL printf
#define ERROR printf
#define FTPINFO printf
#define INFO printf
//---------------------------------------------------------------
// The Application
//---------------------------------------------------------------
int main() {
chdir("/boot/home");
CodyCam app;
app.Run();
return 0;
}
//---------------------------------------------------------------
CodyCam::CodyCam() :
BApplication("application/x-vnd.Be.CodyCam"),
fMediaRoster(NULL),
fVideoConsumer(NULL),
fWindow(NULL),
fPort(0),
mVideoControlWindow(NULL)
{
}
//---------------------------------------------------------------
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 */
uint32 x = WINDOW_SIZE_X;
uint32 y = WINDOW_SIZE_Y;
fWindow = new VideoWindow(BRect(28, 28, 28 + (WINDOW_SIZE_X-1), 28 + (WINDOW_SIZE_Y-1)),
(const char *)"CodyCam", B_TITLED_WINDOW, B_NOT_RESIZABLE | B_NOT_ZOOMABLE, &fPort);
/* set up the node connections */
status_t status = SetUpNodes();
if (status != B_OK)
{
ErrorAlert("Error setting up nodes", status);
return;
}
((VideoWindow *)fWindow)->ApplyControls();
}
//---------------------------------------------------------------
bool
CodyCam::QuitRequested()
{
TearDownNodes();
snooze(100000);
return true;
}
//---------------------------------------------------------------
void
CodyCam::MessageReceived(BMessage *message)
{
status_t status;
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 (mVideoControlWindow) {
mVideoControlWindow->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);
mVideoControlWindow = 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, mVideoControlWindow), node, B_MEDIA_WEB_CHANGED);
mVideoControlWindow->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
mVideoControlWindow = 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);
return status;
}
/* find the time source */
status = fMediaRoster->GetTimeSource(&fTimeSourceNode);
if (status != B_OK) {
ErrorAlert("Can't get a time source", status);
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 input!", status);
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);
return B_ERROR;
}
/* register the node */
status = fMediaRoster->RegisterNode(fVideoConsumer);
if (status != B_OK) {
ErrorAlert("Can't register the video window", status);
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);
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);
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);
}
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;
}
}
//---------------------------------------------------------------
// Utility functions
//---------------------------------------------------------------
static void
ErrorAlert(const char * message, status_t err)
{
char msg[256];
sprintf(msg, "%s\n%s [%x]", message, strerror(err), err);
(new BAlert("", msg, "Quit"))->Go();
be_app->PostMessage(B_QUIT_REQUESTED);
}
//---------------------------------------------------------------
status_t
AddTranslationItems( BMenu * intoMenu, uint32 from_type)
{
BTranslatorRoster * use;
char * translator_type_name;
const char * translator_id_name;
use = BTranslatorRoster::Default();
translator_id_name = "be:translator";
translator_type_name = "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 == from_type) {
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 != from_type) {
BMessage * itemmsg;
itemmsg = new BMessage(msg_translate);
itemmsg->AddInt32(translator_id_name, ids[tix]);
itemmsg->AddInt32(translator_type_name, formats[oix].type);
intoMenu->AddItem(new BMenuItem(formats[oix].name, itemmsg));
}
}
}
delete[] ids;
return B_OK;
}
//---------------------------------------------------------------
// Video Window Class
//---------------------------------------------------------------
VideoWindow::VideoWindow (BRect frame, const char *title, window_type type, uint32 flags, port_id * consumerport) :
BWindow(frame,title,type,flags),
fView(NULL),
fVideoView(NULL),
fPortPtr(consumerport)
{
fFtpInfo.port = 0;
fFtpInfo.rate = 0x7fffffff;
fFtpInfo.imageFormat = 0;
fFtpInfo.translator = 0;
fFtpInfo.passiveFtp = true;
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");
AddChild(menuBar);
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 */
BRect aRect;
aRect = Frame();
aRect.OffsetTo(B_ORIGIN);
aRect.top += menuBar->Frame().Height() + 1;
fView = new BView(aRect, "Background View", B_FOLLOW_ALL, B_WILL_DRAW);
fView->SetViewColor(kViewGray);
AddChild(fView);
/* add some controls */
BuildCaptureControls(fView);
/* add another view to hold the video image */
aRect = BRect(0, 0, VIDEO_SIZE_X - 1, VIDEO_SIZE_Y - 1);
aRect.OffsetBy((WINDOW_SIZE_X - VIDEO_SIZE_X)/2, kYBuffer);
fVideoView = new BView(aRect, "Video View", B_FOLLOW_ALL, B_WILL_DRAW);
fView->AddChild(fVideoView);
Show();
}
//---------------------------------------------------------------
VideoWindow::~VideoWindow()
{
QuitSettings();
}
//---------------------------------------------------------------
bool
VideoWindow::QuitRequested()
{
be_app->PostMessage(B_QUIT_REQUESTED);
return false;
}
//---------------------------------------------------------------
void
VideoWindow::MessageReceived(BMessage *message)
{
BControl *p;
uint32 index;
p = NULL;
message->FindPointer((const char *)"source",(void **)&p);
switch (message->what)
{
case msg_filename:
if (p != NULL)
{
strncpy(fFtpInfo.fileNameText, ((BTextControl *)p)->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_server:
if (p != NULL)
{
strncpy(fFtpInfo.serverText, ((BTextControl *)p)->Text(), 64);
FTPINFO("server = '%s'\n", fFtpInfo.serverText);
}
break;
case msg_login:
if (p != NULL)
{
strncpy(fFtpInfo.loginText, ((BTextControl *)p)->Text(), 64);
FTPINFO("login = '%s'\n", fFtpInfo.loginText);
}
break;
case msg_password:
if (p != NULL)
{
strncpy(fFtpInfo.passwordText, ((BTextControl *)p)->Text(), 64);
FTPINFO("password = '%s'\n", fFtpInfo.passwordText);
if (Lock())
{
((BTextControl *)p)->SetText("<HIDDEN>");
Unlock();
}
}
break;
case msg_directory:
if (p != NULL)
{
strncpy(fFtpInfo.directoryText, ((BTextControl *)p)->Text(), 64);
FTPINFO("directory = '%s'\n", fFtpInfo.directoryText);
}
break;
case msg_passiveftp:
if (p != NULL)
{
fFtpInfo.passiveFtp = ((BCheckBox *)p)->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)
{
BRect aFrame, theFrame;
theFrame = theView->Bounds();
theFrame.top += VIDEO_SIZE_Y + 2*kYBuffer + 40;
theFrame.left += kXBuffer;
theFrame.right -= (WINDOW_SIZE_X/2 + 5);
theFrame.bottom -= kXBuffer;
fCaptureSetupBox = new BBox( theFrame, "Capture Controls", B_FOLLOW_ALL, B_WILL_DRAW);
fCaptureSetupBox->SetLabel("Capture Controls");
theView->AddChild(fCaptureSetupBox);
aFrame = fCaptureSetupBox->Bounds();
aFrame.InsetBy(kXBuffer,kYBuffer);
aFrame.top += kYBuffer/2;
aFrame.bottom = aFrame.top + kMenuHeight;
fFileName = new BTextControl(aFrame, "File Name", "File Name:", fFilenameSetting->Value(), new BMessage(msg_filename));
fFileName->SetTarget(BMessenger(NULL, this));
fFileName->SetDivider(fFileName->Divider() - 30);
fCaptureSetupBox->AddChild(fFileName);
aFrame.top = aFrame.bottom + kYBuffer;
aFrame.bottom = aFrame.top + kMenuHeight;
fImageFormatMenu = new BPopUpMenu("Image Format Menu");
AddTranslationItems(fImageFormatMenu, B_TRANSLATOR_BITMAP);
fImageFormatMenu->SetTargetForItems(this);
if (fImageFormatMenu->FindItem("JPEG Image") != NULL)
fImageFormatMenu->FindItem("JPEG Image")->SetMarked(true);
else
fImageFormatMenu->ItemAt(0)->SetMarked(true);
fImageFormatSelector = new BMenuField(aFrame, "Format", "Format:", fImageFormatMenu);
fImageFormatSelector->SetDivider(fImageFormatSelector->Divider() - 30);
fCaptureSetupBox->AddChild(fImageFormatSelector);
aFrame.top = aFrame.bottom + kYBuffer;
aFrame.bottom = aFrame.top + kMenuHeight;
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(aFrame, "Rate", "Rate:", fCaptureRateMenu);
fCaptureRateSelector->SetDivider(fCaptureRateSelector->Divider() - 30);
fCaptureSetupBox->AddChild(fCaptureRateSelector);
aFrame = theView->Bounds();
aFrame.top += VIDEO_SIZE_Y + 2*kYBuffer + 40;
aFrame.left += WINDOW_SIZE_X/2 + 5;
aFrame.right -= kXBuffer;
aFrame.bottom -= kYBuffer;
fFtpSetupBox = new BBox( aFrame, "Ftp Setup", B_FOLLOW_ALL, B_WILL_DRAW);
fFtpSetupBox->SetLabel("Ftp Setup");
theView->AddChild(fFtpSetupBox);
aFrame = fFtpSetupBox->Bounds();
aFrame.InsetBy(kXBuffer,kYBuffer);
aFrame.top += kYBuffer/2;
aFrame.bottom = aFrame.top + kMenuHeight;
aFrame.right = aFrame.left + 160;
fServerName = new BTextControl(aFrame, "Server", "Server:", fServerSetting->Value(), new BMessage(msg_server));
fServerName->SetTarget(this);
fServerName->SetDivider(fServerName->Divider() - 30);
fFtpSetupBox->AddChild(fServerName);
aFrame.top = aFrame.bottom + kYBuffer;
aFrame.bottom = aFrame.top + kMenuHeight;
fLoginId = new BTextControl(aFrame, "Login", "Login:", fLoginSetting->Value(), new BMessage(msg_login));
fLoginId->SetTarget(this);
fLoginId->SetDivider(fLoginId->Divider() - 30);
fFtpSetupBox->AddChild(fLoginId);
aFrame.top = aFrame.bottom + kYBuffer;
aFrame.bottom = aFrame.top + kMenuHeight;
fPassword = new BTextControl(aFrame, "Password", "Password:", fPasswordSetting->Value(), new BMessage(msg_password));
fPassword->SetTarget(this);
fPassword->SetDivider(fPassword->Divider() - 30);
fFtpSetupBox->AddChild(fPassword);
aFrame.top = aFrame.bottom + kYBuffer;
aFrame.bottom = aFrame.top + kMenuHeight;
fDirectory = new BTextControl(aFrame, "Directory", "Directory:", fDirectorySetting->Value(), new BMessage(msg_directory));
fDirectory->SetTarget(this);
fDirectory->SetDivider(fDirectory->Divider() - 30);
fFtpSetupBox->AddChild(fDirectory);
aFrame.top = aFrame.bottom + kYBuffer;
aFrame.bottom = aFrame.top + kMenuHeight;
fPassiveFtp = new BCheckBox(aFrame, "Passive ftp", "Passive ftp", new BMessage(msg_passiveftp));
fPassiveFtp->SetTarget(this);
fPassiveFtp->SetValue(fPassiveFtpSetting->Value());
fFtpSetupBox->AddChild(fPassiveFtp);
aFrame = theView->Bounds();
aFrame.top += VIDEO_SIZE_Y + 2*kYBuffer;
aFrame.left += kXBuffer;
aFrame.right -= kXBuffer;
aFrame.bottom = aFrame.top + kMenuHeight + 2*kYBuffer;
fStatusBox = new BBox( aFrame, "Status", B_FOLLOW_ALL, B_WILL_DRAW);
fStatusBox->SetLabel("Status");
theView->AddChild(fStatusBox);
aFrame = fStatusBox->Bounds();
aFrame.InsetBy(kXBuffer,kYBuffer);
fStatusLine = new BStringView(aFrame,"Status Line","Waiting ...");
fStatusBox->AddChild(fStatusLine);
}
//---------------------------------------------------------------
void
VideoWindow::ApplyControls()
{
// apply controls
fFileName->Invoke();
PostMessage(fImageFormatMenu->FindMarked()->Message());
PostMessage(fCaptureRateMenu->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(fCaptureRateSetting = new EnumeratedStringValueSetting("CaptureRate", "Every 5 minutes", kCaptureRate,
"capture rate expected", "unrecognized capture rate 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());
fCaptureRateSetting->ValueChanged(fCaptureRateMenu->FindMarked()->Label());
fSettings->SaveSettings();
delete fSettings;
}
//---------------------------------------------------------------
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;
BView * panel = 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;
}

181
src/prefs/codycam/CodyCam.h Normal file
View File

@ -0,0 +1,181 @@
/* CodyCam.h */
#ifndef CODYCAM_H
#define CODYCAM_H
#include <Box.h>
#include <Menu.h>
#include <string.h>
#include <Window.h>
#include <CheckBox.h>
#include <MenuField.h>
#include <StringView.h>
#include <Application.h>
#include <TextControl.h>
#include "Settings.h"
#include"VideoConsumer.h"
enum {
msg_filename = 'file',
msg_rate_15s = 'r15s',
msg_rate_30s = 'r30s',
msg_rate_1m = 'r1m ',
msg_rate_5m = 'r5m ',
msg_rate_10m = 'r10m',
msg_rate_15m = 'r15m',
msg_rate_30m = 'r30m',
msg_rate_1h = 'r1h ',
msg_rate_2h = 'r2h ',
msg_rate_4h = 'r4h ',
msg_rate_8h = 'r8h ',
msg_rate_24h = 'r24h',
msg_rate_never = 'nevr',
msg_translate = 'tran',
msg_server = 'srvr',
msg_login = 'lgin',
msg_password = 'pswd',
msg_directory = 'drct',
msg_passiveftp = 'pasv',
msg_pswrd_text = 'pstx',
msg_start = 'strt',
msg_stop = 'stop',
msg_about = 'abut',
msg_setup = 'setp',
msg_video = 'vdeo',
msg_control_win = 'ctlw'
};
const char *kCaptureRate[] = {
"Every 15 seconds",
"Every 30 seconds",
"Every minute",
"Every 5 minutes",
"Every 10 minutes",
"Every 15 minutes",
"Every 30 minutes",
"Every hour",
"Every 2 hours",
"Every 4 hours",
"Every 8 hours",
"Every 24 hours",
"Never",
0
};
class CodyCam : public BApplication {
public:
CodyCam();
virtual ~CodyCam();
void ReadyToRun();
virtual bool QuitRequested();
virtual void MessageReceived(
BMessage *message);
private:
status_t SetUpNodes();
void TearDownNodes();
BMediaRoster * fMediaRoster;
media_node fTimeSourceNode;
media_node fProducerNode;
VideoConsumer * fVideoConsumer;
media_output fProducerOut;
media_input fConsumerIn;
BWindow * fWindow;
port_id fPort;
BWindow *mVideoControlWindow;
};
class VideoWindow : public BWindow
{
public:
VideoWindow (
BRect frame,
const char * title,
window_type type,
uint32 flags,
port_id * consumerport);
~VideoWindow();
virtual bool QuitRequested();
virtual void MessageReceived(
BMessage *message);
void ApplyControls();
BView * VideoView();
BStringView * StatusLine();
private:
void BuildCaptureControls(
BView *theView);
void SetUpSettings(
const char *filename,
const char *dirname);
void QuitSettings();
private:
media_node * fProducer;
port_id * fPortPtr;
BView * fView;
BView * fVideoView;
BTextControl * fFileName;
BBox * fCaptureSetupBox;
BMenu * fCaptureRateMenu;
BMenuField * fCaptureRateSelector;
BMenu * fImageFormatMenu;
BMenuField * fImageFormatSelector;
BBox * fFtpSetupBox;
BTextControl * fServerName;
BTextControl * fLoginId;
BTextControl * fPassword;
BTextControl * fDirectory;
BCheckBox * fPassiveFtp;
BBox * fStatusBox;
BStringView * fStatusLine;
ftp_msg_info fFtpInfo;
Settings * fSettings;
StringValueSetting * fServerSetting;
StringValueSetting * fLoginSetting;
StringValueSetting * fPasswordSetting;
StringValueSetting * fDirectorySetting;
BooleanValueSetting * fPassiveFtpSetting;
StringValueSetting * fFilenameSetting;
EnumeratedStringValueSetting *fCaptureRateSetting;
};
class ControlWindow : public BWindow {
public:
ControlWindow(const BRect & frame, BView * controls, media_node node);
void MessageReceived(BMessage * message);
bool QuitRequested();
private:
BView * fView;
media_node fNode;
};
#endif

View File

@ -0,0 +1,739 @@
#include "FtpClient.h"
FtpClient::FtpClient()
{
m_control = 0;
m_state = 0;
m_data = 0;
}
FtpClient::~FtpClient()
{
delete m_control;
delete m_data;
}
bool FtpClient::cd(const string &dir)
{
bool rc = false;
int code, codetype;
string cmd = "CWD ", replystr;
cmd += dir;
if(dir.length() == 0)
cmd += '/';
if(p_sendRequest(cmd) == true)
{
if(p_getReply(replystr, code, codetype) == true)
{
if(codetype == 2)
rc = true;
}
}
return rc;
}
bool FtpClient::ls(string &listing)
{
bool rc = false;
string cmd, replystr;
int code, codetype, i, numread;
char buf[513];
cmd = "TYPE A";
if(p_sendRequest(cmd))
p_getReply(replystr, code, codetype);
if(p_openDataConnection())
{
cmd = "LIST";
if(p_sendRequest(cmd))
{
if(p_getReply(replystr, code, codetype))
{
if(codetype <= 2)
{
if(p_acceptDataConnection())
{
numread = 1;
while(numread > 0)
{
memset(buf, 0, sizeof(buf));
numread = m_data->Receive(buf, sizeof(buf) - 1);
listing += buf;
printf(buf);
}
if(p_getReply(replystr, code, codetype))
{
if(codetype <= 2)
{
rc = true;
}
}
}
}
}
}
}
delete m_data;
m_data = 0;
return rc;
}
bool FtpClient::pwd(string &dir)
{
bool rc = false;
int code, codetype;
string cmd = "PWD", replystr;
long i;
if(p_sendRequest(cmd) == true)
{
if(p_getReply(replystr, code, codetype) == true)
{
if(codetype == 2)
{
i = replystr.find('"');
if(i != -1)
{
i++;
dir = replystr.substr(i, replystr.find('"') - i);
rc = true;
}
}
}
}
return rc;
}
bool FtpClient::connect(const string &server, const string &login, const string &passwd)
{
bool rc = false;
int code, codetype;
string cmd, replystr;
BNetAddress addr;
delete m_control;
delete m_data;
m_control = new BNetEndpoint;
if(m_control->InitCheck() != B_NO_ERROR)
return false;
addr.SetTo(server.c_str(), "tcp", "ftp");
if(m_control->Connect(addr) == B_NO_ERROR)
{
//
// read the welcome message, do the login
//
if(p_getReply(replystr, code, codetype))
{
if(code != 421 && codetype != 5)
{
cmd = "USER "; cmd += login;
p_sendRequest(cmd);
if(p_getReply(replystr, code, codetype))
{
switch(code)
{
case 230:
case 202:
rc = true;
break;
case 331: // password needed
cmd = "PASS "; cmd += passwd;
p_sendRequest(cmd);
if(p_getReply(replystr, code, codetype))
{
if(codetype == 2)
{
rc = true;
}
}
break;
default:
break;
}
}
}
}
}
if(rc == true)
{
p_setState(ftp_connected);
} else {
delete m_control;
m_control = 0;
}
return rc;
}
bool FtpClient::putFile(const string &local, const string &remote, ftp_mode mode)
{
bool rc = false;
string cmd, replystr;
int code, codetype, rlen, slen, i;
BFile infile(local.c_str(), B_READ_ONLY);
char buf[8192], sbuf[16384], *stmp;
if(infile.InitCheck() != B_NO_ERROR)
return false;
if(mode == binary_mode)
cmd = "TYPE I";
else
cmd = "TYPE A";
if(p_sendRequest(cmd))
p_getReply(replystr, code, codetype);
try
{
if(p_openDataConnection())
{
cmd = "STOR ";
cmd += remote;
if(p_sendRequest(cmd))
{
if(p_getReply(replystr, code, codetype))
{
if(codetype <= 2)
{
if(p_acceptDataConnection())
{
rlen = 1;
while(rlen > 0)
{
memset(buf, 0, sizeof(buf));
memset(sbuf, 0, sizeof(sbuf));
rlen = infile.Read((void *) buf, sizeof(buf));
slen = rlen;
stmp = buf;
if(mode == ascii_mode)
{
stmp = sbuf;
slen = 0;
for(i=0;i<rlen;i++)
{
if(buf[i] == '\n')
{
*stmp = '\r';
stmp++;
slen++;
}
*stmp = buf[i];
stmp++;
slen++;
}
stmp = sbuf;
}
if(slen > 0)
{
if(m_data->Send(stmp, slen) < 0)
throw "bail";
}
}
rc = true;
}
}
}
}
}
}
catch(const char *errstr)
{
}
delete m_data;
m_data = 0;
if(rc == true)
{
p_getReply(replystr, code, codetype);
rc = (bool) codetype <= 2;
}
return rc;
}
bool FtpClient::getFile(const string &remote, const string &local, ftp_mode mode)
{
bool rc = false;
string cmd, replystr;
int code, codetype, rlen, slen, i;
BFile outfile(local.c_str(), B_READ_WRITE | B_CREATE_FILE);
char buf[8192], sbuf[16384], *stmp;
bool writeerr = false;
if(outfile.InitCheck() != B_NO_ERROR)
return false;
if(mode == binary_mode)
cmd = "TYPE I";
else
cmd = "TYPE A";
if(p_sendRequest(cmd))
p_getReply(replystr, code, codetype);
if(p_openDataConnection())
{
cmd = "RETR ";
cmd += remote;
if(p_sendRequest(cmd))
{
if(p_getReply(replystr, code, codetype))
{
if(codetype <= 2)
{
if(p_acceptDataConnection())
{
rlen = 1;
rc = true;
while(rlen > 0)
{
memset(buf, 0, sizeof(buf));
memset(sbuf, 0, sizeof(sbuf));
rlen = m_data->Receive(buf, sizeof(buf));
if(rlen > 0)
{
slen = rlen;
stmp = buf;
if(mode == ascii_mode)
{
stmp = sbuf;
slen = 0;
for(i=0;i<rlen;i++)
{
if(buf[i] == '\r')
{
i++;
}
*stmp = buf[i];
stmp++;
slen++;
}
stmp = sbuf;
}
if(slen > 0)
{
if(outfile.Write(stmp, slen) < 0)
{
writeerr = true;
}
}
}
}
}
}
}
}
}
delete m_data;
m_data = 0;
if(rc == true)
{
p_getReply(replystr, code, codetype);
rc = (bool) ((codetype <= 2) && (writeerr == false));
}
return rc;
}
//
// Note: this only works for local remote moves, cross filesystem moves
// will not work
//
bool FtpClient::moveFile(const string &oldpath, const string &newpath)
{
bool rc = false;
string from = "RNFR ";
string to = "RNTO ";
string replystr;
int code, codetype;
from += oldpath;
to += newpath;
if(p_sendRequest(from))
{
if(p_getReply(replystr, code, codetype))
{
if(codetype == 3)
{
if(p_sendRequest(to))
{
if(p_getReply(replystr, code, codetype))
{
if(codetype == 2)
rc = true;
}
}
}
}
}
return rc;
}
void FtpClient::setPassive(bool on)
{
if(on)
p_setState(ftp_passive);
else
p_clearState(ftp_passive);
}
bool FtpClient::p_testState(unsigned long state)
{
return (bool) ((m_state & state) != 0);
}
void FtpClient::p_setState(unsigned long state)
{
m_state |= state;
}
void FtpClient::p_clearState(unsigned long state)
{
m_state &= ~state;
}
bool FtpClient::p_sendRequest(const string &cmd)
{
bool rc = false;
string ccmd = cmd;
if(m_control != 0)
{
if(cmd.find("PASS") != -1)
printf("PASS <suppressed> (real password sent)\n");
else
printf("%s\n", ccmd.c_str());
ccmd += "\r\n";
if(m_control->Send(ccmd.c_str(), ccmd.length()) >= 0)
{
rc = true;
}
}
return rc;
}
bool FtpClient::p_getReplyLine(string &line)
{
bool rc = false;
int c = 0;
bool done = false;
line = ""; // Thanks to Stephen van Egmond for catching a bug here
if(m_control != 0)
{
rc = true;
while(done == false && (m_control->Receive(&c, 1) > 0))
{
if(c == EOF || c == xEOF || c == '\n')
{
done = true;
} else {
if(c == IAC)
{
m_control->Receive(&c, 1);
switch(c)
{
unsigned char treply[3];
case WILL:
case WONT:
m_control->Receive(&c, 1);
treply[0] = IAC;
treply[1] = DONT;
treply[2] = c;
m_control->Send(treply, 3);
break;
case DO:
case DONT:
m_control->Receive(&c, 1);
m_control->Receive(&c, 1);
treply[0] = IAC;
treply[1] = WONT;
treply[2] = c;
m_control->Send(treply, 3);
break;
case EOF:
case xEOF:
done = true;
break;
default:
line += c;
break;
}
} else {
//
// normal char
//
if(c != '\r')
line += c;
}
}
}
}
return rc;
}
bool FtpClient::p_getReply(string &outstr, int &outcode, int &codetype)
{
bool rc = false;
string line, tempstr;
//
// comment from the ncftp source:
//
/* RFC 959 states that a reply may span multiple lines. A single
* line message would have the 3-digit code <space> then the msg.
* A multi-line message would have the code <dash> and the first
* line of the msg, then additional lines, until the last line,
* which has the code <space> and last line of the msg.
*
* For example:
* 123-First line
* Second line
* 234 A line beginning with numbers
* 123 The last line
*/
if((rc = p_getReplyLine(line)) == true)
{
outstr = line;
outstr += '\n';
printf(outstr.c_str());
tempstr = line.substr(0, 3);
outcode = atoi(tempstr.c_str());
if(line[3] == '-')
{
while((rc = p_getReplyLine(line)) == true)
{
outstr += line;
outstr += '\n';
printf(outstr.c_str());
//
// we're done with nnn when we get to a "nnn blahblahblah"
//
if((line.find(tempstr) == 0) && line[3] == ' ')
break;
}
}
}
if(rc == false && outcode != 421)
{
outstr += "Remote host has closed the connection.\n";
outcode = 421;
}
if(outcode == 421)
{
delete m_control;
m_control = 0;
p_clearState(ftp_connected);
}
codetype = outcode / 100;
return rc;
}
bool FtpClient::p_openDataConnection()
{
string host, cmd, repstr;
unsigned short port;
BNetAddress addr;
int i, code, codetype;
char buf[32];
bool rc = false;
struct sockaddr_in sa;
delete m_data;
m_data = 0;
m_data = new BNetEndpoint;
if(p_testState(ftp_passive))
{
//
// Here we send a "pasv" command and connect to the remote server
// on the port it sends back to us
//
cmd = "PASV";
if(p_sendRequest(cmd))
{
if(p_getReply(repstr, code, codetype))
{
if(codetype == 2)
{
// It should give us something like:
// "227 Entering Passive Mode (192,168,1,1,10,187)"
int paddr[6];
unsigned char ucaddr[6];
i = repstr.find('(');
i++;
repstr = repstr.substr(i, repstr.find(')') - i);
if (sscanf(repstr.c_str(), "%d,%d,%d,%d,%d,%d",
&paddr[0], &paddr[1], &paddr[2], &paddr[3],
&paddr[4], &paddr[5]) != 6)
{
//
// cannot do passive. Do a little harmless rercursion here
//
p_clearState(ftp_passive);
return p_openDataConnection();
}
for(i=0;i<6;i++)
{
ucaddr[i] = (unsigned char) (paddr[i] & 0xff);
}
memcpy(&sa.sin_addr, &ucaddr[0], (size_t) 4);
memcpy(&sa.sin_port, &ucaddr[4], (size_t) 2);
addr.SetTo(sa);
if(m_data->Connect(addr) == B_NO_ERROR)
{
rc = true;
}
}
}
} else {
//
// cannot do passive. Do a little harmless rercursion here
//
p_clearState(ftp_passive);
rc = p_openDataConnection();
}
} else {
//
// Here we bind to a local port and send a PORT command
//
if(m_data->Bind() == B_NO_ERROR)
{
char buf[255];
m_data->Listen();
addr = m_data->LocalAddr();
addr.GetAddr(buf, &port);
host = buf;
i=0;
while(i >= 0)
{
i = host.find('.', i);
if(i >= 0)
host[i] = ',';
}
sprintf(buf, ",%d,%d", (port & 0xff00) >> 8, port & 0x00ff);
cmd = "PORT ";
cmd += host; cmd += buf;
p_sendRequest(cmd);
p_getReply(repstr, code, codetype);
//
// PORT failure is in the 500-range
//
if(codetype == 2)
rc = true;
}
}
return rc;
}
bool FtpClient::p_acceptDataConnection()
{
BNetEndpoint *ep;
bool rc = false;
if(p_testState(ftp_passive) == false)
{
if(m_data != 0)
{
ep = m_data->Accept();
if(ep != 0)
{
delete m_data;
m_data = ep;
rc = true;
}
}
} else {
rc = true;
}
return rc;
}

View File

@ -0,0 +1,60 @@
#include <string>
#include <File.h>
#include <stdio.h>
#include <NetworkKit.h>
class FtpClient
{
public:
FtpClient();
~FtpClient();
enum ftp_mode
{
binary_mode,
ascii_mode
};
bool connect(const string &server, const string &login, const string &passwd);
bool putFile(const string &local, const string &remote, ftp_mode mode = binary_mode);
bool getFile(const string &remote, const string &local, ftp_mode mode = binary_mode);
bool moveFile(const string &oldpath, const string &newpath);
bool cd(const string &dir);
bool pwd(string &dir);
bool ls(string &listing);
void setPassive(bool on);
protected:
enum {
ftp_complete = 1UL,
ftp_connected = 2,
ftp_passive = 4
};
unsigned long m_state;
bool p_testState(unsigned long state);
void p_setState(unsigned long state);
void p_clearState(unsigned long state);
bool p_sendRequest(const string &cmd);
bool p_getReply(string &outstr, int &outcode, int &codetype);
bool p_getReplyLine(string &line);
bool p_openDataConnection();
bool p_acceptDataConnection();
BNetEndpoint *m_control;
BNetEndpoint *m_data;
};
/*
* Definitions for the TELNET protocol. Snarfed from the BSD source.
*/
#define IAC 255
#define DONT 254
#define DO 253
#define WONT 252
#define WILL 251
#define xEOF 236

View File

@ -0,0 +1,213 @@
#include <Debug.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "Settings.h"
Settings *settings = NULL;
// generic setting handler classes
StringValueSetting::StringValueSetting(const char *name, const char *defaultValue,
const char *valueExpectedErrorString, const char *wrongValueErrorString)
: SettingsArgvDispatcher(name),
defaultValue(defaultValue),
valueExpectedErrorString(valueExpectedErrorString),
wrongValueErrorString(wrongValueErrorString),
value(strdup(defaultValue))
{
}
StringValueSetting::~StringValueSetting()
{
free(value);
}
void
StringValueSetting::ValueChanged(const char *newValue)
{
if (newValue == value)
// guard against self assingment
return;
free(value);
value = strdup(newValue);
}
const char *
StringValueSetting::Value() const
{
return value;
}
void
StringValueSetting::SaveSettingValue(Settings *settings)
{
printf("-------StringValueSetting::SaveSettingValue %s %s\n", Name(), value);
settings->Write("\"%s\"", value);
}
bool
StringValueSetting::NeedsSaving() const
{
// needs saving if different than default
return strcmp(value, defaultValue) != 0;
}
const char *
StringValueSetting::Handle(const char *const *argv)
{
if (!*++argv)
return valueExpectedErrorString;
ValueChanged(*argv);
return 0;
}
EnumeratedStringValueSetting::EnumeratedStringValueSetting(const char *name,
const char *defaultValue, const char *const *values, const char *valueExpectedErrorString,
const char *wrongValueErrorString)
: StringValueSetting(name, defaultValue, valueExpectedErrorString, wrongValueErrorString),
values(values)
{
}
void
EnumeratedStringValueSetting::ValueChanged(const char *newValue)
{
#if DEBUG
// must be one of the enumerated values
bool found = false;
for (int32 index = 0; ; index++) {
if (!values[index])
break;
if (strcmp(values[index], newValue) != 0)
continue;
found = true;
break;
}
ASSERT(found);
#endif
StringValueSetting::ValueChanged(newValue);
}
const char *
EnumeratedStringValueSetting::Handle(const char *const *argv)
{
if (!*++argv)
return valueExpectedErrorString;
printf("-----EnumeratedStringValueSetting::Handle %s %s\n", *(argv-1), *argv);
bool found = false;
for (int32 index = 0; ; index++) {
if (!values[index])
break;
if (strcmp(values[index], *argv) != 0)
continue;
found = true;
break;
}
if (!found)
return wrongValueErrorString;
ValueChanged(*argv);
return 0;
}
ScalarValueSetting::ScalarValueSetting(const char *name, int32 defaultValue,
const char *valueExpectedErrorString, const char *wrongValueErrorString,
int32 min, int32 max)
: SettingsArgvDispatcher(name),
defaultValue(defaultValue),
value(defaultValue),
max(max),
min(min),
valueExpectedErrorString(valueExpectedErrorString),
wrongValueErrorString(wrongValueErrorString)
{
}
void
ScalarValueSetting::ValueChanged(int32 newValue)
{
ASSERT(newValue > min);
ASSERT(newValue < max);
value = newValue;
}
int32
ScalarValueSetting::Value() const
{
return value;
}
void
ScalarValueSetting::GetValueAsString(char *buffer) const
{
sprintf(buffer, "%ld", value);
}
const char *
ScalarValueSetting::Handle(const char *const *argv)
{
if (!*++argv)
return valueExpectedErrorString;
int32 newValue = atoi(*argv);
if (newValue < min || newValue > max)
return wrongValueErrorString;
value = newValue;
return 0;
}
void
ScalarValueSetting::SaveSettingValue(Settings *settings)
{
settings->Write("%d", value);
}
bool
ScalarValueSetting::NeedsSaving() const
{
return value != defaultValue;
}
BooleanValueSetting::BooleanValueSetting(const char *name, bool defaultValue )
: ScalarValueSetting(name, defaultValue, 0, 0)
{
}
bool
BooleanValueSetting::Value() const
{
return value;
}
const char *
BooleanValueSetting::Handle(const char *const *argv)
{
if (!*++argv)
return "or or off expected";
if (strcmp(*argv, "on") == 0)
value = true;
else if (strcmp(*argv, "off") == 0)
value = false;
else
return "or or off expected";
return 0;
}
void
BooleanValueSetting::SaveSettingValue(Settings *settings)
{
settings->Write(value ? "on" : "off");
}

View File

@ -0,0 +1,84 @@
#ifndef __SETTINGS__
#define __SETTINGS__
#include "SettingsHandler.h"
void SetUpSettings(char *filename);
void QuitSettings();
class StringValueSetting : public SettingsArgvDispatcher {
// simple string setting
public:
StringValueSetting(const char *name, const char *defaultValue,
const char *valueExpectedErrorString,
const char *wrongValueErrorString);
virtual ~StringValueSetting();
void ValueChanged(const char *newValue);
const char *Value() const;
virtual const char *Handle(const char *const *argv);
protected:
virtual void SaveSettingValue(Settings *);
virtual bool NeedsSaving() const;
const char *defaultValue;
const char *valueExpectedErrorString;
const char *wrongValueErrorString;
char *value;
};
class EnumeratedStringValueSetting : public StringValueSetting {
// string setting, values that do not match string enumeration
// are rejected
public:
EnumeratedStringValueSetting(const char *name, const char *defaultValue,
const char *const *values, const char *valueExpectedErrorString,
const char *wrongValueErrorString);
void ValueChanged(const char *newValue);
virtual const char *Handle(const char *const *argv);
protected:
const char *const *values;
char *value;
};
class ScalarValueSetting : public SettingsArgvDispatcher {
// simple int32 setting
public:
ScalarValueSetting(const char *name, int32 defaultValue,
const char *valueExpectedErrorString, const char *wrongValueErrorString,
int32 min = LONG_MIN, int32 max = LONG_MAX);
void ValueChanged(int32 newValue);
int32 Value() const;
void GetValueAsString(char *) const;
virtual const char *Handle(const char *const *argv);
protected:
virtual void SaveSettingValue(Settings *);
virtual bool NeedsSaving() const;
int32 defaultValue;
int32 value;
int32 max;
int32 min;
const char *valueExpectedErrorString;
const char *wrongValueErrorString;
};
class BooleanValueSetting : public ScalarValueSetting {
// on-off setting
public:
BooleanValueSetting(const char *name, bool defaultValue);
bool Value() const;
virtual const char *Handle(const char *const *argv);
protected:
virtual void SaveSettingValue(Settings *);
};
#endif

View File

@ -0,0 +1,427 @@
#include <Directory.h>
#include <Entry.h>
#include <FindDirectory.h>
#include <File.h>
#include <Path.h>
#include <StopWatch.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <Debug.h>
#include "SettingsHandler.h"
ArgvParser::ArgvParser(const char *name)
: file(0),
buffer(0),
pos(-1),
argc(0),
currentArgv(0),
currentArgsPos(-1),
sawBackslash(false),
eatComment(false),
inDoubleQuote(false),
inSingleQuote(false),
lineNo(0),
fileName(name)
{
file = fopen(fileName, "r");
if (!file) {
PRINT(("Error opening %s\n", fileName));
return;
}
buffer = new char [kBufferSize];
currentArgv = new char * [1024];
}
ArgvParser::~ArgvParser()
{
delete [] buffer;
MakeArgvEmpty();
delete [] currentArgv;
if (file)
fclose(file);
}
void
ArgvParser::MakeArgvEmpty()
{
// done with current argv, free it up
for (int32 index = 0; index < argc; index++)
delete currentArgv[index];
argc = 0;
}
status_t
ArgvParser::SendArgv(ArgvHandler argvHandlerFunc, void *passThru)
{
if (argc) {
NextArgv();
currentArgv[argc] = 0;
const char *result = (argvHandlerFunc)(argc, currentArgv, passThru);
if (result)
printf("File %s; Line %ld # %s", fileName, lineNo, result);
MakeArgvEmpty();
if (result)
return B_ERROR;
}
return B_NO_ERROR;
}
void
ArgvParser::NextArgv()
{
if (sawBackslash) {
currentArgs[++currentArgsPos] = '\\';
sawBackslash = false;
}
currentArgs[++currentArgsPos] = '\0';
// terminate current arg pos
// copy it as a string to the current argv slot
currentArgv[argc] = new char [strlen(currentArgs) + 1];
strcpy(currentArgv[argc], currentArgs);
currentArgsPos = -1;
argc++;
}
void
ArgvParser::NextArgvIfNotEmpty()
{
if (!sawBackslash && currentArgsPos < 0)
return;
NextArgv();
}
char
ArgvParser::GetCh()
{
if (pos < 0 || buffer[pos] == 0) {
if (file == 0)
return EOF;
if (fgets(buffer, kBufferSize, file) == 0)
return EOF;
pos = 0;
}
return buffer[pos++];
}
status_t
ArgvParser::EachArgv(const char *name, ArgvHandler argvHandlerFunc, void *passThru)
{
ArgvParser parser(name);
return parser.EachArgvPrivate(name, argvHandlerFunc, passThru);
}
status_t
ArgvParser::EachArgvPrivate(const char *name, ArgvHandler argvHandlerFunc, void *passThru)
{
status_t result;
for (;;) {
char ch = GetCh();
if (ch == EOF) {
// done with file
if (inDoubleQuote || inSingleQuote) {
printf("File %s # unterminated quote at end of file\n", name);
result = B_ERROR;
break;
}
result = SendArgv(argvHandlerFunc, passThru);
break;
}
if (ch == '\n' || ch == '\r') {
// handle new line
eatComment = false;
if (!sawBackslash && (inDoubleQuote || inSingleQuote)) {
printf("File %s ; Line %ld # unterminated quote\n", name, lineNo);
result = B_ERROR;
break;
}
lineNo++;
if (sawBackslash) {
sawBackslash = false;
continue;
}
// end of line, flush all argv
result = SendArgv(argvHandlerFunc, passThru);
if (result != B_NO_ERROR)
break;
continue;
}
if (eatComment)
continue;
if (!sawBackslash) {
if (!inDoubleQuote && !inSingleQuote) {
if (ch == ';') {
// semicolon is a command separator, pass on the whole argv
result = SendArgv(argvHandlerFunc, passThru);
if (result != B_NO_ERROR)
break;
continue;
} else if (ch == '#') {
// ignore everything on this line after this character
eatComment = true;
continue;
} else if (ch == ' ' || ch == '\t') {
// space or tab separates the individual arg strings
NextArgvIfNotEmpty();
continue;
} else if (!sawBackslash && ch == '\\') {
// the next character is escaped
sawBackslash = true;
continue;
}
}
if (!inSingleQuote && ch == '"') {
// enter/exit double quote handling
inDoubleQuote = !inDoubleQuote;
continue;
}
if (!inDoubleQuote && ch == '\'') {
// enter/exit single quote handling
inSingleQuote = !inSingleQuote;
continue;
}
} else {
// we just pass through the escape sequence as is
currentArgs[++currentArgsPos] = '\\';
sawBackslash = false;
}
currentArgs[++currentArgsPos] = ch;
}
return result;
}
SettingsArgvDispatcher::SettingsArgvDispatcher(const char *name)
: name(name)
{
}
void
SettingsArgvDispatcher::SaveSettings(Settings *settings, bool onlyIfNonDefault)
{
if (!onlyIfNonDefault || NeedsSaving()) {
settings->Write("%s ", Name());
SaveSettingValue(settings);
settings->Write("\n");
}
}
bool
SettingsArgvDispatcher::HandleRectValue(BRect &result, const char *const *argv,
bool printError)
{
if (!*argv) {
if (printError)
printf("rect left expected");
return false;
}
result.left = atoi(*argv);
if (!*++argv) {
if (printError)
printf("rect top expected");
return false;
}
result.top = atoi(*argv);
if (!*++argv) {
if (printError)
printf("rect right expected");
return false;
}
result.right = atoi(*argv);
if (!*++argv) {
if (printError)
printf("rect bottom expected");
return false;
}
result.bottom = atoi(*argv);
return true;
}
void
SettingsArgvDispatcher::WriteRectValue(Settings *setting, BRect rect)
{
setting->Write("%d %d %d %d", (int32)rect.left, (int32)rect.top,
(int32)rect.right, (int32)rect.bottom);
}
#if 0
static int
CompareByNameOne(const SettingsArgvDispatcher *item1, const SettingsArgvDispatcher *item2)
{
return strcmp(item1->Name(), item2->Name());
}
#endif
Settings::Settings(const char *filename, const char *settingsDirName)
: fileName(filename),
settingsDir(settingsDirName),
list(0),
count(0),
listSize(30),
currentSettings(0)
{
#ifdef SINGLE_SETTING_FILE
settingsHandler = this;
#endif
list = (SettingsArgvDispatcher **)calloc(listSize, sizeof(SettingsArgvDispatcher *));
}
Settings::~Settings()
{
for (int32 index = 0; index < count; index++)
delete list[index];
free(list);
}
const char *
Settings::ParseUserSettings(int, const char *const *argv, void *castToThis)
{
if (!*argv)
return 0;
#ifdef SINGLE_SETTING_FILE
Settings *settings = settingsHandler;
#else
Settings *settings = (Settings *)castToThis;
#endif
SettingsArgvDispatcher *handler = settings->Find(*argv);
if (!handler)
return "unknown command";
return handler->Handle(argv);
}
#if 0
static int
Compare(const SettingsArgvDispatcher *p1, const SettingsArgvDispatcher *p2)
{
return strcmp(p1->Name(), p2->Name());
}
#endif
bool
Settings::Add(SettingsArgvDispatcher *setting)
{
// check for uniqueness
if (Find(setting->Name()))
return false;
if (count >= listSize) {
listSize += 30;
list = (SettingsArgvDispatcher **)realloc(list,
listSize * sizeof(SettingsArgvDispatcher *));
}
list[count++] = setting;
return true;
}
SettingsArgvDispatcher *
Settings::Find(const char *name)
{
for (int32 index = 0; index < count; index++)
if (strcmp(name, list[index]->Name()) == 0)
return list[index];
return 0;
}
void
Settings::TryReadingSettings()
{
BPath prefsPath;
if (find_directory(B_USER_SETTINGS_DIRECTORY, &prefsPath, true) == B_OK) {
prefsPath.Append(settingsDir);
BPath path(prefsPath);
path.Append(fileName);
ArgvParser::EachArgv(path.Path(), Settings::ParseUserSettings, this);
}
}
void
Settings::SaveSettings(bool onlyIfNonDefault)
{
ASSERT(SettingsHandler());
SettingsHandler()->SaveCurrentSettings(onlyIfNonDefault);
}
void
Settings::MakeSettingsDirectory(BDirectory *resultingSettingsDir)
{
BPath path;
if (find_directory(B_USER_SETTINGS_DIRECTORY, &path, true) != B_OK)
return;
// make sure there is a directory
path.Append(settingsDir);
mkdir(path.Path(), 0777);
resultingSettingsDir->SetTo(path.Path());
}
void
Settings::SaveCurrentSettings(bool onlyIfNonDefault)
{
BDirectory settingsDir;
MakeSettingsDirectory(&settingsDir);
if (settingsDir.InitCheck() != B_OK)
return;
printf("+++++++++++ Settings::SaveCurrentSettings %s\n", fileName);
// nuke old settings
BEntry entry(&settingsDir, fileName);
entry.Remove();
BFile prefs(&entry, O_RDWR | O_CREAT);
if (prefs.InitCheck() != B_OK)
return;
currentSettings = &prefs;
for (int32 index = 0; index < count; index++) {
list[index]->SaveSettings(this, onlyIfNonDefault);
}
currentSettings = 0;
}
void
Settings::Write(const char *format, ...)
{
va_list args;
va_start(args, format);
VSWrite(format, args);
va_end(args);
}
void
Settings::VSWrite(const char *format, va_list arg)
{
char buffer[2048];
vsprintf(buffer, format, arg);
ASSERT(currentSettings && currentSettings->InitCheck() == B_OK);
currentSettings->Write(buffer, strlen(buffer));
}
#ifdef SINGLE_SETTING_FILE
Settings *Settings::settingsHandler = 0;
#endif

View File

@ -0,0 +1,147 @@
#ifndef __SETTINGS_FILE__
#define __SETTINGS_FILE__
#include <SupportDefs.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
class BFile;
class BDirectory;
class Settings;
typedef const char *(*ArgvHandler)(int argc, const char *const *argv, void *params);
// return 0 or error string if parsing failed
const int32 kBufferSize = 1024;
class ArgvParser {
// this class opens a text file and passes the context in argv
// format to a specified handler
public:
static status_t EachArgv(const char *name,
ArgvHandler argvHandlerFunc, void *passThru);
private:
ArgvParser(const char *name);
~ArgvParser();
status_t EachArgvPrivate(const char *name,
ArgvHandler argvHandlerFunc, void *passThru);
char GetCh();
status_t SendArgv(ArgvHandler argvHandlerFunc, void *passThru);
// done with a whole line of argv, send it off and get ready
// to build a new one
void NextArgv();
// done with current string, get ready to start building next
void NextArgvIfNotEmpty();
// as above, don't commint current string if empty
void MakeArgvEmpty();
FILE *file;
char *buffer;
int32 pos;
int32 numAvail;
int argc;
char **currentArgv;
int32 currentArgsPos;
char currentArgs [1024];
bool sawBackslash;
bool eatComment;
bool inDoubleQuote;
bool inSingleQuote;
int32 lineNo;
const char *fileName;
};
class SettingsArgvDispatcher {
// base class for a single setting item
public:
SettingsArgvDispatcher(const char *name);
void SaveSettings(Settings *settings, bool onlyIfNonDefault);
const char *Name() const
{ return name; }
// name as it appears in the settings file
virtual const char *Handle(const char *const *argv) = 0;
// override this adding an argv parser that reads in the
// values in argv format for this setting
// return a pointer to an error message or null if parsed OK
// some handy reader/writer calls
bool HandleRectValue(BRect &, const char *const *argv, bool printError = true);
// static bool HandleColorValue(rgb_color &, const char *const *argv, bool printError = true);
void WriteRectValue(Settings *, BRect);
// void WriteColorValue(BRect);
protected:
virtual void SaveSettingValue(Settings *settings) = 0;
// override this to save the current value of this setting in a
// text format
virtual bool NeedsSaving() const
{ return true; }
// override to return false if current value is equal to the default
// and does not need saving
private:
const char *name;
};
class Settings {
// this class is a list of all the settings handlers, reads and
// saves the settings file
public:
Settings(const char *filename, const char *settingsDirName);
~Settings();
void TryReadingSettings();
void SaveSettings(bool onlyIfNonDefault = true);
#ifdef SINGLE_SETTING_FILE
static Settings *SettingsHandler()
{ return settingsHandler; }
#else
Settings *SettingsHandler()
{ return this; }
#endif
bool Add(SettingsArgvDispatcher *);
// return false if argv dispatcher with the same name already
// registered
void Write(const char *format, ...);
void VSWrite(const char *, va_list);
#ifdef SINGLE_SETTING_FILE
static Settings *settingsHandler;
#endif
private:
void MakeSettingsDirectory(BDirectory *);
SettingsArgvDispatcher *Find(const char *);
static const char *ParseUserSettings(int, const char *const *argv, void *);
void SaveCurrentSettings(bool onlyIfNonDefault);
const char *fileName;
const char *settingsDir;
SettingsArgvDispatcher **list;
int32 count;
int32 listSize;
BFile *currentSettings;
};
#endif

View File

@ -0,0 +1,808 @@
// Copyright (c) 1998-99, Be Incorporated, All Rights Reserved.
// SMS
// VideoConsumer.cpp
#include <View.h>
#include <stdio.h>
#include <fcntl.h>
#include <Buffer.h>
#include <unistd.h>
#include <string.h>
#include <NodeInfo.h>
#include <scheduler.h>
#include <TimeSource.h>
#include <StringView.h>
#include <MediaRoster.h>
#include <Application.h>
#include <BufferGroup.h>
#include "FtpClient.h"
#include "VideoConsumer.h"
#define M1 ((double)1000000.0)
#define JITTER 20000
#define FUNCTION printf
#define ERROR printf
#define PROGRESS printf
#define LOOP printf
static status_t SetFileType(BFile * file, int32 translator, uint32 type);
const media_raw_video_format vid_format = { 29.97,1,0,239,B_VIDEO_TOP_LEFT_RIGHT,1,1,{B_RGB16,320,240,320*4,0,0}};
//---------------------------------------------------------------
VideoConsumer::VideoConsumer(
const char * name,
BView *view,
BStringView * statusLine,
BMediaAddOn *addon,
const uint32 internal_id) :
BMediaNode(name),
BMediaEventLooper(),
BBufferConsumer(B_MEDIA_RAW_VIDEO),
mView(view),
mWindow(NULL),
mStatusLine(statusLine),
mInternalID(internal_id),
mAddOn(addon),
mTimeToFtp(false),
mFtpComplete(true),
mRate(1000000),
mImageFormat(0),
mTranslator(0),
mPassiveFtp(true),
mConnectionActive(false),
mMyLatency(20000),
mBuffers(NULL),
mOurBuffers(false)
{
FUNCTION("VideoConsumer::VideoConsumer\n");
AddNodeKind(B_PHYSICAL_OUTPUT);
SetEventLatency(0);
mWindow = mView->Window();
for (uint32 j = 0; j < 3; j++)
{
mBitmap[j] = NULL;
mBufferMap[j] = 0;
}
strcpy(mFileNameText, "");
strcpy(mServerText, "");
strcpy(mLoginText, "");
strcpy(mPasswordText, "");
strcpy(mDirectoryText, "");
SetPriority(B_DISPLAY_PRIORITY);
}
//---------------------------------------------------------------
VideoConsumer::~VideoConsumer()
{
FUNCTION("VideoConsumer::~VideoConsumer\n");
status_t status;
Quit();
if (mWindow)
{
printf("Locking the window\n");
if (mWindow->Lock())
{
printf("Closing the window\n");
mWindow->Close();
mWindow = 0;
}
}
// clean up ftp thread
// wait up to 30 seconds if ftp is in progress
int32 count = 0;
while (!mFtpComplete && (count < 30))
{
snooze(1000000);
count++;
}
if(count == 30)
kill_thread(mFtpThread);
DeleteBuffers();
}
/********************************
From BMediaNode
********************************/
//---------------------------------------------------------------
BMediaAddOn *
VideoConsumer::AddOn(long *cookie) const
{
FUNCTION("VideoConsumer::AddOn\n");
// do the right thing if we're ever used with an add-on
*cookie = mInternalID;
return mAddOn;
}
//---------------------------------------------------------------
// This implementation is required to get around a bug in
// the ppc compiler.
void
VideoConsumer::Start(bigtime_t performance_time)
{
BMediaEventLooper::Start(performance_time);
}
void
VideoConsumer::Stop(bigtime_t performance_time, bool immediate)
{
BMediaEventLooper::Stop(performance_time, immediate);
}
void
VideoConsumer::Seek(bigtime_t media_time, bigtime_t performance_time)
{
BMediaEventLooper::Seek(media_time, performance_time);
}
void
VideoConsumer::TimeWarp(bigtime_t at_real_time, bigtime_t to_performance_time)
{
BMediaEventLooper::TimeWarp(at_real_time, to_performance_time);
}
status_t
VideoConsumer::DeleteHook(BMediaNode *node)
{
return BMediaEventLooper::DeleteHook(node);
}
//---------------------------------------------------------------
void
VideoConsumer::NodeRegistered()
{
FUNCTION("VideoConsumer::NodeRegistered\n");
mIn.destination.port = ControlPort();
mIn.destination.id = 0;
mIn.source = media_source::null;
mIn.format.type = B_MEDIA_RAW_VIDEO;
mIn.format.u.raw_video = vid_format;
Run();
}
//---------------------------------------------------------------
status_t
VideoConsumer::RequestCompleted(const media_request_info & info)
{
FUNCTION("VideoConsumer::RequestCompleted\n");
switch(info.what)
{
case media_request_info::B_SET_OUTPUT_BUFFERS_FOR:
{
if (info.status != B_OK)
ERROR("VideoConsumer::RequestCompleted: Not using our buffers!\n");
}
break;
}
return B_OK;
}
//---------------------------------------------------------------
status_t
VideoConsumer::HandleMessage(int32 message, const void * data, size_t size)
{
//FUNCTION("VideoConsumer::HandleMessage\n");
ftp_msg_info *info = (ftp_msg_info *)data;
status_t status = B_OK;
switch (message)
{
case FTP_INFO:
PROGRESS("VideoConsumer::HandleMessage - FTP_INFO message\n");
mRate = info->rate;
mImageFormat = info->imageFormat;
mTranslator = info->translator;
mPassiveFtp = info->passiveFtp;
strcpy(mFileNameText, info->fileNameText);
strcpy(mServerText, info->serverText);
strcpy(mLoginText, info->loginText);
strcpy(mPasswordText, info->passwordText);
strcpy(mDirectoryText, info->directoryText);
// remove old user events
EventQueue()->FlushEvents(TimeSource()->Now(), BTimedEventQueue::B_ALWAYS, true, BTimedEventQueue::B_USER_EVENT);
if (mRate != B_INFINITE_TIMEOUT) {
// if rate is not "Never," push an event to restart captures 5 seconds from now
media_timed_event event(TimeSource()->Now() + 5000000, BTimedEventQueue::B_USER_EVENT);
EventQueue()->AddEvent(event);
}
break;
}
return status;
}
//---------------------------------------------------------------
void
VideoConsumer::BufferReceived(BBuffer * buffer)
{
LOOP("VideoConsumer::Buffer #%d received\n", buffer->ID());
if (RunState() == B_STOPPED)
{
buffer->Recycle();
return;
}
media_timed_event event(buffer->Header()->start_time, BTimedEventQueue::B_HANDLE_BUFFER,
buffer, BTimedEventQueue::B_RECYCLE_BUFFER);
EventQueue()->AddEvent(event);
}
//---------------------------------------------------------------
void
VideoConsumer::ProducerDataStatus(
const media_destination &for_whom,
int32 status,
bigtime_t at_media_time)
{
FUNCTION("VideoConsumer::ProducerDataStatus\n");
if (for_whom != mIn.destination)
return;
}
//---------------------------------------------------------------
status_t
VideoConsumer::CreateBuffers(
const media_format & with_format)
{
FUNCTION("VideoConsumer::CreateBuffers\n");
// delete any old buffers
DeleteBuffers();
status_t status = B_OK;
// create a buffer group
uint32 mXSize = with_format.u.raw_video.display.line_width;
uint32 mYSize = with_format.u.raw_video.display.line_count;
uint32 mRowBytes = with_format.u.raw_video.display.bytes_per_row;
color_space mColorspace = with_format.u.raw_video.display.format;
PROGRESS("VideoConsumer::CreateBuffers - Colorspace = %d\n", mColorspace);
mBuffers = new BBufferGroup();
status = mBuffers->InitCheck();
if (B_OK != status)
{
ERROR("VideoConsumer::CreateBuffers - ERROR CREATING BUFFER GROUP\n");
return status;
}
// and attach the bitmaps to the buffer group
for (uint32 j=0; j < 3; j++)
{
mBitmap[j] = new BBitmap(BRect(0, 0, (mXSize-1), (mYSize - 1)), mColorspace, false, true);
if (mBitmap[j]->IsValid())
{
buffer_clone_info info;
if ((info.area = area_for(mBitmap[j]->Bits())) == B_ERROR)
ERROR("VideoConsumer::CreateBuffers - ERROR IN AREA_FOR\n");;
info.offset = 0;
info.size = (size_t)mBitmap[j]->BitsLength();
info.flags = j;
info.buffer = 0;
if ((status = mBuffers->AddBuffer(info)) != B_OK)
{
ERROR("VideoConsumer::CreateBuffers - ERROR ADDING BUFFER TO GROUP\n");
return status;
} else PROGRESS("VideoConsumer::CreateBuffers - SUCCESSFUL ADD BUFFER TO GROUP\n");
}
else
{
ERROR("VideoConsumer::CreateBuffers - ERROR CREATING VIDEO RING BUFFER: %08x\n", status);
return B_ERROR;
}
}
BBuffer ** buffList = new BBuffer * [3];
for (int j = 0; j < 3; j++) buffList[j] = 0;
if ((status = mBuffers->GetBufferList(3, buffList)) == B_OK)
for (int j = 0; j < 3; j++)
if (buffList[j] != NULL)
{
mBufferMap[j] = (uint32) buffList[j];
PROGRESS(" j = %d buffer = %08x\n", j, mBufferMap[j]);
}
else
{
ERROR("VideoConsumer::CreateBuffers ERROR MAPPING RING BUFFER\n");
return B_ERROR;
}
else
ERROR("VideoConsumer::CreateBuffers ERROR IN GET BUFFER LIST\n");
FUNCTION("VideoConsumer::CreateBuffers - EXIT\n");
return status;
}
//---------------------------------------------------------------
void
VideoConsumer::DeleteBuffers()
{
FUNCTION("VideoConsumer::DeleteBuffers\n");
status_t status;
if (mBuffers)
{
delete mBuffers;
mBuffers = NULL;
for (uint32 j = 0; j < 3; j++)
if (mBitmap[j]->IsValid())
{
delete mBitmap[j];
mBitmap[j] = NULL;
}
}
FUNCTION("VideoConsumer::DeleteBuffers - EXIT\n");
}
//---------------------------------------------------------------
status_t
VideoConsumer::Connected(
const media_source & producer,
const media_destination & where,
const media_format & with_format,
media_input * out_input)
{
FUNCTION("VideoConsumer::Connected\n");
mIn.source = producer;
mIn.format = with_format;
mIn.node = Node();
sprintf(mIn.name, "Video Consumer");
*out_input = mIn;
uint32 user_data = 0;
int32 change_tag = 1;
if (CreateBuffers(with_format) == B_OK)
BBufferConsumer::SetOutputBuffersFor(producer, mDestination,
mBuffers, (void *)&user_data, &change_tag, true);
else
{
ERROR("VideoConsumer::Connected - COULDN'T CREATE BUFFERS\n");
return B_ERROR;
}
mFtpBitmap = new BBitmap(BRect(0, 0, 320-1, 240-1), B_RGB32, false, false);
mConnectionActive = true;
FUNCTION("VideoConsumer::Connected - EXIT\n");
return B_OK;
}
//---------------------------------------------------------------
void
VideoConsumer::Disconnected(
const media_source & producer,
const media_destination & where)
{
FUNCTION("VideoConsumer::Disconnected\n");
if (where == mIn.destination && producer == mIn.source)
{
// disconnect the connection
mIn.source = media_source::null;
delete mFtpBitmap;
mConnectionActive = false;
}
}
//---------------------------------------------------------------
status_t
VideoConsumer::AcceptFormat(
const media_destination & dest,
media_format * format)
{
FUNCTION("VideoConsumer::AcceptFormat\n");
if (dest != mIn.destination)
{
ERROR("VideoConsumer::AcceptFormat - BAD DESTINATION\n");
return B_MEDIA_BAD_DESTINATION;
}
if (format->type == B_MEDIA_NO_TYPE)
format->type = B_MEDIA_RAW_VIDEO;
if (format->type != B_MEDIA_RAW_VIDEO)
{
ERROR("VideoConsumer::AcceptFormat - BAD FORMAT\n");
return B_MEDIA_BAD_FORMAT;
}
if (format->u.raw_video.display.format != B_RGB32 &&
format->u.raw_video.display.format != B_RGB16 &&
format->u.raw_video.display.format != B_RGB15 &&
format->u.raw_video.display.format != B_GRAY8 &&
format->u.raw_video.display.format != media_raw_video_format::wildcard.display.format)
{
ERROR("AcceptFormat - not a format we know about!\n");
return B_MEDIA_BAD_FORMAT;
}
if (format->u.raw_video.display.format == media_raw_video_format::wildcard.display.format)
{
format->u.raw_video.display.format = B_RGB16;
}
char format_string[256];
string_for_format(*format, format_string, 256);
FUNCTION("VideoConsumer::AcceptFormat: %s\n", format_string);
return B_OK;
}
//---------------------------------------------------------------
status_t
VideoConsumer::GetNextInput(
int32 * cookie,
media_input * out_input)
{
FUNCTION("VideoConsumer::GetNextInput\n");
// custom build a destination for this connection
// put connection number in id
if (*cookie < 1)
{
mIn.node = Node();
mIn.destination.id = *cookie;
sprintf(mIn.name, "Video Consumer");
*out_input = mIn;
(*cookie)++;
return B_OK;
}
else
{
ERROR("VideoConsumer::GetNextInput - - BAD INDEX\n");
return B_MEDIA_BAD_DESTINATION;
}
}
//---------------------------------------------------------------
void
VideoConsumer::DisposeInputCookie(int32 /*cookie*/)
{
}
//---------------------------------------------------------------
status_t
VideoConsumer::GetLatencyFor(
const media_destination &for_whom,
bigtime_t * out_latency,
media_node_id * out_timesource)
{
FUNCTION("VideoConsumer::GetLatencyFor\n");
if (for_whom != mIn.destination)
return B_MEDIA_BAD_DESTINATION;
*out_latency = mMyLatency;
*out_timesource = TimeSource()->ID();
return B_OK;
}
//---------------------------------------------------------------
status_t
VideoConsumer::FormatChanged(
const media_source & producer,
const media_destination & consumer,
int32 from_change_count,
const media_format &format)
{
FUNCTION("VideoConsumer::FormatChanged\n");
if (consumer != mIn.destination)
return B_MEDIA_BAD_DESTINATION;
if (producer != mIn.source)
return B_MEDIA_BAD_SOURCE;
mIn.format = format;
return CreateBuffers(format);
}
//---------------------------------------------------------------
void
VideoConsumer::HandleEvent(
const media_timed_event *event,
bigtime_t lateness,
bool realTimeEvent)
{
LOOP("VideoConsumer::HandleEvent\n");
BBuffer *buffer;
switch (event->type)
{
case BTimedEventQueue::B_START:
PROGRESS("VideoConsumer::HandleEvent - START\n");
break;
case BTimedEventQueue::B_STOP:
PROGRESS("VideoConsumer::HandleEvent - STOP\n");
EventQueue()->FlushEvents(event->event_time, BTimedEventQueue::B_ALWAYS, true, BTimedEventQueue::B_HANDLE_BUFFER);
break;
case BTimedEventQueue::B_USER_EVENT:
PROGRESS("VideoConsumer::HandleEvent - USER EVENT\n");
if (RunState() == B_STARTED)
{
mTimeToFtp = true;
PROGRESS("Pushing user event for %.4f, time now %.4f\n", (event->event_time + mRate)/M1, event->event_time/M1);
media_timed_event newEvent(event->event_time + mRate, BTimedEventQueue::B_USER_EVENT);
EventQueue()->AddEvent(newEvent);
}
break;
case BTimedEventQueue::B_HANDLE_BUFFER:
LOOP("VideoConsumer::HandleEvent - HANDLE BUFFER\n");
buffer = (BBuffer *) event->pointer;
if (RunState() == B_STARTED && mConnectionActive)
{
// see if this is one of our buffers
uint32 index = 0;
mOurBuffers = true;
while(index < 3)
if ((uint32)buffer == mBufferMap[index])
break;
else
index++;
if (index == 3)
{
// no, buffers belong to consumer
mOurBuffers = false;
index = 0;
}
if (mFtpComplete && mTimeToFtp)
{
PROGRESS("VidConsumer::HandleEvent - SPAWNING FTP THREAD\n");
mTimeToFtp = false;
mFtpComplete = false;
memcpy(mFtpBitmap->Bits(), buffer->Data(),mFtpBitmap->BitsLength());
mFtpThread = spawn_thread(FtpRun, "Video Window Ftp", B_NORMAL_PRIORITY, this);
resume_thread(mFtpThread);
}
if ( (RunMode() == B_OFFLINE) ||
((TimeSource()->Now() > (buffer->Header()->start_time - JITTER)) &&
(TimeSource()->Now() < (buffer->Header()->start_time + JITTER))) )
{
if (!mOurBuffers)
// not our buffers, so we need to copy
memcpy(mBitmap[index]->Bits(), buffer->Data(),mBitmap[index]->BitsLength());
if (mWindow->Lock())
{
uint32 flags;
if ((mBitmap[index]->ColorSpace() == B_GRAY8) &&
!bitmaps_support_space(mBitmap[index]->ColorSpace(), &flags))
{
// handle mapping of GRAY8 until app server knows how
uint32 *start = (uint32 *)mBitmap[index]->Bits();
int32 size = mBitmap[index]->BitsLength();
uint32 *end = start + size/4;
for (uint32 *p = start; p < end; p++)
*p = (*p >> 3) & 0x1f1f1f1f;
}
mView->DrawBitmap(mBitmap[index]);
mWindow->Unlock();
}
}
else
PROGRESS("VidConsumer::HandleEvent - DROPPED FRAME\n");
buffer->Recycle();
}
else
buffer->Recycle();
break;
default:
ERROR("VideoConsumer::HandleEvent - BAD EVENT\n");
break;
}
}
//---------------------------------------------------------------
status_t
VideoConsumer::FtpRun(void * data)
{
FUNCTION("VideoConsumer::FtpRun\n");
((VideoConsumer *)data)->FtpThread();
return 0;
}
//---------------------------------------------------------------
void
VideoConsumer::FtpThread()
{
FUNCTION("VideoConsumer::FtpThread\n");
if (LocalSave(mFileNameText, mFtpBitmap) == B_OK)
FtpSave(mFileNameText);
#if 0
// save a small version, too
BBitmap * b = new BBitmap(BRect(0,0,159,119), B_RGB32, true, false);
BView * v = new BView(BRect(0,0,159,119), "SmallView 1", 0, B_WILL_DRAW);
b->AddChild(v);
b->Lock();
v->DrawBitmap(mFtpBitmap, v->Frame());
v->Sync();
b->Unlock();
if (LocalSave("small.jpg", b) == B_OK)
FtpSave("small.jpg");
delete b;
#endif
mFtpComplete = true;
}
//---------------------------------------------------------------
void
VideoConsumer::UpdateFtpStatus(char *status)
{
printf("FTP STATUS: %s\n",status);
if (mView->Window()->Lock())
{
mStatusLine->SetText(status);
mView->Window()->Unlock();
}
}
//---------------------------------------------------------------
status_t
VideoConsumer::LocalSave(char *filename, BBitmap *bitmap)
{
BFile *output;
UpdateFtpStatus("Capturing Image ...");
/* save a local copy of the image in the requested format */
output =new BFile();
if (output->SetTo(filename, B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE) == B_NO_ERROR)
{
BBitmapStream input(bitmap);
status_t err = BTranslatorRoster::Default()->Translate(&input, NULL, NULL, output, mImageFormat);
if (err == B_OK)
{
err = SetFileType(output, mTranslator, mImageFormat);
if (err != B_OK)
UpdateFtpStatus("Error setting type of output file");
}
else
{
UpdateFtpStatus("Error writing output file");
}
input.DetachBitmap(&bitmap);
output->Unset();
delete output;
return B_OK;
}
else
{
UpdateFtpStatus("Error creating output file");
return B_ERROR;
}
}
//---------------------------------------------------------------
status_t
VideoConsumer::FtpSave(char *filename)
{
FtpClient ftp;
/* ftp the local file to our web site */
ftp.setPassive(mPassiveFtp);
UpdateFtpStatus("Logging in ...");
if (ftp.connect((string)mServerText, (string)mLoginText, (string)mPasswordText)) // connect to server
{
UpdateFtpStatus("Connected ...");
if (ftp.cd((string)mDirectoryText))
{ // cd to the desired directory
UpdateFtpStatus("Transmitting ...");
if (ftp.putFile((string)filename, (string)"temp")) // send the file to the server
{
UpdateFtpStatus("Renaming ...");
if (ftp.moveFile((string)"temp",(string)filename)) // change to the desired name
{
uint32 time = real_time_clock();
char s[80];
strcpy(s,"Last Capture: ");
strcat(s,ctime((const long *)&time));
s[strlen(s)-1] = 0;
UpdateFtpStatus(s);
return B_OK;
} else UpdateFtpStatus("Rename failed");
} else UpdateFtpStatus("File transmission failed");
} else UpdateFtpStatus("Couldn't find requested directory on server");
} else UpdateFtpStatus("Server login failed");
return B_ERROR;
}
//---------------------------------------------------------------
status_t
SetFileType(BFile * file, int32 translator, uint32 type)
{
translation_format * formats;
int32 count;
status_t err = BTranslatorRoster::Default()->GetOutputFormats(translator, (const translation_format **) &formats, &count);
if (err < B_OK) return err;
const char * mime = NULL;
for (int ix=0; ix<count; ix++)
{
if (formats[ix].type == type)
{
mime = formats[ix].MIME;
break;
}
}
if (mime == NULL)
{ /* this should not happen, but being defensive might be prudent */
return B_ERROR;
}
/* use BNodeInfo to set the file type */
BNodeInfo ninfo(file);
return ninfo.SetType(mime);
}
//---------------------------------------------------------------

View File

@ -0,0 +1,176 @@
// Copyright (c) 1998-99, Be Incorporated, All Rights Reserved.
// SMS
/* VideoConsumer.h */
#if !defined(VID_CONSUMER_H)
#define VID_CONSUMER_H
#include <View.h>
#include <Bitmap.h>
#include <Window.h>
#include <MediaNode.h>
#include <TranslationKit.h>
#include <BufferConsumer.h>
#include <TimedEventQueue.h>
#include <MediaEventLooper.h>
typedef struct
{
port_id port;
bigtime_t rate;
uint32 imageFormat;
int32 translator;
bool passiveFtp;
char fileNameText[64];
char serverText[64];
char loginText[64];
char passwordText[64];
char directoryText[64];
} ftp_msg_info;
#define FTP_INFO 0x60000001
class VideoConsumer :
public BMediaEventLooper,
public BBufferConsumer
{
public:
VideoConsumer(
const char * name,
BView * view,
BStringView * statusLine,
BMediaAddOn *addon,
const uint32 internal_id);
~VideoConsumer();
/* BMediaNode */
public:
virtual BMediaAddOn *AddOn(long *cookie) const;
protected:
virtual void Start(bigtime_t performance_time);
virtual void Stop(bigtime_t performance_time, bool immediate);
virtual void Seek(bigtime_t media_time, bigtime_t performance_time);
virtual void TimeWarp(bigtime_t at_real_time, bigtime_t to_performance_time);
virtual void NodeRegistered();
virtual status_t RequestCompleted(
const media_request_info & info);
virtual status_t HandleMessage(
int32 message,
const void * data,
size_t size);
virtual status_t DeleteHook(BMediaNode * node);
/* BMediaEventLooper */
protected:
virtual void HandleEvent(
const media_timed_event *event,
bigtime_t lateness,
bool realTimeEvent);
/* BBufferConsumer */
public:
virtual status_t AcceptFormat(
const media_destination &dest,
media_format * format);
virtual status_t GetNextInput(
int32 * cookie,
media_input * out_input);
virtual void DisposeInputCookie(
int32 cookie);
protected:
virtual void BufferReceived(
BBuffer * buffer);
private:
virtual void ProducerDataStatus(
const media_destination &for_whom,
int32 status,
bigtime_t at_media_time);
virtual status_t GetLatencyFor(
const media_destination &for_whom,
bigtime_t * out_latency,
media_node_id * out_id);
virtual status_t Connected(
const media_source &producer,
const media_destination &where,
const media_format & with_format,
media_input * out_input);
virtual void Disconnected(
const media_source &producer,
const media_destination &where);
virtual status_t FormatChanged(
const media_source & producer,
const media_destination & consumer,
int32 from_change_count,
const media_format & format);
/* implementation */
public:
status_t CreateBuffers(
const media_format & with_format);
void DeleteBuffers();
static status_t FtpRun(
void *data);
void FtpThread(
void);
void UpdateFtpStatus(
char *status);
status_t LocalSave(
char *filename,
BBitmap *bitmap);
status_t FtpSave(
char *filename);
private:
BStringView * mStatusLine;
uint32 mInternalID;
BMediaAddOn *mAddOn;
thread_id mFtpThread;
bool mConnectionActive;
media_input mIn;
media_destination mDestination;
bigtime_t mMyLatency;
BWindow *mWindow;
BView *mView;
BBitmap *mBitmap[3];
bool mOurBuffers;
BBufferGroup *mBuffers;
uint32 mBufferMap[3];
BBitmap *mFtpBitmap;
volatile bool mTimeToFtp;
volatile bool mFtpComplete;
bigtime_t mRate;
uint32 mImageFormat;
int32 mTranslator;
bool mPassiveFtp;
char mFileNameText[64];
char mServerText[64];
char mLoginText[64];
char mPasswordText[64];
char mDirectoryText[64];
};
#endif

Binary file not shown.

120
src/prefs/codycam/makefile Normal file
View File

@ -0,0 +1,120 @@
## BeOS Generic Makefile v2.1 ##
## Fill in this file to specify the project being created, and the referenced
## makefile-engine will do all of the hard work for you. This handles both
## Intel and PowerPC builds of the BeOS.
## Application Specific Settings ---------------------------------------------
# specify the name of the binary
NAME= CodyCam
# specify the type of binary
# APP: Application
# SHARED: Shared library or add-on
# STATIC: Static library archive
# DRIVER: Kernel Driver
TYPE= APP
# add support for new Pe and Eddie features
# to fill in generic makefile
#%{
# @src->@
# specify the source files to use
# full paths or paths relative to the makefile can be included
# all files, regardless of directory, will have their object
# files created in the common object directory.
# Note that this means this makefile will not work correctly
# if two source files with the same name (source.c or source.cpp)
# are included from different directories. Also note that spaces
# in folder names do not work well with this makefile.
SRCS= \
CodyCam.cpp \
FtpClient.cpp \
Settings.cpp \
SettingsHandler.cpp \
VideoConsumer.cpp
# specify the resource files to use
# full path or a relative path to the resource file can be used.
RSRCS= codycam.rsrc
# @<-src@
#%}
# end support for Pe and Eddie
# specify additional libraries to link against
# there are two acceptable forms of library specifications
# - if your library follows the naming pattern of:
# libXXX.so or libXXX.a you can simply specify XXX
# library: libbe.so entry: be
#
# - if your library does not follow the standard library
# naming scheme you need to specify the path to the library
# and it's name
# library: my_lib.a entry: my_lib.a or path/my_lib.a
LIBS= be media translation netapi
ifeq ($(shell uname -m), BePC)
LIBS += stdc++.r4
else
LIBS += mslcpp_4_0
endif
# specify additional paths to directories following the standard
# libXXX.so or libXXX.a naming scheme. You can specify full paths
# or paths relative to the makefile. The paths included may not
# be recursive, so include all of the paths where libraries can
# be found. Directories where source files are found are
# automatically included.
LIBPATHS=
# additional paths to look for system headers
# thes use the form: #include <header>
# source file directories are NOT auto-included here
SYSTEM_INCLUDE_PATHS =
# additional paths to look for local headers
# thes use the form: #include "header"
# source file directories are automatically included
LOCAL_INCLUDE_PATHS =
# specify the level of optimization that you desire
# NONE, SOME, FULL
OPTIMIZE= FULL
# specify any preprocessor symbols to be defined. The symbols will not
# have their values set automatically; you must supply the value (if any)
# to use. For example, setting DEFINES to "DEBUG=1" will cause the
# compiler option "-DDEBUG=1" to be used. Setting DEFINES to "DEBUG"
# would pass "-DDEBUG" on the compiler's command line.
DEFINES=
# specify special warning levels
# if unspecified default warnings will be used
# NONE = supress all warnings
# ALL = enable all warnings
WARNINGS =
# specify whether image symbols will be created
# so that stack crawls in the debugger are meaningful
# if TRUE symbols will be created
SYMBOLS =
# specify debug settings
# if TRUE will allow application to be run from a source-level
# debugger. Note that this will disable all optimzation.
DEBUGGER =
# specify additional compiler flags for all files
COMPILER_FLAGS =
# specify additional linker flags
LINKER_FLAGS =
## include the makefile-engine
include /boot/develop/etc/makefile-engine