theora.c 26.6 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
 * 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>
29
#include <vlc/input.h>
30
#include <vlc/sout.h>
Gildas Bazin's avatar
 
Gildas Bazin committed
31 32 33 34 35 36

#include <ogg/ogg.h>

#include <theora/theora.h>

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

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

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

56 57 58 59 60
    /*
     * Decoding properties
     */
    vlc_bool_t b_decoded_first_keyframe;

Gildas Bazin's avatar
 
Gildas Bazin committed
61 62 63 64 65
    /*
     * Common properties
     */
    mtime_t i_pts;
};
Gildas Bazin's avatar
 
Gildas Bazin committed
66 67 68 69

/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
Gildas Bazin's avatar
 
Gildas Bazin committed
70 71 72
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
73

Gildas Bazin's avatar
 
Gildas Bazin committed
74
static void *DecodeBlock  ( decoder_t *, block_t ** );
75
static int  ProcessHeaders( decoder_t * );
Gildas Bazin's avatar
 
Gildas Bazin committed
76
static void *ProcessPacket ( decoder_t *, ogg_packet *, block_t ** );
Gildas Bazin's avatar
 
Gildas Bazin committed
77

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

Gildas Bazin's avatar
 
Gildas Bazin committed
80 81
static void ParseTheoraComments( decoder_t * );
static void theora_CopyPicture( decoder_t *, picture_t *, yuv_buffer * );
82

Gildas Bazin's avatar
 
Gildas Bazin committed
83 84 85 86
static int  OpenEncoder( vlc_object_t *p_this );
static void CloseEncoder( vlc_object_t *p_this );
static block_t *Encode( encoder_t *p_enc, picture_t *p_pict );

Gildas Bazin's avatar
 
Gildas Bazin committed
87 88 89
/*****************************************************************************
 * Module descriptor
 *****************************************************************************/
90 91 92 93 94
#define ENC_QUALITY_TEXT N_("Encoding quality")
#define ENC_QUALITY_LONGTEXT N_( \
  "Allows you to specify a quality between 1 (low) and 10 (high), instead " \
  "of specifying a particular bitrate. This will produce a VBR stream." )

Gildas Bazin's avatar
 
Gildas Bazin committed
95
vlc_module_begin();
96 97
    set_category( CAT_INPUT );
    set_subcategory( SUBCAT_INPUT_VCODEC );
Gildas Bazin's avatar
 
Gildas Bazin committed
98
    set_description( _("Theora video decoder") );
Gildas Bazin's avatar
 
Gildas Bazin committed
99
    set_capability( "decoder", 100 );
Gildas Bazin's avatar
 
Gildas Bazin committed
100
    set_callbacks( OpenDecoder, CloseDecoder );
Gildas Bazin's avatar
 
Gildas Bazin committed
101
    add_shortcut( "theora" );
Gildas Bazin's avatar
 
Gildas Bazin committed
102 103 104 105

    add_submodule();
    set_description( _("Theora video packetizer") );
    set_capability( "packetizer", 100 );
Gildas Bazin's avatar
 
Gildas Bazin committed
106
    set_callbacks( OpenPacketizer, CloseDecoder );
Gildas Bazin's avatar
 
Gildas Bazin committed
107
    add_shortcut( "theora" );
Gildas Bazin's avatar
 
Gildas Bazin committed
108 109 110

    add_submodule();
    set_description( _("Theora video encoder") );
Gildas Bazin's avatar
 
Gildas Bazin committed
111
    set_capability( "encoder", 100 );
Gildas Bazin's avatar
 
Gildas Bazin committed
112 113
    set_callbacks( OpenEncoder, CloseEncoder );
    add_shortcut( "theora" );
114 115 116 117

#   define ENC_CFG_PREFIX "sout-theora-"
    add_integer( ENC_CFG_PREFIX "quality", 2, NULL, ENC_QUALITY_TEXT,
                 ENC_QUALITY_LONGTEXT, VLC_FALSE );
Gildas Bazin's avatar
 
Gildas Bazin committed
118 119
vlc_module_end();

120 121 122 123
static const char *ppsz_enc_options[] = {
    "quality", NULL
};

Gildas Bazin's avatar
 
Gildas Bazin committed
124 125 126 127 128
/*****************************************************************************
 * OpenDecoder: probe the decoder and return score
 *****************************************************************************/
static int OpenDecoder( vlc_object_t *p_this )
{
Gildas Bazin's avatar
 
Gildas Bazin committed
129
    decoder_t *p_dec = (decoder_t*)p_this;
Gildas Bazin's avatar
 
Gildas Bazin committed
130
    decoder_sys_t *p_sys;
Gildas Bazin's avatar
 
Gildas Bazin committed
131

Gildas Bazin's avatar
 
Gildas Bazin committed
132
    if( p_dec->fmt_in.i_codec != VLC_FOURCC('t','h','e','o') )
Gildas Bazin's avatar
 
Gildas Bazin committed
133 134 135 136
    {
        return VLC_EGENERIC;
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
137
    /* Allocate the memory needed to store the decoder's structure */
Gildas Bazin's avatar
 
Gildas Bazin committed
138
    if( ( p_dec->p_sys = p_sys =
Gildas Bazin's avatar
 
Gildas Bazin committed
139 140 141 142 143 144 145
          (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
146
    p_sys->i_pts = 0;
147
    p_sys->b_decoded_first_keyframe = VLC_FALSE;
Gildas Bazin's avatar
 
Gildas Bazin committed
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164

    /* 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
165 166
    return VLC_SUCCESS;
}
Gildas Bazin's avatar
 
Gildas Bazin committed
167 168 169 170 171 172 173

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
174 175 176 177 178
    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
179 180 181 182 183

    return i_ret;
}

/****************************************************************************
Gildas Bazin's avatar
 
Gildas Bazin committed
184
 * DecodeBlock: the whole thing
Gildas Bazin's avatar
 
Gildas Bazin committed
185 186 187
 ****************************************************************************
 * This function must be fed with ogg packets.
 ****************************************************************************/
Gildas Bazin's avatar
 
Gildas Bazin committed
188
static void *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
Gildas Bazin's avatar
 
Gildas Bazin committed
189 190
{
    decoder_sys_t *p_sys = p_dec->p_sys;
Gildas Bazin's avatar
 
Gildas Bazin committed
191
    block_t *p_block;
Gildas Bazin's avatar
 
Gildas Bazin committed
192
    ogg_packet oggpacket;
Gildas Bazin's avatar
 
Gildas Bazin committed
193 194 195 196

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

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

Gildas Bazin's avatar
 
Gildas Bazin committed
198 199 200 201 202 203 204
    /* 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
205

206 207
    /* Check for headers */
    if( p_sys->i_headers == 0 && p_dec->fmt_in.i_extra )
Gildas Bazin's avatar
 
Gildas Bazin committed
208
    {
209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
        /* Headers already available as extra data */
        p_sys->i_headers = 3;
    }
    else if( oggpacket.bytes && p_sys->i_headers < 3 )
    {
        /* Backup headers as extra data */
        uint8_t *p_extra;

        p_dec->fmt_in.p_extra =
            realloc( p_dec->fmt_in.p_extra, p_dec->fmt_in.i_extra +
                     oggpacket.bytes + 2 );
        p_extra = p_dec->fmt_in.p_extra + p_dec->fmt_in.i_extra;
        *(p_extra++) = oggpacket.bytes >> 8;
        *(p_extra++) = oggpacket.bytes & 0xFF;

        memcpy( p_extra, oggpacket.packet, oggpacket.bytes );
        p_dec->fmt_in.i_extra += oggpacket.bytes + 2;

        block_Release( *pp_block );
        p_sys->i_headers++;
        return NULL;
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
231

232 233 234
    if( p_sys->i_headers == 3 )
    {
        if( ProcessHeaders( p_dec ) != VLC_SUCCESS )
Gildas Bazin's avatar
 
Gildas Bazin committed
235
        {
236 237 238
            p_sys->i_headers = 0;
            p_dec->fmt_in.i_extra = 0;
            block_Release( *pp_block );
Gildas Bazin's avatar
 
Gildas Bazin committed
239
            return NULL;
Gildas Bazin's avatar
 
Gildas Bazin committed
240
        }
241 242
        else p_sys->i_headers++;
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
243

244 245
    return ProcessPacket( p_dec, &oggpacket, pp_block );
}
Sam Hocevar's avatar
Sam Hocevar committed
246

247 248 249 250 251 252 253 254 255
/*****************************************************************************
 * ProcessHeaders: process Theora headers.
 *****************************************************************************/
static int ProcessHeaders( decoder_t *p_dec )
{
    decoder_sys_t *p_sys = p_dec->p_sys;
    ogg_packet oggpacket;
    uint8_t *p_extra;
    int i_extra;
Gildas Bazin's avatar
 
Gildas Bazin committed
256

257
    if( !p_dec->fmt_in.i_extra ) return VLC_EGENERIC;
Gildas Bazin's avatar
 
Gildas Bazin committed
258

259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275
    oggpacket.granulepos = -1;
    oggpacket.b_o_s = 1; /* yes this actually is a b_o_s packet :) */
    oggpacket.e_o_s = 0;
    oggpacket.packetno = 0;
    p_extra = p_dec->fmt_in.p_extra;
    i_extra = p_dec->fmt_in.i_extra;

    /* Take care of the initial Vorbis header */
    oggpacket.bytes = *(p_extra++) << 8;
    oggpacket.bytes |= (*(p_extra++) & 0xFF);
    oggpacket.packet = p_extra;
    p_extra += oggpacket.bytes;
    i_extra -= (oggpacket.bytes + 2);
    if( i_extra < 0 )
    {
        msg_Err( p_dec, "header data corrupted");
        return VLC_EGENERIC;
Gildas Bazin's avatar
 
Gildas Bazin committed
276 277
    }

278
    if( theora_decode_header( &p_sys->ti, &p_sys->tc, &oggpacket ) < 0 )
Gildas Bazin's avatar
 
Gildas Bazin committed
279
    {
280 281 282
        msg_Err( p_dec, "This bitstream does not contain Theora video data" );
        return VLC_EGENERIC;
    }
Sam Hocevar's avatar
Sam Hocevar committed
283

284 285 286
    /* 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;
287 288 289 290 291
    if( p_sys->ti.frame_width && p_sys->ti.frame_height )
    {
        p_dec->fmt_out.video.i_width = p_sys->ti.frame_width;
        p_dec->fmt_out.video.i_height = p_sys->ti.frame_height;
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
292

293 294 295 296 297
    if( p_sys->ti.aspect_denominator && p_sys->ti.aspect_numerator )
    {
        p_dec->fmt_out.video.i_aspect = ((int64_t)VOUT_ASPECT_FACTOR) *
            ( p_sys->ti.aspect_numerator * p_sys->ti.width ) /
            ( p_sys->ti.aspect_denominator * p_sys->ti.height );
Gildas Bazin's avatar
 
Gildas Bazin committed
298
    }
299 300 301 302 303 304
    else
    {
        p_dec->fmt_out.video.i_aspect = VOUT_ASPECT_FACTOR *
            p_sys->ti.frame_width / p_sys->ti.frame_height;
    }

305 306 307 308 309 310
    if( p_sys->ti.fps_numerator > 0 && p_sys->ti.fps_denominator > 0 )
    {
        p_dec->fmt_out.video.i_frame_rate = p_sys->ti.fps_numerator;
        p_dec->fmt_out.video.i_frame_rate_base = p_sys->ti.fps_denominator;
    }

311 312 313 314 315 316
    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
317

318 319 320 321 322 323 324 325
    /* The next packet in order is the comments header */
    oggpacket.b_o_s = 0;
    oggpacket.bytes = *(p_extra++) << 8;
    oggpacket.bytes |= (*(p_extra++) & 0xFF);
    oggpacket.packet = p_extra;
    p_extra += oggpacket.bytes;
    i_extra -= (oggpacket.bytes + 2);
    if( i_extra < 0 )
Gildas Bazin's avatar
 
Gildas Bazin committed
326
    {
327 328 329
        msg_Err( p_dec, "header data corrupted");
        return VLC_EGENERIC;
    }
Sam Hocevar's avatar
Sam Hocevar committed
330

331 332 333 334 335 336 337 338
    /* 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;
    }

    ParseTheoraComments( p_dec );
Gildas Bazin's avatar
 
Gildas Bazin committed
339

340 341 342 343 344 345 346 347 348 349 350
    /* 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. */
    oggpacket.bytes = *(p_extra++) << 8;
    oggpacket.bytes |= (*(p_extra++) & 0xFF);
    oggpacket.packet = p_extra;
    i_extra -= (oggpacket.bytes + 2);
    if( i_extra < 0 )
    {
        msg_Err( p_dec, "header data corrupted");
        return VLC_EGENERIC;
Gildas Bazin's avatar
 
Gildas Bazin committed
351 352
    }

353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376
    /* 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;
    }

    if( !p_sys->b_packetizer )
    {
        /* We have all the headers, initialize decoder */
        theora_decode_init( &p_sys->td, &p_sys->ti );
    }
    else
    {
        p_dec->fmt_out.i_extra = p_dec->fmt_in.i_extra;
        p_dec->fmt_out.p_extra =
            realloc( p_dec->fmt_out.p_extra, p_dec->fmt_out.i_extra );
        memcpy( p_dec->fmt_out.p_extra,
                p_dec->fmt_in.p_extra, p_dec->fmt_out.i_extra );
    }

    return VLC_SUCCESS;
Gildas Bazin's avatar
 
Gildas Bazin committed
377
}
Gildas Bazin's avatar
 
Gildas Bazin committed
378

Gildas Bazin's avatar
 
Gildas Bazin committed
379
/*****************************************************************************
Gildas Bazin's avatar
 
Gildas Bazin committed
380
 * ProcessPacket: processes a theora packet.
Gildas Bazin's avatar
 
Gildas Bazin committed
381
 *****************************************************************************/
Gildas Bazin's avatar
 
Gildas Bazin committed
382 383
static void *ProcessPacket( decoder_t *p_dec, ogg_packet *p_oggpacket,
                            block_t **pp_block )
Gildas Bazin's avatar
 
Gildas Bazin committed
384 385
{
    decoder_sys_t *p_sys = p_dec->p_sys;
Gildas Bazin's avatar
 
Gildas Bazin committed
386 387
    block_t *p_block = *pp_block;
    void *p_buf;
Gildas Bazin's avatar
 
Gildas Bazin committed
388

Laurent Aimar's avatar
Laurent Aimar committed
389
    if( ( p_block->i_flags&(BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) ) != 0 )
390 391 392 393 394 395 396
    {
        /* Don't send the the first packet after a discontinuity to
         * theora_decode, otherwise we get purple/green display artifacts
         * appearing in the video output */
        return NULL;
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
397
    /* Date management */
Gildas Bazin's avatar
 
Gildas Bazin committed
398
    if( p_block->i_pts > 0 && p_block->i_pts != p_sys->i_pts )
Gildas Bazin's avatar
 
Gildas Bazin committed
399
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
400
        p_sys->i_pts = p_block->i_pts;
Gildas Bazin's avatar
 
Gildas Bazin committed
401 402
    }

403 404
    *pp_block = NULL; /* To avoid being fed the same packet again */

Gildas Bazin's avatar
 
Gildas Bazin committed
405 406
    if( p_sys->b_packetizer )
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
407 408 409 410 411 412 413 414 415
        /* 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
416 417 418
    }
    else
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
419 420 421 422
        if( p_sys->i_headers >= 3 )
            p_buf = DecodePacket( p_dec, p_oggpacket );
        else
            p_buf = NULL;
Gildas Bazin's avatar
 
Gildas Bazin committed
423

424
        if( p_block ) block_Release( p_block );
Gildas Bazin's avatar
 
Gildas Bazin committed
425
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
426 427

    /* Date management */
Gildas Bazin's avatar
 
Gildas Bazin committed
428 429
    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
430

Gildas Bazin's avatar
 
Gildas Bazin committed
431
    return p_buf;
Gildas Bazin's avatar
 
Gildas Bazin committed
432 433 434
}

/*****************************************************************************
Gildas Bazin's avatar
 
Gildas Bazin committed
435
 * DecodePacket: decodes a Theora packet.
Gildas Bazin's avatar
 
Gildas Bazin committed
436
 *****************************************************************************/
Gildas Bazin's avatar
 
Gildas Bazin committed
437
static picture_t *DecodePacket( decoder_t *p_dec, ogg_packet *p_oggpacket )
Gildas Bazin's avatar
 
Gildas Bazin committed
438
{
Gildas Bazin's avatar
 
Gildas Bazin committed
439
    decoder_sys_t *p_sys = p_dec->p_sys;
Gildas Bazin's avatar
 
Gildas Bazin committed
440 441
    picture_t *p_pic;
    yuv_buffer yuv;
Gildas Bazin's avatar
 
Gildas Bazin committed
442

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

445 446 447
    /* Check for keyframe */
    if( !(p_oggpacket->packet[0] & 0x80) /* data packet */ &&
        !(p_oggpacket->packet[0] & 0x40) /* intra frame */ )
448 449 450 451 452 453 454 455 456 457 458
        p_sys->b_decoded_first_keyframe = VLC_TRUE;

    /* If we haven't seen a single keyframe yet, don't let Theora decode
     * anything, otherwise we'll get display artifacts.  (This is impossible
     * in the general case, but can happen if e.g. we play a network stream
     * using a timed URL, such that the server doesn't start the video with a
     * keyframe). */
    if( p_sys->b_decoded_first_keyframe )
        theora_decode_YUVout( &p_sys->td, &yuv );
    else
        return NULL;
Gildas Bazin's avatar
 
Gildas Bazin committed
459

Gildas Bazin's avatar
 
Gildas Bazin committed
460 461 462
    /* 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
463

Gildas Bazin's avatar
 
Gildas Bazin committed
464
    theora_CopyPicture( p_dec, p_pic, &yuv );
Gildas Bazin's avatar
 
Gildas Bazin committed
465

Gildas Bazin's avatar
 
Gildas Bazin committed
466
    p_pic->date = p_sys->i_pts;
Gildas Bazin's avatar
 
Gildas Bazin committed
467

Gildas Bazin's avatar
 
Gildas Bazin committed
468
    return p_pic;
Gildas Bazin's avatar
 
Gildas Bazin committed
469 470 471
}

/*****************************************************************************
Gildas Bazin's avatar
 
Gildas Bazin committed
472
 * ParseTheoraComments: FIXME should be done in demuxer
Gildas Bazin's avatar
 
Gildas Bazin committed
473
 *****************************************************************************/
Gildas Bazin's avatar
 
Gildas Bazin committed
474
static void ParseTheoraComments( decoder_t *p_dec )
Gildas Bazin's avatar
 
Gildas Bazin committed
475
{
Gildas Bazin's avatar
 
Gildas Bazin committed
476 477
    input_thread_t *p_input = (input_thread_t *)p_dec->p_parent;
    char *psz_name, *psz_value, *psz_comment;
478 479 480 481
    int i = 0;

    if( p_input->i_object_type != VLC_OBJECT_INPUT ) return;

Gildas Bazin's avatar
 
Gildas Bazin committed
482
    while ( i < p_dec->p_sys->tc.comments )
Gildas Bazin's avatar
 
Gildas Bazin committed
483
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
484 485 486
        psz_comment = strdup( p_dec->p_sys->tc.user_comments[i] );
        if( !psz_comment )
        {
Benjamin Pracht's avatar
Benjamin Pracht committed
487
            msg_Warn( p_dec, "out of memory" );
Gildas Bazin's avatar
 
Gildas Bazin committed
488 489 490 491 492 493 494 495
            break;
        }
        psz_name = psz_comment;
        psz_value = strchr( psz_comment, '=' );
        if( psz_value )
        {
            *psz_value = '\0';
            psz_value++;
496 497
            input_Control( p_input, INPUT_ADD_INFO, _("Theora comment"),
                           psz_name, psz_value );
Gildas Bazin's avatar
 
Gildas Bazin committed
498 499 500 501 502 503 504
        }
        free( psz_comment );
        i++;
    }
}

/*****************************************************************************
Gildas Bazin's avatar
 
Gildas Bazin committed
505
 * CloseDecoder: theora decoder destruction
Gildas Bazin's avatar
 
Gildas Bazin committed
506
 *****************************************************************************/
Gildas Bazin's avatar
 
Gildas Bazin committed
507
static void CloseDecoder( vlc_object_t *p_this )
Gildas Bazin's avatar
 
Gildas Bazin committed
508
{
Gildas Bazin's avatar
 
Gildas Bazin committed
509
    decoder_t *p_dec = (decoder_t *)p_this;
Gildas Bazin's avatar
 
Gildas Bazin committed
510
    decoder_sys_t *p_sys = p_dec->p_sys;
Gildas Bazin's avatar
 
Gildas Bazin committed
511

Gildas Bazin's avatar
 
Gildas Bazin committed
512 513
    theora_info_clear( &p_sys->ti );
    theora_comment_clear( &p_sys->tc );
Gildas Bazin's avatar
 
Gildas Bazin committed
514

Gildas Bazin's avatar
 
Gildas Bazin committed
515
    free( p_sys );
Gildas Bazin's avatar
 
Gildas Bazin committed
516 517 518 519 520 521
}

/*****************************************************************************
 * theora_CopyPicture: copy a picture from theora internal buffers to a
 *                     picture_t structure.
 *****************************************************************************/
Gildas Bazin's avatar
 
Gildas Bazin committed
522
static void theora_CopyPicture( decoder_t *p_dec, picture_t *p_pic,
Gildas Bazin's avatar
 
Gildas Bazin committed
523 524 525
                                yuv_buffer *yuv )
{
    int i_plane, i_line, i_width, i_dst_stride, i_src_stride;
Gildas Bazin's avatar
 
Gildas Bazin committed
526
    int i_src_xoffset, i_src_yoffset;
Sam Hocevar's avatar
Sam Hocevar committed
527
    uint8_t *p_dst, *p_src;
Gildas Bazin's avatar
 
Gildas Bazin committed
528 529 530 531 532 533

    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
534 535 536 537 538 539 540 541
        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
542
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
543 544

        p_src += (i_src_yoffset * i_src_stride + i_src_yoffset);
Gildas Bazin's avatar
 
Gildas Bazin committed
545

546
        for( i_line = 0; i_line < p_pic->p[i_plane].i_visible_lines; i_line++ )
Gildas Bazin's avatar
 
Gildas Bazin committed
547
        {
548 549
            p_dec->p_vlc->pf_memcpy( p_dst, p_src + i_src_xoffset,
                                     i_plane ? yuv->uv_width : yuv->y_width );
Gildas Bazin's avatar
 
Gildas Bazin committed
550 551 552 553 554
            p_src += i_src_stride;
            p_dst += i_dst_stride;
        }
    }
}
Gildas Bazin's avatar
 
Gildas Bazin committed
555 556 557 558 559 560 561 562 563

/*****************************************************************************
 * encoder_sys_t : theora encoder descriptor
 *****************************************************************************/
struct encoder_sys_t
{
    /*
     * Input properties
     */
Gildas Bazin's avatar
 
Gildas Bazin committed
564
    vlc_bool_t b_headers;
Gildas Bazin's avatar
 
Gildas Bazin committed
565 566 567 568 569 570 571 572

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

573
    int i_width, i_height;
Gildas Bazin's avatar
 
Gildas Bazin committed
574 575 576 577 578 579 580 581 582
};

/*****************************************************************************
 * 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;
583
    ogg_packet header;
584
    uint8_t *p_extra;
585
    vlc_value_t val;
586
    int i_quality, i;
Gildas Bazin's avatar
 
Gildas Bazin committed
587

588 589
    if( p_enc->fmt_out.i_codec != VLC_FOURCC('t','h','e','o') &&
        !p_enc->b_force )
Gildas Bazin's avatar
 
Gildas Bazin committed
590 591 592 593 594 595 596 597 598 599 600 601 602
    {
        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_encode_video = Encode;
Gildas Bazin's avatar
 
Gildas Bazin committed
603
    p_enc->fmt_in.i_codec = VLC_FOURCC('I','4','2','0');
604
    p_enc->fmt_out.i_codec = VLC_FOURCC('t','h','e','o');
Gildas Bazin's avatar
 
Gildas Bazin committed
605

606
    sout_CfgParse( p_enc, ENC_CFG_PREFIX, ppsz_enc_options, p_enc->p_cfg );
607 608 609 610 611 612

    var_Get( p_enc, ENC_CFG_PREFIX "quality", &val );
    i_quality = val.i_int;
    if( i_quality > 10 ) i_quality = 10;
    if( i_quality < 0 ) i_quality = 0;

Gildas Bazin's avatar
 
Gildas Bazin committed
613 614
    theora_info_init( &p_sys->ti );

Gildas Bazin's avatar
 
Gildas Bazin committed
615 616
    p_sys->ti.width = p_enc->fmt_in.video.i_width;
    p_sys->ti.height = p_enc->fmt_in.video.i_height;
617 618 619 620 621 622 623 624 625 626 627 628 629

    if( p_sys->ti.width % 16 || p_sys->ti.height % 16 )
    {
        /* Pictures from the transcoder should always have a pitch
         * which is a multiple of 16 */
        p_sys->ti.width = (p_sys->ti.width + 15) >> 4 << 4;
        p_sys->ti.height = (p_sys->ti.height + 15) >> 4 << 4;

        msg_Dbg( p_enc, "padding video from %dx%d to %dx%d",
                 p_enc->fmt_in.video.i_width, p_enc->fmt_in.video.i_height,
                 p_sys->ti.width, p_sys->ti.height );
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
630 631
    p_sys->ti.frame_width = p_enc->fmt_in.video.i_width;
    p_sys->ti.frame_height = p_enc->fmt_in.video.i_height;
632
    p_sys->ti.offset_x = 0 /*frame_x_offset*/;
633
    p_sys->ti.offset_y = 0 /*frame_y_offset*/;
634

635 636 637
    p_sys->i_width = p_sys->ti.width;
    p_sys->i_height = p_sys->ti.height;

638 639 640 641 642 643 644 645 646 647 648
    if( !p_enc->fmt_in.video.i_frame_rate ||
        !p_enc->fmt_in.video.i_frame_rate_base )
    {
        p_sys->ti.fps_numerator = 25;
        p_sys->ti.fps_denominator = 1;
    }
    else
    {
        p_sys->ti.fps_numerator = p_enc->fmt_in.video.i_frame_rate;
        p_sys->ti.fps_denominator = p_enc->fmt_in.video.i_frame_rate_base;
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
649 650 651

    if( p_enc->fmt_in.video.i_aspect )
    {
652 653 654 655 656 657 658 659
        int64_t i_num, i_den;
        int i_dst_num, i_dst_den;

        i_num = p_enc->fmt_in.video.i_aspect * (int64_t)p_sys->ti.height;
        i_den = VOUT_ASPECT_FACTOR * p_sys->ti.width;
        vlc_reduce( &i_dst_num, &i_dst_den, i_num, i_den, 0 );
        p_sys->ti.aspect_numerator = i_dst_num;
        p_sys->ti.aspect_denominator = i_dst_den;
Gildas Bazin's avatar
 
Gildas Bazin committed
660 661 662 663 664 665 666
    }
    else
    {
        p_sys->ti.aspect_numerator = 4;
        p_sys->ti.aspect_denominator = 3;
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
667
    p_sys->ti.target_bitrate = p_enc->fmt_out.i_bitrate;
668
    p_sys->ti.quality = ((float)i_quality) * 6.3;
Gildas Bazin's avatar
 
Gildas Bazin committed
669 670 671 672 673 674

    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
675
    p_sys->ti.keyframe_data_target_bitrate = p_enc->fmt_out.i_bitrate * 1.5;
Gildas Bazin's avatar
 
Gildas Bazin committed
676 677 678 679 680 681
    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
682
    theora_comment_init( &p_sys->tc );
Gildas Bazin's avatar
 
Gildas Bazin committed
683

684
    /* Create and store headers */
685
    p_enc->fmt_out.i_extra = 3 * 2;
686
    for( i = 0; i < 3; i++ )
Gildas Bazin's avatar
 
Gildas Bazin committed
687
    {
688 689 690 691 692 693 694 695 696 697 698 699 700 701 702
        if( i == 0 ) theora_encode_header( &p_sys->td, &header );
        else if( i == 1 ) theora_encode_comment( &p_sys->tc, &header );
        else if( i == 2 ) theora_encode_tables( &p_sys->td, &header );

        p_enc->fmt_out.p_extra =
            realloc( p_enc->fmt_out.p_extra,
                     p_enc->fmt_out.i_extra + header.bytes );
        p_extra = p_enc->fmt_out.p_extra;
        p_extra += p_enc->fmt_out.i_extra + (i-3)*2;
        p_enc->fmt_out.i_extra += header.bytes;

        *(p_extra++) = header.bytes >> 8;
        *(p_extra++) = header.bytes & 0xFF;

        memcpy( p_extra, header.packet, header.bytes );
Gildas Bazin's avatar
 
Gildas Bazin committed
703 704
    }

705
    return VLC_SUCCESS;
Gildas Bazin's avatar
 
Gildas Bazin committed
706 707 708 709 710 711 712 713 714 715 716 717 718
}

/****************************************************************************
 * 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;
719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772
    int i;

    /* Sanity check */
    if( p_pict->p[0].i_pitch < (int)p_sys->i_width ||
        p_pict->p[0].i_lines < (int)p_sys->i_height )
    {
        msg_Warn( p_enc, "frame is smaller than encoding size"
                  "(%ix%i->%ix%i) -> dropping frame",
                  p_pict->p[0].i_pitch, p_pict->p[0].i_lines,
                  p_sys->i_width, p_sys->i_height );
        return NULL;
    }

    /* Fill padding */
    if( p_pict->p[0].i_visible_pitch < (int)p_sys->i_width )
    {
        for( i = 0; i < p_sys->i_height; i++ )
        {
            memset( p_pict->p[0].p_pixels + i * p_pict->p[0].i_pitch +
                    p_pict->p[0].i_visible_pitch,
                    *( p_pict->p[0].p_pixels + i * p_pict->p[0].i_pitch +
                       p_pict->p[0].i_visible_pitch - 1 ),
                    p_sys->i_width - p_pict->p[0].i_visible_pitch );
        }
        for( i = 0; i < p_sys->i_height / 2; i++ )
        {
            memset( p_pict->p[1].p_pixels + i * p_pict->p[1].i_pitch +
                    p_pict->p[1].i_visible_pitch,
                    *( p_pict->p[1].p_pixels + i * p_pict->p[1].i_pitch +
                       p_pict->p[1].i_visible_pitch - 1 ),
                    p_sys->i_width / 2 - p_pict->p[1].i_visible_pitch );
            memset( p_pict->p[2].p_pixels + i * p_pict->p[2].i_pitch +
                    p_pict->p[2].i_visible_pitch,
                    *( p_pict->p[2].p_pixels + i * p_pict->p[2].i_pitch +
                       p_pict->p[2].i_visible_pitch - 1 ),
                    p_sys->i_width / 2 - p_pict->p[2].i_visible_pitch );
        }
    }

    if( p_pict->p[0].i_visible_lines < (int)p_sys->i_height )
    {
        for( i = p_pict->p[0].i_visible_lines; i < p_sys->i_height; i++ )
        {
            memset( p_pict->p[0].p_pixels + i * p_pict->p[0].i_pitch, 0,
                    p_sys->i_width );
        }
        for( i = p_pict->p[1].i_visible_lines; i < p_sys->i_height / 2; i++ )
        {
            memset( p_pict->p[1].p_pixels + i * p_pict->p[1].i_pitch, 0x80,
                    p_sys->i_width / 2 );
            memset( p_pict->p[2].p_pixels + i * p_pict->p[2].i_pitch, 0x80,
                    p_sys->i_width / 2 );
        }
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
773 774 775 776

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

777 778
    yuv.y_width  = p_sys->i_width;
    yuv.y_height = p_sys->i_height;
Gildas Bazin's avatar
 
Gildas Bazin committed
779 780
    yuv.y_stride = p_pict->p[0].i_pitch;

781 782
    yuv.uv_width  = p_sys->i_width / 2;
    yuv.uv_height = p_sys->i_height / 2;
Gildas Bazin's avatar
 
Gildas Bazin committed
783 784 785 786 787 788
    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
789 790 791 792 793
    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
794 795 796 797 798

    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
799
    memcpy( p_block->p_buffer, oggpacket.packet, oggpacket.bytes );
800
    p_block->i_dts = p_block->i_pts = p_pict->date;
Gildas Bazin's avatar
 
Gildas Bazin committed
801 802 803 804 805 806 807 808 809 810 811 812 813

    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 );
814
    theora_comment_clear( &p_sys->tc );
Gildas Bazin's avatar
 
Gildas Bazin committed
815 816 817

    free( p_sys );
}