1 /*
2 * oggDump will dump out an ogg file either by packets or by pages
3 *
4 * Copyright (C) 2008 Joern Seger
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 *
20 */
21
22 #ifdef __WIN32
23 #define __GNU_LIBRARY__
24 #include "../win32/getopt_win.h"
25 #endif
26
27 #include <iostream>
28 #include <map>
29 #include <vector>
30 #include <sstream>
31 #include <fstream>
32 #include <ostream>
33 #include <cstdlib>
34 #include <unistd.h>
35
36 #include "fileRepository.h"
37 #include "rawMediaPacket.h"
38 #include "oggDecoder.h"
39 #include "oggEncoder.h"
40 #include "oggStreamDecoder.h"
41 #include "oggPacket.h"
42 #include "oggBOSExtractorFactory.h"
43 #include "streamSerializer.h"
44 #include "exception.h"
45 #include "log.h"
46
47 struct OutputUnit {
48 OggEncoder encoder;
49 FileRepository repository;
50 };
51
printHelp(std::string programName)52 void printHelp(std::string programName)
53 {
54 logger.error() << "usage <"<<programName<<"> [options] file" << std::endl;
55 logger.error() << "Options are:\n"
56 << " -h : help screen \n"
57 << " -g : dump pages \n"
58 << " -p : dump packets \n"
59 << " -l <level> : information depth; default: 5 (most information)\n"
60 << " -s : promt for streams to dump\n"
61 << " -o <file> : output dump information to a file\n";
62 }
63
dumpPacketof(std::string & file,uint8 dumpLevel,bool promptForStreams,std::string & outFilename)64 void dumpPacketof(std::string& file, uint8 dumpLevel, bool promptForStreams, std::string& outFilename)
65 {
66 /* open the first file to be read */
67 std::vector<StreamConfig> configList;
68 StreamSerializer serializer;
69
70 std::ofstream outStream;
71
72 /* if there is a filename given, write the data to this file */
73 if (!outFilename.empty())
74 outStream.open(outFilename.c_str());
75
76 if (!serializer.open(file)) {
77 logger.error() << "Can not open file <" << file << ">\n";
78 exit(-1);
79 }
80
81 /* read the stream configuration */
82 serializer.getStreamConfig(configList);
83
84 std::vector<uint32> outputStreamNo;
85
86 for (uint32 i(0); i<configList.size(); ++i) {
87 std::cout << "Config of stream No. "<<i<<"\n"
88 << "StreamType: ";
89 switch (configList[i].type) {
90 case OggType::kate:
91 std::cout << "kate\n";
92 break;
93 case OggType::theora:
94 std::cout << "theora\n";
95 break;
96 case OggType::vorbis:
97 std::cout << "vorbis\n";
98 break;
99 }
100
101 std::cout << "serial No : 0x"<< std::hex << configList[i].serialNo;
102 if (configList[i].parameter)
103 //std::cout << configList[i].parameter->toString();
104
105 if (promptForStreams) {
106 std::cout << "Dump this stream? (y/n) \n";
107 char answer;
108 std::cin >> answer;
109
110 if (answer != 'Y' && answer != 'y')
111 outputStreamNo.push_back(configList[i].streamNo);
112
113 std::cout << answer << "\n";
114 }
115 }
116
117 OggPacket packet;
118 double _time;
119 bool print;
120
121 while (serializer.available()) {
122
123 _time = serializer.getNextPacket(packet);
124
125 print = true;
126 for (uint32 i(0); i<outputStreamNo.size(); ++i)
127 if (outputStreamNo[i] == packet->getStreamNo())
128 print = false;
129
130 if (!print)
131 continue;
132
133 if (outFilename.empty()) {
134 std::cout << "\nTime: " << _time;
135 std::cout << packet->toString(dumpLevel);
136 } else {
137 outStream << "\nTime: " << _time;
138 outStream << packet->toString(dumpLevel);
139 }
140 }
141 }
142
oggDumpCmd(int argc,char * argv[])143 int oggDumpCmd(int argc, char* argv[])
144 {
145
146 /* default values
147 * for the command line arguments */
148
149 uint8 dumpLevel(5);
150 std::string outFilename("");
151 bool dumpPages(false);
152 bool dumpPackets(false);
153 bool promptForStreams(false);
154
155 std::string programName(argv[0]);
156
157 int opt;
158 while ((opt = getopt(argc, argv, "hgpl:so:")) != EOF)
159
160 switch (opt) {
161
162 case 'h':
163 printHelp(argv[0]);
164 exit(-1);
165
166 case 'g':
167 dumpPages = true;
168 break;
169
170 case 'p':
171 dumpPackets = true;
172 break;
173
174 case 's':
175 promptForStreams = true;
176 break;
177
178 case 'o':
179 outFilename = std::string(optarg);
180 break;
181
182 case 'l':
183 dumpLevel = atoi(optarg); // yes, I know the atoi bug
184 break;
185
186 }
187
188 argc -= optind;
189 argv += optind;
190
191 std::string analysisFile;
192
193 if (argc == 1)
194 analysisFile = std::string(argv[0]);
195 else {
196 printHelp(programName);
197 exit(-1);
198 }
199
200 if ((!dumpPages) && (!dumpPackets)) {
201 logger.error() << "Specify whether you want to dump pages, packet or both by -g and/or -p\n";
202 exit(-1);
203 }
204
205 if (dumpPackets) {
206 dumpPacketof(analysisFile, dumpLevel, promptForStreams, outFilename);
207 return(0);
208 }
209
210 std::ofstream outStream;
211
212 /* if there is a filename given, write the data to this file */
213 if (!outFilename.empty())
214 outStream.open(outFilename.c_str());
215
216 /* open the m_repository
217 in this easy example, it is a simple file */
218 FileRepository repository(analysisFile, MediaUnit::read);
219
220 OggDecoder oggDecoder;
221 std::map<uint32, OggStreamDecoder> oggStreamDecoderList;
222 std::vector<OggPage> bosPages;
223
224 /* run through the m_repository until there is no data left */
225 while (!repository.isEndOfFile()) {
226
227 RawMediaPacket rawDecoderPacket;
228
229 /* extract a raw data bunch from the file .. */
230 repository >> rawDecoderPacket;
231
232 /* .. and insert it into the ogg decoder */
233 oggDecoder << rawDecoderPacket;
234
235 /* are there any complete ogg Pages available ? */
236 while (oggDecoder.isAvailable()) {
237
238 OggPage oggPage;
239
240 /* grap the next page */
241 oggDecoder >> oggPage;
242
243 /* what ID has this page / what stream does this page belongs to */
244 uint32 serialID = oggPage->serialno();
245
246 if (oggPage->isBOS()) {
247
248 bool addPage(false);
249
250 switch (OggBOSExtractorFactory::getStreamType(oggPage)) {
251
252 case OggType::theora: {
253 std::cout << "Found theora stream with ID= 0x" << std::hex
254 << serialID << std::dec << std::endl;
255 if (promptForStreams) {
256 std::cout << "Dump this stream? (y/n) \n";
257 char answer;
258 std::cin >> answer;
259 if (answer == 'Y' || answer == 'y')
260 addPage = true;
261 std::cout << answer << "\n";
262 } else
263 addPage = true;
264 }
265 break;
266
267 case OggType::vorbis: {
268 std::cout << "Found vorbis stream with ID= 0x" << std::hex
269 << serialID << std::dec << std::endl;
270 if (promptForStreams) {
271 std::cout << "Dump this stream? (y/n) ";
272 char answer;
273 std::cin >> answer;
274 if (answer == 'Y' || answer == 'y')
275 addPage = true;
276 std::cout << answer << "\n";
277 } else
278 addPage = true;
279
280 }
281 break;
282
283 case OggType::kate: {
284 std::cout << "Found kate stream with ID= 0x" << std::hex
285 << serialID << std::dec << std::endl;
286 if (promptForStreams) {
287 std::cout << "Dump this stream? (y/n) ";
288 char answer;
289 std::cin >> answer;
290 if (answer == 'Y' || answer == 'y')
291 addPage = true;
292 std::cout << answer << "\n";
293 } else
294 addPage = true;
295
296 }
297 break;
298
299 default: {
300 std::cout << "Found unknown stream with ID= 0x" << std::hex
301 << serialID << std::dec << std::endl;
302 if (promptForStreams) {
303 std::cout << "Dump this stream? (y/n) \n";
304 char answer;
305 std::cin >> answer;
306 if (answer == 'Y' || answer == 'y')
307 addPage = true;
308 std::cout << answer << "\n";
309 } else
310 addPage = true;
311 }
312 break;
313 }
314 if (addPage) {
315 oggStreamDecoderList[serialID] = OggStreamDecoder();
316 oggStreamDecoderList[serialID] << oggPage;
317 bosPages.push_back(oggPage);
318 }
319
320 } else {
321
322 /* does the user want to dump this stream */
323 if (oggStreamDecoderList.find(serialID) != oggStreamDecoderList.end()) {
324
325 if (dumpPages) {
326
327 std::string outputString;
328
329 // are there any bos pages, then toString them first
330 if (!bosPages.empty()) {
331 for (uint32 j(0); j<bosPages.size(); ++j)
332 outputString += bosPages[j]->toString(dumpLevel);
333 bosPages.clear();
334 }
335
336 outputString += oggPage->toString(dumpLevel);
337
338 if (outFilename.empty())
339 std::cout << outputString;
340 else
341 outStream << outputString;
342
343 }
344
345 }
346 }
347 }
348 }
349
350 /* close all files */
351 repository.close();
352 if (!outFilename.empty())
353 outStream.close();
354
355 return (0);
356 }
357
main(int argc,char * argv[])358 int main(int argc, char* argv[])
359 {
360 //logger.setLevel(OggLog::LOG_DEBUG);
361 try {
362 return oggDumpCmd(argc, argv);
363 } catch (OggException & e) {
364 logger.error() << "Fatal error: " << e.what() << std::endl;
365 return -1;
366 }
367 }
368
369