1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * RV30 decoder 3cabdff1aSopenharmony_ci * Copyright (c) 2007 Konstantin Shishkov 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 * RV30 decoder 25cabdff1aSopenharmony_ci */ 26cabdff1aSopenharmony_ci 27cabdff1aSopenharmony_ci#include "avcodec.h" 28cabdff1aSopenharmony_ci#include "codec_internal.h" 29cabdff1aSopenharmony_ci#include "mpegutils.h" 30cabdff1aSopenharmony_ci#include "mpegvideo.h" 31cabdff1aSopenharmony_ci#include "mpegvideodec.h" 32cabdff1aSopenharmony_ci#include "golomb.h" 33cabdff1aSopenharmony_ci 34cabdff1aSopenharmony_ci#include "rv34.h" 35cabdff1aSopenharmony_ci#include "rv30data.h" 36cabdff1aSopenharmony_ci 37cabdff1aSopenharmony_ci 38cabdff1aSopenharmony_cistatic int rv30_parse_slice_header(RV34DecContext *r, GetBitContext *gb, SliceInfo *si) 39cabdff1aSopenharmony_ci{ 40cabdff1aSopenharmony_ci AVCodecContext *avctx = r->s.avctx; 41cabdff1aSopenharmony_ci int mb_bits; 42cabdff1aSopenharmony_ci int w = r->s.width, h = r->s.height; 43cabdff1aSopenharmony_ci int mb_size; 44cabdff1aSopenharmony_ci int rpr; 45cabdff1aSopenharmony_ci 46cabdff1aSopenharmony_ci memset(si, 0, sizeof(SliceInfo)); 47cabdff1aSopenharmony_ci if(get_bits(gb, 3)) 48cabdff1aSopenharmony_ci return -1; 49cabdff1aSopenharmony_ci si->type = get_bits(gb, 2); 50cabdff1aSopenharmony_ci if(si->type == 1) si->type = 0; 51cabdff1aSopenharmony_ci if(get_bits1(gb)) 52cabdff1aSopenharmony_ci return -1; 53cabdff1aSopenharmony_ci si->quant = get_bits(gb, 5); 54cabdff1aSopenharmony_ci skip_bits1(gb); 55cabdff1aSopenharmony_ci si->pts = get_bits(gb, 13); 56cabdff1aSopenharmony_ci rpr = get_bits(gb, av_log2(r->max_rpr) + 1); 57cabdff1aSopenharmony_ci if(rpr){ 58cabdff1aSopenharmony_ci if (rpr > r->max_rpr) { 59cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "rpr too large\n"); 60cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 61cabdff1aSopenharmony_ci } 62cabdff1aSopenharmony_ci 63cabdff1aSopenharmony_ci if (avctx->extradata_size < rpr * 2 + 8) { 64cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, 65cabdff1aSopenharmony_ci "Insufficient extradata - need at least %d bytes, got %d\n", 66cabdff1aSopenharmony_ci 8 + rpr * 2, avctx->extradata_size); 67cabdff1aSopenharmony_ci return AVERROR(EINVAL); 68cabdff1aSopenharmony_ci } 69cabdff1aSopenharmony_ci 70cabdff1aSopenharmony_ci w = r->s.avctx->extradata[6 + rpr*2] << 2; 71cabdff1aSopenharmony_ci h = r->s.avctx->extradata[7 + rpr*2] << 2; 72cabdff1aSopenharmony_ci } else { 73cabdff1aSopenharmony_ci w = r->orig_width; 74cabdff1aSopenharmony_ci h = r->orig_height; 75cabdff1aSopenharmony_ci } 76cabdff1aSopenharmony_ci si->width = w; 77cabdff1aSopenharmony_ci si->height = h; 78cabdff1aSopenharmony_ci mb_size = ((w + 15) >> 4) * ((h + 15) >> 4); 79cabdff1aSopenharmony_ci mb_bits = ff_rv34_get_start_offset(gb, mb_size); 80cabdff1aSopenharmony_ci si->start = get_bits(gb, mb_bits); 81cabdff1aSopenharmony_ci skip_bits1(gb); 82cabdff1aSopenharmony_ci return 0; 83cabdff1aSopenharmony_ci} 84cabdff1aSopenharmony_ci 85cabdff1aSopenharmony_ci/** 86cabdff1aSopenharmony_ci * Decode 4x4 intra types array. 87cabdff1aSopenharmony_ci */ 88cabdff1aSopenharmony_cistatic int rv30_decode_intra_types(RV34DecContext *r, GetBitContext *gb, int8_t *dst) 89cabdff1aSopenharmony_ci{ 90cabdff1aSopenharmony_ci int i, j, k; 91cabdff1aSopenharmony_ci 92cabdff1aSopenharmony_ci for(i = 0; i < 4; i++, dst += r->intra_types_stride - 4){ 93cabdff1aSopenharmony_ci for(j = 0; j < 4; j+= 2){ 94cabdff1aSopenharmony_ci unsigned code = get_interleaved_ue_golomb(gb) << 1; 95cabdff1aSopenharmony_ci if (code > 80U*2U) { 96cabdff1aSopenharmony_ci av_log(r->s.avctx, AV_LOG_ERROR, "Incorrect intra prediction code\n"); 97cabdff1aSopenharmony_ci return -1; 98cabdff1aSopenharmony_ci } 99cabdff1aSopenharmony_ci for(k = 0; k < 2; k++){ 100cabdff1aSopenharmony_ci int A = dst[-r->intra_types_stride] + 1; 101cabdff1aSopenharmony_ci int B = dst[-1] + 1; 102cabdff1aSopenharmony_ci *dst++ = rv30_itype_from_context[A * 90 + B * 9 + rv30_itype_code[code + k]]; 103cabdff1aSopenharmony_ci if(dst[-1] == 9){ 104cabdff1aSopenharmony_ci av_log(r->s.avctx, AV_LOG_ERROR, "Incorrect intra prediction mode\n"); 105cabdff1aSopenharmony_ci return -1; 106cabdff1aSopenharmony_ci } 107cabdff1aSopenharmony_ci } 108cabdff1aSopenharmony_ci } 109cabdff1aSopenharmony_ci } 110cabdff1aSopenharmony_ci return 0; 111cabdff1aSopenharmony_ci} 112cabdff1aSopenharmony_ci 113cabdff1aSopenharmony_ci/** 114cabdff1aSopenharmony_ci * Decode macroblock information. 115cabdff1aSopenharmony_ci */ 116cabdff1aSopenharmony_cistatic int rv30_decode_mb_info(RV34DecContext *r) 117cabdff1aSopenharmony_ci{ 118cabdff1aSopenharmony_ci static const int rv30_p_types[6] = { RV34_MB_SKIP, RV34_MB_P_16x16, RV34_MB_P_8x8, -1, RV34_MB_TYPE_INTRA, RV34_MB_TYPE_INTRA16x16 }; 119cabdff1aSopenharmony_ci static const int rv30_b_types[6] = { RV34_MB_SKIP, RV34_MB_B_DIRECT, RV34_MB_B_FORWARD, RV34_MB_B_BACKWARD, RV34_MB_TYPE_INTRA, RV34_MB_TYPE_INTRA16x16 }; 120cabdff1aSopenharmony_ci MpegEncContext *s = &r->s; 121cabdff1aSopenharmony_ci GetBitContext *gb = &s->gb; 122cabdff1aSopenharmony_ci unsigned code = get_interleaved_ue_golomb(gb); 123cabdff1aSopenharmony_ci 124cabdff1aSopenharmony_ci if (code > 11) { 125cabdff1aSopenharmony_ci av_log(s->avctx, AV_LOG_ERROR, "Incorrect MB type code\n"); 126cabdff1aSopenharmony_ci return -1; 127cabdff1aSopenharmony_ci } 128cabdff1aSopenharmony_ci if(code > 5){ 129cabdff1aSopenharmony_ci av_log(s->avctx, AV_LOG_ERROR, "dquant needed\n"); 130cabdff1aSopenharmony_ci code -= 6; 131cabdff1aSopenharmony_ci } 132cabdff1aSopenharmony_ci if(s->pict_type != AV_PICTURE_TYPE_B) 133cabdff1aSopenharmony_ci return rv30_p_types[code]; 134cabdff1aSopenharmony_ci else 135cabdff1aSopenharmony_ci return rv30_b_types[code]; 136cabdff1aSopenharmony_ci} 137cabdff1aSopenharmony_ci 138cabdff1aSopenharmony_cistatic inline void rv30_weak_loop_filter(uint8_t *src, const int step, 139cabdff1aSopenharmony_ci const int stride, const int lim) 140cabdff1aSopenharmony_ci{ 141cabdff1aSopenharmony_ci const uint8_t *cm = ff_crop_tab + MAX_NEG_CROP; 142cabdff1aSopenharmony_ci int i, diff; 143cabdff1aSopenharmony_ci 144cabdff1aSopenharmony_ci for(i = 0; i < 4; i++){ 145cabdff1aSopenharmony_ci diff = ((src[-2*step] - src[1*step]) - (src[-1*step] - src[0*step])*4) >> 3; 146cabdff1aSopenharmony_ci diff = av_clip(diff, -lim, lim); 147cabdff1aSopenharmony_ci src[-1*step] = cm[src[-1*step] + diff]; 148cabdff1aSopenharmony_ci src[ 0*step] = cm[src[ 0*step] - diff]; 149cabdff1aSopenharmony_ci src += stride; 150cabdff1aSopenharmony_ci } 151cabdff1aSopenharmony_ci} 152cabdff1aSopenharmony_ci 153cabdff1aSopenharmony_cistatic void rv30_loop_filter(RV34DecContext *r, int row) 154cabdff1aSopenharmony_ci{ 155cabdff1aSopenharmony_ci MpegEncContext *s = &r->s; 156cabdff1aSopenharmony_ci int mb_pos, mb_x; 157cabdff1aSopenharmony_ci int i, j, k; 158cabdff1aSopenharmony_ci uint8_t *Y, *C; 159cabdff1aSopenharmony_ci int loc_lim, cur_lim, left_lim = 0, top_lim = 0; 160cabdff1aSopenharmony_ci 161cabdff1aSopenharmony_ci mb_pos = row * s->mb_stride; 162cabdff1aSopenharmony_ci for(mb_x = 0; mb_x < s->mb_width; mb_x++, mb_pos++){ 163cabdff1aSopenharmony_ci int mbtype = s->current_picture_ptr->mb_type[mb_pos]; 164cabdff1aSopenharmony_ci if(IS_INTRA(mbtype) || IS_SEPARATE_DC(mbtype)) 165cabdff1aSopenharmony_ci r->deblock_coefs[mb_pos] = 0xFFFF; 166cabdff1aSopenharmony_ci if(IS_INTRA(mbtype)) 167cabdff1aSopenharmony_ci r->cbp_chroma[mb_pos] = 0xFF; 168cabdff1aSopenharmony_ci } 169cabdff1aSopenharmony_ci 170cabdff1aSopenharmony_ci /* all vertical edges are filtered first 171cabdff1aSopenharmony_ci * and horizontal edges are filtered on the next iteration 172cabdff1aSopenharmony_ci */ 173cabdff1aSopenharmony_ci mb_pos = row * s->mb_stride; 174cabdff1aSopenharmony_ci for(mb_x = 0; mb_x < s->mb_width; mb_x++, mb_pos++){ 175cabdff1aSopenharmony_ci cur_lim = rv30_loop_filt_lim[s->current_picture_ptr->qscale_table[mb_pos]]; 176cabdff1aSopenharmony_ci if(mb_x) 177cabdff1aSopenharmony_ci left_lim = rv30_loop_filt_lim[s->current_picture_ptr->qscale_table[mb_pos - 1]]; 178cabdff1aSopenharmony_ci for(j = 0; j < 16; j += 4){ 179cabdff1aSopenharmony_ci Y = s->current_picture_ptr->f->data[0] + mb_x*16 + (row*16 + j) * s->linesize + 4 * !mb_x; 180cabdff1aSopenharmony_ci for(i = !mb_x; i < 4; i++, Y += 4){ 181cabdff1aSopenharmony_ci int ij = i + j; 182cabdff1aSopenharmony_ci loc_lim = 0; 183cabdff1aSopenharmony_ci if(r->deblock_coefs[mb_pos] & (1 << ij)) 184cabdff1aSopenharmony_ci loc_lim = cur_lim; 185cabdff1aSopenharmony_ci else if(!i && r->deblock_coefs[mb_pos - 1] & (1 << (ij + 3))) 186cabdff1aSopenharmony_ci loc_lim = left_lim; 187cabdff1aSopenharmony_ci else if( i && r->deblock_coefs[mb_pos] & (1 << (ij - 1))) 188cabdff1aSopenharmony_ci loc_lim = cur_lim; 189cabdff1aSopenharmony_ci if(loc_lim) 190cabdff1aSopenharmony_ci rv30_weak_loop_filter(Y, 1, s->linesize, loc_lim); 191cabdff1aSopenharmony_ci } 192cabdff1aSopenharmony_ci } 193cabdff1aSopenharmony_ci for(k = 0; k < 2; k++){ 194cabdff1aSopenharmony_ci int cur_cbp, left_cbp = 0; 195cabdff1aSopenharmony_ci cur_cbp = (r->cbp_chroma[mb_pos] >> (k*4)) & 0xF; 196cabdff1aSopenharmony_ci if(mb_x) 197cabdff1aSopenharmony_ci left_cbp = (r->cbp_chroma[mb_pos - 1] >> (k*4)) & 0xF; 198cabdff1aSopenharmony_ci for(j = 0; j < 8; j += 4){ 199cabdff1aSopenharmony_ci C = s->current_picture_ptr->f->data[k + 1] + mb_x*8 + (row*8 + j) * s->uvlinesize + 4 * !mb_x; 200cabdff1aSopenharmony_ci for(i = !mb_x; i < 2; i++, C += 4){ 201cabdff1aSopenharmony_ci int ij = i + (j >> 1); 202cabdff1aSopenharmony_ci loc_lim = 0; 203cabdff1aSopenharmony_ci if (cur_cbp & (1 << ij)) 204cabdff1aSopenharmony_ci loc_lim = cur_lim; 205cabdff1aSopenharmony_ci else if(!i && left_cbp & (1 << (ij + 1))) 206cabdff1aSopenharmony_ci loc_lim = left_lim; 207cabdff1aSopenharmony_ci else if( i && cur_cbp & (1 << (ij - 1))) 208cabdff1aSopenharmony_ci loc_lim = cur_lim; 209cabdff1aSopenharmony_ci if(loc_lim) 210cabdff1aSopenharmony_ci rv30_weak_loop_filter(C, 1, s->uvlinesize, loc_lim); 211cabdff1aSopenharmony_ci } 212cabdff1aSopenharmony_ci } 213cabdff1aSopenharmony_ci } 214cabdff1aSopenharmony_ci } 215cabdff1aSopenharmony_ci mb_pos = row * s->mb_stride; 216cabdff1aSopenharmony_ci for(mb_x = 0; mb_x < s->mb_width; mb_x++, mb_pos++){ 217cabdff1aSopenharmony_ci cur_lim = rv30_loop_filt_lim[s->current_picture_ptr->qscale_table[mb_pos]]; 218cabdff1aSopenharmony_ci if(row) 219cabdff1aSopenharmony_ci top_lim = rv30_loop_filt_lim[s->current_picture_ptr->qscale_table[mb_pos - s->mb_stride]]; 220cabdff1aSopenharmony_ci for(j = 4*!row; j < 16; j += 4){ 221cabdff1aSopenharmony_ci Y = s->current_picture_ptr->f->data[0] + mb_x*16 + (row*16 + j) * s->linesize; 222cabdff1aSopenharmony_ci for(i = 0; i < 4; i++, Y += 4){ 223cabdff1aSopenharmony_ci int ij = i + j; 224cabdff1aSopenharmony_ci loc_lim = 0; 225cabdff1aSopenharmony_ci if(r->deblock_coefs[mb_pos] & (1 << ij)) 226cabdff1aSopenharmony_ci loc_lim = cur_lim; 227cabdff1aSopenharmony_ci else if(!j && r->deblock_coefs[mb_pos - s->mb_stride] & (1 << (ij + 12))) 228cabdff1aSopenharmony_ci loc_lim = top_lim; 229cabdff1aSopenharmony_ci else if( j && r->deblock_coefs[mb_pos] & (1 << (ij - 4))) 230cabdff1aSopenharmony_ci loc_lim = cur_lim; 231cabdff1aSopenharmony_ci if(loc_lim) 232cabdff1aSopenharmony_ci rv30_weak_loop_filter(Y, s->linesize, 1, loc_lim); 233cabdff1aSopenharmony_ci } 234cabdff1aSopenharmony_ci } 235cabdff1aSopenharmony_ci for(k = 0; k < 2; k++){ 236cabdff1aSopenharmony_ci int cur_cbp, top_cbp = 0; 237cabdff1aSopenharmony_ci cur_cbp = (r->cbp_chroma[mb_pos] >> (k*4)) & 0xF; 238cabdff1aSopenharmony_ci if(row) 239cabdff1aSopenharmony_ci top_cbp = (r->cbp_chroma[mb_pos - s->mb_stride] >> (k*4)) & 0xF; 240cabdff1aSopenharmony_ci for(j = 4*!row; j < 8; j += 4){ 241cabdff1aSopenharmony_ci C = s->current_picture_ptr->f->data[k+1] + mb_x*8 + (row*8 + j) * s->uvlinesize; 242cabdff1aSopenharmony_ci for(i = 0; i < 2; i++, C += 4){ 243cabdff1aSopenharmony_ci int ij = i + (j >> 1); 244cabdff1aSopenharmony_ci loc_lim = 0; 245cabdff1aSopenharmony_ci if (r->cbp_chroma[mb_pos] & (1 << ij)) 246cabdff1aSopenharmony_ci loc_lim = cur_lim; 247cabdff1aSopenharmony_ci else if(!j && top_cbp & (1 << (ij + 2))) 248cabdff1aSopenharmony_ci loc_lim = top_lim; 249cabdff1aSopenharmony_ci else if( j && cur_cbp & (1 << (ij - 2))) 250cabdff1aSopenharmony_ci loc_lim = cur_lim; 251cabdff1aSopenharmony_ci if(loc_lim) 252cabdff1aSopenharmony_ci rv30_weak_loop_filter(C, s->uvlinesize, 1, loc_lim); 253cabdff1aSopenharmony_ci } 254cabdff1aSopenharmony_ci } 255cabdff1aSopenharmony_ci } 256cabdff1aSopenharmony_ci } 257cabdff1aSopenharmony_ci} 258cabdff1aSopenharmony_ci 259cabdff1aSopenharmony_ci/** 260cabdff1aSopenharmony_ci * Initialize decoder. 261cabdff1aSopenharmony_ci */ 262cabdff1aSopenharmony_cistatic av_cold int rv30_decode_init(AVCodecContext *avctx) 263cabdff1aSopenharmony_ci{ 264cabdff1aSopenharmony_ci RV34DecContext *r = avctx->priv_data; 265cabdff1aSopenharmony_ci int ret; 266cabdff1aSopenharmony_ci 267cabdff1aSopenharmony_ci r->orig_width = avctx->coded_width; 268cabdff1aSopenharmony_ci r->orig_height = avctx->coded_height; 269cabdff1aSopenharmony_ci 270cabdff1aSopenharmony_ci if (avctx->extradata_size < 2) { 271cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Extradata is too small.\n"); 272cabdff1aSopenharmony_ci return AVERROR(EINVAL); 273cabdff1aSopenharmony_ci } 274cabdff1aSopenharmony_ci r->rv30 = 1; 275cabdff1aSopenharmony_ci if ((ret = ff_rv34_decode_init(avctx)) < 0) 276cabdff1aSopenharmony_ci return ret; 277cabdff1aSopenharmony_ci 278cabdff1aSopenharmony_ci r->max_rpr = avctx->extradata[1] & 7; 279cabdff1aSopenharmony_ci if(avctx->extradata_size < 2*r->max_rpr + 8){ 280cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_WARNING, "Insufficient extradata - need at least %d bytes, got %d\n", 281cabdff1aSopenharmony_ci 2*r->max_rpr + 8, avctx->extradata_size); 282cabdff1aSopenharmony_ci } 283cabdff1aSopenharmony_ci 284cabdff1aSopenharmony_ci r->parse_slice_header = rv30_parse_slice_header; 285cabdff1aSopenharmony_ci r->decode_intra_types = rv30_decode_intra_types; 286cabdff1aSopenharmony_ci r->decode_mb_info = rv30_decode_mb_info; 287cabdff1aSopenharmony_ci r->loop_filter = rv30_loop_filter; 288cabdff1aSopenharmony_ci r->luma_dc_quant_i = rv30_luma_dc_quant; 289cabdff1aSopenharmony_ci r->luma_dc_quant_p = rv30_luma_dc_quant; 290cabdff1aSopenharmony_ci ff_rv30dsp_init(&r->rdsp); 291cabdff1aSopenharmony_ci return 0; 292cabdff1aSopenharmony_ci} 293cabdff1aSopenharmony_ci 294cabdff1aSopenharmony_ciconst FFCodec ff_rv30_decoder = { 295cabdff1aSopenharmony_ci .p.name = "rv30", 296cabdff1aSopenharmony_ci .p.long_name = NULL_IF_CONFIG_SMALL("RealVideo 3.0"), 297cabdff1aSopenharmony_ci .p.type = AVMEDIA_TYPE_VIDEO, 298cabdff1aSopenharmony_ci .p.id = AV_CODEC_ID_RV30, 299cabdff1aSopenharmony_ci .priv_data_size = sizeof(RV34DecContext), 300cabdff1aSopenharmony_ci .init = rv30_decode_init, 301cabdff1aSopenharmony_ci .close = ff_rv34_decode_end, 302cabdff1aSopenharmony_ci FF_CODEC_DECODE_CB(ff_rv34_decode_frame), 303cabdff1aSopenharmony_ci .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY | 304cabdff1aSopenharmony_ci AV_CODEC_CAP_FRAME_THREADS, 305cabdff1aSopenharmony_ci .flush = ff_mpeg_flush, 306cabdff1aSopenharmony_ci .p.pix_fmts = (const enum AVPixelFormat[]) { 307cabdff1aSopenharmony_ci AV_PIX_FMT_YUV420P, 308cabdff1aSopenharmony_ci AV_PIX_FMT_NONE 309cabdff1aSopenharmony_ci }, 310cabdff1aSopenharmony_ci .update_thread_context = ONLY_IF_THREADS_ENABLED(ff_rv34_decode_update_thread_context), 311cabdff1aSopenharmony_ci .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | 312cabdff1aSopenharmony_ci FF_CODEC_CAP_ALLOCATE_PROGRESS, 313cabdff1aSopenharmony_ci}; 314