theora.c 25.4 KB
Newer Older
Gildas Bazin's avatar
 
Gildas Bazin committed
1 2 3
/*****************************************************************************
 * theora.c: theora decoder module making use of libtheora.
 *****************************************************************************
4
 * Copyright (C) 1999-2001 the VideoLAN team
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
 * 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
Antoine Cellerier's avatar
Antoine Cellerier committed
21
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
Gildas Bazin's avatar
 
Gildas Bazin committed
22 23 24 25 26
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
27 28 29 30
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

31
#include <vlc_common.h>
32
#include <vlc_plugin.h>
Clément Stenac's avatar
Clément Stenac committed
33 34
#include <vlc_codec.h>
#include <vlc_sout.h>
Clément Stenac's avatar
Clément Stenac committed
35
#include <vlc_input.h>
36 37
#include "../demux/xiph.h"

Gildas Bazin's avatar
 
Gildas Bazin committed
38 39 40 41 42
#include <ogg/ogg.h>

#include <theora/theora.h>

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

Gildas Bazin's avatar
 
Gildas Bazin committed
50
    /*
Gildas Bazin's avatar
 
Gildas Bazin committed
51
     * Input properties
Gildas Bazin's avatar
 
Gildas Bazin committed
52
     */
53
    bool b_has_headers;
Gildas Bazin's avatar
 
Gildas Bazin committed
54 55 56 57 58

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

62 63 64
    /*
     * Decoding properties
     */
65
    bool b_decoded_first_keyframe;
66

Gildas Bazin's avatar
 
Gildas Bazin committed
67 68 69 70 71
    /*
     * Common properties
     */
    mtime_t i_pts;
};
Gildas Bazin's avatar
 
Gildas Bazin committed
72 73 74 75

/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
Gildas Bazin's avatar
 
Gildas Bazin committed
76 77 78
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
79

Gildas Bazin's avatar
 
Gildas Bazin committed
80
static void *DecodeBlock  ( decoder_t *, block_t ** );
81
static int  ProcessHeaders( decoder_t * );
Gildas Bazin's avatar
 
Gildas Bazin committed
82
static void *ProcessPacket ( decoder_t *, ogg_packet *, block_t ** );
Gildas Bazin's avatar
 
Gildas Bazin committed
83

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

Gildas Bazin's avatar
 
Gildas Bazin committed
86
static void ParseTheoraComments( decoder_t * );
87
static void theora_CopyPicture( picture_t *, yuv_buffer * );
88

Gildas Bazin's avatar
 
Gildas Bazin committed
89 90 91 92
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
93 94 95
/*****************************************************************************
 * Module descriptor
 *****************************************************************************/
96 97
#define ENC_QUALITY_TEXT N_("Encoding quality")
#define ENC_QUALITY_LONGTEXT N_( \
98
  "Enforce a quality between 1 (low) and 10 (high), instead " \
99 100
  "of specifying a particular bitrate. This will produce a VBR stream." )

101 102 103 104 105 106 107 108 109 110 111 112 113
vlc_module_begin ()
    set_category( CAT_INPUT )
    set_subcategory( SUBCAT_INPUT_VCODEC )
    set_shortname( "Theora" )
    set_description( N_("Theora video decoder") )
    set_capability( "decoder", 100 )
    set_callbacks( OpenDecoder, CloseDecoder )
    add_shortcut( "theora" )

    add_submodule ()
    set_description( N_("Theora video packetizer") )
    set_capability( "packetizer", 100 )
    set_callbacks( OpenPacketizer, CloseDecoder )
114
    add_shortcut( "theora" )
115 116 117 118 119

    add_submodule ()
    set_description( N_("Theora video encoder") )
    set_capability( "encoder", 150 )
    set_callbacks( OpenEncoder, CloseEncoder )
120
    add_shortcut( "theora" )
121 122

#   define ENC_CFG_PREFIX "sout-theora-"
123
    add_integer( ENC_CFG_PREFIX "quality", 2, ENC_QUALITY_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
124
                 ENC_QUALITY_LONGTEXT, false )
125
vlc_module_end ()
Gildas Bazin's avatar
 
Gildas Bazin committed
126

127
static const char *const ppsz_enc_options[] = {
128 129 130
    "quality", NULL
};

Gildas Bazin's avatar
 
Gildas Bazin committed
131 132 133 134 135
/*****************************************************************************
 * OpenDecoder: probe the decoder and return score
 *****************************************************************************/
static int OpenDecoder( vlc_object_t *p_this )
{
Gildas Bazin's avatar
 
Gildas Bazin committed
136
    decoder_t *p_dec = (decoder_t*)p_this;
Gildas Bazin's avatar
 
Gildas Bazin committed
137
    decoder_sys_t *p_sys;
Gildas Bazin's avatar
 
Gildas Bazin committed
138

139
    if( p_dec->fmt_in.i_codec != VLC_CODEC_THEORA )
Gildas Bazin's avatar
 
Gildas Bazin committed
140 141 142 143
    {
        return VLC_EGENERIC;
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
144
    /* Allocate the memory needed to store the decoder's structure */
145
    if( ( p_dec->p_sys = p_sys = malloc(sizeof(*p_sys)) ) == NULL )
146
        return VLC_ENOMEM;
147
    p_dec->p_sys->b_packetizer = false;
148
    p_sys->b_has_headers = false;
149
    p_sys->i_pts = VLC_TS_INVALID;
150
    p_sys->b_decoded_first_keyframe = false;
Gildas Bazin's avatar
 
Gildas Bazin committed
151 152 153

    /* Set output properties */
    p_dec->fmt_out.i_cat = VIDEO_ES;
154
    p_dec->fmt_out.i_codec = VLC_CODEC_I420;
Gildas Bazin's avatar
 
Gildas Bazin committed
155 156 157 158 159 160 161 162 163 164 165

    /* 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 );

Gildas Bazin's avatar
 
Gildas Bazin committed
166 167
    return VLC_SUCCESS;
}
Gildas Bazin's avatar
 
Gildas Bazin committed
168 169 170 171 172 173 174

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
175 176
    if( i_ret == VLC_SUCCESS )
    {
177
        p_dec->p_sys->b_packetizer = true;
178
        p_dec->fmt_out.i_codec = VLC_CODEC_THEORA;
Gildas Bazin's avatar
 
Gildas Bazin committed
179
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
180 181 182 183 184

    return i_ret;
}

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

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

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

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

207
    /* Check for headers */
208
    if( !p_sys->b_has_headers )
209
    {
210
        if( ProcessHeaders( p_dec ) )
Gildas Bazin's avatar
 
Gildas Bazin committed
211
        {
212
            block_Release( *pp_block );
Gildas Bazin's avatar
 
Gildas Bazin committed
213
            return NULL;
Gildas Bazin's avatar
 
Gildas Bazin committed
214
        }
215
        p_sys->b_has_headers = true;
216
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
217

218 219
    return ProcessPacket( p_dec, &oggpacket, pp_block );
}
Sam Hocevar's avatar
Sam Hocevar committed
220

221 222 223 224 225 226 227
/*****************************************************************************
 * ProcessHeaders: process Theora headers.
 *****************************************************************************/
static int ProcessHeaders( decoder_t *p_dec )
{
    decoder_sys_t *p_sys = p_dec->p_sys;
    ogg_packet oggpacket;
Gildas Bazin's avatar
 
Gildas Bazin committed
228

229 230 231 232 233 234 235 236
    unsigned pi_size[XIPH_MAX_HEADER_COUNT];
    void     *pp_data[XIPH_MAX_HEADER_COUNT];
    unsigned i_count;
    if( xiph_SplitHeaders( pi_size, pp_data, &i_count,
                           p_dec->fmt_in.i_extra, p_dec->fmt_in.p_extra) )
        return VLC_EGENERIC;
    if( i_count < 3 )
        goto error;
Gildas Bazin's avatar
 
Gildas Bazin committed
237

238 239 240 241 242
    oggpacket.granulepos = -1;
    oggpacket.e_o_s = 0;
    oggpacket.packetno = 0;

    /* Take care of the initial Vorbis header */
243 244 245
    oggpacket.b_o_s  = 1; /* yes this actually is a b_o_s packet :) */
    oggpacket.bytes  = pi_size[0];
    oggpacket.packet = pp_data[0];
246
    if( theora_decode_header( &p_sys->ti, &p_sys->tc, &oggpacket ) < 0 )
Gildas Bazin's avatar
 
Gildas Bazin committed
247
    {
248
        msg_Err( p_dec, "this bitstream does not contain Theora video data" );
249
        goto error;
250
    }
Sam Hocevar's avatar
Sam Hocevar committed
251

252
    /* Set output properties */
253 254 255
    switch( p_sys->ti.pixelformat )
    {
      case OC_PF_420:
256
        p_dec->fmt_out.i_codec = VLC_CODEC_I420;
257 258
        break;
      case OC_PF_422:
259
        p_dec->fmt_out.i_codec = VLC_CODEC_I422;
260 261
        break;
      case OC_PF_444:
262
        p_dec->fmt_out.i_codec = VLC_CODEC_I444;
263 264 265 266 267 268
        break;
      case OC_PF_RSVD:
      default:
        msg_Err( p_dec, "unknown chroma in theora sample" );
        break;
    }
269 270
    p_dec->fmt_out.video.i_width = p_sys->ti.width;
    p_dec->fmt_out.video.i_height = p_sys->ti.height;
271 272
    if( p_sys->ti.frame_width && p_sys->ti.frame_height )
    {
273 274
        p_dec->fmt_out.video.i_visible_width = p_sys->ti.frame_width;
        p_dec->fmt_out.video.i_visible_height = p_sys->ti.frame_height;
275 276 277 278 279
        if( p_sys->ti.offset_x || p_sys->ti.offset_y )
        {
            p_dec->fmt_out.video.i_x_offset = p_sys->ti.offset_x;
            p_dec->fmt_out.video.i_y_offset = p_sys->ti.offset_y;
        }
280
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
281

282 283
    if( p_sys->ti.aspect_denominator && p_sys->ti.aspect_numerator )
    {
284 285
        p_dec->fmt_out.video.i_sar_num = p_sys->ti.aspect_numerator;
        p_dec->fmt_out.video.i_sar_den = p_sys->ti.aspect_denominator;
Gildas Bazin's avatar
 
Gildas Bazin committed
286
    }
287 288
    else
    {
289 290
        p_dec->fmt_out.video.i_sar_num = 1;
        p_dec->fmt_out.video.i_sar_den = 1;
291 292
    }

293 294 295 296 297 298
    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;
    }

299 300 301 302 303 304
    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
305

306 307 308 309 310 311 312 313 314 315 316 317 318 319 320
    /* Sanity check that seems necessary for some corrupted files */
    if( p_sys->ti.width < p_sys->ti.frame_width ||
        p_sys->ti.height < p_sys->ti.frame_height )
    {
        msg_Warn( p_dec, "trying to correct invalid theora header "
                  "(frame size (%dx%d) is smaller than frame content (%d,%d))",
                  p_sys->ti.width, p_sys->ti.height,
                  p_sys->ti.frame_width, p_sys->ti.frame_height );

        if( p_sys->ti.width < p_sys->ti.frame_width )
            p_sys->ti.width = p_sys->ti.frame_width;
        if( p_sys->ti.height < p_sys->ti.frame_height )
            p_sys->ti.height = p_sys->ti.frame_height;
    }

321
    /* The next packet in order is the comments header */
322 323 324
    oggpacket.b_o_s  = 0;
    oggpacket.bytes  = pi_size[1];
    oggpacket.packet = pp_data[1];
325 326 327
    if( theora_decode_header( &p_sys->ti, &p_sys->tc, &oggpacket ) < 0 )
    {
        msg_Err( p_dec, "2nd Theora header is corrupted" );
328
        goto error;
329 330 331
    }

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

333 334 335
    /* 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. */
336 337 338
    oggpacket.b_o_s  = 0;
    oggpacket.bytes  = pi_size[2];
    oggpacket.packet = pp_data[2];
339 340 341
    if( theora_decode_header( &p_sys->ti, &p_sys->tc, &oggpacket ) < 0 )
    {
        msg_Err( p_dec, "3rd Theora header is corrupted" );
342
        goto error;
343 344 345 346 347 348 349 350 351 352
    }

    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;
353
        p_dec->fmt_out.p_extra = xrealloc( p_dec->fmt_out.p_extra,
354
                                                  p_dec->fmt_out.i_extra );
355 356 357 358
        memcpy( p_dec->fmt_out.p_extra,
                p_dec->fmt_in.p_extra, p_dec->fmt_out.i_extra );
    }

359 360
    for( unsigned i = 0; i < i_count; i++ )
        free( pp_data[i] );
361
    return VLC_SUCCESS;
362 363 364 365 366

error:
    for( unsigned i = 0; i < i_count; i++ )
        free( pp_data[i] );
    return VLC_EGENERIC;
Gildas Bazin's avatar
 
Gildas Bazin committed
367
}
Gildas Bazin's avatar
 
Gildas Bazin committed
368

Gildas Bazin's avatar
 
Gildas Bazin committed
369
/*****************************************************************************
Gildas Bazin's avatar
 
Gildas Bazin committed
370
 * ProcessPacket: processes a theora packet.
Gildas Bazin's avatar
 
Gildas Bazin committed
371
 *****************************************************************************/
Gildas Bazin's avatar
 
Gildas Bazin committed
372 373
static void *ProcessPacket( decoder_t *p_dec, ogg_packet *p_oggpacket,
                            block_t **pp_block )
Gildas Bazin's avatar
 
Gildas Bazin committed
374 375
{
    decoder_sys_t *p_sys = p_dec->p_sys;
Gildas Bazin's avatar
 
Gildas Bazin committed
376 377
    block_t *p_block = *pp_block;
    void *p_buf;
Gildas Bazin's avatar
 
Gildas Bazin committed
378

Laurent Aimar's avatar
Laurent Aimar committed
379
    if( ( p_block->i_flags&(BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) ) != 0 )
380 381 382 383 384 385 386
    {
        /* 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
387
    /* Date management */
388
    if( p_block->i_pts > VLC_TS_INVALID && p_block->i_pts != p_sys->i_pts )
Gildas Bazin's avatar
 
Gildas Bazin committed
389
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
390
        p_sys->i_pts = p_block->i_pts;
Gildas Bazin's avatar
 
Gildas Bazin committed
391 392
    }

393 394
    *pp_block = NULL; /* To avoid being fed the same packet again */

Gildas Bazin's avatar
 
Gildas Bazin committed
395 396
    if( p_sys->b_packetizer )
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
397 398 399
        /* Date management */
        p_block->i_dts = p_block->i_pts = p_sys->i_pts;

400
        p_block->i_length = p_sys->i_pts - p_block->i_pts;
Gildas Bazin's avatar
 
Gildas Bazin committed
401 402

        p_buf = p_block;
Gildas Bazin's avatar
 
Gildas Bazin committed
403 404 405
    }
    else
    {
406 407 408
        p_buf = DecodePacket( p_dec, p_oggpacket );
        if( p_block )
            block_Release( p_block );
Gildas Bazin's avatar
 
Gildas Bazin committed
409
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
410 411

    /* Date management */
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
412
    p_sys->i_pts += ( INT64_C(1000000) * p_sys->ti.fps_denominator /
Gildas Bazin's avatar
 
Gildas Bazin committed
413
                      p_sys->ti.fps_numerator ); /* 1 frame per packet */
Gildas Bazin's avatar
 
Gildas Bazin committed
414

Gildas Bazin's avatar
 
Gildas Bazin committed
415
    return p_buf;
Gildas Bazin's avatar
 
Gildas Bazin committed
416 417 418
}

/*****************************************************************************
Gildas Bazin's avatar
 
Gildas Bazin committed
419
 * DecodePacket: decodes a Theora packet.
Gildas Bazin's avatar
 
Gildas Bazin committed
420
 *****************************************************************************/
Gildas Bazin's avatar
 
Gildas Bazin committed
421
static picture_t *DecodePacket( decoder_t *p_dec, ogg_packet *p_oggpacket )
Gildas Bazin's avatar
 
Gildas Bazin committed
422
{
Gildas Bazin's avatar
 
Gildas Bazin committed
423
    decoder_sys_t *p_sys = p_dec->p_sys;
Gildas Bazin's avatar
 
Gildas Bazin committed
424 425
    picture_t *p_pic;
    yuv_buffer yuv;
Gildas Bazin's avatar
 
Gildas Bazin committed
426

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

429 430 431
    /* Check for keyframe */
    if( !(p_oggpacket->packet[0] & 0x80) /* data packet */ &&
        !(p_oggpacket->packet[0] & 0x40) /* intra frame */ )
432
        p_sys->b_decoded_first_keyframe = true;
433 434 435 436 437 438 439 440 441 442

    /* 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
443

Gildas Bazin's avatar
 
Gildas Bazin committed
444
    /* Get a new picture */
445
    p_pic = decoder_NewPicture( p_dec );
Gildas Bazin's avatar
 
Gildas Bazin committed
446
    if( !p_pic ) return NULL;
Gildas Bazin's avatar
 
Gildas Bazin committed
447

448
    theora_CopyPicture( p_pic, &yuv );
Gildas Bazin's avatar
 
Gildas Bazin committed
449

Gildas Bazin's avatar
 
Gildas Bazin committed
450
    p_pic->date = p_sys->i_pts;
Gildas Bazin's avatar
 
Gildas Bazin committed
451

Gildas Bazin's avatar
 
Gildas Bazin committed
452
    return p_pic;
Gildas Bazin's avatar
 
Gildas Bazin committed
453 454 455
}

/*****************************************************************************
456
 * ParseTheoraComments:
Gildas Bazin's avatar
 
Gildas Bazin committed
457
 *****************************************************************************/
Gildas Bazin's avatar
 
Gildas Bazin committed
458
static void ParseTheoraComments( decoder_t *p_dec )
Gildas Bazin's avatar
 
Gildas Bazin committed
459
{
Gildas Bazin's avatar
 
Gildas Bazin committed
460
    char *psz_name, *psz_value, *psz_comment;
461 462
    int i = 0;

Gildas Bazin's avatar
 
Gildas Bazin committed
463
    while ( i < p_dec->p_sys->tc.comments )
Gildas Bazin's avatar
 
Gildas Bazin committed
464
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
465 466 467 468 469 470 471 472 473
        psz_comment = strdup( p_dec->p_sys->tc.user_comments[i] );
        if( !psz_comment )
            break;
        psz_name = psz_comment;
        psz_value = strchr( psz_comment, '=' );
        if( psz_value )
        {
            *psz_value = '\0';
            psz_value++;
474 475 476 477 478

            if( !p_dec->p_description )
                p_dec->p_description = vlc_meta_New();
            if( p_dec->p_description )
                vlc_meta_AddExtra( p_dec->p_description, psz_name, psz_value );
Gildas Bazin's avatar
 
Gildas Bazin committed
479 480 481 482 483 484 485
        }
        free( psz_comment );
        i++;
    }
}

