1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * V210 decoder 3cabdff1aSopenharmony_ci * 4cabdff1aSopenharmony_ci * Copyright (C) 2009 Michael Niedermayer <michaelni@gmx.at> 5cabdff1aSopenharmony_ci * Copyright (c) 2009 Baptiste Coudurier <baptiste dot coudurier at gmail dot com> 6cabdff1aSopenharmony_ci * 7cabdff1aSopenharmony_ci * This file is part of FFmpeg. 8cabdff1aSopenharmony_ci * 9cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or 10cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public 11cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either 12cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version. 13cabdff1aSopenharmony_ci * 14cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful, 15cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 16cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17cabdff1aSopenharmony_ci * Lesser General Public License for more details. 18cabdff1aSopenharmony_ci * 19cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public 20cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software 21cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 22cabdff1aSopenharmony_ci */ 23cabdff1aSopenharmony_ci 24cabdff1aSopenharmony_ci#include "avcodec.h" 25cabdff1aSopenharmony_ci#include "codec_internal.h" 26cabdff1aSopenharmony_ci#include "v210dec.h" 27cabdff1aSopenharmony_ci#include "v210dec_init.h" 28cabdff1aSopenharmony_ci#include "libavutil/bswap.h" 29cabdff1aSopenharmony_ci#include "libavutil/imgutils.h" 30cabdff1aSopenharmony_ci#include "libavutil/internal.h" 31cabdff1aSopenharmony_ci#include "libavutil/intreadwrite.h" 32cabdff1aSopenharmony_ci#include "thread.h" 33cabdff1aSopenharmony_ci 34cabdff1aSopenharmony_citypedef struct ThreadData { 35cabdff1aSopenharmony_ci AVFrame *frame; 36cabdff1aSopenharmony_ci uint8_t *buf; 37cabdff1aSopenharmony_ci int stride; 38cabdff1aSopenharmony_ci} ThreadData; 39cabdff1aSopenharmony_ci 40cabdff1aSopenharmony_cistatic av_cold int decode_init(AVCodecContext *avctx) 41cabdff1aSopenharmony_ci{ 42cabdff1aSopenharmony_ci V210DecContext *s = avctx->priv_data; 43cabdff1aSopenharmony_ci 44cabdff1aSopenharmony_ci avctx->pix_fmt = AV_PIX_FMT_YUV422P10; 45cabdff1aSopenharmony_ci avctx->bits_per_raw_sample = 10; 46cabdff1aSopenharmony_ci 47cabdff1aSopenharmony_ci s->thread_count = av_clip(avctx->thread_count, 1, avctx->height/4); 48cabdff1aSopenharmony_ci s->aligned_input = 0; 49cabdff1aSopenharmony_ci ff_v210dec_init(s); 50cabdff1aSopenharmony_ci 51cabdff1aSopenharmony_ci return 0; 52cabdff1aSopenharmony_ci} 53cabdff1aSopenharmony_ci 54cabdff1aSopenharmony_cistatic void decode_row(const uint32_t *src, uint16_t *y, uint16_t *u, uint16_t *v, const int width, 55cabdff1aSopenharmony_ci void (*unpack_frame)(const uint32_t *src, uint16_t *y, uint16_t *u, uint16_t *v, int width)) 56cabdff1aSopenharmony_ci{ 57cabdff1aSopenharmony_ci uint32_t val; 58cabdff1aSopenharmony_ci int w = (FFMAX(0, width - 12) / 12) * 12; 59cabdff1aSopenharmony_ci 60cabdff1aSopenharmony_ci unpack_frame(src, y, u, v, w); 61cabdff1aSopenharmony_ci 62cabdff1aSopenharmony_ci y += w; 63cabdff1aSopenharmony_ci u += w >> 1; 64cabdff1aSopenharmony_ci v += w >> 1; 65cabdff1aSopenharmony_ci src += (w << 1) / 3; 66cabdff1aSopenharmony_ci 67cabdff1aSopenharmony_ci while (w < width - 5) { 68cabdff1aSopenharmony_ci READ_PIXELS(u, y, v); 69cabdff1aSopenharmony_ci READ_PIXELS(y, u, y); 70cabdff1aSopenharmony_ci READ_PIXELS(v, y, u); 71cabdff1aSopenharmony_ci READ_PIXELS(y, v, y); 72cabdff1aSopenharmony_ci w += 6; 73cabdff1aSopenharmony_ci } 74cabdff1aSopenharmony_ci 75cabdff1aSopenharmony_ci if (w++ < width) { 76cabdff1aSopenharmony_ci READ_PIXELS(u, y, v); 77cabdff1aSopenharmony_ci 78cabdff1aSopenharmony_ci if (w++ < width) { 79cabdff1aSopenharmony_ci val = av_le2ne32(*src++); 80cabdff1aSopenharmony_ci *y++ = val & 0x3FF; 81cabdff1aSopenharmony_ci 82cabdff1aSopenharmony_ci if (w++ < width) { 83cabdff1aSopenharmony_ci *u++ = (val >> 10) & 0x3FF; 84cabdff1aSopenharmony_ci *y++ = (val >> 20) & 0x3FF; 85cabdff1aSopenharmony_ci val = av_le2ne32(*src++); 86cabdff1aSopenharmony_ci *v++ = val & 0x3FF; 87cabdff1aSopenharmony_ci 88cabdff1aSopenharmony_ci if (w++ < width) { 89cabdff1aSopenharmony_ci *y++ = (val >> 10) & 0x3FF; 90cabdff1aSopenharmony_ci 91cabdff1aSopenharmony_ci if (w++ < width) { 92cabdff1aSopenharmony_ci *u++ = (val >> 20) & 0x3FF; 93cabdff1aSopenharmony_ci val = av_le2ne32(*src++); 94cabdff1aSopenharmony_ci *y++ = val & 0x3FF; 95cabdff1aSopenharmony_ci *v++ = (val >> 10) & 0x3FF; 96cabdff1aSopenharmony_ci 97cabdff1aSopenharmony_ci if (w++ < width) 98cabdff1aSopenharmony_ci *y++ = (val >> 20) & 0x3FF; 99cabdff1aSopenharmony_ci } 100cabdff1aSopenharmony_ci } 101cabdff1aSopenharmony_ci } 102cabdff1aSopenharmony_ci } 103cabdff1aSopenharmony_ci } 104cabdff1aSopenharmony_ci} 105cabdff1aSopenharmony_ci 106cabdff1aSopenharmony_cistatic int v210_decode_slice(AVCodecContext *avctx, void *arg, int jobnr, int threadnr) 107cabdff1aSopenharmony_ci{ 108cabdff1aSopenharmony_ci V210DecContext *s = avctx->priv_data; 109cabdff1aSopenharmony_ci ThreadData *td = arg; 110cabdff1aSopenharmony_ci AVFrame *frame = td->frame; 111cabdff1aSopenharmony_ci int stride = td->stride; 112cabdff1aSopenharmony_ci int slice_start = (avctx->height * jobnr) / s->thread_count; 113cabdff1aSopenharmony_ci int slice_end = (avctx->height * (jobnr+1)) / s->thread_count; 114cabdff1aSopenharmony_ci uint8_t *psrc = td->buf + stride * slice_start; 115cabdff1aSopenharmony_ci int16_t *py = (uint16_t*)frame->data[0] + slice_start * frame->linesize[0] / 2; 116cabdff1aSopenharmony_ci int16_t *pu = (uint16_t*)frame->data[1] + slice_start * frame->linesize[1] / 2; 117cabdff1aSopenharmony_ci int16_t *pv = (uint16_t*)frame->data[2] + slice_start * frame->linesize[2] / 2; 118cabdff1aSopenharmony_ci 119cabdff1aSopenharmony_ci for (int h = slice_start; h < slice_end; h++) { 120cabdff1aSopenharmony_ci decode_row((const uint32_t *)psrc, py, pu, pv, avctx->width, s->unpack_frame); 121cabdff1aSopenharmony_ci psrc += stride; 122cabdff1aSopenharmony_ci py += frame->linesize[0] / 2; 123cabdff1aSopenharmony_ci pu += frame->linesize[1] / 2; 124cabdff1aSopenharmony_ci pv += frame->linesize[2] / 2; 125cabdff1aSopenharmony_ci } 126cabdff1aSopenharmony_ci 127cabdff1aSopenharmony_ci return 0; 128cabdff1aSopenharmony_ci} 129cabdff1aSopenharmony_ci 130cabdff1aSopenharmony_cistatic int v210_stride(int width, int align) { 131cabdff1aSopenharmony_ci int aligned_width = ((width + align - 1) / align) * align; 132cabdff1aSopenharmony_ci return aligned_width * 8 / 3; 133cabdff1aSopenharmony_ci} 134cabdff1aSopenharmony_ci 135cabdff1aSopenharmony_cistatic int decode_frame(AVCodecContext *avctx, AVFrame *pic, 136cabdff1aSopenharmony_ci int *got_frame, AVPacket *avpkt) 137cabdff1aSopenharmony_ci{ 138cabdff1aSopenharmony_ci V210DecContext *s = avctx->priv_data; 139cabdff1aSopenharmony_ci ThreadData td; 140cabdff1aSopenharmony_ci int ret, stride, aligned_input; 141cabdff1aSopenharmony_ci const uint8_t *psrc = avpkt->data; 142cabdff1aSopenharmony_ci 143cabdff1aSopenharmony_ci if (s->custom_stride ) 144cabdff1aSopenharmony_ci stride = s->custom_stride > 0 ? s->custom_stride : 0; 145cabdff1aSopenharmony_ci else { 146cabdff1aSopenharmony_ci stride = v210_stride(avctx->width, 48); 147cabdff1aSopenharmony_ci if (avpkt->size < stride * avctx->height) { 148cabdff1aSopenharmony_ci int align; 149cabdff1aSopenharmony_ci for (align = 24; align >= 6; align >>= 1) { 150cabdff1aSopenharmony_ci int small_stride = v210_stride(avctx->width, align); 151cabdff1aSopenharmony_ci if (avpkt->size == small_stride * avctx->height) { 152cabdff1aSopenharmony_ci stride = small_stride; 153cabdff1aSopenharmony_ci if (!s->stride_warning_shown) 154cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_WARNING, "Broken v210 with too small padding (%d byte) detected\n", align * 8 / 3); 155cabdff1aSopenharmony_ci s->stride_warning_shown = 1; 156cabdff1aSopenharmony_ci break; 157cabdff1aSopenharmony_ci } 158cabdff1aSopenharmony_ci } 159cabdff1aSopenharmony_ci if (align < 6 && avctx->codec_tag == MKTAG('b', 'x', 'y', '2')) 160cabdff1aSopenharmony_ci stride = 0; 161cabdff1aSopenharmony_ci } 162cabdff1aSopenharmony_ci } 163cabdff1aSopenharmony_ci 164cabdff1aSopenharmony_ci if (stride == 0 && ((avctx->width & 1) || (int64_t)avctx->width * avctx->height > INT_MAX / 6)) { 165cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Strideless v210 is not supported for size %dx%d\n", avctx->width, avctx->height); 166cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 167cabdff1aSopenharmony_ci } 168cabdff1aSopenharmony_ci 169cabdff1aSopenharmony_ci if (stride > 0 && avpkt->size < (int64_t)stride * avctx->height || 170cabdff1aSopenharmony_ci stride == 0 && avpkt->size < v210_stride(avctx->width * avctx->height, 6)) { 171cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "packet too small\n"); 172cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 173cabdff1aSopenharmony_ci } 174cabdff1aSopenharmony_ci if ( avctx->codec_tag == MKTAG('C', '2', '1', '0') 175cabdff1aSopenharmony_ci && avpkt->size > 64 176cabdff1aSopenharmony_ci && AV_RN32(psrc) == AV_RN32("INFO") 177cabdff1aSopenharmony_ci && avpkt->size - 64 >= stride * avctx->height) 178cabdff1aSopenharmony_ci psrc += 64; 179cabdff1aSopenharmony_ci 180cabdff1aSopenharmony_ci aligned_input = !((uintptr_t)psrc & 0x1f) && !(stride & 0x1f); 181cabdff1aSopenharmony_ci if (aligned_input != s->aligned_input) { 182cabdff1aSopenharmony_ci s->aligned_input = aligned_input; 183cabdff1aSopenharmony_ci ff_v210dec_init(s); 184cabdff1aSopenharmony_ci } 185cabdff1aSopenharmony_ci 186cabdff1aSopenharmony_ci if ((ret = ff_thread_get_buffer(avctx, pic, 0)) < 0) 187cabdff1aSopenharmony_ci return ret; 188cabdff1aSopenharmony_ci 189cabdff1aSopenharmony_ci pic->pict_type = AV_PICTURE_TYPE_I; 190cabdff1aSopenharmony_ci pic->key_frame = 1; 191cabdff1aSopenharmony_ci 192cabdff1aSopenharmony_ci if (stride) { 193cabdff1aSopenharmony_ci td.stride = stride; 194cabdff1aSopenharmony_ci td.buf = (uint8_t*)psrc; 195cabdff1aSopenharmony_ci td.frame = pic; 196cabdff1aSopenharmony_ci avctx->execute2(avctx, v210_decode_slice, &td, NULL, s->thread_count); 197cabdff1aSopenharmony_ci } else { 198cabdff1aSopenharmony_ci uint8_t *pointers[4]; 199cabdff1aSopenharmony_ci int linesizes[4]; 200cabdff1aSopenharmony_ci int ret = av_image_alloc(pointers, linesizes, avctx->width, avctx->height, avctx->pix_fmt, 1); 201cabdff1aSopenharmony_ci if (ret < 0) 202cabdff1aSopenharmony_ci return ret; 203cabdff1aSopenharmony_ci decode_row((const uint32_t *)psrc, (uint16_t *)pointers[0], (uint16_t *)pointers[1], (uint16_t *)pointers[2], avctx->width * avctx->height, s->unpack_frame); 204cabdff1aSopenharmony_ci av_image_copy(pic->data, pic->linesize, (const uint8_t **)pointers, linesizes, avctx->pix_fmt, avctx->width, avctx->height); 205cabdff1aSopenharmony_ci av_freep(&pointers[0]); 206cabdff1aSopenharmony_ci } 207cabdff1aSopenharmony_ci 208cabdff1aSopenharmony_ci if (avctx->field_order > AV_FIELD_PROGRESSIVE) { 209cabdff1aSopenharmony_ci /* we have interlaced material flagged in container */ 210cabdff1aSopenharmony_ci pic->interlaced_frame = 1; 211cabdff1aSopenharmony_ci if (avctx->field_order == AV_FIELD_TT || avctx->field_order == AV_FIELD_TB) 212cabdff1aSopenharmony_ci pic->top_field_first = 1; 213cabdff1aSopenharmony_ci } 214cabdff1aSopenharmony_ci 215cabdff1aSopenharmony_ci *got_frame = 1; 216cabdff1aSopenharmony_ci 217cabdff1aSopenharmony_ci return avpkt->size; 218cabdff1aSopenharmony_ci} 219cabdff1aSopenharmony_ci 220cabdff1aSopenharmony_ci#define V210DEC_FLAGS AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_VIDEO_PARAM 221cabdff1aSopenharmony_cistatic const AVOption v210dec_options[] = { 222cabdff1aSopenharmony_ci {"custom_stride", "Custom V210 stride", offsetof(V210DecContext, custom_stride), AV_OPT_TYPE_INT, 223cabdff1aSopenharmony_ci {.i64 = 0}, -1, INT_MAX, V210DEC_FLAGS}, 224cabdff1aSopenharmony_ci {NULL} 225cabdff1aSopenharmony_ci}; 226cabdff1aSopenharmony_ci 227cabdff1aSopenharmony_cistatic const AVClass v210dec_class = { 228cabdff1aSopenharmony_ci .class_name = "V210 Decoder", 229cabdff1aSopenharmony_ci .item_name = av_default_item_name, 230cabdff1aSopenharmony_ci .option = v210dec_options, 231cabdff1aSopenharmony_ci .version = LIBAVUTIL_VERSION_INT, 232cabdff1aSopenharmony_ci}; 233cabdff1aSopenharmony_ci 234cabdff1aSopenharmony_ciconst FFCodec ff_v210_decoder = { 235cabdff1aSopenharmony_ci .p.name = "v210", 236cabdff1aSopenharmony_ci .p.long_name = NULL_IF_CONFIG_SMALL("Uncompressed 4:2:2 10-bit"), 237cabdff1aSopenharmony_ci .p.type = AVMEDIA_TYPE_VIDEO, 238cabdff1aSopenharmony_ci .p.id = AV_CODEC_ID_V210, 239cabdff1aSopenharmony_ci .priv_data_size = sizeof(V210DecContext), 240cabdff1aSopenharmony_ci .init = decode_init, 241cabdff1aSopenharmony_ci FF_CODEC_DECODE_CB(decode_frame), 242cabdff1aSopenharmony_ci .p.capabilities = AV_CODEC_CAP_DR1 | 243cabdff1aSopenharmony_ci AV_CODEC_CAP_SLICE_THREADS | 244cabdff1aSopenharmony_ci AV_CODEC_CAP_FRAME_THREADS, 245cabdff1aSopenharmony_ci .p.priv_class = &v210dec_class, 246cabdff1aSopenharmony_ci .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, 247cabdff1aSopenharmony_ci}; 248