00001 #include <ros/ros.h>
00002
00003 #include <theora_image_transport/Packet.h>
00004
00005 #include <theora/codec.h>
00006 #include <theora/theoraenc.h>
00007 #include <theora/theoradec.h>
00008 #include <ogg/ogg.h>
00009
00010 #include <fstream>
00011 #include <vector>
00012 #include <boost/scoped_array.hpp>
00013
00014 using namespace std;
00015
00016 class OggSaver
00017 {
00018 public:
00019 OggSaver(const char* filename)
00020 : fout_(filename, std::ios::out|std::ios::binary)
00021 {
00022 if (ogg_stream_init(&stream_state_, 0) == -1) {
00023 ROS_FATAL("Unable to initialize ogg_stream_state structure");
00024 exit(1);
00025 }
00026
00027 sub_ = nh_.subscribe("stream", 10, &OggSaver::processMsg, this);
00028 }
00029
00030 ~OggSaver()
00031 {
00032 ogg_page page;
00033 if (ogg_stream_flush(&stream_state_, &page) != 0)
00034 writePage(page);
00035 fout_.close();
00036 ogg_stream_clear(&stream_state_);
00037 }
00038
00039 private:
00040
00041 ros::NodeHandle nh_;
00042 ogg_stream_state stream_state_;
00043 ofstream fout_;
00044 ros::Subscriber sub_;
00045
00046
00047 void msgToOggPacket(const theora_image_transport::Packet &msg, ogg_packet &oggpacket)
00048 {
00049 oggpacket.bytes = msg.data.size();
00050 oggpacket.b_o_s = msg.b_o_s;
00051 oggpacket.e_o_s = msg.e_o_s;
00052 oggpacket.granulepos = msg.granulepos;
00053 oggpacket.packetno = msg.packetno;
00054 oggpacket.packet = new unsigned char[oggpacket.bytes];
00055 memcpy(oggpacket.packet, &msg.data[0], oggpacket.bytes);
00056 }
00057
00058 void writePage(ogg_page& page)
00059 {
00060 fout_.write((char*)page.header, page.header_len);
00061 fout_.write((char*)page.body, page.body_len);
00062 }
00063
00064 void processMsg(const theora_image_transport::PacketConstPtr& message)
00065 {
00071 ogg_packet oggpacket;
00072 msgToOggPacket(*message, oggpacket);
00073 boost::scoped_array<unsigned char> packet_guard(oggpacket.packet);
00074
00075 if (ogg_stream_packetin(&stream_state_, &oggpacket)) {
00076 ROS_ERROR("Error while adding packet to stream.");
00077 exit(2);
00078 }
00079
00080 ogg_page page;
00081 if (ogg_stream_pageout(&stream_state_, &page) != 0)
00082 writePage(page);
00083 }
00084 };
00085
00086 int main(int argc, char** argv)
00087 {
00090 ros::init(argc, argv, "OggSaver", ros::init_options::AnonymousName);
00091
00092 if(argc < 2) {
00093 cerr << "Usage: " << argv[0] << " stream:=/theora/image/stream outputFile" << endl;
00094 exit(3);
00095 }
00096 if (ros::names::remap("stream") == "stream") {
00097 ROS_WARN("ogg_saver: stream has not been remapped! Typical command-line usage:\n"
00098 "\t$ ./ogg_saver stream:=<theora stream topic> outputFile");
00099 }
00100
00101 OggSaver saver(argv[1]);
00102
00103 ros::spin();
00104 return 0;
00105 }