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