ginormo merge-back with Kumu, SMPTE MIC key and MPEG parser fix
[asdcplib.git] / src / PCM_Parser.cpp
1 /*
2 Copyright (c) 2004-2006, 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
41
42 //------------------------------------------------------------------------------------------
43
44 //
45 class ASDCP::PCM::WAVParser::h__WAVParser
46 {
47   Kumu::FileReader m_FileReader;
48   bool             m_EOF;
49   ui32_t           m_DataStart;
50   ui32_t           m_DataLength;
51   ui32_t           m_ReadCount;
52   ui32_t           m_FrameBufferSize;
53   ui32_t           m_FramesRead;
54   Rational         m_PictureRate;
55
56   ASDCP_NO_COPY_CONSTRUCT(h__WAVParser);
57
58 public:
59   AudioDescriptor  m_ADesc;
60
61
62   h__WAVParser() :
63     m_EOF(false), m_DataStart(0), m_DataLength(0), m_ReadCount(0),
64     m_FrameBufferSize(0), m_FramesRead(0) {}
65
66   ~h__WAVParser()
67   {
68     Close();
69    }
70
71   Result_t OpenRead(const char* filename, const Rational& PictureRate);
72   void     Close();
73   void     Reset();
74   Result_t ReadFrame(FrameBuffer&);
75 };
76
77
78 //
79 void
80 ASDCP::PCM::WAVParser::h__WAVParser::Close()
81 {
82   m_FileReader.Close();
83 }
84
85 //
86 void
87 ASDCP::PCM::WAVParser::h__WAVParser::Reset()
88 {
89   m_FileReader.Seek(m_DataStart);
90   m_FramesRead = 0;
91   m_ReadCount = 0;
92 }
93
94 //
95 ASDCP::Result_t
96 ASDCP::PCM::WAVParser::h__WAVParser::OpenRead(const char* filename, const Rational& PictureRate)
97 {
98   ASDCP_TEST_NULL_STR(filename);
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           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               Reset();
129             }
130         }
131     }
132
133   return result;
134 }
135
136 //
137 ASDCP::Result_t
138 ASDCP::PCM::WAVParser::h__WAVParser::ReadFrame(FrameBuffer& FB)
139 {
140   FB.Size(0);
141
142   if ( m_EOF || m_ReadCount >= m_DataLength )
143     return RESULT_ENDOFFILE;
144
145   if ( FB.Capacity() < m_FrameBufferSize )
146     {
147       DefaultLogSink().Error("FrameBuf.Capacity: %lu FrameLength: %lu\n",
148                              FB.Capacity(), m_FrameBufferSize);
149       return RESULT_SMALLBUF;
150     }
151
152   ui32_t read_count = 0;
153   Result_t result = m_FileReader.Read(FB.Data(), m_FrameBufferSize, &read_count);
154
155   if ( result == RESULT_ENDOFFILE )
156     {
157       m_EOF = true;
158
159       if ( read_count > 0 )
160         result = RESULT_OK;
161     }
162
163   if ( ASDCP_SUCCESS(result) )
164     {
165       m_ReadCount += read_count;
166       FB.Size(read_count);
167       FB.FrameNumber(m_FramesRead++);
168     }
169
170   return result;
171 }
172
173
174 //------------------------------------------------------------------------------------------
175
176 ASDCP::PCM::WAVParser::WAVParser()
177 {
178 }
179
180 ASDCP::PCM::WAVParser::~WAVParser()
181 {
182 }
183
184 // Opens the stream for reading, parses enough data to provide a complete
185 // set of stream metadata for the MXFWriter below.
186 ASDCP::Result_t
187 ASDCP::PCM::WAVParser::OpenRead(const char* filename, const Rational& PictureRate) const
188 {
189   const_cast<ASDCP::PCM::WAVParser*>(this)->m_Parser = new h__WAVParser;
190
191   Result_t result = m_Parser->OpenRead(filename, PictureRate);
192
193   if ( ASDCP_FAILURE(result) )
194     const_cast<ASDCP::PCM::WAVParser*>(this)->m_Parser.release();
195
196   return result;
197 }
198
199 // Rewinds the stream to the beginning.
200 ASDCP::Result_t
201 ASDCP::PCM::WAVParser::Reset() const
202 {
203   if ( m_Parser.empty() )
204     return RESULT_INIT;
205
206   m_Parser->Reset();
207   return RESULT_OK;
208 }
209
210 // Places a frame of data in the frame buffer. Fails if the buffer is too small
211 // or the stream is empty.
212 ASDCP::Result_t
213 ASDCP::PCM::WAVParser::ReadFrame(FrameBuffer& FB) const
214 {
215   if ( m_Parser.empty() )
216     return RESULT_INIT;
217
218   return m_Parser->ReadFrame(FB);
219 }
220
221 ASDCP::Result_t
222 ASDCP::PCM::WAVParser::FillAudioDescriptor(AudioDescriptor& ADesc) const
223 {
224   if ( m_Parser.empty() )
225     return RESULT_INIT;
226
227   ADesc = m_Parser->m_ADesc;
228   return RESULT_OK;
229 }
230
231
232 //
233 // end PCM_Parser.cpp
234 //