1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
|
#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;
}
|