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

Last change on this file since 4690 was 3630, checked in by Sam Hocevar, 11 years ago

Mark pipi_open_sequence's first argument as const.

File size: 7.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
57#define PAR_NUM 1
58#define PAR_DEN 1
59#define BITRATE (16 * 1024 * 1024)
60
61pipi_sequence_t *pipi_open_sequence(char const *file,
62                                    int width, int height, int fps)
63{
64#if defined USE_FFMPEG
65    static int initialised = 0;
66
67    pipi_sequence_t *seq;
68    ffmpeg_codec_t *ff;
69    uint8_t *tmp;
70
71    seq = malloc(sizeof(pipi_sequence_t));
72    seq->w = width;
73    seq->h = height;
74    seq->fps = fps;
75
76    ff = malloc(sizeof(ffmpeg_codec_t));
77    memset(ff, 0, sizeof(*ff));
78
79    seq->codec_priv = ff;
80
81    if (!initialised)
82    {
83        av_register_all();
84        initialised = 1;
85    }
86
87    ff->fmt_ctx = avformat_alloc_context();
88    if (!ff->fmt_ctx)
89        goto error;
90
91    /* Careful here: the Win32 snprintf doesn't seem to add a trailing
92     * zero to the truncated output. */
93    snprintf(ff->fmt_ctx->filename, sizeof(ff->fmt_ctx->filename),
94             file);
95    ff->fmt_ctx->filename[sizeof(ff->fmt_ctx->filename) - 1] = '\0';
96
97    ff->fmt_ctx->oformat = guess_format(NULL, file, NULL);
98    if (!ff->fmt_ctx->oformat)
99        ff->fmt_ctx->oformat = guess_format("mpeg", NULL, NULL);
100    if (!ff->fmt_ctx->oformat)
101        goto error;
102
103    ff->stream = av_new_stream(ff->fmt_ctx, 0);
104    if (!ff->stream)
105        goto error;
106
107    ff->stream->sample_aspect_ratio.num = PAR_NUM;
108    ff->stream->sample_aspect_ratio.den = PAR_DEN;
109
110    ff->cod_ctx = ff->stream->codec;
111
112    ff->cod_ctx->width = width;
113    ff->cod_ctx->height = height;
114    ff->cod_ctx->sample_aspect_ratio.num = PAR_NUM;
115    ff->cod_ctx->sample_aspect_ratio.den = PAR_DEN;
116    ff->cod_ctx->codec_id = ff->fmt_ctx->oformat->video_codec;
117    ff->cod_ctx->codec_type = CODEC_TYPE_VIDEO;
118    ff->cod_ctx->bit_rate = BITRATE;
119    ff->cod_ctx->time_base.num = 1;
120    ff->cod_ctx->time_base.den = fps;
121    ff->cod_ctx->gop_size = fps * 3 / 4; /* empirical */
122    ff->cod_ctx->pix_fmt = PIX_FMT_YUV420P; /* send YUV 420 */
123    if (ff->cod_ctx->codec_id == CODEC_ID_MPEG2VIDEO)
124        ff->cod_ctx->max_b_frames = 2;
125    if (ff->cod_ctx->codec_id == CODEC_ID_MPEG1VIDEO)
126        ff->cod_ctx->mb_decision = 2;
127    if (ff->fmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
128        ff->cod_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER;
129
130    if (av_set_parameters(ff->fmt_ctx, NULL) < 0)
131        goto error;
132
133    ff->codec = avcodec_find_encoder(ff->cod_ctx->codec_id);
134    if (!ff->codec)
135        goto error;
136    if (avcodec_open(ff->cod_ctx, ff->codec) < 0)
137        goto error;
138
139    ff->frame = avcodec_alloc_frame();
140    if (!ff->frame)
141        goto error;
142    tmp = (uint8_t *)av_malloc(avpicture_get_size(ff->cod_ctx->pix_fmt,
143                                                  ff->cod_ctx->width,
144                                                  ff->cod_ctx->height));
145    if (!tmp)
146        goto error;
147    avpicture_fill((AVPicture *)ff->frame, tmp, ff->cod_ctx->pix_fmt,
148                   ff->cod_ctx->width, ff->cod_ctx->height);
149
150    if (!(ff->fmt_ctx->flags & AVFMT_NOFILE))
151        if (url_fopen(&ff->fmt_ctx->pb, file, URL_WRONLY) < 0)
152            goto error;
153
154    ff->buf_len = 64 * 1024 * 1024;
155    ff->buf = (uint8_t *)av_malloc(ff->buf_len);
156
157    av_write_header(ff->fmt_ctx);
158
159    return seq;
160
161error:
162    pipi_close_sequence(seq);
163    return NULL;
164
165#else
166    return NULL;
167
168#endif
169}
170
171int pipi_feed_sequence(pipi_sequence_t *seq, uint8_t *buffer, int width, int height)
172{
173#if defined USE_FFMPEG
174    AVPacket packet;
175    size_t bytes;
176    int pitch;
177
178    ffmpeg_codec_t *ff = (ffmpeg_codec_t *)seq->codec_priv;
179
180    if (ff->src_width != width || ff->src_height != height)
181    {
182        ff->src_width = width;
183        ff->src_height = height;
184        if (ff->sws_ctx)
185            sws_freeContext(ff->sws_ctx);
186        ff->sws_ctx = NULL;
187    }
188
189    if (!ff->sws_ctx)
190        ff->sws_ctx = sws_getContext(width, height, PIX_FMT_RGB32,
191                                       ff->cod_ctx->width,
192                                       ff->cod_ctx->height,
193                                       ff->cod_ctx->pix_fmt, SWS_BICUBIC,
194                                       NULL, NULL, NULL);
195    if (!ff->sws_ctx)
196        return -1;
197
198    pitch = width * 4;
199    sws_scale(ff->sws_ctx, &buffer, &pitch, 0, height,
200              ff->frame->data, ff->frame->linesize);
201
202    bytes = avcodec_encode_video(ff->cod_ctx, ff->buf,
203                                 ff->buf_len, ff->frame);
204    if (bytes <= 0)
205        return 0;
206
207    av_init_packet(&packet);
208    if (ff->cod_ctx->coded_frame->pts != 0x8000000000000000LL)
209        packet.pts = av_rescale_q(ff->cod_ctx->coded_frame->pts,
210                                  ff->cod_ctx->time_base, ff->stream->time_base);
211    if (ff->cod_ctx->coded_frame->key_frame)
212        packet.flags |= PKT_FLAG_KEY;
213    packet.stream_index = 0;
214    packet.data = ff->buf;
215    packet.size = bytes;
216
217    if (av_interleaved_write_frame(ff->fmt_ctx, &packet) < 0)
218        return -1;
219#endif
220
221    return 0;
222}
223
224int pipi_close_sequence(pipi_sequence_t *seq)
225{
226#if defined USE_FFMPEG
227    ffmpeg_codec_t *ff = (ffmpeg_codec_t *)seq->codec_priv;
228
229    if (ff->fmt_ctx)
230    {
231        av_write_trailer(ff->fmt_ctx);
232    }
233
234    if (ff->buf)
235    {
236        av_free(ff->buf);
237        ff->buf = NULL;
238    }
239
240    if (ff->cod_ctx)
241    {
242        avcodec_close(ff->cod_ctx);
243        ff->cod_ctx = NULL;
244    }
245
246    if (ff->frame)
247    {
248        av_free(ff->frame->data[0]);
249        av_free(ff->frame);
250        ff->frame = NULL;
251    }
252
253    if (ff->fmt_ctx)
254    {
255        av_freep(&ff->fmt_ctx->streams[0]->codec);
256        ff->codec = NULL;
257
258        av_freep(&ff->fmt_ctx->streams[0]);
259        ff->stream = NULL;
260
261        if (!(ff->fmt_ctx->flags & AVFMT_NOFILE))
262            url_fclose(ff->fmt_ctx->pb);
263
264        av_free(ff->fmt_ctx);
265        ff->fmt_ctx = NULL;
266    }
267
268    if (ff->sws_ctx)
269    {
270        sws_freeContext(ff->sws_ctx);
271        ff->sws_ctx = NULL;
272        ff->src_width = ff->src_height = 0;
273    }
274
275    free(ff);
276    free(seq);
277#endif
278
279    return 0;
280}
Note: See TracBrowser for help on using the repository browser.