added Mikey's patch for Solaris
[asdcplib.git] / src / PCM_Parser.cpp
1 /*
2 Copyright (c) 2004-2011, 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    PCM_Parser.cpp
28     \version $Id$
29     \brief   AS-DCP library, PCM raw essence reader implementation
30 */
31
32 #include <Wav.h>
33 #include <assert.h>
34 #include <KM_log.h>
35 using Kumu::DefaultLogSink;
36
37 using namespace ASDCP;
38 using namespace ASDCP::PCM;
39 using namespace ASDCP::Wav;
40 using namespace ASDCP::RF64;
41
42
43 //------------------------------------------------------------------------------------------
44
45 //
46 class ASDCP::PCM::WAVParser::h__WAVParser
47 {
48   Kumu::FileReader m_FileReader;
49   bool             m_EOF;
50   ui32_t           m_DataStart;
51   ui64_t           m_DataLength;
52   ui64_t           m_ReadCount;
53   ui32_t           m_FrameBufferSize;
54   ui32_t           m_FramesRead;
55   Rational         m_PictureRate;
56
57   ASDCP_NO_COPY_CONSTRUCT(h__WAVParser);
58
59 public:
60   AudioDescriptor  m_ADesc;
61
62
63   h__WAVParser() :
64     m_EOF(false), m_DataStart(0), m_DataLength(0), m_ReadCount(0),
65     m_FrameBufferSize(0), m_FramesRead(0) {}
66
67   ~h__WAVParser()
68   {
69     Close();
70    }
71
72   Result_t OpenRead(const std::string& filename, const Rational& PictureRate);
73   void     Close();
74   void     Reset();
75   Result_t ReadFrame(FrameBuffer&);
76 };
77
78
79 //
80 void
81 ASDCP::PCM::WAVParser::h__WAVParser::Close()
82 {
83   m_FileReader.Close();
84 }
85
86 //
87 void
88 ASDCP::PCM::WAVParser::h__WAVParser::Reset()
89 {
90   m_FileReader.Seek(m_DataStart);
91   m_FramesRead = 0;
92   m_ReadCount = 0;
93 }
94
95 //
96 ASDCP::Result_t
97 ASDCP::PCM::WAVParser::h__WAVParser::OpenRead(const std::string& filename, const Rational& PictureRate)
98 {
99   Result_t result = m_FileReader.OpenRead(filename);
100
101   if ( ASDCP_SUCCESS(result) )
102     {
103       SimpleWaveHeader WavHeader;
104       result = WavHeader.ReadFromFile(m_FileReader, &m_DataStart);
105   
106       if ( ASDCP_SUCCESS(result) )
107         {
108           WavHeader.FillADesc(m_ADesc, PictureRate);
109           m_FrameBufferSize = ASDCP::PCM::CalcFrameBufferSize(m_ADesc);
110           m_DataLength = WavHeader.data_len;
111           m_ADesc.ContainerDuration = m_DataLength / m_FrameBufferSize;
112           m_ADesc.ChannelFormat = PCM::CF_NONE;
113           Reset();
114         }
115       else
116         {
117           ASDCP::AIFF::SimpleAIFFHeader AIFFHeader;
118           m_FileReader.Seek(0);
119
120           result = AIFFHeader.ReadFromFile(m_FileReader, &m_DataStart);
121
122           if ( ASDCP_SUCCESS(result) )
123             {
124               AIFFHeader.FillADesc(m_ADesc, PictureRate);
125               m_FrameBufferSize = ASDCP::PCM::CalcFrameBufferSize(m_ADesc);
126               m_DataLength = AIFFHeader.data_len;
127               m_ADesc.ContainerDuration = m_DataLength / m_FrameBufferSize;
128               m_ADesc.ChannelFormat = PCM::CF_NONE;
129               Reset();
130             }
131           else
132             {
133               SimpleRF64Header RF64Header;
134               m_FileReader.Seek(0);
135               result = RF64Header.ReadFromFile(m_FileReader, &m_DataStart);
136
137               if ( ASDCP_SUCCESS(result) )
138                 {
139                   RF64Header.FillADesc(m_ADesc, PictureRate);
140                   m_FrameBufferSize = ASDCP::PCM::CalcFrameBufferSize(m_ADesc);
141                   m_DataLength = RF64Header.data_len;
142                   m_ADesc.ContainerDuration = m_DataLength / m_FrameBufferSize;
143                   m_ADesc.ChannelFormat = PCM::CF_NONE;
144                   Reset();
145                 }
146             }
147         }
148     }
149
150   return result;
151 }
152
153 //
154 ASDCP::Result_t
155 ASDCP::PCM::WAVParser::h__WAVParser::ReadFrame(FrameBuffer& FB)
156 {
157   FB.Size(0);
158
159   if ( m_EOF )
160     {
161       return RESULT_ENDOFFILE;
162     }
163
164   if ( FB.Capacity() < m_FrameBufferSize )
165     {
166       DefaultLogSink().Error("FrameBuf.Capacity: %u FrameLength: %u\n",
167                              FB.Capacity(), m_FrameBufferSize);
168       return RESULT_SMALLBUF;
169     }
170
171   ui32_t read_count = 0;
172   Result_t result = m_FileReader.Read(FB.Data(), m_FrameBufferSize, &read_count);
173
174   if ( result == RESULT_ENDOFFILE )
175     {
176       m_EOF = true;
177
178       if ( read_count > 0 )
179         {
180           result = RESULT_OK;
181         }
182     }
183
184   if ( ASDCP_SUCCESS(result) )
185     {
186       m_ReadCount += read_count;
187       FB.Size(read_count);
188       FB.FrameNumber(m_FramesRead++);
189
190       if ( read_count < FB.Capacity() )
191         {
192           memset(FB.Data() + FB.Size(), 0, FB.Capacity() - FB.Size());
193         }
194     }
195
196   return result;
197 }
198
199
200 //------------------------------------------------------------------------------------------
201
202 ASDCP::PCM::WAVParser::WAVParser()
203 {
204 }
205
206 ASDCP::PCM::WAVParser::~WAVParser()
207 {
208 }
209
210 // Opens the stream for reading, parses enough data to provide a complete
211 // set of stream metadata for the MXFWriter below.
212 ASDCP::Result_t
213 ASDCP::PCM::WAVParser::OpenRead(const std::string& filename, const Rational& PictureRate) const
214 {
215   const_cast<ASDCP::PCM::WAVParser*>(this)->m_Parser = new h__WAVParser;
216
217   Result_t result = m_Parser->OpenRead(filename, PictureRate);
218
219   if ( ASDCP_FAILURE(result) )
220     const_cast<ASDCP::PCM::WAVParser*>(this)->m_Parser.release();
221
222   return result;
223 }
224
225 // Rewinds the stream to the beginning.
226 ASDCP::Result_t
227 ASDCP::PCM::WAVParser::Reset() const
228 {
229   if ( m_Parser.empty() )
230     return RESULT_INIT;
231
232   m_Parser->Reset();
233   return RESULT_OK;
234 }
235
236 // Places a frame of data in the frame buffer. Fails if the buffer is too small
237 // or the stream is empty.
238 ASDCP::Result_t
239 ASDCP::PCM::WAVParser::ReadFrame(FrameBuffer& FB) const
240 {
241   if ( m_Parser.empty() )
242     return RESULT_INIT;
243
244   return m_Parser->ReadFrame(FB);
245 }
246
247 ASDCP::Result_t
248 ASDCP::PCM::WAVParser::FillAudioDescriptor(AudioDescriptor& ADesc) const
249 {
250   if ( m_Parser.empty() )
251     return RESULT_INIT;
252
253   ADesc = m_Parser->m_ADesc;
254   return RESULT_OK;
255 }
256
257
258 //
259 // end PCM_Parser.cpp
260 //