1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * Copyright (c) 1990 James Ashton - Sydney University 3cabdff1aSopenharmony_ci * Copyright (c) 2012 Stefano Sabatini 4cabdff1aSopenharmony_ci * 5cabdff1aSopenharmony_ci * This file is part of FFmpeg. 6cabdff1aSopenharmony_ci * 7cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or 8cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public 9cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either 10cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version. 11cabdff1aSopenharmony_ci * 12cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful, 13cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 14cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15cabdff1aSopenharmony_ci * Lesser General Public License for more details. 16cabdff1aSopenharmony_ci * 17cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public 18cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software 19cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20cabdff1aSopenharmony_ci */ 21cabdff1aSopenharmony_ci 22cabdff1aSopenharmony_ci/** 23cabdff1aSopenharmony_ci * @file 24cabdff1aSopenharmony_ci * X-Face decoder, based on libcompface, by James Ashton. 25cabdff1aSopenharmony_ci */ 26cabdff1aSopenharmony_ci 27cabdff1aSopenharmony_ci#include "libavutil/pixdesc.h" 28cabdff1aSopenharmony_ci#include "avcodec.h" 29cabdff1aSopenharmony_ci#include "bytestream.h" 30cabdff1aSopenharmony_ci#include "codec_internal.h" 31cabdff1aSopenharmony_ci#include "internal.h" 32cabdff1aSopenharmony_ci#include "xface.h" 33cabdff1aSopenharmony_ci 34cabdff1aSopenharmony_cistatic int pop_integer(BigInt *b, const ProbRange *pranges) 35cabdff1aSopenharmony_ci{ 36cabdff1aSopenharmony_ci uint8_t r; 37cabdff1aSopenharmony_ci int i; 38cabdff1aSopenharmony_ci 39cabdff1aSopenharmony_ci /* extract the last byte into r, and shift right b by 8 bits */ 40cabdff1aSopenharmony_ci ff_big_div(b, 0, &r); 41cabdff1aSopenharmony_ci 42cabdff1aSopenharmony_ci i = 0; 43cabdff1aSopenharmony_ci while (r < pranges->offset || r >= pranges->range + pranges->offset) { 44cabdff1aSopenharmony_ci pranges++; 45cabdff1aSopenharmony_ci i++; 46cabdff1aSopenharmony_ci } 47cabdff1aSopenharmony_ci ff_big_mul(b, pranges->range); 48cabdff1aSopenharmony_ci ff_big_add(b, r - pranges->offset); 49cabdff1aSopenharmony_ci return i; 50cabdff1aSopenharmony_ci} 51cabdff1aSopenharmony_ci 52cabdff1aSopenharmony_cistatic void pop_greys(BigInt *b, char *bitmap, int w, int h) 53cabdff1aSopenharmony_ci{ 54cabdff1aSopenharmony_ci if (w > 3) { 55cabdff1aSopenharmony_ci w /= 2; 56cabdff1aSopenharmony_ci h /= 2; 57cabdff1aSopenharmony_ci pop_greys(b, bitmap, w, h); 58cabdff1aSopenharmony_ci pop_greys(b, bitmap + w, w, h); 59cabdff1aSopenharmony_ci pop_greys(b, bitmap + XFACE_WIDTH * h, w, h); 60cabdff1aSopenharmony_ci pop_greys(b, bitmap + XFACE_WIDTH * h + w, w, h); 61cabdff1aSopenharmony_ci } else { 62cabdff1aSopenharmony_ci w = pop_integer(b, ff_xface_probranges_2x2); 63cabdff1aSopenharmony_ci if (w & 1) bitmap[0] = 1; 64cabdff1aSopenharmony_ci if (w & 2) bitmap[1] = 1; 65cabdff1aSopenharmony_ci if (w & 4) bitmap[XFACE_WIDTH] = 1; 66cabdff1aSopenharmony_ci if (w & 8) bitmap[XFACE_WIDTH + 1] = 1; 67cabdff1aSopenharmony_ci } 68cabdff1aSopenharmony_ci} 69cabdff1aSopenharmony_ci 70cabdff1aSopenharmony_cistatic void decode_block(BigInt *b, char *bitmap, int w, int h, int level) 71cabdff1aSopenharmony_ci{ 72cabdff1aSopenharmony_ci switch (pop_integer(b, &ff_xface_probranges_per_level[level][0])) { 73cabdff1aSopenharmony_ci case XFACE_COLOR_WHITE: 74cabdff1aSopenharmony_ci return; 75cabdff1aSopenharmony_ci case XFACE_COLOR_BLACK: 76cabdff1aSopenharmony_ci pop_greys(b, bitmap, w, h); 77cabdff1aSopenharmony_ci return; 78cabdff1aSopenharmony_ci default: 79cabdff1aSopenharmony_ci w /= 2; 80cabdff1aSopenharmony_ci h /= 2; 81cabdff1aSopenharmony_ci level++; 82cabdff1aSopenharmony_ci decode_block(b, bitmap, w, h, level); 83cabdff1aSopenharmony_ci decode_block(b, bitmap + w, w, h, level); 84cabdff1aSopenharmony_ci decode_block(b, bitmap + h * XFACE_WIDTH, w, h, level); 85cabdff1aSopenharmony_ci decode_block(b, bitmap + w + h * XFACE_WIDTH, w, h, level); 86cabdff1aSopenharmony_ci return; 87cabdff1aSopenharmony_ci } 88cabdff1aSopenharmony_ci} 89cabdff1aSopenharmony_ci 90cabdff1aSopenharmony_citypedef struct XFaceContext { 91cabdff1aSopenharmony_ci uint8_t bitmap[XFACE_PIXELS]; ///< image used internally for decoding 92cabdff1aSopenharmony_ci} XFaceContext; 93cabdff1aSopenharmony_ci 94cabdff1aSopenharmony_cistatic av_cold int xface_decode_init(AVCodecContext *avctx) 95cabdff1aSopenharmony_ci{ 96cabdff1aSopenharmony_ci if (avctx->width || avctx->height) { 97cabdff1aSopenharmony_ci if (avctx->width != XFACE_WIDTH || avctx->height != XFACE_HEIGHT) { 98cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, 99cabdff1aSopenharmony_ci "Size value %dx%d not supported, only accepts a size of %dx%d\n", 100cabdff1aSopenharmony_ci avctx->width, avctx->height, XFACE_WIDTH, XFACE_HEIGHT); 101cabdff1aSopenharmony_ci return AVERROR(EINVAL); 102cabdff1aSopenharmony_ci } 103cabdff1aSopenharmony_ci } 104cabdff1aSopenharmony_ci 105cabdff1aSopenharmony_ci avctx->width = XFACE_WIDTH; 106cabdff1aSopenharmony_ci avctx->height = XFACE_HEIGHT; 107cabdff1aSopenharmony_ci avctx->pix_fmt = AV_PIX_FMT_MONOWHITE; 108cabdff1aSopenharmony_ci 109cabdff1aSopenharmony_ci return 0; 110cabdff1aSopenharmony_ci} 111cabdff1aSopenharmony_ci 112cabdff1aSopenharmony_cistatic int xface_decode_frame(AVCodecContext *avctx, AVFrame *frame, 113cabdff1aSopenharmony_ci int *got_frame, AVPacket *avpkt) 114cabdff1aSopenharmony_ci{ 115cabdff1aSopenharmony_ci XFaceContext *xface = avctx->priv_data; 116cabdff1aSopenharmony_ci int ret, i, j, k; 117cabdff1aSopenharmony_ci uint8_t byte; 118cabdff1aSopenharmony_ci BigInt b = {0}; 119cabdff1aSopenharmony_ci char *buf; 120cabdff1aSopenharmony_ci int64_t c; 121cabdff1aSopenharmony_ci 122cabdff1aSopenharmony_ci if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) 123cabdff1aSopenharmony_ci return ret; 124cabdff1aSopenharmony_ci 125cabdff1aSopenharmony_ci for (i = 0, k = 0; i < avpkt->size && avpkt->data[i]; i++) { 126cabdff1aSopenharmony_ci c = avpkt->data[i]; 127cabdff1aSopenharmony_ci 128cabdff1aSopenharmony_ci /* ignore invalid digits */ 129cabdff1aSopenharmony_ci if (c < XFACE_FIRST_PRINT || c > XFACE_LAST_PRINT) 130cabdff1aSopenharmony_ci continue; 131cabdff1aSopenharmony_ci 132cabdff1aSopenharmony_ci if (++k > XFACE_MAX_DIGITS) { 133cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_WARNING, 134cabdff1aSopenharmony_ci "Buffer is longer than expected, truncating at byte %d\n", i); 135cabdff1aSopenharmony_ci break; 136cabdff1aSopenharmony_ci } 137cabdff1aSopenharmony_ci ff_big_mul(&b, XFACE_PRINTS); 138cabdff1aSopenharmony_ci ff_big_add(&b, c - XFACE_FIRST_PRINT); 139cabdff1aSopenharmony_ci } 140cabdff1aSopenharmony_ci 141cabdff1aSopenharmony_ci /* decode image and put it in bitmap */ 142cabdff1aSopenharmony_ci memset(xface->bitmap, 0, XFACE_PIXELS); 143cabdff1aSopenharmony_ci buf = xface->bitmap; 144cabdff1aSopenharmony_ci decode_block(&b, buf, 16, 16, 0); 145cabdff1aSopenharmony_ci decode_block(&b, buf + 16, 16, 16, 0); 146cabdff1aSopenharmony_ci decode_block(&b, buf + 32, 16, 16, 0); 147cabdff1aSopenharmony_ci decode_block(&b, buf + XFACE_WIDTH * 16, 16, 16, 0); 148cabdff1aSopenharmony_ci decode_block(&b, buf + XFACE_WIDTH * 16 + 16, 16, 16, 0); 149cabdff1aSopenharmony_ci decode_block(&b, buf + XFACE_WIDTH * 16 + 32, 16, 16, 0); 150cabdff1aSopenharmony_ci decode_block(&b, buf + XFACE_WIDTH * 32 , 16, 16, 0); 151cabdff1aSopenharmony_ci decode_block(&b, buf + XFACE_WIDTH * 32 + 16, 16, 16, 0); 152cabdff1aSopenharmony_ci decode_block(&b, buf + XFACE_WIDTH * 32 + 32, 16, 16, 0); 153cabdff1aSopenharmony_ci 154cabdff1aSopenharmony_ci ff_xface_generate_face(xface->bitmap, xface->bitmap); 155cabdff1aSopenharmony_ci 156cabdff1aSopenharmony_ci /* convert image from 1=black 0=white bitmap to MONOWHITE */ 157cabdff1aSopenharmony_ci buf = frame->data[0]; 158cabdff1aSopenharmony_ci for (i = 0, j = 0, k = 0, byte = 0; i < XFACE_PIXELS; i++) { 159cabdff1aSopenharmony_ci byte += xface->bitmap[i]; 160cabdff1aSopenharmony_ci if (k == 7) { 161cabdff1aSopenharmony_ci buf[j++] = byte; 162cabdff1aSopenharmony_ci byte = k = 0; 163cabdff1aSopenharmony_ci } else { 164cabdff1aSopenharmony_ci k++; 165cabdff1aSopenharmony_ci byte <<= 1; 166cabdff1aSopenharmony_ci } 167cabdff1aSopenharmony_ci if (j == XFACE_WIDTH/8) { 168cabdff1aSopenharmony_ci j = 0; 169cabdff1aSopenharmony_ci buf += frame->linesize[0]; 170cabdff1aSopenharmony_ci } 171cabdff1aSopenharmony_ci } 172cabdff1aSopenharmony_ci 173cabdff1aSopenharmony_ci *got_frame = 1; 174cabdff1aSopenharmony_ci 175cabdff1aSopenharmony_ci return avpkt->size; 176cabdff1aSopenharmony_ci} 177cabdff1aSopenharmony_ci 178cabdff1aSopenharmony_ciconst FFCodec ff_xface_decoder = { 179cabdff1aSopenharmony_ci .p.name = "xface", 180cabdff1aSopenharmony_ci .p.long_name = NULL_IF_CONFIG_SMALL("X-face image"), 181cabdff1aSopenharmony_ci .p.type = AVMEDIA_TYPE_VIDEO, 182cabdff1aSopenharmony_ci .p.id = AV_CODEC_ID_XFACE, 183cabdff1aSopenharmony_ci .p.capabilities = AV_CODEC_CAP_DR1, 184cabdff1aSopenharmony_ci .priv_data_size = sizeof(XFaceContext), 185cabdff1aSopenharmony_ci .init = xface_decode_init, 186cabdff1aSopenharmony_ci FF_CODEC_DECODE_CB(xface_decode_frame), 187cabdff1aSopenharmony_ci .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_MONOWHITE, AV_PIX_FMT_NONE }, 188cabdff1aSopenharmony_ci .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, 189cabdff1aSopenharmony_ci}; 190