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