Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4349 | Serge | 1 | /* |
2 | * AVS encoding using the xavs library |
||
3 | * Copyright (C) 2010 Amanda, Y.N. Wu |
||
4 | * |
||
5 | * This file is part of FFmpeg. |
||
6 | * |
||
7 | * FFmpeg is free software; you can redistribute it and/or |
||
8 | * modify it under the terms of the GNU Lesser General Public |
||
9 | * License as published by the Free Software Foundation; either |
||
10 | * version 2.1 of the License, or (at your option) any later version. |
||
11 | * |
||
12 | * FFmpeg is distributed in the hope that it will be useful, |
||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||
15 | * Lesser General Public License for more details. |
||
16 | * |
||
17 | * You should have received a copy of the GNU Lesser General Public |
||
18 | * License along with FFmpeg; if not, write to the Free Software |
||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||
20 | */ |
||
21 | |||
22 | #include |
||
23 | #include |
||
24 | #include |
||
25 | #include |
||
26 | #include |
||
27 | #include |
||
28 | #include |
||
29 | #include "avcodec.h" |
||
30 | #include "internal.h" |
||
31 | #include "libavutil/internal.h" |
||
32 | #include "libavutil/mem.h" |
||
33 | #include "libavutil/opt.h" |
||
34 | |||
35 | #define END_OF_STREAM 0x001 |
||
36 | |||
37 | #define XAVS_PART_I8X8 0x002 /* Analyze i8x8 (requires 8x8 transform) */ |
||
38 | #define XAVS_PART_P8X8 0x010 /* Analyze p16x8, p8x16 and p8x8 */ |
||
39 | #define XAVS_PART_B8X8 0x100 /* Analyze b16x8, b*/ |
||
40 | |||
41 | typedef struct XavsContext { |
||
42 | AVClass *class; |
||
43 | xavs_param_t params; |
||
44 | xavs_t *enc; |
||
45 | xavs_picture_t pic; |
||
46 | uint8_t *sei; |
||
47 | int sei_size; |
||
48 | AVFrame out_pic; |
||
49 | int end_of_stream; |
||
50 | float crf; |
||
51 | int cqp; |
||
52 | int b_bias; |
||
53 | float cplxblur; |
||
54 | int direct_pred; |
||
55 | int aud; |
||
56 | int fast_pskip; |
||
57 | int mbtree; |
||
58 | int mixed_refs; |
||
59 | |||
60 | int64_t *pts_buffer; |
||
61 | int out_frame_count; |
||
62 | } XavsContext; |
||
63 | |||
64 | static void XAVS_log(void *p, int level, const char *fmt, va_list args) |
||
65 | { |
||
66 | static const int level_map[] = { |
||
67 | [XAVS_LOG_ERROR] = AV_LOG_ERROR, |
||
68 | [XAVS_LOG_WARNING] = AV_LOG_WARNING, |
||
69 | [XAVS_LOG_INFO] = AV_LOG_INFO, |
||
70 | [XAVS_LOG_DEBUG] = AV_LOG_DEBUG |
||
71 | }; |
||
72 | |||
73 | if (level < 0 || level > XAVS_LOG_DEBUG) |
||
74 | return; |
||
75 | |||
76 | av_vlog(p, level_map[level], fmt, args); |
||
77 | } |
||
78 | |||
79 | static int encode_nals(AVCodecContext *ctx, AVPacket *pkt, |
||
80 | xavs_nal_t *nals, int nnal) |
||
81 | { |
||
82 | XavsContext *x4 = ctx->priv_data; |
||
83 | uint8_t *p; |
||
84 | int i, s, ret, size = x4->sei_size + FF_MIN_BUFFER_SIZE; |
||
85 | |||
86 | if (!nnal) |
||
87 | return 0; |
||
88 | |||
89 | for (i = 0; i < nnal; i++) |
||
90 | size += nals[i].i_payload; |
||
91 | |||
92 | if ((ret = ff_alloc_packet2(ctx, pkt, size)) < 0) |
||
93 | return ret; |
||
94 | p = pkt->data; |
||
95 | |||
96 | /* Write the SEI as part of the first frame. */ |
||
97 | if (x4->sei_size > 0 && nnal > 0) { |
||
98 | memcpy(p, x4->sei, x4->sei_size); |
||
99 | p += x4->sei_size; |
||
100 | x4->sei_size = 0; |
||
101 | } |
||
102 | |||
103 | for (i = 0; i < nnal; i++) { |
||
104 | s = xavs_nal_encode(p, &size, 1, nals + i); |
||
105 | if (s < 0) |
||
106 | return -1; |
||
107 | p += s; |
||
108 | } |
||
109 | pkt->size = p - pkt->data; |
||
110 | |||
111 | return 1; |
||
112 | } |
||
113 | |||
114 | static int XAVS_frame(AVCodecContext *ctx, AVPacket *pkt, |
||
115 | const AVFrame *frame, int *got_packet) |
||
116 | { |
||
117 | XavsContext *x4 = ctx->priv_data; |
||
118 | xavs_nal_t *nal; |
||
119 | int nnal, i, ret; |
||
120 | xavs_picture_t pic_out; |
||
121 | |||
122 | x4->pic.img.i_csp = XAVS_CSP_I420; |
||
123 | x4->pic.img.i_plane = 3; |
||
124 | |||
125 | if (frame) { |
||
126 | for (i = 0; i < 3; i++) { |
||
127 | x4->pic.img.plane[i] = frame->data[i]; |
||
128 | x4->pic.img.i_stride[i] = frame->linesize[i]; |
||
129 | } |
||
130 | |||
131 | x4->pic.i_pts = frame->pts; |
||
132 | x4->pic.i_type = XAVS_TYPE_AUTO; |
||
133 | x4->pts_buffer[ctx->frame_number % (ctx->max_b_frames+1)] = frame->pts; |
||
134 | } |
||
135 | |||
136 | if (xavs_encoder_encode(x4->enc, &nal, &nnal, |
||
137 | frame? &x4->pic: NULL, &pic_out) < 0) |
||
138 | return -1; |
||
139 | |||
140 | ret = encode_nals(ctx, pkt, nal, nnal); |
||
141 | |||
142 | if (ret < 0) |
||
143 | return -1; |
||
144 | |||
145 | if (!ret) { |
||
146 | if (!frame && !(x4->end_of_stream)) { |
||
147 | if ((ret = ff_alloc_packet2(ctx, pkt, 4)) < 0) |
||
148 | return ret; |
||
149 | |||
150 | pkt->data[0] = 0x0; |
||
151 | pkt->data[1] = 0x0; |
||
152 | pkt->data[2] = 0x01; |
||
153 | pkt->data[3] = 0xb1; |
||
154 | pkt->dts = 2*x4->pts_buffer[(x4->out_frame_count-1)%(ctx->max_b_frames+1)] - |
||
155 | x4->pts_buffer[(x4->out_frame_count-2)%(ctx->max_b_frames+1)]; |
||
156 | x4->end_of_stream = END_OF_STREAM; |
||
157 | *got_packet = 1; |
||
158 | } |
||
159 | return 0; |
||
160 | } |
||
161 | |||
162 | x4->out_pic.pts = pic_out.i_pts; |
||
163 | pkt->pts = pic_out.i_pts; |
||
164 | if (ctx->has_b_frames) { |
||
165 | if (!x4->out_frame_count) |
||
166 | pkt->dts = pkt->pts - (x4->pts_buffer[1] - x4->pts_buffer[0]); |
||
167 | else |
||
168 | pkt->dts = x4->pts_buffer[(x4->out_frame_count-1)%(ctx->max_b_frames+1)]; |
||
169 | } else |
||
170 | pkt->dts = pkt->pts; |
||
171 | |||
172 | switch (pic_out.i_type) { |
||
173 | case XAVS_TYPE_IDR: |
||
174 | case XAVS_TYPE_I: |
||
175 | x4->out_pic.pict_type = AV_PICTURE_TYPE_I; |
||
176 | break; |
||
177 | case XAVS_TYPE_P: |
||
178 | x4->out_pic.pict_type = AV_PICTURE_TYPE_P; |
||
179 | break; |
||
180 | case XAVS_TYPE_B: |
||
181 | case XAVS_TYPE_BREF: |
||
182 | x4->out_pic.pict_type = AV_PICTURE_TYPE_B; |
||
183 | break; |
||
184 | } |
||
185 | |||
186 | /* There is no IDR frame in AVS JiZhun */ |
||
187 | /* Sequence header is used as a flag */ |
||
188 | if (pic_out.i_type == XAVS_TYPE_I) { |
||
189 | x4->out_pic.key_frame = 1; |
||
190 | pkt->flags |= AV_PKT_FLAG_KEY; |
||
191 | } |
||
192 | |||
193 | x4->out_pic.quality = (pic_out.i_qpplus1 - 1) * FF_QP2LAMBDA; |
||
194 | |||
195 | x4->out_frame_count++; |
||
196 | *got_packet = ret; |
||
197 | return 0; |
||
198 | } |
||
199 | |||
200 | static av_cold int XAVS_close(AVCodecContext *avctx) |
||
201 | { |
||
202 | XavsContext *x4 = avctx->priv_data; |
||
203 | |||
204 | av_freep(&avctx->extradata); |
||
205 | av_free(x4->sei); |
||
206 | av_freep(&x4->pts_buffer); |
||
207 | |||
208 | if (x4->enc) |
||
209 | xavs_encoder_close(x4->enc); |
||
210 | |||
211 | return 0; |
||
212 | } |
||
213 | |||
214 | static av_cold int XAVS_init(AVCodecContext *avctx) |
||
215 | { |
||
216 | XavsContext *x4 = avctx->priv_data; |
||
217 | |||
218 | x4->sei_size = 0; |
||
219 | xavs_param_default(&x4->params); |
||
220 | |||
221 | x4->params.pf_log = XAVS_log; |
||
222 | x4->params.p_log_private = avctx; |
||
223 | x4->params.i_keyint_max = avctx->gop_size; |
||
224 | if (avctx->bit_rate) { |
||
225 | x4->params.rc.i_bitrate = avctx->bit_rate / 1000; |
||
226 | x4->params.rc.i_rc_method = XAVS_RC_ABR; |
||
227 | } |
||
228 | x4->params.rc.i_vbv_buffer_size = avctx->rc_buffer_size / 1000; |
||
229 | x4->params.rc.i_vbv_max_bitrate = avctx->rc_max_rate / 1000; |
||
230 | x4->params.rc.b_stat_write = avctx->flags & CODEC_FLAG_PASS1; |
||
231 | if (avctx->flags & CODEC_FLAG_PASS2) { |
||
232 | x4->params.rc.b_stat_read = 1; |
||
233 | } else { |
||
234 | if (x4->crf >= 0) { |
||
235 | x4->params.rc.i_rc_method = XAVS_RC_CRF; |
||
236 | x4->params.rc.f_rf_constant = x4->crf; |
||
237 | } else if (x4->cqp >= 0) { |
||
238 | x4->params.rc.i_rc_method = XAVS_RC_CQP; |
||
239 | x4->params.rc.i_qp_constant = x4->cqp; |
||
240 | } |
||
241 | } |
||
242 | |||
243 | if (x4->aud >= 0) |
||
244 | x4->params.b_aud = x4->aud; |
||
245 | if (x4->mbtree >= 0) |
||
246 | x4->params.rc.b_mb_tree = x4->mbtree; |
||
247 | if (x4->direct_pred >= 0) |
||
248 | x4->params.analyse.i_direct_mv_pred = x4->direct_pred; |
||
249 | if (x4->fast_pskip >= 0) |
||
250 | x4->params.analyse.b_fast_pskip = x4->fast_pskip; |
||
251 | if (x4->mixed_refs >= 0) |
||
252 | x4->params.analyse.b_mixed_references = x4->mixed_refs; |
||
253 | if (x4->b_bias != INT_MIN) |
||
254 | x4->params.i_bframe_bias = x4->b_bias; |
||
255 | if (x4->cplxblur >= 0) |
||
256 | x4->params.rc.f_complexity_blur = x4->cplxblur; |
||
257 | |||
258 | x4->params.i_bframe = avctx->max_b_frames; |
||
259 | /* cabac is not included in AVS JiZhun Profile */ |
||
260 | x4->params.b_cabac = 0; |
||
261 | |||
262 | x4->params.i_bframe_adaptive = avctx->b_frame_strategy; |
||
263 | |||
264 | avctx->has_b_frames = !!avctx->max_b_frames; |
||
265 | |||
266 | /* AVS doesn't allow B picture as reference */ |
||
267 | /* The max allowed reference frame number of B is 2 */ |
||
268 | x4->params.i_keyint_min = avctx->keyint_min; |
||
269 | if (x4->params.i_keyint_min > x4->params.i_keyint_max) |
||
270 | x4->params.i_keyint_min = x4->params.i_keyint_max; |
||
271 | |||
272 | x4->params.i_scenecut_threshold = avctx->scenechange_threshold; |
||
273 | |||
274 | // x4->params.b_deblocking_filter = avctx->flags & CODEC_FLAG_LOOP_FILTER; |
||
275 | |||
276 | x4->params.rc.i_qp_min = avctx->qmin; |
||
277 | x4->params.rc.i_qp_max = avctx->qmax; |
||
278 | x4->params.rc.i_qp_step = avctx->max_qdiff; |
||
279 | |||
280 | x4->params.rc.f_qcompress = avctx->qcompress; /* 0.0 => cbr, 1.0 => constant qp */ |
||
281 | x4->params.rc.f_qblur = avctx->qblur; /* temporally blur quants */ |
||
282 | |||
283 | x4->params.i_frame_reference = avctx->refs; |
||
284 | |||
285 | x4->params.i_width = avctx->width; |
||
286 | x4->params.i_height = avctx->height; |
||
287 | x4->params.vui.i_sar_width = avctx->sample_aspect_ratio.num; |
||
288 | x4->params.vui.i_sar_height = avctx->sample_aspect_ratio.den; |
||
289 | /* This is only used for counting the fps */ |
||
290 | x4->params.i_fps_num = avctx->time_base.den; |
||
291 | x4->params.i_fps_den = avctx->time_base.num; |
||
292 | x4->params.analyse.inter = XAVS_ANALYSE_I8x8 |XAVS_ANALYSE_PSUB16x16| XAVS_ANALYSE_BSUB16x16; |
||
293 | |||
294 | switch (avctx->me_method) { |
||
295 | case ME_EPZS: |
||
296 | x4->params.analyse.i_me_method = XAVS_ME_DIA; |
||
297 | break; |
||
298 | case ME_HEX: |
||
299 | x4->params.analyse.i_me_method = XAVS_ME_HEX; |
||
300 | break; |
||
301 | case ME_UMH: |
||
302 | x4->params.analyse.i_me_method = XAVS_ME_UMH; |
||
303 | break; |
||
304 | case ME_FULL: |
||
305 | x4->params.analyse.i_me_method = XAVS_ME_ESA; |
||
306 | break; |
||
307 | case ME_TESA: |
||
308 | x4->params.analyse.i_me_method = XAVS_ME_TESA; |
||
309 | break; |
||
310 | default: |
||
311 | x4->params.analyse.i_me_method = XAVS_ME_HEX; |
||
312 | } |
||
313 | |||
314 | x4->params.analyse.i_me_range = avctx->me_range; |
||
315 | x4->params.analyse.i_subpel_refine = avctx->me_subpel_quality; |
||
316 | |||
317 | x4->params.analyse.b_chroma_me = avctx->me_cmp & FF_CMP_CHROMA; |
||
318 | /* AVS P2 only enables 8x8 transform */ |
||
319 | x4->params.analyse.b_transform_8x8 = 1; //avctx->flags2 & CODEC_FLAG2_8X8DCT; |
||
320 | |||
321 | x4->params.analyse.i_trellis = avctx->trellis; |
||
322 | x4->params.analyse.i_noise_reduction = avctx->noise_reduction; |
||
323 | |||
324 | if (avctx->level > 0) |
||
325 | x4->params.i_level_idc = avctx->level; |
||
326 | |||
327 | x4->params.rc.f_rate_tolerance = |
||
328 | (float)avctx->bit_rate_tolerance/avctx->bit_rate; |
||
329 | |||
330 | if ((avctx->rc_buffer_size) && |
||
331 | (avctx->rc_initial_buffer_occupancy <= avctx->rc_buffer_size)) { |
||
332 | x4->params.rc.f_vbv_buffer_init = |
||
333 | (float)avctx->rc_initial_buffer_occupancy / avctx->rc_buffer_size; |
||
334 | } else |
||
335 | x4->params.rc.f_vbv_buffer_init = 0.9; |
||
336 | |||
337 | /* TAG:do we have MB tree RC method */ |
||
338 | /* what is the RC method we are now using? Default NO */ |
||
339 | x4->params.rc.f_ip_factor = 1 / fabs(avctx->i_quant_factor); |
||
340 | x4->params.rc.f_pb_factor = avctx->b_quant_factor; |
||
341 | x4->params.analyse.i_chroma_qp_offset = avctx->chromaoffset; |
||
342 | |||
343 | x4->params.analyse.b_psnr = avctx->flags & CODEC_FLAG_PSNR; |
||
344 | x4->params.i_log_level = XAVS_LOG_DEBUG; |
||
345 | x4->params.i_threads = avctx->thread_count; |
||
346 | x4->params.b_interlaced = avctx->flags & CODEC_FLAG_INTERLACED_DCT; |
||
347 | |||
348 | if (avctx->flags & CODEC_FLAG_GLOBAL_HEADER) |
||
349 | x4->params.b_repeat_headers = 0; |
||
350 | |||
351 | x4->enc = xavs_encoder_open(&x4->params); |
||
352 | if (!x4->enc) |
||
353 | return -1; |
||
354 | |||
355 | if (!(x4->pts_buffer = av_mallocz((avctx->max_b_frames+1) * sizeof(*x4->pts_buffer)))) |
||
356 | return AVERROR(ENOMEM); |
||
357 | |||
358 | avctx->coded_frame = &x4->out_pic; |
||
359 | /* TAG: Do we have GLOBAL HEADER in AVS */ |
||
360 | /* We Have PPS and SPS in AVS */ |
||
361 | if (avctx->flags & CODEC_FLAG_GLOBAL_HEADER) { |
||
362 | xavs_nal_t *nal; |
||
363 | int nnal, s, i, size; |
||
364 | uint8_t *p; |
||
365 | |||
366 | s = xavs_encoder_headers(x4->enc, &nal, &nnal); |
||
367 | |||
368 | avctx->extradata = p = av_malloc(s); |
||
369 | for (i = 0; i < nnal; i++) { |
||
370 | /* Don't put the SEI in extradata. */ |
||
371 | if (nal[i].i_type == NAL_SEI) { |
||
372 | x4->sei = av_malloc( 5 + nal[i].i_payload * 4 / 3 ); |
||
373 | if (xavs_nal_encode(x4->sei, &x4->sei_size, 1, nal + i) < 0) |
||
374 | return -1; |
||
375 | |||
376 | continue; |
||
377 | } |
||
378 | size = xavs_nal_encode(p, &s, 1, nal + i); |
||
379 | if (size < 0) |
||
380 | return -1; |
||
381 | p += size; |
||
382 | } |
||
383 | avctx->extradata_size = p - avctx->extradata; |
||
384 | } |
||
385 | return 0; |
||
386 | } |
||
387 | |||
388 | #define OFFSET(x) offsetof(XavsContext, x) |
||
389 | #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM |
||
390 | static const AVOption options[] = { |
||
391 | { "crf", "Select the quality for constant quality mode", OFFSET(crf), AV_OPT_TYPE_FLOAT, {.dbl = -1 }, -1, FLT_MAX, VE }, |
||
392 | { "qp", "Constant quantization parameter rate control method",OFFSET(cqp), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, INT_MAX, VE }, |
||
393 | { "b-bias", "Influences how often B-frames are used", OFFSET(b_bias), AV_OPT_TYPE_INT, {.i64 = INT_MIN}, INT_MIN, INT_MAX, VE }, |
||
394 | { "cplxblur", "Reduce fluctuations in QP (before curve compression)", OFFSET(cplxblur), AV_OPT_TYPE_FLOAT, {.dbl = -1 }, -1, FLT_MAX, VE}, |
||
395 | { "direct-pred", "Direct MV prediction mode", OFFSET(direct_pred), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, INT_MAX, VE, "direct-pred" }, |
||
396 | { "none", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = XAVS_DIRECT_PRED_NONE }, 0, 0, VE, "direct-pred" }, |
||
397 | { "spatial", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = XAVS_DIRECT_PRED_SPATIAL }, 0, 0, VE, "direct-pred" }, |
||
398 | { "temporal", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = XAVS_DIRECT_PRED_TEMPORAL }, 0, 0, VE, "direct-pred" }, |
||
399 | { "auto", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = XAVS_DIRECT_PRED_AUTO }, 0, 0, VE, "direct-pred" }, |
||
400 | { "aud", "Use access unit delimiters.", OFFSET(aud), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, 1, VE}, |
||
401 | { "mbtree", "Use macroblock tree ratecontrol.", OFFSET(mbtree), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, 1, VE}, |
||
402 | { "mixed-refs", "One reference per partition, as opposed to one reference per macroblock", OFFSET(mixed_refs), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 1, VE }, |
||
403 | { "fast-pskip", NULL, OFFSET(fast_pskip), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, 1, VE}, |
||
404 | { NULL }, |
||
405 | }; |
||
406 | |||
407 | static const AVClass xavs_class = { |
||
408 | .class_name = "libxavs", |
||
409 | .item_name = av_default_item_name, |
||
410 | .option = options, |
||
411 | .version = LIBAVUTIL_VERSION_INT, |
||
412 | }; |
||
413 | |||
414 | static const AVCodecDefault xavs_defaults[] = { |
||
415 | { "b", "0" }, |
||
416 | { NULL }, |
||
417 | }; |
||
418 | |||
419 | AVCodec ff_libxavs_encoder = { |
||
420 | .name = "libxavs", |
||
421 | .long_name = NULL_IF_CONFIG_SMALL("libxavs Chinese AVS (Audio Video Standard)"), |
||
422 | .type = AVMEDIA_TYPE_VIDEO, |
||
423 | .id = AV_CODEC_ID_CAVS, |
||
424 | .priv_data_size = sizeof(XavsContext), |
||
425 | .init = XAVS_init, |
||
426 | .encode2 = XAVS_frame, |
||
427 | .close = XAVS_close, |
||
428 | .capabilities = CODEC_CAP_DELAY | CODEC_CAP_AUTO_THREADS, |
||
429 | .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE }, |
||
430 | .priv_class = &xavs_class, |
||
431 | .defaults = xavs_defaults, |
||
432 | };>>>=>>>>>>>>>> |