4 * Copyright (C) 2009 Michael Niedermayer <michaelni@gmx.at>
5 * Copyright (c) 2009 Baptiste Coudurier <baptiste dot coudurier at gmail dot com>
7 * This file is part of FFmpeg.
9 * FFmpeg is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * FFmpeg is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with FFmpeg; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
25 #include "bytestream.h"
29 #define CLIP(v, depth) av_clip(v, 1 << (depth-8), ((1 << depth)-(1 << (depth-8)) -1))
30 #define WRITE_PIXELS(a, b, c, depth) \
32 val = CLIP(*a++, depth) << (10-depth); \
33 val |= (CLIP(*b++, depth) << (20-depth)) | \
34 (CLIP(*c++, depth) << (30-depth)); \
39 static void v210_planar_pack_8_c(const uint8_t *y, const uint8_t *u,
40 const uint8_t *v, uint8_t *dst,
46 /* unroll this to match the assembly */
47 for (i = 0; i < width - 11; i += 12) {
48 WRITE_PIXELS(u, y, v, 8);
49 WRITE_PIXELS(y, u, y, 8);
50 WRITE_PIXELS(v, y, u, 8);
51 WRITE_PIXELS(y, v, y, 8);
52 WRITE_PIXELS(u, y, v, 8);
53 WRITE_PIXELS(y, u, y, 8);
54 WRITE_PIXELS(v, y, u, 8);
55 WRITE_PIXELS(y, v, y, 8);
59 static void v210_planar_pack_10_c(const uint16_t *y, const uint16_t *u,
60 const uint16_t *v, uint8_t *dst,
66 for (i = 0; i < width - 5; i += 6) {
67 WRITE_PIXELS(u, y, v, 10);
68 WRITE_PIXELS(y, u, y, 10);
69 WRITE_PIXELS(v, y, u, 10);
70 WRITE_PIXELS(y, v, y, 10);
74 av_cold void ff_v210enc_init(V210EncContext *s)
76 s->pack_line_8 = v210_planar_pack_8_c;
77 s->pack_line_10 = v210_planar_pack_10_c;
78 s->sample_factor_8 = 2;
79 s->sample_factor_10 = 1;
82 ff_v210enc_init_x86(s);
85 static av_cold int encode_init(AVCodecContext *avctx)
87 V210EncContext *s = avctx->priv_data;
89 if (avctx->width & 1) {
90 av_log(avctx, AV_LOG_ERROR, "v210 needs even width\n");
91 return AVERROR(EINVAL);
94 #if FF_API_CODED_FRAME
95 FF_DISABLE_DEPRECATION_WARNINGS
96 avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;
97 FF_ENABLE_DEPRECATION_WARNINGS
102 avctx->bits_per_coded_sample = 20;
103 avctx->bit_rate = ff_guess_coded_bitrate(avctx) * 16 / 15;
108 static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
109 const AVFrame *pic, int *got_packet)
111 V210EncContext *s = avctx->priv_data;
112 int aligned_width = ((avctx->width + 47) / 48) * 48;
113 int stride = aligned_width * 8 / 3;
114 int line_padding = stride - ((avctx->width * 8 + 11) / 12) * 4;
115 AVFrameSideData *side_data;
119 ret = ff_alloc_packet2(avctx, pkt, avctx->height * stride, avctx->height * stride);
121 av_log(avctx, AV_LOG_ERROR, "Error getting output packet.\n");
126 if (pic->format == AV_PIX_FMT_YUV422P10) {
127 const uint16_t *y = (const uint16_t *)pic->data[0];
128 const uint16_t *u = (const uint16_t *)pic->data[1];
129 const uint16_t *v = (const uint16_t *)pic->data[2];
131 const int sample_size = 6 * s->sample_factor_10;
132 const int sample_w = avctx->width / sample_size;
134 for (h = 0; h < avctx->height; h++) {
136 w = sample_w * sample_size;
137 s->pack_line_10(y, u, v, dst, w);
142 dst += sample_w * 16 * s->sample_factor_10;
144 for (; w < avctx->width - 5; w += 6) {
145 WRITE_PIXELS(u, y, v, 10);
146 WRITE_PIXELS(y, u, y, 10);
147 WRITE_PIXELS(v, y, u, 10);
148 WRITE_PIXELS(y, v, y, 10);
150 if (w < avctx->width - 1) {
151 WRITE_PIXELS(u, y, v, 10);
153 val = CLIP(*y++, 10) << (10-10);
154 if (w == avctx->width - 2) {
159 if (w < avctx->width - 3) {
160 val |= (CLIP(*u++, 10) << (20-10)) | (CLIP(*y++, 10) << (30-10));
164 val = CLIP(*v++, 10) << (10-10) | (CLIP(*y++, 10) << (20-10));
169 memset(dst, 0, line_padding);
171 y += pic->linesize[0] / 2 - avctx->width;
172 u += pic->linesize[1] / 2 - avctx->width / 2;
173 v += pic->linesize[2] / 2 - avctx->width / 2;
175 } else if(pic->format == AV_PIX_FMT_YUV422P) {
176 const uint8_t *y = pic->data[0];
177 const uint8_t *u = pic->data[1];
178 const uint8_t *v = pic->data[2];
180 const int sample_size = 6 * s->sample_factor_8;
181 const int sample_w = avctx->width / sample_size;
183 for (h = 0; h < avctx->height; h++) {
185 w = sample_w * sample_size;
186 s->pack_line_8(y, u, v, dst, w);
191 dst += sample_w * 16 * s->sample_factor_8;
193 for (; w < avctx->width - 5; w += 6) {
194 WRITE_PIXELS(u, y, v, 8);
195 WRITE_PIXELS(y, u, y, 8);
196 WRITE_PIXELS(v, y, u, 8);
197 WRITE_PIXELS(y, v, y, 8);
199 if (w < avctx->width - 1) {
200 WRITE_PIXELS(u, y, v, 8);
202 val = CLIP(*y++, 8) << (10-8);
203 if (w == avctx->width - 2) {
208 if (w < avctx->width - 3) {
209 val |= (CLIP(*u++, 8) << (20-8)) | (CLIP(*y++, 8) << (30-8));
213 val = (CLIP(*v++, 8) << (10-8)) | (CLIP(*y++, 8) << (20-8));
217 memset(dst, 0, line_padding);
220 y += pic->linesize[0] - avctx->width;
221 u += pic->linesize[1] - avctx->width / 2;
222 v += pic->linesize[2] - avctx->width / 2;
226 side_data = av_frame_get_side_data(pic, AV_FRAME_DATA_A53_CC);
227 if (side_data && side_data->size) {
228 uint8_t *buf = av_packet_new_side_data(pkt, AV_PKT_DATA_A53_CC, side_data->size);
230 return AVERROR(ENOMEM);
231 memcpy(buf, side_data->data, side_data->size);
234 side_data = av_frame_get_side_data(pic, AV_FRAME_DATA_AFD);
235 if (side_data && side_data->size) {
236 uint8_t *buf = av_packet_new_side_data(pkt, AV_PKT_DATA_AFD, side_data->size);
238 return AVERROR(ENOMEM);
239 memcpy(buf, side_data->data, side_data->size);
242 pkt->flags |= AV_PKT_FLAG_KEY;
247 AVCodec ff_v210_encoder = {
249 .long_name = NULL_IF_CONFIG_SMALL("Uncompressed 4:2:2 10-bit"),
250 .type = AVMEDIA_TYPE_VIDEO,
251 .id = AV_CODEC_ID_V210,
252 .priv_data_size = sizeof(V210EncContext),
254 .encode2 = encode_frame,
255 .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV422P, AV_PIX_FMT_NONE },