yading@10: /* yading@10: * Copyright (C) 2009 Michael Niedermayer yading@10: * yading@10: * This file is part of FFmpeg. yading@10: * yading@10: * FFmpeg is free software; you can redistribute it and/or yading@10: * modify it under the terms of the GNU Lesser General Public yading@10: * License as published by the Free Software Foundation; either yading@10: * version 2.1 of the License, or (at your option) any later version. yading@10: * yading@10: * FFmpeg is distributed in the hope that it will be useful, yading@10: * but WITHOUT ANY WARRANTY; without even the implied warranty of yading@10: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU yading@10: * Lesser General Public License for more details. yading@10: * yading@10: * You should have received a copy of the GNU Lesser General Public yading@10: * License along with FFmpeg; if not, write to the Free Software yading@10: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA yading@10: */ yading@10: yading@10: #include "avcodec.h" yading@10: #include "internal.h" yading@10: #include "libavutil/bswap.h" yading@10: #include "libavutil/internal.h" yading@10: #include "libavutil/mem.h" yading@10: yading@10: static av_cold int decode_init(AVCodecContext *avctx) yading@10: { yading@10: if (avctx->width & 1) { yading@10: av_log(avctx, AV_LOG_ERROR, "v210x needs even width\n"); yading@10: return AVERROR(EINVAL); yading@10: } yading@10: avctx->pix_fmt = AV_PIX_FMT_YUV422P16; yading@10: avctx->bits_per_raw_sample = 10; yading@10: yading@10: return 0; yading@10: } yading@10: yading@10: static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, yading@10: AVPacket *avpkt) yading@10: { yading@10: const uint32_t *src = (const uint32_t *)avpkt->data; yading@10: AVFrame *pic = data; yading@10: int width = avctx->width; yading@10: int y = 0; yading@10: uint16_t *ydst, *udst, *vdst, *yend; yading@10: int ret; yading@10: yading@10: if (avpkt->size < avctx->width * avctx->height * 8 / 3) { yading@10: av_log(avctx, AV_LOG_ERROR, "Packet too small\n"); yading@10: return AVERROR_INVALIDDATA; yading@10: } yading@10: yading@10: if (avpkt->size > avctx->width * avctx->height * 8 / 3) { yading@10: avpriv_request_sample(avctx, "(Probably) padded data"); yading@10: } yading@10: yading@10: if ((ret = ff_get_buffer(avctx, pic, 0)) < 0) yading@10: return ret; yading@10: yading@10: ydst = (uint16_t *)pic->data[0]; yading@10: udst = (uint16_t *)pic->data[1]; yading@10: vdst = (uint16_t *)pic->data[2]; yading@10: yend = ydst + width; yading@10: pic->pict_type = AV_PICTURE_TYPE_I; yading@10: pic->key_frame = 1; yading@10: yading@10: for (;;) { yading@10: uint32_t v = av_be2ne32(*src++); yading@10: *udst++ = (v >> 16) & 0xFFC0; yading@10: *ydst++ = (v >> 6 ) & 0xFFC0; yading@10: *vdst++ = (v << 4 ) & 0xFFC0; yading@10: yading@10: v = av_be2ne32(*src++); yading@10: *ydst++ = (v >> 16) & 0xFFC0; yading@10: yading@10: if (ydst >= yend) { yading@10: ydst += pic->linesize[0] / 2 - width; yading@10: udst += pic->linesize[1] / 2 - width / 2; yading@10: vdst += pic->linesize[2] / 2 - width / 2; yading@10: yend = ydst + width; yading@10: if (++y >= avctx->height) yading@10: break; yading@10: } yading@10: yading@10: *udst++ = (v >> 6 ) & 0xFFC0; yading@10: *ydst++ = (v << 4 ) & 0xFFC0; yading@10: yading@10: v = av_be2ne32(*src++); yading@10: *vdst++ = (v >> 16) & 0xFFC0; yading@10: *ydst++ = (v >> 6 ) & 0xFFC0; yading@10: yading@10: if (ydst >= yend) { yading@10: ydst += pic->linesize[0] / 2 - width; yading@10: udst += pic->linesize[1] / 2 - width / 2; yading@10: vdst += pic->linesize[2] / 2 - width / 2; yading@10: yend = ydst + width; yading@10: if (++y >= avctx->height) yading@10: break; yading@10: } yading@10: yading@10: *udst++ = (v << 4 ) & 0xFFC0; yading@10: yading@10: v = av_be2ne32(*src++); yading@10: *ydst++ = (v >> 16) & 0xFFC0; yading@10: *vdst++ = (v >> 6 ) & 0xFFC0; yading@10: *ydst++ = (v << 4 ) & 0xFFC0; yading@10: if (ydst >= yend) { yading@10: ydst += pic->linesize[0] / 2 - width; yading@10: udst += pic->linesize[1] / 2 - width / 2; yading@10: vdst += pic->linesize[2] / 2 - width / 2; yading@10: yend = ydst + width; yading@10: if (++y >= avctx->height) yading@10: break; yading@10: } yading@10: } yading@10: yading@10: *got_frame = 1; yading@10: yading@10: return avpkt->size; yading@10: } yading@10: yading@10: AVCodec ff_v210x_decoder = { yading@10: .name = "v210x", yading@10: .type = AVMEDIA_TYPE_VIDEO, yading@10: .id = AV_CODEC_ID_V210X, yading@10: .init = decode_init, yading@10: .decode = decode_frame, yading@10: .capabilities = CODEC_CAP_DR1, yading@10: .long_name = NULL_IF_CONFIG_SMALL("Uncompressed 4:2:2 10-bit"), yading@10: };