theora.c 19.5 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$
Gildas Bazin's avatar
 
Gildas Bazin committed
6
 *
7
 * Authors: Gildas Bazin <gbazin@videolan.org>
Gildas Bazin's avatar
 
Gildas Bazin committed
8 9 10 11 12
 *
 * 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 "
Benjamin Pracht's avatar
Benjamin Pracht committed
191
                     "video data." );
Gildas Bazin's avatar
 
Gildas Bazin committed
192
            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
        if( p_sys->ti.aspect_denominator )
Gildas Bazin's avatar
 
Gildas Bazin committed
202
            p_dec->fmt_out.video.i_aspect = ((int64_t)VOUT_ASPECT_FACTOR) *
Gildas Bazin's avatar
 
Gildas Bazin committed
203
                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
        msg_Dbg( p_dec, "%dx%d %.02f fps video, frame content "
Benjamin Pracht's avatar
Benjamin Pracht committed
209
                 "is %dx%d with offset (%d,%d).",
Gildas Bazin's avatar
 
Gildas Bazin committed
210 211 212 213
                 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
        /* The next packet in order is the comments header */
        if( theora_decode_header( &p_sys->ti, &p_sys->tc, &oggpacket ) < 0 )
        {
Benjamin Pracht's avatar
Benjamin Pracht committed
223
            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
        /* 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 )
        {
Benjamin Pracht's avatar
Benjamin Pracht committed
240
            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
    input_thread_t *p_input = (input_thread_t *)p_dec->p_parent;
337

Gildas Bazin's avatar
 
Gildas Bazin committed
338 339 340
    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
341
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
342 343 344
        psz_comment = strdup( p_dec->p_sys->tc.user_comments[i] );
        if( !psz_comment )
        {
Benjamin Pracht's avatar
Benjamin Pracht committed
345
            msg_Warn( p_dec, "out of memory" );
Gildas Bazin's avatar
 
Gildas Bazin committed
346 347 348 349 350 351 352 353
            break;
        }
        psz_name = psz_comment;
        psz_value = strchr( psz_comment, '=' );
        if( psz_value )
        {
            *psz_value = '\0';
            psz_value++;
354 355
            input_Control( p_input, INPUT_ADD_INFO, _("Theora comment"),
                           psz_name, psz_value );
Gildas Bazin's avatar
 
Gildas Bazin committed
356 357 358 359 360 361 362
        }
        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;

444 445
    if( p_enc->fmt_out.i_codec != VLC_FOURCC('t','h','e','o') &&
        !p_enc->b_force )
Gildas Bazin's avatar
 
Gildas Bazin committed
446 447 448 449
    {
        return VLC_EGENERIC;
    }

450 451 452 453
    if( p_enc->fmt_in.video.i_width % 16 ||
        p_enc->fmt_in.video.i_height % 16 )
    {
        msg_Err( p_enc, "Theora video encoding requires dimensions which are "
Benjamin Pracht's avatar
Benjamin Pracht committed
454
                 "multiples of 16. Which is not the case here (%dx%d).",
455 456 457 458
                 p_enc->fmt_in.video.i_width, p_enc->fmt_in.video.i_height );
        return VLC_EGENERIC;
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
459 460 461 462 463 464 465 466 467 468
    /* 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
469
    p_enc->fmt_in.i_codec = VLC_FOURCC('I','4','2','0');
470
    p_enc->fmt_out.i_codec = VLC_FOURCC('t','h','e','o');
Gildas Bazin's avatar
 
Gildas Bazin committed
471 472 473 474 475 476 477 478 479

#define frame_x_offset 0
#define frame_y_offset 0
#define video_hzn 25
#define video_hzd 1
#define video_q 5

    theora_info_init( &p_sys->ti );

Gildas Bazin's avatar
 
Gildas Bazin committed
480 481 482 483
    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
484 485 486 487
    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;
Gildas Bazin's avatar
 
Gildas Bazin committed
488 489 490 491 492 493 494 495 496 497 498 499

    if( p_enc->fmt_in.video.i_aspect )
    {
        p_sys->ti.aspect_numerator = p_enc->fmt_in.video.i_aspect;
        p_sys->ti.aspect_denominator = VOUT_ASPECT_FACTOR;
    }
    else
    {
        p_sys->ti.aspect_numerator = 4;
        p_sys->ti.aspect_denominator = 3;
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
500
    p_sys->ti.target_bitrate = p_enc->fmt_out.i_bitrate;
Gildas Bazin's avatar
 
Gildas Bazin committed
501 502 503 504 505 506 507
    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
508
    p_sys->ti.keyframe_data_target_bitrate = p_enc->fmt_out.i_bitrate * 1.5;
Gildas Bazin's avatar
 
Gildas Bazin committed
509 510 511 512 513 514
    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
515
    theora_comment_init( &p_sys->tc );
Gildas Bazin's avatar
 
Gildas Bazin committed
516

Gildas Bazin's avatar
 
Gildas Bazin committed
517
    p_sys->b_headers = VLC_FALSE;
Gildas Bazin's avatar
 
Gildas Bazin committed
518 519 520 521 522 523 524 525 526 527 528 529

    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
530
    block_t *p_chain = NULL;
Gildas Bazin's avatar
 
Gildas Bazin committed
531 532

    /* Create theora headers */
Gildas Bazin's avatar
 
Gildas Bazin committed
533
    if( !p_sys->b_headers )
Gildas Bazin's avatar
 
Gildas Bazin committed
534
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
535
        ogg_packet oggpackets;
Gildas Bazin's avatar
 
Gildas Bazin committed
536
        int i;
Eric Petit's avatar
Eric Petit committed
537
        block_t *p_block;
Gildas Bazin's avatar
 
Gildas Bazin committed
538

Gildas Bazin's avatar
 
Gildas Bazin committed
539 540 541
        /* Ogg packet to block */
        for( i = 0; i < 3; i++ )
        {
Gildas Bazin's avatar
 
Gildas Bazin committed
542 543 544 545 546 547 548 549 550 551 552 553 554
            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;
            }

Eric Petit's avatar
Eric Petit committed
555
            p_block = block_New( p_enc, oggpackets.bytes );
Gildas Bazin's avatar
 
Gildas Bazin committed
556
            memcpy( p_block->p_buffer, oggpackets.packet, oggpackets.bytes );
Gildas Bazin's avatar
 
Gildas Bazin committed
557 558 559
            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
560

Gildas Bazin's avatar
 
Gildas Bazin committed
561 562 563 564
        p_sys->b_headers = VLC_TRUE;
    }

    return p_chain;
Gildas Bazin's avatar
 
Gildas Bazin committed
565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593
}

/****************************************************************************
 * 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
594 595 596 597 598
    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
599 600 601 602 603

    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
604
    memcpy( p_block->p_buffer, oggpacket.packet, oggpacket.bytes );
Gildas Bazin's avatar
 
Gildas Bazin committed
605
    p_block->i_dts = p_block->i_pts = p_pict->date;;
Gildas Bazin's avatar
 
Gildas Bazin committed
606 607 608 609 610 611 612 613 614 615 616 617 618

    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 );
619
    theora_comment_clear( &p_sys->tc );
Gildas Bazin's avatar
 
Gildas Bazin committed
620 621 622

    free( p_sys );
}