source: libpipi/trunk/pipi/sequence.c @ 4700

Last change on this file since 4700 was 4700, checked in by Sam Hocevar, 10 years ago

Import x264 presets into sequence.c. Doesn't work properly yet.

File size: 8.2 KB
Line 
1/*
2 *  libpipi       Pathetic image processing interface library
3 *  Copyright (c) 2004-2009 Sam Hocevar <sam@hocevar.net>
4 *                All Rights Reserved
5 *
6 *  $Id$
7 *
8 *  This library is free software. It comes without any warranty, to
9 *  the extent permitted by applicable law. You can redistribute it
10 *  and/or modify it under the terms of the Do What The Fuck You Want
11 *  To Public License, Version 2, as published by Sam Hocevar. See
12 *  http://sam.zoy.org/wtfpl/COPYING for more details.
13 */
14
15/*
16 * codec.c: image I/O functions
17 */
18
19#include "config.h"
20
21#if defined _WIN32
22#   undef _CRT_SECURE_NO_WARNINGS
23#   define _CRT_SECURE_NO_WARNINGS /* I know how to use snprintf, thank you */
24#   define snprintf _snprintf
25#endif
26
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30
31#if defined USE_FFMPEG
32#   include <libavformat/avformat.h>
33#   include <libswscale/swscale.h>
34#endif
35
36#include "pipi.h"
37#include "pipi_internals.h"
38
39#if defined USE_FFMPEG
40typedef struct
41{
42    uint8_t *buf;
43    size_t buf_len;
44
45    AVFormatContext *fmt_ctx;
46    AVStream *stream;
47    AVCodecContext *cod_ctx;
48    AVCodec *codec;
49    AVFrame *frame;
50
51    struct SwsContext *sws_ctx;
52    int src_width, src_height;
53}
54ffmpeg_codec_t;
55#endif
56
57pipi_sequence_t *pipi_open_sequence(char const *file,
58                                    int width, int height, int fps,
59                                    int par_num, int par_den, int bitrate)
60{
61#if defined USE_FFMPEG
62    static int initialised = 0;
63
64    pipi_sequence_t *seq;
65    ffmpeg_codec_t *ff;
66    uint8_t *tmp;
67
68    seq = malloc(sizeof(pipi_sequence_t));
69    seq->w = width;
70    seq->h = height;
71    seq->fps = fps;
72
73    ff = malloc(sizeof(ffmpeg_codec_t));
74    memset(ff, 0, sizeof(*ff));
75
76    seq->codec_priv = ff;
77
78    if (!initialised)
79    {
80        av_register_all();
81        initialised = 1;
82    }
83
84    ff->fmt_ctx = avformat_alloc_context();
85    if (!ff->fmt_ctx)
86        goto error;
87
88    /* Careful here: the Win32 snprintf doesn't seem to add a trailing
89     * zero to the truncated output. */
90    snprintf(ff->fmt_ctx->filename, sizeof(ff->fmt_ctx->filename),
91             file);
92    ff->fmt_ctx->filename[sizeof(ff->fmt_ctx->filename) - 1] = '\0';
93
94    ff->fmt_ctx->oformat = av_guess_format(NULL, file, NULL);
95    if (!ff->fmt_ctx->oformat)
96        ff->fmt_ctx->oformat = av_guess_format("mpeg", NULL, NULL);
97    if (!ff->fmt_ctx->oformat)
98        goto error;
99
100    ff->stream = av_new_stream(ff->fmt_ctx, 0);
101    if (!ff->stream)
102        goto error;
103
104    ff->stream->sample_aspect_ratio.num = par_num;
105    ff->stream->sample_aspect_ratio.den = par_den;
106
107    ff->cod_ctx = ff->stream->codec;
108
109    ff->cod_ctx->width = width;
110    ff->cod_ctx->height = height;
111    ff->cod_ctx->sample_aspect_ratio.num = par_num;
112    ff->cod_ctx->sample_aspect_ratio.den = par_den;
113    ff->cod_ctx->codec_id = ff->fmt_ctx->oformat->video_codec;
114    ff->cod_ctx->codec_type = CODEC_TYPE_VIDEO;
115    ff->cod_ctx->bit_rate = bitrate;
116    ff->cod_ctx->time_base.num = 1;
117    ff->cod_ctx->time_base.den = fps;
118
119    ff->cod_ctx->pix_fmt = PIX_FMT_YUV420P; /* send YUV 420 */
120    if (ff->cod_ctx->codec_id == CODEC_ID_MPEG2VIDEO)
121        ff->cod_ctx->max_b_frames = 2;
122    if (ff->cod_ctx->codec_id == CODEC_ID_MPEG1VIDEO)
123        ff->cod_ctx->mb_decision = 2;
124    if (ff->cod_ctx->codec_id == CODEC_ID_H264)
125    {
126        /* Import x264 slow presets */
127        ff->cod_ctx->coder_type = 1;
128        ff->cod_ctx->flags |= CODEC_FLAG_LOOP_FILTER;
129        ff->cod_ctx->me_cmp |= FF_CMP_CHROMA;
130        ff->cod_ctx->partitions |= X264_PART_I4X4 | X264_PART_I8X8
131                                 | X264_PART_P4X4 | X264_PART_P8X8;
132        ff->cod_ctx->me_method = ME_UMH;
133        ff->cod_ctx->me_subpel_quality = 8;
134        ff->cod_ctx->me_range = 16;
135        ff->cod_ctx->gop_size = 250;
136        ff->cod_ctx->keyint_min = 25;
137        ff->cod_ctx->scenechange_threshold = 40;
138        ff->cod_ctx->i_quant_factor = 0.71f;
139        ff->cod_ctx->b_frame_strategy = 2;
140        ff->cod_ctx->qcompress = 0.6f;
141        ff->cod_ctx->qmin = 10;
142        ff->cod_ctx->qmax = 51;
143        ff->cod_ctx->max_qdiff = 4;
144        ff->cod_ctx->max_b_frames = 3;
145        ff->cod_ctx->refs = 5;
146        ff->cod_ctx->directpred = 3;
147        ff->cod_ctx->trellis = 1;
148        ff->cod_ctx->flags2 |= CODEC_FLAG2_BPYRAMID | CODEC_FLAG2_MIXED_REFS
149                             | CODEC_FLAG2_WPRED | CODEC_FLAG2_8X8DCT
150                             | CODEC_FLAG2_FASTPSKIP;
151        ff->cod_ctx->weighted_p_pred = 2;
152        ff->cod_ctx->rc_lookahead = 50;
153    }
154    if (ff->fmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
155        ff->cod_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER;
156
157    if (av_set_parameters(ff->fmt_ctx, NULL) < 0)
158        goto error;
159
160    ff->codec = avcodec_find_encoder(ff->cod_ctx->codec_id);
161    if (!ff->codec)
162        goto error;
163    if (avcodec_open(ff->cod_ctx, ff->codec) < 0)
164        goto error;
165
166    ff->frame = avcodec_alloc_frame();
167    if (!ff->frame)
168        goto error;
169    tmp = (uint8_t *)av_malloc(avpicture_get_size(ff->cod_ctx->pix_fmt,
170                                                  ff->cod_ctx->width,
171                                                  ff->cod_ctx->height));
172    if (!tmp)
173        goto error;
174    avpicture_fill((AVPicture *)ff->frame, tmp, ff->cod_ctx->pix_fmt,
175                   ff->cod_ctx->width, ff->cod_ctx->height);
176
177    if (!(ff->fmt_ctx->flags & AVFMT_NOFILE))
178        if (url_fopen(&ff->fmt_ctx->pb, file, URL_WRONLY) < 0)
179            goto error;
180
181    ff->buf_len = 64 * 1024 * 1024;
182    ff->buf = (uint8_t *)av_malloc(ff->buf_len);
183
184    av_write_header(ff->fmt_ctx);
185
186    return seq;
187
188error:
189    pipi_close_sequence(seq);
190    return NULL;
191
192#else
193    return NULL;
194
195#endif
196}
197
198int pipi_feed_sequence(pipi_sequence_t *seq, uint8_t const *buffer,
199                       int width, int height)
200{
201#if defined USE_FFMPEG
202    AVPacket packet;
203    size_t bytes;
204    int pitch;
205
206    ffmpeg_codec_t *ff = (ffmpeg_codec_t *)seq->codec_priv;
207
208    if (ff->src_width != width || ff->src_height != height)
209    {
210        ff->src_width = width;
211        ff->src_height = height;
212        if (ff->sws_ctx)
213            sws_freeContext(ff->sws_ctx);
214        ff->sws_ctx = NULL;
215    }
216
217    if (!ff->sws_ctx)
218        ff->sws_ctx = sws_getContext(width, height, PIX_FMT_RGB32,
219                                       ff->cod_ctx->width,
220                                       ff->cod_ctx->height,
221                                       ff->cod_ctx->pix_fmt, SWS_BICUBIC,
222                                       NULL, NULL, NULL);
223    if (!ff->sws_ctx)
224        return -1;
225
226    pitch = width * 4;
227    sws_scale(ff->sws_ctx, &buffer, &pitch, 0, height,
228              ff->frame->data, ff->frame->linesize);
229
230    bytes = avcodec_encode_video(ff->cod_ctx, ff->buf,
231                                 ff->buf_len, ff->frame);
232    if (bytes <= 0)
233        return 0;
234
235    av_init_packet(&packet);
236    if (ff->cod_ctx->coded_frame->pts != 0x8000000000000000LL)
237        packet.pts = av_rescale_q(ff->cod_ctx->coded_frame->pts,
238                                  ff->cod_ctx->time_base, ff->stream->time_base);
239    if (ff->cod_ctx->coded_frame->key_frame)
240        packet.flags |= PKT_FLAG_KEY;
241    packet.stream_index = 0;
242    packet.data = ff->buf;
243    packet.size = bytes;
244
245    if (av_interleaved_write_frame(ff->fmt_ctx, &packet) < 0)
246        return -1;
247#endif
248
249    return 0;
250}
251
252int pipi_close_sequence(pipi_sequence_t *seq)
253{
254#if defined USE_FFMPEG
255    ffmpeg_codec_t *ff = (ffmpeg_codec_t *)seq->codec_priv;
256
257    if (ff->fmt_ctx)
258    {
259        av_write_trailer(ff->fmt_ctx);
260    }
261
262    if (ff->buf)
263    {
264        av_free(ff->buf);
265        ff->buf = NULL;
266    }
267
268    if (ff->cod_ctx)
269    {
270        avcodec_close(ff->cod_ctx);
271        ff->cod_ctx = NULL;
272    }
273
274    if (ff->frame)
275    {
276        av_free(ff->frame->data[0]);
277        av_free(ff->frame);
278        ff->frame = NULL;
279    }
280
281    if (ff->fmt_ctx)
282    {
283        av_freep(&ff->fmt_ctx->streams[0]->codec);
284        ff->codec = NULL;
285
286        av_freep(&ff->fmt_ctx->streams[0]);
287        ff->stream = NULL;
288
289        if (!(ff->fmt_ctx->flags & AVFMT_NOFILE))
290            url_fclose(ff->fmt_ctx->pb);
291
292        av_free(ff->fmt_ctx);
293        ff->fmt_ctx = NULL;
294    }
295
296    if (ff->sws_ctx)
297    {
298        sws_freeContext(ff->sws_ctx);
299        ff->sws_ctx = NULL;
300        ff->src_width = ff->src_height = 0;
301    }
302
303    free(ff);
304    free(seq);
305#endif
306
307    return 0;
308}
Note: See TracBrowser for help on using the repository browser.