/* * 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; }