/src/ffmpeg/libavcodec/v210dec.c
Line | Count | Source |
1 | | /* |
2 | | * V210 decoder |
3 | | * |
4 | | * Copyright (C) 2009 Michael Niedermayer <michaelni@gmx.at> |
5 | | * Copyright (c) 2009 Baptiste Coudurier <baptiste dot coudurier at gmail dot com> |
6 | | * |
7 | | * This file is part of FFmpeg. |
8 | | * |
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. |
13 | | * |
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. |
18 | | * |
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 |
22 | | */ |
23 | | |
24 | | #include "avcodec.h" |
25 | | #include "codec_internal.h" |
26 | | #include "v210dec.h" |
27 | | #include "v210dec_init.h" |
28 | | #include "libavutil/bswap.h" |
29 | | #include "libavutil/imgutils.h" |
30 | | #include "libavutil/internal.h" |
31 | | #include "libavutil/intreadwrite.h" |
32 | | #include "libavutil/mem.h" |
33 | | #include "thread.h" |
34 | | |
35 | | typedef struct ThreadData { |
36 | | AVFrame *frame; |
37 | | const uint8_t *buf; |
38 | | int stride; |
39 | | } ThreadData; |
40 | | |
41 | | static av_cold int decode_init(AVCodecContext *avctx) |
42 | 967 | { |
43 | 967 | V210DecContext *s = avctx->priv_data; |
44 | | |
45 | 967 | avctx->pix_fmt = AV_PIX_FMT_YUV422P10; |
46 | 967 | avctx->bits_per_raw_sample = 10; |
47 | | |
48 | 967 | s->thread_count = av_clip(avctx->thread_count, 1, avctx->height/4); |
49 | 967 | s->aligned_input = 0; |
50 | 967 | ff_v210dec_init(s); |
51 | | |
52 | 967 | return 0; |
53 | 967 | } |
54 | | |
55 | | static void decode_row(const uint32_t *src, uint16_t *y, uint16_t *u, uint16_t *v, const int width, |
56 | | void (*unpack_frame)(const uint32_t *src, uint16_t *y, uint16_t *u, uint16_t *v, int width)) |
57 | 86.1k | { |
58 | 86.1k | uint32_t val; |
59 | 86.1k | int w = (FFMAX(0, width - 12) / 12) * 12; |
60 | | |
61 | 86.1k | unpack_frame(src, y, u, v, w); |
62 | | |
63 | 86.1k | y += w; |
64 | 86.1k | u += w >> 1; |
65 | 86.1k | v += w >> 1; |
66 | 86.1k | src += (w << 1) / 3; |
67 | | |
68 | 96.2k | while (w < width - 5) { |
69 | 10.1k | READ_PIXELS(u, y, v); |
70 | 10.1k | READ_PIXELS(y, u, y); |
71 | 10.1k | READ_PIXELS(v, y, u); |
72 | 10.1k | READ_PIXELS(y, v, y); |
73 | 10.1k | w += 6; |
74 | 10.1k | } |
75 | | |
76 | 86.1k | if (w++ < width) { |
77 | 79.5k | READ_PIXELS(u, y, v); |
78 | | |
79 | 79.5k | if (w++ < width) { |
80 | 76.6k | val = av_le2ne32(*src++); |
81 | 76.6k | *y++ = val & 0x3FF; |
82 | | |
83 | 76.6k | if (w++ < width) { |
84 | 42.0k | *u++ = (val >> 10) & 0x3FF; |
85 | 42.0k | *y++ = (val >> 20) & 0x3FF; |
86 | 42.0k | val = av_le2ne32(*src++); |
87 | 42.0k | *v++ = val & 0x3FF; |
88 | | |
89 | 42.0k | if (w++ < width) { |
90 | 38.6k | *y++ = (val >> 10) & 0x3FF; |
91 | | |
92 | 38.6k | if (w++ < width) { |
93 | 987 | *u++ = (val >> 20) & 0x3FF; |
94 | 987 | val = av_le2ne32(*src++); |
95 | 987 | *y++ = val & 0x3FF; |
96 | 987 | *v++ = (val >> 10) & 0x3FF; |
97 | | |
98 | 987 | if (w++ < width) |
99 | 0 | *y++ = (val >> 20) & 0x3FF; |
100 | 987 | } |
101 | 38.6k | } |
102 | 42.0k | } |
103 | 76.6k | } |
104 | 79.5k | } |
105 | 86.1k | } |
106 | | |
107 | | static int v210_decode_slice(AVCodecContext *avctx, void *arg, int jobnr, int threadnr) |
108 | 499 | { |
109 | 499 | V210DecContext *s = avctx->priv_data; |
110 | 499 | ThreadData *td = arg; |
111 | 499 | AVFrame *frame = td->frame; |
112 | 499 | int stride = td->stride; |
113 | 499 | int slice_start = (avctx->height * jobnr) / s->thread_count; |
114 | 499 | int slice_end = (avctx->height * (jobnr+1)) / s->thread_count; |
115 | 499 | const uint8_t *psrc = td->buf + stride * slice_start; |
116 | 499 | int16_t *py = (uint16_t*)frame->data[0] + slice_start * frame->linesize[0] / 2; |
117 | 499 | int16_t *pu = (uint16_t*)frame->data[1] + slice_start * frame->linesize[1] / 2; |
118 | 499 | int16_t *pv = (uint16_t*)frame->data[2] + slice_start * frame->linesize[2] / 2; |
119 | | |
120 | 47.0k | for (int h = slice_start; h < slice_end; h++) { |
121 | 46.5k | decode_row((const uint32_t *)psrc, py, pu, pv, avctx->width, s->unpack_frame); |
122 | 46.5k | psrc += stride; |
123 | 46.5k | py += frame->linesize[0] / 2; |
124 | 46.5k | pu += frame->linesize[1] / 2; |
125 | 46.5k | pv += frame->linesize[2] / 2; |
126 | 46.5k | } |
127 | | |
128 | 499 | return 0; |
129 | 499 | } |
130 | | |
131 | 2.38M | static int v210_stride(int width, int align) { |
132 | 2.38M | int aligned_width = ((width + align - 1) / align) * align; |
133 | 2.38M | return aligned_width * 8 / 3; |
134 | 2.38M | } |
135 | | |
136 | | static int decode_frame(AVCodecContext *avctx, AVFrame *pic, |
137 | | int *got_frame, AVPacket *avpkt) |
138 | 593k | { |
139 | 593k | V210DecContext *s = avctx->priv_data; |
140 | 593k | ThreadData td; |
141 | 593k | int ret, stride, aligned_input; |
142 | 593k | const uint8_t *psrc = avpkt->data; |
143 | | |
144 | 593k | if (s->custom_stride ) |
145 | 0 | stride = s->custom_stride > 0 ? s->custom_stride : 0; |
146 | 593k | else { |
147 | 593k | stride = v210_stride(avctx->width, 48); |
148 | 593k | if (avpkt->size < stride * avctx->height) { |
149 | 575k | int align; |
150 | 2.23M | for (align = 24; align >= 6; align >>= 1) { |
151 | 1.72M | int small_stride = v210_stride(avctx->width, align); |
152 | 1.72M | if (avpkt->size == small_stride * avctx->height) { |
153 | 65.9k | stride = small_stride; |
154 | 65.9k | if (!s->stride_warning_shown) |
155 | 127 | av_log(avctx, AV_LOG_WARNING, "Broken v210 with too small padding (%d byte) detected\n", align * 8 / 3); |
156 | 65.9k | s->stride_warning_shown = 1; |
157 | 65.9k | break; |
158 | 65.9k | } |
159 | 1.72M | } |
160 | 575k | if (align < 6 && avctx->codec_tag == MKTAG('b', 'x', 'y', '2')) |
161 | 52.5k | stride = 0; |
162 | 575k | } |
163 | 593k | } |
164 | | |
165 | 593k | if (stride == 0 && ((avctx->width & 1) || (int64_t)avctx->width * avctx->height > INT_MAX / 6)) { |
166 | 349 | av_log(avctx, AV_LOG_ERROR, "Strideless v210 is not supported for size %dx%d\n", avctx->width, avctx->height); |
167 | 349 | return AVERROR_INVALIDDATA; |
168 | 349 | } |
169 | | |
170 | 593k | if (stride > 0 && avpkt->size < (int64_t)stride * avctx->height || |
171 | 469k | stride == 0 && avpkt->size < v210_stride(avctx->width * avctx->height, 6)) { |
172 | 469k | av_log(avctx, AV_LOG_ERROR, "packet too small\n"); |
173 | 469k | return AVERROR_INVALIDDATA; |
174 | 469k | } |
175 | 124k | if ( avctx->codec_tag == MKTAG('C', '2', '1', '0') |
176 | 4.61k | && avpkt->size > 64 |
177 | 124k | && AV_RN32(psrc) == AV_RN32("INFO") |
178 | 633 | && avpkt->size - 64 >= stride * avctx->height) |
179 | 294 | psrc += 64; |
180 | | |
181 | 124k | aligned_input = !((uintptr_t)psrc & 0x1f) && !(stride & 0x1f); |
182 | 124k | if (aligned_input != s->aligned_input) { |
183 | 8.57k | s->aligned_input = aligned_input; |
184 | 8.57k | ff_v210dec_init(s); |
185 | 8.57k | } |
186 | | |
187 | 124k | if ((ret = ff_thread_get_buffer(avctx, pic, 0)) < 0) |
188 | 18.2k | return ret; |
189 | | |
190 | 106k | if (stride) { |
191 | 66.6k | td.stride = stride; |
192 | 66.6k | td.buf = psrc; |
193 | 66.6k | td.frame = pic; |
194 | 66.6k | avctx->execute2(avctx, v210_decode_slice, &td, NULL, s->thread_count); |
195 | 66.6k | } else { |
196 | 39.5k | uint8_t *pointers[4]; |
197 | 39.5k | int linesizes[4]; |
198 | 39.5k | int ret = av_image_alloc(pointers, linesizes, avctx->width, avctx->height, avctx->pix_fmt, 1); |
199 | 39.5k | if (ret < 0) |
200 | 0 | return ret; |
201 | 39.5k | 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); |
202 | 39.5k | av_image_copy2(pic->data, pic->linesize, pointers, linesizes, |
203 | 39.5k | avctx->pix_fmt, avctx->width, avctx->height); |
204 | 39.5k | av_freep(&pointers[0]); |
205 | 39.5k | } |
206 | | |
207 | 106k | if (avctx->field_order > AV_FIELD_PROGRESSIVE) { |
208 | | /* we have interlaced material flagged in container */ |
209 | 0 | pic->flags |= AV_FRAME_FLAG_INTERLACED; |
210 | 0 | if (avctx->field_order == AV_FIELD_TT || avctx->field_order == AV_FIELD_TB) |
211 | 0 | pic->flags |= AV_FRAME_FLAG_TOP_FIELD_FIRST; |
212 | 0 | } |
213 | | |
214 | 106k | *got_frame = 1; |
215 | | |
216 | 106k | return avpkt->size; |
217 | 106k | } |
218 | | |
219 | | #define V210DEC_FLAGS AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_VIDEO_PARAM |
220 | | static const AVOption v210dec_options[] = { |
221 | | {"custom_stride", "Custom V210 stride", offsetof(V210DecContext, custom_stride), AV_OPT_TYPE_INT, |
222 | | {.i64 = 0}, -1, INT_MAX, V210DEC_FLAGS}, |
223 | | {NULL} |
224 | | }; |
225 | | |
226 | | static const AVClass v210dec_class = { |
227 | | .class_name = "V210 Decoder", |
228 | | .item_name = av_default_item_name, |
229 | | .option = v210dec_options, |
230 | | .version = LIBAVUTIL_VERSION_INT, |
231 | | }; |
232 | | |
233 | | const FFCodec ff_v210_decoder = { |
234 | | .p.name = "v210", |
235 | | CODEC_LONG_NAME("Uncompressed 4:2:2 10-bit"), |
236 | | .p.type = AVMEDIA_TYPE_VIDEO, |
237 | | .p.id = AV_CODEC_ID_V210, |
238 | | .priv_data_size = sizeof(V210DecContext), |
239 | | .init = decode_init, |
240 | | FF_CODEC_DECODE_CB(decode_frame), |
241 | | .p.capabilities = AV_CODEC_CAP_DR1 | |
242 | | AV_CODEC_CAP_SLICE_THREADS | |
243 | | AV_CODEC_CAP_FRAME_THREADS, |
244 | | .p.priv_class = &v210dec_class, |
245 | | }; |