1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * Quicktime Animation (RLE) Video Encoder 3cabdff1aSopenharmony_ci * Copyright (C) 2007 Clemens Fruhwirth 4cabdff1aSopenharmony_ci * Copyright (C) 2007 Alexis Ballier 5cabdff1aSopenharmony_ci * 6cabdff1aSopenharmony_ci * This file is based on flashsvenc.c. 7cabdff1aSopenharmony_ci * 8cabdff1aSopenharmony_ci * This file is part of FFmpeg. 9cabdff1aSopenharmony_ci * 10cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or 11cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public 12cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either 13cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version. 14cabdff1aSopenharmony_ci * 15cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful, 16cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 17cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18cabdff1aSopenharmony_ci * Lesser General Public License for more details. 19cabdff1aSopenharmony_ci * 20cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public 21cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software 22cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 23cabdff1aSopenharmony_ci */ 24cabdff1aSopenharmony_ci 25cabdff1aSopenharmony_ci#include "libavutil/imgutils.h" 26cabdff1aSopenharmony_ci#include "avcodec.h" 27cabdff1aSopenharmony_ci#include "bytestream.h" 28cabdff1aSopenharmony_ci#include "codec_internal.h" 29cabdff1aSopenharmony_ci#include "encode.h" 30cabdff1aSopenharmony_ci 31cabdff1aSopenharmony_ci/** Maximum RLE code for bulk copy */ 32cabdff1aSopenharmony_ci#define MAX_RLE_BULK 127 33cabdff1aSopenharmony_ci/** Maximum RLE code for repeat */ 34cabdff1aSopenharmony_ci#define MAX_RLE_REPEAT 128 35cabdff1aSopenharmony_ci/** Maximum RLE code for skip */ 36cabdff1aSopenharmony_ci#define MAX_RLE_SKIP 254 37cabdff1aSopenharmony_ci 38cabdff1aSopenharmony_citypedef struct QtrleEncContext { 39cabdff1aSopenharmony_ci AVCodecContext *avctx; 40cabdff1aSopenharmony_ci int pixel_size; 41cabdff1aSopenharmony_ci AVFrame *previous_frame; 42cabdff1aSopenharmony_ci unsigned int max_buf_size; 43cabdff1aSopenharmony_ci int logical_width; 44cabdff1aSopenharmony_ci /** 45cabdff1aSopenharmony_ci * This array will contain at ith position the value of the best RLE code 46cabdff1aSopenharmony_ci * if the line started at pixel i 47cabdff1aSopenharmony_ci * There can be 3 values : 48cabdff1aSopenharmony_ci * skip (0) : skip as much as possible pixels because they are equal to the 49cabdff1aSopenharmony_ci * previous frame ones 50cabdff1aSopenharmony_ci * repeat (<-1) : repeat that pixel -rle_code times, still as much as 51cabdff1aSopenharmony_ci * possible 52cabdff1aSopenharmony_ci * copy (>0) : copy the raw next rle_code pixels */ 53cabdff1aSopenharmony_ci signed char *rlecode_table; 54cabdff1aSopenharmony_ci /** 55cabdff1aSopenharmony_ci * This array will contain the length of the best rle encoding of the line 56cabdff1aSopenharmony_ci * starting at ith pixel */ 57cabdff1aSopenharmony_ci int *length_table; 58cabdff1aSopenharmony_ci /** 59cabdff1aSopenharmony_ci * Will contain at ith position the number of consecutive pixels equal to the previous 60cabdff1aSopenharmony_ci * frame starting from pixel i */ 61cabdff1aSopenharmony_ci uint8_t* skip_table; 62cabdff1aSopenharmony_ci 63cabdff1aSopenharmony_ci /** Encoded frame is a key frame */ 64cabdff1aSopenharmony_ci int key_frame; 65cabdff1aSopenharmony_ci} QtrleEncContext; 66cabdff1aSopenharmony_ci 67cabdff1aSopenharmony_cistatic av_cold int qtrle_encode_end(AVCodecContext *avctx) 68cabdff1aSopenharmony_ci{ 69cabdff1aSopenharmony_ci QtrleEncContext *s = avctx->priv_data; 70cabdff1aSopenharmony_ci 71cabdff1aSopenharmony_ci av_frame_free(&s->previous_frame); 72cabdff1aSopenharmony_ci av_free(s->rlecode_table); 73cabdff1aSopenharmony_ci av_free(s->length_table); 74cabdff1aSopenharmony_ci av_free(s->skip_table); 75cabdff1aSopenharmony_ci return 0; 76cabdff1aSopenharmony_ci} 77cabdff1aSopenharmony_ci 78cabdff1aSopenharmony_cistatic av_cold int qtrle_encode_init(AVCodecContext *avctx) 79cabdff1aSopenharmony_ci{ 80cabdff1aSopenharmony_ci QtrleEncContext *s = avctx->priv_data; 81cabdff1aSopenharmony_ci 82cabdff1aSopenharmony_ci if (av_image_check_size(avctx->width, avctx->height, 0, avctx) < 0) { 83cabdff1aSopenharmony_ci return AVERROR(EINVAL); 84cabdff1aSopenharmony_ci } 85cabdff1aSopenharmony_ci s->avctx=avctx; 86cabdff1aSopenharmony_ci s->logical_width=avctx->width; 87cabdff1aSopenharmony_ci 88cabdff1aSopenharmony_ci switch (avctx->pix_fmt) { 89cabdff1aSopenharmony_ci case AV_PIX_FMT_GRAY8: 90cabdff1aSopenharmony_ci if (avctx->width % 4) { 91cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Width not being a multiple of 4 is not supported\n"); 92cabdff1aSopenharmony_ci return AVERROR(EINVAL); 93cabdff1aSopenharmony_ci } 94cabdff1aSopenharmony_ci s->logical_width = avctx->width / 4; 95cabdff1aSopenharmony_ci s->pixel_size = 4; 96cabdff1aSopenharmony_ci break; 97cabdff1aSopenharmony_ci case AV_PIX_FMT_RGB555BE: 98cabdff1aSopenharmony_ci s->pixel_size = 2; 99cabdff1aSopenharmony_ci break; 100cabdff1aSopenharmony_ci case AV_PIX_FMT_RGB24: 101cabdff1aSopenharmony_ci s->pixel_size = 3; 102cabdff1aSopenharmony_ci break; 103cabdff1aSopenharmony_ci case AV_PIX_FMT_ARGB: 104cabdff1aSopenharmony_ci s->pixel_size = 4; 105cabdff1aSopenharmony_ci break; 106cabdff1aSopenharmony_ci default: 107cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Unsupported colorspace.\n"); 108cabdff1aSopenharmony_ci break; 109cabdff1aSopenharmony_ci } 110cabdff1aSopenharmony_ci avctx->bits_per_coded_sample = avctx->pix_fmt == AV_PIX_FMT_GRAY8 ? 40 : s->pixel_size*8; 111cabdff1aSopenharmony_ci 112cabdff1aSopenharmony_ci s->rlecode_table = av_mallocz(s->logical_width); 113cabdff1aSopenharmony_ci s->skip_table = av_mallocz(s->logical_width); 114cabdff1aSopenharmony_ci s->length_table = av_calloc(s->logical_width + 1, sizeof(*s->length_table)); 115cabdff1aSopenharmony_ci if (!s->skip_table || !s->length_table || !s->rlecode_table) { 116cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Error allocating memory.\n"); 117cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 118cabdff1aSopenharmony_ci } 119cabdff1aSopenharmony_ci s->previous_frame = av_frame_alloc(); 120cabdff1aSopenharmony_ci if (!s->previous_frame) { 121cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Error allocating picture\n"); 122cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 123cabdff1aSopenharmony_ci } 124cabdff1aSopenharmony_ci 125cabdff1aSopenharmony_ci s->max_buf_size = s->logical_width*s->avctx->height*s->pixel_size*2 /* image base material */ 126cabdff1aSopenharmony_ci + 15 /* header + footer */ 127cabdff1aSopenharmony_ci + s->avctx->height*2 /* skip code+rle end */ 128cabdff1aSopenharmony_ci + s->logical_width/MAX_RLE_BULK + 1 /* rle codes */; 129cabdff1aSopenharmony_ci 130cabdff1aSopenharmony_ci return 0; 131cabdff1aSopenharmony_ci} 132cabdff1aSopenharmony_ci 133cabdff1aSopenharmony_ci/** 134cabdff1aSopenharmony_ci * Compute the best RLE sequence for a line 135cabdff1aSopenharmony_ci */ 136cabdff1aSopenharmony_cistatic void qtrle_encode_line(QtrleEncContext *s, const AVFrame *p, int line, uint8_t **buf) 137cabdff1aSopenharmony_ci{ 138cabdff1aSopenharmony_ci int width=s->logical_width; 139cabdff1aSopenharmony_ci int i; 140cabdff1aSopenharmony_ci signed char rlecode; 141cabdff1aSopenharmony_ci 142cabdff1aSopenharmony_ci /* This will be the number of pixels equal to the previous frame one's 143cabdff1aSopenharmony_ci * starting from the ith pixel */ 144cabdff1aSopenharmony_ci unsigned int skipcount; 145cabdff1aSopenharmony_ci /* This will be the number of consecutive equal pixels in the current 146cabdff1aSopenharmony_ci * frame, starting from the ith one also */ 147cabdff1aSopenharmony_ci unsigned int av_uninit(repeatcount); 148cabdff1aSopenharmony_ci 149cabdff1aSopenharmony_ci /* The cost of the three different possibilities */ 150cabdff1aSopenharmony_ci int total_skip_cost; 151cabdff1aSopenharmony_ci int total_repeat_cost; 152cabdff1aSopenharmony_ci 153cabdff1aSopenharmony_ci int base_bulk_cost; 154cabdff1aSopenharmony_ci int lowest_bulk_cost; 155cabdff1aSopenharmony_ci int lowest_bulk_cost_index; 156cabdff1aSopenharmony_ci int sec_lowest_bulk_cost; 157cabdff1aSopenharmony_ci int sec_lowest_bulk_cost_index; 158cabdff1aSopenharmony_ci 159cabdff1aSopenharmony_ci const uint8_t *this_line = p->data[0] + line * p->linesize[0] + width * s->pixel_size; 160cabdff1aSopenharmony_ci /* There might be no earlier frame if the current frame is a keyframe. 161cabdff1aSopenharmony_ci * So just use a pointer to the current frame to avoid a check 162cabdff1aSopenharmony_ci * to avoid NULL - s->pixel_size (which is undefined behaviour). */ 163cabdff1aSopenharmony_ci const uint8_t *prev_line = s->key_frame ? this_line 164cabdff1aSopenharmony_ci : s->previous_frame->data[0] 165cabdff1aSopenharmony_ci + line * s->previous_frame->linesize[0] 166cabdff1aSopenharmony_ci + width * s->pixel_size; 167cabdff1aSopenharmony_ci 168cabdff1aSopenharmony_ci s->length_table[width] = 0; 169cabdff1aSopenharmony_ci skipcount = 0; 170cabdff1aSopenharmony_ci 171cabdff1aSopenharmony_ci /* Initial values */ 172cabdff1aSopenharmony_ci lowest_bulk_cost = INT_MAX / 2; 173cabdff1aSopenharmony_ci lowest_bulk_cost_index = width; 174cabdff1aSopenharmony_ci sec_lowest_bulk_cost = INT_MAX / 2; 175cabdff1aSopenharmony_ci sec_lowest_bulk_cost_index = width; 176cabdff1aSopenharmony_ci 177cabdff1aSopenharmony_ci base_bulk_cost = 1 + s->pixel_size; 178cabdff1aSopenharmony_ci 179cabdff1aSopenharmony_ci for (i = width - 1; i >= 0; i--) { 180cabdff1aSopenharmony_ci 181cabdff1aSopenharmony_ci int prev_bulk_cost; 182cabdff1aSopenharmony_ci 183cabdff1aSopenharmony_ci this_line -= s->pixel_size; 184cabdff1aSopenharmony_ci prev_line -= s->pixel_size; 185cabdff1aSopenharmony_ci 186cabdff1aSopenharmony_ci /* If our lowest bulk cost index is too far away, replace it 187cabdff1aSopenharmony_ci * with the next lowest bulk cost */ 188cabdff1aSopenharmony_ci if (FFMIN(width, i + MAX_RLE_BULK) < lowest_bulk_cost_index) { 189cabdff1aSopenharmony_ci lowest_bulk_cost = sec_lowest_bulk_cost; 190cabdff1aSopenharmony_ci lowest_bulk_cost_index = sec_lowest_bulk_cost_index; 191cabdff1aSopenharmony_ci 192cabdff1aSopenharmony_ci sec_lowest_bulk_cost = INT_MAX / 2; 193cabdff1aSopenharmony_ci sec_lowest_bulk_cost_index = width; 194cabdff1aSopenharmony_ci } 195cabdff1aSopenharmony_ci 196cabdff1aSopenharmony_ci /* Deal with the first pixel's bulk cost */ 197cabdff1aSopenharmony_ci if (!i) { 198cabdff1aSopenharmony_ci base_bulk_cost++; 199cabdff1aSopenharmony_ci lowest_bulk_cost++; 200cabdff1aSopenharmony_ci sec_lowest_bulk_cost++; 201cabdff1aSopenharmony_ci } 202cabdff1aSopenharmony_ci 203cabdff1aSopenharmony_ci /* Look at the bulk cost of the previous loop and see if it is 204cabdff1aSopenharmony_ci * a new lower bulk cost */ 205cabdff1aSopenharmony_ci prev_bulk_cost = s->length_table[i + 1] + base_bulk_cost; 206cabdff1aSopenharmony_ci if (prev_bulk_cost <= sec_lowest_bulk_cost) { 207cabdff1aSopenharmony_ci /* If it's lower than the 2nd lowest, then it may be lower 208cabdff1aSopenharmony_ci * than the lowest */ 209cabdff1aSopenharmony_ci if (prev_bulk_cost <= lowest_bulk_cost) { 210cabdff1aSopenharmony_ci 211cabdff1aSopenharmony_ci /* If we have found a new lowest bulk cost, 212cabdff1aSopenharmony_ci * then the 2nd lowest bulk cost is now farther than the 213cabdff1aSopenharmony_ci * lowest bulk cost, and will never be used */ 214cabdff1aSopenharmony_ci sec_lowest_bulk_cost = INT_MAX / 2; 215cabdff1aSopenharmony_ci 216cabdff1aSopenharmony_ci lowest_bulk_cost = prev_bulk_cost; 217cabdff1aSopenharmony_ci lowest_bulk_cost_index = i + 1; 218cabdff1aSopenharmony_ci } else { 219cabdff1aSopenharmony_ci /* Then it must be the 2nd lowest bulk cost */ 220cabdff1aSopenharmony_ci sec_lowest_bulk_cost = prev_bulk_cost; 221cabdff1aSopenharmony_ci sec_lowest_bulk_cost_index = i + 1; 222cabdff1aSopenharmony_ci } 223cabdff1aSopenharmony_ci } 224cabdff1aSopenharmony_ci 225cabdff1aSopenharmony_ci if (!s->key_frame && !memcmp(this_line, prev_line, s->pixel_size)) 226cabdff1aSopenharmony_ci skipcount = FFMIN(skipcount + 1, MAX_RLE_SKIP); 227cabdff1aSopenharmony_ci else 228cabdff1aSopenharmony_ci skipcount = 0; 229cabdff1aSopenharmony_ci 230cabdff1aSopenharmony_ci total_skip_cost = s->length_table[i + skipcount] + 2; 231cabdff1aSopenharmony_ci s->skip_table[i] = skipcount; 232cabdff1aSopenharmony_ci 233cabdff1aSopenharmony_ci 234cabdff1aSopenharmony_ci if (i < width - 1 && !memcmp(this_line, this_line + s->pixel_size, s->pixel_size)) 235cabdff1aSopenharmony_ci repeatcount = FFMIN(repeatcount + 1, MAX_RLE_REPEAT); 236cabdff1aSopenharmony_ci else 237cabdff1aSopenharmony_ci repeatcount = 1; 238cabdff1aSopenharmony_ci 239cabdff1aSopenharmony_ci total_repeat_cost = s->length_table[i + repeatcount] + 1 + s->pixel_size; 240cabdff1aSopenharmony_ci 241cabdff1aSopenharmony_ci /* skip code is free for the first pixel, it costs one byte for repeat and bulk copy 242cabdff1aSopenharmony_ci * so let's make it aware */ 243cabdff1aSopenharmony_ci if (i == 0) { 244cabdff1aSopenharmony_ci total_skip_cost--; 245cabdff1aSopenharmony_ci total_repeat_cost++; 246cabdff1aSopenharmony_ci } 247cabdff1aSopenharmony_ci 248cabdff1aSopenharmony_ci if (repeatcount > 1 && (skipcount == 0 || total_repeat_cost < total_skip_cost)) { 249cabdff1aSopenharmony_ci /* repeat is the best */ 250cabdff1aSopenharmony_ci s->length_table[i] = total_repeat_cost; 251cabdff1aSopenharmony_ci s->rlecode_table[i] = -repeatcount; 252cabdff1aSopenharmony_ci } 253cabdff1aSopenharmony_ci else if (skipcount > 0) { 254cabdff1aSopenharmony_ci /* skip is the best choice here */ 255cabdff1aSopenharmony_ci s->length_table[i] = total_skip_cost; 256cabdff1aSopenharmony_ci s->rlecode_table[i] = 0; 257cabdff1aSopenharmony_ci } 258cabdff1aSopenharmony_ci else { 259cabdff1aSopenharmony_ci /* We cannot do neither skip nor repeat 260cabdff1aSopenharmony_ci * thus we use the best bulk copy */ 261cabdff1aSopenharmony_ci 262cabdff1aSopenharmony_ci s->length_table[i] = lowest_bulk_cost; 263cabdff1aSopenharmony_ci s->rlecode_table[i] = lowest_bulk_cost_index - i; 264cabdff1aSopenharmony_ci 265cabdff1aSopenharmony_ci } 266cabdff1aSopenharmony_ci 267cabdff1aSopenharmony_ci /* These bulk costs increase every iteration */ 268cabdff1aSopenharmony_ci lowest_bulk_cost += s->pixel_size; 269cabdff1aSopenharmony_ci sec_lowest_bulk_cost += s->pixel_size; 270cabdff1aSopenharmony_ci } 271cabdff1aSopenharmony_ci 272cabdff1aSopenharmony_ci /* Good! Now we have the best sequence for this line, let's output it. */ 273cabdff1aSopenharmony_ci 274cabdff1aSopenharmony_ci /* We do a special case for the first pixel so that we avoid testing it in 275cabdff1aSopenharmony_ci * the whole loop */ 276cabdff1aSopenharmony_ci 277cabdff1aSopenharmony_ci i=0; 278cabdff1aSopenharmony_ci this_line = p-> data[0] + line*p->linesize[0]; 279cabdff1aSopenharmony_ci 280cabdff1aSopenharmony_ci if (s->rlecode_table[0] == 0) { 281cabdff1aSopenharmony_ci bytestream_put_byte(buf, s->skip_table[0] + 1); 282cabdff1aSopenharmony_ci i += s->skip_table[0]; 283cabdff1aSopenharmony_ci } 284cabdff1aSopenharmony_ci else bytestream_put_byte(buf, 1); 285cabdff1aSopenharmony_ci 286cabdff1aSopenharmony_ci 287cabdff1aSopenharmony_ci while (i < width) { 288cabdff1aSopenharmony_ci rlecode = s->rlecode_table[i]; 289cabdff1aSopenharmony_ci bytestream_put_byte(buf, rlecode); 290cabdff1aSopenharmony_ci if (rlecode == 0) { 291cabdff1aSopenharmony_ci /* Write a skip sequence */ 292cabdff1aSopenharmony_ci bytestream_put_byte(buf, s->skip_table[i] + 1); 293cabdff1aSopenharmony_ci i += s->skip_table[i]; 294cabdff1aSopenharmony_ci } 295cabdff1aSopenharmony_ci else if (rlecode > 0) { 296cabdff1aSopenharmony_ci /* bulk copy */ 297cabdff1aSopenharmony_ci if (s->avctx->pix_fmt == AV_PIX_FMT_GRAY8) { 298cabdff1aSopenharmony_ci int j; 299cabdff1aSopenharmony_ci // QT grayscale colorspace has 0=white and 255=black, we will 300cabdff1aSopenharmony_ci // ignore the palette that is included in the AVFrame because 301cabdff1aSopenharmony_ci // AV_PIX_FMT_GRAY8 has defined color mapping 302cabdff1aSopenharmony_ci for (j = 0; j < rlecode*s->pixel_size; ++j) 303cabdff1aSopenharmony_ci bytestream_put_byte(buf, *(this_line + i*s->pixel_size + j) ^ 0xff); 304cabdff1aSopenharmony_ci } else { 305cabdff1aSopenharmony_ci bytestream_put_buffer(buf, this_line + i*s->pixel_size, rlecode*s->pixel_size); 306cabdff1aSopenharmony_ci } 307cabdff1aSopenharmony_ci i += rlecode; 308cabdff1aSopenharmony_ci } 309cabdff1aSopenharmony_ci else { 310cabdff1aSopenharmony_ci /* repeat the bits */ 311cabdff1aSopenharmony_ci if (s->avctx->pix_fmt == AV_PIX_FMT_GRAY8) { 312cabdff1aSopenharmony_ci int j; 313cabdff1aSopenharmony_ci // QT grayscale colorspace has 0=white and 255=black, ... 314cabdff1aSopenharmony_ci for (j = 0; j < s->pixel_size; ++j) 315cabdff1aSopenharmony_ci bytestream_put_byte(buf, *(this_line + i*s->pixel_size + j) ^ 0xff); 316cabdff1aSopenharmony_ci } else { 317cabdff1aSopenharmony_ci bytestream_put_buffer(buf, this_line + i*s->pixel_size, s->pixel_size); 318cabdff1aSopenharmony_ci } 319cabdff1aSopenharmony_ci i -= rlecode; 320cabdff1aSopenharmony_ci } 321cabdff1aSopenharmony_ci } 322cabdff1aSopenharmony_ci bytestream_put_byte(buf, -1); // end RLE line 323cabdff1aSopenharmony_ci} 324cabdff1aSopenharmony_ci 325cabdff1aSopenharmony_ci/** Encode frame including header */ 326cabdff1aSopenharmony_cistatic int encode_frame(QtrleEncContext *s, const AVFrame *p, uint8_t *buf) 327cabdff1aSopenharmony_ci{ 328cabdff1aSopenharmony_ci int i; 329cabdff1aSopenharmony_ci int start_line = 0; 330cabdff1aSopenharmony_ci int end_line = s->avctx->height; 331cabdff1aSopenharmony_ci uint8_t *orig_buf = buf; 332cabdff1aSopenharmony_ci 333cabdff1aSopenharmony_ci if (!s->key_frame) { 334cabdff1aSopenharmony_ci unsigned line_size = s->logical_width * s->pixel_size; 335cabdff1aSopenharmony_ci for (start_line = 0; start_line < s->avctx->height; start_line++) 336cabdff1aSopenharmony_ci if (memcmp(p->data[0] + start_line*p->linesize[0], 337cabdff1aSopenharmony_ci s->previous_frame->data[0] + start_line * s->previous_frame->linesize[0], 338cabdff1aSopenharmony_ci line_size)) 339cabdff1aSopenharmony_ci break; 340cabdff1aSopenharmony_ci 341cabdff1aSopenharmony_ci for (end_line=s->avctx->height; end_line > start_line; end_line--) 342cabdff1aSopenharmony_ci if (memcmp(p->data[0] + (end_line - 1)*p->linesize[0], 343cabdff1aSopenharmony_ci s->previous_frame->data[0] + (end_line - 1) * s->previous_frame->linesize[0], 344cabdff1aSopenharmony_ci line_size)) 345cabdff1aSopenharmony_ci break; 346cabdff1aSopenharmony_ci } 347cabdff1aSopenharmony_ci 348cabdff1aSopenharmony_ci bytestream_put_be32(&buf, 0); // CHUNK SIZE, patched later 349cabdff1aSopenharmony_ci 350cabdff1aSopenharmony_ci if ((start_line == 0 && end_line == s->avctx->height) || start_line == s->avctx->height) 351cabdff1aSopenharmony_ci bytestream_put_be16(&buf, 0); // header 352cabdff1aSopenharmony_ci else { 353cabdff1aSopenharmony_ci bytestream_put_be16(&buf, 8); // header 354cabdff1aSopenharmony_ci bytestream_put_be16(&buf, start_line); // starting line 355cabdff1aSopenharmony_ci bytestream_put_be16(&buf, 0); // unknown 356cabdff1aSopenharmony_ci bytestream_put_be16(&buf, end_line - start_line); // lines to update 357cabdff1aSopenharmony_ci bytestream_put_be16(&buf, 0); // unknown 358cabdff1aSopenharmony_ci } 359cabdff1aSopenharmony_ci for (i = start_line; i < end_line; i++) 360cabdff1aSopenharmony_ci qtrle_encode_line(s, p, i, &buf); 361cabdff1aSopenharmony_ci 362cabdff1aSopenharmony_ci bytestream_put_byte(&buf, 0); // zero skip code = frame finished 363cabdff1aSopenharmony_ci AV_WB32(orig_buf, buf - orig_buf); // patch the chunk size 364cabdff1aSopenharmony_ci return buf - orig_buf; 365cabdff1aSopenharmony_ci} 366cabdff1aSopenharmony_ci 367cabdff1aSopenharmony_cistatic int qtrle_encode_frame(AVCodecContext *avctx, AVPacket *pkt, 368cabdff1aSopenharmony_ci const AVFrame *pict, int *got_packet) 369cabdff1aSopenharmony_ci{ 370cabdff1aSopenharmony_ci QtrleEncContext * const s = avctx->priv_data; 371cabdff1aSopenharmony_ci int ret; 372cabdff1aSopenharmony_ci 373cabdff1aSopenharmony_ci if ((ret = ff_alloc_packet(avctx, pkt, s->max_buf_size)) < 0) 374cabdff1aSopenharmony_ci return ret; 375cabdff1aSopenharmony_ci 376cabdff1aSopenharmony_ci if (avctx->gop_size == 0 || !s->previous_frame->data[0] || 377cabdff1aSopenharmony_ci (s->avctx->frame_number % avctx->gop_size) == 0) { 378cabdff1aSopenharmony_ci /* I-Frame */ 379cabdff1aSopenharmony_ci s->key_frame = 1; 380cabdff1aSopenharmony_ci } else { 381cabdff1aSopenharmony_ci /* P-Frame */ 382cabdff1aSopenharmony_ci s->key_frame = 0; 383cabdff1aSopenharmony_ci } 384cabdff1aSopenharmony_ci 385cabdff1aSopenharmony_ci pkt->size = encode_frame(s, pict, pkt->data); 386cabdff1aSopenharmony_ci 387cabdff1aSopenharmony_ci /* save the current frame */ 388cabdff1aSopenharmony_ci av_frame_unref(s->previous_frame); 389cabdff1aSopenharmony_ci ret = av_frame_ref(s->previous_frame, pict); 390cabdff1aSopenharmony_ci if (ret < 0) { 391cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "cannot add reference\n"); 392cabdff1aSopenharmony_ci return ret; 393cabdff1aSopenharmony_ci } 394cabdff1aSopenharmony_ci 395cabdff1aSopenharmony_ci if (s->key_frame) 396cabdff1aSopenharmony_ci pkt->flags |= AV_PKT_FLAG_KEY; 397cabdff1aSopenharmony_ci *got_packet = 1; 398cabdff1aSopenharmony_ci 399cabdff1aSopenharmony_ci return 0; 400cabdff1aSopenharmony_ci} 401cabdff1aSopenharmony_ci 402cabdff1aSopenharmony_ciconst FFCodec ff_qtrle_encoder = { 403cabdff1aSopenharmony_ci .p.name = "qtrle", 404cabdff1aSopenharmony_ci .p.long_name = NULL_IF_CONFIG_SMALL("QuickTime Animation (RLE) video"), 405cabdff1aSopenharmony_ci .p.type = AVMEDIA_TYPE_VIDEO, 406cabdff1aSopenharmony_ci .p.id = AV_CODEC_ID_QTRLE, 407cabdff1aSopenharmony_ci .priv_data_size = sizeof(QtrleEncContext), 408cabdff1aSopenharmony_ci .init = qtrle_encode_init, 409cabdff1aSopenharmony_ci FF_CODEC_ENCODE_CB(qtrle_encode_frame), 410cabdff1aSopenharmony_ci .close = qtrle_encode_end, 411cabdff1aSopenharmony_ci .p.pix_fmts = (const enum AVPixelFormat[]){ 412cabdff1aSopenharmony_ci AV_PIX_FMT_RGB24, AV_PIX_FMT_RGB555BE, AV_PIX_FMT_ARGB, AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE 413cabdff1aSopenharmony_ci }, 414cabdff1aSopenharmony_ci .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, 415cabdff1aSopenharmony_ci}; 416