Statistics
| Branch: | Revision:

ffmpeg / libavcodec / libtheoraenc.c @ 99ed41a8

History | View | Annotate | Download (8.71 KB)

1
/*
2
 * Copyright (c) 2006 Paul Richards <paul.richards@gmail.com>
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 Lesser General Public
8
 * License as published by the Free Software Foundation; either
9
 * version 2.1 of the License, or (at your option) any later version.
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
 * Lesser General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Lesser 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 libtheoraenc.c
23
 * \brief Theora encoder using libtheora.
24
 * \author Paul Richards <paul.richards@gmail.com>
25
 *
26
 * A lot of this is copy / paste from other output codecs in
27
 * libavcodec or pure guesswork (or both).
28
 *
29
 * I have used t_ prefixes on variables which are libtheora types
30
 * and o_ prefixes on variables which are libogg types.
31
 */
32

    
33
/* FFmpeg includes */
34
#include "libavutil/intreadwrite.h"
35
#include "libavutil/log.h"
36
#include "avcodec.h"
37

    
38
/* libtheora includes */
39
#include <theora/theora.h>
40

    
41
typedef struct TheoraContext{
42
    theora_state t_state;
43
} TheoraContext;
44

    
45
/*!
46
    Concatenates an ogg_packet into the extradata.
47
*/
48
static int concatenate_packet(unsigned int* offset, AVCodecContext* avc_context, const ogg_packet* packet)
49
{
50
    char* message = NULL;
51
    uint8_t* newdata = NULL;
52
    int newsize = avc_context->extradata_size + 2 + packet->bytes;
53

    
54
    if (packet->bytes < 0) {
55
        message = "ogg_packet has negative size";
56
    } else if (packet->bytes > 0xffff) {
57
        message = "ogg_packet is larger than 65535 bytes";
58
    } else if (newsize < avc_context->extradata_size) {
59
        message = "extradata_size would overflow";
60
    } else {
61
        newdata = av_realloc(avc_context->extradata, newsize);
62
        if (newdata == NULL) {
63
            message = "av_realloc failed";
64
        }
65
    }
66
    if (message != NULL) {
67
        av_log(avc_context, AV_LOG_ERROR, "concatenate_packet failed: %s\n", message);
68
        return -1;
69
    }
70

    
71
    avc_context->extradata = newdata;
72
    avc_context->extradata_size = newsize;
73
    AV_WB16(avc_context->extradata + (*offset), packet->bytes);
74
    *offset += 2;
75
    memcpy( avc_context->extradata + (*offset), packet->packet, packet->bytes );
76
    (*offset) += packet->bytes;
77
    return 0;
78
}
79

    
80
static int encode_init(AVCodecContext* avc_context)
81
{
82
    theora_info t_info;
83
    theora_comment t_comment;
84
    ogg_packet o_packet;
85
    unsigned int offset;
86
    TheoraContext *h = avc_context->priv_data;
87

    
88
    /* Set up the theora_info struct */
89
    theora_info_init( &t_info );
90
    t_info.width = avc_context->width;
91
    t_info.height = avc_context->height;
92
    t_info.frame_width = avc_context->width;
93
    t_info.frame_height = avc_context->height;
94
    t_info.offset_x = 0;
95
    t_info.offset_y = 0;
96
    /* Swap numerator and denominator as time_base in AVCodecContext gives the
97
     * time period between frames, but theora_info needs the framerate.  */
98
    t_info.fps_numerator = avc_context->time_base.den;
99
    t_info.fps_denominator = avc_context->time_base.num;
100
    if (avc_context->sample_aspect_ratio.num != 0) {
101
        t_info.aspect_numerator = avc_context->sample_aspect_ratio.num;
102
        t_info.aspect_denominator = avc_context->sample_aspect_ratio.den;
103
    } else {
104
        t_info.aspect_numerator = 1;
105
        t_info.aspect_denominator = 1;
106
    }
107
    t_info.colorspace = OC_CS_UNSPECIFIED;
108
    t_info.pixelformat = OC_PF_420;
109
    t_info.target_bitrate = avc_context->bit_rate;
110
    t_info.keyframe_frequency = avc_context->gop_size;
111
    t_info.keyframe_frequency_force = avc_context->gop_size;
112
    t_info.keyframe_mindistance = avc_context->keyint_min;
113
    t_info.quality = 0;
114

    
115
    t_info.quick_p = 1;
116
    t_info.dropframes_p = 0;
117
    t_info.keyframe_auto_p = 1;
118
    t_info.keyframe_data_target_bitrate = t_info.target_bitrate * 1.5;
119
    t_info.keyframe_auto_threshold = 80;
120
    t_info.noise_sensitivity = 1;
121
    t_info.sharpness = 0;
122

    
123
    /* Now initialise libtheora */
124
    if (theora_encode_init( &(h->t_state), &t_info ) != 0) {
125
        av_log(avc_context, AV_LOG_ERROR, "theora_encode_init failed\n");
126
        return -1;
127
    }
128

    
129
    /* Clear up theora_info struct */
130
    theora_info_clear( &t_info );
131

    
132
    /*
133
        Output first header packet consisting of theora
134
        header, comment, and tables.
135

136
        Each one is prefixed with a 16bit size, then they
137
        are concatenated together into ffmpeg's extradata.
138
    */
139
    offset = 0;
140

    
141
    /* Header */
142
    theora_encode_header( &(h->t_state), &o_packet );
143
    if (concatenate_packet( &offset, avc_context, &o_packet ) != 0) {
144
        return -1;
145
    }
146

    
147
    /* Comment */
148
    theora_comment_init( &t_comment );
149
    theora_encode_comment( &t_comment, &o_packet );
150
    if (concatenate_packet( &offset, avc_context, &o_packet ) != 0) {
151
        return -1;
152
    }
153

    
154
    /* Tables */
155
    theora_encode_tables( &(h->t_state), &o_packet );
156
    if (concatenate_packet( &offset, avc_context, &o_packet ) != 0) {
157
        return -1;
158
    }
159

    
160
    /* Clear up theora_comment struct */
161
    theora_comment_clear( &t_comment );
162

    
163
    /* Set up the output AVFrame */
164
    avc_context->coded_frame= avcodec_alloc_frame();
165

    
166
    return 0;
167
}
168

    
169
static int encode_frame(
170
    AVCodecContext* avc_context,
171
    uint8_t *outbuf,
172
    int buf_size,
173
    void *data)
