theora.c 16 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.6 2003/09/02 20:19:25 gbazin Exp $
Gildas Bazin's avatar
 
Gildas Bazin committed
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
 *
 * 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.
 * 
 * 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
 *****************************************************************************/
Gildas Bazin's avatar
 
Gildas Bazin committed
27 28 29
#include <stdlib.h>                                      /* malloc(), free() */
#include <string.h>                                    /* memcpy(), memset() */

Gildas Bazin's avatar
 
Gildas Bazin committed
30 31 32
#include <vlc/vlc.h>
#include <vlc/vout.h>
#include <vlc/decoder.h>
Gildas Bazin's avatar
 
Gildas Bazin committed
33 34 35
#include <vlc/input.h>
#include <vlc/sout.h>
#include <input_ext-dec.h>
Gildas Bazin's avatar
 
Gildas Bazin committed
36 37 38 39 40 41

#include <ogg/ogg.h>

#include <theora/theora.h>

/*****************************************************************************
Gildas Bazin's avatar
 
Gildas Bazin committed
42
 * decoder_sys_t : theora decoder descriptor
Gildas Bazin's avatar
 
Gildas Bazin committed
43
 *****************************************************************************/
Gildas Bazin's avatar
 
Gildas Bazin committed
44
struct decoder_sys_t
Gildas Bazin's avatar
 
Gildas Bazin committed
45
{
Gildas Bazin's avatar
 
Gildas Bazin committed
46 47 48
    /* Module mode */
    vlc_bool_t b_packetizer;

Gildas Bazin's avatar
 
Gildas Bazin committed
49
    /*
Gildas Bazin's avatar
 
Gildas Bazin committed
50
     * Input properties
Gildas Bazin's avatar
 
Gildas Bazin committed
51
     */
Gildas Bazin's avatar
 
Gildas Bazin committed
52
    int i_headers;
Gildas Bazin's avatar
 
Gildas Bazin committed
53 54 55 56 57

    /*
     * Theora properties
     */
    theora_info      ti;                        /* theora bitstream settings */
Gildas Bazin's avatar
 
Gildas Bazin committed
58
    theora_comment   tc;                            /* theora comment header */
Gildas Bazin's avatar
 
Gildas Bazin committed
59 60 61
    theora_state     td;                   /* theora bitstream user comments */

    /*
Gildas Bazin's avatar
 
Gildas Bazin committed
62
     * Output properties
Gildas Bazin's avatar
 
Gildas Bazin committed
63
     */
Gildas Bazin's avatar
 
Gildas Bazin committed
64
    vout_thread_t *p_vout;
Gildas Bazin's avatar
 
Gildas Bazin committed
65 66

    /*
Gildas Bazin's avatar
 
Gildas Bazin committed
67
     * Packetizer output properties
Gildas Bazin's avatar
 
Gildas Bazin committed
68
     */
Gildas Bazin's avatar
 
Gildas Bazin committed
69 70
    sout_packetizer_input_t *p_sout_input;
    sout_format_t           sout_format;
Gildas Bazin's avatar
 
Gildas Bazin committed
71

Gildas Bazin's avatar
 
Gildas Bazin committed
72 73 74 75 76
    /*
     * Common properties
     */
    mtime_t i_pts;
};
Gildas Bazin's avatar
 
Gildas Bazin committed
77 78 79 80

/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
Gildas Bazin's avatar
 
Gildas Bazin committed
81 82 83 84 85 86
static int OpenDecoder   ( vlc_object_t * );
static int OpenPacketizer( vlc_object_t * );

static int InitDecoder   ( decoder_t * );
static int RunDecoder    ( decoder_t *, block_t * );
static int EndDecoder    ( decoder_t * );
Gildas Bazin's avatar
 
Gildas Bazin committed
87

Gildas Bazin's avatar
 
Gildas Bazin committed
88 89 90
static int ProcessPacket ( decoder_t *, ogg_packet *, mtime_t );
static int DecodePacket  ( decoder_t *, ogg_packet * );
static int SendPacket    ( decoder_t *, ogg_packet * );
Gildas Bazin's avatar
 
Gildas Bazin committed
91

Gildas Bazin's avatar
 
Gildas Bazin committed
92 93 94
static void ParseTheoraComments( decoder_t * );

static void theora_CopyPicture( decoder_t *, picture_t *, yuv_buffer * );
95

Gildas Bazin's avatar
 
