added COD decoding to the JP2K parser, fixed interpreter lock bug in text writer
[asdcplib.git] / src / JP2K.cpp
1 /*
2 Copyright (c) 2005-2009, 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$
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(ui32_t index, ASDCP::JP2K::ImageComponent_t& IC)
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)
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)
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: %hu\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 void
184 ASDCP::JP2K::Accessor::COM::Dump(FILE* stream)
185 {
186   if ( stream == 0 )
187     stream = stderr;
188
189   if ( IsText() )
190     {
191       char* t_str = (char*)malloc(CommentSize() + 1);
192       assert( t_str != 0 );
193       ui32_t cs = CommentSize();
194       memcpy(t_str, CommentData(), cs);
195       t_str[cs] = 0;
196       fprintf(stream, "COM:%s\n", t_str);
197     }
198   else
199     {
200       fprintf(stream, "COM:\n");
201       Kumu::hexdump(CommentData(), CommentSize(), stream);
202     }
203 }
204
205
206 //-------------------------------------------------------------------------------------------------------
207 //
208
209
210 //
211 void
212 ASDCP::JP2K::Marker::Dump(FILE* stream) const
213 {
214   if ( stream == 0 )
215     stream = stderr;
216
217   fprintf(stream, "Marker%s 0x%04x: %s", (m_IsSegment ? " segment" : ""), m_Type, GetMarkerString(m_Type));  
218
219   if ( m_IsSegment )
220     fprintf(stream, ", 0x%0x bytes", m_DataSize);
221
222   fputc('\n', stream);
223 }
224
225 //
226 const char*
227 ASDCP::JP2K::GetMarkerString(Marker_t m)
228 {
229   switch ( m )
230     {
231     case MRK_NIL: return "NIL"; break;
232     case MRK_SOC: return "SOC: Start of codestream"; break;
233     case MRK_SOT: return "SOT: Start of tile-part"; break;
234     case MRK_SOD: return "SOD: Start of data"; break;
235     case MRK_EOC: return "EOC: End of codestream"; break;
236     case MRK_SIZ: return "SIZ: Image and tile size"; break;
237     case MRK_COD: return "COD: Coding style default"; break;
238     case MRK_COC: return "COC: Coding style component"; break;
239     case MRK_RGN: return "RGN: Region of interest"; break;
240     case MRK_QCD: return "QCD: Quantization default"; break;
241     case MRK_QCC: return "QCC: Quantization component"; break;
242     case MRK_POC: return "POC: Progression order change"; break;
243     case MRK_TLM: return "TLM: Tile-part lengths"; break;
244     case MRK_PLM: return "PLM: Packet length, main header"; break;
245     case MRK_PLT: return "PLT: Packet length, tile-part header"; break;
246     case MRK_PPM: return "PPM: Packed packet headers, main header"; break;
247     case MRK_PPT: return "PPT: Packed packet headers, tile-part header"; break;
248     case MRK_SOP: return "SOP: Start of packet"; break;
249     case MRK_EPH: return "EPH: End of packet header"; break;
250     case MRK_CRG: return "CRG: Component registration"; break;
251     case MRK_COM: return "COM: Comment"; break;
252     }
253
254   return "Unknown marker code";
255 }
256
257 //
258 // end JP2K.cpp
259 //