Bump patch version post tag.
[asdcplib.git] / src / JP2K_Codestream_Parser.cpp
1 /*
2 Copyright (c) 2004-2013, 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    Codestream_Parser.cpp
28     \version $Id$
29     \brief   AS-DCP library, JPEG 2000 codestream essence reader implementation
30 */
31
32 #include <KM_fileio.h>
33 #include <AS_DCP.h>
34 #include <JP2K.h>
35 #include <assert.h>
36 #include <KM_log.h>
37 using Kumu::DefaultLogSink;
38
39 //------------------------------------------------------------------------------------------
40
41 class ASDCP::JP2K::CodestreamParser::h__CodestreamParser
42 {
43   ASDCP_NO_COPY_CONSTRUCT(h__CodestreamParser);
44
45 public:
46   PictureDescriptor  m_PDesc;
47   Kumu::FileReader   m_File;
48
49   h__CodestreamParser()
50   {
51     memset(&m_PDesc, 0, sizeof(m_PDesc));
52     m_PDesc.EditRate = Rational(24,1);
53     m_PDesc.SampleRate = m_PDesc.EditRate;
54   }
55
56   ~h__CodestreamParser() {}
57
58   Result_t OpenReadFrame(const std::string& filename, FrameBuffer& FB)
59   {
60     m_File.Close();
61     Result_t result = m_File.OpenRead(filename);
62
63     if ( ASDCP_SUCCESS(result) )
64       {
65         Kumu::fsize_t file_size = m_File.Size();
66
67         if ( FB.Capacity() < file_size )
68           {
69             DefaultLogSink().Error("FrameBuf.Capacity: %u frame length: %u\n", FB.Capacity(), (ui32_t)file_size);
70             return RESULT_SMALLBUF;
71           }
72       }
73
74     ui32_t read_count;
75
76     if ( ASDCP_SUCCESS(result) )
77       result = m_File.Read(FB.Data(), FB.Capacity(), &read_count);
78
79     if ( ASDCP_SUCCESS(result) )
80       FB.Size(read_count);
81
82     if ( ASDCP_SUCCESS(result) )
83       {
84         byte_t start_of_data = 0; // out param
85         result = ParseMetadataIntoDesc(FB, m_PDesc, &start_of_data);
86
87         if ( ASDCP_SUCCESS(result) )
88           FB.PlaintextOffset(start_of_data);
89       }
90
91     return result;
92   }
93 };
94
95 ASDCP::Result_t
96 ASDCP::JP2K::ParseMetadataIntoDesc(const FrameBuffer& FB, PictureDescriptor& PDesc, byte_t* start_of_data)
97 {
98   Result_t result = RESULT_OK;
99   Marker NextMarker;
100   ui32_t i;
101   const byte_t* p = FB.RoData();
102   const byte_t* end_p = p + FB.Size();
103
104   /* initialize optional items */
105
106   PDesc.ExtendedCapabilities.N = JP2K::NoExtendedCapabilitiesSignaled;
107   PDesc.Profile.N = 0;
108   PDesc.CorrespondingProfile.N = 0;
109
110   while ( p < end_p && ASDCP_SUCCESS(result) )
111     {
112       result = GetNextMarker(&p, NextMarker);
113
114       if ( ASDCP_FAILURE(result) )
115         {
116           result = RESULT_RAW_ESS;
117           break;
118         }
119
120       switch ( NextMarker.m_Type )
121         {
122         case MRK_SOD:
123           if ( start_of_data != 0 )
124             *start_of_data = p - FB.RoData();
125
126           p = end_p;
127           break;
128
129         case MRK_SIZ:
130           {
131             Accessor::SIZ SIZ_(NextMarker);
132             PDesc.StoredWidth = SIZ_.Xsize();
133             PDesc.StoredHeight = SIZ_.Ysize();
134             PDesc.AspectRatio = Rational(SIZ_.Xsize(), SIZ_.Ysize());
135             PDesc.Rsize = SIZ_.Rsize();
136             PDesc.Xsize = SIZ_.Xsize();
137             PDesc.Ysize = SIZ_.Ysize();
138             PDesc.XOsize = SIZ_.XOsize();
139             PDesc.YOsize = SIZ_.YOsize();
140             PDesc.XTsize = SIZ_.XTsize();
141             PDesc.YTsize = SIZ_.YTsize();
142             PDesc.XTOsize = SIZ_.XTOsize();
143             PDesc.YTOsize = SIZ_.YTOsize();
144             PDesc.Csize = SIZ_.Csize();
145
146             if ( PDesc.Csize != 3 )
147               {
148                 DefaultLogSink().Error("Unexpected number of components: %u\n", PDesc.Csize);
149                 return RESULT_RAW_FORMAT;
150               }
151             
152             for ( i = 0; i < PDesc.Csize; i++ )
153               SIZ_.ReadComponent(i, PDesc.ImageComponents[i]);
154           }
155           break;
156
157         case MRK_COD:
158           memset(&PDesc.CodingStyleDefault, 0, sizeof(CodingStyleDefault_t));
159
160           if ( NextMarker.m_DataSize > sizeof(CodingStyleDefault_t) )
161             {
162               DefaultLogSink().Error("Unexpectedly large CodingStyle data: %u\n", NextMarker.m_DataSize);
163               return RESULT_RAW_FORMAT;
164             }
165           
166           memcpy(&PDesc.CodingStyleDefault, NextMarker.m_Data, NextMarker.m_DataSize);
167           break;
168
169         case MRK_QCD:
170           memset(&PDesc.QuantizationDefault, 0, sizeof(QuantizationDefault_t));
171
172           if ( NextMarker.m_DataSize < 3 ) // ( Sqcd = 8 bits, SPqcd = 8 bits ) == 2 bytes, error if not greater
173             {
174               DefaultLogSink().Error("No quantization signaled. QCD size=%s.\n", NextMarker.m_DataSize);
175               return RESULT_RAW_FORMAT;
176             }
177           
178           if ( NextMarker.m_DataSize > MaxDefaults )
179             {
180               DefaultLogSink().Error("Quantization Default length exceeds maximum %d\n", NextMarker.m_DataSize);
181               return RESULT_RAW_FORMAT;
182             }
183
184           memcpy(&PDesc.QuantizationDefault, NextMarker.m_Data, NextMarker.m_DataSize);
185           PDesc.QuantizationDefault.SPqcdLength = NextMarker.m_DataSize - 1;
186           break;
187
188         case MRK_CAP:
189           {
190             Accessor::CAP CAP_(NextMarker);
191             
192                         PDesc.ExtendedCapabilities.Pcap = CAP_.pcap();
193
194                         PDesc.ExtendedCapabilities.N = CAP_.N();
195
196                         for (i32_t i = 0; i < CAP_.N(); i++) {
197
198                                 PDesc.ExtendedCapabilities.Ccap[i] = CAP_.ccap(i);
199
200                         }
201
202           }
203           break;
204
205                 case MRK_PRF:
206           {
207             Accessor::PRF PRF_(NextMarker);
208
209                 ui16_t n = PRF_.N();
210
211                 if ( n > MaxPRFN )
212             {
213               DefaultLogSink().Error("Number (%d) of Pprf^i exceeds maximum supported\n", n);
214               return RESULT_RAW_FORMAT;
215             }
216
217                         PDesc.Profile.N = n;
218
219                         for(i32_t i = 0; i < n ; i++) {
220
221                                 PDesc.Profile.Pprf[i] = PRF_.pprf(i+1);
222                         }
223           }
224           break;
225
226                 case MRK_CPF:
227           {
228             Accessor::CPF CPF_(NextMarker);
229
230                 ui16_t n = CPF_.N();
231
232                 if ( n > MaxCPFN )
233             {
234               DefaultLogSink().Error("Number (%d) of Pcpf^i exceeds maximum supported\n", n);
235               return RESULT_RAW_FORMAT;
236             }
237
238                         PDesc.CorrespondingProfile.N = n;
239
240                         for(i32_t i = 0; i < n; i++) {
241
242                                 PDesc.CorrespondingProfile.Pcpf[i] = CPF_.pcpf(i+1);
243                         }
244           }
245           break;
246
247         }
248     }
249
250   return result;
251 }
252
253 //------------------------------------------------------------------------------------------
254
255 ASDCP::JP2K::CodestreamParser::CodestreamParser()
256 {
257 }
258
259 ASDCP::JP2K::CodestreamParser::~CodestreamParser()
260 {
261 }
262
263 // Opens the stream for reading, parses enough data to provide a complete
264 // set of stream metadata for the MXFWriter below.
265 ASDCP::Result_t
266 ASDCP::JP2K::CodestreamParser::OpenReadFrame(const std::string& filename, FrameBuffer& FB) const
267 {
268   const_cast<ASDCP::JP2K::CodestreamParser*>(this)->m_Parser = new h__CodestreamParser;
269   return m_Parser->OpenReadFrame(filename, FB);
270 }
271
272 //
273 ASDCP::Result_t
274 ASDCP::JP2K::CodestreamParser::FillPictureDescriptor(PictureDescriptor& PDesc) const
275 {
276   if ( m_Parser.empty() )
277     return RESULT_INIT;
278
279   PDesc = m_Parser->m_PDesc;
280   return RESULT_OK;
281 }
282
283
284 //
285 // end Codestream_Parser.cpp
286 //