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

Last change on this file since 4704 was 4704, checked in by Sam Hocevar, 9 years ago

YUV support in dumpmovie and makemovie.

File size: 9.0 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    seq->convert_buf = NULL;
73
74    ff = malloc(sizeof(ffmpeg_codec_t));
75    memset(ff, 0, sizeof(*ff));
76
77    seq->codec_priv = ff;
78
79    if (!initialised)
80    {
81        av_register_all();
82        initialised = 1;
83    }
84
85    ff->fmt_ctx = avformat_alloc_context();
86    if (!ff->fmt_ctx)
87        goto error;
88
89    /* Careful here: the Win32 snprintf doesn't seem to add a trailing
90     * zero to the truncated output. */
91    snprintf(ff->fmt_ctx->filename, sizeof(ff->fmt_ctx->filename),
92             file);
93    ff->fmt_ctx->filename[sizeof(ff->fmt_ctx->filename) - 1] = '\0';
94
95    ff->fmt_ctx->oformat = av_guess_format(NULL, file, NULL);
96    if (!ff->fmt_ctx->oformat)
97        ff->fmt_ctx->oformat = av_guess_format("mpeg", NULL, NULL);
98    if (!ff->fmt_ctx->oformat)
99        goto error;
100
101    ff->stream = av_new_stream(ff->fmt_ctx, 0);
102    if (!ff->stream)
103        goto error;
104
105    ff->stream->sample_aspect_ratio.num = par_num;
106    ff->stream->sample_aspect_ratio.den = par_den;
107
108    ff->cod_ctx = ff->stream->codec;
109
110    ff->cod_ctx->width = width;
111    ff->cod_ctx->height = height;
112    ff->cod_ctx->sample_aspect_ratio.num = par_num;
113    ff->cod_ctx->sample_aspect_ratio.den = par_den;
114    ff->cod_ctx->codec_id = ff->fmt_ctx->oformat->video_codec;
115    ff->cod_ctx->codec_type = CODEC_TYPE_VIDEO;
116    ff->cod_ctx->bit_rate = bitrate;
117    ff->cod_ctx->time_base.num = 1;
118    ff->cod_ctx->time_base.den = fps;
119
120    ff->cod_ctx->pix_fmt = PIX_FMT_YUV420P; /* send YUV 420 */
121    if (ff->cod_ctx->codec_id == CODEC_ID_MPEG2VIDEO)
122        ff->cod_ctx->max_b_frames = 2;
123    if (ff->cod_ctx->codec_id == CODEC_ID_MPEG1VIDEO)
124        ff->cod_ctx->mb_decision = 2;
125    if (ff->cod_ctx->codec_id == CODEC_ID_H264)
126    {
127        /* Import x264 slow presets */
128        ff->cod_ctx->coder_type = 1;
129        ff->cod_ctx->flags |= CODEC_FLAG_LOOP_FILTER;
130        ff->cod_ctx->me_cmp |= FF_CMP_CHROMA;
131        ff->cod_ctx->partitions |= X264_PART_I4X4 | X264_PART_I8X8
132                                 | X264_PART_P4X4 | X264_PART_P8X8;
133        ff->cod_ctx->me_method = ME_UMH;
134        ff->cod_ctx->me_subpel_quality = 8;
135        ff->cod_ctx->me_range = 16;
136        ff->cod_ctx->gop_size = 250;
137        ff->cod_ctx->keyint_min = 25;
138        ff->cod_ctx->scenechange_threshold = 40;
139        ff->cod_ctx->i_quant_factor = 0.71f;
140        ff->cod_ctx->b_frame_strategy = 2;
141        ff->cod_ctx->qcompress = 0.6f;
142        ff->cod_ctx->qmin = 10;
143        ff->cod_ctx->qmax = 51;
144        ff->cod_ctx->max_qdiff = 4;
145        ff->cod_ctx->max_b_frames = 3;
146        ff->cod_ctx->refs = 5;
147        ff->cod_ctx->directpred = 3;
148        ff->cod_ctx->trellis = 1;
149        ff->cod_ctx->flags2 |= CODEC_FLAG2_BPYRAMID | CODEC_FLAG2_MIXED_REFS
150                             | CODEC_FLAG2_WPRED | CODEC_FLAG2_8X8DCT
151                             | CODEC_FLAG2_FASTPSKIP;
152        ff->cod_ctx->weighted_p_pred = 2;
153        ff->cod_ctx->rc_lookahead = 50;
154    }
155    if (ff->fmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
156        ff->cod_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER;
157
158    if (av_set_parameters(ff->fmt_ctx, NULL) < 0)
159        goto error;
160
161    ff->codec = avcodec_find_encoder(ff->cod_ctx->codec_id);
162    if (!ff->codec)
163        goto error;
164    if (avcodec_open(ff->cod_ctx, ff->codec) < 0)
165        goto error;
166
167    ff->frame = avcodec_alloc_frame();
168    if (!ff->frame)
169        goto error;
170    tmp = (uint8_t *)av_malloc(avpicture_get_size(ff->cod_ctx->pix_fmt,
171                                                  ff->cod_ctx->width,
172                                                  ff->cod_ctx->height));
173    if (!tmp)
174        goto error;
175    avpicture_fill((AVPicture *)ff->frame, tmp, ff->cod_ctx->pix_fmt,
176                   ff->cod_ctx->width, ff->cod_ctx->height);
177
178    if (!(ff->fmt_ctx->flags & AVFMT_NOFILE))
179        if (url_fopen(&ff->fmt_ctx->pb, file, URL_WRONLY) < 0)
180            goto error;
181
182    ff->buf_len = 64 * 1024 * 1024;
183    ff->buf = (uint8_t *)av_malloc(ff->buf_len);
184
185    av_write_header(ff->fmt_ctx);
186
187    return seq;
188
189error:
190    pipi_close_sequence(seq);
191    return NULL;
192
193#else
194    return NULL;
195
196#endif
197}
198
199int pipi_feed_sequence(pipi_sequence_t *seq, uint8_t const *buffer,
200                       int width, int height)
201{
202#if defined USE_FFMPEG
203    AVPacket packet;
204    uint8_t const *buflist[3];
205    int pitchlist[3];
206    size_t bytes;
207    int n;
208
209    ffmpeg_codec_t *ff = (ffmpeg_codec_t *)seq->codec_priv;
210
211    if (ff->src_width != width || ff->src_height != height)
212    {
213        ff->src_width = width;
214        ff->src_height = height;
215        if (ff->sws_ctx)
216            sws_freeContext(ff->sws_ctx);
217        ff->sws_ctx = NULL;
218    }
219
220    if (!ff->sws_ctx)
221    {
222        ff->sws_ctx = sws_getContext(width, height, PIX_FMT_YUV444P,
223                                     ff->cod_ctx->width,
224                                     ff->cod_ctx->height,
225                                     ff->cod_ctx->pix_fmt, SWS_BICUBIC,
226                                     NULL, NULL, NULL);
227        if (seq->convert_buf)
228        {
229           free(seq->convert_buf);
230           seq->convert_buf = NULL;
231        }
232    }
233    if (!ff->sws_ctx)
234        return -1;
235
236    /* Convert interleaved YUV to planar YUV */
237    if (!seq->convert_buf)
238        seq->convert_buf = malloc(width * height * 3);
239
240    for (n = 0; n < width * height; n++)
241    {
242        seq->convert_buf[n] = buffer[4 * n];
243        seq->convert_buf[n + width * height] = buffer[4 * n + 1];
244        seq->convert_buf[n + 2 * width * height] = buffer[4 * n + 2];
245    }
246
247    /* Feed the buffers to FFmpeg */
248    buflist[0] = seq->convert_buf;
249    buflist[1] = seq->convert_buf + 2 * width * height;
250    buflist[2] = seq->convert_buf + width * height;
251    pitchlist[0] = pitchlist[1] = pitchlist[2] = width;
252    sws_scale(ff->sws_ctx, buflist, pitchlist, 0, height,
253              ff->frame->data, ff->frame->linesize);
254
255    bytes = avcodec_encode_video(ff->cod_ctx, ff->buf,
256                                 ff->buf_len, ff->frame);
257    if (bytes <= 0)
258        return 0;
259
260    av_init_packet(&packet);
261    if (ff->cod_ctx->coded_frame->pts != 0x8000000000000000LL)
262        packet.pts = av_rescale_q(ff->cod_ctx->coded_frame->pts,
263                                  ff->cod_ctx->time_base, ff->stream->time_base);
264    if (ff->cod_ctx->coded_frame->key_frame)
265        packet.flags |= PKT_FLAG_KEY;
266    packet.stream_index = 0;
267    packet.data = ff->buf;
268    packet.size = bytes;
269
270    if (av_interleaved_write_frame(ff->fmt_ctx, &packet) < 0)
271        return -1;
272#endif
273
274    return 0;
275}
276
277int pipi_close_sequence(pipi_sequence_t *seq)
278{
279#if defined USE_FFMPEG
280    ffmpeg_codec_t *ff = (ffmpeg_codec_t *)seq->codec_priv;
281
282    if (ff->fmt_ctx)
283    {
284        av_write_trailer(ff->fmt_ctx);
285    }
286
287    if (ff->buf)
288    {
289        av_free(ff->buf);
290        ff->buf = NULL;
291    }
292
293    if (ff->cod_ctx)
294    {
295        avcodec_close(ff->cod_ctx);
296        ff->cod_ctx = NULL;
297    }
298
299    if (ff->frame)
300    {
301        av_free(ff->frame->data[0]);
302        av_free(ff->frame);
303        ff->frame = NULL;
304    }
305
306    if (ff->fmt_ctx)
307    {
308        av_freep(&ff->fmt_ctx->streams[0]->codec);
309        ff->codec = NULL;
310
311        av_freep(&ff->fmt_ctx->streams[0]);
312        ff->stream = NULL;
313
314        if (!(ff->fmt_ctx->flags & AVFMT_NOFILE))
315            url_fclose(ff->fmt_ctx->pb);
316
317        av_free(ff->fmt_ctx);
318        ff->fmt_ctx = NULL;
319    }
320
321    if (ff->sws_ctx)
322    {
323        sws_freeContext(ff->sws_ctx);
324        ff->sws_ctx = NULL;
325        ff->src_width = ff->src_height = 0;
326    }
327
328    free(ff);
329    free(seq);
330#endif
331
332    return 0;
333}
Note: See TracBrowser for help on using the repository browser.