Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4349 | Serge | 1 | /* |
2 | * Copyright (c) 2012 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 "libavutil/avassert.h" |
||
30 | #include "avcodec.h" |
||
31 | #include "internal.h" |
||
32 | } |
||
33 | |||
34 | #include "libutvideo.h" |
||
35 | #include "put_bits.h" |
||
36 | |||
37 | static av_cold int utvideo_encode_init(AVCodecContext *avctx) |
||
38 | { |
||
39 | UtVideoContext *utv = (UtVideoContext *)avctx->priv_data; |
||
40 | UtVideoExtra *info; |
||
41 | uint32_t flags, in_format; |
||
42 | |||
43 | switch (avctx->pix_fmt) { |
||
44 | case AV_PIX_FMT_YUV420P: |
||
45 | in_format = UTVF_YV12; |
||
46 | avctx->bits_per_coded_sample = 12; |
||
47 | avctx->codec_tag = MKTAG('U', 'L', 'Y', '0'); |
||
48 | break; |
||
49 | case AV_PIX_FMT_YUYV422: |
||
50 | in_format = UTVF_YUYV; |
||
51 | avctx->bits_per_coded_sample = 16; |
||
52 | avctx->codec_tag = MKTAG('U', 'L', 'Y', '2'); |
||
53 | break; |
||
54 | case AV_PIX_FMT_BGR24: |
||
55 | in_format = UTVF_NFCC_BGR_BU; |
||
56 | avctx->bits_per_coded_sample = 24; |
||
57 | avctx->codec_tag = MKTAG('U', 'L', 'R', 'G'); |
||
58 | break; |
||
59 | case AV_PIX_FMT_RGB32: |
||
60 | in_format = UTVF_NFCC_BGRA_BU; |
||
61 | avctx->bits_per_coded_sample = 32; |
||
62 | avctx->codec_tag = MKTAG('U', 'L', 'R', 'A'); |
||
63 | break; |
||
64 | default: |
||
65 | return AVERROR(EINVAL); |
||
66 | } |
||
67 | |||
68 | /* Check before we alloc anything */ |
||
69 | if (avctx->prediction_method != 0 && avctx->prediction_method != 2) { |
||
70 | av_log(avctx, AV_LOG_ERROR, "Invalid prediction method.\n"); |
||
71 | return AVERROR(EINVAL); |
||
72 | } |
||
73 | |||
74 | flags = ((avctx->prediction_method + 1) << 8) | (avctx->thread_count - 1); |
||
75 | |||
76 | avctx->priv_data = utv; |
||
77 | avctx->coded_frame = avcodec_alloc_frame(); |
||
78 | |||
79 | /* Alloc extradata buffer */ |
||
80 | info = (UtVideoExtra *)av_malloc(sizeof(*info)); |
||
81 | |||
82 | if (info == NULL) { |
||
83 | av_log(avctx, AV_LOG_ERROR, "Could not allocate extradata buffer.\n"); |
||
84 | return AVERROR(ENOMEM); |
||
85 | } |
||
86 | |||
87 | /* |
||
88 | * We use this buffer to hold the data that Ut Video returns, |
||
89 | * since we cannot decode planes separately with it. |
||
90 | */ |
||
91 | utv->buf_size = avpicture_get_size(avctx->pix_fmt, |
||
92 | avctx->width, avctx->height); |
||
93 | utv->buffer = (uint8_t *)av_malloc(utv->buf_size); |
||
94 | |||
95 | if (utv->buffer == NULL) { |
||
96 | av_log(avctx, AV_LOG_ERROR, "Could not allocate output buffer.\n"); |
||
97 | return AVERROR(ENOMEM); |
||
98 | } |
||
99 | |||
100 | /* |
||
101 | * Create a Ut Video instance. Since the function wants |
||
102 | * an "interface name" string, pass it the name of the lib. |
||
103 | */ |
||
104 | utv->codec = CCodec::CreateInstance(UNFCC(avctx->codec_tag), "libavcodec"); |
||
105 | |||
106 | /* Initialize encoder */ |
||
107 | utv->codec->EncodeBegin(in_format, avctx->width, avctx->height, |
||
108 | CBGROSSWIDTH_WINDOWS); |
||
109 | |||
110 | /* Get extradata from encoder */ |
||
111 | avctx->extradata_size = utv->codec->EncodeGetExtraDataSize(); |
||
112 | utv->codec->EncodeGetExtraData(info, avctx->extradata_size, in_format, |
||
113 | avctx->width, avctx->height, |
||
114 | CBGROSSWIDTH_WINDOWS); |
||
115 | avctx->extradata = (uint8_t *)info; |
||
116 | |||
117 | /* Set flags */ |
||
118 | utv->codec->SetState(&flags, sizeof(flags)); |
||
119 | |||
120 | return 0; |
||
121 | } |
||
122 | |||
123 | static int utvideo_encode_frame(AVCodecContext *avctx, AVPacket *pkt, |
||
124 | const AVFrame *pic, int *got_packet) |
||
125 | { |
||
126 | UtVideoContext *utv = (UtVideoContext *)avctx->priv_data; |
||
127 | int w = avctx->width, h = avctx->height; |
||
128 | int ret, rgb_size, i; |
||
129 | bool keyframe; |
||
130 | uint8_t *y, *u, *v; |
||
131 | uint8_t *dst; |
||
132 | |||
133 | /* Alloc buffer */ |
||
134 | if ((ret = ff_alloc_packet2(avctx, pkt, utv->buf_size)) < 0) |
||
135 | return ret; |
||
136 | |||
137 | dst = pkt->data; |
||
138 | |||
139 | /* Move input if needed data into Ut Video friendly buffer */ |
||
140 | switch (avctx->pix_fmt) { |
||
141 | case AV_PIX_FMT_YUV420P: |
||
142 | y = utv->buffer; |
||
143 | u = y + w * h; |
||
144 | v = u + w * h / 4; |
||
145 | for (i = 0; i < h; i++) { |
||
146 | memcpy(y, pic->data[0] + i * pic->linesize[0], w); |
||
147 | y += w; |
||
148 | } |
||
149 | for (i = 0; i < h / 2; i++) { |
||
150 | memcpy(u, pic->data[2] + i * pic->linesize[2], w >> 1); |
||
151 | memcpy(v, pic->data[1] + i * pic->linesize[1], w >> 1); |
||
152 | u += w >> 1; |
||
153 | v += w >> 1; |
||
154 | } |
||
155 | break; |
||
156 | case AV_PIX_FMT_YUYV422: |
||
157 | for (i = 0; i < h; i++) |
||
158 | memcpy(utv->buffer + i * (w << 1), |
||
159 | pic->data[0] + i * pic->linesize[0], w << 1); |
||
160 | break; |
||
161 | case AV_PIX_FMT_BGR24: |
||
162 | case AV_PIX_FMT_RGB32: |
||
163 | /* Ut Video takes bottom-up BGR */ |
||
164 | rgb_size = avctx->pix_fmt == AV_PIX_FMT_BGR24 ? 3 : 4; |
||
165 | for (i = 0; i < h; i++) |
||
166 | memcpy(utv->buffer + (h - i - 1) * w * rgb_size, |
||
167 | pic->data[0] + i * pic->linesize[0], |
||
168 | w * rgb_size); |
||
169 | break; |
||
170 | default: |
||
171 | return AVERROR(EINVAL); |
||
172 | } |
||
173 | |||
174 | /* Encode frame */ |
||
175 | pkt->size = utv->codec->EncodeFrame(dst, &keyframe, utv->buffer); |
||
176 | |||
177 | if (!pkt->size) { |
||
178 | av_log(avctx, AV_LOG_ERROR, "EncodeFrame failed!\n"); |
||
179 | return AVERROR_INVALIDDATA; |
||
180 | } |
||
181 | |||
182 | /* |
||
183 | * Ut Video is intra-only and every frame is a keyframe, |
||
184 | * and the API always returns true. In case something |
||
185 | * durastic changes in the future, such as inter support, |
||
186 | * assert that this is true. |
||
187 | */ |
||
188 | av_assert2(keyframe == true); |
||
189 | avctx->coded_frame->key_frame = 1; |
||
190 | avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I; |
||
191 | |||
192 | pkt->flags |= AV_PKT_FLAG_KEY; |
||
193 | *got_packet = 1; |
||
194 | return 0; |
||
195 | } |
||
196 | |||
197 | static av_cold int utvideo_encode_close(AVCodecContext *avctx) |
||
198 | { |
||
199 | UtVideoContext *utv = (UtVideoContext *)avctx->priv_data; |
||
200 | |||
201 | av_freep(&avctx->coded_frame); |
||
202 | av_freep(&avctx->extradata); |
||
203 | av_freep(&utv->buffer); |
||
204 | |||
205 | utv->codec->EncodeEnd(); |
||
206 | CCodec::DeleteInstance(utv->codec); |
||
207 | |||
208 | return 0; |
||
209 | } |
||
210 | |||
211 | AVCodec ff_libutvideo_encoder = { |
||
212 | "libutvideo", |
||
213 | NULL_IF_CONFIG_SMALL("Ut Video"), |
||
214 | AVMEDIA_TYPE_VIDEO, |
||
215 | AV_CODEC_ID_UTVIDEO, |
||
216 | CODEC_CAP_AUTO_THREADS | CODEC_CAP_LOSSLESS, |
||
217 | NULL, /* supported_framerates */ |
||
218 | (const enum AVPixelFormat[]) { |
||
219 | AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUYV422, AV_PIX_FMT_BGR24, |
||
220 | AV_PIX_FMT_RGB32, AV_PIX_FMT_NONE |
||
221 | }, |
||
222 | NULL, /* supported_samplerates */ |
||
223 | NULL, /* sample_fmts */ |
||
224 | NULL, /* channel_layouts */ |
||
225 | 0, /* max_lowres */ |
||
226 | NULL, /* priv_class */ |
||
227 | NULL, /* profiles */ |
||
228 | sizeof(UtVideoContext), |
||
229 | NULL, /* next */ |
||
230 | NULL, /* init_thread_copy */ |
||
231 | NULL, /* update_thread_context */ |
||
232 | NULL, /* defaults */ |
||
233 | NULL, /* init_static_data */ |
||
234 | utvideo_encode_init, |
||
235 | NULL, /* encode */ |
||
236 | utvideo_encode_frame, |
||
237 | NULL, /* decode */ |
||
238 | utvideo_encode_close, |
||
239 | NULL, /* flush */ |
||
240 | };>><>><>>>>>><> |