e3b693d6bcf01928b88fc21362e0eeb7483ef1fc
[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 char* 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 char* filename, const Rational& PictureRate)
98 {
99   ASDCP_TEST_NULL_STR(filename);
100
101   Result_t result = m_FileReader.OpenRead(filename);
102
103   if ( ASDCP_SUCCESS(result) )
104     {
105       SimpleWaveHeader WavHeader;
106       result = WavHeader.ReadFromFile(m_FileReader, &m_DataStart);
107   
108       if ( ASDCP_SUCCESS(result) )
109         {
110           WavHeader.FillADesc(m_ADesc, PictureRate);
111           m_FrameBufferSize = ASDCP::PCM::CalcFrameBufferSize(m_ADesc);
112           m_DataLength = WavHeader.data_len;
113           m_ADesc.ContainerDuration = m_DataLength / m_FrameBufferSize;
114           m_ADesc.ChannelFormat = PCM::CF_NONE;
115           Reset();
116         }
117       else
118         {
119           ASDCP::AIFF::SimpleAIFFHeader AIFFHeader;
120           m_FileReader.Seek(0);
121
122           result = AIFFHeader.ReadFromFile(m_FileReader, &m_DataStart);
123
124           if ( ASDCP_SUCCESS(result) )
125             {
126               AIFFHeader.FillADesc(m_ADesc, PictureRate);
127               m_FrameBufferSize = ASDCP::PCM::CalcFrameBufferSize(m_ADesc);
128               m_DataLength = AIFFHeader.data_len;
129               m_ADesc.ContainerDuration = m_DataLength / m_FrameBufferSize;
130               m_ADesc.ChannelFormat = PCM::CF_NONE;
131               Reset();
132             }
133       else
134         {
135           SimpleRF64Header RF64Header;
136           m_FileReader.Seek(0);
137           result = RF64Header.ReadFromFile(m_FileReader, &m_DataStart);
138
139           if ( ASDCP_SUCCESS(result) )
140             {
141                 RF64Header.FillADesc(m_ADesc, PictureRate);
142                 m_FrameBufferSize = ASDCP::PCM::CalcFrameBufferSize(m_ADesc);
143                 m_DataLength = RF64Header.data_len;
144                 m_ADesc.ContainerDuration = m_DataLength / m_FrameBufferSize;
145                 m_ADesc.ChannelFormat = PCM::CF_NONE;
146                 Reset();
147             }
148         }
149         }
150     }
151
152   return result;
153 }
154
155 //
156 ASDCP::Result_t
157 ASDCP::PCM::WAVParser::h__WAVParser::ReadFrame(FrameBuffer& FB)
158 {
159   FB.Size(0);
160
161   if ( m_EOF || m_ReadCount >= m_DataLength )
162     return RESULT_ENDOFFILE;
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         result = RESULT_OK;
180     }
181
182   if ( ASDCP_SUCCESS(result) )
183     {
184       m_ReadCount += read_count;
185       FB.Size(read_count);
186       FB.FrameNumber(m_FramesRead++);
187     }
188
189   return result;
190 }
191
192
193 //------------------------------------------------------------------------------------------
194
195 ASDCP::PCM::WAVParser::WAVParser()
196 {
197 }
198
199 ASDCP::PCM::WAVParser::~WAVParser()
200 {
201 }
202
203 // Opens the stream for reading, parses enough data to provide a complete
204 // set of stream metadata for the MXFWriter below.
205 ASDCP::Result_t
206 ASDCP::PCM::WAVParser::OpenRead(const char* filename, const Rational& PictureRate) const
207 {
208   const_cast<ASDCP::PCM::WAVParser*>(this)->m_Parser = new h__WAVParser;
209
210   Result_t result = m_Parser->OpenRead(filename, PictureRate);
211
212   if ( ASDCP_FAILURE(result) )
213     const_cast<ASDCP::PCM::WAVParser*>(this)->m_Parser.release();
214
215   return result;
216 }
217
218 // Rewinds the stream to the beginning.
219 ASDCP::Result_t
220 ASDCP::PCM::WAVParser::Reset() const
221 {
222   if ( m_Parser.empty() )
223     return RESULT_INIT;
224
225   m_Parser->Reset();
226   return RESULT_OK;
227 }
228
229 // Places a frame of data in the frame buffer. Fails if the buffer is too small
230 // or the stream is empty.
231 ASDCP::Result_t
232 ASDCP::PCM::WAVParser::ReadFrame(FrameBuffer& FB) const
233 {
234   if ( m_Parser.empty() )
235     return RESULT_INIT;
236
237   return m_Parser->ReadFrame(FB);
238 }
239
240 ASDCP::Result_t
241 ASDCP::PCM::WAVParser::FillAudioDescriptor(AudioDescriptor& ADesc) const
242 {
243   if ( m_Parser.empty() )
244     return RESULT_INIT;
245
246   ADesc = m_Parser->m_ADesc;
247   return RESULT_OK;
248 }
249
250
251 //
252 // end PCM_Parser.cpp
253 //