EVOLUTION-MANAGER
Edit File: oggThumb.cpp
/* * oggThumb creates thumbs from an ogg/theora video * * Copyright (C) 2008-2009 Joern Seger * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #ifdef __WIN32 #define __GNU_LIBRARY__ #include "../win32/getopt_win.h" #endif #include <vector> #include <deque> #include <limits> #include <sstream> #include <string> #include <iostream> #include <cstdlib> #include <queue> #include <unistd.h> #include "fileRepository.h" #include "streamSerializer.h" #include "theoraDecoder.h" #include "theoraStreamParameter.h" #include "oggComment.h" #include "rgbPlane.h" #include "pictureLoader.h" #include "pictureResize.h" const std::string validChars("0123456789,.x"); void extractUint32(std::deque<uint32>& list, const std::string& _argument, char seperator) { std::string argument(_argument); std::stringstream str; std::string substr; // if there is no argument given, the first frame will be created as a thumbnail if (argument.empty()) { list.push_back(0); return; } // delete all invalid data std::size_t pos; while ((pos = argument.find_first_not_of(validChars)) != std::string::npos) { std::cerr << "erasing <"<<argument.at(pos)<<">\n"; argument.erase(pos,1); } str << argument; uint32 value(0); while (!str.eof()) { std::stringstream part; getline(str, substr, seperator); part << substr; part >> value; list.push_back(value); } } void extractUint32Sort(std::deque<uint32>& list, const std::string& _argument, char seperator) { std::string argument(_argument); std::stringstream str; std::string substr; std::priority_queue<uint32> _list; // if there is no argument given, the first frame will be created as a thumbnail if (argument.empty()) { list.push_back(0); return; } // delete all invalid data std::size_t pos; while ((pos = argument.find_first_not_of(validChars)) != std::string::npos) { std::cerr << "erasing <"<<argument.at(pos)<<">\n"; argument.erase(pos,1); } str << argument; uint32 value(0); while (!str.eof()) { std::stringstream part; getline(str, substr, seperator); part << substr; part >> value; _list.push(value); } while (!_list.empty()) { list.push_front(_list.top()); _list.pop(); } } void extractDoubleSort(std::deque<double>& list, const std::string& _argument, char seperator) { std::string argument(_argument); std::stringstream str; std::string substr; std::priority_queue<double> _list; // if there is no argument given, the first frame will be created as a thumbnail if (argument.empty()) { list.push_back(0); return; } std::size_t pos; while ((pos = argument.find_first_not_of(validChars)) != std::string::npos) argument.erase(pos); str << argument; double value(0); while (!str.eof()) { std::stringstream part; getline(str, substr, seperator); part << substr; part >> value; _list.push(value); } while (!_list.empty()) { list.push_front(_list.top()); _list.pop(); } } void writeActualFrame(TheoraDecoder& decoder, std::deque<OggPacket>& packetList, const std::string& name, uint32 width, uint32 height) { th_ycbcr_buffer picture; RGBPlane plane; if (!TheoraDecoder::isPacketKeyframe(packetList[0])) { std::cerr << "first packet is not a keyframe\n"; return; // could not happen ;-) } for (uint32 i(0); i<packetList.size(); ++i) { decoder << packetList[i]; decoder >> picture; } plane = PictureLoader::importYCrCb_theora(picture, decoder.getWidth(), decoder.getHeight(), decoder.getInfo().pic_x, decoder.getInfo().pic_y ); PictureLoader::save(plane, name, width, height); } std::string getThumbname(const std::string& filename, const std::string& extension, uint32& counter) { std::stringstream thumbname; std::size_t filenamestart = filename.find_last_of('/'); std::size_t filenamelength = filename.find_last_of('.'); if (filenamestart == std::string::npos) filenamestart = 0; else filenamestart++; if ((filenamelength != std::string::npos) && (filenamelength > filenamestart)) filenamelength = filenamelength - filenamestart; else filenamelength = std::string::npos; thumbname << filename.substr(filenamestart,filenamelength); thumbname << "_" << counter++ << extension; return(thumbname.str()); } void printHelpScreen(std::string& prog) { std::cout << "\nusage: "<<prog<<" [options] file1.ogv [ file2.ogv [ file3.ogv [...] ] ]\n" << "Options:\n" << " -t <time1, time2, time3, ...> : create thumbnail from frame at time position time1, time2, time3 second\n" << " -f <frameNo1, frameNo2, frameNo3, ...>: create thumbnail from frame number frameNo1, frameNo2, frameNo3\n" << " -s <width>:<height> : resize to given values (if one argument is set to 0, it is calculated to meet the aspect ratio\n" << " -o <output format> : formats are jpg or png" << "\n\n"; } int main(int argc, char* argv[]) { std::deque<double> timePosList; std::deque<uint32> frameNoList; uint32 width(0); uint32 height(0); std::string programName(argv[0]); std::string extension(".jpg"); int opt; while ((opt = getopt(argc, argv, "hf:t:s:o:")) != EOF) switch (opt) { case '?': case 'h': printHelpScreen(programName); exit(-1); case 'f': extractUint32Sort(frameNoList, optarg, ','); break; case 't': extractDoubleSort(timePosList,optarg, ','); break; case 's': { std::deque<uint32> framesize; extractUint32(framesize, optarg, 'x'); if (framesize.size() != 2) { std::cerr << "please specify the size in the following way: -s320x480\n"; exit(-1); } width = framesize[0]; height = framesize[1]; } break; case 'o': extension = optarg; extension = "." + extension; break; } argc -= optind; argv += optind; if (argc == 0) { std::cerr << "Please specify at least one ogg file\n;"; exit(-1); } std::cout << "Creating thumbs under the following option:\n"; if (!timePosList.empty()) { std::cout << "Frames at time (in seconds): "; for (uint32 i(0); i<timePosList.size(); ++i) std::cout << timePosList[i] <<" "; std::cout << "\n"; } if (!frameNoList.empty()) { std::cout << "Frame numbers: "; for (uint32 i(0); i<frameNoList.size(); ++i) std::cout << frameNoList[i] <<" "; std::cout << "\n"; } if (width) std::cout << "width is set to: "<<width<<"\n"; if (height) std::cout << "height is set to: "<<height<<"\n"; std::cout << "file type: " << extension << "\n"; std::cout << "The following ogg media files will be used: "; for (int i(0); i<argc; ++i) std::cout << argv[i] << " "; std::cout << "\n"; // go through the files for (int i(0); i<argc; ++i) { /* create the stream serializer */ StreamSerializer streamSerializer; TheoraDecoder theoraDecoder; uint8 foundTheora(0); uint32 counter(0); std::string filename(argv[i]); double aspectCorrection; std::deque<double> tmptimePosList = timePosList; std::deque<uint32> tmpframeNoList = frameNoList; if (!streamSerializer.open(filename)) { std::cerr << "Error: can not open file <"<<filename<<">\n"; continue; } uint8 theoraStreamNo(0); /* create the headers */ std::vector<StreamConfig> streamConfigList; streamSerializer.getStreamConfig(streamConfigList); TheoraStreamParameter* theoraConfig(0); std::vector<OggComment> oggComments; /* Output some stream information */ for (uint32 i(0); i<streamConfigList.size(); ++i) { if (streamConfigList[i].type == ogg_theora) { // take the first theora stream if (!foundTheora) { theoraStreamNo = streamConfigList[i].streamNo; theoraConfig = (TheoraStreamParameter*)streamConfigList[i].parameter; theoraDecoder.initDecoder(streamConfigList[i], oggComments); std::cerr << "Info:\n" << theoraDecoder.getInfoString()<<std::endl; aspectCorrection = (theoraDecoder.getInfo().aspect_numerator*1.0)/(theoraDecoder.getInfo().aspect_denominator*1.0); if ((width == 0) && (height == 0)) { width = theoraConfig->pictureX * aspectCorrection; //theoraConfig->frameX; height = theoraConfig->pictureY; //theoraConfig->frameY; } else { if (height == 0) height = (uint32)((width * theoraConfig->pictureY*1.0)/(theoraConfig->pictureX*aspectCorrection*1.0) + 0.5); else if (width == 0) width = (uint32)((height * theoraConfig->pictureX*aspectCorrection*1.0)/(theoraConfig->pictureY*1.0) +0.5); } std::cout << "width: "<<width<<" and height: "<<height<<"\n"; } foundTheora++; } } if (!foundTheora) { std::cerr << "There is no theora stream in file <"<<filename<<">\n"; continue; } if (foundTheora > 2) std::cout << "Found more than one theora stream in file <"<<filename<<"> using first stream\n"; /* set up first time/frame */ double nextTime; uint32 nextFrame; bool noMoreTime(false); bool noMoreFrame(false); if (tmpframeNoList.empty()) { nextFrame = std::numeric_limits<uint32>::max(); noMoreFrame = true; } else { nextFrame = tmpframeNoList.front(); tmpframeNoList.pop_front(); } if (tmptimePosList.empty()) { nextTime = std::numeric_limits<double>::max(); noMoreTime = true; } else { nextTime = tmptimePosList.front(); tmptimePosList.pop_front(); } std::deque<OggPacket> packetList; double time; OggPacket packet; while (streamSerializer.available()) { // get the next packet time = streamSerializer.getNextPacket(packet); // is this packet a theora frame if (packet.getStreamType() != ogg_theora) continue; // write actual time std::cout << "\r "<<time<<" "; // if this is a keyframe, we are able to decode from this if (TheoraDecoder::isPacketKeyframe(packet)) { packetList.clear(); } // store packets for decoding since last keyframe packetList.push_back(packet); // should this packet be written due to frame number comparison? if (nextFrame == packet.getPacketNo()) { if (tmpframeNoList.empty()) { nextFrame = std::numeric_limits<uint32>::max(); noMoreFrame = true; } else { nextFrame = tmpframeNoList.front(); tmpframeNoList.pop_front(); } std::string thumbname(getThumbname(filename, extension, counter)); std::cout << "writing "<<thumbname<<std::endl; writeActualFrame(theoraDecoder, packetList, thumbname, width, height); } // should this packt be written due to time limit? if (time >= nextTime) { if (tmptimePosList.empty()) { nextTime = std::numeric_limits<uint32>::max(); noMoreTime = true; } else { nextTime = tmptimePosList.front(); tmptimePosList.pop_front(); } std::string thumbname(getThumbname(filename, extension, counter)); std::cout << "writing "<<thumbname<<std::endl; writeActualFrame(theoraDecoder, packetList, thumbname, width, height); } if (noMoreTime && noMoreFrame) break; } streamSerializer.close(); } std::cout << std::endl; #ifdef OSX_MALLOC_DEBUG std::cout << "Done!\n"; while (1==1) { } #endif return(0); }