update copyright date
[gnash.git] / utilities / flvdumper.cpp
blobc45e34d07d9d9232a7a4ea819946b04d365bf293
1 //
2 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010,
3 // 2011 Free Software 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 if (dump) {
239 flv.dump();
241 //total -= sizeof(Flv::previous_size_t);
242 size_t bodysize = flv.convert24(tag->bodysize);
243 if (bodysize == 0) {
244 cerr << "FLV Tag size is zero, skipping reading packet body " << bodysize << endl;
245 continue;
246 } else {
247 if (all) {
248 cout << "FLV Tag size is: " << bodysize + sizeof(Flv::previous_size_t) << endl;
251 buf->resize(bodysize);
252 ifs.read(reinterpret_cast<char *>(buf->reference()), bodysize);
253 // if (ifs.gcount() != bodysize) {
254 // log_error("Couldn't read the entire body");
255 // }
256 //total -= bodysize;
257 switch (tag->type) {
258 case Flv::TAG_AUDIO:
260 if (all) {
261 cerr << "FLV Tag type is: Audio" << endl;
262 boost::shared_ptr<Flv::flv_audio_t> data = flv.decodeAudioData(*(buf->reference() + sizeof(Flv::flv_tag_t)));
263 cout << "\tSound Type is: " << type_strs[data->type] << endl;
264 cout << "\tSound Size is: " << size_strs[data->size] << endl;
265 cout << "\tSound Rate is: " << rate_strs[data->rate] << endl;
266 cout << "\tSound Format is: " << format_strs[data->format] << endl;
268 break;
270 case Flv::TAG_VIDEO:
272 if (all) {
273 cout << "FLV Tag type is: Video" << endl;
274 boost::shared_ptr<Flv::flv_video_t> data = flv.decodeVideoData(*(buf->reference() + sizeof(Flv::flv_tag_t)));
275 cout << "\tCodec ID is: " << codec_strs[data->codecID] << endl;
276 cout << "\tFrame Type is: " << frame_strs[data->type] << endl;
278 break;
280 case Flv::TAG_METADATA:
281 if (meta || all) {
282 cout << "FLV Tag type is: MetaData" << endl;
284 boost::shared_ptr<cygnal::Element> metadata = flv.decodeMetaData(buf->reference(), bodysize);
285 if (meta && metadata) {
286 metadata->dump();
288 continue;
291 } catch (std::exception& e) {
292 log_error("Reading %s: %s", filespec, e.what());
293 return false;
298 /// \brief Display the command line arguments
299 static void
300 usage ()
302 cerr << _("This program dumps the internal data of an FLV video file")
303 << endl;
304 cerr << _("Usage: flvdumper [-h] [-m] [-a] filename") << endl;
305 cerr << _("-h\tHelp") << endl;
306 cerr << _("-m\tPrint only Meta tags (default)") << endl;
307 cerr << _("-a\tPrint all tags.") << endl;
308 exit (-1);
311 // Local Variables:
312 // mode: C++
313 // indent-tabs-mode: t
314 // End: