Exemple #1
0
        /**
         * decodes a residual block.
         * @param n block index
         * @param scantable scantable
         * @param max_coeff number of coefficients in the block
         * @return <0 if an error occurred
         */
        public static int decode_residual(H264Context h, GetBitContext gb, short[] block_base, int block_offset
            , int n, byte[] scantable_base, int scantable_offset, long[] qmul_base, int qmul_offset, int max_coeff)
        {
            //			, int n, uint8_t *scantable, uint32_t *qmul, int max_coeff){
            //MpegEncContext s = h.s;
            int[/*17*/] coeff_token_table_index = { 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3 };
            int[] level = new int[16];
            int zeros_left, coeff_token, total_coeff, i, trailing_ones, run_before;

            //FIXME put trailing_onex into the context

            if (n >= H264Context.CHROMA_DC_BLOCK_INDEX)
            {
                coeff_token = gb.get_vlc2(
                        chroma_dc_coeff_token_vlc.table_base, chroma_dc_coeff_token_vlc.table_offset,
                        H264Context.CHROMA_DC_COEFF_TOKEN_VLC_BITS, 1, "coeff_token_CROMA_DC");
                total_coeff = coeff_token >> 2;
                //Console.WriteLine("get_vlc2(CHROMA_DC_COEFF_TOKEN) => total_coeff = " + total_coeff );
            }
            else
            {
                if (n == H264Context.LUMA_DC_BLOCK_INDEX)
                {
                    total_coeff = pred_non_zero_count(h, 0);
                    //Console.WriteLine("Prediected Non-Zero count = "+total_coeff);
                    coeff_token = gb.get_vlc2(
                            coeff_token_vlc[coeff_token_table_index[total_coeff]].table_base,
                            coeff_token_vlc[coeff_token_table_index[total_coeff]].table_offset,
                            H264Context.COEFF_TOKEN_VLC_BITS, 2, "coeff_token_LUMA_DC");
                    total_coeff = coeff_token >> 2;
                    //Console.WriteLine("get_vlc2(LUMA_DC_COEFF_TOKEN) => total_coeff = " + total_coeff );
                }
                else
                {
                    total_coeff = pred_non_zero_count(h, n);

                    // DebugTool.printDebugString("predicted non_zero_count("+n+") = "+total_coeff+"\n");

                    coeff_token = gb.get_vlc2(
                            coeff_token_vlc[coeff_token_table_index[total_coeff]].table_base,
                            coeff_token_vlc[coeff_token_table_index[total_coeff]].table_offset,
                            H264Context.COEFF_TOKEN_VLC_BITS, 2, "coeff_token_LUMA(2)_DC");
                    total_coeff = coeff_token >> 2;

                    // DebugTool.printDebugString("predicted non_zero_count-2 = "+total_coeff+"\n");

                }
            }
            h.non_zero_count_cache[H264Context.scan8[n]] = total_coeff;

            //FIXME set last_non_zero?

            if (total_coeff == 0)
                return 0;
            if (total_coeff > /*(unsigned)*/max_coeff)
            {
                //	        av_log(h.s.avctx, AV_LOG_ERROR, "corrupted macroblock %d %d (total_coeff=%d)\n", s.mb_x, s.mb_y, total_coeff);
                // DebugTool.printDebugString("  --------  Error type 1.0\n");
                return -1;
            }

            trailing_ones = coeff_token & 3;
            //	    tprintf(h.s.avctx, "trailing:%d, total:%d\n", trailing_ones, total_coeff);
            //assert(total_coeff<=16);

            // DebugTool.printDebugString("   - trailing_ones = "+trailing_ones+"\n");

            i = (int)gb.show_bits(3);
            gb.skip_bits(trailing_ones);
            level[0] = 1 - ((i & 4) >> 1);
            level[1] = 1 - ((i & 2));
            level[2] = 1 - ((i & 1) << 1);

            // DebugTool.printDebugString("   - i = "+i+"\n");

            if (trailing_ones < total_coeff)
            {
                int mask, prefix;
                int suffix_length = ((total_coeff > 10) ? 1 : 0) & ((trailing_ones < 3) ? 1 : 0);
                int bitsi = (int)gb.show_bits(LEVEL_TAB_BITS);
                int level_code = cavlc_level_tab[suffix_length][bitsi][0];

                // DebugTool.printDebugString("   - bitsi = "+bitsi+", level_code = "+level_code+", skip_bit = "+cavlc_level_tab[suffix_length][bitsi][1]+"\n");

                gb.skip_bits(cavlc_level_tab[suffix_length][bitsi][1]);
                if (level_code >= 100)
                {
                    prefix = level_code - 100;
                    if (prefix == LEVEL_TAB_BITS)
                        prefix += get_level_prefix(gb);

                    // DebugTool.printDebugString("   - prefix = "+prefix+"\n");

                    //first coefficient has suffix_length equal to 0 or 1
                    if (prefix < 14)
                    { //FIXME try to build a large unified VLC table for all this
                        if (suffix_length != 0)
                            level_code = (int)((prefix << 1) + gb.get_bits1("level_code")); //part
                        else
                            level_code = prefix; //part
                    }
                    else if (prefix == 14)
                    {
                        if (suffix_length != 0)
                            level_code = (int)((prefix << 1) + gb.get_bits1("level_code")); //part
                        else
                            level_code = (int)(prefix + gb.get_bits(4, "level_code")); //part
                    }
                    else
                    {
                        // Nok: Prevent bug?? in ffmpeg that the decoder may overflow?
                        level_code = 30 + (int)(gb.get_bits(prefix - 3, "level_code")); //part
                        if (prefix >= 16)
                        {
                            if (prefix > 25 + 3)
                            {
                                // DebugTool.printDebugString("  --------  Error type 1.1\n");
                                //av_log(h.s.avctx, AV_LOG_ERROR, "Invalid level prefix\n");
                                return -1;
                            }
                            level_code += (1 << (prefix - 3)) - 4096;
                        }
                    }

                    if (trailing_ones < 3) level_code += 2;

                    // DebugTool.printDebugString("   - level_code(1) = "+level_code+"\n");

                    suffix_length = 2;
                    mask = -(level_code & 1);
                    level[trailing_ones] = (((2 + level_code) >> 1) ^ mask) - mask;
                }
                else
                {
                    level_code += ((level_code >> 31) | 1) & -((trailing_ones < 3) ? 1 : 0);

                    // DebugTool.printDebugString("   - level_code(2) = "+level_code+"\n");

                    // Fix: for difference between JAVA and C, we need to convert signed to unsigned when we compare
                    //      signed and unsigned number because, in C, such comparing will be done in common part.
                    //      In which, common part in C in unsigned, while java is signed. -= Nok =-
                    suffix_length = 1 + (((0xffffffffL & (level_code + 3)) > 6) ? 1 : 0);
                    level[trailing_ones] = level_code;
                }

                // DebugTool.printDebugString("   - suffix_length(1) = "+suffix_length+"\n");

                //remaining coefficients have suffix_length > 0
                for (i = trailing_ones + 1; i < total_coeff; i++)
                {
                    int[/*7*/] suffix_limit = { 0, 3, 6, 12, 24, 48, int.MaxValue };
                    bitsi = (int)gb.show_bits(LEVEL_TAB_BITS);
                    level_code = cavlc_level_tab[suffix_length][bitsi][0];

                    // DebugTool.printDebugString("       - cavlc_level_tab["+suffix_length+"]["+bitsi+"][0] = "+level_code+"\n");

                    gb.skip_bits(cavlc_level_tab[suffix_length][bitsi][1]);
                    if (level_code >= 100)
                    {
                        prefix = level_code - 100;
                        if (prefix == LEVEL_TAB_BITS)
                        {
                            prefix += get_level_prefix(gb);
                        }
                        if (prefix < 15)
                        {
                            level_code = (int)((prefix << suffix_length) + gb.get_bits(suffix_length, "level_code"));
                        }
                        else
                        {
                            level_code = (int)((15 << suffix_length) + gb.get_bits(prefix - 3, "level_code"));
                            if (prefix >= 16)
                                level_code += (1 << (prefix - 3)) - 4096;
                        }
                        mask = -(level_code & 1);
                        level_code = (((2 + level_code) >> 1) ^ mask) - mask;
                    }
                    level[i] = level_code;

                    // DebugTool.printDebugString("       - prefix(6) = "+level_code+"\n");

                    // Fix: for difference between JAVA and C, we need to convert signed to unsigned when we compare
                    //      signed and unsigned number because, in C, such comparing will be done in common part.
                    //      In which, common part in C in unsigned, while java is signed. -= Nok =-
                    suffix_length += (((0xffffffffL & (suffix_limit[suffix_length] + level_code)) > (2L * suffix_limit[suffix_length])) ? 1 : 0);
                }

                // DebugTool.printDebugString("   - suffix_length(2) = "+suffix_length+"\n");
            }

            if (total_coeff == max_coeff)
                zeros_left = 0;
            else
            {
                if (n >= H264Context.CHROMA_DC_BLOCK_INDEX)
                {
                    zeros_left = gb.get_vlc2(chroma_dc_total_zeros_vlc[total_coeff - 1].table_base,
                            chroma_dc_total_zeros_vlc[total_coeff - 1].table_offset,
                            H264Context.CHROMA_DC_TOTAL_ZEROS_VLC_BITS, 1, "coeff_token_CROMA_DC_TOTAL_ZERO");
                    // DebugTool.printDebugString("get_vlc2(CHROMA_DC_ZERO_LEFT) => zeros_left = " + zeros_left +"\n");
                }
                else
                {
                    zeros_left = gb.get_vlc2(total_zeros_vlc[total_coeff - 1].table_base,
                            total_zeros_vlc[total_coeff - 1].table_offset,
                            H264Context.TOTAL_ZEROS_VLC_BITS, 1, "coeff_token_TOTAL_ZEROS");
                    // DebugTool.printDebugString("get_vlc2(LUMA_DC_ZERO_LEFT) => zeros_left = " + zeros_left +"\n");
                } // if
            }

            /*
            // DebugTool.printDebugString("scantable_offset(before) = {"
                    +scantable_base[scantable_offset+0]+","
                    +scantable_base[scantable_offset+1]+","
                    +scantable_base[scantable_offset+2]+","
                    +scantable_base[scantable_offset+3]+","
                    +scantable_base[scantable_offset+4]
                    +"}\n");
            */
            scantable_offset += zeros_left + total_coeff - 1;

            /*
            // DebugTool.printDebugString("scantable_offset(after) = {"
                    +scantable_base[scantable_offset+0]+","
                    +scantable_base[scantable_offset+1]+","
                    +scantable_base[scantable_offset+2]+","
                    +scantable_base[scantable_offset+3]+","
                    +scantable_base[scantable_offset+4]
                    +"}\n");
             */

            //!!????????????????????????????????? Magic about array resizing??
            if (scantable_offset < 0)
            {
                byte[] new_scantable_base = new byte[scantable_base.Length + (-scantable_offset)];
                Array.Copy(scantable_base, 0, new_scantable_base, -scantable_offset, scantable_base.Length);
                scantable_base = new_scantable_base;
                scantable_offset = 0;
            }

            if (n >= H264Context.LUMA_DC_BLOCK_INDEX)
            {
                // DebugTool.printDebugString("****RESE-CASE 1\n");

                block_base[block_offset + scantable_base[scantable_offset]] = (short)level[0];
                for (i = 1; i < total_coeff && zeros_left > 0; i++)
                {
                    if (zeros_left < 7)
                    {
                        //????????????????????????????????????????/
                        // run_before= gb.get_vlc2((run_vlc-1)[zeros_left].table, H264Context.RUN_VLC_BITS, 1);
                        run_before = gb.get_vlc2(run_vlc[zeros_left - 1].table_base, run_vlc[zeros_left - 1].table_offset, H264Context.RUN_VLC_BITS, 1, "RUN_VLC");
                        //Console.WriteLine("get_vlc2(LUMA_RUN_VLC) => run_before = " + run_before );
                    }
                    else
                    {
                        run_before = gb.get_vlc2(run7_vlc.table_base, run7_vlc.table_offset, H264Context.RUN7_VLC_BITS, 2, "RUN7_VLC");
                        //Console.WriteLine("get_vlc2(LUMA_RUN_VLC7) => run_before = " + run_before );
                    } // if
                    ////Console.WriteLine("run_before = "+run_before);
                    zeros_left -= run_before;
                    scantable_offset -= 1 + run_before;
                    block_base[block_offset + scantable_base[scantable_offset]] = (short)level[i];
                }
                for (; i < total_coeff; i++)
                {
                    scantable_offset--;
                    block_base[block_offset + scantable_base[scantable_offset]] = (short)level[i];
                }
            }
            else
            {
                // DebugTool.printDebugString("****RESE-CASE 2\n");

                block_base[block_offset + scantable_base[scantable_offset]] = (short)((level[0] * qmul_base[qmul_offset + scantable_base[scantable_offset]] + 32) >> 6);
                for (i = 1; i < total_coeff && zeros_left > 0; i++)
                {
                    if (zeros_left < 7)
                    {
                        run_before = gb.get_vlc2(run_vlc[zeros_left - 1].table_base, run_vlc[zeros_left - 1].table_offset, H264Context.RUN_VLC_BITS, 1, "RUN_VLC");
                        //Console.WriteLine("get_vlc2(CHROMA_RUN_VLC) => run_before = " + run_before );
                    }
                    else
                    {
                        run_before = gb.get_vlc2(run7_vlc.table_base, run7_vlc.table_offset, H264Context.RUN7_VLC_BITS, 2, "RUN7_VLC");
                        //Console.WriteLine("get_vlc2(CHROMA_RUN_VLC7) => run_before = " + run_before );
                    } // if
                    ////Console.WriteLine("run_before = "+run_before);
                    zeros_left -= run_before;
                    scantable_offset -= (1 + run_before);
                    block_base[block_offset + scantable_base[scantable_offset]] = (short)((level[i] * qmul_base[qmul_offset + scantable_base[scantable_offset]] + 32) >> 6);
                }
                for (; i < total_coeff; i++)
                {
                    scantable_offset--;
                    block_base[block_offset + scantable_base[scantable_offset]] = (short)((level[i] * qmul_base[qmul_offset + scantable_base[scantable_offset]] + 32) >> 6);
                }
            }

            if (zeros_left < 0)
            {
                //av_log(h.s.avctx, AV_LOG_ERROR, "negative number of zero coeffs at %d %d\n", s.mb_x, s.mb_y);
                // DebugTool.printDebugString("  --------  Error type 1.2\n");
                return -1;
            }

            return 0;
        }