1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * a64 video encoder - multicolor modes 3cabdff1aSopenharmony_ci * Copyright (c) 2009 Tobias Bindhammer 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 * a64 video encoder - multicolor modes 25cabdff1aSopenharmony_ci */ 26cabdff1aSopenharmony_ci 27cabdff1aSopenharmony_ci#include "config_components.h" 28cabdff1aSopenharmony_ci 29cabdff1aSopenharmony_ci#include "a64colors.h" 30cabdff1aSopenharmony_ci#include "a64tables.h" 31cabdff1aSopenharmony_ci#include "codec_internal.h" 32cabdff1aSopenharmony_ci#include "elbg.h" 33cabdff1aSopenharmony_ci#include "encode.h" 34cabdff1aSopenharmony_ci#include "libavutil/avassert.h" 35cabdff1aSopenharmony_ci#include "libavutil/common.h" 36cabdff1aSopenharmony_ci#include "libavutil/intreadwrite.h" 37cabdff1aSopenharmony_ci 38cabdff1aSopenharmony_ci#define DITHERSTEPS 8 39cabdff1aSopenharmony_ci#define CHARSET_CHARS 256 40cabdff1aSopenharmony_ci#define INTERLACED 1 41cabdff1aSopenharmony_ci#define CROP_SCREENS 1 42cabdff1aSopenharmony_ci 43cabdff1aSopenharmony_ci#define C64XRES 320 44cabdff1aSopenharmony_ci#define C64YRES 200 45cabdff1aSopenharmony_ci 46cabdff1aSopenharmony_citypedef struct A64Context { 47cabdff1aSopenharmony_ci /* variables for multicolor modes */ 48cabdff1aSopenharmony_ci struct ELBGContext *elbg; 49cabdff1aSopenharmony_ci AVLFG randctx; 50cabdff1aSopenharmony_ci int mc_lifetime; 51cabdff1aSopenharmony_ci int mc_use_5col; 52cabdff1aSopenharmony_ci unsigned mc_frame_counter; 53cabdff1aSopenharmony_ci int *mc_meta_charset; 54cabdff1aSopenharmony_ci int *mc_charmap; 55cabdff1aSopenharmony_ci int *mc_best_cb; 56cabdff1aSopenharmony_ci int mc_luma_vals[5]; 57cabdff1aSopenharmony_ci uint8_t *mc_colram; 58cabdff1aSopenharmony_ci uint8_t *mc_palette; 59cabdff1aSopenharmony_ci int mc_pal_size; 60cabdff1aSopenharmony_ci 61cabdff1aSopenharmony_ci /* pts of the next packet that will be output */ 62cabdff1aSopenharmony_ci int64_t next_pts; 63cabdff1aSopenharmony_ci} A64Context; 64cabdff1aSopenharmony_ci 65cabdff1aSopenharmony_ci/* gray gradient */ 66cabdff1aSopenharmony_cistatic const uint8_t mc_colors[5]={0x0,0xb,0xc,0xf,0x1}; 67cabdff1aSopenharmony_ci 68cabdff1aSopenharmony_ci/* other possible gradients - to be tested */ 69cabdff1aSopenharmony_ci//static const uint8_t mc_colors[5]={0x0,0x8,0xa,0xf,0x7}; 70cabdff1aSopenharmony_ci//static const uint8_t mc_colors[5]={0x0,0x9,0x8,0xa,0x3}; 71cabdff1aSopenharmony_ci 72cabdff1aSopenharmony_cistatic void to_meta_with_crop(AVCodecContext *avctx, 73cabdff1aSopenharmony_ci const AVFrame *p, int *dest) 74cabdff1aSopenharmony_ci{ 75cabdff1aSopenharmony_ci int blockx, blocky, x, y; 76cabdff1aSopenharmony_ci int luma = 0; 77cabdff1aSopenharmony_ci int height = FFMIN(avctx->height, C64YRES); 78cabdff1aSopenharmony_ci int width = FFMIN(avctx->width , C64XRES); 79cabdff1aSopenharmony_ci uint8_t *src = p->data[0]; 80cabdff1aSopenharmony_ci 81cabdff1aSopenharmony_ci for (blocky = 0; blocky < C64YRES; blocky += 8) { 82cabdff1aSopenharmony_ci for (blockx = 0; blockx < C64XRES; blockx += 8) { 83cabdff1aSopenharmony_ci for (y = blocky; y < blocky + 8 && y < C64YRES; y++) { 84cabdff1aSopenharmony_ci for (x = blockx; x < blockx + 8 && x < C64XRES; x += 2) { 85cabdff1aSopenharmony_ci if(x < width && y < height) { 86cabdff1aSopenharmony_ci if (x + 1 < width) { 87cabdff1aSopenharmony_ci /* build average over 2 pixels */ 88cabdff1aSopenharmony_ci luma = (src[(x + 0 + y * p->linesize[0])] + 89cabdff1aSopenharmony_ci src[(x + 1 + y * p->linesize[0])]) / 2; 90cabdff1aSopenharmony_ci } else { 91cabdff1aSopenharmony_ci luma = src[(x + y * p->linesize[0])]; 92cabdff1aSopenharmony_ci } 93cabdff1aSopenharmony_ci /* write blocks as linear data now so they are suitable for elbg */ 94cabdff1aSopenharmony_ci dest[0] = luma; 95cabdff1aSopenharmony_ci } 96cabdff1aSopenharmony_ci dest++; 97cabdff1aSopenharmony_ci } 98cabdff1aSopenharmony_ci } 99cabdff1aSopenharmony_ci } 100cabdff1aSopenharmony_ci } 101cabdff1aSopenharmony_ci} 102cabdff1aSopenharmony_ci 103cabdff1aSopenharmony_cistatic void render_charset(AVCodecContext *avctx, uint8_t *charset, 104cabdff1aSopenharmony_ci uint8_t *colrammap) 105cabdff1aSopenharmony_ci{ 106cabdff1aSopenharmony_ci A64Context *c = avctx->priv_data; 107cabdff1aSopenharmony_ci uint8_t row1, row2; 108cabdff1aSopenharmony_ci int charpos, x, y; 109cabdff1aSopenharmony_ci int a, b; 110cabdff1aSopenharmony_ci uint8_t pix; 111cabdff1aSopenharmony_ci int lowdiff, highdiff; 112cabdff1aSopenharmony_ci int *best_cb = c->mc_best_cb; 113cabdff1aSopenharmony_ci uint8_t index1[256]; 114cabdff1aSopenharmony_ci uint8_t index2[256]; 115cabdff1aSopenharmony_ci uint8_t dither[256]; 116cabdff1aSopenharmony_ci int i; 117cabdff1aSopenharmony_ci int distance; 118cabdff1aSopenharmony_ci 119cabdff1aSopenharmony_ci /* Generate lookup-tables for dither and index before looping. 120cabdff1aSopenharmony_ci * This code relies on c->mc_luma_vals[c->mc_pal_size - 1] being 121cabdff1aSopenharmony_ci * the maximum of all the mc_luma_vals values and on the minimum 122cabdff1aSopenharmony_ci * being zero; this ensures that dither is properly initialized. */ 123cabdff1aSopenharmony_ci i = 0; 124cabdff1aSopenharmony_ci for (a=0; a < 256; a++) { 125cabdff1aSopenharmony_ci if(i < c->mc_pal_size -1 && a == c->mc_luma_vals[i + 1]) { 126cabdff1aSopenharmony_ci distance = c->mc_luma_vals[i + 1] - c->mc_luma_vals[i]; 127cabdff1aSopenharmony_ci for(b = 0; b <= distance; b++) { 128cabdff1aSopenharmony_ci dither[c->mc_luma_vals[i] + b] = b * (DITHERSTEPS - 1) / distance; 129cabdff1aSopenharmony_ci } 130cabdff1aSopenharmony_ci i++; 131cabdff1aSopenharmony_ci } 132cabdff1aSopenharmony_ci if(i >= c->mc_pal_size - 1) dither[a] = 0; 133cabdff1aSopenharmony_ci index1[a] = i; 134cabdff1aSopenharmony_ci index2[a] = FFMIN(i + 1, c->mc_pal_size - 1); 135cabdff1aSopenharmony_ci } 136cabdff1aSopenharmony_ci 137cabdff1aSopenharmony_ci /* and render charset */ 138cabdff1aSopenharmony_ci for (charpos = 0; charpos < CHARSET_CHARS; charpos++) { 139cabdff1aSopenharmony_ci lowdiff = 0; 140cabdff1aSopenharmony_ci highdiff = 0; 141cabdff1aSopenharmony_ci for (y = 0; y < 8; y++) { 142cabdff1aSopenharmony_ci row1 = 0; row2 = 0; 143cabdff1aSopenharmony_ci for (x = 0; x < 4; x++) { 144cabdff1aSopenharmony_ci pix = best_cb[y * 4 + x]; 145cabdff1aSopenharmony_ci 146cabdff1aSopenharmony_ci /* accumulate error for brightest/darkest color */ 147cabdff1aSopenharmony_ci if (index1[pix] >= 3) 148cabdff1aSopenharmony_ci highdiff += pix - c->mc_luma_vals[3]; 149cabdff1aSopenharmony_ci if (index1[pix] < 1) 150cabdff1aSopenharmony_ci lowdiff += c->mc_luma_vals[1] - pix; 151cabdff1aSopenharmony_ci 152cabdff1aSopenharmony_ci row1 <<= 2; 153cabdff1aSopenharmony_ci 154cabdff1aSopenharmony_ci if (INTERLACED) { 155cabdff1aSopenharmony_ci row2 <<= 2; 156cabdff1aSopenharmony_ci if (interlaced_dither_patterns[dither[pix]][(y & 3) * 2 + 0][x & 3]) 157cabdff1aSopenharmony_ci row1 |= 3-(index2[pix] & 3); 158cabdff1aSopenharmony_ci else 159cabdff1aSopenharmony_ci row1 |= 3-(index1[pix] & 3); 160cabdff1aSopenharmony_ci 161cabdff1aSopenharmony_ci if (interlaced_dither_patterns[dither[pix]][(y & 3) * 2 + 1][x & 3]) 162cabdff1aSopenharmony_ci row2 |= 3-(index2[pix] & 3); 163cabdff1aSopenharmony_ci else 164cabdff1aSopenharmony_ci row2 |= 3-(index1[pix] & 3); 165cabdff1aSopenharmony_ci } 166cabdff1aSopenharmony_ci else { 167cabdff1aSopenharmony_ci if (multi_dither_patterns[dither[pix]][(y & 3)][x & 3]) 168cabdff1aSopenharmony_ci row1 |= 3-(index2[pix] & 3); 169cabdff1aSopenharmony_ci else 170cabdff1aSopenharmony_ci row1 |= 3-(index1[pix] & 3); 171cabdff1aSopenharmony_ci } 172cabdff1aSopenharmony_ci } 173cabdff1aSopenharmony_ci charset[y+0x000] = row1; 174cabdff1aSopenharmony_ci if (INTERLACED) charset[y+0x800] = row2; 175cabdff1aSopenharmony_ci } 176cabdff1aSopenharmony_ci /* do we need to adjust pixels? */ 177cabdff1aSopenharmony_ci if (highdiff > 0 && lowdiff > 0 && c->mc_use_5col) { 178cabdff1aSopenharmony_ci if (lowdiff > highdiff) { 179cabdff1aSopenharmony_ci for (x = 0; x < 32; x++) 180cabdff1aSopenharmony_ci best_cb[x] = FFMIN(c->mc_luma_vals[3], best_cb[x]); 181cabdff1aSopenharmony_ci } else { 182cabdff1aSopenharmony_ci for (x = 0; x < 32; x++) 183cabdff1aSopenharmony_ci best_cb[x] = FFMAX(c->mc_luma_vals[1], best_cb[x]); 184cabdff1aSopenharmony_ci } 185cabdff1aSopenharmony_ci charpos--; /* redo now adjusted char */ 186cabdff1aSopenharmony_ci /* no adjustment needed, all fine */ 187cabdff1aSopenharmony_ci } else { 188cabdff1aSopenharmony_ci /* advance pointers */ 189cabdff1aSopenharmony_ci best_cb += 32; 190cabdff1aSopenharmony_ci charset += 8; 191cabdff1aSopenharmony_ci 192cabdff1aSopenharmony_ci /* remember colorram value */ 193cabdff1aSopenharmony_ci colrammap[charpos] = (highdiff > 0); 194cabdff1aSopenharmony_ci } 195cabdff1aSopenharmony_ci } 196cabdff1aSopenharmony_ci} 197cabdff1aSopenharmony_ci 198cabdff1aSopenharmony_cistatic av_cold int a64multi_close_encoder(AVCodecContext *avctx) 199cabdff1aSopenharmony_ci{ 200cabdff1aSopenharmony_ci A64Context *c = avctx->priv_data; 201cabdff1aSopenharmony_ci 202cabdff1aSopenharmony_ci avpriv_elbg_free(&c->elbg); 203cabdff1aSopenharmony_ci 204cabdff1aSopenharmony_ci av_freep(&c->mc_meta_charset); 205cabdff1aSopenharmony_ci av_freep(&c->mc_best_cb); 206cabdff1aSopenharmony_ci av_freep(&c->mc_charmap); 207cabdff1aSopenharmony_ci av_freep(&c->mc_colram); 208cabdff1aSopenharmony_ci return 0; 209cabdff1aSopenharmony_ci} 210cabdff1aSopenharmony_ci 211cabdff1aSopenharmony_cistatic av_cold int a64multi_encode_init(AVCodecContext *avctx) 212cabdff1aSopenharmony_ci{ 213cabdff1aSopenharmony_ci A64Context *c = avctx->priv_data; 214cabdff1aSopenharmony_ci int a; 215cabdff1aSopenharmony_ci av_lfg_init(&c->randctx, 1); 216cabdff1aSopenharmony_ci 217cabdff1aSopenharmony_ci if (avctx->global_quality < 1) { 218cabdff1aSopenharmony_ci c->mc_lifetime = 4; 219cabdff1aSopenharmony_ci } else { 220cabdff1aSopenharmony_ci c->mc_lifetime = avctx->global_quality / FF_QP2LAMBDA; 221cabdff1aSopenharmony_ci } 222cabdff1aSopenharmony_ci 223cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_INFO, "charset lifetime set to %d frame(s)\n", c->mc_lifetime); 224cabdff1aSopenharmony_ci 225cabdff1aSopenharmony_ci c->mc_frame_counter = 0; 226cabdff1aSopenharmony_ci c->mc_use_5col = avctx->codec->id == AV_CODEC_ID_A64_MULTI5; 227cabdff1aSopenharmony_ci c->mc_pal_size = 4 + c->mc_use_5col; 228cabdff1aSopenharmony_ci 229cabdff1aSopenharmony_ci /* precalc luma values for later use */ 230cabdff1aSopenharmony_ci for (a = 0; a < c->mc_pal_size; a++) { 231cabdff1aSopenharmony_ci c->mc_luma_vals[a]=a64_palette[mc_colors[a]][0] * 0.30 + 232cabdff1aSopenharmony_ci a64_palette[mc_colors[a]][1] * 0.59 + 233cabdff1aSopenharmony_ci a64_palette[mc_colors[a]][2] * 0.11; 234cabdff1aSopenharmony_ci } 235cabdff1aSopenharmony_ci 236cabdff1aSopenharmony_ci if (!(c->mc_meta_charset = av_calloc(c->mc_lifetime, 32000 * sizeof(int))) || 237cabdff1aSopenharmony_ci !(c->mc_best_cb = av_malloc(CHARSET_CHARS * 32 * sizeof(int))) || 238cabdff1aSopenharmony_ci !(c->mc_charmap = av_calloc(c->mc_lifetime, 1000 * sizeof(int))) || 239cabdff1aSopenharmony_ci !(c->mc_colram = av_mallocz(CHARSET_CHARS * sizeof(uint8_t)))) { 240cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Failed to allocate buffer memory.\n"); 241cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 242cabdff1aSopenharmony_ci } 243cabdff1aSopenharmony_ci 244cabdff1aSopenharmony_ci /* set up extradata */ 245cabdff1aSopenharmony_ci if (!(avctx->extradata = av_mallocz(8 * 4 + AV_INPUT_BUFFER_PADDING_SIZE))) { 246cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Failed to allocate memory for extradata.\n"); 247cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 248cabdff1aSopenharmony_ci } 249cabdff1aSopenharmony_ci avctx->extradata_size = 8 * 4; 250cabdff1aSopenharmony_ci AV_WB32(avctx->extradata, c->mc_lifetime); 251cabdff1aSopenharmony_ci AV_WB32(avctx->extradata + 16, INTERLACED); 252cabdff1aSopenharmony_ci 253cabdff1aSopenharmony_ci if (!avctx->codec_tag) 254cabdff1aSopenharmony_ci avctx->codec_tag = AV_RL32("a64m"); 255cabdff1aSopenharmony_ci 256cabdff1aSopenharmony_ci c->next_pts = AV_NOPTS_VALUE; 257cabdff1aSopenharmony_ci 258cabdff1aSopenharmony_ci return 0; 259cabdff1aSopenharmony_ci} 260cabdff1aSopenharmony_ci 261cabdff1aSopenharmony_cistatic void a64_compress_colram(unsigned char *buf, int *charmap, uint8_t *colram) 262cabdff1aSopenharmony_ci{ 263cabdff1aSopenharmony_ci int a; 264cabdff1aSopenharmony_ci uint8_t temp; 265cabdff1aSopenharmony_ci /* only needs to be done in 5col mode */ 266cabdff1aSopenharmony_ci /* XXX could be squeezed to 0x80 bytes */ 267cabdff1aSopenharmony_ci for (a = 0; a < 256; a++) { 268cabdff1aSopenharmony_ci temp = colram[charmap[a + 0x000]] << 0; 269cabdff1aSopenharmony_ci temp |= colram[charmap[a + 0x100]] << 1; 270cabdff1aSopenharmony_ci temp |= colram[charmap[a + 0x200]] << 2; 271cabdff1aSopenharmony_ci if (a < 0xe8) temp |= colram[charmap[a + 0x300]] << 3; 272cabdff1aSopenharmony_ci buf[a] = temp << 2; 273cabdff1aSopenharmony_ci } 274cabdff1aSopenharmony_ci} 275cabdff1aSopenharmony_ci 276cabdff1aSopenharmony_cistatic int a64multi_encode_frame(AVCodecContext *avctx, AVPacket *pkt, 277cabdff1aSopenharmony_ci const AVFrame *p, int *got_packet) 278cabdff1aSopenharmony_ci{ 279cabdff1aSopenharmony_ci A64Context *c = avctx->priv_data; 280cabdff1aSopenharmony_ci 281cabdff1aSopenharmony_ci int frame; 282cabdff1aSopenharmony_ci int x, y; 283cabdff1aSopenharmony_ci int b_height; 284cabdff1aSopenharmony_ci int b_width; 285cabdff1aSopenharmony_ci 286cabdff1aSopenharmony_ci int req_size, ret; 287cabdff1aSopenharmony_ci uint8_t *buf = NULL; 288cabdff1aSopenharmony_ci 289cabdff1aSopenharmony_ci int *charmap = c->mc_charmap; 290cabdff1aSopenharmony_ci uint8_t *colram = c->mc_colram; 291cabdff1aSopenharmony_ci int *meta = c->mc_meta_charset; 292cabdff1aSopenharmony_ci int *best_cb = c->mc_best_cb; 293cabdff1aSopenharmony_ci 294cabdff1aSopenharmony_ci int charset_size = 0x800 * (INTERLACED + 1); 295cabdff1aSopenharmony_ci int colram_size = 0x100 * c->mc_use_5col; 296cabdff1aSopenharmony_ci int screen_size; 297cabdff1aSopenharmony_ci 298cabdff1aSopenharmony_ci if(CROP_SCREENS) { 299cabdff1aSopenharmony_ci b_height = FFMIN(avctx->height,C64YRES) >> 3; 300cabdff1aSopenharmony_ci b_width = FFMIN(avctx->width ,C64XRES) >> 3; 301cabdff1aSopenharmony_ci screen_size = b_width * b_height; 302cabdff1aSopenharmony_ci } else { 303cabdff1aSopenharmony_ci b_height = C64YRES >> 3; 304cabdff1aSopenharmony_ci b_width = C64XRES >> 3; 305cabdff1aSopenharmony_ci screen_size = 0x400; 306cabdff1aSopenharmony_ci } 307cabdff1aSopenharmony_ci 308cabdff1aSopenharmony_ci /* no data, means end encoding asap */ 309cabdff1aSopenharmony_ci if (!p) { 310cabdff1aSopenharmony_ci /* all done, end encoding */ 311cabdff1aSopenharmony_ci if (!c->mc_lifetime) return 0; 312cabdff1aSopenharmony_ci /* no more frames in queue, prepare to flush remaining frames */ 313cabdff1aSopenharmony_ci if (!c->mc_frame_counter) { 314cabdff1aSopenharmony_ci c->mc_lifetime = 0; 315cabdff1aSopenharmony_ci } 316cabdff1aSopenharmony_ci /* still frames in queue so limit lifetime to remaining frames */ 317cabdff1aSopenharmony_ci else c->mc_lifetime = c->mc_frame_counter; 318cabdff1aSopenharmony_ci /* still new data available */ 319cabdff1aSopenharmony_ci } else { 320cabdff1aSopenharmony_ci /* fill up mc_meta_charset with data until lifetime exceeds */ 321cabdff1aSopenharmony_ci if (c->mc_frame_counter < c->mc_lifetime) { 322cabdff1aSopenharmony_ci to_meta_with_crop(avctx, p, meta + 32000 * c->mc_frame_counter); 323cabdff1aSopenharmony_ci c->mc_frame_counter++; 324cabdff1aSopenharmony_ci if (c->next_pts == AV_NOPTS_VALUE) 325cabdff1aSopenharmony_ci c->next_pts = p->pts; 326cabdff1aSopenharmony_ci /* lifetime is not reached so wait for next frame first */ 327cabdff1aSopenharmony_ci return 0; 328cabdff1aSopenharmony_ci } 329cabdff1aSopenharmony_ci } 330cabdff1aSopenharmony_ci 331cabdff1aSopenharmony_ci /* lifetime reached so now convert X frames at once */ 332cabdff1aSopenharmony_ci if (c->mc_frame_counter == c->mc_lifetime) { 333cabdff1aSopenharmony_ci req_size = 0; 334cabdff1aSopenharmony_ci /* any frames to encode? */ 335cabdff1aSopenharmony_ci if (c->mc_lifetime) { 336cabdff1aSopenharmony_ci int alloc_size = charset_size + c->mc_lifetime*(screen_size + colram_size); 337cabdff1aSopenharmony_ci if ((ret = ff_get_encode_buffer(avctx, pkt, alloc_size, 0)) < 0) 338cabdff1aSopenharmony_ci return ret; 339cabdff1aSopenharmony_ci buf = pkt->data; 340cabdff1aSopenharmony_ci 341cabdff1aSopenharmony_ci /* calc optimal new charset + charmaps */ 342cabdff1aSopenharmony_ci ret = avpriv_elbg_do(&c->elbg, meta, 32, 1000 * c->mc_lifetime, 343cabdff1aSopenharmony_ci best_cb, CHARSET_CHARS, 50, charmap, &c->randctx, 0); 344cabdff1aSopenharmony_ci if (ret < 0) 345cabdff1aSopenharmony_ci return ret; 346cabdff1aSopenharmony_ci 347cabdff1aSopenharmony_ci /* create colorram map and a c64 readable charset */ 348cabdff1aSopenharmony_ci render_charset(avctx, buf, colram); 349cabdff1aSopenharmony_ci 350cabdff1aSopenharmony_ci /* advance pointers */ 351cabdff1aSopenharmony_ci buf += charset_size; 352cabdff1aSopenharmony_ci req_size += charset_size; 353cabdff1aSopenharmony_ci } 354cabdff1aSopenharmony_ci 355cabdff1aSopenharmony_ci /* write x frames to buf */ 356cabdff1aSopenharmony_ci for (frame = 0; frame < c->mc_lifetime; frame++) { 357cabdff1aSopenharmony_ci /* copy charmap to buf. buf is uchar*, charmap is int*, so no memcpy here, sorry */ 358cabdff1aSopenharmony_ci for (y = 0; y < b_height; y++) { 359cabdff1aSopenharmony_ci for (x = 0; x < b_width; x++) { 360cabdff1aSopenharmony_ci buf[y * b_width + x] = charmap[y * b_width + x]; 361cabdff1aSopenharmony_ci } 362cabdff1aSopenharmony_ci } 363cabdff1aSopenharmony_ci /* advance pointers */ 364cabdff1aSopenharmony_ci buf += screen_size; 365cabdff1aSopenharmony_ci req_size += screen_size; 366cabdff1aSopenharmony_ci 367cabdff1aSopenharmony_ci /* compress and copy colram to buf */ 368cabdff1aSopenharmony_ci if (c->mc_use_5col) { 369cabdff1aSopenharmony_ci a64_compress_colram(buf, charmap, colram); 370cabdff1aSopenharmony_ci /* advance pointers */ 371cabdff1aSopenharmony_ci buf += colram_size; 372cabdff1aSopenharmony_ci req_size += colram_size; 373cabdff1aSopenharmony_ci } 374cabdff1aSopenharmony_ci 375cabdff1aSopenharmony_ci /* advance to next charmap */ 376cabdff1aSopenharmony_ci charmap += 1000; 377cabdff1aSopenharmony_ci } 378cabdff1aSopenharmony_ci 379cabdff1aSopenharmony_ci AV_WB32(avctx->extradata + 4, c->mc_frame_counter); 380cabdff1aSopenharmony_ci AV_WB32(avctx->extradata + 8, charset_size); 381cabdff1aSopenharmony_ci AV_WB32(avctx->extradata + 12, screen_size + colram_size); 382cabdff1aSopenharmony_ci 383cabdff1aSopenharmony_ci /* reset counter */ 384cabdff1aSopenharmony_ci c->mc_frame_counter = 0; 385cabdff1aSopenharmony_ci 386cabdff1aSopenharmony_ci pkt->pts = pkt->dts = c->next_pts; 387cabdff1aSopenharmony_ci c->next_pts = AV_NOPTS_VALUE; 388cabdff1aSopenharmony_ci 389cabdff1aSopenharmony_ci av_assert0(pkt->size == req_size); 390cabdff1aSopenharmony_ci *got_packet = !!req_size; 391cabdff1aSopenharmony_ci } 392cabdff1aSopenharmony_ci return 0; 393cabdff1aSopenharmony_ci} 394cabdff1aSopenharmony_ci 395cabdff1aSopenharmony_ci#if CONFIG_A64MULTI_ENCODER 396cabdff1aSopenharmony_ciconst FFCodec ff_a64multi_encoder = { 397cabdff1aSopenharmony_ci .p.name = "a64multi", 398cabdff1aSopenharmony_ci .p.long_name = NULL_IF_CONFIG_SMALL("Multicolor charset for Commodore 64"), 399cabdff1aSopenharmony_ci .p.type = AVMEDIA_TYPE_VIDEO, 400cabdff1aSopenharmony_ci .p.id = AV_CODEC_ID_A64_MULTI, 401cabdff1aSopenharmony_ci .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY, 402cabdff1aSopenharmony_ci .priv_data_size = sizeof(A64Context), 403cabdff1aSopenharmony_ci .init = a64multi_encode_init, 404cabdff1aSopenharmony_ci FF_CODEC_ENCODE_CB(a64multi_encode_frame), 405cabdff1aSopenharmony_ci .close = a64multi_close_encoder, 406cabdff1aSopenharmony_ci .p.pix_fmts = (const enum AVPixelFormat[]) {AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE}, 407cabdff1aSopenharmony_ci .caps_internal = FF_CODEC_CAP_INIT_CLEANUP | FF_CODEC_CAP_INIT_THREADSAFE, 408cabdff1aSopenharmony_ci}; 409cabdff1aSopenharmony_ci#endif 410cabdff1aSopenharmony_ci#if CONFIG_A64MULTI5_ENCODER 411cabdff1aSopenharmony_ciconst FFCodec ff_a64multi5_encoder = { 412cabdff1aSopenharmony_ci .p.name = "a64multi5", 413cabdff1aSopenharmony_ci .p.long_name = NULL_IF_CONFIG_SMALL("Multicolor charset for Commodore 64, extended with 5th color (colram)"), 414cabdff1aSopenharmony_ci .p.type = AVMEDIA_TYPE_VIDEO, 415cabdff1aSopenharmony_ci .p.id = AV_CODEC_ID_A64_MULTI5, 416cabdff1aSopenharmony_ci .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY, 417cabdff1aSopenharmony_ci .priv_data_size = sizeof(A64Context), 418cabdff1aSopenharmony_ci .init = a64multi_encode_init, 419cabdff1aSopenharmony_ci FF_CODEC_ENCODE_CB(a64multi_encode_frame), 420cabdff1aSopenharmony_ci .close = a64multi_close_encoder, 421cabdff1aSopenharmony_ci .p.pix_fmts = (const enum AVPixelFormat[]) {AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE}, 422cabdff1aSopenharmony_ci .caps_internal = FF_CODEC_CAP_INIT_CLEANUP | FF_CODEC_CAP_INIT_THREADSAFE, 423cabdff1aSopenharmony_ci}; 424cabdff1aSopenharmony_ci#endif 425