| /* |
| * MQ-coder encoder |
| * Copyright (c) 2007 Kamil Nowosad |
| * |
| * This file is part of FFmpeg. |
| * |
| * FFmpeg is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * FFmpeg is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with FFmpeg; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
| */ |
| |
| /** |
| * MQ-coder encoder |
| * @file |
| * @author Kamil Nowosad |
| */ |
| |
| #include "libavutil/avassert.h" |
| #include "mqc.h" |
| |
| static void byteout(MqcState *mqc) |
| { |
| retry: |
| if (*mqc->bp == 0xff){ |
| mqc->bp++; |
| *mqc->bp = mqc->c >> 20; |
| mqc->c &= 0xfffff; |
| mqc->ct = 7; |
| } else if ((mqc->c & 0x8000000)){ |
| (*mqc->bp)++; |
| mqc->c &= 0x7ffffff; |
| goto retry; |
| } else{ |
| mqc->bp++; |
| *mqc->bp = mqc->c >> 19; |
| mqc->c &= 0x7ffff; |
| mqc->ct = 8; |
| } |
| } |
| |
| static void renorme(MqcState *mqc) |
| { |
| do{ |
| mqc->a += mqc->a; |
| mqc->c += mqc->c; |
| if (!--mqc->ct) |
| byteout(mqc); |
| } while (!(mqc->a & 0x8000)); |
| } |
| |
| static void setbits(MqcState *mqc) |
| { |
| int tmp = mqc->c + mqc->a; |
| mqc->c |= 0xffff; |
| if (mqc->c >= tmp) |
| mqc->c -= 0x8000; |
| } |
| |
| void ff_mqc_initenc(MqcState *mqc, uint8_t *bp) |
| { |
| ff_mqc_init_contexts(mqc); |
| mqc->a = 0x8000; |
| mqc->c = 0; |
| mqc->bp = bp-1; |
| mqc->bpstart = bp; |
| mqc->ct = 12 + (*mqc->bp == 0xff); |
| } |
| |
| void ff_mqc_encode(MqcState *mqc, uint8_t *cxstate, int d) |
| { |
| int qe; |
| |
| qe = ff_mqc_qe[*cxstate]; |
| mqc->a -= qe; |
| if ((*cxstate & 1) == d){ |
| if (!(mqc->a & 0x8000)){ |
| if (mqc->a < qe) |
| mqc->a = qe; |
| else |
| mqc->c += qe; |
| *cxstate = ff_mqc_nmps[*cxstate]; |
| renorme(mqc); |
| } else |
| mqc->c += qe; |
| } else{ |
| if (mqc->a < qe) |
| mqc->c += qe; |
| else |
| mqc->a = qe; |
| *cxstate = ff_mqc_nlps[*cxstate]; |
| renorme(mqc); |
| } |
| } |
| |
| int ff_mqc_length(MqcState *mqc) |
| { |
| return mqc->bp - mqc->bpstart; |
| } |
| |
| int ff_mqc_flush(MqcState *mqc) |
| { |
| setbits(mqc); |
| mqc->c = mqc->c << mqc->ct; |
| byteout(mqc); |
| mqc->c = mqc->c << mqc->ct; |
| byteout(mqc); |
| if (*mqc->bp != 0xff) |
| mqc->bp++; |
| return mqc->bp - mqc->bpstart; |
| } |
| |
| int ff_mqc_flush_to(MqcState *mqc, uint8_t *dst, int *dst_len) |
| { |
| MqcState mqc2 = *mqc; |
| mqc2.bpstart= |
| mqc2.bp = dst; |
| *mqc2.bp = *mqc->bp; |
| ff_mqc_flush(&mqc2); |
| *dst_len = mqc2.bp - dst; |
| if (mqc->bp < mqc->bpstart) { |
| av_assert1(mqc->bpstart - mqc->bp == 1); |
| av_assert1(*dst_len > 0); |
| av_assert1(mqc->bp[0] == 0 && dst[0] == 0); |
| (*dst_len) --; |
| memmove(dst, dst+1, *dst_len); |
| return mqc->bp - mqc->bpstart + 1 + *dst_len; |
| } |
| return mqc->bp - mqc->bpstart + *dst_len; |
| } |