theora.c 18.9 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
5
 * $Id: theora.c,v 1.15 2003/11/22 23:39:14 fenrir 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 29 30 31 32 33 34
 * 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>

#include <ogg/ogg.h>

#include <theora/theora.h>

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

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

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

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

/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
Gildas Bazin's avatar
 
Gildas Bazin committed
63 64 65
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
66

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

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

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

Gildas Bazin's avatar
 
Gildas Bazin committed
75 76 77 78 79
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
80 81 82 83
/*****************************************************************************
 * Module descriptor
 *****************************************************************************/
vlc_module_begin();
Gildas Bazin's avatar
 
Gildas Bazin committed
84
    set_description( _("Theora video decoder") );
Gildas Bazin's avatar
 
Gildas Bazin committed
85
    set_capability( "decoder", 100 );
Gildas Bazin's avatar
 
Gildas Bazin committed
86
    set_callbacks( OpenDecoder, CloseDecoder );
Gildas Bazin's avatar
 
Gildas Bazin committed
87
    add_shortcut( "theora" );
Gildas Bazin's avatar
 
Gildas Bazin committed
88 89 90 91

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

    add_submodule();
    set_description( _("Theora video encoder") );
Gildas Bazin's avatar
 
Gildas Bazin committed
97
    set_capability( "encoder", 100 );
Gildas Bazin's avatar
 
Gildas Bazin committed
98 99
    set_callbacks( OpenEncoder, CloseEncoder );
    add_shortcut( "theora" );
Gildas Bazin's avatar
 
Gildas Bazin committed
100 101 102 103 104 105 106
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
107
    decoder_t *p_dec = (decoder_t*)p_this;
Gildas Bazin's avatar
 
Gildas Bazin committed
108
    decoder_sys_t *p_sys;
Gildas Bazin's avatar
 
Gildas Bazin committed
109

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

Gildas Bazin's avatar
 
Gildas Bazin committed
115
    /* Allocate the memory needed to store the decoder's structure */
Gildas Bazin's avatar
 
Gildas Bazin committed
116
    if( ( p_dec->p_sys = p_sys =
Gildas Bazin's avatar
 
Gildas Bazin committed
117 118 119 120 121 122 123
          (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
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
    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
142 143
    return VLC_SUCCESS;
}
Gildas Bazin's avatar
 
Gildas Bazin committed
144 145 146 147 148 149 150

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
151 152 153 154 155
    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
156 157 158 159 160

    return i_ret;
}

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

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

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

Gildas Bazin's avatar
 
Gildas Bazin committed
175 176 177 178 179 180 181
    /* 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
182

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

Gildas Bazin's avatar
 
Gildas Bazin committed
187 188 189
        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
190
            msg_Err( p_dec, "This bitstream does not contain Theora "
Gildas Bazin's avatar
 
Gildas Bazin committed
191 192
                     "video data" );
            block_Release( p_block );
Gildas Bazin's avatar
 
Gildas Bazin committed
193
            return NULL;
Gildas Bazin's avatar
 
Gildas Bazin committed
194 195
        }
        p_sys->i_headers++;
Gildas Bazin's avatar
 
Gildas Bazin committed
196

Gildas Bazin's avatar
 
Gildas Bazin committed
197 198 199
        /* 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
200

Gildas Bazin's avatar
 
Gildas Bazin committed
201 202 203
        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
204
        else
Gildas Bazin's avatar
 
Gildas Bazin committed
205 206
            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
207

Gildas Bazin's avatar
 
Gildas Bazin committed
208 209 210 211 212 213
        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
214

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

    if( p_sys->i_headers == 1 )
Gildas Bazin's avatar
 
Gildas Bazin committed
219
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
220 221 222 223
        /* 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
224
            return NULL;
Gildas Bazin's avatar
 
Gildas Bazin committed
225 226
        }
        p_sys->i_headers++;
Sam Hocevar's avatar
Sam Hocevar committed
227

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

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

Gildas Bazin's avatar
 
Gildas Bazin committed
233
    if( p_sys->i_headers == 2 )
Gildas Bazin's avatar
 
Gildas Bazin committed
234
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
235 236 237 238 239 240
        /* 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
241
            return NULL;
Gildas Bazin's avatar
 
Gildas Bazin committed
242 243
        }
        p_sys->i_headers++;
Sam Hocevar's avatar
Sam Hocevar committed
244

Gildas Bazin's avatar
 
Gildas Bazin committed
245 246 247 248 249 250
        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
251
        return ProcessPacket( p_dec, &oggpacket, pp_block );
Gildas Bazin's avatar
 
Gildas Bazin committed
252 253
    }

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

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

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

Gildas Bazin's avatar
 
Gildas Bazin committed
273 274
    if( p_sys->b_packetizer )
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
275 276 277 278 279 280 281 282 283
        /* 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
284 285 286
    }
    else
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
287 288 289 290
        if( p_sys->i_headers >= 3 )
            p_buf = DecodePacket( p_dec, p_oggpacket );
        else
            p_buf = NULL;
Gildas Bazin's avatar
 
Gildas Bazin committed
291

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

    /* Date management */
Gildas Bazin's avatar
 
Gildas Bazin committed
300 301
    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
302

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

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

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

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

Gildas Bazin's avatar
 
Gildas Bazin committed
320 321 322
    /* 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
323

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

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

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

/*****************************************************************************
Gildas Bazin's avatar
 
Gildas Bazin committed
332
 * ParseTheoraComments: FIXME should be done in demuxer
Gildas Bazin's avatar
 
Gildas Bazin committed
333
 *****************************************************************************/
Gildas Bazin's avatar
 
Gildas Bazin committed
334
static void ParseTheoraComments( decoder_t *p_dec )
Gildas Bazin's avatar
 
Gildas Bazin committed
335
{
Gildas Bazin's avatar
 
Gildas Bazin committed
336 337 338 339 340 341
    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
342
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362
        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
363
 * CloseDecoder: theora decoder destruction
Gildas Bazin's avatar
 
Gildas Bazin committed
364
 *****************************************************************************/
Gildas Bazin's avatar
 
Gildas Bazin committed
365
static void CloseDecoder( vlc_object_t *p_this )
Gildas Bazin's avatar
 
Gildas Bazin committed
366
{
Gildas Bazin's avatar
 
Gildas Bazin committed
367
    decoder_t *p_dec = (decoder_t *)p_this;
Gildas Bazin's avatar
 
Gildas Bazin committed
368
    decoder_sys_t *p_sys = p_dec->p_sys;
Gildas Bazin's avatar
 
Gildas Bazin committed
369

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

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

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

    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
392 393 394 395 396 397 398 399
        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
400
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
401 402

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

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

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

    /*
     * 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
444
    if( p_enc->fmt_out.i_codec != VLC_FOURCC('t','h','e','o') )
Gildas Bazin's avatar
 
Gildas Bazin committed
445 446 447 448 449 450 451 452 453 454 455 456 457 458
    {
        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
459
    p_enc->fmt_in.i_codec = VLC_FOURCC('I','4','2','0');
Gildas Bazin's avatar
 
Gildas Bazin committed
460 461 462 463 464 465 466 467 468 469 470

#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
471 472 473 474
    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
475 476 477 478 479 480 481
    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
482
    p_sys->ti.target_bitrate = p_enc->fmt_out.i_bitrate;
Gildas Bazin's avatar
 
Gildas Bazin committed
483 484 485 486 487 488 489
    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
490
    p_sys->ti.keyframe_data_target_bitrate = p_enc->fmt_out.i_bitrate * 1.5;
Gildas Bazin's avatar
 
Gildas Bazin committed
491 492 493 494 495 496
    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
497
    theora_comment_init( &p_sys->tc );
Gildas Bazin's avatar
 
Gildas Bazin committed
498

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

    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
512
    block_t *p_chain = NULL;
Gildas Bazin's avatar
 
Gildas Bazin committed
513 514

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

Gildas Bazin's avatar
 
Gildas Bazin committed
520 521 522
        theora_encode_header( &p_sys->td, &oggpackets[0] );
        theora_encode_comment( &p_sys->tc, &oggpackets[1] );
        theora_encode_tables( &p_sys->td, &oggpackets[2] );
Gildas Bazin's avatar
 
Gildas Bazin committed
523

Gildas Bazin's avatar
 
Gildas Bazin committed
524 525 526 527 528 529 530 531 532
        /* Ogg packet to block */
        for( i = 0; i < 3; i++ )
        {
            block_t *p_block = block_New( p_enc, oggpackets[i].bytes );
            memcpy( p_block->p_buffer, oggpackets[i].packet,
                    oggpackets[i].bytes );
            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
533

Gildas Bazin's avatar
 
Gildas Bazin committed
534 535 536 537
        p_sys->b_headers = VLC_TRUE;
    }

    return p_chain;
Gildas Bazin's avatar
 
Gildas Bazin committed
538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566
}

/****************************************************************************
 * 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
567 568 569 570 571
    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
572 573 574 575 576

    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
577
    memcpy( p_block->p_buffer, oggpacket.packet, oggpacket.bytes );
Gildas Bazin's avatar
 
Gildas Bazin committed
578
    p_block->i_dts = p_block->i_pts = p_pict->date;;
Gildas Bazin's avatar
 
Gildas Bazin committed
579 580 581 582 583 584 585 586 587 588 589 590 591

    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 );
592
    theora_comment_clear( &p_sys->tc );
Gildas Bazin's avatar
 
Gildas Bazin committed
593 594 595

    free( p_sys );
}