Simplify time representation; better in-tree DCP subtitle parser.
[libsub.git] / asdcplib / src / PCMParserList.cpp
1 /*
2 Copyright (c) 2004-2012, John Hurst
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8 1. Redistributions of source code must retain the above copyright
9    notice, this list of conditions and the following disclaimer.
10 2. Redistributions in binary form must reproduce the above copyright
11    notice, this list of conditions and the following disclaimer in the
12    documentation and/or other materials provided with the distribution.
13 3. The name of the author may not be used to endorse or promote products
14    derived from this software without specific prior written permission.
15
16 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27 /*! \file    PCMParserList.cpp
28     \version $Id: PCMParserList.cpp,v 1.9 2012/02/21 02:09:31 jhurst Exp $
29     \brief   Read WAV file(s), multiplex multiple PCM frame buffers into one
30 */
31
32 #include <PCMParserList.h>
33 #include <KM_fileio.h>
34 #include <KM_log.h>
35 #include <assert.h>
36
37 using namespace ASDCP;
38 using namespace Kumu;
39
40
41 ASDCP::ParserInstance::ParserInstance() : m_p(0), m_SampleSize(0)
42 {
43 }
44
45 ASDCP::ParserInstance::~ParserInstance()
46 {
47 }
48
49 // PCM::CalcSampleSize(ADesc);
50 Result_t
51 ASDCP::ParserInstance::OpenRead(const char* filename, const Rational& PictureRate)
52 {
53   ASDCP_TEST_NULL_STR(filename);
54
55   Result_t result = Parser.OpenRead(filename, PictureRate);
56
57   if ( ASDCP_SUCCESS(result) )
58     result = Parser.FillAudioDescriptor(ADesc);
59
60   if ( ASDCP_SUCCESS(result) )
61     {
62       ADesc.EditRate = PictureRate;
63       m_SampleSize = PCM::CalcSampleSize(ADesc);
64       result = FB.Capacity(PCM::CalcFrameBufferSize(ADesc));
65     }
66
67   return result;
68 }
69
70
71 // deposit the next available sample into the given framebuffer
72 Result_t
73 ASDCP::ParserInstance::PutSample(byte_t* p)
74 {
75   ASDCP_TEST_NULL(p);
76
77   memcpy(p, m_p, m_SampleSize);
78   m_p += m_SampleSize;
79   return RESULT_OK;
80 }
81
82
83 //
84 Result_t
85 ASDCP::ParserInstance::ReadFrame()
86 {
87   Result_t result = Parser.ReadFrame(FB);
88   m_p = ASDCP_SUCCESS(result) ? FB.RoData() : 0;
89   return result;
90 }
91
92
93 //------------------------------------------------------------------------------------------
94 //
95
96
97 //
98 ASDCP::PCMParserList::PCMParserList() : m_ChannelCount(0)
99 {
100 }
101
102 ASDCP::PCMParserList::~PCMParserList()
103 {
104   while ( ! empty() )
105     {
106       delete back();
107       pop_back();
108     }
109 }
110
111 //
112 Result_t
113 ASDCP::PCMParserList::OpenRead(ui32_t argc, const char** argv, const Rational& PictureRate)
114 {
115   ASDCP_TEST_NULL_STR(argv);
116   PathList_t TmpFileList;
117
118   for ( ui32_t i = 0; i < argc; ++i )
119     TmpFileList.push_back(argv[i]);
120
121   return OpenRead(TmpFileList, PictureRate);
122 }
123
124 //
125 Result_t
126 ASDCP::PCMParserList::OpenRead(const Kumu::PathList_t& argv, const Rational& PictureRate)
127 {
128   Result_t result = RESULT_OK;
129   PathList_t::iterator fi;
130   Kumu::PathList_t file_list;
131
132   if ( argv.size() == 1 && PathIsDirectory(argv.front()) )
133     {
134       DirScanner Dir;
135       char name_buf[MaxFilePath];
136       result = Dir.Open(argv.front().c_str());
137
138       if ( KM_SUCCESS(result) )
139         result = Dir.GetNext(name_buf);
140
141       while ( KM_SUCCESS(result) )
142         {
143           if ( name_buf[0] != '.' ) // no hidden files
144             {
145               std::string tmp_path = argv.front() + "/" + name_buf;
146               file_list.push_back(tmp_path);
147             }
148
149           result = Dir.GetNext(name_buf);
150         }
151
152       if ( result == RESULT_ENDOFFILE )
153         {
154           result = RESULT_OK;
155           file_list.sort();
156         }
157     }
158   else
159     {
160       file_list = argv;
161     }
162
163   for ( fi = file_list.begin(); KM_SUCCESS(result) && fi != file_list.end(); ++fi )
164     {
165       mem_ptr<ParserInstance> I = new ParserInstance;
166       result = I->OpenRead(fi->c_str(), PictureRate);
167
168       if ( ASDCP_SUCCESS(result) )
169         {
170           if ( fi == file_list.begin() )
171             {
172               m_ADesc = I->ADesc;
173             }
174           else
175             {
176               if ( I->ADesc.AudioSamplingRate != m_ADesc.AudioSamplingRate )
177                 {
178                   DefaultLogSink().Error("AudioSamplingRate mismatch in PCM parser list.");
179                   return RESULT_FORMAT;
180                 }
181
182               if ( I->ADesc.QuantizationBits  != m_ADesc.QuantizationBits )
183                 {
184                   DefaultLogSink().Error("QuantizationBits mismatch in PCM parser list.");
185                   return RESULT_FORMAT;
186                 }
187
188               if ( I->ADesc.ContainerDuration < m_ADesc.ContainerDuration )
189                 m_ADesc.ContainerDuration = I->ADesc.ContainerDuration;
190
191               m_ADesc.BlockAlign += I->ADesc.BlockAlign;
192             }
193
194           m_ChannelCount += I->ADesc.ChannelCount;
195         }
196
197       if ( ASDCP_SUCCESS(result) )
198         result = I->FB.Capacity(PCM::CalcFrameBufferSize(m_ADesc));
199
200       if ( ASDCP_SUCCESS(result) )
201         {
202           push_back(I);
203           I.release();
204         }
205     }
206
207   if ( ASDCP_SUCCESS(result) )
208     {
209       m_ADesc.ChannelCount = m_ChannelCount;
210       m_ADesc.AvgBps = (ui32_t)(ceil(m_ADesc.AudioSamplingRate.Quotient()) * m_ADesc.BlockAlign);
211     }
212   else
213     {
214       clear();
215     }
216
217   return result;
218 }
219
220 //
221 Result_t
222 ASDCP::PCMParserList::FillAudioDescriptor(PCM::AudioDescriptor& ADesc) const
223 {
224   ADesc = m_ADesc;
225   return RESULT_OK;
226 }
227
228 //
229 Result_t
230 ASDCP::PCMParserList::Reset()
231 {
232   Result_t result = RESULT_OK;
233   PCMParserList::iterator self_i;
234
235   for ( self_i = begin(); self_i != end() && ASDCP_SUCCESS(result) ; self_i++ )
236     result = (*self_i)->Parser.Reset();
237
238   return result;
239 }
240
241
242 //
243 Result_t
244 ASDCP::PCMParserList::ReadFrame(PCM::FrameBuffer& OutFB)
245 {
246   Result_t result = RESULT_OK;
247
248   if ( size() == 1 )
249     return front()->Parser.ReadFrame(OutFB);
250
251   PCMParserList::iterator self_i;
252   assert(PCM::CalcFrameBufferSize(m_ADesc) <= OutFB.Capacity());
253
254   for ( self_i = begin(); self_i != end() && ASDCP_SUCCESS(result) ; self_i++ )
255     result = (*self_i)->ReadFrame();
256
257   if ( ASDCP_SUCCESS(result) )
258     {
259       OutFB.Size(PCM::CalcFrameBufferSize(m_ADesc));
260
261       //      ui32_t sample_size = (PCM::CalcSampleSize(m_ADesc));
262       byte_t* Out_p = OutFB.Data();
263       byte_t* End_p = Out_p + OutFB.Size();
264
265       while ( Out_p < End_p && ASDCP_SUCCESS(result) )
266         {
267           self_i = begin();
268
269           while ( self_i != end() && ASDCP_SUCCESS(result) )
270             {
271               result = (*self_i)->PutSample(Out_p);
272               Out_p += (*self_i)->SampleSize();
273               self_i++;
274             }
275         }
276
277       assert(Out_p == End_p);
278     }
279
280   return result;
281 }
282
283 //
284 // end PCMParserList.cpp
285 //