Update with current status
[gnash.git] / utilities / flvdumper.cpp
blobe941b43c73ba1fc2d4adbae89e259755a40afe67
1 //
2 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2014
3 // 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 <dirent.h>
27 #include <iostream>
28 #include <cstdarg>
29 #include <cstring>
30 #include <string>
31 #include <vector>
33 #ifdef ENABLE_NLS
34 # include <clocale>
35 #endif
37 #include "log.h"
38 #include "rc.h"
39 #include "amf.h"
40 #include "flv.h"
41 #include "buffer.h"
42 #include "arg_parser.h"
44 using namespace cygnal;
45 using namespace std;
46 using namespace gnash;
48 namespace {
49 gnash::LogFile& dbglogfile = gnash::LogFile::getDefaultInstance();
50 gnash::RcInitFile& rcfile = gnash::RcInitFile::getDefaultInstance();
53 #ifdef BOOST_NO_EXCEPTIONS
54 namespace boost
57 void throw_exception(std::exception const & e)
59 std::abort();
62 #endif
64 static void usage ();
66 static const char *codec_strs[] = {
67 "None",
68 "None",
69 "H263",
70 "Screen",
71 "VP6",
72 "VP6_Alpha",
73 "Screen2",
74 "Theora",
75 "Dirac",
76 "Speex"
79 static const char *format_strs[] = {
80 "Uncompressed",
81 "ADPCM",
82 "MP3",
83 "Unknown",
84 "Unknown",
85 "Nellymoser_8KHZ",
86 "Nellymoser",
87 // These next are only supported by Gnash
88 "Vorbis"
91 static const char *frame_strs[] = {
92 "NO_frame",
93 "Keyframe",
94 "Interframe",
95 "Disposable"
98 static const char *size_strs[] = {
99 "8Bit",
100 "16Bit"
103 static const char *type_strs[] = {
104 "Mono",
105 "Stereo"
108 static const char *rate_strs[] = {
109 "55Khz",
110 "11Khz",
111 "22Khz",
112 "44Khz",
116 main(int argc, char *argv[])
118 bool dump = false; // dump the FLV data
119 bool all = false; // dump all the tags too
120 bool meta = true; // dump all Meta tags only
121 vector<string> infiles;
123 // Enable native language support, i.e. internationalization
124 #ifdef ENABLE_NLS
125 setlocale (LC_ALL, "");
126 bindtextdomain (PACKAGE, LOCALEDIR);
127 textdomain (PACKAGE);
128 #endif
129 const Arg_parser::Option opts[] =
131 { 'h', "help", Arg_parser::no },
132 { 'v', "verbose", Arg_parser::no },
133 { 'd', "dump", Arg_parser::no },
134 { 'a', "all", Arg_parser::no },
135 { 'm', "meta", Arg_parser::no },
138 Arg_parser parser(argc, argv, opts);
139 if( ! parser.error().empty() ) {
140 cout << parser.error() << endl;
141 exit(EXIT_FAILURE);
144 for( int i = 0; i < parser.arguments(); ++i ) {
145 const int code = parser.code(i);
146 try {
147 switch( code ) {
148 case 'h':
149 usage ();
150 exit(EXIT_SUCCESS);
151 case 'v':
152 dbglogfile.setVerbosity();
153 log_debug(_("Verbose output turned on"));
154 break;
155 case 'd':
156 dump = true;
157 break;
158 case 'a':
159 all = true;
160 break;
161 case 'm':
162 meta = true;
163 break;
164 case 0:
165 infiles.push_back(parser.argument(i));
166 break;
170 catch (Arg_parser::ArgParserException &e) {
171 cerr << _("Error parsing command line options: ") << e.what() << endl;
172 cerr << _("This is a Gnash flvdumper bug.") << endl;
176 if (infiles.empty()) {
177 cerr << _("Error: no input file was specified. Exiting.") << endl;
178 usage();
179 return EXIT_FAILURE;
182 // Get the filename from the command line
183 string filespec = infiles[0];
185 Flv flv;
186 struct stat st;
188 // std::shared_ptr<Flv::flv_header_t> head;
189 Flv::previous_size_t previous = 0;
190 std::shared_ptr<Flv::flv_tag_t> tag;
192 // Make sure it's an FLV file
193 if (stat(filespec.c_str(), &st) == 0) {
194 try {
195 // Open the binary file
196 ifstream ifs(filespec.c_str(), ios::binary);
197 std::shared_ptr<cygnal::Buffer> buf(new Buffer);
198 // Read just the initial 9 byte header
199 ifs.read(reinterpret_cast<char *>(buf->reference()), sizeof(Flv::flv_header_t));
200 log_debug("header is: %s", hexify(buf->reference(), 9, false));
201 std::shared_ptr<Flv::flv_header_t> head = flv.decodeHeader(buf);
202 if (head == 0) {
203 log_error("Couldn't decode the header! %s", hexify(buf->reference(), 9, false));
204 exit(EXIT_FAILURE);
206 if ((head->type & Flv::FLV_VIDEO) && (head->type & Flv::FLV_AUDIO)) {
207 cout <<"FLV File type: Video and Audio" << endl;
208 } else if (head->type && Flv::FLV_VIDEO) {
209 cout << "FLV File type: Video" << endl;
210 } else if (head->type && Flv::FLV_AUDIO) {
211 cout <<"FLV File type: Audio" << endl;
214 cout << "FLV Version: " << int(head->version) << " (should always be 1)" << endl;
215 std::uint32_t headsize = flv.convert24(head->head_size);
216 if (all) {
217 cout << "FLV Header size: " << headsize << " (should always be 9)" << endl;
219 // Extract all the Tags
220 //size_t total = st.st_size - sizeof(Flv::flv_header_t);
221 while (!ifs.eof()) {
222 ifs.read(reinterpret_cast<char *>(&previous), sizeof(Flv::previous_size_t));
223 if (ifs.gcount() != sizeof(Flv::previous_size_t)) {
224 log_error("Couldn't read the entire header");
227 previous = ntohl(previous);
228 //total -= sizeof(Flv::previous_size_t);
229 if (all) {
230 cout << "FLV Previous Tag Size was: " << previous << endl;
232 ifs.read(reinterpret_cast<char *>(buf->reference()), sizeof(Flv::flv_tag_t));
233 if (ifs.gcount() != sizeof(Flv::flv_tag_t)) {
234 log_error("Couldn't read the entire tag");
236 tag = flv.decodeTagHeader(buf);
237 if (dump) {
238 flv.dump();
240 //total -= sizeof(Flv::previous_size_t);
241 size_t bodysize = flv.convert24(tag->bodysize);
242 if (bodysize == 0) {
243 cerr << "FLV Tag size is zero, skipping reading packet body " << bodysize << endl;
244 continue;
245 } else {
246 if (all) {
247 cout << "FLV Tag size is: " << bodysize + sizeof(Flv::previous_size_t) << endl;
250 buf->resize(bodysize);
251 ifs.read(reinterpret_cast<char *>(buf->reference()), bodysize);
252 // if (ifs.gcount() != bodysize) {
253 // log_error("Couldn't read the entire body");
254 // }
255 //total -= bodysize;
256 switch (tag->type) {
257 case Flv::TAG_AUDIO:
259 if (all) {
260 cerr << "FLV Tag type is: Audio" << endl;
261 std::shared_ptr<Flv::flv_audio_t> data = flv.decodeAudioData(*(buf->reference() + sizeof(Flv::flv_tag_t)));
262 cout << "\tSound Type is: " << type_strs[data->type] << endl;
263 cout << "\tSound Size is: " << size_strs[data->size] << endl;
264 cout << "\tSound Rate is: " << rate_strs[data->rate] << endl;
265 cout << "\tSound Format is: " << format_strs[data->format] << endl;
267 break;
269 case Flv::TAG_VIDEO:
271 if (all) {
272 cout << "FLV Tag type is: Video" << endl;
273 std::shared_ptr<Flv::flv_video_t> data = flv.decodeVideoData(*(buf->reference() + sizeof(Flv::flv_tag_t)));
274 cout << "\tCodec ID is: " << codec_strs[data->codecID] << endl;
275 cout << "\tFrame Type is: " << frame_strs[data->type] << endl;
277 break;
279 case Flv::TAG_METADATA:
280 if (meta || all) {
281 cout << "FLV Tag type is: MetaData" << endl;
283 std::shared_ptr<cygnal::Element> metadata = flv.decodeMetaData(buf->reference(), bodysize);
284 if (meta && metadata) {
285 metadata->dump();
287 continue;
290 } catch (std::exception& e) {
291 log_error("Reading %s: %s", filespec, e.what());
292 return false;
297 /// \brief Display the command line arguments
298 static void
299 usage ()
301 cerr << _("This program dumps the internal data of an FLV video file")
302 << endl;
303 cerr << _("Usage: flvdumper [-h] [-m] [-a] filename") << endl;
304 cerr << _("-h\tHelp") << endl;
305 cerr << _("-m\tPrint only Meta tags (default)") << endl;
306 cerr << _("-a\tPrint all tags.") << endl;
307 exit (-1);
310 // Local Variables:
311 // mode: C++
312 // indent-tabs-mode: t
313 // End: