theora.c 19 KB
Newer Older
Gildas Bazin's avatar
 
Gildas Bazin committed
1 2 3 4
/*****************************************************************************
 * theora.c: theora decoder module making use of libtheora.
 *****************************************************************************
 * Copyright (C) 1999-2001 VideoLAN
Gildas Bazin's avatar
 
Gildas Bazin committed
5
 * $Id: theora.c,v 1.16 2003/12/07 17:09:33 gbazin Exp $
Gildas Bazin's avatar
 
Gildas Bazin committed
6 7 8 9 10 11 12
 *
 * Authors: Gildas Bazin <gbazin@netcourrier.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
Sam Hocevar's avatar
Sam Hocevar committed
13
 *
Gildas Bazin's avatar
 
Gildas Bazin committed
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
#include <vlc/vlc.h>
#include <vlc/decoder.h>
Gildas Bazin's avatar
 
Gildas Bazin committed
29
#include "input_ext-plugins.h"
Gildas Bazin's avatar
 
Gildas Bazin committed
30 31 32 33 34 35

#include <ogg/ogg.h>

#include <theora/theora.h>

/*****************************************************************************
Gildas Bazin's avatar
 
Gildas Bazin committed
36
 * decoder_sys_t : theora decoder descriptor
Gildas Bazin's avatar
 
Gildas Bazin committed
37
 *****************************************************************************/
Gildas Bazin's avatar
 
Gildas Bazin committed
38
struct decoder_sys_t
Gildas Bazin's avatar
 
Gildas Bazin committed
39
{
Gildas Bazin's avatar
 
Gildas Bazin committed
40 41 42
    /* Module mode */
    vlc_bool_t b_packetizer;

Gildas Bazin's avatar
 
Gildas Bazin committed
43
    /*
Gildas Bazin's avatar
 
Gildas Bazin committed
44
     * Input properties
Gildas Bazin's avatar
 
Gildas Bazin committed
45
     */
Gildas Bazin's avatar
 
Gildas Bazin committed
46
    int i_headers;
Gildas Bazin's avatar
 
Gildas Bazin committed
47 48 49 50 51

    /*
     * Theora properties
     */
    theora_info      ti;                        /* theora bitstream settings */
Gildas Bazin's avatar
 
Gildas Bazin committed
52
    theora_comment   tc;                            /* theora comment header */
Gildas Bazin's avatar
 
Gildas Bazin committed
53 54
    theora_state     td;                   /* theora bitstream user comments */

Gildas Bazin's avatar
 
Gildas Bazin committed
55 56 57 58 59
    /*
     * Common properties
     */
    mtime_t i_pts;
};
Gildas Bazin's avatar
 
Gildas Bazin committed
60 61 62 63

/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
Gildas Bazin's avatar
 
Gildas Bazin committed
64 65 66
static int  OpenDecoder   ( vlc_object_t * );
static int  OpenPacketizer( vlc_object_t * );
static void CloseDecoder  ( vlc_object_t * );
Gildas Bazin's avatar
 
Gildas Bazin committed
67

Gildas Bazin's avatar
 
Gildas Bazin committed
68 69
static void *DecodeBlock  ( decoder_t *, block_t ** );
static void *ProcessPacket ( decoder_t *, ogg_packet *, block_t ** );
Gildas Bazin's avatar
 
Gildas Bazin committed
70

Gildas Bazin's avatar
 
Gildas Bazin committed
71
static picture_t *DecodePacket( decoder_t *, ogg_packet * );
Gildas Bazin's avatar
 
Gildas Bazin committed
72

Gildas Bazin's avatar
 
Gildas Bazin committed
73 74
static void ParseTheoraComments( decoder_t * );
static void theora_CopyPicture( decoder_t *, picture_t *, yuv_buffer * );
75

Gildas Bazin's avatar
 
Gildas Bazin committed
76 77 78 79 80
static int  OpenEncoder( vlc_object_t *p_this );
static void CloseEncoder( vlc_object_t *p_this );
static block_t *Headers( encoder_t *p_enc );
static block_t *Encode( encoder_t *p_enc, picture_t *p_pict );

Gildas Bazin's avatar
 
Gildas Bazin committed
81 82 83 84
/*****************************************************************************
 * Module descriptor
 *****************************************************************************/
vlc_module_begin();
Gildas Bazin's avatar
 
Gildas Bazin committed
85
    set_description( _("Theora video decoder") );
Gildas Bazin's avatar
 
Gildas Bazin committed
86
    set_capability( "decoder", 100 );
Gildas Bazin's avatar
 
Gildas Bazin committed
87
    set_callbacks( OpenDecoder, CloseDecoder );
Gildas Bazin's avatar
 
Gildas Bazin committed
88
    add_shortcut( "theora" );
Gildas Bazin's avatar
 
Gildas Bazin committed
89 90 91 92

    add_submodule();
    set_description( _("Theora video packetizer") );
    set_capability( "packetizer", 100 );
Gildas Bazin's avatar
 
Gildas Bazin committed
93
    set_callbacks( OpenPacketizer, CloseDecoder );
Gildas Bazin's avatar
 
Gildas Bazin committed
94
    add_shortcut( "theora" );
Gildas Bazin's avatar
 
Gildas Bazin committed
95 96 97

    add_submodule();
    set_description( _("Theora video encoder") );
Gildas Bazin's avatar
 
Gildas Bazin committed
98
    set_capability( "encoder", 100 );
Gildas Bazin's avatar
 
Gildas Bazin committed
99 100
    set_callbacks( OpenEncoder, CloseEncoder );
    add_shortcut( "theora" );
Gildas Bazin's avatar
 
Gildas Bazin committed
101 102 103 104 105 106 107
vlc_module_end();

/*****************************************************************************
 * OpenDecoder: probe the decoder and return score
 *****************************************************************************/
static int OpenDecoder( vlc_object_t *p_this )
{
Gildas Bazin's avatar
 
Gildas Bazin committed
108
    decoder_t *p_dec = (decoder_t*)p_this;
Gildas Bazin's avatar
 
Gildas Bazin committed
109
    decoder_sys_t *p_sys;
Gildas Bazin's avatar
 
Gildas Bazin committed
110

Gildas Bazin's avatar
 
Gildas Bazin committed
111
    if( p_dec->fmt_in.i_codec != VLC_FOURCC('t','h','e','o') )
Gildas Bazin's avatar
 
Gildas Bazin committed
112 113 114 115
    {
        return VLC_EGENERIC;
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
116
    /* Allocate the memory needed to store the decoder's structure */
Gildas Bazin's avatar
 
Gildas Bazin committed
117
    if( ( p_dec->p_sys = p_sys =
Gildas Bazin's avatar
 
Gildas Bazin committed
118 119 120 121 122 123 124
          (decoder_sys_t *)malloc(sizeof(decoder_sys_t)) ) == NULL )
    {
        msg_Err( p_dec, "out of memory" );
        return VLC_EGENERIC;
    }
    p_dec->p_sys->b_packetizer = VLC_FALSE;

Gildas Bazin's avatar
 
Gildas Bazin committed
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
    p_sys->i_pts = 0;

    /* Set output properties */
    p_dec->fmt_out.i_cat = VIDEO_ES;
    p_dec->fmt_out.i_codec = VLC_FOURCC('I','4','2','0');

    /* Set callbacks */
    p_dec->pf_decode_video = (picture_t *(*)(decoder_t *, block_t **))
        DecodeBlock;
    p_dec->pf_packetize    = (block_t *(*)(decoder_t *, block_t **))
        DecodeBlock;

    /* Init supporting Theora structures needed in header parsing */
    theora_comment_init( &p_sys->tc );
    theora_info_init( &p_sys->ti );

    p_sys->i_headers = 0;

Gildas Bazin's avatar
 
Gildas Bazin committed
143 144
    return VLC_SUCCESS;
}
Gildas Bazin's avatar
 
Gildas Bazin committed
145 146 147 148 149 150 151

static int OpenPacketizer( vlc_object_t *p_this )
{
    decoder_t *p_dec = (decoder_t*)p_this;

    int i_ret = OpenDecoder( p_this );

Gildas Bazin's avatar
 
Gildas Bazin committed
152 153 154 155 156
    if( i_ret == VLC_SUCCESS )
    {
        p_dec->p_sys->b_packetizer = VLC_TRUE;
        p_dec->fmt_out.i_codec = VLC_FOURCC( 't', 'h', 'e', 'o' );
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
157 158 159 160 161

    return i_ret;
}

/****************************************************************************
Gildas Bazin's avatar
 
Gildas Bazin committed
162
 * DecodeBlock: the whole thing
Gildas Bazin's avatar
 
Gildas Bazin committed
163 164 165
 ****************************************************************************
 * This function must be fed with ogg packets.
 ****************************************************************************/
Gildas Bazin's avatar
 
Gildas Bazin committed
166
static void *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
Gildas Bazin's avatar
 
Gildas Bazin committed
167 168
{
    decoder_sys_t *p_sys = p_dec->p_sys;
Gildas Bazin's avatar
 
Gildas Bazin committed
169
    block_t *p_block;
Gildas Bazin's avatar
 
Gildas Bazin committed
170
    ogg_packet oggpacket;
Gildas Bazin's avatar
 
Gildas Bazin committed
171 172 173 174

    if( !pp_block || !*pp_block ) return NULL;

    p_block = *pp_block;
Gildas Bazin's avatar
 
Gildas Bazin committed
175

Gildas Bazin's avatar
 
Gildas Bazin committed
176 177 178 179 180 181 182
    /* Block to Ogg packet */
    oggpacket.packet = p_block->p_buffer;
    oggpacket.bytes = p_block->i_buffer;
    oggpacket.granulepos = p_block->i_dts;
    oggpacket.b_o_s = 0;
    oggpacket.e_o_s = 0;
    oggpacket.packetno = 0;
Gildas Bazin's avatar
 
Gildas Bazin committed
183

Gildas Bazin's avatar
 
Gildas Bazin committed
184
    if( p_sys->i_headers == 0 )
Gildas Bazin's avatar
 
Gildas Bazin committed
185
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
186
        /* Take care of the initial Theora header */
Gildas Bazin's avatar
 
Gildas Bazin committed
187

Gildas Bazin's avatar
 
Gildas Bazin committed
188 189 190
        oggpacket.b_o_s = 1; /* yes this actually is a b_o_s packet :) */
        if( theora_decode_header( &p_sys->ti, &p_sys->tc, &oggpacket ) < 0 )
        {
Gildas Bazin's avatar
 
Gildas Bazin committed
191
            msg_Err( p_dec, "This bitstream does not contain Theora "
Gildas Bazin's avatar
 
Gildas Bazin committed
192 193
                     "video data" );
            block_Release( p_block );
Gildas Bazin's avatar
 
Gildas Bazin committed
194
            return NULL;
Gildas Bazin's avatar
 
Gildas Bazin committed
195 196
        }
        p_sys->i_headers++;
Gildas Bazin's avatar
 
Gildas Bazin committed
197

Gildas Bazin's avatar
 
Gildas Bazin committed
198 199 200
        /* Set output properties */
        p_dec->fmt_out.video.i_width = p_sys->ti.width;
        p_dec->fmt_out.video.i_height = p_sys->ti.height;
Sam Hocevar's avatar
Sam Hocevar committed
201

Gildas Bazin's avatar
 
Gildas Bazin committed
202 203 204
        if( p_sys->ti.aspect_denominator )
            p_dec->fmt_out.video.i_aspect = VOUT_ASPECT_FACTOR *
                p_sys->ti.aspect_numerator / p_sys->ti.aspect_denominator;
Gildas Bazin's avatar
 
Gildas Bazin committed
205
        else
Gildas Bazin's avatar
 
Gildas Bazin committed
206 207
            p_dec->fmt_out.video.i_aspect = VOUT_ASPECT_FACTOR *
                p_sys->ti.frame_width / p_sys->ti.frame_height;
Gildas Bazin's avatar
 
Gildas Bazin committed
208

Gildas Bazin's avatar
 
Gildas Bazin committed
209 210 211 212 213 214
        msg_Dbg( p_dec, "%dx%d %.02f fps video, frame content "
                 "is %dx%d with offset (%d,%d)",
                 p_sys->ti.width, p_sys->ti.height,
                 (double)p_sys->ti.fps_numerator/p_sys->ti.fps_denominator,
                 p_sys->ti.frame_width, p_sys->ti.frame_height,
                 p_sys->ti.offset_x, p_sys->ti.offset_y );
Gildas Bazin's avatar
 
Gildas Bazin committed
215

Gildas Bazin's avatar
 
Gildas Bazin committed
216
        return ProcessPacket( p_dec, &oggpacket, pp_block );
Gildas Bazin's avatar
 
Gildas Bazin committed
217 218 219
    }

    if( p_sys->i_headers == 1 )
Gildas Bazin's avatar
 
Gildas Bazin committed
220
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
221 222 223 224
        /* The next packet in order is the comments header */
        if( theora_decode_header( &p_sys->ti, &p_sys->tc, &oggpacket ) < 0 )
        {
            msg_Err( p_dec, "2nd Theora header is corrupted" );
Gildas Bazin's avatar
 
Gildas Bazin committed
225
            return NULL;
Gildas Bazin's avatar
 
Gildas Bazin committed
226 227
        }
        p_sys->i_headers++;
Sam Hocevar's avatar
Sam Hocevar committed
228

Gildas Bazin's avatar
 
Gildas Bazin committed
229 230
        ParseTheoraComments( p_dec );

Gildas Bazin's avatar
 
Gildas Bazin committed
231
        return ProcessPacket( p_dec, &oggpacket, pp_block );
Gildas Bazin's avatar
 
Gildas Bazin committed
232 233
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
234
    if( p_sys->i_headers == 2 )
Gildas Bazin's avatar
 
Gildas Bazin committed
235
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
236 237 238 239 240 241
        /* The next packet in order is the codebooks header
           We need to watch out that this packet is not missing as a
           missing or corrupted header is fatal. */
        if( theora_decode_header( &p_sys->ti, &p_sys->tc, &oggpacket ) < 0 )
        {
            msg_Err( p_dec, "3rd Theora header is corrupted" );
Gildas Bazin's avatar
 
Gildas Bazin committed
242
            return NULL;
Gildas Bazin's avatar
 
Gildas Bazin committed
243 244
        }
        p_sys->i_headers++;
Sam Hocevar's avatar
Sam Hocevar committed
245

Gildas Bazin's avatar
 
Gildas Bazin committed
246 247 248 249 250 251
        if( !p_sys->b_packetizer )
        {
            /* We have all the headers, initialize decoder */
            theora_decode_init( &p_sys->td, &p_sys->ti );
        }

Gildas Bazin's avatar
 
Gildas Bazin committed
252
        return ProcessPacket( p_dec, &oggpacket, pp_block );
Gildas Bazin's avatar
 
Gildas Bazin committed
253 254
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
255
    return ProcessPacket( p_dec, &oggpacket, pp_block );
Gildas Bazin's avatar
 
Gildas Bazin committed
256
}
Gildas Bazin's avatar
 
Gildas Bazin committed
257

Gildas Bazin's avatar
 
Gildas Bazin committed
258
/*****************************************************************************
Gildas Bazin's avatar
 
Gildas Bazin committed
259
 * ProcessPacket: processes a theora packet.
Gildas Bazin's avatar
 
Gildas Bazin committed
260
 *****************************************************************************/
Gildas Bazin's avatar
 
Gildas Bazin committed
261 262
static void *ProcessPacket( decoder_t *p_dec, ogg_packet *p_oggpacket,
                            block_t **pp_block )
Gildas Bazin's avatar
 
Gildas Bazin committed
263 264
{
    decoder_sys_t *p_sys = p_dec->p_sys;
Gildas Bazin's avatar
 
Gildas Bazin committed
265 266
    block_t *p_block = *pp_block;
    void *p_buf;
Gildas Bazin's avatar
 
Gildas Bazin committed
267

Gildas Bazin's avatar
 
Gildas Bazin committed
268
    /* Date management */
Gildas Bazin's avatar
 
Gildas Bazin committed
269
    if( p_block->i_pts > 0 && p_block->i_pts != p_sys->i_pts )
Gildas Bazin's avatar
 
Gildas Bazin committed
270
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
271
        p_sys->i_pts = p_block->i_pts;
Gildas Bazin's avatar
 
Gildas Bazin committed
272 273
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
274 275
    if( p_sys->b_packetizer )
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
276 277 278 279 280 281 282 283 284
        /* Date management */
        p_block->i_dts = p_block->i_pts = p_sys->i_pts;

        if( p_sys->i_headers >= 3 )
            p_block->i_length = p_sys->i_pts - p_block->i_pts;
        else
            p_block->i_length = 0;

        p_buf = p_block;
Gildas Bazin's avatar
 
Gildas Bazin committed
285 286 287
    }
    else
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
288 289 290 291
        if( p_sys->i_headers >= 3 )
            p_buf = DecodePacket( p_dec, p_oggpacket );
        else
            p_buf = NULL;
Gildas Bazin's avatar
 
Gildas Bazin committed
292

Gildas Bazin's avatar
 
Gildas Bazin committed
293
        if( p_block )
Gildas Bazin's avatar
 
Gildas Bazin committed
294
        {
Gildas Bazin's avatar
 
Gildas Bazin committed
295 296
            block_Release( p_block );
            *pp_block = NULL;
Gildas Bazin's avatar
 
Gildas Bazin committed
297 298
        }
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
299 300

    /* Date management */
Gildas Bazin's avatar
 
Gildas Bazin committed
301 302
    p_sys->i_pts += ( I64C(1000000) * p_sys->ti.fps_denominator /
                      p_sys->ti.fps_numerator ); /* 1 frame per packet */
Gildas Bazin's avatar
 
Gildas Bazin committed
303

Gildas Bazin's avatar
 
Gildas Bazin committed
304
    return p_buf;
Gildas Bazin's avatar
 
Gildas Bazin committed
305 306 307
}

/*****************************************************************************
Gildas Bazin's avatar
 
Gildas Bazin committed
308
 * DecodePacket: decodes a Theora packet.
Gildas Bazin's avatar
 
Gildas Bazin committed
309
 *****************************************************************************/
Gildas Bazin's avatar
 
Gildas Bazin committed
310
static picture_t *DecodePacket( decoder_t *p_dec, ogg_packet *p_oggpacket )
Gildas Bazin's avatar
 
Gildas Bazin committed
311
{
Gildas Bazin's avatar
 
Gildas Bazin committed
312
    decoder_sys_t *p_sys = p_dec->p_sys;
Gildas Bazin's avatar
 
Gildas Bazin committed
313 314
    picture_t *p_pic;
    yuv_buffer yuv;
Gildas Bazin's avatar
 
Gildas Bazin committed
315

Gildas Bazin's avatar
 
Gildas Bazin committed
316
    theora_decode_packetin( &p_sys->td, p_oggpacket );
Gildas Bazin's avatar
 
Gildas Bazin committed
317

Gildas Bazin's avatar
 
Gildas Bazin committed
318 319
    /* Decode */
    theora_decode_YUVout( &p_sys->td, &yuv );
Gildas Bazin's avatar
 
Gildas Bazin committed
320

Gildas Bazin's avatar
 
Gildas Bazin committed
321 322 323
    /* Get a new picture */
    p_pic = p_dec->pf_vout_buffer_new( p_dec );
    if( !p_pic ) return NULL;
Gildas Bazin's avatar
 
Gildas Bazin committed
324

Gildas Bazin's avatar
 
Gildas Bazin committed
325
    theora_CopyPicture( p_dec, p_pic, &yuv );
Gildas Bazin's avatar
 
Gildas Bazin committed
326

Gildas Bazin's avatar
 
Gildas Bazin committed
327
    p_pic->date = p_sys->i_pts;
Gildas Bazin's avatar
 
Gildas Bazin committed
328

Gildas Bazin's avatar
 
Gildas Bazin committed
329
    return p_pic;
Gildas Bazin's avatar
 
Gildas Bazin committed
330 331 332
}

/*****************************************************************************
Gildas Bazin's avatar
 
Gildas Bazin committed
333
 * ParseTheoraComments: FIXME should be done in demuxer
Gildas Bazin's avatar
 
Gildas Bazin committed
334
 *****************************************************************************/
Gildas Bazin's avatar
 
Gildas Bazin committed
335
static void ParseTheoraComments( decoder_t *p_dec )
Gildas Bazin's avatar
 
Gildas Bazin committed
336
{
Gildas Bazin's avatar
 
Gildas Bazin committed
337 338 339 340 341 342
    input_thread_t *p_input = (input_thread_t *)p_dec->p_parent;
    input_info_category_t *p_cat =
        input_InfoCategory( p_input, _("Theora Comment") );
    int i = 0;
    char *psz_name, *psz_value, *psz_comment;
    while ( i < p_dec->p_sys->tc.comments )
Gildas Bazin's avatar
 
Gildas Bazin committed
343
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363
        psz_comment = strdup( p_dec->p_sys->tc.user_comments[i] );
        if( !psz_comment )
        {
            msg_Warn( p_dec, "Out of memory" );
            break;
        }
        psz_name = psz_comment;
        psz_value = strchr( psz_comment, '=' );
        if( psz_value )
        {
            *psz_value = '\0';
            psz_value++;
            input_AddInfo( p_cat, psz_name, psz_value );
        }
        free( psz_comment );
        i++;
    }
}

/*****************************************************************************
Gildas Bazin's avatar
 
Gildas Bazin committed
364
 * CloseDecoder: theora decoder destruction
Gildas Bazin's avatar
 
Gildas Bazin committed
365
 *****************************************************************************/
Gildas Bazin's avatar
 
Gildas Bazin committed
366
static void CloseDecoder( vlc_object_t *p_this )
Gildas Bazin's avatar
 
Gildas Bazin committed
367
{
Gildas Bazin's avatar
 
Gildas Bazin committed
368
    decoder_t *p_dec = (decoder_t *)p_this;
Gildas Bazin's avatar
 
Gildas Bazin committed
369
    decoder_sys_t *p_sys = p_dec->p_sys;
Gildas Bazin's avatar
 
Gildas Bazin committed
370

Gildas Bazin's avatar
 
Gildas Bazin committed
371 372
    theora_info_clear( &p_sys->ti );
    theora_comment_clear( &p_sys->tc );
Gildas Bazin's avatar
 
Gildas Bazin committed
373

Gildas Bazin's avatar
 
Gildas Bazin committed
374
    free( p_sys );
Gildas Bazin's avatar
 
Gildas Bazin committed
375 376 377 378 379 380
}

/*****************************************************************************
 * theora_CopyPicture: copy a picture from theora internal buffers to a
 *                     picture_t structure.
 *****************************************************************************/
Gildas Bazin's avatar
 
