2.5.11.
[asdcplib-cth.git] / src / JP2K.cpp
1 /*
2 Copyright (c) 2005-2014, 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    JP2K.cpp
28     \version $Id: JP2K.cpp,v 1.11 2015/10/07 16:41:23 jhurst Exp $
29     \brief   JPEG 2000 parser implementation
30
31     This is not a complete implementation of all things JP2K.  There is just enough here to
32     support parsing picture metadata from a codestream header.
33 */
34
35 #include <JP2K.h>
36 #include <KM_log.h>
37 using Kumu::DefaultLogSink;
38
39
40 // when indexed with the second byte of a marker code, this table will procuce one of
41 // two values:
42 //   0 - the marker is a standalone marker
43 //   1 - the marker designates a marker segment
44 //
45 const byte_t MarkerSegmentMap[] =
46   {
47     /*      0   1   2   3   4   5   6   7      8   9   a   b   c   d   e   f */
48     /* 0 */ 0,  0,  0,  0,  0,  0,  0,  0,     0,  0,  0,  0,  0,  0,  0,  0, // 0
49     /* 1 */ 0,  0,  0,  0,  0,  0,  0,  0,     0,  0,  0,  0,  0,  0,  0,  0, // 1
50     /* 2 */ 0,  0,  0,  0,  0,  0,  0,  0,     0,  0,  0,  0,  0,  0,  0,  0, // 2
51     /* 3 */ 0,  0,  0,  0,  0,  0,  0,  0,     0,  0,  0,  0,  0,  0,  0,  0, // 3
52     /* 4 */ 0,  0,  0,  0,  0,  0,  0,  0,     0,  0,  0,  0,  0,  0,  0,  0, // 4
53     /* 5 */ 0,  1,  1,  1,  1,  1,  0,  1,     1,  0,  0,  0,  1,  1,  1,  1, // 5
54     /* 6 */ 1,  1,  0,  1,  1,  0,  0,  0,     0,  0,  0,  0,  0,  0,  0,  0, // 6
55     /* 7 */ 0,  0,  0,  0,  0,  0,  0,  0,     0,  0,  0,  0,  0,  0,  0,  0, // 7
56     /* 8 */ 0,  0,  0,  0,  0,  0,  0,  0,     0,  0,  0,  0,  0,  0,  0,  0, // 8
57     /* 9 */ 1,  1,  0,  0,  0,  0,  0,  0,     0,  0,  0,  0,  0,  0,  0,  0, // 9
58     /* a */ 0,  0,  0,  0,  0,  0,  0,  0,     0,  0,  0,  0,  0,  0,  0,  0, // a
59     /* b */ 0,  0,  0,  0,  0,  0,  0,  0,     0,  0,  0,  0,  0,  0,  0,  0, // b
60     /* c */ 0,  0,  0,  0,  0,  0,  0,  0,     0,  0,  0,  0,  0,  0,  0,  0, // c
61     /* d */ 0,  0,  0,  0,  0,  0,  0,  0,     0,  0,  0,  0,  0,  0,  0,  0, // d
62     /* e */ 0,  0,  0,  0,  0,  0,  0,  0,     0,  0,  0,  0,  0,  0,  0,  0, // e
63     /* f */ 0,  0,  0,  0,  0,  0,  0,  0,     0,  0,  0,  0,  0,  0,  0,  0, // f
64     /*      0   1   2   3   4   5   6   7      8   9   a   b   c   d   e   f */
65   };
66
67
68 //
69 ASDCP::Result_t
70 ASDCP::JP2K::GetNextMarker(const byte_t** buf, JP2K::Marker& Marker)
71 {
72   assert((buf != 0) && (*buf != 0 ));
73   
74   if ( **buf != 0xff )
75     return ASDCP::RESULT_FAIL;
76
77   Marker.m_IsSegment = (MarkerSegmentMap[*(++(*buf))] == 1);
78   Marker.m_Type = (Marker_t)(0xff00 | *(*buf)++);
79
80   if ( Marker.m_IsSegment )
81     {
82       Marker.m_DataSize = *(*buf)++ << 8;
83       Marker.m_DataSize |= *(*buf)++;
84       Marker.m_DataSize -= 2;
85       Marker.m_Data = *buf;
86       *buf += Marker.m_DataSize;
87     }
88
89
90   if ( Marker.m_DataSize != 0 && Marker.m_DataSize < 3 )
91     {
92       DefaultLogSink().Error("Illegal data size: %u\n", Marker.m_DataSize);
93       return ASDCP::RESULT_FAIL;
94     }
95
96   return ASDCP::RESULT_OK;
97 }
98
99
100 //-------------------------------------------------------------------------------------------------------
101 //
102
103 //
104 void
105 ASDCP::JP2K::Accessor::SIZ::ReadComponent(const ui32_t index, ASDCP::JP2K::ImageComponent_t& IC) const
106 {
107   assert ( index < Csize() );
108   const byte_t* p = m_MarkerData + 36 + (index * 3);
109   IC.Ssize = *p++;
110   IC.XRsize = *p++;
111   IC.YRsize = *p;
112 }
113
114 //
115 void
116 ASDCP::JP2K::Accessor::SIZ::Dump(FILE* stream) const
117 {
118   if ( stream == 0 )
119     stream = stderr;
120
121   fprintf(stream, "SIZ: \n");
122   fprintf(stream, "  Rsize: %hu\n", Rsize());
123   fprintf(stream, "  Xsize: %u\n",  Xsize());
124   fprintf(stream, "  Ysize: %u\n",  Ysize());
125   fprintf(stream, " XOsize: %u\n",  XOsize());
126   fprintf(stream, " YOsize: %u\n",  YOsize());
127   fprintf(stream, " XTsize: %u\n",  XTsize());
128   fprintf(stream, " YTsize: %u\n",  YTsize());
129   fprintf(stream, "XTOsize: %u\n",  XTOsize());
130   fprintf(stream, "YTOsize: %u\n",  YTOsize());
131   fprintf(stream, "  Csize: %u\n",  Csize());
132
133   if ( Csize() > 0 )
134     {
135       fprintf(stream, "Components\n");
136
137       for ( ui32_t i = 0; i < Csize(); i++ )
138         {
139           ImageComponent_t TmpComp;
140           ReadComponent(i, TmpComp);
141           fprintf(stream, "%u: ", i);
142           fprintf(stream, "%u, %u, %u\n", TmpComp.Ssize, TmpComp.XRsize, TmpComp.YRsize);
143         }
144     }
145 }
146
147 //
148 void
149 ASDCP::JP2K::Accessor::COD::Dump(FILE* stream) const
150 {
151   if ( stream == 0 )
152     stream = stderr;
153
154   fprintf(stream, "COD: \n");
155   const char* prog_order_str = "RESERVED";
156   const char* transformations_str = prog_order_str;
157
158   switch ( ProgOrder() )
159     {
160     case 0: prog_order_str = "LRCP"; break;
161     case 1: prog_order_str = "RLCP"; break;
162     case 2: prog_order_str = "RPCL"; break;
163     case 3: prog_order_str = "PCRL"; break;
164     case 4: prog_order_str = "CPRL"; break;
165     }
166
167   switch ( Transformation() )
168     {
169     case 0: transformations_str = "9/7"; break;
170     case 1: transformations_str = "5/3"; break;
171     }
172
173   fprintf(stream, "      ProgOrder: %s\n", prog_order_str);
174   fprintf(stream, "         Layers: %hu\n", Layers());
175   fprintf(stream, "   DecompLevels: %hhu\n", DecompLevels());
176   fprintf(stream, " CodeBlockWidth: %d\n", 1 << CodeBlockWidth());
177   fprintf(stream, "CodeBlockHeight: %d\n", 1 << CodeBlockHeight());
178   fprintf(stream, " CodeBlockStyle: %d\n", CodeBlockStyle());
179   fprintf(stream, " Transformation: %s\n", transformations_str);
180 }
181
182 //
183 const char*
184 ASDCP::JP2K::Accessor::GetQuantizationTypeString(const Accessor::QuantizationType_t t)
185 {
186   switch ( t )
187     {
188     case QT_NONE: return "none";
189     case QT_DERIVED: return "scalar derived";
190     case QT_EXP: return "scalar expounded";
191     }
192
193   return "**UNKNOWN**";
194 }
195
196 //
197 void
198 ASDCP::JP2K::Accessor::QCD::Dump(FILE* stream) const
199 {
200   if ( stream == 0 )
201     stream = stderr;
202
203   fprintf(stream, "QCD: \n");
204   fprintf(stream, "QuantizationType: %s\n", GetQuantizationTypeString(QuantizationType()));
205   fprintf(stream, "       GuardBits: %d\n", GuardBits());
206   fprintf(stream, "           SPqcd: %d\n", GuardBits());
207   Kumu::hexdump(m_MarkerData, m_DataSize, stream);
208 }
209
210 //
211 void
212 ASDCP::JP2K::Accessor::COM::Dump(FILE* stream) const
213 {
214   if ( stream == 0 )
215     stream = stderr;
216
217   if ( IsText() )
218     {
219       std::string tmp_str;
220       tmp_str.assign((char*)CommentData(), CommentSize());
221       fprintf(stream, "COM:%s\n", tmp_str.c_str());
222     }
223   else
224     {
225       fprintf(stream, "COM:\n");
226       Kumu::hexdump(CommentData(), CommentSize(), stream);
227     }
228 }
229
230
231 //-------------------------------------------------------------------------------------------------------
232 //
233
234
235 //
236 void
237 ASDCP::JP2K::Marker::Dump(FILE* stream) const
238 {
239   if ( stream == 0 )
240     stream = stderr;
241
242   fprintf(stream, "Marker%s 0x%04x: %s", (m_IsSegment ? " segment" : ""), m_Type, GetMarkerString(m_Type));  
243
244   if ( m_IsSegment )
245     fprintf(stream, ", 0x%0x bytes", m_DataSize);
246
247   fputc('\n', stream);
248 }
249
250 //
251 const char*
252 ASDCP::JP2K::GetMarkerString(Marker_t m)
253 {
254   switch ( m )
255     {
256     case MRK_NIL: return "NIL"; break;
257     case MRK_SOC: return "SOC: Start of codestream"; break;
258     case MRK_SOT: return "SOT: Start of tile-part"; break;
259     case MRK_SOD: return "SOD: Start of data"; break;
260     case MRK_EOC: return "EOC: End of codestream"; break;
261     case MRK_SIZ: return "SIZ: Image and tile size"; break;
262     case MRK_COD: return "COD: Coding style default"; break;
263     case MRK_COC: return "COC: Coding style component"; break;
264     case MRK_RGN: return "RGN: Region of interest"; break;
265     case MRK_QCD: return "QCD: Quantization default"; break;
266     case MRK_QCC: return "QCC: Quantization component"; break;
267     case MRK_POC: return "POC: Progression order change"; break;
268     case MRK_TLM: return "TLM: Tile-part lengths"; break;
269     case MRK_PLM: return "PLM: Packet length, main header"; break;
270     case MRK_PLT: return "PLT: Packet length, tile-part header"; break;
271     case MRK_PPM: return "PPM: Packed packet headers, main header"; break;
272     case MRK_PPT: return "PPT: Packed packet headers, tile-part header"; break;
273     case MRK_SOP: return "SOP: Start of packet"; break;
274     case MRK_EPH: return "EPH: End of packet header"; break;
275     case MRK_CRG: return "CRG: Component registration"; break;
276     case MRK_COM: return "COM: Comment"; break;
277     }
278
279   return "Unknown marker code";
280 }
281
282 //
283 // end JP2K.cpp
284 //