Add call to parent constructor.
[asdcplib-cth.git] / src / PCMParserList.cpp
1 /*
2 Copyright (c) 2004-2015, 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.12 2015/02/19 19:06:57 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 std::string& filename, const Rational& PictureRate)
52 {
53   Result_t result = Parser.OpenRead(filename, PictureRate);
54
55   if ( ASDCP_SUCCESS(result) )
56     result = Parser.FillAudioDescriptor(ADesc);
57
58   if ( ASDCP_SUCCESS(result) )
59     {
60       ADesc.EditRate = PictureRate;
61       m_SampleSize = PCM::CalcSampleSize(ADesc);
62       result = FB.Capacity(PCM::CalcFrameBufferSize(ADesc));
63     }
64
65   return result;
66 }
67
68
69 // deposit the next available sample into the given framebuffer
70 Result_t
71 ASDCP::ParserInstance::PutSample(byte_t* p)
72 {
73   ASDCP_TEST_NULL(p);
74
75   if ( m_p != 0 )
76     {
77       if ( m_p < ( FB.RoData() + FB.Size() ) )
78         {
79           memcpy(p, m_p, m_SampleSize);
80           m_p += m_SampleSize;
81           return RESULT_OK;
82         }
83     }
84
85   return RESULT_ENDOFFILE;
86 }
87
88 //
89 Result_t
90 ASDCP::ParserInstance::ReadFrame()
91 {
92   Result_t result = Parser.ReadFrame(FB);
93   m_p = ASDCP_SUCCESS(result) ? FB.RoData() : 0;
94   return result;
95 }
96
97
98 //------------------------------------------------------------------------------------------
99 //
100
101
102 //
103 ASDCP::PCMParserList::PCMParserList() : m_ChannelCount(0)
104 {
105 }
106
107 ASDCP::PCMParserList::~PCMParserList()
108 {
109   while ( ! empty() )
110     {
111       delete back();
112       pop_back();
113     }
114 }
115
116 //
117 Result_t
118 ASDCP::PCMParserList::OpenRead(ui32_t argc, const char** argv, const Rational& PictureRate)
119 {
120   ASDCP_TEST_NULL(argv);
121   PathList_t TmpFileList;
122
123   for ( ui32_t i = 0; i < argc; ++i )
124     {
125       ASDCP_TEST_NULL(argv[i]);
126       TmpFileList.push_back(argv[i]);
127     }
128
129   return OpenRead(TmpFileList, PictureRate);
130 }
131
132 //
133 Result_t
134 ASDCP::PCMParserList::OpenRead(const Kumu::PathList_t& argv, const Rational& PictureRate)
135 {
136   Result_t result = RESULT_OK;
137   PathList_t::iterator fi;
138   Kumu::PathList_t file_list;
139
140   if ( argv.size() == 1 && PathIsDirectory(argv.front()) )
141     {
142       DirScanner Dir;
143       char name_buf[MaxFilePath];
144       result = Dir.Open(argv.front().c_str());
145
146       if ( KM_SUCCESS(result) )
147         result = Dir.GetNext(name_buf);
148
149       while ( KM_SUCCESS(result) )
150         {
151           if ( name_buf[0] != '.' ) // no hidden files
152             {
153               std::string tmp_path = argv.front() + "/" + name_buf;
154               file_list.push_back(tmp_path);
155             }
156
157           result = Dir.GetNext(name_buf);
158         }
159
160       if ( result == RESULT_ENDOFFILE )
161         {
162           result = RESULT_OK;
163           file_list.sort();
164         }
165     }
166   else
167     {
168       file_list = argv;
169     }
170
171   for ( fi = file_list.begin(); KM_SUCCESS(result) && fi != file_list.end(); ++fi )
172     {
173       mem_ptr<ParserInstance> I = new ParserInstance;
174       result = I->OpenRead(fi->c_str(), PictureRate);
175
176       if ( ASDCP_SUCCESS(result) )
177         {
178           if ( fi == file_list.begin() )
179             {
180               m_ADesc = I->ADesc;
181             }
182           else
183             {
184               if ( I->ADesc.AudioSamplingRate != m_ADesc.AudioSamplingRate )
185                 {
186                   DefaultLogSink().Error("AudioSamplingRate mismatch in PCM parser list.");
187                   return RESULT_FORMAT;
188                 }
189
190               if ( I->ADesc.QuantizationBits  != m_ADesc.QuantizationBits )
191                 {
192                   DefaultLogSink().Error("QuantizationBits mismatch in PCM parser list.");
193                   return RESULT_FORMAT;
194                 }
195
196               if ( I->ADesc.ContainerDuration < m_ADesc.ContainerDuration )
197                 m_ADesc.ContainerDuration = I->ADesc.ContainerDuration;
198
199               m_ADesc.BlockAlign += I->ADesc.BlockAlign;
200             }
201
202           m_ChannelCount += I->ADesc.ChannelCount;
203         }
204
205       if ( ASDCP_SUCCESS(result) )
206         result = I->FB.Capacity(PCM::CalcFrameBufferSize(m_ADesc));
207
208       if ( ASDCP_SUCCESS(result) )
209         {
210           push_back(I);
211           I.release();
212         }
213     }
214
215   if ( ASDCP_SUCCESS(result) )
216     {
217       m_ADesc.ChannelCount = m_ChannelCount;
218       m_ADesc.AvgBps = (ui32_t)(ceil(m_ADesc.AudioSamplingRate.Quotient()) * m_ADesc.BlockAlign);
219     }
220   else
221     {
222       clear();
223     }
224
225   return result;
226 }
227
228 //
229 Result_t
230 ASDCP::PCMParserList::FillAudioDescriptor(PCM::AudioDescriptor& ADesc) const
231 {
232   ADesc = m_ADesc;
233   return RESULT_OK;
234 }
235
236 //
237 Result_t
238 ASDCP::PCMParserList::Reset()
239 {
240   Result_t result = RESULT_OK;
241   PCMParserList::iterator self_i;
242
243   for ( self_i = begin(); self_i != end() && ASDCP_SUCCESS(result) ; self_i++ )
244     result = (*self_i)->Parser.Reset();
245
246   return result;
247 }
248
249
250 //
251 Result_t
252 ASDCP::PCMParserList::ReadFrame(PCM::FrameBuffer& OutFB)
253 {
254   Result_t result = RESULT_OK;
255
256   if ( size() == 1 )
257     {
258       return front()->Parser.ReadFrame(OutFB);
259     }
260
261   PCMParserList::iterator self_i;
262   assert(PCM::CalcFrameBufferSize(m_ADesc) <= OutFB.Capacity());
263
264   for ( self_i = begin(); self_i != end() && ASDCP_SUCCESS(result) ; self_i++ )
265     {
266       result = (*self_i)->ReadFrame();
267     }
268
269   if ( ASDCP_SUCCESS(result) )
270     {
271       byte_t* Out_p = OutFB.Data();
272       byte_t* End_p = Out_p + OutFB.Capacity();
273       ui64_t total_sample_bytes = 0;
274
275       while ( Out_p < End_p && ASDCP_SUCCESS(result) )
276         {
277           self_i = begin();
278
279           while ( self_i != end() && ASDCP_SUCCESS(result) )
280             {
281               result = (*self_i)->PutSample(Out_p);
282
283               if ( ASDCP_SUCCESS(result) )
284                 {
285                   Out_p += (*self_i)->SampleSize();
286                   total_sample_bytes += (*self_i)->SampleSize();
287                   self_i++;
288                 }
289             }
290         }
291
292       OutFB.Size(total_sample_bytes);
293
294       if ( result == RESULT_ENDOFFILE )
295         {
296           result = RESULT_OK;
297         }
298     }
299
300   return result;
301 }
302
303 //
304 // end PCMParserList.cpp
305 //