1 /*
2  * H.265 video codec.
3  * Copyright (c) 2013-2014 struktur AG, Dirk Farin <farin@struktur.de>
4  *
5  * This file is part of libde265.
6  *
7  * libde265 is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU Lesser General Public License as
9  * published by the Free Software Foundation, either version 3 of
10  * the License, or (at your option) any later version.
11  *
12  * libde265 is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with libde265.  If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 #include "sei.h"
22 #include "util.h"
23 #include "md5.h"
24 
25 #include "libde265/sps.h"
26 #include "libde265/image.h"
27 #include "libde265/decctx.h"
28 
29 #include <assert.h>
30 
31 
read_sei_decoded_picture_hash(bitreader * reader,sei_message * sei,const seq_parameter_set * sps)32 static de265_error read_sei_decoded_picture_hash(bitreader* reader, sei_message* sei,
33                                                  const seq_parameter_set* sps)
34 {
35   sei_decoded_picture_hash* seihash = &sei->data.decoded_picture_hash;
36 
37   seihash->hash_type = (enum sei_decoded_picture_hash_type)get_bits(reader,8);
38 
39   if (sps==NULL) {
40     return DE265_WARNING_SPS_MISSING_CANNOT_DECODE_SEI;
41   }
42 
43   int nHashes = sps->chroma_format_idc==0 ? 1 : 3;
44   for (int i=0;i<nHashes;i++) {
45     switch (seihash->hash_type) {
46     case sei_decoded_picture_hash_type_MD5:
47       for (int b=0;b<16;b++) { seihash->md5[i][b] = get_bits(reader,8); }
48       break;
49 
50     case sei_decoded_picture_hash_type_CRC:
51       seihash->crc[i] = get_bits(reader,16);
52       break;
53 
54     case sei_decoded_picture_hash_type_checksum:
55       seihash->checksum[i]  = get_bits(reader,32);
56       break;
57     }
58   }
59 
60   return DE265_OK;
61 }
62 
63 
dump_sei_decoded_picture_hash(const sei_message * sei,const seq_parameter_set * sps)64 static void dump_sei_decoded_picture_hash(const sei_message* sei,
65                                           const seq_parameter_set* sps)
66 {
67   const sei_decoded_picture_hash* seihash = &sei->data.decoded_picture_hash;
68 
69   loginfo(LogSEI,"  hash_type: ");
70   switch (seihash->hash_type) {
71   case sei_decoded_picture_hash_type_MD5: loginfo(LogSEI,"MD5\n"); break;
72   case sei_decoded_picture_hash_type_CRC: loginfo(LogSEI,"CRC\n"); break;
73   case sei_decoded_picture_hash_type_checksum: loginfo(LogSEI,"checksum\n"); break;
74   }
75 
76   int nHashes = sps->chroma_format_idc==0 ? 1 : 3;
77   for (int i=0;i<nHashes;i++) {
78     switch (seihash->hash_type) {
79     case sei_decoded_picture_hash_type_MD5:
80       loginfo(LogSEI,"  MD5[%d]: %02x", i,seihash->md5[i][0]);
81       for (int b=1;b<16;b++) {
82         loginfo(LogSEI,"*:%02x", seihash->md5[i][b]);
83       }
84       loginfo(LogSEI,"*\n");
85       break;
86 
87     case sei_decoded_picture_hash_type_CRC:
88       loginfo(LogSEI,"  CRC[%d]: %02x\n", i,seihash->crc[i]);
89       break;
90 
91     case sei_decoded_picture_hash_type_checksum:
92       loginfo(LogSEI,"  checksum[%d]: %04x\n", i,seihash->checksum[i]);
93       break;
94     }
95   }
96 }
97 
98 
99 class raw_hash_data
100 {
101 public:
102   raw_hash_data(int w, int stride);
103   ~raw_hash_data();
104 
105   struct data_chunk {
106     const uint8_t* data;
107     int            len;
108   };
109 
110   data_chunk prepare_8bit(const uint8_t* data,int y);
111   data_chunk prepare_16bit(const uint8_t* data,int y);
112 
113 private:
114   int mWidth, mStride;
115 
116   uint8_t* mMem;
117 };
118 
119 
raw_hash_data(int w,int stride)120 raw_hash_data::raw_hash_data(int w, int stride)
121 {
122   mWidth=w;
123   mStride=stride;
124   mMem = NULL;
125 }
126 
~raw_hash_data()127 raw_hash_data::~raw_hash_data()
128 {
129   delete[] mMem;
130 }
131 
prepare_8bit(const uint8_t * data,int y)132 raw_hash_data::data_chunk raw_hash_data::prepare_8bit(const uint8_t* data,int y)
133 {
134   data_chunk chunk;
135   chunk.data = data+y*mStride;
136   chunk.len  = mWidth;
137   return chunk;
138 }
139 
prepare_16bit(const uint8_t * data,int y)140 raw_hash_data::data_chunk raw_hash_data::prepare_16bit(const uint8_t* data,int y)
141 {
142   if (mMem == NULL) {
143     mMem = new uint8_t[2*mWidth];
144   }
145 
146   const uint16_t* data16 = (uint16_t*)data;
147 
148   for (int x=0; x<mWidth; x++) {
149     mMem[2*x+0] = data16[y*mStride+x] & 0xFF;
150     mMem[2*x+1] = data16[y*mStride+x] >> 8;
151   }
152 
153   data_chunk chunk;
154   chunk.data = mMem;
155   chunk.len  = 2*mWidth;
156   return chunk;
157 }
158 
159 
compute_checksum_8bit(uint8_t * data,int w,int h,int stride,int bit_depth)160 static uint32_t compute_checksum_8bit(uint8_t* data,int w,int h,int stride, int bit_depth)
161 {
162   uint32_t sum = 0;
163 
164   if (bit_depth<=8) {
165     for (int y=0; y<h; y++)
166       for(int x=0; x<w; x++) {
167         uint8_t xorMask = ( x & 0xFF ) ^ ( y & 0xFF ) ^ ( x  >>  8 ) ^ ( y  >>  8 );
168         sum += data[y*stride + x] ^ xorMask;
169       }
170   }
171   else {
172     for (int y=0; y<h; y++)
173       for(int x=0; x<w; x++) {
174         uint8_t xorMask = ( x & 0xFF ) ^ ( y & 0xFF ) ^ ( x  >>  8 ) ^ ( y  >>  8 );
175         sum += (data[y*stride + x] & 0xFF) ^ xorMask;
176         sum += (data[y*stride + x] >> 8)   ^ xorMask;
177       }
178   }
179 
180   return sum & 0xFFFFFFFF;
181 }
182 
crc_process_byte(uint16_t crc,uint8_t byte)183 static inline uint16_t crc_process_byte(uint16_t crc, uint8_t byte)
184 {
185   for (int bit=0;bit<8;bit++) {
186     int bitVal = (byte >> (7-bit)) & 1;
187 
188     int crcMsb = (crc>>15) & 1;
189     crc = (((crc<<1) + bitVal) & 0xFFFF);
190 
191     if (crcMsb) { crc ^=  0x1021; }
192   }
193 
194   return crc;
195 }
196 
197 /*
198 static uint16_t compute_CRC_8bit_old(const uint8_t* data,int w,int h,int stride)
199 {
200   uint16_t crc = 0xFFFF;
201 
202   for (int y=0; y<h; y++)
203     for(int x=0; x<w; x++) {
204       crc = crc_process_byte(crc, data[y*stride+x]);
205     }
206 
207   crc = crc_process_byte(crc, 0);
208   crc = crc_process_byte(crc, 0);
209 
210   return crc;
211 }
212 */
213 
crc_process_byte_parallel(uint16_t crc,uint8_t byte)214 static inline uint16_t crc_process_byte_parallel(uint16_t crc, uint8_t byte)
215 {
216   uint16_t s = byte ^ (crc >> 8);
217   uint16_t t = s ^ (s >> 4);
218 
219   return  ((crc << 8) ^
220 	   t ^
221 	   (t <<  5) ^
222 	   (t << 12)) & 0xFFFF;
223 }
224 
compute_CRC_8bit_fast(const uint8_t * data,int w,int h,int stride,int bit_depth)225 static uint32_t compute_CRC_8bit_fast(const uint8_t* data,int w,int h,int stride, int bit_depth)
226 {
227   raw_hash_data raw_data(w,stride);
228 
229   uint16_t crc = 0xFFFF;
230 
231   crc = crc_process_byte_parallel(crc, 0);
232   crc = crc_process_byte_parallel(crc, 0);
233 
234   for (int y=0; y<h; y++) {
235     raw_hash_data::data_chunk chunk;
236 
237     if (bit_depth>8)
238       chunk = raw_data.prepare_16bit(data, y);
239     else
240       chunk = raw_data.prepare_8bit(data, y);
241 
242     for(int x=0; x<chunk.len; x++) {
243       crc = crc_process_byte_parallel(crc, chunk.data[x]);
244     }
245   }
246 
247   return crc;
248 }
249 
250 
compute_MD5(uint8_t * data,int w,int h,int stride,uint8_t * result,int bit_depth)251 static void compute_MD5(uint8_t* data,int w,int h,int stride, uint8_t* result, int bit_depth)
252 {
253   MD5_CTX md5;
254   MD5_Init(&md5);
255 
256   raw_hash_data raw_data(w,stride);
257 
258   for (int y=0; y<h; y++) {
259     raw_hash_data::data_chunk chunk;
260 
261     if (bit_depth>8)
262       chunk = raw_data.prepare_16bit(data, y);
263     else
264       chunk = raw_data.prepare_8bit(data, y);
265 
266     MD5_Update(&md5, (void*)chunk.data, chunk.len);
267   }
268 
269   MD5_Final(result, &md5);
270 }
271 
272 
process_sei_decoded_picture_hash(const sei_message * sei,de265_image * img)273 static de265_error process_sei_decoded_picture_hash(const sei_message* sei, de265_image* img)
274 {
275   const sei_decoded_picture_hash* seihash = &sei->data.decoded_picture_hash;
276 
277   /* Do not check SEI on pictures that are not output.
278      Hash may be wrong, because of a broken link (BLA).
279      This happens, for example in conformance stream RAP_B, where a EOS-NAL
280      appears before a CRA (POC=32). */
281   if (img->PicOutputFlag == false) {
282     return DE265_OK;
283   }
284 
285   //write_picture(img);
286 
287   int nHashes = img->sps.chroma_format_idc==0 ? 1 : 3;
288   for (int i=0;i<nHashes;i++) {
289     uint8_t* data;
290     int w,h,stride;
291 
292     w = img->get_width(i);
293     h = img->get_height(i);
294 
295     data = img->get_image_plane(i);
296     stride = img->get_image_stride(i);
297 
298     switch (seihash->hash_type) {
299     case sei_decoded_picture_hash_type_MD5:
300       {
301         uint8_t md5[16];
302         compute_MD5(data,w,h,stride,md5, img->get_bit_depth(i));
303 
304 /*
305         fprintf(stderr,"computed MD5: ");
306         for (int b=0;b<16;b++) {
307           fprintf(stderr,"%02x", md5[b]);
308         }
309         fprintf(stderr,"\n");
310 */
311 
312         for (int b=0;b<16;b++) {
313           if (md5[b] != seihash->md5[i][b]) {
314             fprintf(stderr,"SEI decoded picture MD5 mismatch (POC=%d)\n", img->PicOrderCntVal);
315             return DE265_ERROR_CHECKSUM_MISMATCH;
316           }
317         }
318       }
319       break;
320 
321     case sei_decoded_picture_hash_type_CRC:
322       {
323         uint16_t crc = compute_CRC_8bit_fast(data,w,h,stride, img->get_bit_depth(i));
324 
325         logtrace(LogSEI,"SEI decoded picture hash: %04x <-[%d]-> decoded picture: %04x\n",
326                  seihash->crc[i], i, crc);
327 
328         if (crc != seihash->crc[i]) {
329           fprintf(stderr,"SEI decoded picture hash: %04x, decoded picture: %04x (POC=%d)\n",
330                   seihash->crc[i], crc, img->PicOrderCntVal);
331           return DE265_ERROR_CHECKSUM_MISMATCH;
332         }
333       }
334       break;
335 
336     case sei_decoded_picture_hash_type_checksum:
337       {
338         uint32_t chksum = compute_checksum_8bit(data,w,h,stride, img->get_bit_depth(i));
339 
340         if (chksum != seihash->checksum[i]) {
341           fprintf(stderr,"SEI decoded picture hash: %04x, decoded picture: %04x (POC=%d)\n",
342                   seihash->checksum[i], chksum, img->PicOrderCntVal);
343           return DE265_ERROR_CHECKSUM_MISMATCH;
344         }
345       }
346       break;
347     }
348   }
349 
350   loginfo(LogSEI,"decoded picture hash checked: OK\n");
351   //printf("checked picture %d SEI: OK\n", img->PicOrderCntVal);
352 
353   return DE265_OK;
354 }
355 
356 
read_sei(bitreader * reader,sei_message * sei,bool suffix,const seq_parameter_set * sps)357 de265_error read_sei(bitreader* reader, sei_message* sei, bool suffix, const seq_parameter_set* sps)
358 {
359   int payload_type = 0;
360   for (;;)
361     {
362       int byte = get_bits(reader,8);
363       payload_type += byte;
364       if (byte != 0xFF) { break; }
365     }
366 
367   //printf("SEI payload: %d\n",payload_type);
368 
369   int payload_size = 0;
370   for (;;)
371     {
372       int byte = get_bits(reader,8);
373       payload_size += byte;
374       if (byte != 0xFF) { break; }
375     }
376 
377   sei->payload_type = (enum sei_payload_type)payload_type;
378   sei->payload_size = payload_size;
379 
380 
381   // --- sei message dispatch
382 
383   de265_error err = DE265_OK;
384 
385   switch (sei->payload_type) {
386   case sei_payload_type_decoded_picture_hash:
387     err = read_sei_decoded_picture_hash(reader,sei,sps);
388     break;
389 
390   default:
391     // TODO: unknown SEI messages are ignored
392     break;
393   }
394 
395   return err;
396 }
397 
dump_sei(const sei_message * sei,const seq_parameter_set * sps)398 void dump_sei(const sei_message* sei, const seq_parameter_set* sps)
399 {
400   loginfo(LogHeaders,"SEI message: %s\n", sei_type_name(sei->payload_type));
401 
402   switch (sei->payload_type) {
403   case sei_payload_type_decoded_picture_hash:
404     dump_sei_decoded_picture_hash(sei, sps);
405     break;
406 
407   default:
408     // TODO: unknown SEI messages are ignored
409     break;
410   }
411 }
412 
413 
process_sei(const sei_message * sei,de265_image * img)414 de265_error process_sei(const sei_message* sei, de265_image* img)
415 {
416   de265_error err = DE265_OK;
417 
418   switch (sei->payload_type) {
419   case sei_payload_type_decoded_picture_hash:
420     if (img->decctx->param_sei_check_hash) {
421       err = process_sei_decoded_picture_hash(sei, img);
422       if (err==DE265_OK) {
423         //printf("SEI check ok\n");
424       }
425     }
426 
427     break;
428 
429   default:
430     // TODO: unknown SEI messages are ignored
431     break;
432   }
433 
434   return err;
435 }
436 
437 
sei_type_name(enum sei_payload_type type)438 const char* sei_type_name(enum sei_payload_type type)
439 {
440   switch (type) {
441   case sei_payload_type_buffering_period:
442     return "buffering_period";
443   case sei_payload_type_pic_timing:
444     return "pic_timing";
445   case sei_payload_type_pan_scan_rect:
446     return "pan_scan_rect";
447   case sei_payload_type_filler_payload:
448     return "filler_payload";
449   case sei_payload_type_user_data_registered_itu_t_t35:
450     return "user_data_registered_itu_t_t35";
451   case sei_payload_type_user_data_unregistered:
452     return "user_data_unregistered";
453   case sei_payload_type_recovery_point:
454     return "recovery_point";
455   case sei_payload_type_scene_info:
456     return "scene_info";
457   case sei_payload_type_picture_snapshot:
458     return "picture_snapshot";
459   case sei_payload_type_progressive_refinement_segment_start:
460     return "progressive_refinement_segment_start";
461   case sei_payload_type_progressive_refinement_segment_end:
462     return "progressive_refinement_segment_end";
463   case sei_payload_type_film_grain_characteristics:
464     return "film_grain_characteristics";
465   case sei_payload_type_post_filter_hint:
466     return "post_filter_hint";
467   case sei_payload_type_tone_mapping_info:
468     return "tone_mapping_info";
469   case sei_payload_type_frame_packing_arrangement:
470     return "frame_packing_arrangement";
471   case sei_payload_type_display_orientation:
472     return "display_orientation";
473   case sei_payload_type_structure_of_pictures_info:
474     return "structure_of_pictures_info";
475   case sei_payload_type_active_parameter_sets:
476     return "active_parameter_sets";
477   case sei_payload_type_decoding_unit_info:
478     return "decoding_unit_info";
479   case sei_payload_type_temporal_sub_layer_zero_index:
480     return "temporal_sub_layer_zero_index";
481   case sei_payload_type_decoded_picture_hash:
482     return "decoded_picture_hash";
483   case sei_payload_type_scalable_nesting:
484     return "scalable_nesting";
485   case sei_payload_type_region_refresh_info:
486     return "region_refresh_info";
487   case sei_payload_type_no_display:
488     return "no_display";
489   case sei_payload_type_motion_constrained_tile_sets:
490     return "motion_constrained_tile_sets";
491 
492   default:
493     return "unknown SEI message";
494   }
495 }
496