Commit | Line | Data |
---|---|---|
2ba45a60 DM |
1 | /* |
2 | * Copyright (c) 2011 Derek Buitenhuis | |
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 General Public | |
8 | * License as published by the Free Software Foundation; | |
9 | * version 2 of the License. | |
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 | * General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU 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 | /** | |
22 | * @file | |
23 | * Known FOURCCs: | |
24 | * 'ULY0' (YCbCr 4:2:0), 'ULY2' (YCbCr 4:2:2), 'ULRG' (RGB), 'ULRA' (RGBA), | |
25 | * 'ULH0' (YCbCr 4:2:0 BT.709), 'ULH2' (YCbCr 4:2:2 BT.709) | |
26 | */ | |
27 | ||
28 | extern "C" { | |
29 | #include "avcodec.h" | |
30 | } | |
31 | ||
32 | #include "libutvideo.h" | |
33 | #include "get_bits.h" | |
34 | ||
35 | static av_cold int utvideo_decode_init(AVCodecContext *avctx) | |
36 | { | |
37 | UtVideoContext *utv = (UtVideoContext *)avctx->priv_data; | |
38 | UtVideoExtra info; | |
39 | int format; | |
40 | int begin_ret; | |
41 | ||
f6fa7814 DM |
42 | if (avctx->extradata_size != 16 && avctx->extradata_size != 8 ) { |
43 | av_log(avctx, AV_LOG_ERROR, "Extradata size (%d) mismatch.\n", avctx->extradata_size); | |
2ba45a60 DM |
44 | return -1; |
45 | } | |
46 | ||
47 | /* Read extradata */ | |
48 | info.version = AV_RL32(avctx->extradata); | |
49 | info.original_format = AV_RL32(avctx->extradata + 4); | |
50 | info.frameinfo_size = AV_RL32(avctx->extradata + 8); | |
51 | info.flags = AV_RL32(avctx->extradata + 12); | |
52 | ||
53 | /* Pick format based on FOURCC */ | |
54 | switch (avctx->codec_tag) { | |
55 | #ifdef UTV_BT709 | |
56 | case MKTAG('U', 'L', 'H', '0'): | |
57 | avctx->pix_fmt = AV_PIX_FMT_YUV420P; | |
58 | avctx->colorspace = AVCOL_SPC_BT709; | |
59 | format = UTVF_YV12; | |
60 | break; | |
61 | case MKTAG('U', 'L', 'H', '2'): | |
62 | avctx->pix_fmt = AV_PIX_FMT_YUYV422; | |
63 | avctx->colorspace = AVCOL_SPC_BT709; | |
64 | format = UTVF_YUY2; | |
65 | break; | |
66 | #endif | |
67 | case MKTAG('U', 'L', 'Y', '0'): | |
68 | avctx->pix_fmt = AV_PIX_FMT_YUV420P; | |
69 | format = UTVF_YV12; | |
70 | break; | |
71 | case MKTAG('U', 'L', 'Y', '2'): | |
72 | avctx->pix_fmt = AV_PIX_FMT_YUYV422; | |
73 | format = UTVF_YUY2; | |
74 | break; | |
75 | case MKTAG('U', 'L', 'R', 'G'): | |
76 | avctx->pix_fmt = AV_PIX_FMT_BGR24; | |
77 | format = UTVF_NFCC_BGR_BU; | |
78 | break; | |
79 | case MKTAG('U', 'L', 'R', 'A'): | |
80 | avctx->pix_fmt = AV_PIX_FMT_RGB32; | |
81 | format = UTVF_NFCC_BGRA_BU; | |
82 | break; | |
f6fa7814 DM |
83 | #ifdef UTVF_UQY2 |
84 | case MKTAG('U', 'Q', 'Y', '2'): | |
85 | avctx->pix_fmt = AV_PIX_FMT_YUV422P10; | |
86 | format = UTVF_v210; | |
87 | break; | |
88 | #endif | |
2ba45a60 DM |
89 | default: |
90 | av_log(avctx, AV_LOG_ERROR, | |
91 | "Not a Ut Video FOURCC: %X\n", avctx->codec_tag); | |
92 | return -1; | |
93 | } | |
94 | ||
95 | /* Only allocate the buffer once */ | |
96 | utv->buf_size = avpicture_get_size(avctx->pix_fmt, avctx->width, avctx->height); | |
f6fa7814 DM |
97 | #ifdef UTVF_UQY2 |
98 | if (format == UTVF_v210) | |
99 | utv->buf_size += avctx->height * ((avctx->width + 47) / 48) * 128; // the linesize used by the decoder, this does not seem to be exported | |
100 | #endif | |
2ba45a60 DM |
101 | utv->buffer = (uint8_t *)av_malloc(utv->buf_size * sizeof(uint8_t)); |
102 | ||
103 | if (utv->buffer == NULL) { | |
104 | av_log(avctx, AV_LOG_ERROR, "Unable to allocate output buffer.\n"); | |
105 | return -1; | |
106 | } | |
107 | ||
108 | /* Allocate the output frame */ | |
109 | avctx->coded_frame = av_frame_alloc(); | |
110 | ||
111 | /* Ut Video only supports 8-bit */ | |
112 | avctx->bits_per_raw_sample = 8; | |
113 | ||
114 | /* Is it interlaced? */ | |
115 | avctx->coded_frame->interlaced_frame = info.flags & 0x800 ? 1 : 0; | |
116 | ||
117 | /* Apparently Ut Video doesn't store this info... */ | |
118 | avctx->coded_frame->top_field_first = 1; | |
119 | ||
120 | /* | |
121 | * Create a Ut Video instance. Since the function wants | |
122 | * an "interface name" string, pass it the name of the lib. | |
123 | */ | |
124 | utv->codec = CCodec::CreateInstance(UNFCC(avctx->codec_tag), "libavcodec"); | |
125 | ||
126 | /* Initialize Decoding */ | |
127 | begin_ret = utv->codec->DecodeBegin(format, avctx->width, avctx->height, | |
128 | CBGROSSWIDTH_WINDOWS, &info, sizeof(UtVideoExtra)); | |
129 | ||
130 | /* Check to see if the decoder initlized properly */ | |
131 | if (begin_ret != 0) { | |
132 | av_log(avctx, AV_LOG_ERROR, | |
133 | "Could not initialize decoder: %d\n", begin_ret); | |
134 | return -1; | |
135 | } | |
136 | ||
137 | return 0; | |
138 | } | |
139 | ||
140 | static int utvideo_decode_frame(AVCodecContext *avctx, void *data, | |
141 | int *got_frame, AVPacket *avpkt) | |
142 | { | |
143 | UtVideoContext *utv = (UtVideoContext *)avctx->priv_data; | |
144 | AVFrame *pic = avctx->coded_frame; | |
145 | int w = avctx->width, h = avctx->height; | |
146 | ||
147 | /* Set flags */ | |
148 | pic->reference = 0; | |
149 | pic->pict_type = AV_PICTURE_TYPE_I; | |
150 | pic->key_frame = 1; | |
151 | ||
152 | /* Decode the frame */ | |
153 | utv->codec->DecodeFrame(utv->buffer, avpkt->data, true); | |
154 | ||
155 | /* Set the output data depending on the colorspace */ | |
156 | switch (avctx->pix_fmt) { | |
157 | case AV_PIX_FMT_YUV420P: | |
158 | pic->linesize[0] = w; | |
159 | pic->linesize[1] = pic->linesize[2] = w / 2; | |
160 | pic->data[0] = utv->buffer; | |
161 | pic->data[2] = utv->buffer + (w * h); | |
162 | pic->data[1] = pic->data[2] + (w * h / 4); | |
163 | break; | |
164 | case AV_PIX_FMT_YUYV422: | |
165 | pic->linesize[0] = w * 2; | |
166 | pic->data[0] = utv->buffer; | |
167 | break; | |
f6fa7814 DM |
168 | case AV_PIX_FMT_YUV422P10: { |
169 | uint16_t *y, *u, *v; | |
170 | int i,j; | |
171 | int linesize = ((w + 47) / 48) * 128; | |
172 | ||
173 | pic->linesize[0] = w * 2; | |
174 | pic->linesize[1] = | |
175 | pic->linesize[2] = w; | |
176 | pic->data[0] = utv->buffer + linesize * h; | |
177 | pic->data[1] = pic->data[0] + h*pic->linesize[0]; | |
178 | pic->data[2] = pic->data[1] + h*pic->linesize[1]; | |
179 | y = (uint16_t*)pic->data[0]; | |
180 | u = (uint16_t*)pic->data[1]; | |
181 | v = (uint16_t*)pic->data[2]; | |
182 | for (j = 0; j < h; j++) { | |
183 | const uint8_t *in = utv->buffer + j * linesize; | |
184 | ||
185 | for (i = 0; i + 1 < w; i += 6, in += 4) { | |
186 | unsigned a,b; | |
187 | a = AV_RL32(in); | |
188 | in += 4; | |
189 | b = AV_RL32(in); | |
190 | *u++ = (a ) & 0x3FF; | |
191 | *y++ = (a>>10) & 0x3FF; | |
192 | *v++ = (a>>20) & 0x3FF; | |
193 | *y++ = (b ) & 0x3FF; | |
194 | ||
195 | if (i + 3 >= w) | |
196 | break; | |
197 | ||
198 | in += 4; | |
199 | a = AV_RL32(in); | |
200 | *u++ = (b>>10) & 0x3FF; | |
201 | *y++ = (b>>20) & 0x3FF; | |
202 | *v++ = (a ) & 0x3FF; | |
203 | *y++ = (a>>10) & 0x3FF; | |
204 | ||
205 | if (i + 5 >= w) | |
206 | break; | |
207 | ||
208 | in += 4; | |
209 | b = AV_RL32(in); | |
210 | *u++ = (a>>20) & 0x3FF; | |
211 | *y++ = (b ) & 0x3FF; | |
212 | *v++ = (b>>10) & 0x3FF; | |
213 | *y++ = (b>>20) & 0x3FF; | |
214 | } | |
215 | } | |
216 | break; | |
217 | } | |
2ba45a60 DM |
218 | case AV_PIX_FMT_BGR24: |
219 | case AV_PIX_FMT_RGB32: | |
220 | /* Make the linesize negative, since Ut Video uses bottom-up BGR */ | |
221 | pic->linesize[0] = -1 * w * (avctx->pix_fmt == AV_PIX_FMT_BGR24 ? 3 : 4); | |
222 | pic->data[0] = utv->buffer + utv->buf_size + pic->linesize[0]; | |
223 | break; | |
224 | } | |
225 | ||
226 | *got_frame = 1; | |
227 | av_frame_move_ref((AVFrame*)data, pic); | |
228 | ||
229 | return avpkt->size; | |
230 | } | |
231 | ||
232 | static av_cold int utvideo_decode_close(AVCodecContext *avctx) | |
233 | { | |
234 | UtVideoContext *utv = (UtVideoContext *)avctx->priv_data; | |
235 | ||
236 | /* Free output */ | |
237 | av_frame_free(&avctx->coded_frame); | |
238 | av_freep(&utv->buffer); | |
239 | ||
240 | /* Finish decoding and clean up the instance */ | |
241 | utv->codec->DecodeEnd(); | |
242 | CCodec::DeleteInstance(utv->codec); | |
243 | ||
244 | return 0; | |
245 | } | |
246 | ||
247 | AVCodec ff_libutvideo_decoder = { | |
248 | "libutvideo", | |
249 | NULL_IF_CONFIG_SMALL("Ut Video"), | |
250 | AVMEDIA_TYPE_VIDEO, | |
251 | AV_CODEC_ID_UTVIDEO, | |
252 | 0, //capabilities | |
253 | NULL, //supported_framerates | |
254 | NULL, //pix_fmts | |
255 | NULL, //supported_samplerates | |
256 | NULL, //sample_fmts | |
257 | NULL, //channel_layouts | |
258 | 0, //max_lowres | |
259 | NULL, //priv_class | |
260 | NULL, //profiles | |
261 | sizeof(UtVideoContext), | |
262 | NULL, //next | |
263 | NULL, //init_thread_copy | |
264 | NULL, //update_thread_context | |
265 | NULL, //defaults | |
266 | NULL, //init_static_data | |
267 | utvideo_decode_init, | |
268 | NULL, //encode | |
269 | NULL, //encode2 | |
270 | utvideo_decode_frame, | |
271 | utvideo_decode_close, | |
272 | }; |