Gildas Bazin committed
381
static void theora_CopyPicture( decoder_t *p_dec, picture_t *p_pic,
Gildas Bazin's avatar
 
Gildas Bazin committed
382 383 384
                                yuv_buffer *yuv )
{
    int i_plane, i_line, i_width, i_dst_stride, i_src_stride;
Gildas Bazin's avatar
 
Gildas Bazin committed
385
    int i_src_xoffset, i_src_yoffset;
Sam Hocevar's avatar
Sam Hocevar committed
386
    uint8_t *p_dst, *p_src;
Gildas Bazin's avatar
 
Gildas Bazin committed
387 388 389 390 391 392

    for( i_plane = 0; i_plane < p_pic->i_planes; i_plane++ )
    {
        p_dst = p_pic->p[i_plane].p_pixels;
        p_src = i_plane ? (i_plane - 1 ? yuv->v : yuv->u ) : yuv->y;
        i_width = p_pic->p[i_plane].i_visible_pitch;
Gildas Bazin's avatar
 
Gildas Bazin committed
393 394 395 396 397 398 399 400
        i_dst_stride  = p_pic->p[i_plane].i_pitch;
        i_src_stride  = i_plane ? yuv->uv_stride : yuv->y_stride;
        i_src_xoffset = p_dec->p_sys->ti.offset_x;
        i_src_yoffset = p_dec->p_sys->ti.offset_y;
        if( i_plane )
        {
            i_src_xoffset /= 2;
            i_src_yoffset /= 2;
Sam Hocevar's avatar
Sam Hocevar committed
401
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
402 403

        p_src += (i_src_yoffset * i_src_stride + i_src_yoffset);
Gildas Bazin's avatar
 
Gildas Bazin committed
404 405 406

        for( i_line = 0; i_line < p_pic->p[i_plane].i_lines; i_line++ )
        {
Gildas Bazin's avatar
 
Gildas Bazin committed
407
            p_dec->p_vlc->pf_memcpy( p_dst, p_src, i_width );
Gildas Bazin's avatar
 
Gildas Bazin committed
408 409 410 411 412
            p_src += i_src_stride;
            p_dst += i_dst_stride;
        }
    }
}
Gildas Bazin's avatar
 
Gildas Bazin committed
413 414 415 416 417 418 419 420 421

/*****************************************************************************
 * encoder_sys_t : theora encoder descriptor
 *****************************************************************************/
struct encoder_sys_t
{
    /*
     * Input properties
     */
Gildas Bazin's avatar
 
Gildas Bazin committed
422
    vlc_bool_t b_headers;
Gildas Bazin's avatar
 
Gildas Bazin committed
423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444

    /*
     * Theora properties
     */
    theora_info      ti;                        /* theora bitstream settings */
    theora_comment   tc;                            /* theora comment header */
    theora_state     td;                   /* theora bitstream user comments */

    /*
     * Common properties
     */
    mtime_t i_pts;
};

/*****************************************************************************
 * OpenEncoder: probe the encoder and return score
 *****************************************************************************/
static int OpenEncoder( vlc_object_t *p_this )
{
    encoder_t *p_enc = (encoder_t *)p_this;
    encoder_sys_t *p_sys = p_enc->p_sys;

Gildas Bazin's avatar
 
Gildas Bazin committed
445
    if( p_enc->fmt_out.i_codec != VLC_FOURCC('t','h','e','o') )
Gildas Bazin's avatar
 
Gildas Bazin committed
446 447 448 449 450 451 452 453 454 455 456 457 458 459
    {
        return VLC_EGENERIC;
    }

    /* Allocate the memory needed to store the decoder's structure */
    if( ( p_sys = (encoder_sys_t *)malloc(sizeof(encoder_sys_t)) ) == NULL )
    {
        msg_Err( p_enc, "out of memory" );
        return VLC_EGENERIC;
    }
    p_enc->p_sys = p_sys;

    p_enc->pf_header = Headers;
    p_enc->pf_encode_video = Encode;
Gildas Bazin's avatar
 
Gildas Bazin committed
460
    p_enc->fmt_in.i_codec = VLC_FOURCC('I','4','2','0');
Gildas Bazin's avatar
 
Gildas Bazin committed
461 462 463 464 465 466 467 468 469 470 471

#define frame_x_offset 0
#define frame_y_offset 0
#define video_hzn 25
#define video_hzd 1
#define video_an 4
#define video_ad 3
#define video_q 5

    theora_info_init( &p_sys->ti );

Gildas Bazin's avatar
 
Gildas Bazin committed
472 473 474 475
    p_sys->ti.width = p_enc->fmt_in.video.i_width;
    p_sys->ti.height = p_enc->fmt_in.video.i_height;
    p_sys->ti.frame_width = p_enc->fmt_in.video.i_width;
    p_sys->ti.frame_height = p_enc->fmt_in.video.i_height;
Gildas Bazin's avatar
 
Gildas Bazin committed
476 477 478 479 480 481 482
    p_sys->ti.offset_x = frame_x_offset;
    p_sys->ti.offset_y = frame_y_offset;
    p_sys->ti.fps_numerator = video_hzn;
    p_sys->ti.fps_denominator = video_hzd;
    p_sys->ti.aspect_numerator = video_an;
    p_sys->ti.aspect_denominator = video_ad;
    p_sys->ti.colorspace = not_specified;
Gildas Bazin's avatar
 
Gildas Bazin committed
483
    p_sys->ti.target_bitrate = p_enc->fmt_out.i_bitrate;
Gildas Bazin's avatar
 
Gildas Bazin committed
484 485 486 487 488 489 490
    p_sys->ti.quality = video_q;

    p_sys->ti.dropframes_p = 0;
    p_sys->ti.quick_p = 1;
    p_sys->ti.keyframe_auto_p = 1;
    p_sys->ti.keyframe_frequency = 64;
    p_sys->ti.keyframe_frequency_force = 64;
Gildas Bazin's avatar
 
Gildas Bazin committed
491
    p_sys->ti.keyframe_data_target_bitrate = p_enc->fmt_out.i_bitrate * 1.5;
Gildas Bazin's avatar
 
Gildas Bazin committed
492 493 494 495 496 497
    p_sys->ti.keyframe_auto_threshold = 80;
    p_sys->ti.keyframe_mindistance = 8;
    p_sys->ti.noise_sensitivity = 1;

    theora_encode_init( &p_sys->td, &p_sys->ti );
    theora_info_clear( &p_sys->ti );
Gildas Bazin's avatar
 
Gildas Bazin committed
498
    theora_comment_init( &p_sys->tc );
Gildas Bazin's avatar
 
Gildas Bazin committed
499

Gildas Bazin's avatar
 
Gildas Bazin committed
500
    p_sys->b_headers = VLC_FALSE;
Gildas Bazin's avatar
 
Gildas Bazin committed
501 502 503 504 505 506 507 508 509 510 511 512

    return VLC_SUCCESS;
}

/****************************************************************************
 * Encode: the whole thing
 ****************************************************************************
 * This function spits out ogg packets.
 ****************************************************************************/
static block_t *Headers( encoder_t *p_enc )
{
    encoder_sys_t *p_sys = p_enc->p_sys;
Gildas Bazin's avatar
 
Gildas Bazin committed
513
    block_t *p_chain = NULL;
Gildas Bazin's avatar
 
Gildas Bazin committed
514 515

    /* Create theora headers */
Gildas Bazin's avatar
 
Gildas Bazin committed
516
    if( !p_sys->b_headers )
Gildas Bazin's avatar
 
Gildas Bazin committed
517
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
518
        ogg_packet oggpackets;
Gildas Bazin's avatar
 
Gildas Bazin committed
519
        int i;
Gildas Bazin's avatar
 
Gildas Bazin committed
520

Gildas Bazin's avatar
 
Gildas Bazin committed
521 522 523
        /* Ogg packet to block */
        for( i = 0; i < 3; i++ )
        {
Gildas Bazin's avatar
 
Gildas Bazin committed
524 525 526 527 528 529 530 531 532 533 534 535 536 537 538
            switch( i )
            {
            case 0:
                theora_encode_header( &p_sys->td, &oggpackets );
                break;
            case 1:
                theora_encode_comment( &p_sys->tc, &oggpackets );
                break;
            case 2:
                theora_encode_tables( &p_sys->td, &oggpackets );
                break;
            }

            block_t *p_block = block_New( p_enc, oggpackets.bytes );
            memcpy( p_block->p_buffer, oggpackets.packet, oggpackets.bytes );
Gildas Bazin's avatar
 
Gildas Bazin committed
539 540 541
            p_block->i_dts = p_block->i_pts = p_block->i_length = 0;
            block_ChainAppend( &p_chain, p_block );
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
542

Gildas Bazin's avatar
 
Gildas Bazin committed
543 544 545 546
        p_sys->b_headers = VLC_TRUE;
    }

    return p_chain;
Gildas Bazin's avatar
 
Gildas Bazin committed
547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575
}

/****************************************************************************
 * Encode: the whole thing
 ****************************************************************************
 * This function spits out ogg packets.
 ****************************************************************************/
static block_t *Encode( encoder_t *p_enc, picture_t *p_pict )
{
    encoder_sys_t *p_sys = p_enc->p_sys;
    ogg_packet oggpacket;
    block_t *p_block;
    yuv_buffer yuv;

    /* Theora is a one-frame-in, one-frame-out system. Submit a frame
     * for compression and pull out the packet. */

    yuv.y_width  = p_pict->p[0].i_visible_pitch;
    yuv.y_height = p_pict->p[0].i_lines;
    yuv.y_stride = p_pict->p[0].i_pitch;

    yuv.uv_width  = p_pict->p[1].i_visible_pitch;
    yuv.uv_height = p_pict->p[1].i_lines;
    yuv.uv_stride = p_pict->p[1].i_pitch;

    yuv.y = p_pict->p[0].p_pixels;
    yuv.u = p_pict->p[1].p_pixels;
    yuv.v = p_pict->p[2].p_pixels;

Gildas Bazin's avatar
 
Gildas Bazin committed
576 577 578 579 580
    if( theora_encode_YUVin( &p_sys->td, &yuv ) < 0 )
    {
        msg_Warn( p_enc, "failed encoding a frame" );
        return NULL;
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
581 582 583 584 585

    theora_encode_packetout( &p_sys->td, 0, &oggpacket );

    /* Ogg packet to block */
    p_block = block_New( p_enc, oggpacket.bytes );
Gildas Bazin's avatar
 
Gildas Bazin committed
586
    memcpy( p_block->p_buffer, oggpacket.packet, oggpacket.bytes );
Gildas Bazin's avatar
 
Gildas Bazin committed
587
    p_block->i_dts = p_block->i_pts = p_pict->date;;
Gildas Bazin's avatar
 
Gildas Bazin committed
588 589 590 591 592 593 594 595 596 597 598 599 600

    return p_block;
}

/*****************************************************************************
 * CloseEncoder: theora encoder destruction
 *****************************************************************************/
static void CloseEncoder( vlc_object_t *p_this )
{
    encoder_t *p_enc = (encoder_t *)p_this;
    encoder_sys_t *p_sys = p_enc->p_sys;

    theora_info_clear( &p_sys->ti );
601
    theora_comment_clear( &p_sys->tc );
Gildas Bazin's avatar
 
Gildas Bazin committed
602 603 604

    free( p_sys );
}