void WriteFilterTables(PB_INSTANCE *pbi, oggpack_buffer *opb){ int i; int bits=5; oggpackB_write(opb, bits, 3); for(i=0;i<Q_TABLE_SIZE;i++) oggpackB_write(opb, pbi->LoopFilterLimits[i],bits); }
static void WriteHuffTree(HUFF_ENTRY *HuffRoot, oggpack_buffer *opb) { if (HuffRoot->Value >= 0) { oggpackB_write(opb, 1, 1); oggpackB_write(opb, HuffRoot->Value, 5); } else { oggpackB_write(opb, 0, 1); WriteHuffTree(HuffRoot->ZeroChild, opb); WriteHuffTree(HuffRoot->OneChild, opb); } }
/* build the comment header packet from the passed metadata */ int theora_encode_comment(theora_comment *tc, ogg_packet *op) { const char *vendor = theora_version_string(); const int vendor_length = strlen(vendor); oggpack_buffer *opb; #ifndef LIBOGG2 opb = _ogg_malloc(sizeof(oggpack_buffer)); oggpackB_writeinit(opb); #else opb = _ogg_malloc(oggpack_buffersize()); oggpackB_writeinit(opb, ogg_buffer_create()); #endif oggpackB_write(opb, 0x81, 8); _tp_writebuffer(opb, "theora", 6); _tp_writelsbint(opb, vendor_length); _tp_writebuffer(opb, vendor, vendor_length); _tp_writelsbint(opb, tc->comments); if(tc->comments){ int i; for(i=0;i<tc->comments;i++){ if(tc->user_comments[i]){ _tp_writelsbint(opb,tc->comment_lengths[i]); _tp_writebuffer(opb,tc->user_comments[i],tc->comment_lengths[i]); }else{ oggpackB_write(opb,0,32); } } } op->bytes=oggpack_bytes(opb); #ifndef LIBOGG2 /* So we're expecting the application will free this? */ op->packet=_ogg_malloc(oggpack_bytes(opb)); memcpy(op->packet, oggpack_get_buffer(opb), oggpack_bytes(opb)); oggpack_writeclear(opb); #else op->packet = oggpack_writebuffer(opb); /* When the application puts op->packet into a stream_state object, it becomes the property of libogg2's internal memory management. */ #endif _ogg_free(opb); op->b_o_s=0; op->e_o_s=0; op->packetno=0; op->granulepos=0; return (0); }
/* build the final header packet with the tables required for decode */ int theora_encode_tables(theora_state *t, ogg_packet *op){ CP_INSTANCE *cpi=(CP_INSTANCE *)(t->internal_encode); #ifndef LIBOGG2 oggpackB_reset(cpi->oggbuffer); #else oggpackB_writeinit(cpi->oggbuffer, cpi->oggbufferstate); #endif oggpackB_write(cpi->oggbuffer,0x82,8); _tp_writebuffer(cpi->oggbuffer,"theora",6); WriteFilterTables(&cpi->pb,cpi->oggbuffer); WriteQTables(&cpi->pb,cpi->oggbuffer); WriteHuffmanTrees(cpi->pb.HuffRoot_VP3x,cpi->oggbuffer); #ifndef LIBOGG2 op->packet=oggpackB_get_buffer(cpi->oggbuffer); #else op->packet=oggpackB_writebuffer(cpi->oggbuffer); #endif op->bytes=oggpackB_bytes(cpi->oggbuffer); op->b_o_s=0; op->e_o_s=0; op->packetno=0; op->granulepos=0; cpi->packetflag=0; return(0); }
static void _tp_writelsbint(oggpack_buffer *opb, long value) { oggpackB_write(opb, value&0xFF, 8); oggpackB_write(opb, value>>8&0xFF, 8); oggpackB_write(opb, value>>16&0xFF, 8); oggpackB_write(opb, value>>24&0xFF, 8); }
static void _tp_writebuffer(oggpack_buffer *opb, const char *buf, const long len) { long i; for (i = 0; i < len; i++) oggpackB_write(opb, *buf++, 8); }
/* build the comment header packet from the passed metadata */ int theora_encode_comment(theora_comment *tc, ogg_packet *op) { const char *vendor = theora_version_string(); const int vendor_length = strlen(vendor); oggpack_buffer *opb; opb = _ogg_malloc(sizeof(oggpack_buffer)); oggpackB_writeinit(opb); oggpackB_write(opb, 0x81, 8); _tp_writebuffer(opb, "theora", 6); _tp_writelsbint(opb, vendor_length); _tp_writebuffer(opb, vendor, vendor_length); _tp_writelsbint(opb, tc->comments); if(tc->comments){ int i; for(i=0;i<tc->comments;i++){ if(tc->user_comments[i]){ _tp_writelsbint(opb,tc->comment_lengths[i]); _tp_writebuffer(opb,tc->user_comments[i],tc->comment_lengths[i]); }else{ oggpackB_write(opb,0,32); } } } op->bytes=oggpack_bytes(opb); /* So we're expecting the application will free this? */ op->packet=_ogg_malloc(oggpack_bytes(opb)); memcpy(op->packet, oggpack_get_buffer(opb), oggpack_bytes(opb)); oggpack_writeclear(opb); _ogg_free(opb); op->b_o_s=0; op->e_o_s=0; op->packetno=0; op->granulepos=0; return (0); }
static ogg_uint32_t FrArrayCodeBlockRun( CP_INSTANCE *cpi, ogg_uint32_t value ) { ogg_uint32_t CodedVal = 0; ogg_uint32_t CodedBits = 0; /* Coding scheme: Codeword RunLength 0x 1-2 10x 3-4 110x 5-6 1110xx 7-10 11110xx 11-14 11111xxxx 15-30 */ if ( value <= 2 ) { CodedVal = value - 1; CodedBits = 2; } else if ( value <= 4 ) { CodedVal = 0x0004 + (value - 3); CodedBits = 3; } else if ( value <= 6 ) { CodedVal = 0x000C + (value - 5); CodedBits = 4; } else if ( value <= 10 ) { CodedVal = 0x0038 + (value - 7); CodedBits = 6; } else if ( value <= 14 ) { CodedVal = 0x0078 + (value - 11); CodedBits = 7; } else { CodedVal = 0x01F0 + (value - 15); CodedBits = 9; } /* Add the bits to the encode holding buffer. */ oggpackB_write( cpi->oggbuffer, CodedVal, (ogg_uint32_t)CodedBits ); return CodedBits; }
static ogg_uint32_t FrArrayCodeSBRun( CP_INSTANCE *cpi, ogg_uint32_t value ){ ogg_uint32_t CodedVal = 0; ogg_uint32_t CodedBits = 0; /* Coding scheme: Codeword RunLength 0 1 10x 2-3 110x 4-5 1110xx 6-9 11110xxx 10-17 111110xxxx 18-33 111111xxxxxxxxxxxx 34-4129 */ if ( value == 1 ){ CodedVal = 0; CodedBits = 1; } else if ( value <= 3 ) { CodedVal = 0x0004 + (value - 2); CodedBits = 3; } else if ( value <= 5 ) { CodedVal = 0x000C + (value - 4); CodedBits = 4; } else if ( value <= 9 ) { CodedVal = 0x0038 + (value - 6); CodedBits = 6; } else if ( value <= 17 ) { CodedVal = 0x00F0 + (value - 10); CodedBits = 8; } else if ( value <= 33 ) { CodedVal = 0x03E0 + (value - 18); CodedBits = 10; } else { CodedVal = 0x3F000 + (value - 34); CodedBits = 18; } /* Add the bits to the encode holding buffer. */ oggpackB_write( cpi->oggbuffer, CodedVal, (ogg_uint32_t)CodedBits ); return CodedBits; }
/*Encodes a description of the given Huffman tables. Although the codes are stored in the encoder as flat arrays, in the bit stream and in the decoder they are structured as a tree. This function recovers the tree structure from the flat array and then writes it out. Note that the codes MUST form a Huffman code, and not merely a prefix-free code, since the binary tree is assumed to be full. _opb: The buffer to store the tree in. _codes: The Huffman tables to pack. Return: 0 on success, or a negative value if one of the given Huffman tables does not form a full, prefix-free code.*/ int oc_huff_codes_pack(oggpack_buffer *_opb, const th_huff_code _codes[TH_NHUFFMAN_TABLES][TH_NDCT_TOKENS]){ int i; for(i=0;i<TH_NHUFFMAN_TABLES;i++){ oc_huff_entry entries[TH_NDCT_TOKENS]; int bpos; int maxlen; int mask; int j; /*First, find the maximum code length so we can align all the bit patterns.*/ maxlen=_codes[i][0].nbits; for(j=1;j<TH_NDCT_TOKENS;j++)maxlen=OC_MAXI(_codes[i][j].nbits,maxlen); /*It's improbable that a code with more than 32 bits could pass the validation below, but abort early in any case.*/ if(maxlen>32)return TH_EINVAL; mask=(1<<(maxlen>>1)<<(maxlen+1>>1))-1; /*Copy over the codes into our temporary workspace. The bit patterns are aligned, and the original entry each code is from is stored as well.*/ for(j=0;j<TH_NDCT_TOKENS;j++){ entries[j].shift=maxlen-_codes[i][j].nbits; entries[j].pattern=_codes[i][j].pattern<<entries[j].shift&mask; entries[j].token=j; } /*Sort the codes into ascending order. This is the order the leaves of the tree will be traversed.*/ qsort(entries,TH_NDCT_TOKENS,sizeof(entries[0]),huff_entry_cmp); /*For each leaf of the tree:*/ bpos=maxlen; for(j=0;j<TH_NDCT_TOKENS;j++){ ogg_uint32_t bit; /*Fail if this code has no bits at all. Technically a codebook with a single 0-bit entry is legal, but the encoder currently does not support codebooks which do not contain all the tokens.*/ if(entries[j].shift>=maxlen)return TH_EINVAL; /*Descend into the tree, writing a bit for each branch.*/ for(;bpos>entries[j].shift;bpos--)oggpackB_write(_opb,0,1); /*Mark this as a leaf node, and write its value.*/ oggpackB_write(_opb,1,1); oggpackB_write(_opb,entries[j].token,5); /*For each 1 branch we've descended, back up the tree until we reach a 0 branch.*/ bit=(ogg_uint32_t)1<<bpos; for(;entries[j].pattern&bit;bpos++)bit<<=1; /*Validate the code.*/ if(j+1<TH_NDCT_TOKENS){ mask=~(bit-1)<<1; /*The next entry should have a 1 bit where we had a 0, and should match our code above that bit. This verifies both fullness and prefix-freeness simultaneously.*/ if(!(entries[j+1].pattern&bit)|| (entries[j].pattern&mask)!=(entries[j+1].pattern&mask)){ return TH_EINVAL; } } /*If there are no more codes, we should have ascended back to the top of the tree.*/ else if(bpos<maxlen)return TH_EINVAL; } } return 0; }
static void UpdateFrame(CP_INSTANCE *cpi){ double CorrectionFactor; /* Reset the DC predictors. */ cpi->pb.LastIntraDC = 0; cpi->pb.InvLastIntraDC = 0; cpi->pb.LastInterDC = 0; cpi->pb.InvLastInterDC = 0; /* Initialise bit packing mechanism. */ #ifndef LIBOGG2 oggpackB_reset(cpi->oggbuffer); #else oggpackB_writeinit(cpi->oggbuffer, cpi->oggbufferstate); #endif /* mark as video frame */ oggpackB_write(cpi->oggbuffer,0,1); /* Write out the frame header information including size. */ WriteFrameHeader(cpi); /* Copy back any extra frags that are to be updated by the codec as part of the background cleanup task */ CopyBackExtraFrags(cpi); /* Encode the data. */ EncodeData(cpi); /* Adjust drop frame trigger. */ if ( GetFrameType(&cpi->pb) != KEY_FRAME ) { /* Apply decay factor then add in the last frame size. */ cpi->DropFrameTriggerBytes = ((cpi->DropFrameTriggerBytes * (DF_CANDIDATE_WINDOW-1)) / DF_CANDIDATE_WINDOW) + oggpackB_bytes(cpi->oggbuffer); }else{ /* Increase cpi->DropFrameTriggerBytes a little. Just after a key frame may actually be a good time to drop a frame. */ cpi->DropFrameTriggerBytes = (cpi->DropFrameTriggerBytes * DF_CANDIDATE_WINDOW) / (DF_CANDIDATE_WINDOW-1); } /* Test for overshoot which may require a dropped frame next time around. If we are already in a drop frame condition but the previous frame was not dropped then the threshold for continuing to allow dropped frames is reduced. */ if ( cpi->DropFrameCandidate ) { if ( cpi->DropFrameTriggerBytes > (cpi->frame_target_rate * (DF_CANDIDATE_WINDOW+1)) ) cpi->DropFrameCandidate = 1; else cpi->DropFrameCandidate = 0; } else { if ( cpi->DropFrameTriggerBytes > (cpi->frame_target_rate * ((DF_CANDIDATE_WINDOW*2)-2)) ) cpi->DropFrameCandidate = 1; else cpi->DropFrameCandidate = 0; } /* Update the BpbCorrectionFactor variable according to whether or not we were close enough with our selection of DCT quantiser. */ if ( GetFrameType(&cpi->pb) != KEY_FRAME ) { /* Work out a size correction factor. */ CorrectionFactor = (double)oggpackB_bytes(cpi->oggbuffer) / (double)cpi->ThisFrameTargetBytes; if ( (CorrectionFactor > 1.05) && (cpi->pb.ThisFrameQualityValue < cpi->pb.QThreshTable[cpi->Configuration.ActiveMaxQ]) ) { CorrectionFactor = 1.0 + ((CorrectionFactor - 1.0)/2); if ( CorrectionFactor > 1.5 ) cpi->BpbCorrectionFactor *= 1.5; else cpi->BpbCorrectionFactor *= CorrectionFactor; /* Keep BpbCorrectionFactor within limits */ if ( cpi->BpbCorrectionFactor > MAX_BPB_FACTOR ) cpi->BpbCorrectionFactor = MAX_BPB_FACTOR; } else if ( (CorrectionFactor < 0.95) && (cpi->pb.ThisFrameQualityValue > VERY_BEST_Q) ){ CorrectionFactor = 1.0 - ((1.0 - CorrectionFactor)/2); if ( CorrectionFactor < 0.75 ) cpi->BpbCorrectionFactor *= 0.75; else cpi->BpbCorrectionFactor *= CorrectionFactor; /* Keep BpbCorrectionFactor within limits */ if ( cpi->BpbCorrectionFactor < MIN_BPB_FACTOR ) cpi->BpbCorrectionFactor = MIN_BPB_FACTOR; } } /* Adjust carry over and or key frame context. */ if ( GetFrameType(&cpi->pb) == KEY_FRAME ) { /* Adjust the key frame context unless the key frame was very small */ AdjustKeyFrameContext(cpi); } else { /* Update the frame carry over */ cpi->CarryOver += ((ogg_int32_t)cpi->frame_target_rate - (ogg_int32_t)oggpackB_bytes(cpi->oggbuffer)); } cpi->TotalByteCount += oggpackB_bytes(cpi->oggbuffer); }
/* build the initial short header for stream recognition and format */ int theora_encode_header(theora_state *t, ogg_packet *op){ CP_INSTANCE *cpi=(CP_INSTANCE *)(t->internal_encode); int offset_y; #ifndef LIBOGG2 oggpackB_reset(cpi->oggbuffer); #else oggpackB_writeinit(cpi->oggbuffer, cpi->oggbufferstate); #endif oggpackB_write(cpi->oggbuffer,0x80,8); _tp_writebuffer(cpi->oggbuffer, "theora", 6); oggpackB_write(cpi->oggbuffer,VERSION_MAJOR,8); oggpackB_write(cpi->oggbuffer,VERSION_MINOR,8); oggpackB_write(cpi->oggbuffer,VERSION_SUB,8); oggpackB_write(cpi->oggbuffer,cpi->pb.info.width>>4,16); oggpackB_write(cpi->oggbuffer,cpi->pb.info.height>>4,16); oggpackB_write(cpi->oggbuffer,cpi->pb.info.frame_width,24); oggpackB_write(cpi->oggbuffer,cpi->pb.info.frame_height,24); oggpackB_write(cpi->oggbuffer,cpi->pb.info.offset_x,8); /* Applications use offset_y to mean offset from the top of the image; the * meaning in the bitstream is the opposite (from the bottom). Transform. */ offset_y = cpi->pb.info.height - cpi->pb.info.frame_height - cpi->pb.info.offset_y; oggpackB_write(cpi->oggbuffer,offset_y,8); oggpackB_write(cpi->oggbuffer,cpi->pb.info.fps_numerator,32); oggpackB_write(cpi->oggbuffer,cpi->pb.info.fps_denominator,32); oggpackB_write(cpi->oggbuffer,cpi->pb.info.aspect_numerator,24); oggpackB_write(cpi->oggbuffer,cpi->pb.info.aspect_denominator,24); oggpackB_write(cpi->oggbuffer,cpi->pb.info.colorspace,8); oggpackB_write(cpi->oggbuffer,cpi->pb.info.target_bitrate,24); oggpackB_write(cpi->oggbuffer,cpi->pb.info.quality,6); oggpackB_write(cpi->oggbuffer,cpi->pb.keyframe_granule_shift,5); oggpackB_write(cpi->oggbuffer,cpi->pb.info.pixelformat,2); oggpackB_write(cpi->oggbuffer,0,3); /* spare config bits */ #ifndef LIBOGG2 op->packet=oggpackB_get_buffer(cpi->oggbuffer); #else op->packet=oggpackB_writebuffer(cpi->oggbuffer); #endif op->bytes=oggpackB_bytes(cpi->oggbuffer); op->b_o_s=1; op->e_o_s=0; op->packetno=0; op->granulepos=0; cpi->packetflag=0; return(0); }
void PackAndWriteDFArray( CP_INSTANCE *cpi ){ ogg_uint32_t i; unsigned char val; ogg_uint32_t run_count; ogg_uint32_t SB, MB, B; /* Block, MB and SB loop variables */ ogg_uint32_t BListIndex = 0; ogg_uint32_t LastSbBIndex = 0; ogg_int32_t DfBlockIndex; /* Block index in display_fragments */ /* Initialise workspaces */ memset( cpi->pb.SBFullyFlags, 1, cpi->pb.SuperBlocks); memset( cpi->pb.SBCodedFlags, 0, cpi->pb.SuperBlocks ); memset( cpi->PartiallyCodedFlags, 0, cpi->pb.SuperBlocks ); memset( cpi->BlockCodedFlags, 0, cpi->pb.UnitFragments); for( SB = 0; SB < cpi->pb.SuperBlocks; SB++ ) { /* Check for coded blocks and macro-blocks */ for ( MB=0; MB<4; MB++ ) { /* If MB in frame */ if ( QuadMapToMBTopLeft(cpi->pb.BlockMap,SB,MB) >= 0 ) { for ( B=0; B<4; B++ ) { DfBlockIndex = QuadMapToIndex1( cpi->pb.BlockMap,SB, MB, B ); /* Does Block lie in frame: */ if ( DfBlockIndex >= 0 ) { /* In Frame: If it is not coded then this SB is only partly coded.: */ if ( cpi->pb.display_fragments[DfBlockIndex] ) { cpi->pb.SBCodedFlags[SB] = 1; /* SB at least partly coded */ cpi->BlockCodedFlags[BListIndex] = 1; /* Block is coded */ }else{ cpi->pb.SBFullyFlags[SB] = 0; /* SB not fully coded */ cpi->BlockCodedFlags[BListIndex] = 0; /* Block is not coded */ } BListIndex++; } } } } /* Is the SB fully coded or uncoded. If so then backup BListIndex and MBListIndex */ if ( cpi->pb.SBFullyFlags[SB] || !cpi->pb.SBCodedFlags[SB] ) { BListIndex = LastSbBIndex; /* Reset to values from previous SB */ }else{ cpi->PartiallyCodedFlags[SB] = 1; /* Set up list of partially coded SBs */ LastSbBIndex = BListIndex; } } /* Code list of partially coded Super-Block. */ val = cpi->PartiallyCodedFlags[0]; oggpackB_write( cpi->oggbuffer, (ogg_uint32_t)val, 1); i = 0; while ( i < cpi->pb.SuperBlocks ) { run_count = 0; while ( (i<cpi->pb.SuperBlocks) && (cpi->PartiallyCodedFlags[i]==val) ) { i++; run_count++; } /* Code the run */ FrArrayCodeSBRun( cpi, run_count ); val = ( val == 0 ) ? 1 : 0; } /* RLC Super-Block fully/not coded. */ i = 0; /* Skip partially coded blocks */ while( (i < cpi->pb.SuperBlocks) && cpi->PartiallyCodedFlags[i] ) i++; if ( i < cpi->pb.SuperBlocks ) { val = cpi->pb.SBFullyFlags[i]; oggpackB_write( cpi->oggbuffer, (ogg_uint32_t)val, 1); while ( i < cpi->pb.SuperBlocks ) { run_count = 0; while ( (i < cpi->pb.SuperBlocks) && (cpi->pb.SBFullyFlags[i] == val) ) { i++; /* Skip partially coded blocks */ while( (i < cpi->pb.SuperBlocks) && cpi->PartiallyCodedFlags[i] ) i++; run_count++; } /* Code the run */ FrArrayCodeSBRun( cpi, run_count ); val = ( val == 0 ) ? 1 : 0; } } /* Now code the block flags */ if ( BListIndex > 0 ) { /* Code the block flags start value */ val = cpi->BlockCodedFlags[0]; oggpackB_write( cpi->oggbuffer, (ogg_uint32_t)val, 1); /* Now code the block flags. */ for ( i = 0; i < BListIndex; ) { run_count = 0; while ( (cpi->BlockCodedFlags[i] == val) && (i < BListIndex) ) { i++; run_count++; } FrArrayCodeBlockRun( cpi, run_count ); val = ( val == 0 ) ? 1 : 0; } } }
void oc_quant_params_pack(oggpack_buffer *_opb,const th_quant_info *_qinfo){ const th_quant_ranges *qranges; const th_quant_base *base_mats[2*3*64]; int indices[2][3][64]; int nbase_mats; int nbits; int ci; int qi; int qri; int qti; int pli; int qtj; int plj; int bmi; int i; i=_qinfo->loop_filter_limits[0]; for(qi=1;qi<64;qi++)i=OC_MAXI(i,_qinfo->loop_filter_limits[qi]); nbits=OC_ILOG_32(i); oggpackB_write(_opb,nbits,3); for(qi=0;qi<64;qi++){ oggpackB_write(_opb,_qinfo->loop_filter_limits[qi],nbits); } /*580 bits for VP3.*/ i=1; for(qi=0;qi<64;qi++)i=OC_MAXI(_qinfo->ac_scale[qi],i); nbits=OC_ILOGNZ_32(i); oggpackB_write(_opb,nbits-1,4); for(qi=0;qi<64;qi++)oggpackB_write(_opb,_qinfo->ac_scale[qi],nbits); /*516 bits for VP3.*/ i=1; for(qi=0;qi<64;qi++)i=OC_MAXI(_qinfo->dc_scale[qi],i); nbits=OC_ILOGNZ_32(i); oggpackB_write(_opb,nbits-1,4); for(qi=0;qi<64;qi++)oggpackB_write(_opb,_qinfo->dc_scale[qi],nbits); /*Consolidate any duplicate base matrices.*/ nbase_mats=0; for(qti=0;qti<2;qti++)for(pli=0;pli<3;pli++){ qranges=_qinfo->qi_ranges[qti]+pli; for(qri=0;qri<=qranges->nranges;qri++){ for(bmi=0;;bmi++){ if(bmi>=nbase_mats){ base_mats[bmi]=qranges->base_matrices+qri; indices[qti][pli][qri]=nbase_mats++; break; } else if(memcmp(base_mats[bmi][0],qranges->base_matrices[qri], sizeof(base_mats[bmi][0]))==0){ indices[qti][pli][qri]=bmi; break; } } } } /*Write out the list of unique base matrices. 1545 bits for VP3 matrices.*/ oggpackB_write(_opb,nbase_mats-1,9); for(bmi=0;bmi<nbase_mats;bmi++){ for(ci=0;ci<64;ci++)oggpackB_write(_opb,base_mats[bmi][0][ci],8); } /*Now store quant ranges and their associated indices into the base matrix list. 46 bits for VP3 matrices.*/ nbits=OC_ILOG_32(nbase_mats-1); for(i=0;i<6;i++){ qti=i/3; pli=i%3; qranges=_qinfo->qi_ranges[qti]+pli; if(i>0){ if(qti>0){ if(qranges->nranges==_qinfo->qi_ranges[qti-1][pli].nranges&& memcmp(qranges->sizes,_qinfo->qi_ranges[qti-1][pli].sizes, qranges->nranges*sizeof(qranges->sizes[0]))==0&& memcmp(indices[qti][pli],indices[qti-1][pli], (qranges->nranges+1)*sizeof(indices[qti][pli][0]))==0){ oggpackB_write(_opb,1,2); continue; } } qtj=(i-1)/3; plj=(i-1)%3; if(qranges->nranges==_qinfo->qi_ranges[qtj][plj].nranges&& memcmp(qranges->sizes,_qinfo->qi_ranges[qtj][plj].sizes, qranges->nranges*sizeof(qranges->sizes[0]))==0&& memcmp(indices[qti][pli],indices[qtj][plj], (qranges->nranges+1)*sizeof(indices[qti][pli][0]))==0){ oggpackB_write(_opb,0,1+(qti>0)); continue; } oggpackB_write(_opb,1,1); } oggpackB_write(_opb,indices[qti][pli][0],nbits); for(qi=qri=0;qi<63;qri++){ oggpackB_write(_opb,qranges->sizes[qri]-1,OC_ILOG_32(62-qi)); qi+=qranges->sizes[qri]; oggpackB_write(_opb,indices[qti][pli][qri+1],nbits); } } }