1 /*****************************************************************
2 |
3 | AP4 - MP4 Compacter
4 |
5 | Copyright 2002-2011 Axiomatic Systems, LLC
6 |
7 |
8 | This file is part of Bento4/AP4 (MP4 Atom Processing Library).
9 |
10 | Unless you have obtained Bento4 under a difference license,
11 | this version of Bento4 is Bento4|GPL.
12 | Bento4|GPL is free software; you can redistribute it and/or modify
13 | it under the terms of the GNU General Public License as published by
14 | the Free Software Foundation; either version 2, or (at your option)
15 | any later version.
16 |
17 | Bento4|GPL is distributed in the hope that it will be useful,
18 | but WITHOUT ANY WARRANTY; without even the implied warranty of
19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 | GNU General Public License for more details.
21 |
22 | You should have received a copy of the GNU General Public License
23 | along with Bento4|GPL; see the file COPYING. If not, write to the
24 | Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
25 | 02111-1307, USA.
26 |
27 ****************************************************************/
28
29 /*----------------------------------------------------------------------
30 | includes
31 +---------------------------------------------------------------------*/
32 #include <stdio.h>
33 #include <stdlib.h>
34
35 #include "Ap4.h"
36
37 /*----------------------------------------------------------------------
38 | constants
39 +---------------------------------------------------------------------*/
40 #define BANNER "MP4 Compacter - Version 1.0\n"\
41 "(Bento4 Version " AP4_VERSION_STRING ")\n"\
42 "(c) 2002-2011 Axiomatic Systems, LLC"
43
44 /*----------------------------------------------------------------------
45 | PrintUsageAndExit
46 +---------------------------------------------------------------------*/
47 static void
PrintUsageAndExit()48 PrintUsageAndExit()
49 {
50 fprintf(stderr,
51 BANNER
52 "\n\n"
53 "usage: mp4compact [options] <input> <output>\n"
54 "Options:\n"
55 " --verbose\n"
56 );
57 exit(1);
58 }
59
60 /*----------------------------------------------------------------------
61 | AP4_CompactingProcessor
62 +---------------------------------------------------------------------*/
63 class AP4_CompactingProcessor : public AP4_Processor
64 {
65 public:
66 // inner classes
67 class TrackHandler : public AP4_Processor::TrackHandler
68 {
69 public:
TrackHandler(AP4_CompactingProcessor & outer,AP4_TrakAtom * trak_atom)70 TrackHandler(AP4_CompactingProcessor& outer, AP4_TrakAtom* trak_atom) :
71 m_Outer(outer),
72 m_TrakAtom(trak_atom),
73 m_StszAtom(NULL) {}
74 ~TrackHandler();
75 virtual AP4_Result ProcessTrack();
ProcessSample(AP4_DataBuffer & data_in,AP4_DataBuffer & data_out)76 virtual AP4_Result ProcessSample(AP4_DataBuffer& data_in,
77 AP4_DataBuffer& data_out) {
78 return data_out.SetData(data_in.GetData(), data_in.GetDataSize());
79 }
80 private:
81 AP4_CompactingProcessor& m_Outer;
82 AP4_TrakAtom* m_TrakAtom;
83 AP4_StszAtom* m_StszAtom;
84 };
85
86 // methods
AP4_CompactingProcessor(bool verbose)87 AP4_CompactingProcessor(bool verbose) : m_Verbose(verbose), m_SizeReduction(0) {}
88 ~AP4_CompactingProcessor();
CreateTrackHandler(AP4_TrakAtom * trak_atom)89 virtual TrackHandler* CreateTrackHandler(AP4_TrakAtom* trak_atom) {
90 return new TrackHandler(*this, trak_atom);
91 }
92
93 // members
94 bool m_Verbose;
95 AP4_UI32 m_SizeReduction;
96 };
97
98 /*----------------------------------------------------------------------
99 | AP4_CompactingProcessor::~AP4_CompactingProcessor
100 +---------------------------------------------------------------------*/
~AP4_CompactingProcessor()101 AP4_CompactingProcessor::~AP4_CompactingProcessor()
102 {
103 if (m_Verbose) {
104 printf("Total stz2 reduction = %d bytes\n", m_SizeReduction);
105 }
106 }
107
108 /*----------------------------------------------------------------------
109 | AP4_CompactingProcessor::TrackHandler::~TrackHandler()
110 +---------------------------------------------------------------------*/
~TrackHandler()111 AP4_CompactingProcessor::TrackHandler::~TrackHandler()
112 {
113 delete m_StszAtom;
114 }
115
116 /*----------------------------------------------------------------------
117 | AP4_CompactingProcessor::TrackHandler::ProcessTrack
118 +---------------------------------------------------------------------*/
119 AP4_Result
ProcessTrack()120 AP4_CompactingProcessor::TrackHandler::ProcessTrack()
121 {
122 // find the stsz atom
123 AP4_ContainerAtom* stbl = AP4_DYNAMIC_CAST(AP4_ContainerAtom, m_TrakAtom->FindChild("mdia/minf/stbl"));
124 if (stbl == NULL) return AP4_SUCCESS;
125 AP4_StszAtom* stsz = AP4_DYNAMIC_CAST(AP4_StszAtom, stbl->GetChild(AP4_ATOM_TYPE_STSZ));
126 if (stsz == NULL) return AP4_SUCCESS;
127
128 // check if we can reduce the size of stsz by changing it to stz2
129 AP4_UI32 max_size = 0;
130 for (unsigned int i=1; i<=stsz->GetSampleCount(); i++) {
131 AP4_Size sample_size;
132 stsz->GetSampleSize(i, sample_size);
133 if (sample_size > max_size) {
134 max_size = sample_size;
135 }
136 }
137 AP4_UI08 field_size = 0;
138 if (max_size <= 0xFF) {
139 field_size = 1;
140 } else if (max_size <= 0xFFFF) {
141 field_size = 2;
142 }
143 if (m_Outer.m_Verbose) printf("Track %d: ", m_TrakAtom->GetId());
144 if (field_size == 0) {
145 if (m_Outer.m_Verbose) {
146 printf("no stz2 reduction possible\n");
147 }
148 return AP4_SUCCESS;
149 } else {
150 if (m_Outer.m_Verbose) {
151 unsigned int reduction = (4-field_size)*stsz->GetSampleCount();
152 printf("stz2 reduction = %d bytes\n", reduction);
153 m_Outer.m_SizeReduction += reduction;
154 }
155 }
156
157 // detach the original stsz atom so we can destroy it later
158 m_StszAtom = stsz;
159 stsz->Detach();
160
161 // create an stz2 atom and populate its entries
162 AP4_Stz2Atom* stz2 = new AP4_Stz2Atom(field_size);
163 for (unsigned int i=1; i<=m_StszAtom->GetSampleCount(); i++) {
164 AP4_Size sample_size;
165 m_StszAtom->GetSampleSize(i, sample_size);
166 stz2->AddEntry(sample_size);
167 }
168 stbl->AddChild(stz2);
169
170 return AP4_SUCCESS;
171 }
172
173 /*----------------------------------------------------------------------
174 | main
175 +---------------------------------------------------------------------*/
176 int
main(int argc,char ** argv)177 main(int argc, char** argv)
178 {
179 if (argc == 1) PrintUsageAndExit();
180
181 // parse options
182 const char* input_filename = NULL;
183 const char* output_filename = NULL;
184 bool verbose = false;
185 AP4_Result result;
186
187 // parse the command line arguments
188 char* arg;
189 while ((arg = *++argv)) {
190 if (!AP4_CompareStrings(arg, "--verbose")) {
191 verbose = true;
192 } else if (input_filename == NULL) {
193 input_filename = arg;
194 } else if (output_filename == NULL) {
195 output_filename = arg;
196 } else {
197 fprintf(stderr, "ERROR: unexpected argument (%s)\n", arg);
198 return 1;
199 }
200 }
201
202 // create the input stream
203 AP4_ByteStream* input = NULL;
204 result = AP4_FileByteStream::Create(input_filename, AP4_FileByteStream::STREAM_MODE_READ, input);
205 if (AP4_FAILED(result)) {
206 fprintf(stderr, "ERROR: cannot open input file (%s)\n", input_filename);
207 return 1;
208 }
209
210 // create the output stream
211 AP4_ByteStream* output = NULL;
212 result = AP4_FileByteStream::Create(output_filename, AP4_FileByteStream::STREAM_MODE_WRITE, output);
213 if (AP4_FAILED(result)) {
214 fprintf(stderr, "ERROR: cannot open output file (%s)\n", output_filename);
215 return 1;
216 }
217
218 // process the file
219 AP4_CompactingProcessor* processor = new AP4_CompactingProcessor(verbose);
220 result = processor->Process(*input, *output, NULL);
221 if (AP4_FAILED(result)) {
222 fprintf(stderr, "ERROR: failed to process the file (%d)\n", result);
223 }
224
225 // cleanup
226 delete processor;
227 input->Release();
228 output->Release();
229
230 return 0;
231 }
232