/*****************************************************************************
Gildas Bazin's avatar
 
Gildas Bazin committed
486
 * CloseDecoder: theora decoder destruction
Gildas Bazin's avatar
 
Gildas Bazin committed
487
 *****************************************************************************/
Gildas Bazin's avatar
 
Gildas Bazin committed
488
static void CloseDecoder( vlc_object_t *p_this )
Gildas Bazin's avatar
 
Gildas Bazin committed
489
{
Gildas Bazin's avatar
 
Gildas Bazin committed
490
    decoder_t *p_dec = (decoder_t *)p_this;
Gildas Bazin's avatar
 
Gildas Bazin committed
491
    decoder_sys_t *p_sys = p_dec->p_sys;
Gildas Bazin's avatar
 
Gildas Bazin committed
492

Gildas Bazin's avatar
 
Gildas Bazin committed
493 494
    theora_info_clear( &p_sys->ti );
    theora_comment_clear( &p_sys->tc );
Gildas Bazin's avatar
 
Gildas Bazin committed
495

Gildas Bazin's avatar
 
Gildas Bazin committed
496
    free( p_sys );
Gildas Bazin's avatar
 
Gildas Bazin committed
497 498 499 500 501 502
}

/*****************************************************************************
 * theora_CopyPicture: copy a picture from theora internal buffers to a
 *                     picture_t structure.
 *****************************************************************************/
