PageRenderTime 74ms CodeModel.GetById 24ms app.highlight 42ms RepoModel.GetById 1ms app.codeStats 0ms

/Play/nal.js

http://github.com/mbebenita/Broadway
JavaScript | 648 lines | 451 code | 81 blank | 116 comment | 131 complexity | a50e9c99b47a5afae897393b470f8415 MD5 | raw file
  1var Video = (function() {
  2    function constructor() {
  3    }
  4    return constructor;
  5})();
  6
  7/**
  8 * Represents a video decoder capturing all of its internal state. 
  9 */
 10var Decoder = (function() {
 11    function constructor() {
 12        this.SequenceParameterSets = [];
 13        this.PictureParameterSets = [];
 14        this.Video = new Video();
 15    }
 16
 17    constructor.prototype = {
 18        decode : function(ptr) {
 19            var reader = new AnnexBNALUnitReader(ptr);
 20
 21            var i = 0;
 22            do {
 23                var nal = reader.readNALUnit();
 24                if (nal != null) {
 25                    traceln("+ NAL Unit " + (i++));
 26                    var unit = nal.createUnit();
 27                    traceln("| nal_size: " + (nal.rbsp.length + 1));
 28                    traceln("| nal_type: " + nal.nal_type);
 29                    traceln("| nal_ref_idc: " + nal.nal_ref_idc);
 30                    if (unit != null) {
 31                        unit.decode(new Bitstream(nal.rbsp));
 32                        // println(unit.toString());
 33                    }
 34                }
 35            } while (nal != null);
 36        }
 37    };
 38
 39    return constructor;
 40})();
 41
 42
 43/*
 44 * Represents an Annex B (B) byte stream that encodes NAL Units. In the Annex B
 45 * byte stream NAL Units are prefixed by a 3 byte start code prefix. The actual
 46 * NAL Unit payload data is interleaved with 'emulation prevention' bytes.
 47 */
 48var AnnexBNALUnitReader = (function () {
 49	var ptr = null;
 50	
 51    function constructor(ptr) {
 52        this.ptr = ptr;
 53    }
 54
 55	constructor.prototype = {
 56
 57        readNALUnit : function() {
 58            if (this.ptr == null) {
 59                return null;
 60            }
 61            var res = this.findNextAnnexBNALUnit(this.ptr);
 62            this.ptr = res.next;
 63            return new NALUnit(res.nal);
 64        },
 65
 66        /*
 67         * Finds the next NAL unit from an Annex B byte stream.
 68         */
 69        findNextAnnexBNALUnit : function findNextAnnexBNALUnit(ptr) {
 70            var i = 0, size = ptr.length;
 71
 72            /* look for start_code_prefix */
 73            while (ptr[i] == 0 && i < size) {
 74                i += 1;
 75            }
 76            if (i >= size) {
 77                error("cannot find any start_code_prefix");
 78            } else if (ptr[i] != 0x1) {
 79                /* start_code_prefix is not at the beginning, continue */
 80                i = -1;
 81            }
 82            i++;
 83            var j = i, start = i, end = start, foundStartCode = 0;
 84            while (!foundStartCode) {
 85                /* see 2 consecutive zero bytes */
 86                while ((j + 1 < size) && (ptr[j] != 0 || ptr[j + 1] != 0)) { 
 87                    j += 1;
 88                }
 89                end = j; /* stop and check for start code */
 90                /* keep reading for zero byte */
 91                while (j + 2 < size && ptr[j + 2] == 0) {
 92                    j += 1;
 93                }
 94                if (j + 2 >= size) {
 95                    size -= start;
 96                    return {
 97                        start : start,
 98                        nal : ptr.subarray(start, start + size),
 99                        next : null
100                    };
101                }
102                if (ptr[j + 2] == 0x1) {
103                    foundStartCode = 1;
104                } else {
105                    /* could be emulation code 0x3 */
106                    j += 2; /* continue the search */
107                }
108            }
109            size = end - start;
110            return {
111                start : start,
112                nal : ptr.subarray(start, start + size),
113                next : ptr.subarray(end)
114            };
115        }
116    };
117
118    return constructor;
119})();
120
121/**
122 * Indicates the type of the NAL Unit. The decoder needs to know how slices are coded. Some information can change from
123 * slice to slice and can be encoded in each slice. Other information such as coding parameters, picture format, size,
124 * type of entropy coder, bit rate, etc. does not change as often and does not need to be retransmitted as often.
125 * 
126 * Combinations of coding parameters are stored on both the encoder and decoder side in various tables.
127 * 
128 * There are two parameter sets: Picture Parameter Set (PPS) contains information about the slices of one or more
129 * pictures. Sequence Parameter Set (SPS) contains information about the sequence.
130 * 
131 * Instantaneous Decoding Refresh (IDR) picture contains only slices with I and SI slice types. IDR pictures invalidate
132 * all reference pictures in the buffer prior to itself and can thus confine drifting errors. IDR pictures are always
133 * the first in a sequence of pictures.
134 * 
135 * Baseline Profile and Main Profile does not include NAL Unit Types: 2, 3, 4.
136 */
137NALU_TYPE = {
138    SLICE : 1,
139    DPA : 2,
140    DPB : 3,
141    DPC : 4,
142    IDR : 5,
143    SEI : 6,
144    
145    /**
146     * Sequence Parameter Set
147     */
148    SPS : 7,
149    
150    /**
151     * Picture Parameter Set
152     */
153    PPS : 8,
154    
155    /**
156     * Access Unit Delimiter
157     */
158    AUD : 9,
159    EOSEQ : 10,
160    EOSTREAM : 11,
161    FILL : 12,
162    PREFIX : 14,
163    SUB_SPS : 15,
164    SLC_EXT : 20,
165    VDRD : 24
166};
167
168/**
169 * Indicates the importance of the NAL Unit for the reconstruction process. The higher the value the more important the
170 * NAL Unit. For instance, a value of 0 indicates that the NAL Unit is not used as a reference by any other units can be
171 * safely DISCARDED.
172 */
173NALU_REF_IDC = {
174    NALU_PRIORITY_HIGHEST : 3,
175    NALU_PRIORITY_HIGH : 2,
176    NALU_PRIORITY_LOW : 1,
177    NALU_PRIORITY_DISPOSABLE : 0
178};
179
180SLICE_TYPE = {
181    /**
182     * Intra prediction (I) and/or prediction from one reference per macroblock partition (P).
183     */
184    P_SLICE : 0,
185    
186    /**
187     * Intra prediction (I), prediction from one reference frame (P) or biprediction from two references (B).
188     */
189    B_SLICE : 1,
190    
191    /** Intra prediction only. */
192    I_SLICE : 2,
193    SP_SLICE : 3,
194    SI_SLICE : 4,
195    P_ALL_SLICE : 5,
196    B_ALL_SLICE : 6,
197    I_ALL_SLICE : 7,
198    SP_ALL_SLICE : 8,
199    SI_ALL_SLICE : 9
200};
201
202/**
203 * Represents a NAL (Network Abstraction Layer) Unit
204 * 
205 * NAL Unit Header Format:
206 * 
207 * forbidden_zero_bit (F): Usually set to 0 at source, set to 1 to indicate
208 * errors in the NAL Unit.
209 * 
210 * nal_ref_idc (NRI): Indicates the importance of the NAL Unit, from 0 (low) to
211 * 3 (high).
212 * 
213 * nal_unit_type (TYPE): Indicates the type of the NAL Unit. Although this field
214 * encodes 32 possible values, only 12 are used by H.264.
215 * 
216 * Payload: A buffer that contains an encapsulated byte sequence payload (EBSP)
217 * which needs to be decoded to a raw byte sequence payload (RBSP) before
218 * further processing.
219 * 
220 *  <1> <-2-> <-----5-----> <--------- ? ---------> 
221 * +---+-----+-------------+-----------------------+ | F | NRI | TYPE | Payload |
222 * +---+-----+-------------+-----------------------+
223 */
224var NALUnit = (function () {
225	function constructor(ptr) {
226		var forbidden_zero_bit;
227		if (ptr.length == 0) {
228			unexpected();
229		} else {
230	        forbidden_zero_bit = ptr[0] >> 7;
231	        if (forbidden_zero_bit != 0) {
232	        	unexpected();
233	        }
234	        this.nal_ref_idc = (ptr[0] & 0x60) >> 5;
235	        this.nal_type = ptr[0] & 0x1F;
236	        this.rbsp = ptr.subarray(1, 1 + convertEBSPToRBSP(ptr.subarray(1)));
237	        return;
238	    }
239	}
240	
241	/**
242	 * Converts an encapsulated byte sequence payload (EBSP) to a raw byte sequence payload (RBSP).
243	 */
244    function convertEBSPToRBSP(ptr) {
245        var j = 0;
246        var count = 0;
247        var size = ptr.length;
248        for (var i = 0; i < size; i++) {
249            var x = ptr[i];
250            if (count == 2 && x == 0x03) {
251                i += 1;
252                count = 0;
253            }
254            ptr[j++] = x;
255            if (x == 0x00) {
256                count += 1;
257            } else {
258                count = 0;
259            }
260        }
261        return j;
262    }
263
264	constructor.prototype = {
265        toString : function toString() {
266            return getProperties(this);
267        },
268        createUnit : function() {
269            switch (this.nal_type) {
270            case NALU_TYPE.SPS:
271                return new SPS();
272            case NALU_TYPE.PPS:
273                return new PPS();
274            case NALU_TYPE.SLICE:
275            case NALU_TYPE.IDR:
276                return new Slice(this.nal_type);
277            default:
278                return null;
279                // unexpected();
280            }
281        }
282    };
283	
284	return constructor;
285})();
286
287
288
289
290var Slice = (function() {
291    function constructor(nal_unit_type) {
292        this.nal_unit_type = nal_unit_type;
293        this.header = new SliceHeader();
294        this.data = new SliceData(this.header);
295    }
296    
297    constructor.prototype.decode = function (stream) {
298        var header = this.header;
299        var video = decoder.video;
300        
301        header.decode(this.nal_unit_type, stream);
302        
303        if (this.nal_unit_type == NALU_TYPE.IDR) {
304            // video.prevFrameNumber = 0;
305        }
306        
307        // this.data.decode(stream);
308    };
309    
310    constructor.prototype.toString = function () {
311        return "Slice: " + getProperties(this, true);
312    };
313    
314    return constructor;
315})();
316
317/**
318 * Represents a Slice's Data
319 */
320var SliceData = (function() {
321    function constructor(header) {
322        this.header = header;
323    }
324    
325    constructor.prototype.decode = function (stream) {
326        
327    };
328    
329    constructor.prototype.toString = function () {
330        return "Slice Data: " + getProperties(this, true);
331    };
332    
333    return constructor;
334})();
335
336    
337/**
338 * Represents a Slice Header
339 * 
340 * Clause 7.4.3
341 */
342var SliceHeader = (function() {
343    function constructor() { }
344    
345    constructor.prototype.decode = function (nal_unit_type, stream) {
346        var video = decoder.Video;
347        
348        traceln("| + Slice Header");
349        this.first_mb_in_slice = stream.uev();
350        traceln("| | first_mb_in_slice: " + this.first_mb_in_slice);
351        this.slice_type = stream.uev();
352        traceln("| | slice_type: " + this.slice_type);
353        if (this.first_mb_in_slice != 0) {
354            notImplemented();
355        }
356        this.pic_parameter_set_id = stream.uev();
357        traceln("| | pic_parameter_set_id: " + this.pic_parameter_set_id);
358        assertRange(this.pic_parameter_set_id, 0, 255);
359        
360        var currentPPS = video.CurrentPPS = decoder.PictureParameterSets[this.pic_parameter_set_id];
361        if (currentPPS == null) {
362            unexpected("pic_parameter_set_id: " + this.pic_parameter_set_id);
363        }
364        
365        var currentSPS = video.CurrentSPS = decoder.SequenceParameterSets[currentPPS.seq_parameter_set_id];
366        if (currentSPS == null) {
367            unexpected();
368        }
369        
370        if (video.CurrentPPS !== currentPPS) {
371            video.CurrentPPS = currentPPS;  
372            
373//            notImplemented("currentPPS.seq_parameter_set_id: " + currentPPS.seq_parameter_set_id +
374//                           " != decoder.Video.seq_parameter_set_id: " + decoder.Video.seq_parameter_set_id);
375        }
376        
377        /* derived variables from SPS */
378        video.MaxFrameNum = 1 << (currentSPS.log2_max_frame_num_minus4 + 4);
379        // MC_OPTIMIZE
380        video.PicWidthInMbs = currentSPS.pic_width_in_mbs_minus1 + 1;
381        video.PicWidthInSamplesL = video.PicWidthInMbs * 16;
382        video.PicWidthInSamplesC = video.PicWidthInMbs * 8;
383        video.PicHeightInMapUnits = currentSPS.pic_height_in_map_units_minus1 + 1;
384        video.PicSizeInMapUnits = video.PicWidthInMbs * video.PicHeightInMapUnits;
385        video.FrameHeightInMbs = (2 - currentSPS.frame_mbs_only_flag) * video.PicHeightInMapUnits;
386
387        /* derived from PPS */
388        video.SliceGroupChangeRate = currentPPS.slice_group_change_rate_minus1 + 1;
389
390        this.frame_num = stream.readBits(currentSPS.log2_max_frame_num_minus4 + 4);
391        traceln("| | frame_num: " + this.frame_num);
392        
393        /* Book 5.3.4, if the frame_mbs_only_flag is set to zero, special coding of fields or interlaced video
394         * is enabled. */
395        if (!currentSPS.frame_mbs_only_flag) {
396            /* Clause 7.4.3, a field_pic_flag set to zero indicates the slice is a coded frame, otherwise it's
397             * a coded field. We don't support interlaced video. */ 
398            this.field_pic_flag = stream.readBit();
399            traceln("| | field_pic_flag: " + this.field_pic_flag);
400            assertFalse (this.field_pic_flag);
401        }
402        
403        /* derived variables from slice header */
404        video.PicHeightInMbs = video.FrameHeightInMbs;
405        video.PicHeightInSamplesL = video.PicHeightInMbs * 16;
406        video.PicHeightInSamplesC = video.PicHeightInMbs * 8;
407        video.PicSizeInMbs = video.PicWidthInMbs * video.PicHeightInMbs;
408        
409        if (this.first_mb_in_slice >= video.PicSizeInMbs) {
410            unexpected();
411        }
412        video.MaxPicNum = video.MaxFrameNum;
413        video.CurrPicNum = this.frame_num;
414
415        if (nal_unit_type == NALU_TYPE.IDR) {
416            if (this.frame_num != 0) {
417                unexpected();
418            }
419            this.idr_pic_id = stream.uev();
420            traceln("| | idr_pic_id: " + this.idr_pic_id);
421        }
422        
423        this.delta_pic_order_cnt_bottom = 0; /* default value */
424        this.delta_pic_order_cnt = [0, 0];
425        
426        if (currentSPS.pic_order_cnt_type == 0) {
427            this.pic_order_cnt_lsb = stream.readBits(currentSPS.log2_max_pic_order_cnt_lsb_minus4 + 4);
428            traceln("| | pic_order_cnt_lsb: " + this.pic_order_cnt_lsb);
429            video.MaxPicOrderCntLsb = 1 << (currentSPS.log2_max_pic_order_cnt_lsb_minus4 + 4);
430            if (this.pic_order_cnt_lsb > video.MaxPicOrderCntLsb - 1) {
431                unexpected();
432            }
433
434            if (currentPPS.pic_order_present_flag) {
435                notImplemented();
436                this.delta_pic_order_cnt_bottom = stream.sev32();
437                traceln("| | delta_pic_order_cnt_bottom: " + this.delta_pic_order_cnt_bottom);
438            }
439        }
440        
441        if (currentSPS.pic_order_cnt_type == 1 && !currentSPS.delta_pic_order_always_zero_flag) {
442            this.delta_pic_order_cnt[0] = stream.sev32();
443            traceln("| | delta_pic_order_cnt[0]: " + this.delta_pic_order_cnt[0]);
444            if (currentPPS.pic_order_present_flag) {
445                this.delta_pic_order_cnt[1] = stream.sev32();
446                traceln("| | delta_pic_order_cnt[1]: " + this.delta_pic_order_cnt[1]);
447            }
448        }
449
450        this.redundant_pic_cnt = 0; /* default value */
451        if (currentPPS.redundant_pic_cnt_present_flag) {
452            // MC_CHECK
453            this.redundant_pic_cnt = stream.uev();
454            if (this.redundant_pic_cnt > 127) /* out of range */
455                unexpected();
456
457            if (this.redundant_pic_cnt > 0) /* redundant picture */
458                unexpected(); /* not supported */
459        }
460        
461        this.num_ref_idx_l0_active_minus1 = currentPPS.num_ref_idx_l0_active_minus1;
462        this.num_ref_idx_l1_active_minus1 = currentPPS.num_ref_idx_l1_active_minus1;
463
464        if (this.slice_type == SLICE_TYPE.P_SLICE) {
465            this.num_ref_idx_active_override_flag = stream.readBit();
466            traceln("| | num_ref_idx_active_override_flag: " + this.num_ref_idx_active_override_flag);
467            if (this.num_ref_idx_active_override_flag) {
468                this.num_ref_idx_l0_active_minus1 = stream.uev();
469                traceln("| | num_ref_idx_l0_active_minus1: " + this.num_ref_idx_l0_active_minus1);
470            } else   {
471                /* the following condition is not allowed if the flag is zero */
472                if ((slice_type == SLICE_TYPE.P_SLICE) && currentPPS.num_ref_idx_l0_active_minus1 > 15) {
473                    unexpected(); /* not allowed */
474                }
475            }
476        }
477
478        if (this.num_ref_idx_l0_active_minus1 > 15 || this.num_ref_idx_l1_active_minus1 > 15) {
479            unexpected(); /* not allowed */
480        }
481        
482        /* if MbaffFrameFlag =1,
483        max value of index is num_ref_idx_l0_active_minus1 for frame MBs and
484        2*this.num_ref_idx_l0_active_minus1 + 1 for field MBs */
485
486        this.ref_pic_list_reordering(video, stream);
487
488        if (video.nal_ref_idc) {
489            this.dec_ref_pic_marking(video, stream, this);
490        }
491        
492        this.slice_qp_delta = stream.sev();
493        traceln("| | slice_qp_delta: " + this.slice_qp_delta);
494
495        video.QPy = 26 + currentPPS.pic_init_qp_minus26 + this.slice_qp_delta;
496        if (video.QPy > 51 || video.QPy < 0) {
497            video.QPy = clip(0, 51, video.QPy);
498        }
499        video.QPc = mapQPi2QPc[clip(0, 51, video.QPy + video.CurrentPPS.chroma_qp_index_offset)];
500
501        video.QPy_div_6 = (video.QPy * 43) >>> 8;
502        video.QPy_mod_6 = video.QPy - 6 * video.QPy_div_6;
503
504        video.QPc_div_6 = (video.QPc * 43) >>> 8;
505        video.QPc_mod_6 = video.QPc - 6 * video.QPc_div_6;
506
507        this.slice_alpha_c0_offset_div2 = 0;
508        this.slice_beta_offset_div_2 = 0;
509        this.disable_deblocking_filter_idc = 0;
510        video.FilterOffsetA = video.FilterOffsetB = 0;
511
512        if (currentPPS.deblocking_filter_control_present_flag) {
513            this.disable_deblocking_filter_idc = stream.uev();
514            traceln("| | disable_deblocking_filter_idc: " + this.disable_deblocking_filter_idc);
515            if (this.disable_deblocking_filter_idc > 2) {
516                unexpected(); /* out of range */
517            }
518            if (this.disable_deblocking_filter_idc != 1) {
519                this.slice_alpha_c0_offset_div2 = stream.sev();
520                traceln("| | slice_alpha_c0_offset_div2: " + this.slice_alpha_c0_offset_div2);
521                if (this.slice_alpha_c0_offset_div2 < -6 || this.slice_alpha_c0_offset_div2 > 6) {
522                    unexpected();
523                }
524                video.FilterOffsetA = this.slice_alpha_c0_offset_div2 << 1;
525                this.slice_beta_offset_div_2 = stream.sev();
526                traceln("| | slice_beta_offset_div_2: " + this.slice_beta_offset_div_2);
527                if (this.slice_beta_offset_div_2 < -6 || this.slice_beta_offset_div_2 > 6) {
528                    unexpected();
529                }
530                video.FilterOffsetB = this.slice_beta_offset_div_2 << 1;
531            }
532        }
533
534        if (currentPPS.num_slice_groups_minus1 > 0 && 
535            currentPPS.slice_group_map_type >= 3 &&
536            currentPPS.slice_group_map_type <= 5) {
537            /* Ceil(Log2(PicSizeInMapUnits/(float)SliceGroupChangeRate + 1)) */
538            temp = video.PicSizeInMapUnits / video.SliceGroupChangeRate;
539            if (video.PicSizeInMapUnits % video.SliceGroupChangeRate) {
540                temp++;
541            }
542            i = 0;
543            temp++;
544            while (temp)
545            {
546                temp >>= 1;
547                i++;
548            }
549            this.slice_group_change_cycle = stream.readBits(i);
550            traceln("| | slice_group_change_cycle: " + this.slice_group_change_cycle);
551            video.MapUnitsInSliceGroup0 = min(this.slice_group_change_cycle * video.SliceGroupChangeRate, video.PicSizeInMapUnits);
552        }
553    };
554   
555    /**
556     * Book 5.3.3.2
557     * Clause 7.3.3.1
558     * 
559     * The reference picture list order can be change for the current slice only using this command. The
560     * ref_pic_list_reordering_flag indicates that such an operation should occur.
561     */
562    constructor.prototype.ref_pic_list_reordering = function(video, stream) {
563        if (this.slice_type != SLICE_TYPE.I_SLICE) {
564            this.ref_pic_list_reordering_flag_l0 = stream.readBit();
565            traceln("| | ref_pic_list_reordering_flag_l0: " + this.ref_pic_list_reordering_flag_l0);
566            if (this.ref_pic_list_reordering_flag_l0) {
567                traceln("| | + Reference Picture List Reordering Commands");
568                var i = 0;
569                this.reordering_of_pic_nums_idc_l0 = [];
570                this.abs_diff_pic_num_minus1_l0 = [];
571                do {
572                    var res = this.reordering_of_pic_nums_idc_l0[i] = stream.uev();
573                    if (res == 0 || res == 1) {
574                        this.abs_diff_pic_num_minus1_l0[i] = stream.uev();
575                        traceln("| | abs_diff_pic_num_minus1_l0[" + i + "]: " + this.abs_diff_pic_num_minus1_l0[i]);
576                        assertFalse (res == 0 && this.abs_diff_pic_num_minus1_l0[i] > video.MaxPicNum / 2 - 1);
577                        assertFalse (res == 1 && this.abs_diff_pic_num_minus1_l0[i] > video.MaxPicNum / 2 - 2);
578                    } else if (res == 2) {
579                        this.long_term_pic_num_l0[i] = stream.uev();
580                        traceln("| | long_term_pic_num_l0[" + i + "]: " + this.long_term_pic_num_l0[i]);
581                    }
582                    i++;
583                } while (this.reordering_of_pic_nums_idc_l0[i - 1] != 3 && i <= this.num_ref_idx_l0_active_minus1 + 1);
584            }
585        }
586    };
587    
588    /**
589     * Clause 7.4.3.3
590     */
591    constructor.prototype.dec_ref_pic_marking = function(video, stream) {
592        traceln("| | + dec_ref_pic_marking");
593        if (video.nal_unit_type == NALU_TYPE.IDR) {
594            this.no_output_of_prior_pics_flag = stream.readBit();
595            traceln("| | | no_output_of_prior_pics_flag: " + this.no_output_of_prior_pics_flag);
596            this.long_term_reference_flag = stream.readBit();
597            traceln("| | | long_term_reference_flag: " + this.long_term_reference_flag);
598            if (this.long_term_reference_flag == 0) {
599                video.MaxLongTermFrameIdx = -1;
600            } else {
601                video.MaxLongTermFrameIdx = 0;
602                video.LongTermFrameIdx = 0;
603            }
604        } else {
605            this.adaptive_ref_pic_marking_mode_flag = stream.readBit();
606            traceln("| | | adaptive_ref_pic_marking_mode_flag: " + this.adaptive_ref_pic_marking_mode_flag);
607            if (this.adaptive_ref_pic_marking_mode_flag) {
608                this.memory_management_control_operation = [];
609                this.difference_of_pic_nums_minus1 = [];
610                this.long_term_pic_num = [];
611                this.max_long_term_frame_idx_plus1 = [];
612                var i = 0;
613                do {
614                    var res = this.memory_management_control_operation[i] = stream.uev();
615                    traceln("| | | memory_management_control_operation[" + i + "]: " + this.memory_management_control_operation[i]);
616                    if (res == 1 || res == 3) {
617                        this.difference_of_pic_nums_minus1[i] = stream.uev();
618                        traceln("| | | difference_of_pic_nums_minus1[" + i + "]: " + this.difference_of_pic_nums_minus1[i]);
619                    }
620                    if (res == 2) {
621                        this.long_term_pic_num[i] = stream.uev();
622                        traceln("| | | long_term_pic_num[" + i + "]: " + this.long_term_pic_num[i]);
623                    }
624                    if (res == 3 || res == 6) {
625                        this.long_term_frame_idx[i] = stream.uev();
626                        traceln("| | | long_term_frame_idx[" + i + "]: " + this.long_term_frame_idx[i]);
627                    }
628                    if (res == 4) {
629                        this.max_long_term_frame_idx_plus1[i] = stream.uev();
630                        traceln("| | | max_long_term_frame_idx_plus1[" + i + "]: " + this.max_long_term_frame_idx_plus1[i]);
631                    }
632                    i++;
633                } while (this.memory_management_control_operation[i - 1] != 0 && i < MAX_DEC_REF_PIC_MARKING);
634                assertFalse(i >= MAX_DEC_REF_PIC_MARKING);
635            }
636        }
637    };
638    
639    constructor.prototype.toString = function () {
640        return "Slice Header: " + getProperties(this, true);
641    };
642    
643    return constructor;
644})();
645
646
647
648