Bump patch version post tag.
[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   Result_t Seek(ui32_t frame_number);
77 };
78
79
80 //
81 void
82 ASDCP::PCM::WAVParser::h__WAVParser::Close()
83 {
84   m_FileReader.Close();
85 }
86
87 //
88 void
89 ASDCP::PCM::WAVParser::h__WAVParser::Reset()
90 {
91   m_FileReader.Seek(m_DataStart);
92   m_FramesRead = 0;
93   m_ReadCount = 0;
94 }
95
96 //
97 ASDCP::Result_t
98 ASDCP::PCM::WAVParser::h__WAVParser::OpenRead(const std::string& filename, const Rational& PictureRate)
99 {
100   Result_t result = m_FileReader.OpenRead(filename);
101
102   if ( ASDCP_SUCCESS(result) )
103     {
104       SimpleWaveHeader WavHeader;
105       result = WavHeader.ReadFromFile(m_FileReader, &m_DataStart);
106   
107       if ( ASDCP_SUCCESS(result) )
108         {
109           WavHeader.FillADesc(m_ADesc, PictureRate);
110           m_FrameBufferSize = ASDCP::PCM::CalcFrameBufferSize(m_ADesc);
111           m_DataLength = WavHeader.data_len;
112           m_ADesc.ContainerDuration = m_DataLength / m_FrameBufferSize;
113           m_ADesc.ChannelFormat = PCM::CF_NONE;
114           Reset();
115         }
116       else
117         {
118           ASDCP::AIFF::SimpleAIFFHeader AIFFHeader;
119           m_FileReader.Seek(0);
120
121           result = AIFFHeader.ReadFromFile(m_FileReader, &m_DataStart);
122
123           if ( ASDCP_SUCCESS(result) )
124             {
125               AIFFHeader.FillADesc(m_ADesc, PictureRate);
126               m_FrameBufferSize = ASDCP::PCM::CalcFrameBufferSize(m_ADesc);
127               m_DataLength = AIFFHeader.data_len;
128               m_ADesc.ContainerDuration = m_DataLength / m_FrameBufferSize;
129               m_ADesc.ChannelFormat = PCM::CF_NONE;
130               Reset();
131             }
132           else
133             {
134               SimpleRF64Header RF64Header;
135               m_FileReader.Seek(0);
136               result = RF64Header.ReadFromFile(m_FileReader, &m_DataStart);
137
138               if ( ASDCP_SUCCESS(result) )
139                 {
140                   RF64Header.FillADesc(m_ADesc, PictureRate);
141                   m_FrameBufferSize = ASDCP::PCM::CalcFrameBufferSize(m_ADesc);
142                   m_DataLength = RF64Header.data_len;
143                   m_ADesc.ContainerDuration = m_DataLength / m_FrameBufferSize;
144                   m_ADesc.ChannelFormat = PCM::CF_NONE;
145                   Reset();
146                 }
147             }
148         }
149     }
150
151   return result;
152 }
153
154 //
155 ASDCP::Result_t
156 ASDCP::PCM::WAVParser::h__WAVParser::ReadFrame(FrameBuffer& FB)
157 {
158   FB.Size(0);
159
160   if ( m_EOF )
161     {
162       return RESULT_ENDOFFILE;
163     }
164
165   if ( FB.Capacity() < m_FrameBufferSize )
166     {
167       DefaultLogSink().Error("FrameBuf.Capacity: %u FrameLength: %u\n",
168                              FB.Capacity(), m_FrameBufferSize);
169       return RESULT_SMALLBUF;
170     }
171
172   ui32_t read_count = 0;
173   Result_t result = m_FileReader.Read(FB.Data(), m_FrameBufferSize, &read_count);
174
175   if ( result == RESULT_ENDOFFILE )
176     {
177       m_EOF = true;
178
179       if ( read_count > 0 )
180         {
181           result = RESULT_OK;
182         }
183     }
184
185   if ( ASDCP_SUCCESS(result) )
186     {
187       m_ReadCount += read_count;
188       FB.Size(read_count);
189       FB.FrameNumber(m_FramesRead++);
190
191       if ( read_count < FB.Capacity() )
192         {
193           memset(FB.Data() + FB.Size(), 0, FB.Capacity() - FB.Size());
194         }
195     }
196
197   return result;
198 }
199
200 //
201 ASDCP::Result_t ASDCP::PCM::WAVParser::h__WAVParser::Seek(ui32_t frame_number)
202 {
203   m_FramesRead = frame_number - 1;
204   m_ReadCount = 0;
205   return m_FileReader.Seek(m_DataStart + m_FrameBufferSize * frame_number);
206 }
207
208
209 //------------------------------------------------------------------------------------------
210
211 ASDCP::PCM::WAVParser::WAVParser()
212 {
213 }
214
215 ASDCP::PCM::WAVParser::~WAVParser()
216 {
217 }
218
219 // Opens the stream for reading, parses enough data to provide a complete
220 // set of stream metadata for the MXFWriter below.
221 ASDCP::Result_t
222 ASDCP::PCM::WAVParser::OpenRead(const std::string& filename, const Rational& PictureRate) const
223 {
224   const_cast<ASDCP::PCM::WAVParser*>(this)->m_Parser = new h__WAVParser;
225
226   Result_t result = m_Parser->OpenRead(filename, PictureRate);
227
228   if ( ASDCP_FAILURE(result) )
229     const_cast<ASDCP::PCM::WAVParser*>(this)->m_Parser.release();
230
231   return result;
232 }
233
234 // Rewinds the stream to the beginning.
235 ASDCP::Result_t
236 ASDCP::PCM::WAVParser::Reset() const
237 {
238   if ( m_Parser.empty() )
239     return RESULT_INIT;
240
241   m_Parser->Reset();
242   return RESULT_OK;
243 }
244
245 // Places a frame of data in the frame buffer. Fails if the buffer is too small
246 // or the stream is empty.
247 ASDCP::Result_t
248 ASDCP::PCM::WAVParser::ReadFrame(FrameBuffer& FB) const
249 {
250   if ( m_Parser.empty() )
251     return RESULT_INIT;
252
253   return m_Parser->ReadFrame(FB);
254 }
255
256 ASDCP::Result_t
257 ASDCP::PCM::WAVParser::FillAudioDescriptor(AudioDescriptor& ADesc) const
258 {
259   if ( m_Parser.empty() )
260     return RESULT_INIT;
261
262   ADesc = m_Parser->m_ADesc;
263   return RESULT_OK;
264 }
265
266 ASDCP::Result_t ASDCP::PCM::WAVParser::Seek(ui32_t frame_number) const
267 {
268   if ( m_Parser.empty() )
269     return RESULT_INIT;
270
271   return m_Parser->Seek(frame_number);;
272 }
273
274 //
275 // end PCM_Parser.cpp
276 //