174
{
175
    yuv_buffer t_yuv_buffer;
176
    TheoraContext *h = avc_context->priv_data;
177
    AVFrame *frame = data;
178
    ogg_packet o_packet;
179
    int result;
180

    
181
    assert(avc_context->pix_fmt == PIX_FMT_YUV420P);
182

    
183
    /* Copy planes to the theora yuv_buffer */
184
    if (frame->linesize[1] != frame->linesize[2]) {
185
        av_log(avc_context, AV_LOG_ERROR, "U and V stride differ\n");
186
        return -1;
187
    }
188

    
189
    t_yuv_buffer.y_width = avc_context->width;
190
    t_yuv_buffer.y_height = avc_context->height;
191
    t_yuv_buffer.y_stride = frame->linesize[0];
192
    t_yuv_buffer.uv_width = t_yuv_buffer.y_width / 2;
193
    t_yuv_buffer.uv_height = t_yuv_buffer.y_height / 2;
194
    t_yuv_buffer.uv_stride = frame->linesize[1];
195

    
196
    t_yuv_buffer.y = frame->data[0];
197
    t_yuv_buffer.u = frame->data[1];
198
    t_yuv_buffer.v = frame->data[2];
199

    
200
    /* Now call into theora_encode_YUVin */
201
    result = theora_encode_YUVin( &(h->t_state), &t_yuv_buffer );
202
    if (result != 0) {
203
        const char* message;
204
        switch (result) {
205
            case -1:
206
                message = "differing frame sizes";
207
                break;
208
            case OC_EINVAL:
209
                message = "encoder is not ready or is finished";
210
                break;
211
            default:
212
                message = "unknown reason";
213
                break;
214
        }
215
        av_log(avc_context, AV_LOG_ERROR, "theora_encode_YUVin failed (%s) [%d]\n", message, result);
216
        return -1;
217
    }
218

    
219
    /* Pick up returned ogg_packet */
220
    result = theora_encode_packetout( &(h->t_state), 0, &o_packet );
221
    switch (result) {
222
        case 0:
223
            /* No packet is ready */
224
            return 0;
225
        case 1:
226
            /* Success, we have a packet */
227
            break;
228
        default:
229
            av_log(avc_context, AV_LOG_ERROR, "theora_encode_packetout failed [%d]\n", result);
230
            return -1;
231
    }
232

    
233
    /* Copy ogg_packet content out to buffer */
234
    if (buf_size < o_packet.bytes) {
235
        av_log(avc_context, AV_LOG_ERROR, "encoded frame too large\n");
236
        return -1;
237
    }
238
    memcpy(outbuf, o_packet.packet, o_packet.bytes);
239

    
240
    return o_packet.bytes;
241
}
242

    
243
static int encode_close(AVCodecContext* avc_context)
244
{
245
    ogg_packet o_packet;
246
    TheoraContext *h = avc_context->priv_data;
247
    int result;
248
    const char* message;
249

    
250
    result = theora_encode_packetout( &(h->t_state), 1, &o_packet );
251
    theora_clear( &(h->t_state) );
252
    switch (result) {
253
        case 0:/* No packet is ready */
254
        case -1:/* Encoding finished */
255
            return 0;
256
        case 1:
257
            /* We have a packet */
258
            message = "gave us a packet";
259
            break;
260
        default:
261
            message = "unknown reason";
262
            break;
263
    }
264
    av_log(avc_context, AV_LOG_ERROR, "theora_encode_packetout failed (%s) [%d]\n", message, result);
265
    return -1;
266
}
267

    
268
static const enum PixelFormat supported_pixel_formats[] = { PIX_FMT_YUV420P, PIX_FMT_NONE };
269

    
270
/*! AVCodec struct exposed to libavcodec */
271
AVCodec libtheora_encoder =
272
{
273
    .name = "libtheora",
274
    .type = CODEC_TYPE_VIDEO,
275
    .id = CODEC_ID_THEORA,
276
    .priv_data_size = sizeof(TheoraContext),
277
    .init = encode_init,
278
    .close = encode_close,
279
    .encode = encode_frame,
280
    .pix_fmts = supported_pixel_formats,
281
    .long_name = NULL_IF_CONFIG_SMALL("libtheora Theora"),
282
};