1/* 2 * 012v decoder 3 * 4 * Copyright (C) 2012 Carl Eugen Hoyos 5 * 6 * This file is part of FFmpeg. 7 * 8 * FFmpeg is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Lesser General Public 10 * License as published by the Free Software Foundation; either 11 * version 2.1 of the License, or (at your option) any later version. 12 * 13 * FFmpeg is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public 19 * License along with FFmpeg; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 */ 22 23#include "avcodec.h" 24#include "internal.h" 25#include "libavutil/intreadwrite.h" 26 27static av_cold int zero12v_decode_init(AVCodecContext *avctx) 28{ 29 avctx->pix_fmt = AV_PIX_FMT_YUV422P16; 30 avctx->bits_per_raw_sample = 10; 31 32 if (avctx->codec_tag == MKTAG('a', '1', '2', 'v')) 33 avpriv_request_sample(avctx, "transparency"); 34 35 return 0; 36} 37 38static int zero12v_decode_frame(AVCodecContext *avctx, void *data, 39 int *got_frame, AVPacket *avpkt) 40{ 41 int line = 0, ret; 42 const int width = avctx->width; 43 AVFrame *pic = data; 44 uint16_t *y, *u, *v; 45 const uint8_t *line_end, *src = avpkt->data; 46 int stride = avctx->width * 8 / 3; 47 48 if (width == 1) { 49 av_log(avctx, AV_LOG_ERROR, "Width 1 not supported.\n"); 50 return AVERROR_INVALIDDATA; 51 } 52 53 if ( avctx->codec_tag == MKTAG('0', '1', '2', 'v') 54 && avpkt->size % avctx->height == 0 55 && avpkt->size / avctx->height * 3 >= width * 8) 56 stride = avpkt->size / avctx->height; 57 58 if (avpkt->size < avctx->height * stride) { 59 av_log(avctx, AV_LOG_ERROR, "Packet too small: %d instead of %d\n", 60 avpkt->size, avctx->height * stride); 61 return AVERROR_INVALIDDATA; 62 } 63 64 if ((ret = ff_get_buffer(avctx, pic, 0)) < 0) 65 return ret; 66 67 pic->pict_type = AV_PICTURE_TYPE_I; 68 pic->key_frame = 1; 69 70 y = (uint16_t *)pic->data[0]; 71 u = (uint16_t *)pic->data[1]; 72 v = (uint16_t *)pic->data[2]; 73 line_end = avpkt->data + stride; 74 75 while (line++ < avctx->height) { 76 while (1) { 77 uint32_t t = AV_RL32(src); 78 src += 4; 79 *u++ = t << 6 & 0xFFC0; 80 *y++ = t >> 4 & 0xFFC0; 81 *v++ = t >> 14 & 0xFFC0; 82 83 if (src >= line_end - 1) { 84 *y = 0x80; 85 src++; 86 line_end += stride; 87 y = (uint16_t *)(pic->data[0] + line * pic->linesize[0]); 88 u = (uint16_t *)(pic->data[1] + line * pic->linesize[1]); 89 v = (uint16_t *)(pic->data[2] + line * pic->linesize[2]); 90 break; 91 } 92 93 t = AV_RL32(src); 94 src += 4; 95 *y++ = t << 6 & 0xFFC0; 96 *u++ = t >> 4 & 0xFFC0; 97 *y++ = t >> 14 & 0xFFC0; 98 if (src >= line_end - 2) { 99 if (!(width & 1)) { 100 *y = 0x80; 101 src += 2; 102 } 103 line_end += stride; 104 y = (uint16_t *)(pic->data[0] + line * pic->linesize[0]); 105 u = (uint16_t *)(pic->data[1] + line * pic->linesize[1]); 106 v = (uint16_t *)(pic->data[2] + line * pic->linesize[2]); 107 break; 108 } 109 110 t = AV_RL32(src); 111 src += 4; 112 *v++ = t << 6 & 0xFFC0; 113 *y++ = t >> 4 & 0xFFC0; 114 *u++ = t >> 14 & 0xFFC0; 115 116 if (src >= line_end - 1) { 117 *y = 0x80; 118 src++; 119 line_end += stride; 120 y = (uint16_t *)(pic->data[0] + line * pic->linesize[0]); 121 u = (uint16_t *)(pic->data[1] + line * pic->linesize[1]); 122 v = (uint16_t *)(pic->data[2] + line * pic->linesize[2]); 123 break; 124 } 125 126 t = AV_RL32(src); 127 src += 4; 128 *y++ = t << 6 & 0xFFC0; 129 *v++ = t >> 4 & 0xFFC0; 130 *y++ = t >> 14 & 0xFFC0; 131 132 if (src >= line_end - 2) { 133 if (width & 1) { 134 *y = 0x80; 135 src += 2; 136 } 137 line_end += stride; 138 y = (uint16_t *)(pic->data[0] + line * pic->linesize[0]); 139 u = (uint16_t *)(pic->data[1] + line * pic->linesize[1]); 140 v = (uint16_t *)(pic->data[2] + line * pic->linesize[2]); 141 break; 142 } 143 } 144 } 145 146 *got_frame = 1; 147 148 return avpkt->size; 149} 150 151AVCodec ff_zero12v_decoder = { 152 .name = "012v", 153 .long_name = NULL_IF_CONFIG_SMALL("Uncompressed 4:2:2 10-bit"), 154 .type = AVMEDIA_TYPE_VIDEO, 155 .id = AV_CODEC_ID_012V, 156 .init = zero12v_decode_init, 157 .decode = zero12v_decode_frame, 158 .capabilities = CODEC_CAP_DR1, 159}; 160