rosaria/Legacy/Aria/ArNetworking/examples/getVideoExample.cpp
2021-12-16 14:07:59 +00:00

165 lines
5.0 KiB
C++

#include "Aria.h"
#include "ArNetworking.h"
/** @example getVideoExample.cpp
*
* This example client requests video images from the server
* and saves them repeatedly to a file named "video.jpg", or
* to a series of files ("video1.jpg", "video2.jpg", etc.) if
* you give the -counter option. Give the image request rate
* in images per second with the -rate option (or use -1 to let
* the server decide when to send image; may not work with all servers).
*
* Connect to SAVserver, ACTS, or another video server to get
* images.
*
* To make a movie from the images, you can use ffmpeg on Linux.
* First run with frame rate and counter options to save multiple images:
* ./getVideoExample -host robothost -port 7272 -rate 20 -counter
* Then use ffmpeg:
* ffmpeg -i video%d.jpeg -r 20 movie.mpeg
* See ffmpeg -h for full list of options.
*/
bool useCounter = false;
unsigned long counter = 1;
double rate = 0;
int rateAsTime = 0;
void jpegHandler(ArNetPacket *packet)
{
unsigned int width;
unsigned int height;
static unsigned char jpeg[50000];
int jpegSize;
FILE *file;
width = packet->bufToUByte2();
height = packet->bufToUByte2();
jpegSize = packet->getDataLength() - packet->getDataReadLength();
if(jpegSize > 50000)
{
ArLog::log(ArLog::Normal, "Cannot save image, it's too big. (image is %d bytes, my buffer is 50000 bytes)", jpegSize);
return;
}
packet->bufToData((char *)jpeg, jpegSize);
char filename[128];
char tmpFilename[128];
sprintf(tmpFilename, "tmp.jpg");
if ((file = ArUtil::fopen(tmpFilename, "wb")) != NULL)
{
fwrite(jpeg, jpegSize, 1, file);
fclose(file);
if(useCounter)
snprintf(filename, 64, "video%lu.jpg", counter++);
else
strcpy(filename, "video.jpg");
#ifdef WIN32
// On windows, rename() fails if the new file already exists
unlink(filename);
#endif
if (rename(tmpFilename, filename) == 0)
ArLog::log(ArLog::Normal, "Wrote a %dx%d image, %d bytes, named %s.", width, height, jpegSize, filename);
else
ArLog::log(ArLog::Normal, "Wrote a %dx%d image, %d bytes, named %s (could not rename to real name).", width, height, jpegSize, tmpFilename);
}
else
ArLog::log(ArLog::Normal, "Could not write temp file %s", tmpFilename);
if (rate == 0 || rateAsTime == 0)
{
ArLog::log(ArLog::Normal, "Only one frame was requested, so exiting");
Aria::exit(0);
}
}
int main(int argc, char **argv)
{
#ifndef WIN32
ArDaemonizer daemonizer(&argc, argv, false);
bool isDaemonized = false;
if (!daemonizer.daemonize())
{
ArLog::log(ArLog::Terse, "Could not daemonize process");
exit(1);
}
if (daemonizer.isDaemonized())
isDaemonized = true;
#endif
Aria::init();
ArLog::init(ArLog::File, ArLog::Normal, "getVideoLog.txt", true, true, true);
ArArgumentParser argParser(&argc, argv);
argParser.loadDefaultArguments();
ArClientSimpleConnector clientConnector(&argParser);
if(argParser.checkParameterArgumentDouble("-rate", &rate) && rate != 0.0)
{
if(rate == -1)
rateAsTime = -1;
else
rateAsTime = ArMath::roundInt(1000.0 / rate);
}
useCounter = argParser.checkArgument("-counter");
if(!Aria::parseArgs() || !argParser.checkHelpAndWarnUnparsed())
{
Aria::logOptions();
ArLog::log(ArLog::Terse, "\n\n%s options:\n-rate <FramesPerSecondAsDouble> (If this isn't given, then the program will take one frame then exit, note that it is a double (so you can do .5 to do one frame per 2 seconds) and that if you set it to be too fast you'll saturate the robot's bandwidth and make it useless)\n-counter (default no)\n", argv[0]);
ArLog::log(ArLog::Terse, "\n\nNotes:\nThis program saves the images as video.jpg if you aren't using a counter, or video<counter>.jpg if you are using the counter.\nIt puts its logs into getVideoLog.txt, and overwrites it whenever it runs\n");
return 1;
}
ArClientBase client;
if (!clientConnector.connectClient(&client))
{
ArLog::log(ArLog::Normal, "Could not connect to server, exiting\n");
exit(1);
}
ArGlobalFunctor1<ArNetPacket *> jpegHandlerCB(&jpegHandler);
if(client.dataExists("getPictureCam1"))
{
ArLog::log(ArLog::Normal, "Requesting images using \"getPictureCam1\" request.");
client.addHandler("getPictureCam1", &jpegHandlerCB);
if (rate != 0 && rateAsTime != 0)
client.request("getPictureCam1", rateAsTime);
else
client.requestOnce("getPictureCam1");
}
else if(client.dataExists("sendVideo"))
{
ArLog::log(ArLog::Normal, "Server does not have \"getPictureCam1\" request, requesting images using old \"sendVideo\" request.");
client.addHandler("sendVideo", &jpegHandlerCB);
if (rate != 0 && rateAsTime != 0)
client.request("sendVideo", rateAsTime);
else
client.requestOnce("sendVideo");
}
else
{
ArLog::log(ArLog::Terse, "Error: Server does not have \"getPictureCam1\" or \"sendVideo\" request, cannot request images.");
Aria::exit(2);
}
client.run();
Aria::shutdown();
return 0;
}