newlines are valid inside elements!
[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 || m_ReadCount >= m_DataLength )
160     return RESULT_ENDOFFILE;
161
162   if ( FB.Capacity() < m_FrameBufferSize )
163     {
164       DefaultLogSink().Error("FrameBuf.Capacity: %u FrameLength: %u\n",
165                              FB.Capacity(), m_FrameBufferSize);
166       return RESULT_SMALLBUF;
167     }
168
169   ui32_t read_count = 0;
170   Result_t result = m_FileReader.Read(FB.Data(), m_FrameBufferSize, &read_count);
171
172   if ( result == RESULT_ENDOFFILE )
173     {
174       m_EOF = true;
175
176       if ( read_count > 0 )
177         result = RESULT_OK;
178     }
179
180   if ( ASDCP_SUCCESS(result) )
181     {
182       m_ReadCount += read_count;
183       FB.Size(read_count);
184       FB.FrameNumber(m_FramesRead++);
185     }
186
187   return result;
188 }
189
190
191 //------------------------------------------------------------------------------------------
192
193 ASDCP::PCM::WAVParser::WAVParser()
194 {
195 }
196
197 ASDCP::PCM::WAVParser::~WAVParser()
198 {
199 }
200
201 // Opens the stream for reading, parses enough data to provide a complete
202 // set of stream metadata for the MXFWriter below.
203 ASDCP::Result_t
204 ASDCP::PCM::WAVParser::OpenRead(const std::string& filename, const Rational& PictureRate) const
205 {
206   const_cast<ASDCP::PCM::WAVParser*>(this)->m_Parser = new h__WAVParser;
207
208   Result_t result = m_Parser->OpenRead(filename, PictureRate);
209
210   if ( ASDCP_FAILURE(result) )
211     const_cast<ASDCP::PCM::WAVParser*>(this)->m_Parser.release();
212
213   return result;
214 }
215
216 // Rewinds the stream to the beginning.
217 ASDCP::Result_t
218 ASDCP::PCM::WAVParser::Reset() const
219 {
220   if ( m_Parser.empty() )
221     return RESULT_INIT;
222
223   m_Parser->Reset();
224   return RESULT_OK;
225 }
226
227 // Places a frame of data in the frame buffer. Fails if the buffer is too small
228 // or the stream is empty.
229 ASDCP::Result_t
230 ASDCP::PCM::WAVParser::ReadFrame(FrameBuffer& FB) const
231 {
232   if ( m_Parser.empty() )
233     return RESULT_INIT;
234
235   return m_Parser->ReadFrame(FB);
236 }
237
238 ASDCP::Result_t
239 ASDCP::PCM::WAVParser::FillAudioDescriptor(AudioDescriptor& ADesc) const
240 {
241   if ( m_Parser.empty() )
242     return RESULT_INIT;
243
244   ADesc = m_Parser->m_ADesc;
245   return RESULT_OK;
246 }
247
248
249 //
250 // end PCM_Parser.cpp
251 //