503
static void theora_CopyPicture( picture_t *p_pic,
Gildas Bazin's avatar
 
Gildas Bazin committed
504 505
                                yuv_buffer *yuv )
{
506
    int i_plane, i_line, i_dst_stride, i_src_stride;
Sam Hocevar's avatar
Sam Hocevar committed
507
    uint8_t *p_dst, *p_src;
Gildas Bazin's avatar
 
Gildas Bazin committed
508 509 510 511 512

    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;
Gildas Bazin's avatar
 
Gildas Bazin committed
513 514
        i_dst_stride  = p_pic->p[i_plane].i_pitch;
        i_src_stride  = i_plane ? yuv->uv_stride : yuv->y_stride;
Gildas Bazin's avatar
 
Gildas Bazin committed
515

516
        for( i_line = 0; i_line < p_pic->p[i_plane].i_lines; i_line++ )
Gildas Bazin's avatar
 
Gildas Bazin committed
517
        {
518
            vlc_memcpy( p_dst, p_src,
519
                        i_plane ? yuv->uv_width : yuv->y_width );
Gildas Bazin's avatar
 
Gildas Bazin committed
520 521 522 523 524
            p_src += i_src_stride;
            p_dst += i_dst_stride;
        }
    }
}
Gildas Bazin's avatar
 