Gildas Bazin committed
96 97 98 99
/*****************************************************************************
 * Module descriptor
 *****************************************************************************/
vlc_module_begin();
Gildas Bazin's avatar
 
Gildas Bazin committed
100
    set_description( _("Theora video decoder") );
Gildas Bazin's avatar
 
Gildas Bazin committed
101 102 103
    set_capability( "decoder", 100 );
    set_callbacks( OpenDecoder, NULL );
    add_shortcut( "theora" );
Gildas Bazin's avatar
 
Gildas Bazin committed
104 105 106 107 108 109

    add_submodule();
    set_description( _("Theora video packetizer") );
    set_capability( "packetizer", 100 );
    set_callbacks( OpenPacketizer, NULL );
    add_shortcut( "theora" );
Gildas Bazin's avatar
 
Gildas Bazin committed
110 111 112 113 114 115 116
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
117
    decoder_t *p_dec = (decoder_t*)p_this;
Gildas Bazin's avatar
 
Gildas Bazin committed
118

Gildas Bazin's avatar
 
Gildas Bazin committed
119
    if( p_dec->p_fifo->i_fourcc != VLC_FOURCC('t','h','e','o') )
Gildas Bazin's avatar
 
Gildas Bazin committed
120 121 122 123
    {
        return VLC_EGENERIC;
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
124 125 126 127 128 129 130 131 132 133 134 135 136
    p_dec->pf_init = InitDecoder;
    p_dec->pf_decode = RunDecoder;
    p_dec->pf_end = EndDecoder;

    /* Allocate the memory needed to store the decoder's structure */
    if( ( p_dec->p_sys =
          (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
137 138
    return VLC_SUCCESS;
}
Gildas Bazin's avatar
 
Gildas Bazin committed
139 140 141 142 143 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 );

    if( i_ret == VLC_SUCCESS ) p_dec->p_sys->b_packetizer = VLC_TRUE;

    return i_ret;
}

Gildas Bazin's avatar
 
Gildas Bazin committed
151
/*****************************************************************************
Gildas Bazin's avatar
 
Gildas Bazin committed
152
 * InitDecoder: Initalize the decoder
Gildas Bazin's avatar
 
Gildas Bazin committed
153
 *****************************************************************************/
Gildas Bazin's avatar
 
Gildas Bazin committed
154
static int InitDecoder( decoder_t *p_dec )
Gildas Bazin's avatar
 
Gildas Bazin committed
155
{
Gildas Bazin's avatar
 
Gildas Bazin committed
156
    decoder_sys_t *p_sys = p_dec->p_sys;
Gildas Bazin's avatar
 
Gildas Bazin committed
157

Gildas Bazin's avatar
 
Gildas Bazin committed
158
    p_sys->i_pts = 0;
Gildas Bazin's avatar
 
Gildas Bazin committed
159

Gildas Bazin's avatar
 
Gildas Bazin committed
160 161 162 163 164 165 166 167
    p_sys->p_sout_input = NULL;
    p_sys->sout_format.i_cat = VIDEO_ES;
    p_sys->sout_format.i_fourcc = VLC_FOURCC( 't', 'h', 'e', 'o' );
    p_sys->sout_format.i_width  = 0;
    p_sys->sout_format.i_height = 0;
    p_sys->sout_format.i_bitrate     = 0;
    p_sys->sout_format.i_extra_data  = 0;
    p_sys->sout_format.p_extra_data  = NULL;
Gildas Bazin's avatar
 
Gildas Bazin committed
168

Gildas Bazin's avatar
 
Gildas Bazin committed
169
    /* Init supporting Theora structures needed in header parsing */
Gildas Bazin's avatar
 
Gildas Bazin committed
170 171
    theora_comment_init( &p_sys->tc );
    theora_info_init( &p_sys->ti );
Gildas Bazin's avatar
 
Gildas Bazin committed
172

Gildas Bazin's avatar
 
Gildas Bazin committed
173
    p_sys->i_headers = 0;
Gildas Bazin's avatar
 
Gildas Bazin committed
174

Gildas Bazin's avatar
 
Gildas Bazin committed
175 176
    return VLC_SUCCESS;
}
Gildas Bazin's avatar
 
Gildas Bazin committed
177

Gildas Bazin's avatar
 
Gildas Bazin committed
178 179 180 181 182 183 184 185 186 187
/****************************************************************************
 * RunDecoder: the whole thing
 ****************************************************************************
 * This function must be fed with ogg packets.
 ****************************************************************************/
static int RunDecoder( decoder_t *p_dec, block_t *p_block )
{
    decoder_sys_t *p_sys = p_dec->p_sys;
    ogg_packet oggpacket;
    int i_ret;
Gildas Bazin's avatar
 
Gildas Bazin committed
188

Gildas Bazin's avatar
 
Gildas Bazin committed
189 190 191 192 193 194 195
    /* 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
196

Gildas Bazin's avatar
 
Gildas Bazin committed
197
    if( p_sys->i_headers == 0 )
Gildas Bazin's avatar
 
Gildas Bazin committed
198
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
199
        /* Take care of the initial Theora header */
Gildas Bazin's avatar
 
Gildas Bazin committed
200

Gildas Bazin's avatar
 
Gildas Bazin committed
201 202 203 204 205 206 207 208 209
        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 )
        {
            msg_Err( p_dec->p_fifo, "This bitstream does not contain Theora "
                     "video data" );
            block_Release( p_block );
            return VLC_EGENERIC;
        }
        p_sys->i_headers++;
Gildas Bazin's avatar
 
Gildas Bazin committed
210

Gildas Bazin's avatar
 
Gildas Bazin committed
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252
 
        if( p_sys->b_packetizer )
        {
            /* add a input for the stream ouput */
            p_sys->sout_format.i_width  = p_sys->ti.width;
            p_sys->sout_format.i_height = p_sys->ti.height;

            p_sys->p_sout_input =
                sout_InputNew( p_dec, &p_sys->sout_format );

            if( !p_sys->p_sout_input )
            {
                msg_Err( p_dec, "cannot add a new stream" );
                block_Release( p_block );
                return VLC_EGENERIC;
            }
        }
        else
        {
            /* Initialize video output */
            int i_chroma, i_aspect;

            if( p_sys->ti.aspect_denominator )
                i_aspect = VOUT_ASPECT_FACTOR * p_sys->ti.aspect_numerator /
                    p_sys->ti.aspect_denominator;
            else
                i_aspect = VOUT_ASPECT_FACTOR *
                    p_sys->ti.frame_width / p_sys->ti.frame_height;

            i_chroma = VLC_FOURCC('Y','V','1','2');

            p_sys->p_vout =
                vout_Request( p_dec, NULL,
                              p_sys->ti.frame_width, p_sys->ti.frame_height,
                              i_chroma, i_aspect );
            if( p_sys->p_vout == NULL )
            {
                msg_Err( p_dec, "failed to create video output" );
                block_Release( p_block );
                return VLC_EGENERIC;
            }
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
253

Gildas Bazin's avatar
 
Gildas Bazin committed
254 255 256 257 258 259
        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
260

Gildas Bazin's avatar
 
Gildas Bazin committed
261 262 263 264 265 266 267 268 269 270 271 272 273 274
        if( p_sys->b_packetizer )
        {
            i_ret = SendPacket( p_dec, &oggpacket );
            block_Release( p_block );
            return i_ret;
        }
        else
        {
            block_Release( p_block );
            return VLC_SUCCESS;
        }
    }

    if( p_sys->i_headers == 1 )
Gildas Bazin's avatar
 
Gildas Bazin committed
275
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296
        /* 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" );
            return VLC_EGENERIC;
        }
        p_sys->i_headers++;
    
        ParseTheoraComments( p_dec );

        if( p_sys->b_packetizer )
        {
            i_ret = SendPacket( p_dec, &oggpacket );
            block_Release( p_block );
            return i_ret;
        }
        else
        {
            block_Release( p_block );
            return VLC_SUCCESS;
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
297 298
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
299
    if( p_sys->i_headers == 2 )
Gildas Bazin's avatar
 
Gildas Bazin committed
300
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327
        /* 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" );
            return VLC_EGENERIC;
        }
        p_sys->i_headers++;
    
        if( !p_sys->b_packetizer )
        {
            /* We have all the headers, initialize decoder */
            theora_decode_init( &p_sys->td, &p_sys->ti );
        }

        if( p_sys->b_packetizer )
        {
            i_ret = SendPacket( p_dec, &oggpacket );
            block_Release( p_block );
            return i_ret;
        }
        else
        {
            block_Release( p_block );
            return VLC_SUCCESS;
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
328 329
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
330 331 332 333
    i_ret = ProcessPacket( p_dec, &oggpacket, p_block->i_pts );
    block_Release( p_block );
    return i_ret;
}
Gildas Bazin's avatar
 
Gildas Bazin committed
334

Gildas Bazin's avatar
 
Gildas Bazin committed
335 336 337 338 339 340 341
/*****************************************************************************
 * ProcessPacket: processes a Vorbis packet.
 *****************************************************************************/
static int ProcessPacket( decoder_t *p_dec, ogg_packet *p_oggpacket,
                          mtime_t i_pts )
{
    decoder_sys_t *p_sys = p_dec->p_sys;
Gildas Bazin's avatar
 
Gildas Bazin committed
342

Gildas Bazin's avatar
 
Gildas Bazin committed
343 344
    /* Date management */
    if( i_pts > 0 && i_pts != p_sys->i_pts )
Gildas Bazin's avatar
 
Gildas Bazin committed
345
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
346
        p_sys->i_pts = i_pts;
Gildas Bazin's avatar
 
Gildas Bazin committed
347 348
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
349 350 351 352 353 354 355 356
    if( p_sys->b_packetizer )
    {
        return SendPacket( p_dec, p_oggpacket );
    }
    else
    {
        return DecodePacket( p_dec, p_oggpacket );
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
357 358 359 360 361
}

/*****************************************************************************
 * DecodePacket: decodes a Theora packet.
 *****************************************************************************/
Gildas Bazin's avatar
 
Gildas Bazin committed
362
static int DecodePacket( decoder_t *p_dec, ogg_packet *p_oggpacket )
Gildas Bazin's avatar
 
Gildas Bazin committed
363 364 365 366
{
    picture_t *p_pic;
    yuv_buffer yuv;

Gildas Bazin's avatar
 
Gildas Bazin committed
367
    decoder_sys_t *p_sys = p_dec->p_sys;
Gildas Bazin's avatar
 
Gildas Bazin committed
368

Gildas Bazin's avatar
 
Gildas Bazin committed
369
    theora_decode_packetin( &p_sys->td, p_oggpacket );
Gildas Bazin's avatar
 
Gildas Bazin committed
370 371

    /* Decode */
Gildas Bazin's avatar
 
Gildas Bazin committed
372
    theora_decode_YUVout( &p_sys->td, &yuv );
Gildas Bazin's avatar
 
Gildas Bazin committed
373 374

    /* Get a new picture */
Gildas Bazin's avatar
 
Gildas Bazin committed
375
    while( !(p_pic = vout_CreatePicture( p_sys->p_vout, 0, 0, 0 ) ) )
Gildas Bazin's avatar
 
Gildas Bazin committed
376 377 378
    {
        if( p_dec->p_fifo->b_die || p_dec->p_fifo->b_error )
        {
Gildas Bazin's avatar
 
Gildas Bazin committed
379
            return VLC_EGENERIC;
Gildas Bazin's avatar
 
Gildas Bazin committed
380 381 382
        }
        msleep( VOUT_OUTMEM_SLEEP );
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
383
    if( !p_pic ) return VLC_EGENERIC;
Gildas Bazin's avatar
 
Gildas Bazin committed
384 385 386

    theora_CopyPicture( p_dec, p_pic, &yuv );

Gildas Bazin's avatar
 
Gildas Bazin committed
387 388 389 390 391 392 393 394
    vout_DatePicture( p_sys->p_vout, p_pic, p_sys->i_pts );
    vout_DisplayPicture( p_sys->p_vout, p_pic );

    /* Date management */
    p_sys->i_pts += ( 1000000 * p_sys->ti.fps_numerator /
                      p_sys->ti.fps_denominator ); /* 1 frame per packet */

    return VLC_SUCCESS;
Gildas Bazin's avatar
 
Gildas Bazin committed
395 396 397
}

/*****************************************************************************
Gildas Bazin's avatar
 
Gildas Bazin committed
398
 * SendPacket: send an ogg packet to the stream output.
Gildas Bazin's avatar
 
Gildas Bazin committed
399
 *****************************************************************************/
Gildas Bazin's avatar
 
Gildas Bazin committed
400
static int SendPacket( decoder_t *p_dec, ogg_packet *p_oggpacket )
Gildas Bazin's avatar
 
Gildas Bazin committed
401
{
Gildas Bazin's avatar
 
Gildas Bazin committed
402 403 404 405
    decoder_sys_t *p_sys = p_dec->p_sys;

    sout_buffer_t *p_sout_buffer =
        sout_BufferNew( p_sys->p_sout_input->p_sout, p_oggpacket->bytes );
Gildas Bazin's avatar
 
Gildas Bazin committed
406

Gildas Bazin's avatar
 
Gildas Bazin committed
407
    if( !p_sout_buffer ) return VLC_EGENERIC;
Gildas Bazin's avatar
 
Gildas Bazin committed
408

Gildas Bazin's avatar
 
Gildas Bazin committed
409 410 411
    p_dec->p_vlc->pf_memcpy( p_sout_buffer->p_buffer,
                             p_oggpacket->packet,
                             p_oggpacket->bytes );
Gildas Bazin's avatar
 
Gildas Bazin committed
412

Gildas Bazin's avatar
 
Gildas Bazin committed
413 414 415 416 417 418 419 420 421 422 423
    /* Date management */
    p_sout_buffer->i_dts = p_sout_buffer->i_pts = p_sys->i_pts;
    p_sys->i_pts += ( 1000000 * p_sys->ti.fps_numerator /
                      p_sys->ti.fps_denominator ); /* 1 frame per packet */

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

    sout_InputSendBuffer( p_sys->p_sout_input, p_sout_buffer );
Gildas Bazin's avatar
 
Gildas Bazin committed
424 425 426 427 428

    return VLC_SUCCESS;
}

/*****************************************************************************
Gildas Bazin's avatar
 
Gildas Bazin committed
429
 * ParseTheoraComments: FIXME should be done in demuxer
Gildas Bazin's avatar
 
Gildas Bazin committed
430
 *****************************************************************************/
Gildas Bazin's avatar
 
Gildas Bazin committed
431
static void ParseTheoraComments( decoder_t *p_dec )
Gildas Bazin's avatar
 
Gildas Bazin committed
432
{
Gildas Bazin's avatar
 
Gildas Bazin committed
433 434 435 436 437 438
    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
439
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464
        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++;
    }
}

/*****************************************************************************
 * EndDecoder: theora decoder destruction
 *****************************************************************************/
static int EndDecoder( decoder_t *p_dec )
{
    decoder_sys_t *p_sys = p_dec->p_sys;
Gildas Bazin's avatar
 
Gildas Bazin committed
465

Gildas Bazin's avatar
 
Gildas Bazin committed
466 467
    if( !p_sys->b_packetizer )
        vout_Request( p_dec, p_sys->p_vout, 0, 0, 0, 0 );
Gildas Bazin's avatar
 
Gildas Bazin committed
468

Gildas Bazin's avatar
 
Gildas Bazin committed
469 470
    theora_info_clear( &p_sys->ti );
    theora_comment_clear( &p_sys->tc );
Gildas Bazin's avatar
 
Gildas Bazin committed
471

Gildas Bazin's avatar
 
Gildas Bazin committed
472 473 474
    free( p_sys );

    return VLC_SUCCESS;
Gildas Bazin's avatar
 
Gildas Bazin committed
475 476 477 478 479 480
}

/*****************************************************************************
 * theora_CopyPicture: copy a picture from theora internal buffers to a
 *                     picture_t structure.
 *****************************************************************************/
Gildas Bazin's avatar
 
Gildas Bazin committed
481
static void theora_CopyPicture( decoder_t *p_dec, picture_t *p_pic,
Gildas Bazin's avatar
 
Gildas Bazin committed
482 483 484
                                yuv_buffer *yuv )
{
    int i_plane, i_line, i_width, i_dst_stride, i_src_stride;
Gildas Bazin's avatar
 
Gildas Bazin committed
485
    int i_src_xoffset, i_src_yoffset;
Gildas Bazin's avatar
 
Gildas Bazin committed
486 487 488 489 490 491 492
    u8  *p_dst, *p_src;

    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
493 494 495 496 497 498 499 500 501 502 503
        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;
        } 

        p_src += (i_src_yoffset * i_src_stride + i_src_yoffset);
Gildas Bazin's avatar
 
Gildas Bazin committed
504 505 506

        for( i_line = 0; i_line < p_pic->p[i_plane].i_lines; i_line++ )
        {
Gildas Bazin's avatar
 
Gildas Bazin committed
507
            p_dec->p_vlc->pf_memcpy( p_dst, p_src, i_width );
Gildas Bazin's avatar
 
Gildas Bazin committed
508 509 510 511 512
            p_src += i_src_stride;
            p_dst += i_dst_stride;
        }
    }
}