* theora.c: theora decoder module making use of libtheora.
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
- * $Id: theora.c,v 1.16 2003/12/07 17:09:33 gbazin Exp $
+ * $Id$
*
- * Authors: Gildas Bazin <gbazin@netcourrier.com>
+ * Authors: Gildas Bazin <gbazin@videolan.org>
*
* 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
*****************************************************************************/
#include <vlc/vlc.h>
#include <vlc/decoder.h>
-#include "input_ext-plugins.h"
+#include <vlc/input.h>
+#include <vlc/sout.h>
#include <ogg/ogg.h>
/*****************************************************************************
* Module descriptor
*****************************************************************************/
+#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." )
+
vlc_module_begin();
set_description( _("Theora video decoder") );
set_capability( "decoder", 100 );
set_capability( "encoder", 100 );
set_callbacks( OpenEncoder, CloseEncoder );
add_shortcut( "theora" );
+
+# define ENC_CFG_PREFIX "sout-theora-"
+ add_integer( ENC_CFG_PREFIX "quality", 2, NULL, ENC_QUALITY_TEXT,
+ ENC_QUALITY_LONGTEXT, VLC_FALSE );
vlc_module_end();
+static const char *ppsz_enc_options[] = {
+ "quality", NULL
+};
+
/*****************************************************************************
* OpenDecoder: probe the decoder and return score
*****************************************************************************/
if( theora_decode_header( &p_sys->ti, &p_sys->tc, &oggpacket ) < 0 )
{
msg_Err( p_dec, "This bitstream does not contain Theora "
- "video data" );
+ "video data." );
block_Release( p_block );
return NULL;
}
p_dec->fmt_out.video.i_width = p_sys->ti.width;
p_dec->fmt_out.video.i_height = p_sys->ti.height;
- if( p_sys->ti.aspect_denominator )
- p_dec->fmt_out.video.i_aspect = VOUT_ASPECT_FACTOR *
- p_sys->ti.aspect_numerator / p_sys->ti.aspect_denominator;
+ 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 );
+ }
else
+ {
p_dec->fmt_out.video.i_aspect = VOUT_ASPECT_FACTOR *
p_sys->ti.frame_width / p_sys->ti.frame_height;
+ }
msg_Dbg( p_dec, "%dx%d %.02f fps video, frame content "
- "is %dx%d with offset (%d,%d)",
+ "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,
/* 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" );
+ msg_Err( p_dec, "2nd Theora header is corrupted." );
return NULL;
}
p_sys->i_headers++;
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" );
+ msg_Err( p_dec, "3rd Theora header is corrupted." );
return NULL;
}
p_sys->i_headers++;
static void ParseTheoraComments( decoder_t *p_dec )
{
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 )
psz_comment = strdup( p_dec->p_sys->tc.user_comments[i] );
if( !psz_comment )
{
- msg_Warn( p_dec, "Out of memory" );
+ msg_Warn( p_dec, "out of memory" );
break;
}
psz_name = psz_comment;
{
*psz_value = '\0';
psz_value++;
- input_AddInfo( p_cat, psz_name, psz_value );
+ input_Control( p_input, INPUT_ADD_INFO, _("Theora comment"),
+ psz_name, psz_value );
}
free( psz_comment );
i++;
{
encoder_t *p_enc = (encoder_t *)p_this;
encoder_sys_t *p_sys = p_enc->p_sys;
+ vlc_value_t val;
+ int i_quality;
+
+ if( p_enc->fmt_out.i_codec != VLC_FOURCC('t','h','e','o') &&
+ !p_enc->b_force )
+ {
+ return VLC_EGENERIC;
+ }
- if( p_enc->fmt_out.i_codec != VLC_FOURCC('t','h','e','o') )
+ if( p_enc->fmt_in.video.i_width % 16 ||
+ p_enc->fmt_in.video.i_height % 16 )
{
+ msg_Err( p_enc, "Theora video encoding requires dimensions which are "
+ "multiples of 16. Which is not the case here (%dx%d).",
+ p_enc->fmt_in.video.i_width, p_enc->fmt_in.video.i_height );
return VLC_EGENERIC;
}
p_enc->pf_header = Headers;
p_enc->pf_encode_video = Encode;
p_enc->fmt_in.i_codec = VLC_FOURCC('I','4','2','0');
+ p_enc->fmt_out.i_codec = VLC_FOURCC('t','h','e','o');
-#define frame_x_offset 0
-#define frame_y_offset 0
-#define video_hzn 25
-#define video_hzd 1
-#define video_an 4
-#define video_ad 3
-#define video_q 5
+ sout_CfgParse( p_enc, ENC_CFG_PREFIX, ppsz_enc_options, p_enc->p_cfg );
+
+ 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;
theora_info_init( &p_sys->ti );
p_sys->ti.height = p_enc->fmt_in.video.i_height;
p_sys->ti.frame_width = p_enc->fmt_in.video.i_width;
p_sys->ti.frame_height = p_enc->fmt_in.video.i_height;
- p_sys->ti.offset_x = frame_x_offset;
- p_sys->ti.offset_y = frame_y_offset;
- p_sys->ti.fps_numerator = video_hzn;
- p_sys->ti.fps_denominator = video_hzd;
- p_sys->ti.aspect_numerator = video_an;
- p_sys->ti.aspect_denominator = video_ad;
- p_sys->ti.colorspace = not_specified;
+ p_sys->ti.offset_x = 0 /*frame_x_offset*/;
+ p_sys->ti.offset_y = 0/*frame_y_offset*/;
+
+ 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;
+ }
+
+ if( p_enc->fmt_in.video.i_aspect )
+ {
+ p_sys->ti.aspect_numerator =
+ p_enc->fmt_in.video.i_aspect * p_sys->ti.height / p_sys->ti.width;
+ p_sys->ti.aspect_denominator = VOUT_ASPECT_FACTOR;
+ }
+ else
+ {
+ p_sys->ti.aspect_numerator = 4;
+ p_sys->ti.aspect_denominator = 3;
+ }
+
p_sys->ti.target_bitrate = p_enc->fmt_out.i_bitrate;
- p_sys->ti.quality = video_q;
+ p_sys->ti.quality = ((float)i_quality) * 6.3;
p_sys->ti.dropframes_p = 0;
p_sys->ti.quick_p = 1;
{
ogg_packet oggpackets;
int i;
+ block_t *p_block;
/* Ogg packet to block */
for( i = 0; i < 3; i++ )
break;
}
- block_t *p_block = block_New( p_enc, oggpackets.bytes );
+ p_block = block_New( p_enc, oggpackets.bytes );
memcpy( p_block->p_buffer, oggpackets.packet, oggpackets.bytes );
p_block->i_dts = p_block->i_pts = p_block->i_length = 0;
block_ChainAppend( &p_chain, p_block );
/* Ogg packet to block */
p_block = block_New( p_enc, oggpacket.bytes );
memcpy( p_block->p_buffer, oggpacket.packet, oggpacket.bytes );
- p_block->i_dts = p_block->i_pts = p_pict->date;;
+ p_block->i_dts = p_block->i_pts = p_pict->date;
return p_block;
}