Gildas Bazin committed
525 526 527 528 529 530 531 532 533

/*****************************************************************************
 * encoder_sys_t : theora encoder descriptor
 *****************************************************************************/
struct encoder_sys_t
{
    /*
     * Input properties
     */
534
    bool b_headers;
Gildas Bazin's avatar
 
Gildas Bazin committed
535 536 537 538 539 540 541 542

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

543
    int i_width, i_height;
Gildas Bazin's avatar
 
Gildas Bazin committed
544 545 546 547 548 549 550 551
};

/*****************************************************************************
 * OpenEncoder: probe the encoder and return score
 *****************************************************************************/
static int OpenEncoder( vlc_object_t *p_this )
{
    encoder_t *p_enc = (encoder_t *)p_this;
552
    encoder_sys_t *p_sys;
Laurent Aimar's avatar
Laurent Aimar committed
553
    int i_quality;
Gildas Bazin's avatar
 
Gildas Bazin committed
554

555
    if( p_enc->fmt_out.i_codec != VLC_CODEC_THEORA &&
556
        !p_enc->b_force )
Gildas Bazin's avatar
 
Gildas Bazin committed
557 558 559 560 561
    {
        return VLC_EGENERIC;
    }

    /* Allocate the memory needed to store the decoder's structure */
562
    if( ( p_sys = malloc(sizeof(encoder_sys_t)) ) == NULL )
563
        return VLC_ENOMEM;
Gildas Bazin's avatar
 
Gildas Bazin committed
564 565 566
    p_enc->p_sys = p_sys;

    p_enc->pf_encode_video = Encode;
567 568
    p_enc->fmt_in.i_codec = VLC_CODEC_I420;
    p_enc->fmt_out.i_codec = VLC_CODEC_THEORA;
Gildas Bazin's avatar
 
Gildas Bazin committed
569

570
    config_ChainParse( p_enc, ENC_CFG_PREFIX, ppsz_enc_options, p_enc->p_cfg );
571

572
    i_quality = var_GetInteger( p_enc, ENC_CFG_PREFIX "quality" );
573 574 575
    if( i_quality > 10 ) i_quality = 10;
    if( i_quality < 0 ) i_quality = 0;

Gildas Bazin's avatar
 
Gildas Bazin committed
576 577
    theora_info_init( &p_sys->ti );

Gildas Bazin's avatar
 
Gildas Bazin committed
578 579
    p_sys->ti.width = p_enc->fmt_in.video.i_width;
    p_sys->ti.height = p_enc->fmt_in.video.i_height;
580 581 582 583 584 585 586 587 588 589 590 591 592

    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
593 594
    p_sys->ti.frame_width = p_enc->fmt_in.video.i_width;
    p_sys->ti.frame_height = p_enc->fmt_in.video.i_height;
595
    p_sys->ti.offset_x = 0 /*frame_x_offset*/;
596
    p_sys->ti.offset_y = 0 /*frame_y_offset*/;
597

598 599 600
    p_sys->i_width = p_sys->ti.width;
    p_sys->i_height = p_sys->ti.height;

601 602 603 604 605 606 607 608 609 610 611
    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
612

613
    if( p_enc->fmt_in.video.i_sar_num > 0 && p_enc->fmt_in.video.i_sar_den > 0 )
Gildas Bazin's avatar
 
Gildas Bazin committed
614
    {
615
        unsigned i_dst_num, i_dst_den;
616 617 618
        vlc_ureduce( &i_dst_num, &i_dst_den,
                     p_enc->fmt_in.video.i_sar_num,
                     p_enc->fmt_in.video.i_sar_den, 0 );
619 620
        p_sys->ti.aspect_numerator = i_dst_num;
        p_sys->ti.aspect_denominator = i_dst_den;
Gildas Bazin's avatar
 
Gildas Bazin committed
621 622 623 624 625 626 627
    }
    else
    {
        p_sys->ti.aspect_numerator = 4;
        p_sys->ti.aspect_denominator = 3;
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
628
    p_sys->ti.target_bitrate = p_enc->fmt_out.i_bitrate;
629
    p_sys->ti.quality = ((float)i_quality) * 6.3;
Gildas Bazin's avatar
 
Gildas Bazin committed
630 631 632 633 634 635

    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
636
    p_sys->ti.keyframe_data_target_bitrate = p_enc->fmt_out.i_bitrate * 1.5;
Gildas Bazin's avatar
 
Gildas Bazin committed
637 638 639 640 641
    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 );
Gildas Bazin's avatar
 
Gildas Bazin committed
642
    theora_comment_init( &p_sys->tc );
Gildas Bazin's avatar
 
Gildas Bazin committed
643

644
    /* Create and store headers */
Laurent Aimar's avatar
Laurent Aimar committed
645
    for( int i = 0; i < 3; i++ )
Gildas Bazin's avatar
 
Gildas Bazin committed
646
    {
Laurent Aimar's avatar
Laurent Aimar committed
647
        ogg_packet header;
648

Laurent Aimar's avatar
Laurent Aimar committed
649 650 651 652 653 654
        if( i == 0 )
            theora_encode_header( &p_sys->td, &header );
        else if( i == 1 )
            theora_encode_comment( &p_sys->tc, &header );
        else
            theora_encode_tables( &p_sys->td, &header );
655

Laurent Aimar's avatar
Laurent Aimar committed
656 657 658 659 660 661
        if( xiph_AppendHeaders( &p_enc->fmt_out.i_extra, &p_enc->fmt_out.p_extra,
                                header.bytes, header.packet ) )
        {
            p_enc->fmt_out.i_extra = 0;
            p_enc->fmt_out.p_extra = NULL;
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
662
    }
663
    return VLC_SUCCESS;
Gildas Bazin's avatar
 
Gildas Bazin committed
664 665 666 667 668 669 670 671 672 673 674 675 676
}

/****************************************************************************
 * 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;
677 678
    int i;

679
    if( !p_pict ) return NULL;
680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731
    /* 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
732 733 734 735

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

736 737
    yuv.y_width  = p_sys->i_width;
    yuv.y_height = p_sys->i_height;
Gildas Bazin's avatar
 
Gildas Bazin committed
738 739
    yuv.y_stride = p_pict->p[0].i_pitch;

740 741
    yuv.uv_width  = p_sys->i_width / 2;
    yuv.uv_height = p_sys->i_height / 2;
Gildas Bazin's avatar
 
Gildas Bazin committed
742 743 744 745 746 747
    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
748 749 750 751 752
    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
753 754 755 756 757

    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
758
    memcpy( p_block->p_buffer, oggpacket.packet, oggpacket.bytes );
759
    p_block->i_dts = p_block->i_pts = p_pict->date;
Gildas Bazin's avatar
 
Gildas Bazin committed
760

ogg.k.ogg.k's avatar
ogg.k.ogg.k committed
761 762 763 764 765
    if( theora_packet_iskeyframe( &oggpacket ) )
    {
        p_block->i_flags |= BLOCK_FLAG_TYPE_I;
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
766 767 768 769 770 771 772 773 774 775 776 777
    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 );
778
    theora_comment_clear( &p_sys->tc );
Gildas Bazin's avatar
 
Gildas Bazin committed
779 780 781

    free( p_sys );
}