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