1/* 2 * Copyright (C) 2009 Michael Niedermayer <michaelni@gmx.at> 3 * 4 * This file is part of FFmpeg. 5 * 6 * FFmpeg is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * FFmpeg is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with FFmpeg; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 */ 20 21#include "avcodec.h" 22#include "codec_internal.h" 23#include "internal.h" 24#include "libavutil/bswap.h" 25#include "libavutil/internal.h" 26 27static av_cold int decode_init(AVCodecContext *avctx) 28{ 29 if (avctx->width & 1) { 30 av_log(avctx, AV_LOG_ERROR, "v210x needs even width\n"); 31 return AVERROR(EINVAL); 32 } 33 avctx->pix_fmt = AV_PIX_FMT_YUV422P16; 34 avctx->bits_per_raw_sample = 10; 35 36 return 0; 37} 38 39static int decode_frame(AVCodecContext *avctx, AVFrame *pic, 40 int *got_frame, AVPacket *avpkt) 41{ 42 const uint32_t *src = (const uint32_t *)avpkt->data; 43 int width = avctx->width; 44 int y = 0; 45 uint16_t *ydst, *udst, *vdst, *yend; 46 int ret; 47 48 if (avpkt->size < avctx->width * avctx->height * 8 / 3) { 49 av_log(avctx, AV_LOG_ERROR, "Packet too small\n"); 50 return AVERROR_INVALIDDATA; 51 } 52 53 if (avpkt->size > avctx->width * avctx->height * 8 / 3) { 54 avpriv_request_sample(avctx, "(Probably) padded data"); 55 } 56 57 if ((ret = ff_get_buffer(avctx, pic, 0)) < 0) 58 return ret; 59 60 ydst = (uint16_t *)pic->data[0]; 61 udst = (uint16_t *)pic->data[1]; 62 vdst = (uint16_t *)pic->data[2]; 63 yend = ydst + width; 64 pic->pict_type = AV_PICTURE_TYPE_I; 65 pic->key_frame = 1; 66 67 for (;;) { 68 uint32_t v = av_be2ne32(*src++); 69 *udst++ = (v >> 16) & 0xFFC0; 70 *ydst++ = (v >> 6 ) & 0xFFC0; 71 *vdst++ = (v << 4 ) & 0xFFC0; 72 73 v = av_be2ne32(*src++); 74 *ydst++ = (v >> 16) & 0xFFC0; 75 76 if (ydst >= yend) { 77 ydst += pic->linesize[0] / 2 - width; 78 udst += pic->linesize[1] / 2 - width / 2; 79 vdst += pic->linesize[2] / 2 - width / 2; 80 yend = ydst + width; 81 if (++y >= avctx->height) 82 break; 83 } 84 85 *udst++ = (v >> 6 ) & 0xFFC0; 86 *ydst++ = (v << 4 ) & 0xFFC0; 87 88 v = av_be2ne32(*src++); 89 *vdst++ = (v >> 16) & 0xFFC0; 90 *ydst++ = (v >> 6 ) & 0xFFC0; 91 92 if (ydst >= yend) { 93 ydst += pic->linesize[0] / 2 - width; 94 udst += pic->linesize[1] / 2 - width / 2; 95 vdst += pic->linesize[2] / 2 - width / 2; 96 yend = ydst + width; 97 if (++y >= avctx->height) 98 break; 99 } 100 101 *udst++ = (v << 4 ) & 0xFFC0; 102 103 v = av_be2ne32(*src++); 104 *ydst++ = (v >> 16) & 0xFFC0; 105 *vdst++ = (v >> 6 ) & 0xFFC0; 106 *ydst++ = (v << 4 ) & 0xFFC0; 107 if (ydst >= yend) { 108 ydst += pic->linesize[0] / 2 - width; 109 udst += pic->linesize[1] / 2 - width / 2; 110 vdst += pic->linesize[2] / 2 - width / 2; 111 yend = ydst + width; 112 if (++y >= avctx->height) 113 break; 114 } 115 } 116 117 *got_frame = 1; 118 119 return avpkt->size; 120} 121 122const FFCodec ff_v210x_decoder = { 123 .p.name = "v210x", 124 .p.long_name = NULL_IF_CONFIG_SMALL("Uncompressed 4:2:2 10-bit"), 125 .p.type = AVMEDIA_TYPE_VIDEO, 126 .p.id = AV_CODEC_ID_V210X, 127 .init = decode_init, 128 FF_CODEC_DECODE_CB(decode_frame), 129 .p.capabilities = AV_CODEC_CAP_DR1, 130 .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, 131}; 132