CodyCam from the BeOS Sample Code.
git-svn-id: file:///srv/svn/repos/haiku/trunk/current@2776 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -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
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -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
|
||||||
|
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
SubDir OBOS_TOP src apps codycam ;
|
||||||
|
|
||||||
|
AddResources CodyCam : codycam.rsrc ;
|
||||||
|
|
||||||
|
Application CodyCam :
|
||||||
|
CodyCam.cpp
|
||||||
|
FTPClient.cpp
|
||||||
|
Settings.cpp
|
||||||
|
SettingsHandler.cpp
|
||||||
|
VideoConsumer.cpp;
|
||||||
|
|
||||||
|
LinkSharedOSLibs CodyCam : be media translation netapi stdc++.r4;
|
||||||
|
|
||||||
@@ -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");
|
||||||
|
}
|
||||||
|
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
@@ -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.
@@ -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
|
||||||
|
|
||||||
Reference in New Issue
Block a user