Check return from std::string::find
[gnash.git] / utilities / flvdumper.cpp
bloba22fa0aca2cc0888b2087ce7124cfe8f0b339bf6
1 //
2 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Free Software
3 // Foundation, Inc
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 #ifdef HAVE_CONFIG_H
20 #include "gnashconfig.h"
21 #endif
23 #include "GnashFileUtilities.h"
24 #include "GnashSystemNetHeaders.h"
26 #include <boost/shared_ptr.hpp>
27 #include <dirent.h>
28 #include <iostream>
29 #include <cstdarg>
30 #include <cstring>
31 #include <string>
32 #include <vector>
34 #ifdef ENABLE_NLS
35 # include <clocale>
36 #endif
38 #include "log.h"
39 #include "rc.h"
40 #include "amf.h"
41 #include "flv.h"
42 #include "buffer.h"
43 #include "arg_parser.h"
45 using namespace cygnal;
46 using namespace std;
47 using namespace gnash;
49 namespace {
50 gnash::LogFile& dbglogfile = gnash::LogFile::getDefaultInstance();
51 gnash::RcInitFile& rcfile = gnash::RcInitFile::getDefaultInstance();
54 #ifdef BOOST_NO_EXCEPTIONS
55 namespace boost
58 void throw_exception(std::exception const & e)
60 std::abort();
63 #endif
65 static void usage ();
67 static const char *codec_strs[] = {
68 "None",
69 "None",
70 "H263",
71 "Screen",
72 "VP6",
73 "VP6_Alpha",
74 "Screen2",
75 "Theora",
76 "Dirac",
77 "Speex"
80 static const char *format_strs[] = {
81 "Uncompressed",
82 "ADPCM",
83 "MP3",
84 "Unknown",
85 "Unknown",
86 "Nellymoser_8KHZ",
87 "Nellymoser",
88 // These next are only supported by Gnash
89 "Vorbis"
92 static const char *frame_strs[] = {
93 "NO_frame",
94 "Keyframe",
95 "Interframe",
96 "Disposable"
99 static const char *size_strs[] = {
100 "8Bit",
101 "16Bit"
104 static const char *type_strs[] = {
105 "Mono",
106 "Stereo"
109 static const char *rate_strs[] = {
110 "55Khz",
111 "11Khz",
112 "22Khz",
113 "44Khz",
117 main(int argc, char *argv[])
119 bool dump = false; // dump the FLV data
120 bool all = false; // dump all the tags too
121 bool meta = true; // dump all Meta tags only
122 vector<string> infiles;
124 // Enable native language support, i.e. internationalization
125 #ifdef ENABLE_NLS
126 std::setlocale (LC_ALL, "");
127 bindtextdomain (PACKAGE, LOCALEDIR);
128 textdomain (PACKAGE);
129 #endif
130 const Arg_parser::Option opts[] =
132 { 'h', "help", Arg_parser::no },
133 { 'v', "verbose", Arg_parser::no },
134 { 'd', "dump", Arg_parser::no },
135 { 'a', "all", Arg_parser::no },
136 { 'm', "meta", Arg_parser::no },
139 Arg_parser parser(argc, argv, opts);
140 if( ! parser.error().empty() ) {
141 cout << parser.error() << endl;
142 exit(EXIT_FAILURE);
145 for( int i = 0; i < parser.arguments(); ++i ) {
146 const int code = parser.code(i);
147 try {
148 switch( code ) {
149 case 'h':
150 usage ();
151 exit(EXIT_SUCCESS);
152 case 'v':
153 dbglogfile.setVerbosity();
154 log_debug(_("Verbose output turned on"));
155 break;
156 case 'd':
157 dump = true;
158 break;
159 case 'a':
160 all = true;
161 break;
162 case 'm':
163 meta = true;
164 break;
165 case 0:
166 infiles.push_back(parser.argument(i));
167 break;
171 catch (Arg_parser::ArgParserException &e) {
172 cerr << _("Error parsing command line options: ") << e.what() << endl;
173 cerr << _("This is a Gnash flvdumper bug.") << endl;
177 if (infiles.empty()) {
178 cerr << _("Error: no input file was specified. Exiting.") << endl;
179 usage();
180 return EXIT_FAILURE;
183 // Get the filename from the command line
184 string filespec = infiles[0];
186 Flv flv;
187 struct stat st;
189 // boost::shared_ptr<Flv::flv_header_t> head;
190 Flv::previous_size_t previous = 0;
191 boost::shared_ptr<Flv::flv_tag_t> tag;
193 // Make sure it's an FLV file
194 if (stat(filespec.c_str(), &st) == 0) {
195 try {
196 // Open the binary file
197 ifstream ifs(filespec.c_str(), ios::binary);
198 boost::shared_ptr<cygnal::Buffer> buf(new Buffer);
199 // Read just the initial 9 byte header
200 ifs.read(reinterpret_cast<char *>(buf->reference()), sizeof(Flv::flv_header_t));
201 log_debug("header is: %s", hexify(buf->reference(), 9, false));
202 boost::shared_ptr<Flv::flv_header_t> head = flv.decodeHeader(buf);
203 if (head == 0) {
204 log_error("Couldn't decode the header! %s", hexify(buf->reference(), 9, false));
205 exit(EXIT_FAILURE);
207 if ((head->type & Flv::FLV_VIDEO) && (head->type & Flv::FLV_AUDIO)) {
208 cout <<"FLV File type: Video and Audio" << endl;
209 } else if (head->type && Flv::FLV_VIDEO) {
210 cout << "FLV File type: Video" << endl;
211 } else if (head->type && Flv::FLV_AUDIO) {
212 cout <<"FLV File type: Audio" << endl;
215 cout << "FLV Version: " << int(head->version) << " (should always be 1)" << endl;
216 boost::uint32_t headsize = flv.convert24(head->head_size);
217 if (all) {
218 cout << "FLV Header size: " << headsize << " (should always be 9)" << endl;
220 // Extract all the Tags
221 size_t total = st.st_size - sizeof(Flv::flv_header_t);
222 while (!ifs.eof()) {
223 ifs.read(reinterpret_cast<char *>(&previous), sizeof(Flv::previous_size_t));
224 if (ifs.gcount() != sizeof(Flv::previous_size_t)) {
225 log_error("Couldn't read the entire header");
228 previous = ntohl(previous);
229 total -= sizeof(Flv::previous_size_t);
230 if (all) {
231 cout << "FLV Previous Tag Size was: " << previous << endl;
233 ifs.read(reinterpret_cast<char *>(buf->reference()), sizeof(Flv::flv_tag_t));
234 if (ifs.gcount() != sizeof(Flv::flv_tag_t)) {
235 log_error("Couldn't read the entire tag");
237 tag = flv.decodeTagHeader(buf);
238 flv.dump();
239 total -= sizeof(Flv::previous_size_t);
240 size_t bodysize = flv.convert24(tag->bodysize);
241 if (bodysize == 0) {
242 cerr << "FLV Tag size is zero, skipping reading packet body " << bodysize << endl;
243 continue;
244 } else {
245 if (all) {
246 cout << "FLV Tag size is: " << bodysize + sizeof(Flv::previous_size_t) << endl;
249 buf->resize(bodysize);
250 ifs.read(reinterpret_cast<char *>(buf->reference()), bodysize);
251 // if (ifs.gcount() != bodysize) {
252 // log_error("Couldn't read the entire body");
253 // }
254 total -= bodysize;
255 switch (tag->type) {
256 case Flv::TAG_AUDIO:
258 if (all) {
259 cerr << "FLV Tag type is: Audio" << endl;
260 boost::shared_ptr<Flv::flv_audio_t> data = flv.decodeAudioData(*(buf->reference() + sizeof(Flv::flv_tag_t)));
261 cout << "\tSound Type is: " << type_strs[data->type] << endl;
262 cout << "\tSound Size is: " << size_strs[data->size] << endl;
263 cout << "\tSound Rate is: " << rate_strs[data->rate] << endl;
264 cout << "\tSound Format is: " << format_strs[data->format] << endl;
266 break;
268 case Flv::TAG_VIDEO:
270 if (all) {
271 cout << "FLV Tag type is: Video" << endl;
272 boost::shared_ptr<Flv::flv_video_t> data = flv.decodeVideoData(*(buf->reference() + sizeof(Flv::flv_tag_t)));
273 cout << "\tCodec ID is: " << codec_strs[data->codecID] << endl;
274 cout << "\tFrame Type is: " << frame_strs[data->type] << endl;
276 break;
278 case Flv::TAG_METADATA:
279 if (meta || all) {
280 cout << "FLV Tag type is: MetaData" << endl;
282 boost::shared_ptr<cygnal::Element> metadata = flv.decodeMetaData(buf->reference(), bodysize);
283 if (meta && metadata) {
284 metadata->dump();
286 continue;
289 } catch (std::exception& e) {
290 log_error("Reading %s: %s", filespec, e.what());
291 return false;
296 /// \brief Display the command line arguments
297 static void
298 usage ()
300 cerr << _("This program dumps the internal data of an FLV video file")
301 << endl;
302 cerr << _("Usage: flvdumper [-h] [-m] [-a] filename") << endl;
303 cerr << _("-h\tHelp") << endl;
304 cerr << _("-m\tPrint only Meta tags (default)") << endl;
305 cerr << _("-a\tPrint all tags.") << endl;
306 exit (-1);
309 // Local Variables:
310 // mode: C++
311 // indent-tabs-mode: t
312 // End: