[xiph-commits] r14950 - in trunk/ffmpeg2theora: . src
j at svn.xiph.org
j at svn.xiph.org
Fri May 23 10:56:21 PDT 2008
Author: j
Date: 2008-05-23 10:56:21 -0700 (Fri, 23 May 2008)
New Revision: 14950
Added:
trunk/ffmpeg2theora/src/
trunk/ffmpeg2theora/src/ffmpeg2theora.c
trunk/ffmpeg2theora/src/ffmpeg2theora.h
trunk/ffmpeg2theora/src/subtitles.c
trunk/ffmpeg2theora/src/subtitles.h
trunk/ffmpeg2theora/src/theorautils.c
trunk/ffmpeg2theora/src/theorautils.h
Removed:
trunk/ffmpeg2theora/ffmpeg2theora.c
trunk/ffmpeg2theora/subtitles.c
trunk/ffmpeg2theora/subtitles.h
trunk/ffmpeg2theora/theorautils.c
trunk/ffmpeg2theora/theorautils.h
Modified:
trunk/ffmpeg2theora/
trunk/ffmpeg2theora/INSTALL
trunk/ffmpeg2theora/Makefile.am
trunk/ffmpeg2theora/README
trunk/ffmpeg2theora/SConstruct
trunk/ffmpeg2theora/TODO
trunk/ffmpeg2theora/get_libkate.sh
Log:
more files to ./src
Property changes on: trunk/ffmpeg2theora
___________________________________________________________________
Name: bzr:revision-info
- timestamp: 2008-05-23 18:59:04.180999994 +0200
committer: j
properties:
branch-nick: ffmpeg2theora
+ timestamp: 2008-05-23 19:54:32.194999933 +0200
committer: j
properties:
branch-nick: ffmpeg2theora
Name: bzr:file-ids
- SConstruct sconstruct-20080523165848-8nlost8hilp0zdcm-1
+ src src-20080523174144-dkwx1i25ujognb2c-1
src/ffmpeg2theora.c 6863 at 0101bb08-14d6-0310-b084-bc0e0c8e3800:trunk%2Fffmpeg2theora:ffmpeg2theora.c
src/ffmpeg2theora.h ffmpeg2theora.h-20080523174200-q6z54q34pgkgpz50-1
src/subtitles.c subtitles.c-20080523092315-berdpbqhudpfrkh7-1
src/subtitles.h subtitles.h-20080523092316-79y08zf0g4v687h5-1
src/theorautils.c 6863 at 0101bb08-14d6-0310-b084-bc0e0c8e3800:trunk%2Fffmpeg2theora:theorautils.c
src/theorautils.h 6863 at 0101bb08-14d6-0310-b084-bc0e0c8e3800:trunk%2Fffmpeg2theora:theorautils.h
Name: bzr:revision-id:v3-single1-dHJ1bmsvZmZtcGVnMnRoZW9yYQ..
- 191 j-20080517230830-he5x8v2m8yrfiw35
192 j-20080518224037-pkmoctzf4qce7tog
193 j-20080518224409-6hbfp3k2ssn6egqa
194 j-20080520111939-dhi52qwbqe7a47cu
195 j-20080523092252-gj9k9db0s67vl7dw
196 j-20080523092420-l0850yrq1qkgz9t0
197 j-20080523093057-l5g0ezzy5geu0pey
198 j-20080523094343-kcno1dm2e1lr38q4
199 j-20080523163006-kjl6ewea5sxawmq2
200 j-20080523165904-l2vm52qae0hlqkhp
+ 191 j-20080517230830-he5x8v2m8yrfiw35
192 j-20080518224037-pkmoctzf4qce7tog
193 j-20080518224409-6hbfp3k2ssn6egqa
194 j-20080520111939-dhi52qwbqe7a47cu
195 j-20080523092252-gj9k9db0s67vl7dw
196 j-20080523092420-l0850yrq1qkgz9t0
197 j-20080523093057-l5g0ezzy5geu0pey
198 j-20080523094343-kcno1dm2e1lr38q4
199 j-20080523163006-kjl6ewea5sxawmq2
200 j-20080523165904-l2vm52qae0hlqkhp
201 j-20080523175432-2ed953iktnl8c7cr
Modified: trunk/ffmpeg2theora/INSTALL
===================================================================
--- trunk/ffmpeg2theora/INSTALL 2008-05-23 17:55:53 UTC (rev 14949)
+++ trunk/ffmpeg2theora/INSTALL 2008-05-23 17:56:21 UTC (rev 14950)
@@ -1,7 +1,7 @@
Compiling from SVN
------------------
-If you donwloaded ffmpeg2theora from svn you have
-need automake 1.6 or later to build the configure script.
+If you donwloaded ffmpeg2theora from svn you need
+automake 1.8 or later to build the configure script.
To do this run ./autogen.sh
Then build as you would from a tarball.
@@ -36,14 +36,6 @@
sudo make install
-Compiling on windows using mingw32:
----------------------------------
-you have to compile libvorbis, libogg, libtheora
-configure ffmpeg like this:
-./configure --disable-encoder --enable-libogg --enable-vorbis --enable-theora \
- --enable-pp --enable-a52 --enable-gpl
-
-
vhook suppport
--------------
@@ -52,7 +44,6 @@
undefined symbol: av_read_frame
this is a known limitation of vhooks in ffmpeg.
-
subtitles suppport
------------------
Modified: trunk/ffmpeg2theora/Makefile.am
===================================================================
--- trunk/ffmpeg2theora/Makefile.am 2008-05-23 17:55:53 UTC (rev 14949)
+++ trunk/ffmpeg2theora/Makefile.am 2008-05-23 17:56:21 UTC (rev 14950)
@@ -8,9 +8,9 @@
bin_PROGRAMS = ffmpeg2theora
-ffmpeg2theora_SOURCES = ffmpeg2theora.c theorautils.c subtitles.c \
- ffmpeg2theora.h theorautils.h subtitles.h
+ffmpeg2theora_SOURCES = src/ffmpeg2theora.c src/theorautils.c src/subtitles.c \
+ src/ffmpeg2theora.h src/theorautils.h src/subtitles.h
ffmpeg2theora_LDFLAGS = -L$(prefix)/lib @XIPH_LIBS@ @KATE_LIBS@ @FFMPEG_LIBS@
-ffmpeg2theora_CFLAGS = @XIPH_CFLAGS@ @KATE_CFLAGS@ @FFMPEG_CFLAGS@
+ffmpeg2theora_CFLAGS = -I./src @XIPH_CFLAGS@ @KATE_CFLAGS@ @FFMPEG_CFLAGS@
man_MANS = ffmpeg2theora.1
Modified: trunk/ffmpeg2theora/README
===================================================================
--- trunk/ffmpeg2theora/README 2008-05-23 17:55:53 UTC (rev 14949)
+++ trunk/ffmpeg2theora/README 2008-05-23 17:56:21 UTC (rev 14950)
@@ -6,7 +6,6 @@
along sites like v2v.cc to enable as many people as possible
to encode video clips with the same settings.
-
usage right now:
./ffmpeg2theora clip.avi
will produce clip.ogv
Modified: trunk/ffmpeg2theora/SConstruct
===================================================================
--- trunk/ffmpeg2theora/SConstruct 2008-05-23 17:55:53 UTC (rev 14949)
+++ trunk/ffmpeg2theora/SConstruct 2008-05-23 17:56:21 UTC (rev 14950)
@@ -22,7 +22,6 @@
'-DPACKAGE_VERSION=\\"%s\\"' %pkg_version,
'-DPACKAGE_STRING=\\"%s-%s\\"' %(pkg_name, pkg_version),
'-DPACKAGE=\\"%s\\"' % pkg_name,
- '-DVERSION=\\"%s\\"' %pkg_version,
])
#if env['CC'] == 'gcc':
# env.Append(CCFLAGS=["-g", "-O2", "-Wall"])
@@ -81,13 +80,13 @@
env.Append(CCFLAGS=['-DHAVE_KATE', '-DHAVE_OGGKATE'])
else:
print """
- Could not find %s.
- update PKG_CONFIG_PATH to point to ffmpeg's source folder
- or run ./get_libkate.sh (for more information see INSTALL)
- """ % KATE_LIBS
+ Could not find libkate. Subtitles support will be disabled.
+ You can also run ./get_libkate.sh (for more information see INSTALL)
+ or update PKG_CONFIG_PATH to point to libkate's source folder
+ """
env = conf.Finish()
# ffmpeg2theora
ffmpeg2theora = env.Copy()
-ffmpeg2theora_sources = glob('*.c')
+ffmpeg2theora_sources = glob('src/*.c')
ffmpeg2theora.Program('ffmpeg2theora', ffmpeg2theora_sources)
Modified: trunk/ffmpeg2theora/TODO
===================================================================
--- trunk/ffmpeg2theora/TODO 2008-05-23 17:55:53 UTC (rev 14949)
+++ trunk/ffmpeg2theora/TODO 2008-05-23 17:56:21 UTC (rev 14950)
@@ -1,5 +1,4 @@
- remove global variable info
- more commandline options
-- think of adding noise reduction(best would be integration of denoise3d)
- allow frame size not multiple of 16.
- add option for pixel aspect ratio
Deleted: trunk/ffmpeg2theora/ffmpeg2theora.c
===================================================================
--- trunk/ffmpeg2theora/ffmpeg2theora.c 2008-05-23 17:55:53 UTC (rev 14949)
+++ trunk/ffmpeg2theora/ffmpeg2theora.c 2008-05-23 17:56:21 UTC (rev 14950)
@@ -1,1769 +0,0 @@
-/* -*- tab-width:4;c-file-style:"cc-mode"; -*- */
-/*
- * ffmpeg2theora.c -- Convert ffmpeg supported a/v files to Ogg Theora / Ogg Vorbis
- * Copyright (C) 2003-2008 <j at v2v.cc>
- *
- * 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-1307, USA.
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <getopt.h>
-#include <math.h>
-#include <errno.h>
-
-#include "libavformat/avformat.h"
-#include "libavdevice/avdevice.h"
-#include "libswscale/swscale.h"
-#include "libpostproc/postprocess.h"
-
-#include "theora/theora.h"
-#include "vorbis/codec.h"
-#include "vorbis/vorbisenc.h"
-
-#ifdef WIN32
-#include "fcntl.h"
-#endif
-
-#include "theorautils.h"
-#include "subtitles.h"
-#include "ffmpeg2theora.h"
-
-#ifdef __linux__
- #define VIDEO4LINUX_ENABLED
-#endif
-
-enum {
- NULL_FLAG,
- DEINTERLACE_FLAG,
- OPTIMIZE_FLAG,
- SYNC_FLAG,
- NOSOUND_FLAG,
- CROPTOP_FLAG,
- CROPBOTTOM_FLAG,
- CROPRIGHT_FLAG,
- CROPLEFT_FLAG,
- ASPECT_FLAG,
- INPUTFPS_FLAG,
- AUDIOSTREAM_FLAG,
- SUBTITLES_FLAG,
- SUBTITLES_ENCODING_FLAG,
- SUBTITLES_LANGUAGE_FLAG,
- SUBTITLES_CATEGORY_FLAG,
- VHOOK_FLAG,
- FRONTEND_FLAG,
- SPEEDLEVEL_FLAG,
- PP_FLAG,
- NOSKELETON
-} F2T_FLAGS;
-
-enum {
- V2V_PRESET_NONE,
- V2V_PRESET_PRO,
- V2V_PRESET_PREVIEW,
- V2V_PRESET_VIDEOBIN,
- V2V_PRESET_PADMA,
- V2V_PRESET_PADMASTREAM,
-} F2T_PRESETS;
-
-
-#define PAL_HALF_WIDTH 384
-#define PAL_HALF_HEIGHT 288
-#define NTSC_HALF_WIDTH 320
-#define NTSC_HALF_HEIGHT 240
-
-#define PAL_FULL_WIDTH 720
-#define PAL_FULL_HEIGHT 576
-#define NTSC_FULL_WIDTH 720
-#define NTSC_FULL_HEIGHT 480
-
-
-static int sws_flags = SWS_BICUBIC;
-
-oggmux_info info;
-
-static int using_stdin = 0;
-
-
-/**
- * Allocate and initialise an AVFrame.
- */
-AVFrame *frame_alloc (int pix_fmt, int width, int height) {
- AVFrame *picture;
- uint8_t *picture_buf;
- int size;
-
- picture = avcodec_alloc_frame ();
- if (!picture)
- return NULL;
- size = avpicture_get_size (pix_fmt, width, height);
- picture_buf = av_malloc (size);
- if (!picture_buf){
- av_free (picture);
- return NULL;
- }
- avpicture_fill ((AVPicture *) picture, picture_buf,
- pix_fmt, width, height);
- return picture;
-}
-
-/**
- * initialize ff2theora with default values
- * @return ff2theora struct
- */
-ff2theora ff2theora_init (){
- ff2theora this = calloc (1, sizeof (*this));
- if (this != NULL){
- this->disable_audio=0;
- this->video_index = -1;
- this->audio_index = -1;
- this->start_time=0;
- this->end_time=0; /* 0 denotes no end time set */
-
- // audio
- this->sample_rate = -1; // samplerate hmhmhm
- this->channels = -1;
- this->audio_quality = 1.00;// audio quality 1
- this->audio_bitrate=0;
- this->audiostream = -1;
-
- // video
- this->picture_width=0; // set to 0 to not resize the output
- this->picture_height=0; // set to 0 to not resize the output
- this->video_quality=rint(5*6.3); // video quality 5
- this->video_bitrate=0;
- this->sharpness=0;
- this->keyint=64;
- this->force_input_fps=0;
- this->sync=0;
- this->aspect_numerator=0;
- this->aspect_denominator=0;
- this->frame_aspect=0;
- this->deinterlace=0; // auto by default, if input is flaged as interlaced it will deinterlace.
- this->vhook=0;
- this->framerate_new.num = -1;
- this->framerate_new.den = 1;
-
- this->frame_topBand=0;
- this->frame_bottomBand=0;
- this->frame_leftBand=0;
- this->frame_rightBand=0;
-
- this->n_kate_streams=0;
- this->kate_streams=NULL;
-
- this->pix_fmt = PIX_FMT_YUV420P;
-
- // ffmpeg2theora --nosound -f dv -H 32000 -S 0 -v 8 -x 384 -y 288 -G 1.5 input.dv
- this->video_gamma = 0.0;
- this->video_bright = 0.0;
- this->video_contr = 0.0;
- this->video_satur = 1.0;
-
- this->y_lut_used = 0;
- this->uv_lut_used = 0;
- this->y_lut[256];
- this->uv_lut[256];
- }
- return this;
-}
-
-// gamma lookup table code
-
-static void y_lut_init(ff2theora this) {
- int i;
- double v;
-
- double c = this->video_contr;
- double b = this->video_bright;
- double g = this->video_gamma;
-
- if ((g < 0.01) || (g > 100.0)) g = 1.0;
- if ((c < 0.01) || (c > 100.0)) c = 1.0;
- if ((b < -1.0) || (b > 1.0)) b = 0.0;
-
- if (g == 1.0 && c == 1.0 && b == 0.0) return;
- this->y_lut_used = 1;
-
- printf(" Video correction: gamma=%g, contrast=%g, brightness=%g\n", g, c, b);
-
- g = 1.0 / g; // larger values shall make brighter video.
-
- for (i = 0; i < 256; i++) {
- v = (double) i / 255.0;
- v = c * v + b * 0.1;
- if (v < 0.0) v = 0.0;
- v = pow(v, g) * 255.0; // mplayer's vf_eq2.c multiplies with 256 here, strange...
-
- if (v >= 255)
- this->y_lut[i] = 255;
- else
- this->y_lut[i] = (unsigned char)(v+0.5);
- }
-}
-
-
-static void uv_lut_init(ff2theora this) {
- int i;
- double v, s;
- s = this->video_satur;
-
- if ((s < 0.0) || (s > 100.0)) s = 1.0;
-
- if (s == 1.0) return;
- this->uv_lut_used = 1;
-
- printf(" Color correction: saturation=%g\n", s);
-
- for (i = 0; i < 256; i++) {
- v = 127.0 + (s * ((double)i - 127.0));
- if (v < 0.0) v = 0.0;
-
- if (v >= 255.0)
- this->uv_lut[i] = 255;
- else
- this->uv_lut[i] = (unsigned char)(v+0.5);
- }
-}
-
-static void lut_init(ff2theora this) {
- y_lut_init(this);
- uv_lut_init(this);
-}
-
-static void lut_apply(unsigned char *lut, unsigned char *src, unsigned char *dst, int width, int height, int stride) {
- int x, y;
-
- for (y = 0; y < height; y++) {
- for (x = 0; x < width; x++) {
- dst[x] = lut[src[x]];
- }
- src += stride;
- dst += stride;
- }
-}
-
-static void prepare_yuv_buffer(ff2theora this, yuv_buffer *yuv, AVFrame *output_buffered) {
- /* pysical pages */
- yuv->y_width = this->frame_width;
- yuv->y_height = this->frame_height;
- yuv->y_stride = output_buffered->linesize[0];
-
- yuv->uv_width = this->frame_width / 2;
- yuv->uv_height = this->frame_height / 2;
- yuv->uv_stride = output_buffered->linesize[1];
-
- yuv->y = output_buffered->data[0];
- yuv->u = output_buffered->data[1];
- yuv->v = output_buffered->data[2];
- if (this->y_lut_used) {
- lut_apply(this->y_lut, yuv->y, yuv->y, yuv->y_width, yuv->y_height, yuv->y_stride);
- }
- if (this->uv_lut_used) {
- lut_apply(this->uv_lut, yuv->u, yuv->u, yuv->uv_width, yuv->uv_height, yuv->uv_stride);
- lut_apply(this->uv_lut, yuv->v, yuv->v, yuv->uv_width, yuv->uv_height, yuv->uv_stride);
- }
-}
-
-void ff2theora_output(ff2theora this) {
- int i;
- AVCodecContext *aenc = NULL;
- AVCodecContext *venc = NULL;
- AVStream *astream = NULL;
- AVStream *vstream = NULL;
- AVCodec *acodec = NULL;
- AVCodec *vcodec = NULL;
- pp_mode_t *ppMode = NULL;
- pp_context_t *ppContext = NULL;
- float frame_aspect;
- double fps = 0.0;
-
- if(this->audiostream >= 0 && this->context->nb_streams > this->audiostream) {
- AVCodecContext *enc = this->context->streams[this->audiostream]->codec;
- if (enc->codec_type == CODEC_TYPE_AUDIO) {
- this->audio_index = this->audiostream;
- fprintf(stderr," Using stream #0.%d as audio input\n",this->audio_index);
- }
- else {
- fprintf(stderr," The selected stream is not audio, falling back to automatic selection\n");
- }
- }
-
- for (i = 0; i < this->context->nb_streams; i++){
- AVCodecContext *enc = this->context->streams[i]->codec;
- switch (enc->codec_type){
- case CODEC_TYPE_VIDEO:
- if (this->video_index < 0)
- this->video_index = i;
- break;
- case CODEC_TYPE_AUDIO:
- if (this->audio_index < 0 && !this->disable_audio)
- this->audio_index = i;
- break;
- default:
- break;
- }
- }
-
- if (this->video_index >= 0){
- vstream = this->context->streams[this->video_index];
- venc = this->context->streams[this->video_index]->codec;
- vcodec = avcodec_find_decoder (venc->codec_id);
-
- fps = (double) vstream->r_frame_rate.num / vstream->r_frame_rate.den;
- if (fps > 10000)
- fps /= 1000;
-
- if(this->force_input_fps)
- fps=this->force_input_fps;
- if (vcodec == NULL || avcodec_open (venc, vcodec) < 0) {
- this->video_index = -1;
- }
- this->fps = fps;
-
-
- if(this->preset == V2V_PRESET_PREVIEW){
- if(abs(this->fps-30)<1 && (venc->width!=NTSC_HALF_WIDTH || venc->height!=NTSC_HALF_HEIGHT) ){
- this->picture_width=NTSC_HALF_WIDTH;
- this->picture_height=NTSC_HALF_HEIGHT;
- }
- else {
- this->picture_width=PAL_HALF_WIDTH;
- this->picture_height=PAL_HALF_HEIGHT;
- }
- }
- else if(this->preset == V2V_PRESET_PRO){
- if(abs(this->fps-30)<1 && (venc->width!=NTSC_FULL_WIDTH || venc->height!=NTSC_FULL_HEIGHT) ){
- this->picture_width=NTSC_FULL_WIDTH;
- this->picture_height=NTSC_FULL_HEIGHT;
- }
- else {
- this->picture_width=PAL_FULL_WIDTH;
- this->picture_height=PAL_FULL_HEIGHT;
- }
- }
- else if(this->preset == V2V_PRESET_PADMA){
- int width=venc->width-this->frame_leftBand-this->frame_rightBand;
- int height=venc->height-this->frame_topBand-this->frame_bottomBand;
- if(venc->sample_aspect_ratio.den!=0 && venc->sample_aspect_ratio.num!=0) {
- height=((float)venc->sample_aspect_ratio.den/venc->sample_aspect_ratio.num) * height;
- }
- if(this->frame_aspect == 0)
- this->frame_aspect = (float)width/height;
- if(this->frame_aspect <= 1.5) {
- if(width > 640 || height > 480) {
- //4:3 640 x 480
- this->picture_width=640;
- this->picture_height=480;
- }
- else {
- this->picture_width=width;
- this->picture_height=height;
- }
- }
- else {
- if(width > 640 || height > 360) {
- //16:9 640 x 360
- this->picture_width=640;
- this->picture_height=360;
- }
- else {
- this->picture_width=width;
- this->picture_height=height;
- }
- }
-
- }
- else if(this->preset == V2V_PRESET_PADMASTREAM){
- int width=venc->width-this->frame_leftBand-this->frame_rightBand;
- int height=venc->height-this->frame_topBand-this->frame_bottomBand;
- if(venc->sample_aspect_ratio.den!=0 && venc->sample_aspect_ratio.num!=0) {
- height=((float)venc->sample_aspect_ratio.den/venc->sample_aspect_ratio.num) * height;
- }
- if(this->frame_aspect == 0)
- this->frame_aspect = (float)width/height;
- if(this->frame_aspect <= 1.5) {
- this->picture_width=128;
- this->picture_height=96;
- }
- else {
- this->picture_width=128;
- this->picture_height=72;
- }
- }
- else if(this->preset == V2V_PRESET_VIDEOBIN){
- int width=venc->width-this->frame_leftBand-this->frame_rightBand;
- int height=venc->height-this->frame_topBand-this->frame_bottomBand;
- if(venc->sample_aspect_ratio.den!=0 && venc->sample_aspect_ratio.num!=0) {
- height=((float)venc->sample_aspect_ratio.den/venc->sample_aspect_ratio.num) * height;
- }
- if( ((float)width /height) <= 1.5) {
- if(width > 448) {
- //4:3 448 x 336
- this->picture_width=448;
- this->picture_height=336;
- }
- else {
- this->picture_width=width;
- this->picture_height=height;
- }
- }
- else {
- if(width > 512) {
- //16:9 512 x 288
- this->picture_width=512;
- this->picture_height=288;
- }
- else {
- this->picture_width=width;
- this->picture_height=height;
- }
- }
-
- }
- if(this->picture_height==0 &&
- (this->frame_leftBand || this->frame_rightBand || this->frame_topBand || this->frame_bottomBand) ){
- this->picture_height=venc->height-
- this->frame_topBand-this->frame_bottomBand;
- }
- if(this->picture_width==0 &&
- (this->frame_leftBand || this->frame_rightBand || this->frame_topBand || this->frame_bottomBand) ){
- this->picture_width=venc->width-
- this->frame_leftBand-this->frame_rightBand;
- }
- //so frame_aspect is set on the commandline
- if(this->frame_aspect != 0){
- if(this->picture_height){
- this->aspect_numerator = 10000*this->frame_aspect*this->picture_height;
- this->aspect_denominator = 10000*this->picture_width;
- }
- else{
- this->aspect_numerator = 10000*this->frame_aspect*venc->height;
- this->aspect_denominator = 10000*venc->width;
- }
- av_reduce(&this->aspect_numerator,&this->aspect_denominator,this->aspect_numerator,this->aspect_denominator,10000);
- frame_aspect=this->frame_aspect;
- }
- if(venc->sample_aspect_ratio.num!=0 && this->frame_aspect==0){
- // just use the ratio from the input
- this->aspect_numerator=venc->sample_aspect_ratio.num;
- this->aspect_denominator=venc->sample_aspect_ratio.den;
- // or we use ratio for the output
- if(this->picture_height){
- int width=venc->width-this->frame_leftBand-this->frame_rightBand;
- int height=venc->height-this->frame_topBand-this->frame_bottomBand;
- av_reduce(&this->aspect_numerator,&this->aspect_denominator,
- venc->sample_aspect_ratio.num*width*this->picture_height,
- venc->sample_aspect_ratio.den*height*this->picture_width,10000);
- frame_aspect=(float)(this->aspect_numerator*this->picture_width)/
- (this->aspect_denominator*this->picture_height);
- }
- else{
- frame_aspect=(float)(this->aspect_numerator*venc->width)/
- (this->aspect_denominator*venc->height);
- }
- }
- if((float)this->aspect_numerator/this->aspect_denominator < 1.09){
- this->aspect_numerator = 1;
- this->aspect_denominator = 1;
- frame_aspect=(float)(this->aspect_numerator*this->picture_width)/
- (this->aspect_denominator*this->picture_height);
- }
- if(this->aspect_denominator && frame_aspect){
- fprintf(stderr," Pixel Aspect Ratio: %.2f/1 ",(float)this->aspect_numerator/this->aspect_denominator);
- fprintf(stderr," Frame Aspect Ratio: %.2f/1\n",frame_aspect);
- }
-
- if (this->deinterlace==1)
- fprintf(stderr," Deinterlace: on\n");
-
- if (strcmp(this->pp_mode, "")) {
- ppContext = pp_get_context(venc->width, venc->height, PP_FORMAT_420);
- ppMode = pp_get_mode_by_name_and_quality(this->pp_mode, PP_QUALITY_MAX);
- fprintf(stderr," Postprocessing: %s\n", this->pp_mode);
- }
-
- if(!this->picture_width)
- this->picture_width = venc->width;
- if(!this->picture_height)
- this->picture_height = venc->height;
-
- /* Theora has a divisible-by-sixteen restriction for the encoded video size */
- /* scale the frame size up to the nearest /16 and calculate offsets */
- this->frame_width = ((this->picture_width + 15) >>4)<<4;
- this->frame_height = ((this->picture_height + 15) >>4)<<4;
-
- this->frame_x_offset = 0;
- this->frame_y_offset = 0;
-
- if(this->frame_width > 0 || this->frame_height > 0){
- this->sws_colorspace_ctx = sws_getContext(
- venc->width, venc->height, venc->pix_fmt,
- venc->width, venc->height, this->pix_fmt,
- sws_flags, NULL, NULL, NULL
- );
- this->sws_scale_ctx = sws_getContext(
- venc->width - (this->frame_leftBand + this->frame_rightBand),
- venc->height - (this->frame_topBand + this->frame_bottomBand),
- this->pix_fmt,
- this->frame_width, this->frame_height, this->pix_fmt,
- sws_flags, NULL, NULL, NULL
- );
- fprintf(stderr," Resize: %dx%d",venc->width,venc->height);
- if(this->frame_topBand || this->frame_bottomBand ||
- this->frame_leftBand || this->frame_rightBand){
- fprintf(stderr," => %dx%d",
- venc->width-this->frame_leftBand-this->frame_rightBand,
- venc->height-this->frame_topBand-this->frame_bottomBand);
- }
- if(this->picture_width != (venc->width-this->frame_leftBand - this->frame_rightBand)
- || this->picture_height != (venc->height-this->frame_topBand-this->frame_bottomBand))
- fprintf(stderr," => %dx%d",this->picture_width, this->picture_height);
- fprintf(stderr,"\n");
- }
-
- lut_init(this);
- }
- if (this->framerate_new.num > 0) {
- fprintf(stderr," Resample Framerate: %0.2f => %0.2f\n",
- this->fps,(double)this->framerate_new.num / this->framerate_new.den);
- }
- if (this->audio_index >= 0){
- astream = this->context->streams[this->audio_index];
- aenc = this->context->streams[this->audio_index]->codec;
- acodec = avcodec_find_decoder (aenc->codec_id);
- if (this->channels < 1) {
- if (aenc->channels > 2)
- this->channels = 2;
- else
- this->channels = aenc->channels;
- }
- if(this->sample_rate==-1) {
- this->sample_rate = aenc->sample_rate;
- }
- if (this->channels != aenc->channels && aenc->codec_id == CODEC_ID_AC3)
- aenc->channels = this->channels;
-
- if (acodec != NULL && avcodec_open (aenc, acodec) >= 0){
- if(this->sample_rate != aenc->sample_rate || this->channels != aenc->channels){
- this->audio_resample_ctx = audio_resample_init (this->channels,aenc->channels,this->sample_rate,aenc->sample_rate);
- if(this->sample_rate!=aenc->sample_rate)
- fprintf(stderr," Resample: %dHz => %dHz\n",aenc->sample_rate,this->sample_rate);
- if(this->channels!=aenc->channels)
- fprintf(stderr," Channels: %d => %d\n",aenc->channels,this->channels);
- }
- else{
- this->audio_resample_ctx=NULL;
- }
- }
- else{
- this->audio_index = -1;
- }
- }
-
- if (this->video_index >= 0 || this->audio_index >=0){
- AVFrame *frame=NULL;
- AVFrame *output=NULL;
- AVFrame *output_tmp=NULL;
- AVFrame *output_resized=NULL;
- AVFrame *output_buffered=NULL;
-
- AVPacket pkt;
- int len;
- int len1;
- int got_picture;
- int first = 1;
- int e_o_s = 0;
- int ret;
- uint8_t *ptr;
- int16_t *audio_buf= av_malloc(4*AVCODEC_MAX_AUDIO_FRAME_SIZE);
- int16_t *resampled= av_malloc(4*AVCODEC_MAX_AUDIO_FRAME_SIZE);
- int no_frames;
-
- double framerate_add;
- double framerate_tmpcount = 0;
-
- if(this->video_index >= 0)
- info.audio_only=0;
- else
- info.audio_only=1;
-
- if(this->audio_index>=0)
- info.video_only=0;
- else
- info.video_only=1;
-
- if(!info.audio_only){
- frame = frame_alloc(vstream->codec->pix_fmt,
- vstream->codec->width,vstream->codec->height);
- output_tmp =frame_alloc(this->pix_fmt,
- vstream->codec->width,vstream->codec->height);
- output =frame_alloc(this->pix_fmt,
- vstream->codec->width,vstream->codec->height);
- output_resized =frame_alloc(this->pix_fmt,
- this->frame_width, this->frame_height);
- output_buffered =frame_alloc(this->pix_fmt,
- this->frame_width, this->frame_height);
-
- /* video settings here */
- /* config file? commandline options? v2v presets? */
-
- theora_info_init (&info.ti);
-
- info.ti.width = this->frame_width;
- info.ti.height = this->frame_height;
- info.ti.frame_width = this->picture_width;
- info.ti.frame_height = this->picture_height;
- info.ti.offset_x = this->frame_x_offset;
- info.ti.offset_y = this->frame_y_offset;
- if(this->force_input_fps) {
- info.ti.fps_numerator = 1000000 * (this->fps); /* fps= numerator/denominator */
- info.ti.fps_denominator = 1000000;
- }
- else {
- if (this->framerate_new.num > 0) {
- // new framerate is interger only right now,
- // so denominator is always 1
- info.ti.fps_numerator = this->framerate_new.num;
- info.ti.fps_denominator = this->framerate_new.den;
- }
- else {
- info.ti.fps_numerator=vstream->r_frame_rate.num;
- info.ti.fps_denominator = vstream->r_frame_rate.den;
- }
- }
-
- /* this is pixel aspect ratio */
- info.ti.aspect_numerator=this->aspect_numerator;
- info.ti.aspect_denominator=this->aspect_denominator;
- // FIXME: is all input material with fps==25 OC_CS_ITU_REC_470BG?
- // guess not, commandline option to select colorspace would be the best.
- if((this->fps-25)<1)
- info.ti.colorspace = OC_CS_ITU_REC_470BG;
- else if(abs(this->fps-30)<1)
- info.ti.colorspace = OC_CS_ITU_REC_470M;
- else
- info.ti.colorspace = OC_CS_UNSPECIFIED;
-
- info.ti.target_bitrate = this->video_bitrate;
- info.ti.quality = this->video_quality;
- info.ti.dropframes_p = 0;
- info.ti.keyframe_auto_p = 1;
- info.ti.keyframe_frequency = this->keyint;
- info.ti.keyframe_frequency_force = this->keyint;
- info.ti.keyframe_data_target_bitrate = info.ti.target_bitrate * 1.5;
- info.ti.keyframe_auto_threshold = 80;
- info.ti.keyframe_mindistance = 8;
- info.ti.noise_sensitivity = 1;
- // range 0-2, 0 sharp, 2 less sharp,less bandwidth
- info.ti.sharpness = this->sharpness;
-
- }
- /* audio settings here */
- info.channels = this->channels;
- info.sample_rate = this->sample_rate;
- info.vorbis_quality = this->audio_quality * 0.1;
- info.vorbis_bitrate = this->audio_bitrate;
- /* subtitles */
-#ifdef HAVE_KATE
- for (i=0; i<this->n_kate_streams; ++i) {
- ff2theora_kate_stream *ks = this->kate_streams+i;
- kate_info *ki = &info.kate_streams[i].ki;
- kate_info_init(ki);
- if (ks->num_subtitles > 0) {
- kate_info_set_language(ki, ks->subtitles_language);
- kate_info_set_category(ki, ks->subtitles_category[0]?ks->subtitles_category:"subtitles");
- if(this->force_input_fps) {
- ki->gps_numerator = 1000000 * (this->fps); /* fps= numerator/denominator */
- ki->gps_denominator = 1000000;
- }
- else {
- if (this->framerate_new.num > 0) {
- // new framerate is interger only right now,
- // so denominator is always 1
- ki->gps_numerator = this->framerate_new.num;
- ki->gps_denominator = this->framerate_new.den;
- }
- else {
- ki->gps_numerator=vstream->r_frame_rate.num;
- ki->gps_denominator = vstream->r_frame_rate.den;
- }
- }
- ki->granule_shift = 32;
- }
- }
-#endif
- oggmux_init (&info);
- /*seek to start time*/
- if(this->start_time) {
- av_seek_frame( this->context, -1, (int64_t)AV_TIME_BASE*this->start_time, 1);
- /* discard subtitles by their end time, so we still have those that start before the start time,
- but end after it */
- for (i=0; i<this->n_kate_streams; ++i) {
- ff2theora_kate_stream *ks=this->kate_streams+i;
- while (ks->subtitles_count < ks->num_subtitles && ks->subtitles[ks->subtitles_count].t1 <= this->start_time) {
- /* printf("skipping subtitle %u\n", ks->subtitles_count); */
- ks->subtitles_count++;
- }
- }
- }
-
- if(info.audio_only && (this->end_time>0 || this->start_time>0)){
- fprintf(stderr,"Sorry, right now start/end time does not work for audio only files.\n");
- exit(1);
- }
-
- if (this->framerate_new.num > 0) {
- double framerate_new = (double)this->framerate_new.num / this->framerate_new.den;
- framerate_add = framerate_new/this->fps;
- //fprintf(stderr,"calculating framerate addition to %f\n",framerate_add);
- this->fps = framerate_new;
- }
-
- /*check for end time and calculate number of frames to encode*/
- no_frames = this->fps*(this->end_time - this->start_time);
- if(this->end_time > 0 && no_frames <= 0){
- fprintf(stderr,"End time has to be bigger than start time.\n");
- exit(1);
- }
- /* main decoding loop */
- do{
- if(no_frames > 0){
- if(this->frame_count > no_frames){
- break;
- }
- }
- ret = av_read_frame(this->context,&pkt);
- if(ret<0){
- e_o_s=1;
- }
-
- ptr = pkt.data;
- len = pkt.size;
- if (e_o_s && !info.audio_only || (ret >= 0 && pkt.stream_index == this->video_index)){
- if(len == 0 && !first && !e_o_s){
- fprintf (stderr, "no frame available\n");
- }
- while(e_o_s || len > 0){
- int dups = 0;
- yuv_buffer yuv;
- len1 = avcodec_decode_video(vstream->codec, frame, &got_picture, ptr, len);
- if(len1>=0) {
- if(got_picture){
- // this is disabled by default since it does not work
- // for all input formats the way it should.
- if(this->sync == 1) {
- double delta = ((double) pkt.dts /
- AV_TIME_BASE - this->pts_offset) *
- this->fps - this->frame_count;
- /* 0.7 is an arbitrary value */
- /* it should be larger than half a frame to
- avoid excessive dropping and duplicating */
- if (delta < -0.7) {
-#ifdef DEBUG
- fprintf(stderr,
- "Frame dropped to maintain sync\n");
-#endif
- break;
- }
- if (delta > 0.7) {
- //dups = lrintf(delta);
- dups = (int)delta;
-#ifdef DEBUG
- fprintf(stderr,
- "%d duplicate %s added to maintain sync\n",
- dups, (dups == 1) ? "frame" : "frames");
-#endif
- }
- }
-
- if (this->framerate_new.num > 0) {
- framerate_tmpcount += framerate_add;
- if (framerate_tmpcount < (double)(this->frame_count+1)) {
- got_picture = 0;
- }
- else {
- dups = 0;
- while (framerate_tmpcount >= (double)(this->frame_count+2+dups)) {
- dups += 1;
- }
- }
- }
-
- //For audio only files command line option"-e" will not work
- //as we don't increment frame_count in audio section.
-
- if(venc->pix_fmt != this->pix_fmt) {
- sws_scale(this->sws_colorspace_ctx,
- frame->data, frame->linesize, 0, venc->height,
- output_tmp->data, output_tmp->linesize);
-
- }
- else{
- output_tmp = frame;
- }
- if(frame->interlaced_frame || this->deinterlace){
- if(avpicture_deinterlace((AVPicture *)output,(AVPicture *)output_tmp,this->pix_fmt,venc->width,venc->height)<0){
- fprintf(stderr,"Deinterlace failed.\n");
- exit(1);
- }
- }
- else{
- output=output_tmp;
- }
- // now output
- if(ppMode)
- pp_postprocess(output->data, output->linesize,
- output->data, output->linesize,
- venc->width, venc->height,
- output->qscale_table, output->qstride,
- ppMode, ppContext, this->pix_fmt);
- if(this->vhook)
- frame_hook_process((AVPicture *)output, this->pix_fmt, venc->width,venc->height);
-
- if (this->frame_topBand || this->frame_leftBand) {
- if (av_picture_crop((AVPicture *)output_tmp, (AVPicture *)output,
- this->pix_fmt, this->frame_topBand, this->frame_leftBand) < 0) {
- av_log(NULL, AV_LOG_ERROR, "error cropping picture\n");
- }
- output = output_tmp;
- }
- if(this->sws_scale_ctx){
- sws_scale(this->sws_scale_ctx,
- output->data, output->linesize, 0, venc->height - (this->frame_topBand + this->frame_bottomBand),
- output_resized->data, output_resized->linesize);
- }
- else{
- output_resized=output;
- }
-
- }
- ptr += len1;
- len -= len1;
- }
- //now output_resized
-
- if(!first) {
- if(got_picture || e_o_s) {
- prepare_yuv_buffer(this, &yuv, output_buffered);
- do {
- oggmux_add_video(&info, &yuv, e_o_s);
- this->frame_count++;
- } while(dups--);
- }
- }
- if(got_picture) {
- first=0;
- av_picture_copy ((AVPicture *)output_buffered, (AVPicture *)output_resized, this->pix_fmt, this->frame_width, this->frame_height);
- }
- if(!got_picture){
- break;
- }
- }
-
- }
- if(e_o_s && !info.video_only
- || (ret >= 0 && pkt.stream_index == this->audio_index)){
- this->pts_offset = (double) pkt.pts / AV_TIME_BASE -
- (double) this->sample_count / this->sample_rate;
- while(e_o_s || len > 0 ){
- int samples=0;
- int samples_out=0;
- int data_size = 4*AVCODEC_MAX_AUDIO_FRAME_SIZE;
- if(len > 0){
- len1 = avcodec_decode_audio2(astream->codec, audio_buf, &data_size, ptr, len);
- if (len1 < 0){
- /* if error, we skip the frame */
- break;
- }
- len -= len1;
- ptr += len1;
- if(data_size >0){
- samples =data_size / (aenc->channels * 2);
-
- samples_out = samples;
- if(this->audio_resample_ctx){
- samples_out = audio_resample(this->audio_resample_ctx, resampled, audio_buf, samples);
- }
- else
- resampled=audio_buf;
- }
- }
- oggmux_add_audio(&info, resampled,
- samples_out *(this->channels),samples_out,e_o_s);
- this->sample_count += samples_out;
- if(e_o_s && len <= 0){
- break;
- }
- }
-
- }
-
- /* if we have subtitles starting before then, add it */
- if (info.with_kate) {
- double avtime = info.audio_only ? info.audiotime :
- info.video_only ? info.videotime :
- info.audiotime < info.videotime ? info.audiotime : info.videotime;
- for (i=0; i<this->n_kate_streams; ++i) {
- ff2theora_kate_stream *ks = this->kate_streams+i;
- if (ks->num_subtitles > 0) {
- ff2theora_subtitle *sub = ks->subtitles+ks->subtitles_count;
- /* we encode a bit in advance so we're sure to hit the time, the packet will
- be held till the right time. If we don't do that, we can insert late and
- oggz-validate moans */
- while (ks->subtitles_count < ks->num_subtitles && sub->t0-1.0 <= avtime+this->start_time) {
- int eos = (ks->subtitles_count == ks->num_subtitles-1);
- oggmux_add_kate_text(&info, i, sub->t0, sub->t1, sub->text, sub->len, eos);
- ks->subtitles_count++;
- ++sub;
- }
- }
- }
- }
-
- /* flush out the file */
- oggmux_flush (&info, e_o_s);
- av_free_packet (&pkt);
- }
- while (ret >= 0);
-
- for (i=0; i<this->n_kate_streams; ++i) {
- ff2theora_kate_stream *ks = this->kate_streams+i;
- if (ks->num_subtitles > 0 && ks->subtitles_count<ks->num_subtitles) {
- double t = (info.videotime<info.audiotime?info.audiotime:info.videotime)+this->start_time;
- oggmux_add_kate_end_packet(&info, i, t);
- oggmux_flush (&info, e_o_s);
- }
- }
-
- oggmux_close (&info);
- if(ppContext)
- pp_free_context(ppContext);
- }
- else{
- fprintf (stderr, "No video or audio stream found.\n");
- }
-}
-
-void ff2theora_close (ff2theora this){
- /* clear out state */
- free_subtitles(this);
- av_free (this);
-}
-
-double aspect_check(const char *arg)
-{
- int x = 0, y = 0;
- double ar = 0;
- const char *p;
-
- p = strchr(arg, ':');
- if (!p) {
- p = strchr(arg, '/');
- }
- if (p) {
- x = strtol(arg, (char **)&arg, 10);
- if (arg == p)
- y = strtol(arg+1, (char **)&arg, 10);
- if (x > 0 && y > 0)
- ar = (double)x / (double)y;
- } else
- ar = strtod(arg, (char **)&arg);
-
- if (!ar) {
- fprintf(stderr, "Incorrect aspect ratio specification.\n");
- exit(1);
- }
- return ar;
-}
-
-static void add_frame_hooker(const char *arg)
-{
- int argc = 0;
- char *argv[64];
- int i;
- char *args = av_strdup(arg);
-
- argv[0] = strtok(args, " ");
- while (argc < 62 && (argv[++argc] = strtok(NULL, " "))) {
- }
-
- i = frame_hook_add(argc, argv);
- if (i != 0) {
- fprintf(stderr, "Failed to add video hook function: %s\n", arg);
- exit(1);
- }
-}
-
-AVRational get_framerate(const char* arg)
-{
- const char *p;
- AVRational framerate;
-
- p = strchr(arg, ':');
- if (!p) {
- p = strchr(arg, '/');
- }
- if (p) {
- framerate.num = strtol(arg, (char **)&arg, 10);
- if (arg == p)
- framerate.den = strtol(arg+1, (char **)&arg, 10);
- if(framerate.num <= 0)
- framerate.num = -1;
- if(framerate.den <= 0)
- framerate.den = 1;
- } else {
- framerate.num = strtol(arg, (char **)&arg,10);
- framerate.den = 1;
- }
- return(framerate);
-}
-
-int crop_check(ff2theora this, char *name, const char *arg)
-{
- int crop_value = atoi(arg);
- if (crop_value < 0) {
- fprintf(stderr, "Incorrect crop size `%s'.\n",name);
- exit(1);
- }
- if ((crop_value % 2) != 0) {
- fprintf(stderr, "Crop size `%s' must be a multiple of 2.\n",name);
- exit(1);
- }
- /*
- if ((crop_value) >= this->height){
- fprintf(stderr, "Vertical crop dimensions are outside the range of the original image.\nRemember to crop first and scale second.\n");
- exit(1);
- }
- */
- return crop_value;
-}
-
-
-
-void print_presets_info() {
- fprintf (stdout,
- // "v2v presets - more info at http://wiki.v2v.cc/presets"
- "v2v presets:\n"
- " preview Video: 320x240 if fps ~ 30, 384x288 otherwise\n"
- " Quality 5 - Sharpness 2\n"
- " Audio: Max 2 channels - Quality 1\n"
- "\n"
- " pro Video: 720x480 if fps ~ 30, 720x576 otherwise\n"
- " Quality 7 - Sharpness 0\n"
- " Audio: Max 2 channels - Quality 3\n"
- "\n"
- " videobin Video: 512x288 for 16:9 material, 448x336 for 4:3 material\n"
- " Bitrate 600kbs\n"
- " Audio: Max 2 channels - Quality 3\n"
- "\n"
- " padma Video: 640x360 for 16:9 material, 640x480 for 4:3 material\n"
- " Quality 5 - Sharpness 0\n"
- " Audio: Max 2 channels - Quality 3\n"
- "\n"
- " padma-stream Video: 128x72 for 16:9 material, 128x96 for 4:3 material\n"
- " Audio: mono quality -1\n"
- "\n"
- );
-}
-
-void print_usage (){
- fprintf (stdout,
- PACKAGE " " PACKAGE_VERSION "\n"
- "\n"
- " Usage: " PACKAGE " [options] input\n"
- "\n"
- "General output options:\n"
- " -o, --output alternative output filename\n"
- " --no-skeleton disables ogg skeleton metadata output\n"
- " -s, --starttime start encoding at this time (in sec.)\n"
- " -e, --endtime end encoding at this time (in sec.)\n"
- " -p, --v2v-preset encode file with v2v preset.\n"
- " Right now there is preview, pro and videobin. Run\n"
- " '"PACKAGE" -p info' for more informations\n"
- "\n"
- "Video output options:\n"
- " -v, --videoquality [0 to 10] encoding quality for video (default: 5)\n"
- " use higher values for better quality\n"
- " -V, --videobitrate [1 to 16778] encoding bitrate for video (kb/s)\n"
- " --optimize optimize video output filesize (slower) (same as speedlevel 0)\n"
- " --speedlevel [0 2] encoding is faster with higher values the cost is quality and bandwidth\n"
- " -x, --width scale to given width (in pixels)\n"
- " -y, --height scale to given height (in pixels)\n"
- " --aspect define frame aspect ratio: i.e. 4:3 or 16:9\n"
- " -F, --framerate output framerate e.g 25:2 or 16\n"
- " --croptop, --cropbottom, --cropleft, --cropright\n"
- " crop input by given pixels before resizing\n"
- " -S, --sharpness [0 to 2] sharpness of images (default: 0).\n"
- " Note: lower values make the video sharper.\n"
- " -K, --keyint [1 to 65536] keyframe interval (default: 64)\n"
- "\n"
- "Video transfer options:\n"
- " --pp Video Postprocessing, denoise, deblock, deinterlacer\n"
- " use --pp help for a list of available filters.\n"
- " -C, --contrast [0.1 to 10.0] contrast correction (default: 1.0)\n"
- " Note: lower values make the video darker.\n"
- " -B, --brightness [-1.0 to 1.0] brightness correction (default: 0.0)\n"
- " Note: lower values make the video darker.\n"
- " -G, --gamma [0.1 to 10.0] gamma correction (default: 1.0)\n"
- " Note: lower values make the video darker.\n"
- " -Z, --saturation [0.1 to 10.0] saturation correction (default: 1.0)\n"
- " Note: lower values make the video grey.\n"
- "\n"
- "Audio output options:\n"
- " -a, --audioquality [-2 to 10] encoding quality for audio (default: 1)\n"
- " use higher values for better quality\n"
- " -A, --audiobitrate [32 to 500] encoding bitrate for audio (kb/s)\n"
- " -c, --channels set number of output channels\n"
- " -H, --samplerate set output samplerate (in Hz)\n"
- " --nosound disable the sound from input\n"
- "\n"
- "Input options:\n"
- " --deinterlace force deinterlace, otherwise only material\n"
- " marked as interlaced will be deinterlaced\n"
- " --vhook you can use ffmpeg's vhook system, example:\n"
- " ffmpeg2theora --vhook '/path/watermark.so -f wm.gif' input.dv\n"
- " -f, --format specify input format\n"
- " --inputfps fps override input fps\n"
- " --audiostream id by default the last audio stream is selected,\n"
- " use this to select another audio stream\n"
- " --sync use A/V sync from input container. Since this does\n"
- " not work with all input format you have to manually\n"
- " enable it if you have issues with A/V sync\n"
- "\n"
-#ifdef HAVE_KATE
- "Subtitles options:\n"
- " --subtitles file use subtitles from the given file (SubRip (.srt) format)\n"
- " --subtitles-encoding encoding set encoding of the subtitles file\n"
- " supported are " SUPPORTED_ENCODINGS "\n"
- " --subtitles-language language set subtitles language (de, en_GB, etc)\n"
- " --subtitles-category category set subtitles category (default \"subtitles\")\n"
- "\n"
-#endif
- "Metadata options:\n"
- " --artist Name of artist (director)\n"
- " --title Title\n"
- " --date Date\n"
- " --location Location\n"
- " --organization Name of organization (studio)\n"
- " --copyright Copyright\n"
- " --license License\n"
- " --contact Contact link\n"
- "\n"
- "Other options:\n"
-#ifndef _WIN32
- " --nice n set niceness to n\n"
-#endif
- " -P, --pid fname write the process' id to a file\n"
- " -h, --help this message\n"
- "\n"
- "Examples:\n"
- " ffmpeg2theora videoclip.avi (will write output to videoclip.ogv)\n"
- "\n"
- " ffmpeg2theora videoclip.avi --subtitles subtitles.srt (same, with subtitles)\n"
- "\n"
- " cat something.dv | ffmpeg2theora -f dv -o output.ogv -\n"
- "\n"
- " Encode a series of images:\n"
- " ffmpeg2theora -f image2 frame%%06d.png -o output.ogv\n"
- "\n"
-#if 0
- " Live streaming from V4L Device:\n"
- " ffmpeg2theora /dev/video0 -fps 15 -x 160 -y 128 -o - \\\n"
- " | oggfwd iccast2server 8000 password /theora.ogv\n"
- "\n"
-#endif
- " Live encoding from a DV camcorder (needs a fast machine):\n"
- " dvgrab - | ffmpeg2theora -f dv -x 352 -y 288 -o output.ogv -\n"
- "\n"
- " Live encoding and streaming to icecast server:\n"
- " dvgrab --format raw - \\\n"
- " | ffmpeg2theora -f dv -x 160 -y 128 -o /dev/stdout - \\\n"
- " | oggfwd iccast2server 8000 password /theora.ogv\n"
- "\n"
- );
- exit (0);
-}
-
-int main (int argc, char **argv){
- int n;
- int outputfile_set=0;
- char outputfile_name[255];
- char inputfile_name[255];
- char *str_ptr;
-
- static int flag = -1;
- static int metadata_flag = 0;
-
- AVInputFormat *input_fmt = NULL;
- AVFormatParameters *formatParams = NULL;
-
- int c,long_option_index;
- const char *optstring = "P:o:k:f:F:x:y:v:V:a:A:S:K:d:H:c:G:Z:C:B:p:N:s:e:D:h::";
- struct option options [] = {
- {"pid",required_argument,NULL, 'P'},
- {"output",required_argument,NULL,'o'},
- {"skeleton",no_argument,NULL,'k'},
- {"no-skeleton",no_argument,&flag,NOSKELETON},
- {"format",required_argument,NULL,'f'},
- {"width",required_argument,NULL,'x'},
- {"height",required_argument,NULL,'y'},
- {"videoquality",required_argument,NULL,'v'},
- {"videobitrate",required_argument,NULL,'V'},
- {"audioquality",required_argument,NULL,'a'},
- {"audiobitrate",required_argument,NULL,'A'},
- {"sharpness",required_argument,NULL,'S'},
- {"keyint",required_argument,NULL,'K'},
- {"deinterlace",0,&flag,DEINTERLACE_FLAG},
- {"pp",required_argument,&flag,PP_FLAG},
- {"samplerate",required_argument,NULL,'H'},
- {"channels",required_argument,NULL,'c'},
- {"gamma",required_argument,NULL,'G'},
- {"brightness",required_argument,NULL,'B'},
- {"contrast",required_argument,NULL,'C'},
- {"saturation",required_argument,NULL,'Z'},
- {"nosound",0,&flag,NOSOUND_FLAG},
- {"vhook",required_argument,&flag,VHOOK_FLAG},
- {"framerate",required_argument,NULL,'F'},
- {"aspect",required_argument,&flag,ASPECT_FLAG},
- {"v2v-preset",required_argument,NULL,'p'},
- {"nice",required_argument,NULL,'N'},
- {"croptop",required_argument,&flag,CROPTOP_FLAG},
- {"cropbottom",required_argument,&flag,CROPBOTTOM_FLAG},
- {"cropright",required_argument,&flag,CROPRIGHT_FLAG},
- {"cropleft",required_argument,&flag,CROPLEFT_FLAG},
- {"inputfps",required_argument,&flag,INPUTFPS_FLAG},
- {"audiostream",required_argument,&flag,AUDIOSTREAM_FLAG},
- {"subtitles",required_argument,&flag,SUBTITLES_FLAG},
- {"subtitles-encoding",required_argument,&flag,SUBTITLES_ENCODING_FLAG},
- {"subtitles-language",required_argument,&flag,SUBTITLES_LANGUAGE_FLAG},
- {"subtitles-category",required_argument,&flag,SUBTITLES_CATEGORY_FLAG},
- {"starttime",required_argument,NULL,'s'},
- {"endtime",required_argument,NULL,'e'},
- {"sync",0,&flag,SYNC_FLAG},
- {"optimize",0,&flag,OPTIMIZE_FLAG},
- {"speedlevel",required_argument,&flag,SPEEDLEVEL_FLAG},
- {"frontend",0,&flag,FRONTEND_FLAG},
-
- {"artist",required_argument,&metadata_flag,10},
- {"title",required_argument,&metadata_flag,11},
- {"date",required_argument,&metadata_flag,12},
- {"location",required_argument,&metadata_flag,13},
- {"organization",required_argument,&metadata_flag,14},
- {"copyright",required_argument,&metadata_flag,15},
- {"license",required_argument,&metadata_flag,16},
- {"contact",required_argument,&metadata_flag,17},
- {"source-hash",required_argument,&metadata_flag,18},
-
- {"help",0,NULL,'h'},
- {NULL,0,NULL,0}
- };
-
- char pidfile_name[255] = { '\0' };
- FILE *fpid = NULL;
-
- ff2theora convert = ff2theora_init ();
- avcodec_register_all();
- avdevice_register_all();
- av_register_all();
-
- if (argc == 1){
- print_usage ();
- }
- // set some variables;
- init_info(&info);
- theora_comment_init (&info.tc);
-
- while((c=getopt_long(argc,argv,optstring,options,&long_option_index))!=EOF){
- switch(c)
- {
- case 0:
- if (flag) {
- switch (flag)
- {
- case DEINTERLACE_FLAG:
- convert->deinterlace = 1;
- flag = -1;
- break;
- case PP_FLAG:
- if(!strcmp(optarg, "help")) {
- fprintf(stdout, pp_help);
- exit(1);
- }
- snprintf(convert->pp_mode,sizeof(convert->pp_mode),"%s",optarg);
- flag = -1;
- break;
- case VHOOK_FLAG:
- convert->vhook = 1;
- add_frame_hooker(optarg);
- flag = -1;
- break;
-
- case SYNC_FLAG:
- convert->sync = 1;
- flag = -1;
- break;
- case NOSOUND_FLAG:
- convert->disable_audio = 1;
- flag = -1;
- break;
- case OPTIMIZE_FLAG:
- info.speed_level = 0;
- flag = -1;
- break;
- case SPEEDLEVEL_FLAG:
- info.speed_level = atoi(optarg);
- flag = -1;
- break;
- case FRONTEND_FLAG:
- info.frontend = 1;
- flag = -1;
- break;
- /* crop */
- case CROPTOP_FLAG:
- convert->frame_topBand = crop_check(convert,"top",optarg);
- flag = -1;
- break;
- case CROPBOTTOM_FLAG:
- convert->frame_bottomBand = crop_check(convert,"bottom",optarg);
- flag = -1;
- break;
- case CROPRIGHT_FLAG:
- convert->frame_rightBand = crop_check(convert,"right",optarg);
- flag = -1;
- break;
- case CROPLEFT_FLAG:
- convert->frame_leftBand = crop_check(convert,"left",optarg);
- flag = -1;
- break;
- case ASPECT_FLAG:
- convert->frame_aspect = aspect_check(optarg);
- flag = -1;
- break;
- case INPUTFPS_FLAG:
- convert->force_input_fps = atof(optarg);
- flag = -1;
- break;
- case AUDIOSTREAM_FLAG:
- convert->audiostream = atoi(optarg);
- flag = -1;
- break;
- case NOSKELETON:
- info.with_skeleton=0;
- break;
-#ifdef HAVE_KATE
- case SUBTITLES_FLAG:
- set_subtitles_file(convert,optarg);
- flag = -1;
- info.with_kate=1;
- break;
- case SUBTITLES_ENCODING_FLAG:
- if (!strcmp(optarg,"utf-8")) set_subtitles_encoding(convert,ENC_UTF8);
- if (!strcmp(optarg,"utf8")) set_subtitles_encoding(convert,ENC_UTF8);
- else if (!strcmp(optarg,"iso-8859-1")) set_subtitles_encoding(convert,ENC_ISO_8859_1);
- else if (!strcmp(optarg,"latin1")) set_subtitles_encoding(convert,ENC_ISO_8859_1);
- else report_unknown_subtitle_encoding(optarg);
- flag = -1;
- break;
- case SUBTITLES_LANGUAGE_FLAG:
- if (strlen(optarg)>15) {
- fprintf(stderr, "WARNING - language is limited to 15 characters, and will be truncated\n");
- }
- set_subtitles_language(convert,optarg);
- flag = -1;
- break;
- case SUBTITLES_CATEGORY_FLAG:
- if (strlen(optarg)>15) {
- fprintf(stderr, "WARNING - category is limited to 15 characters, and will be truncated\n");
- }
- set_subtitles_category(convert,optarg);
- flag = -1;
- break;
-#else
- case SUBTITLES_FLAG:
- case SUBTITLES_ENCODING_FLAG:
- case SUBTITLES_LANGUAGE_FLAG:
- case SUBTITLES_CATEGORY_FLAG:
- fprintf(stderr, "WARNING - Kate support not compiled in, subtitles will not be output\n"
- " - install libkate and rebuild ffmpeg2theora for subtitle support\n");
- break;
-#endif
- }
- }
-
- /* metadata */
- if (metadata_flag){
- switch(metadata_flag) {
- case 10:
- theora_comment_add_tag(&info.tc, "ARTIST", optarg);
- break;
- case 11:
- theora_comment_add_tag(&info.tc, "TITLE", optarg);
- break;
- case 12:
- theora_comment_add_tag(&info.tc, "DATE", optarg);
- break;
- case 13:
- theora_comment_add_tag(&info.tc, "LOCATION", optarg);
- break;
- case 14:
- theora_comment_add_tag(&info.tc, "ORGANIZATION", optarg);
- break;
- case 15:
- theora_comment_add_tag(&info.tc, "COPYRIGHT", optarg);
- break;
- case 16:
- theora_comment_add_tag(&info.tc, "LICENSE", optarg);
- break;
- case 17:
- theora_comment_add_tag(&info.tc, "CONTACT", optarg);
- break;
- case 18:
- theora_comment_add_tag(&info.tc, "SOURCE HASH", optarg);
- break;
- }
- metadata_flag=0;
- }
- break;
- case 'e':
- convert->end_time = atoi(optarg);
- break;
- case 's':
- convert->start_time = atoi(optarg);
- break;
- case 'o':
- snprintf(outputfile_name,sizeof(outputfile_name),"%s",optarg);
- outputfile_set=1;
- break;
- case 'k':
- info.with_skeleton=1;
- break;
- case 'P':
- sprintf(pidfile_name,optarg);
- break;
- case 'f':
- input_fmt=av_find_input_format(optarg);
- break;
- case 'x':
- convert->picture_width=atoi(optarg);
- break;
- case 'y':
- convert->picture_height=atoi(optarg);
- break;
- case 'v':
- convert->video_quality = rint(atof(optarg)*6.3);
- if(convert->video_quality <0 || convert->video_quality >63){
- fprintf(stderr,"Only values from 0 to 10 are valid for video quality.\n");
- exit(1);
- }
- convert->video_bitrate=0;
- break;
- case 'V':
- convert->video_bitrate=rint(atof(optarg)*1000);
- if (convert->video_bitrate < 1) {
- fprintf(stderr, "Only values from 1 to 16000 are valid for video bitrate (in kb/s).\n");
- exit(1);
- }
- convert->video_quality=0;
- break;
- case 'a':
- convert->audio_quality=atof(optarg);
- if(convert->audio_quality<-2 || convert->audio_quality>10){
- fprintf(stderr,"Only values from -2 to 10 are valid for audio quality.\n");
- exit(1);
- }
- convert->audio_bitrate=0;
- break;
- case 'A':
- convert->audio_bitrate=atof(optarg)*1000;
- if(convert->audio_bitrate<0){
- fprintf(stderr,"Only values >0 are valid for audio bitrate.\n");
- exit(1);
- }
- convert->audio_quality = -990;
- break;
- case 'G':
- convert->video_gamma = atof(optarg);
- break;
- case 'C':
- convert->video_contr = atof(optarg);
- break;
- case 'Z':
- convert->video_satur = atof(optarg);
- break;
- case 'B':
- convert->video_bright = atof(optarg);
- break;
- case 'S':
- convert->sharpness = atoi(optarg);
- if (convert->sharpness < 0 || convert->sharpness > 2) {
- fprintf (stderr, "Only values from 0 to 2 are valid for sharpness.\n");
- exit(1);
- }
- break;
- case 'K':
- convert->keyint = atoi(optarg);
- if (convert->keyint < 1 || convert->keyint > 65536) {
- fprintf (stderr, "Only values from 1 to 65536 are valid for keyframe interval.\n");
- exit(1);
- }
- break;
- case 'H':
- convert->sample_rate=atoi(optarg);
- break;
- case 'F':
- convert->framerate_new = get_framerate(optarg);
- break;
- case 'c':
- convert->channels=atoi(optarg);
- if(convert->channels <= 0) {
- fprintf (stderr, "You can not have less than one audio channel.\n");
- exit(1);
- }
- break;
- case 'p':
- //v2v presets
- if(!strcmp(optarg, "info")){
- print_presets_info();
- exit(1);
- }
- else if(!strcmp(optarg, "pro")){
- //need a way to set resize here. and not later
- convert->preset=V2V_PRESET_PRO;
- convert->video_quality = rint(7*6.3);
- convert->audio_quality = 3.00;
- convert->sharpness = 0;
- info.speed_level = 0;
- }
- else if(!strcmp(optarg,"preview")){
- //need a way to set resize here. and not later
- convert->preset=V2V_PRESET_PREVIEW;
- convert->video_quality = rint(5*6.3);
- convert->audio_quality = 1.00;
- convert->sharpness = 2;
- info.speed_level = 0;
- }
- else if(!strcmp(optarg,"videobin")){
- convert->preset=V2V_PRESET_VIDEOBIN;
- convert->video_bitrate=rint(600*1000);
- convert->video_quality = 0;
- convert->audio_quality = 3.00;
- convert->sharpness = 2;
- info.speed_level = 0;
- }
- else if(!strcmp(optarg,"padma")){
- convert->preset=V2V_PRESET_PADMA;
- convert->video_quality = rint(5*6.3);
- convert->audio_quality = 3.00;
- convert->sharpness = 0;
- info.speed_level = 0;
- }
- else if(!strcmp(optarg,"padma-stream")){
- convert->preset=V2V_PRESET_PADMASTREAM;
- convert->video_bitrate=rint(180*1000);
- convert->video_quality = 0;
- convert->audio_quality = -1.00;
- convert->sample_rate=44100;
- convert->sharpness = 2;
- convert->keyint = 16;
- info.speed_level = 0;
- }
- else{
- fprintf(stderr,"\nUnknown preset.\n\n");
- print_presets_info();
- exit(1);
- }
- break;
- case 'N':
- n = atoi(optarg);
- if (n) {
-#ifndef _WIN32
- if (nice(n)<0) {
- fprintf(stderr,"Error setting `%d' for niceness.", n);
- }
-#endif
- }
- break;
- case 'h':
- print_usage ();
- exit(1);
- }
- }
-
- while(optind<argc){
- /* assume that anything following the options must be a filename */
- snprintf(inputfile_name,sizeof(inputfile_name),"%s",argv[optind]);
- if(!strcmp(inputfile_name,"-")){
- snprintf(inputfile_name,sizeof(inputfile_name),"pipe:");
- }
- if(outputfile_set!=1){
- /* reserve 4 bytes in the buffer for the `.ogv' extension */
- snprintf(outputfile_name, sizeof(outputfile_name) - 4, "%s", argv[optind]);
- if((str_ptr = strrchr(outputfile_name, '.'))) {
- sprintf(str_ptr, ".ogv");
- if(!strcmp(inputfile_name, outputfile_name)){
- snprintf(outputfile_name, sizeof(outputfile_name), "%s.ogv", inputfile_name);
- }
- }
- else {
- snprintf(outputfile_name, sizeof(outputfile_name), "%s.ogv", outputfile_name);
- }
- outputfile_set=1;
- }
- optind++;
- }
-
-#ifdef VIDEO4LINUX_ENABLED
- if(formatParams != NULL) {
- formatParams->channel = 0;
- formatParams->width = PAL_HALF_WIDTH;
- formatParams->height = PAL_HALF_HEIGHT;
- if(convert->picture_width)
- formatParams->width = convert->picture_width;
- if(convert->picture_height)
- formatParams->height = convert->picture_height;
-
- formatParams->time_base.den = 25;
- formatParams->time_base.num = 1;
- if(convert->force_input_fps) {
-
- formatParams->time_base.den = convert->force_input_fps * 1000;
- formatParams->time_base.num = 1000;
-
- }
- formatParams->standard = "pal";
- input_fmt = av_find_input_format("video4linux");
- sprintf(inputfile_name,"");
- }
-#endif
-
- //FIXME: is using_stdin still neded? is it needed as global variable?
- using_stdin |= !strcmp(inputfile_name, "pipe:" ) ||
- !strcmp( inputfile_name, "/dev/stdin" );
-
- if(outputfile_set!=1){
- fprintf(stderr,"You have to specify an output file with -o output.ogv.\n");
- exit(1);
- }
-
- /* could go, but so far no player supports offset_x/y */
- if(convert->picture_width % 8 || convert->picture_height % 8){
- fprintf(stderr,"Output size must be a multiple of 8 for now.\n");
- exit(1);
- }
- /*
- if(convert->picture_width % 4 || convert->picture_height % 4){
- fprintf(stderr,"Output width and height size must be a multiple of 2.\n");
- exit(1);
- }
- */
- if(convert->end_time>0 && convert->end_time <= convert->start_time){
- fprintf(stderr,"End time has to be bigger than start time.\n");
- exit(1);
- }
-
- if (*pidfile_name)
- {
- fpid = fopen(pidfile_name, "w");
- if (fpid != NULL)
- {
- fprintf(fpid, "%i", getpid());
- fclose(fpid);
- }
- }
-
- oggmux_setup_kate_streams(&info, convert->n_kate_streams);
-
- for (n=0; n<convert->n_kate_streams; ++n) {
- ff2theora_kate_stream *ks=convert->kate_streams+n;
- if (load_subtitles(ks)>=0) {
- printf("Muxing Kate stream %d from %s as %s %s\n",
- n,ks->filename,
- ks->subtitles_language[0]?ks->subtitles_language:"<unknown language>",
- ks->subtitles_category[0]?ks->subtitles_category:"subtitles");
- }
- }
-
- if (av_open_input_file(&convert->context, inputfile_name, input_fmt, 0, formatParams) >= 0){
- if (av_find_stream_info (convert->context) >= 0){
-#ifdef WIN32
- if(!strcmp(outputfile_name,"-") || !strcmp(outputfile_name,"/dev/stdout")){
- _setmode(_fileno(stdout), _O_BINARY);
- info.outfile = stdout;
- }
- else {
- info.outfile = fopen(outputfile_name,"wb");
- }
-#else
- if(!strcmp(outputfile_name,"-")){
- snprintf(outputfile_name,sizeof(outputfile_name),"/dev/stdout");
- }
- info.outfile = fopen(outputfile_name,"wb");
-#endif
- if(info.frontend) {
- fprintf(stderr, "\nf2t ;duration: %d;\n", convert->context->duration / AV_TIME_BASE);
- }
- else {
- dump_format (convert->context, 0,inputfile_name, 0);
- }
- if(convert->disable_audio){
- fprintf(stderr," [audio disabled].\n");
- }
- if(convert->sync){
- fprintf(stderr," Use A/V Sync from input container.\n");
- }
-
- convert->pts_offset =
- (double) convert->context->start_time / AV_TIME_BASE;
- if(!info.outfile) {
- if(info.frontend)
- fprintf(stderr, "\nf2t ;result: Unable to open output file.;\n");
- else
- fprintf (stderr,"\nUnable to open output file `%s'.\n", outputfile_name);
- return(1);
- }
- if (convert->context->duration != AV_NOPTS_VALUE) {
- info.duration = convert->context->duration / AV_TIME_BASE;
- }
- ff2theora_output (convert);
- convert->audio_index =convert->video_index = -1;
- }
- else{
- if(info.frontend)
- fprintf(stderr, "\nf2t ;result: input format not suported.;\n");
- else
- fprintf (stderr,"\nUnable to decode input.\n");
- return(1);
- }
- av_close_input_file (convert->context);
- }
- else{
- fprintf (stderr, "\nFile `%s' does not exist or has an unknown data format.\n", inputfile_name);
- return(1);
- }
- ff2theora_close (convert);
- fprintf(stderr,"\n");
-
- if (*pidfile_name)
- unlink(pidfile_name);
-
- if(info.frontend)
- fprintf(stderr, "\nf2t ;result: ok;\n");
-
- return(0);
-}
Modified: trunk/ffmpeg2theora/get_libkate.sh
===================================================================
--- trunk/ffmpeg2theora/get_libkate.sh 2008-05-23 17:55:53 UTC (rev 14949)
+++ trunk/ffmpeg2theora/get_libkate.sh 2008-05-23 17:56:21 UTC (rev 14950)
@@ -6,12 +6,12 @@
which wget >& /dev/null
if [ $? -eq 0 ]
then
- wget "$baseurl"
+ test -e "libkate-$version.tar.gz" || wget "$baseurl"
else
which curl >& /dev/null
if [ $? -eq 0 ]
then
- curl "$baseurl"
+ test -e "libkate-$version.tar.gz" || curl "$baseurl" -o "libkate-$version.tar.gz"
else
echo "Neither wget nor curl were found, cannot download libkate"
exit 1
Copied: trunk/ffmpeg2theora/src/ffmpeg2theora.c (from rev 14949, trunk/ffmpeg2theora/ffmpeg2theora.c)
===================================================================
--- trunk/ffmpeg2theora/src/ffmpeg2theora.c (rev 0)
+++ trunk/ffmpeg2theora/src/ffmpeg2theora.c 2008-05-23 17:56:21 UTC (rev 14950)
@@ -0,0 +1,1769 @@
+/* -*- tab-width:4;c-file-style:"cc-mode"; -*- */
+/*
+ * ffmpeg2theora.c -- Convert ffmpeg supported a/v files to Ogg Theora / Ogg Vorbis
+ * Copyright (C) 2003-2008 <j at v2v.cc>
+ *
+ * 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-1307, USA.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <getopt.h>
+#include <math.h>
+#include <errno.h>
+
+#include "libavformat/avformat.h"
+#include "libavdevice/avdevice.h"
+#include "libswscale/swscale.h"
+#include "libpostproc/postprocess.h"
+
+#include "theora/theora.h"
+#include "vorbis/codec.h"
+#include "vorbis/vorbisenc.h"
+
+#ifdef WIN32
+#include "fcntl.h"
+#endif
+
+#include "theorautils.h"
+#include "subtitles.h"
+#include "ffmpeg2theora.h"
+
+#ifdef __linux__
+ #define VIDEO4LINUX_ENABLED
+#endif
+
+enum {
+ NULL_FLAG,
+ DEINTERLACE_FLAG,
+ OPTIMIZE_FLAG,
+ SYNC_FLAG,
+ NOSOUND_FLAG,
+ CROPTOP_FLAG,
+ CROPBOTTOM_FLAG,
+ CROPRIGHT_FLAG,
+ CROPLEFT_FLAG,
+ ASPECT_FLAG,
+ INPUTFPS_FLAG,
+ AUDIOSTREAM_FLAG,
+ SUBTITLES_FLAG,
+ SUBTITLES_ENCODING_FLAG,
+ SUBTITLES_LANGUAGE_FLAG,
+ SUBTITLES_CATEGORY_FLAG,
+ VHOOK_FLAG,
+ FRONTEND_FLAG,
+ SPEEDLEVEL_FLAG,
+ PP_FLAG,
+ NOSKELETON
+} F2T_FLAGS;
+
+enum {
+ V2V_PRESET_NONE,
+ V2V_PRESET_PRO,
+ V2V_PRESET_PREVIEW,
+ V2V_PRESET_VIDEOBIN,
+ V2V_PRESET_PADMA,
+ V2V_PRESET_PADMASTREAM,
+} F2T_PRESETS;
+
+
+#define PAL_HALF_WIDTH 384
+#define PAL_HALF_HEIGHT 288
+#define NTSC_HALF_WIDTH 320
+#define NTSC_HALF_HEIGHT 240
+
+#define PAL_FULL_WIDTH 720
+#define PAL_FULL_HEIGHT 576
+#define NTSC_FULL_WIDTH 720
+#define NTSC_FULL_HEIGHT 480
+
+
+static int sws_flags = SWS_BICUBIC;
+
+oggmux_info info;
+
+static int using_stdin = 0;
+
+
+/**
+ * Allocate and initialise an AVFrame.
+ */
+AVFrame *frame_alloc (int pix_fmt, int width, int height) {
+ AVFrame *picture;
+ uint8_t *picture_buf;
+ int size;
+
+ picture = avcodec_alloc_frame ();
+ if (!picture)
+ return NULL;
+ size = avpicture_get_size (pix_fmt, width, height);
+ picture_buf = av_malloc (size);
+ if (!picture_buf){
+ av_free (picture);
+ return NULL;
+ }
+ avpicture_fill ((AVPicture *) picture, picture_buf,
+ pix_fmt, width, height);
+ return picture;
+}
+
+/**
+ * initialize ff2theora with default values
+ * @return ff2theora struct
+ */
+ff2theora ff2theora_init (){
+ ff2theora this = calloc (1, sizeof (*this));
+ if (this != NULL){
+ this->disable_audio=0;
+ this->video_index = -1;
+ this->audio_index = -1;
+ this->start_time=0;
+ this->end_time=0; /* 0 denotes no end time set */
+
+ // audio
+ this->sample_rate = -1; // samplerate hmhmhm
+ this->channels = -1;
+ this->audio_quality = 1.00;// audio quality 1
+ this->audio_bitrate=0;
+ this->audiostream = -1;
+
+ // video
+ this->picture_width=0; // set to 0 to not resize the output
+ this->picture_height=0; // set to 0 to not resize the output
+ this->video_quality=rint(5*6.3); // video quality 5
+ this->video_bitrate=0;
+ this->sharpness=0;
+ this->keyint=64;
+ this->force_input_fps=0;
+ this->sync=0;
+ this->aspect_numerator=0;
+ this->aspect_denominator=0;
+ this->frame_aspect=0;
+ this->deinterlace=0; // auto by default, if input is flaged as interlaced it will deinterlace.
+ this->vhook=0;
+ this->framerate_new.num = -1;
+ this->framerate_new.den = 1;
+
+ this->frame_topBand=0;
+ this->frame_bottomBand=0;
+ this->frame_leftBand=0;
+ this->frame_rightBand=0;
+
+ this->n_kate_streams=0;
+ this->kate_streams=NULL;
+
+ this->pix_fmt = PIX_FMT_YUV420P;
+
+ // ffmpeg2theora --nosound -f dv -H 32000 -S 0 -v 8 -x 384 -y 288 -G 1.5 input.dv
+ this->video_gamma = 0.0;
+ this->video_bright = 0.0;
+ this->video_contr = 0.0;
+ this->video_satur = 1.0;
+
+ this->y_lut_used = 0;
+ this->uv_lut_used = 0;
+ this->y_lut[256];
+ this->uv_lut[256];
+ }
+ return this;
+}
+
+// gamma lookup table code
+
+static void y_lut_init(ff2theora this) {
+ int i;
+ double v;
+
+ double c = this->video_contr;
+ double b = this->video_bright;
+ double g = this->video_gamma;
+
+ if ((g < 0.01) || (g > 100.0)) g = 1.0;
+ if ((c < 0.01) || (c > 100.0)) c = 1.0;
+ if ((b < -1.0) || (b > 1.0)) b = 0.0;
+
+ if (g == 1.0 && c == 1.0 && b == 0.0) return;
+ this->y_lut_used = 1;
+
+ printf(" Video correction: gamma=%g, contrast=%g, brightness=%g\n", g, c, b);
+
+ g = 1.0 / g; // larger values shall make brighter video.
+
+ for (i = 0; i < 256; i++) {
+ v = (double) i / 255.0;
+ v = c * v + b * 0.1;
+ if (v < 0.0) v = 0.0;
+ v = pow(v, g) * 255.0; // mplayer's vf_eq2.c multiplies with 256 here, strange...
+
+ if (v >= 255)
+ this->y_lut[i] = 255;
+ else
+ this->y_lut[i] = (unsigned char)(v+0.5);
+ }
+}
+
+
+static void uv_lut_init(ff2theora this) {
+ int i;
+ double v, s;
+ s = this->video_satur;
+
+ if ((s < 0.0) || (s > 100.0)) s = 1.0;
+
+ if (s == 1.0) return;
+ this->uv_lut_used = 1;
+
+ printf(" Color correction: saturation=%g\n", s);
+
+ for (i = 0; i < 256; i++) {
+ v = 127.0 + (s * ((double)i - 127.0));
+ if (v < 0.0) v = 0.0;
+
+ if (v >= 255.0)
+ this->uv_lut[i] = 255;
+ else
+ this->uv_lut[i] = (unsigned char)(v+0.5);
+ }
+}
+
+static void lut_init(ff2theora this) {
+ y_lut_init(this);
+ uv_lut_init(this);
+}
+
+static void lut_apply(unsigned char *lut, unsigned char *src, unsigned char *dst, int width, int height, int stride) {
+ int x, y;
+
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++) {
+ dst[x] = lut[src[x]];
+ }
+ src += stride;
+ dst += stride;
+ }
+}
+
+static void prepare_yuv_buffer(ff2theora this, yuv_buffer *yuv, AVFrame *output_buffered) {
+ /* pysical pages */
+ yuv->y_width = this->frame_width;
+ yuv->y_height = this->frame_height;
+ yuv->y_stride = output_buffered->linesize[0];
+
+ yuv->uv_width = this->frame_width / 2;
+ yuv->uv_height = this->frame_height / 2;
+ yuv->uv_stride = output_buffered->linesize[1];
+
+ yuv->y = output_buffered->data[0];
+ yuv->u = output_buffered->data[1];
+ yuv->v = output_buffered->data[2];
+ if (this->y_lut_used) {
+ lut_apply(this->y_lut, yuv->y, yuv->y, yuv->y_width, yuv->y_height, yuv->y_stride);
+ }
+ if (this->uv_lut_used) {
+ lut_apply(this->uv_lut, yuv->u, yuv->u, yuv->uv_width, yuv->uv_height, yuv->uv_stride);
+ lut_apply(this->uv_lut, yuv->v, yuv->v, yuv->uv_width, yuv->uv_height, yuv->uv_stride);
+ }
+}
+
+void ff2theora_output(ff2theora this) {
+ int i;
+ AVCodecContext *aenc = NULL;
+ AVCodecContext *venc = NULL;
+ AVStream *astream = NULL;
+ AVStream *vstream = NULL;
+ AVCodec *acodec = NULL;
+ AVCodec *vcodec = NULL;
+ pp_mode_t *ppMode = NULL;
+ pp_context_t *ppContext = NULL;
+ float frame_aspect;
+ double fps = 0.0;
+
+ if(this->audiostream >= 0 && this->context->nb_streams > this->audiostream) {
+ AVCodecContext *enc = this->context->streams[this->audiostream]->codec;
+ if (enc->codec_type == CODEC_TYPE_AUDIO) {
+ this->audio_index = this->audiostream;
+ fprintf(stderr," Using stream #0.%d as audio input\n",this->audio_index);
+ }
+ else {
+ fprintf(stderr," The selected stream is not audio, falling back to automatic selection\n");
+ }
+ }
+
+ for (i = 0; i < this->context->nb_streams; i++){
+ AVCodecContext *enc = this->context->streams[i]->codec;
+ switch (enc->codec_type){
+ case CODEC_TYPE_VIDEO:
+ if (this->video_index < 0)
+ this->video_index = i;
+ break;
+ case CODEC_TYPE_AUDIO:
+ if (this->audio_index < 0 && !this->disable_audio)
+ this->audio_index = i;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (this->video_index >= 0){
+ vstream = this->context->streams[this->video_index];
+ venc = this->context->streams[this->video_index]->codec;
+ vcodec = avcodec_find_decoder (venc->codec_id);
+
+ fps = (double) vstream->r_frame_rate.num / vstream->r_frame_rate.den;
+ if (fps > 10000)
+ fps /= 1000;
+
+ if(this->force_input_fps)
+ fps=this->force_input_fps;
+ if (vcodec == NULL || avcodec_open (venc, vcodec) < 0) {
+ this->video_index = -1;
+ }
+ this->fps = fps;
+
+
+ if(this->preset == V2V_PRESET_PREVIEW){
+ if(abs(this->fps-30)<1 && (venc->width!=NTSC_HALF_WIDTH || venc->height!=NTSC_HALF_HEIGHT) ){
+ this->picture_width=NTSC_HALF_WIDTH;
+ this->picture_height=NTSC_HALF_HEIGHT;
+ }
+ else {
+ this->picture_width=PAL_HALF_WIDTH;
+ this->picture_height=PAL_HALF_HEIGHT;
+ }
+ }
+ else if(this->preset == V2V_PRESET_PRO){
+ if(abs(this->fps-30)<1 && (venc->width!=NTSC_FULL_WIDTH || venc->height!=NTSC_FULL_HEIGHT) ){
+ this->picture_width=NTSC_FULL_WIDTH;
+ this->picture_height=NTSC_FULL_HEIGHT;
+ }
+ else {
+ this->picture_width=PAL_FULL_WIDTH;
+ this->picture_height=PAL_FULL_HEIGHT;
+ }
+ }
+ else if(this->preset == V2V_PRESET_PADMA){
+ int width=venc->width-this->frame_leftBand-this->frame_rightBand;
+ int height=venc->height-this->frame_topBand-this->frame_bottomBand;
+ if(venc->sample_aspect_ratio.den!=0 && venc->sample_aspect_ratio.num!=0) {
+ height=((float)venc->sample_aspect_ratio.den/venc->sample_aspect_ratio.num) * height;
+ }
+ if(this->frame_aspect == 0)
+ this->frame_aspect = (float)width/height;
+ if(this->frame_aspect <= 1.5) {
+ if(width > 640 || height > 480) {
+ //4:3 640 x 480
+ this->picture_width=640;
+ this->picture_height=480;
+ }
+ else {
+ this->picture_width=width;
+ this->picture_height=height;
+ }
+ }
+ else {
+ if(width > 640 || height > 360) {
+ //16:9 640 x 360
+ this->picture_width=640;
+ this->picture_height=360;
+ }
+ else {
+ this->picture_width=width;
+ this->picture_height=height;
+ }
+ }
+
+ }
+ else if(this->preset == V2V_PRESET_PADMASTREAM){
+ int width=venc->width-this->frame_leftBand-this->frame_rightBand;
+ int height=venc->height-this->frame_topBand-this->frame_bottomBand;
+ if(venc->sample_aspect_ratio.den!=0 && venc->sample_aspect_ratio.num!=0) {
+ height=((float)venc->sample_aspect_ratio.den/venc->sample_aspect_ratio.num) * height;
+ }
+ if(this->frame_aspect == 0)
+ this->frame_aspect = (float)width/height;
+ if(this->frame_aspect <= 1.5) {
+ this->picture_width=128;
+ this->picture_height=96;
+ }
+ else {
+ this->picture_width=128;
+ this->picture_height=72;
+ }
+ }
+ else if(this->preset == V2V_PRESET_VIDEOBIN){
+ int width=venc->width-this->frame_leftBand-this->frame_rightBand;
+ int height=venc->height-this->frame_topBand-this->frame_bottomBand;
+ if(venc->sample_aspect_ratio.den!=0 && venc->sample_aspect_ratio.num!=0) {
+ height=((float)venc->sample_aspect_ratio.den/venc->sample_aspect_ratio.num) * height;
+ }
+ if( ((float)width /height) <= 1.5) {
+ if(width > 448) {
+ //4:3 448 x 336
+ this->picture_width=448;
+ this->picture_height=336;
+ }
+ else {
+ this->picture_width=width;
+ this->picture_height=height;
+ }
+ }
+ else {
+ if(width > 512) {
+ //16:9 512 x 288
+ this->picture_width=512;
+ this->picture_height=288;
+ }
+ else {
+ this->picture_width=width;
+ this->picture_height=height;
+ }
+ }
+
+ }
+ if(this->picture_height==0 &&
+ (this->frame_leftBand || this->frame_rightBand || this->frame_topBand || this->frame_bottomBand) ){
+ this->picture_height=venc->height-
+ this->frame_topBand-this->frame_bottomBand;
+ }
+ if(this->picture_width==0 &&
+ (this->frame_leftBand || this->frame_rightBand || this->frame_topBand || this->frame_bottomBand) ){
+ this->picture_width=venc->width-
+ this->frame_leftBand-this->frame_rightBand;
+ }
+ //so frame_aspect is set on the commandline
+ if(this->frame_aspect != 0){
+ if(this->picture_height){
+ this->aspect_numerator = 10000*this->frame_aspect*this->picture_height;
+ this->aspect_denominator = 10000*this->picture_width;
+ }
+ else{
+ this->aspect_numerator = 10000*this->frame_aspect*venc->height;
+ this->aspect_denominator = 10000*venc->width;
+ }
+ av_reduce(&this->aspect_numerator,&this->aspect_denominator,this->aspect_numerator,this->aspect_denominator,10000);
+ frame_aspect=this->frame_aspect;
+ }
+ if(venc->sample_aspect_ratio.num!=0 && this->frame_aspect==0){
+ // just use the ratio from the input
+ this->aspect_numerator=venc->sample_aspect_ratio.num;
+ this->aspect_denominator=venc->sample_aspect_ratio.den;
+ // or we use ratio for the output
+ if(this->picture_height){
+ int width=venc->width-this->frame_leftBand-this->frame_rightBand;
+ int height=venc->height-this->frame_topBand-this->frame_bottomBand;
+ av_reduce(&this->aspect_numerator,&this->aspect_denominator,
+ venc->sample_aspect_ratio.num*width*this->picture_height,
+ venc->sample_aspect_ratio.den*height*this->picture_width,10000);
+ frame_aspect=(float)(this->aspect_numerator*this->picture_width)/
+ (this->aspect_denominator*this->picture_height);
+ }
+ else{
+ frame_aspect=(float)(this->aspect_numerator*venc->width)/
+ (this->aspect_denominator*venc->height);
+ }
+ }
+ if((float)this->aspect_numerator/this->aspect_denominator < 1.09){
+ this->aspect_numerator = 1;
+ this->aspect_denominator = 1;
+ frame_aspect=(float)(this->aspect_numerator*this->picture_width)/
+ (this->aspect_denominator*this->picture_height);
+ }
+ if(this->aspect_denominator && frame_aspect){
+ fprintf(stderr," Pixel Aspect Ratio: %.2f/1 ",(float)this->aspect_numerator/this->aspect_denominator);
+ fprintf(stderr," Frame Aspect Ratio: %.2f/1\n",frame_aspect);
+ }
+
+ if (this->deinterlace==1)
+ fprintf(stderr," Deinterlace: on\n");
+
+ if (strcmp(this->pp_mode, "")) {
+ ppContext = pp_get_context(venc->width, venc->height, PP_FORMAT_420);
+ ppMode = pp_get_mode_by_name_and_quality(this->pp_mode, PP_QUALITY_MAX);
+ fprintf(stderr," Postprocessing: %s\n", this->pp_mode);
+ }
+
+ if(!this->picture_width)
+ this->picture_width = venc->width;
+ if(!this->picture_height)
+ this->picture_height = venc->height;
+
+ /* Theora has a divisible-by-sixteen restriction for the encoded video size */
+ /* scale the frame size up to the nearest /16 and calculate offsets */
+ this->frame_width = ((this->picture_width + 15) >>4)<<4;
+ this->frame_height = ((this->picture_height + 15) >>4)<<4;
+
+ this->frame_x_offset = 0;
+ this->frame_y_offset = 0;
+
+ if(this->frame_width > 0 || this->frame_height > 0){
+ this->sws_colorspace_ctx = sws_getContext(
+ venc->width, venc->height, venc->pix_fmt,
+ venc->width, venc->height, this->pix_fmt,
+ sws_flags, NULL, NULL, NULL
+ );
+ this->sws_scale_ctx = sws_getContext(
+ venc->width - (this->frame_leftBand + this->frame_rightBand),
+ venc->height - (this->frame_topBand + this->frame_bottomBand),
+ this->pix_fmt,
+ this->frame_width, this->frame_height, this->pix_fmt,
+ sws_flags, NULL, NULL, NULL
+ );
+ fprintf(stderr," Resize: %dx%d",venc->width,venc->height);
+ if(this->frame_topBand || this->frame_bottomBand ||
+ this->frame_leftBand || this->frame_rightBand){
+ fprintf(stderr," => %dx%d",
+ venc->width-this->frame_leftBand-this->frame_rightBand,
+ venc->height-this->frame_topBand-this->frame_bottomBand);
+ }
+ if(this->picture_width != (venc->width-this->frame_leftBand - this->frame_rightBand)
+ || this->picture_height != (venc->height-this->frame_topBand-this->frame_bottomBand))
+ fprintf(stderr," => %dx%d",this->picture_width, this->picture_height);
+ fprintf(stderr,"\n");
+ }
+
+ lut_init(this);
+ }
+ if (this->framerate_new.num > 0) {
+ fprintf(stderr," Resample Framerate: %0.2f => %0.2f\n",
+ this->fps,(double)this->framerate_new.num / this->framerate_new.den);
+ }
+ if (this->audio_index >= 0){
+ astream = this->context->streams[this->audio_index];
+ aenc = this->context->streams[this->audio_index]->codec;
+ acodec = avcodec_find_decoder (aenc->codec_id);
+ if (this->channels < 1) {
+ if (aenc->channels > 2)
+ this->channels = 2;
+ else
+ this->channels = aenc->channels;
+ }
+ if(this->sample_rate==-1) {
+ this->sample_rate = aenc->sample_rate;
+ }
+ if (this->channels != aenc->channels && aenc->codec_id == CODEC_ID_AC3)
+ aenc->channels = this->channels;
+
+ if (acodec != NULL && avcodec_open (aenc, acodec) >= 0){
+ if(this->sample_rate != aenc->sample_rate || this->channels != aenc->channels){
+ this->audio_resample_ctx = audio_resample_init (this->channels,aenc->channels,this->sample_rate,aenc->sample_rate);
+ if(this->sample_rate!=aenc->sample_rate)
+ fprintf(stderr," Resample: %dHz => %dHz\n",aenc->sample_rate,this->sample_rate);
+ if(this->channels!=aenc->channels)
+ fprintf(stderr," Channels: %d => %d\n",aenc->channels,this->channels);
+ }
+ else{
+ this->audio_resample_ctx=NULL;
+ }
+ }
+ else{
+ this->audio_index = -1;
+ }
+ }
+
+ if (this->video_index >= 0 || this->audio_index >=0){
+ AVFrame *frame=NULL;
+ AVFrame *output=NULL;
+ AVFrame *output_tmp=NULL;
+ AVFrame *output_resized=NULL;
+ AVFrame *output_buffered=NULL;
+
+ AVPacket pkt;
+ int len;
+ int len1;
+ int got_picture;
+ int first = 1;
+ int e_o_s = 0;
+ int ret;
+ uint8_t *ptr;
+ int16_t *audio_buf= av_malloc(4*AVCODEC_MAX_AUDIO_FRAME_SIZE);
+ int16_t *resampled= av_malloc(4*AVCODEC_MAX_AUDIO_FRAME_SIZE);
+ int no_frames;
+
+ double framerate_add;
+ double framerate_tmpcount = 0;
+
+ if(this->video_index >= 0)
+ info.audio_only=0;
+ else
+ info.audio_only=1;
+
+ if(this->audio_index>=0)
+ info.video_only=0;
+ else
+ info.video_only=1;
+
+ if(!info.audio_only){
+ frame = frame_alloc(vstream->codec->pix_fmt,
+ vstream->codec->width,vstream->codec->height);
+ output_tmp =frame_alloc(this->pix_fmt,
+ vstream->codec->width,vstream->codec->height);
+ output =frame_alloc(this->pix_fmt,
+ vstream->codec->width,vstream->codec->height);
+ output_resized =frame_alloc(this->pix_fmt,
+ this->frame_width, this->frame_height);
+ output_buffered =frame_alloc(this->pix_fmt,
+ this->frame_width, this->frame_height);
+
+ /* video settings here */
+ /* config file? commandline options? v2v presets? */
+
+ theora_info_init (&info.ti);
+
+ info.ti.width = this->frame_width;
+ info.ti.height = this->frame_height;
+ info.ti.frame_width = this->picture_width;
+ info.ti.frame_height = this->picture_height;
+ info.ti.offset_x = this->frame_x_offset;
+ info.ti.offset_y = this->frame_y_offset;
+ if(this->force_input_fps) {
+ info.ti.fps_numerator = 1000000 * (this->fps); /* fps= numerator/denominator */
+ info.ti.fps_denominator = 1000000;
+ }
+ else {
+ if (this->framerate_new.num > 0) {
+ // new framerate is interger only right now,
+ // so denominator is always 1
+ info.ti.fps_numerator = this->framerate_new.num;
+ info.ti.fps_denominator = this->framerate_new.den;
+ }
+ else {
+ info.ti.fps_numerator=vstream->r_frame_rate.num;
+ info.ti.fps_denominator = vstream->r_frame_rate.den;
+ }
+ }
+
+ /* this is pixel aspect ratio */
+ info.ti.aspect_numerator=this->aspect_numerator;
+ info.ti.aspect_denominator=this->aspect_denominator;
+ // FIXME: is all input material with fps==25 OC_CS_ITU_REC_470BG?
+ // guess not, commandline option to select colorspace would be the best.
+ if((this->fps-25)<1)
+ info.ti.colorspace = OC_CS_ITU_REC_470BG;
+ else if(abs(this->fps-30)<1)
+ info.ti.colorspace = OC_CS_ITU_REC_470M;
+ else
+ info.ti.colorspace = OC_CS_UNSPECIFIED;
+
+ info.ti.target_bitrate = this->video_bitrate;
+ info.ti.quality = this->video_quality;
+ info.ti.dropframes_p = 0;
+ info.ti.keyframe_auto_p = 1;
+ info.ti.keyframe_frequency = this->keyint;
+ info.ti.keyframe_frequency_force = this->keyint;
+ info.ti.keyframe_data_target_bitrate = info.ti.target_bitrate * 1.5;
+ info.ti.keyframe_auto_threshold = 80;
+ info.ti.keyframe_mindistance = 8;
+ info.ti.noise_sensitivity = 1;
+ // range 0-2, 0 sharp, 2 less sharp,less bandwidth
+ info.ti.sharpness = this->sharpness;
+
+ }
+ /* audio settings here */
+ info.channels = this->channels;
+ info.sample_rate = this->sample_rate;
+ info.vorbis_quality = this->audio_quality * 0.1;
+ info.vorbis_bitrate = this->audio_bitrate;
+ /* subtitles */
+#ifdef HAVE_KATE
+ for (i=0; i<this->n_kate_streams; ++i) {
+ ff2theora_kate_stream *ks = this->kate_streams+i;
+ kate_info *ki = &info.kate_streams[i].ki;
+ kate_info_init(ki);
+ if (ks->num_subtitles > 0) {
+ kate_info_set_language(ki, ks->subtitles_language);
+ kate_info_set_category(ki, ks->subtitles_category[0]?ks->subtitles_category:"subtitles");
+ if(this->force_input_fps) {
+ ki->gps_numerator = 1000000 * (this->fps); /* fps= numerator/denominator */
+ ki->gps_denominator = 1000000;
+ }
+ else {
+ if (this->framerate_new.num > 0) {
+ // new framerate is interger only right now,
+ // so denominator is always 1
+ ki->gps_numerator = this->framerate_new.num;
+ ki->gps_denominator = this->framerate_new.den;
+ }
+ else {
+ ki->gps_numerator=vstream->r_frame_rate.num;
+ ki->gps_denominator = vstream->r_frame_rate.den;
+ }
+ }
+ ki->granule_shift = 32;
+ }
+ }
+#endif
+ oggmux_init (&info);
+ /*seek to start time*/
+ if(this->start_time) {
+ av_seek_frame( this->context, -1, (int64_t)AV_TIME_BASE*this->start_time, 1);
+ /* discard subtitles by their end time, so we still have those that start before the start time,
+ but end after it */
+ for (i=0; i<this->n_kate_streams; ++i) {
+ ff2theora_kate_stream *ks=this->kate_streams+i;
+ while (ks->subtitles_count < ks->num_subtitles && ks->subtitles[ks->subtitles_count].t1 <= this->start_time) {
+ /* printf("skipping subtitle %u\n", ks->subtitles_count); */
+ ks->subtitles_count++;
+ }
+ }
+ }
+
+ if(info.audio_only && (this->end_time>0 || this->start_time>0)){
+ fprintf(stderr,"Sorry, right now start/end time does not work for audio only files.\n");
+ exit(1);
+ }
+
+ if (this->framerate_new.num > 0) {
+ double framerate_new = (double)this->framerate_new.num / this->framerate_new.den;
+ framerate_add = framerate_new/this->fps;
+ //fprintf(stderr,"calculating framerate addition to %f\n",framerate_add);
+ this->fps = framerate_new;
+ }
+
+ /*check for end time and calculate number of frames to encode*/
+ no_frames = this->fps*(this->end_time - this->start_time);
+ if(this->end_time > 0 && no_frames <= 0){
+ fprintf(stderr,"End time has to be bigger than start time.\n");
+ exit(1);
+ }
+ /* main decoding loop */
+ do{
+ if(no_frames > 0){
+ if(this->frame_count > no_frames){
+ break;
+ }
+ }
+ ret = av_read_frame(this->context,&pkt);
+ if(ret<0){
+ e_o_s=1;
+ }
+
+ ptr = pkt.data;
+ len = pkt.size;
+ if (e_o_s && !info.audio_only || (ret >= 0 && pkt.stream_index == this->video_index)){
+ if(len == 0 && !first && !e_o_s){
+ fprintf (stderr, "no frame available\n");
+ }
+ while(e_o_s || len > 0){
+ int dups = 0;
+ yuv_buffer yuv;
+ len1 = avcodec_decode_video(vstream->codec, frame, &got_picture, ptr, len);
+ if(len1>=0) {
+ if(got_picture){
+ // this is disabled by default since it does not work
+ // for all input formats the way it should.
+ if(this->sync == 1) {
+ double delta = ((double) pkt.dts /
+ AV_TIME_BASE - this->pts_offset) *
+ this->fps - this->frame_count;
+ /* 0.7 is an arbitrary value */
+ /* it should be larger than half a frame to
+ avoid excessive dropping and duplicating */
+ if (delta < -0.7) {
+#ifdef DEBUG
+ fprintf(stderr,
+ "Frame dropped to maintain sync\n");
+#endif
+ break;
+ }
+ if (delta > 0.7) {
+ //dups = lrintf(delta);
+ dups = (int)delta;
+#ifdef DEBUG
+ fprintf(stderr,
+ "%d duplicate %s added to maintain sync\n",
+ dups, (dups == 1) ? "frame" : "frames");
+#endif
+ }
+ }
+
+ if (this->framerate_new.num > 0) {
+ framerate_tmpcount += framerate_add;
+ if (framerate_tmpcount < (double)(this->frame_count+1)) {
+ got_picture = 0;
+ }
+ else {
+ dups = 0;
+ while (framerate_tmpcount >= (double)(this->frame_count+2+dups)) {
+ dups += 1;
+ }
+ }
+ }
+
+ //For audio only files command line option"-e" will not work
+ //as we don't increment frame_count in audio section.
+
+ if(venc->pix_fmt != this->pix_fmt) {
+ sws_scale(this->sws_colorspace_ctx,
+ frame->data, frame->linesize, 0, venc->height,
+ output_tmp->data, output_tmp->linesize);
+
+ }
+ else{
+ output_tmp = frame;
+ }
+ if(frame->interlaced_frame || this->deinterlace){
+ if(avpicture_deinterlace((AVPicture *)output,(AVPicture *)output_tmp,this->pix_fmt,venc->width,venc->height)<0){
+ fprintf(stderr,"Deinterlace failed.\n");
+ exit(1);
+ }
+ }
+ else{
+ output=output_tmp;
+ }
+ // now output
+ if(ppMode)
+ pp_postprocess(output->data, output->linesize,
+ output->data, output->linesize,
+ venc->width, venc->height,
+ output->qscale_table, output->qstride,
+ ppMode, ppContext, this->pix_fmt);
+ if(this->vhook)
+ frame_hook_process((AVPicture *)output, this->pix_fmt, venc->width,venc->height);
+
+ if (this->frame_topBand || this->frame_leftBand) {
+ if (av_picture_crop((AVPicture *)output_tmp, (AVPicture *)output,
+ this->pix_fmt, this->frame_topBand, this->frame_leftBand) < 0) {
+ av_log(NULL, AV_LOG_ERROR, "error cropping picture\n");
+ }
+ output = output_tmp;
+ }
+ if(this->sws_scale_ctx){
+ sws_scale(this->sws_scale_ctx,
+ output->data, output->linesize, 0, venc->height - (this->frame_topBand + this->frame_bottomBand),
+ output_resized->data, output_resized->linesize);
+ }
+ else{
+ output_resized=output;
+ }
+
+ }
+ ptr += len1;
+ len -= len1;
+ }
+ //now output_resized
+
+ if(!first) {
+ if(got_picture || e_o_s) {
+ prepare_yuv_buffer(this, &yuv, output_buffered);
+ do {
+ oggmux_add_video(&info, &yuv, e_o_s);
+ this->frame_count++;
+ } while(dups--);
+ }
+ }
+ if(got_picture) {
+ first=0;
+ av_picture_copy ((AVPicture *)output_buffered, (AVPicture *)output_resized, this->pix_fmt, this->frame_width, this->frame_height);
+ }
+ if(!got_picture){
+ break;
+ }
+ }
+
+ }
+ if(e_o_s && !info.video_only
+ || (ret >= 0 && pkt.stream_index == this->audio_index)){
+ this->pts_offset = (double) pkt.pts / AV_TIME_BASE -
+ (double) this->sample_count / this->sample_rate;
+ while(e_o_s || len > 0 ){
+ int samples=0;
+ int samples_out=0;
+ int data_size = 4*AVCODEC_MAX_AUDIO_FRAME_SIZE;
+ if(len > 0){
+ len1 = avcodec_decode_audio2(astream->codec, audio_buf, &data_size, ptr, len);
+ if (len1 < 0){
+ /* if error, we skip the frame */
+ break;
+ }
+ len -= len1;
+ ptr += len1;
+ if(data_size >0){
+ samples =data_size / (aenc->channels * 2);
+
+ samples_out = samples;
+ if(this->audio_resample_ctx){
+ samples_out = audio_resample(this->audio_resample_ctx, resampled, audio_buf, samples);
+ }
+ else
+ resampled=audio_buf;
+ }
+ }
+ oggmux_add_audio(&info, resampled,
+ samples_out *(this->channels),samples_out,e_o_s);
+ this->sample_count += samples_out;
+ if(e_o_s && len <= 0){
+ break;
+ }
+ }
+
+ }
+
+ /* if we have subtitles starting before then, add it */
+ if (info.with_kate) {
+ double avtime = info.audio_only ? info.audiotime :
+ info.video_only ? info.videotime :
+ info.audiotime < info.videotime ? info.audiotime : info.videotime;
+ for (i=0; i<this->n_kate_streams; ++i) {
+ ff2theora_kate_stream *ks = this->kate_streams+i;
+ if (ks->num_subtitles > 0) {
+ ff2theora_subtitle *sub = ks->subtitles+ks->subtitles_count;
+ /* we encode a bit in advance so we're sure to hit the time, the packet will
+ be held till the right time. If we don't do that, we can insert late and
+ oggz-validate moans */
+ while (ks->subtitles_count < ks->num_subtitles && sub->t0-1.0 <= avtime+this->start_time) {
+ int eos = (ks->subtitles_count == ks->num_subtitles-1);
+ oggmux_add_kate_text(&info, i, sub->t0, sub->t1, sub->text, sub->len, eos);
+ ks->subtitles_count++;
+ ++sub;
+ }
+ }
+ }
+ }
+
+ /* flush out the file */
+ oggmux_flush (&info, e_o_s);
+ av_free_packet (&pkt);
+ }
+ while (ret >= 0);
+
+ for (i=0; i<this->n_kate_streams; ++i) {
+ ff2theora_kate_stream *ks = this->kate_streams+i;
+ if (ks->num_subtitles > 0 && ks->subtitles_count<ks->num_subtitles) {
+ double t = (info.videotime<info.audiotime?info.audiotime:info.videotime)+this->start_time;
+ oggmux_add_kate_end_packet(&info, i, t);
+ oggmux_flush (&info, e_o_s);
+ }
+ }
+
+ oggmux_close (&info);
+ if(ppContext)
+ pp_free_context(ppContext);
+ }
+ else{
+ fprintf (stderr, "No video or audio stream found.\n");
+ }
+}
+
+void ff2theora_close (ff2theora this){
+ /* clear out state */
+ free_subtitles(this);
+ av_free (this);
+}
+
+double aspect_check(const char *arg)
+{
+ int x = 0, y = 0;
+ double ar = 0;
+ const char *p;
+
+ p = strchr(arg, ':');
+ if (!p) {
+ p = strchr(arg, '/');
+ }
+ if (p) {
+ x = strtol(arg, (char **)&arg, 10);
+ if (arg == p)
+ y = strtol(arg+1, (char **)&arg, 10);
+ if (x > 0 && y > 0)
+ ar = (double)x / (double)y;
+ } else
+ ar = strtod(arg, (char **)&arg);
+
+ if (!ar) {
+ fprintf(stderr, "Incorrect aspect ratio specification.\n");
+ exit(1);
+ }
+ return ar;
+}
+
+static void add_frame_hooker(const char *arg)
+{
+ int argc = 0;
+ char *argv[64];
+ int i;
+ char *args = av_strdup(arg);
+
+ argv[0] = strtok(args, " ");
+ while (argc < 62 && (argv[++argc] = strtok(NULL, " "))) {
+ }
+
+ i = frame_hook_add(argc, argv);
+ if (i != 0) {
+ fprintf(stderr, "Failed to add video hook function: %s\n", arg);
+ exit(1);
+ }
+}
+
+AVRational get_framerate(const char* arg)
+{
+ const char *p;
+ AVRational framerate;
+
+ p = strchr(arg, ':');
+ if (!p) {
+ p = strchr(arg, '/');
+ }
+ if (p) {
+ framerate.num = strtol(arg, (char **)&arg, 10);
+ if (arg == p)
+ framerate.den = strtol(arg+1, (char **)&arg, 10);
+ if(framerate.num <= 0)
+ framerate.num = -1;
+ if(framerate.den <= 0)
+ framerate.den = 1;
+ } else {
+ framerate.num = strtol(arg, (char **)&arg,10);
+ framerate.den = 1;
+ }
+ return(framerate);
+}
+
+int crop_check(ff2theora this, char *name, const char *arg)
+{
+ int crop_value = atoi(arg);
+ if (crop_value < 0) {
+ fprintf(stderr, "Incorrect crop size `%s'.\n",name);
+ exit(1);
+ }
+ if ((crop_value % 2) != 0) {
+ fprintf(stderr, "Crop size `%s' must be a multiple of 2.\n",name);
+ exit(1);
+ }
+ /*
+ if ((crop_value) >= this->height){
+ fprintf(stderr, "Vertical crop dimensions are outside the range of the original image.\nRemember to crop first and scale second.\n");
+ exit(1);
+ }
+ */
+ return crop_value;
+}
+
+
+
+void print_presets_info() {
+ fprintf (stdout,
+ // "v2v presets - more info at http://wiki.v2v.cc/presets"
+ "v2v presets:\n"
+ " preview Video: 320x240 if fps ~ 30, 384x288 otherwise\n"
+ " Quality 5 - Sharpness 2\n"
+ " Audio: Max 2 channels - Quality 1\n"
+ "\n"
+ " pro Video: 720x480 if fps ~ 30, 720x576 otherwise\n"
+ " Quality 7 - Sharpness 0\n"
+ " Audio: Max 2 channels - Quality 3\n"
+ "\n"
+ " videobin Video: 512x288 for 16:9 material, 448x336 for 4:3 material\n"
+ " Bitrate 600kbs\n"
+ " Audio: Max 2 channels - Quality 3\n"
+ "\n"
+ " padma Video: 640x360 for 16:9 material, 640x480 for 4:3 material\n"
+ " Quality 5 - Sharpness 0\n"
+ " Audio: Max 2 channels - Quality 3\n"
+ "\n"
+ " padma-stream Video: 128x72 for 16:9 material, 128x96 for 4:3 material\n"
+ " Audio: mono quality -1\n"
+ "\n"
+ );
+}
+
+void print_usage (){
+ fprintf (stdout,
+ PACKAGE " " PACKAGE_VERSION "\n"
+ "\n"
+ " Usage: " PACKAGE " [options] input\n"
+ "\n"
+ "General output options:\n"
+ " -o, --output alternative output filename\n"
+ " --no-skeleton disables ogg skeleton metadata output\n"
+ " -s, --starttime start encoding at this time (in sec.)\n"
+ " -e, --endtime end encoding at this time (in sec.)\n"
+ " -p, --v2v-preset encode file with v2v preset.\n"
+ " Right now there is preview, pro and videobin. Run\n"
+ " '"PACKAGE" -p info' for more informations\n"
+ "\n"
+ "Video output options:\n"
+ " -v, --videoquality [0 to 10] encoding quality for video (default: 5)\n"
+ " use higher values for better quality\n"
+ " -V, --videobitrate [1 to 16778] encoding bitrate for video (kb/s)\n"
+ " --optimize optimize video output filesize (slower) (same as speedlevel 0)\n"
+ " --speedlevel [0 2] encoding is faster with higher values the cost is quality and bandwidth\n"
+ " -x, --width scale to given width (in pixels)\n"
+ " -y, --height scale to given height (in pixels)\n"
+ " --aspect define frame aspect ratio: i.e. 4:3 or 16:9\n"
+ " -F, --framerate output framerate e.g 25:2 or 16\n"
+ " --croptop, --cropbottom, --cropleft, --cropright\n"
+ " crop input by given pixels before resizing\n"
+ " -S, --sharpness [0 to 2] sharpness of images (default: 0).\n"
+ " Note: lower values make the video sharper.\n"
+ " -K, --keyint [1 to 65536] keyframe interval (default: 64)\n"
+ "\n"
+ "Video transfer options:\n"
+ " --pp Video Postprocessing, denoise, deblock, deinterlacer\n"
+ " use --pp help for a list of available filters.\n"
+ " -C, --contrast [0.1 to 10.0] contrast correction (default: 1.0)\n"
+ " Note: lower values make the video darker.\n"
+ " -B, --brightness [-1.0 to 1.0] brightness correction (default: 0.0)\n"
+ " Note: lower values make the video darker.\n"
+ " -G, --gamma [0.1 to 10.0] gamma correction (default: 1.0)\n"
+ " Note: lower values make the video darker.\n"
+ " -Z, --saturation [0.1 to 10.0] saturation correction (default: 1.0)\n"
+ " Note: lower values make the video grey.\n"
+ "\n"
+ "Audio output options:\n"
+ " -a, --audioquality [-2 to 10] encoding quality for audio (default: 1)\n"
+ " use higher values for better quality\n"
+ " -A, --audiobitrate [32 to 500] encoding bitrate for audio (kb/s)\n"
+ " -c, --channels set number of output channels\n"
+ " -H, --samplerate set output samplerate (in Hz)\n"
+ " --nosound disable the sound from input\n"
+ "\n"
+ "Input options:\n"
+ " --deinterlace force deinterlace, otherwise only material\n"
+ " marked as interlaced will be deinterlaced\n"
+ " --vhook you can use ffmpeg's vhook system, example:\n"
+ " ffmpeg2theora --vhook '/path/watermark.so -f wm.gif' input.dv\n"
+ " -f, --format specify input format\n"
+ " --inputfps fps override input fps\n"
+ " --audiostream id by default the last audio stream is selected,\n"
+ " use this to select another audio stream\n"
+ " --sync use A/V sync from input container. Since this does\n"
+ " not work with all input format you have to manually\n"
+ " enable it if you have issues with A/V sync\n"
+ "\n"
+#ifdef HAVE_KATE
+ "Subtitles options:\n"
+ " --subtitles file use subtitles from the given file (SubRip (.srt) format)\n"
+ " --subtitles-encoding encoding set encoding of the subtitles file\n"
+ " supported are " SUPPORTED_ENCODINGS "\n"
+ " --subtitles-language language set subtitles language (de, en_GB, etc)\n"
+ " --subtitles-category category set subtitles category (default \"subtitles\")\n"
+ "\n"
+#endif
+ "Metadata options:\n"
+ " --artist Name of artist (director)\n"
+ " --title Title\n"
+ " --date Date\n"
+ " --location Location\n"
+ " --organization Name of organization (studio)\n"
+ " --copyright Copyright\n"
+ " --license License\n"
+ " --contact Contact link\n"
+ "\n"
+ "Other options:\n"
+#ifndef _WIN32
+ " --nice n set niceness to n\n"
+#endif
+ " -P, --pid fname write the process' id to a file\n"
+ " -h, --help this message\n"
+ "\n"
+ "Examples:\n"
+ " ffmpeg2theora videoclip.avi (will write output to videoclip.ogv)\n"
+ "\n"
+ " ffmpeg2theora videoclip.avi --subtitles subtitles.srt (same, with subtitles)\n"
+ "\n"
+ " cat something.dv | ffmpeg2theora -f dv -o output.ogv -\n"
+ "\n"
+ " Encode a series of images:\n"
+ " ffmpeg2theora -f image2 frame%%06d.png -o output.ogv\n"
+ "\n"
+#if 0
+ " Live streaming from V4L Device:\n"
+ " ffmpeg2theora /dev/video0 -fps 15 -x 160 -y 128 -o - \\\n"
+ " | oggfwd iccast2server 8000 password /theora.ogv\n"
+ "\n"
+#endif
+ " Live encoding from a DV camcorder (needs a fast machine):\n"
+ " dvgrab - | ffmpeg2theora -f dv -x 352 -y 288 -o output.ogv -\n"
+ "\n"
+ " Live encoding and streaming to icecast server:\n"
+ " dvgrab --format raw - \\\n"
+ " | ffmpeg2theora -f dv -x 160 -y 128 -o /dev/stdout - \\\n"
+ " | oggfwd iccast2server 8000 password /theora.ogv\n"
+ "\n"
+ );
+ exit (0);
+}
+
+int main (int argc, char **argv){
+ int n;
+ int outputfile_set=0;
+ char outputfile_name[255];
+ char inputfile_name[255];
+ char *str_ptr;
+
+ static int flag = -1;
+ static int metadata_flag = 0;
+
+ AVInputFormat *input_fmt = NULL;
+ AVFormatParameters *formatParams = NULL;
+
+ int c,long_option_index;
+ const char *optstring = "P:o:k:f:F:x:y:v:V:a:A:S:K:d:H:c:G:Z:C:B:p:N:s:e:D:h::";
+ struct option options [] = {
+ {"pid",required_argument,NULL, 'P'},
+ {"output",required_argument,NULL,'o'},
+ {"skeleton",no_argument,NULL,'k'},
+ {"no-skeleton",no_argument,&flag,NOSKELETON},
+ {"format",required_argument,NULL,'f'},
+ {"width",required_argument,NULL,'x'},
+ {"height",required_argument,NULL,'y'},
+ {"videoquality",required_argument,NULL,'v'},
+ {"videobitrate",required_argument,NULL,'V'},
+ {"audioquality",required_argument,NULL,'a'},
+ {"audiobitrate",required_argument,NULL,'A'},
+ {"sharpness",required_argument,NULL,'S'},
+ {"keyint",required_argument,NULL,'K'},
+ {"deinterlace",0,&flag,DEINTERLACE_FLAG},
+ {"pp",required_argument,&flag,PP_FLAG},
+ {"samplerate",required_argument,NULL,'H'},
+ {"channels",required_argument,NULL,'c'},
+ {"gamma",required_argument,NULL,'G'},
+ {"brightness",required_argument,NULL,'B'},
+ {"contrast",required_argument,NULL,'C'},
+ {"saturation",required_argument,NULL,'Z'},
+ {"nosound",0,&flag,NOSOUND_FLAG},
+ {"vhook",required_argument,&flag,VHOOK_FLAG},
+ {"framerate",required_argument,NULL,'F'},
+ {"aspect",required_argument,&flag,ASPECT_FLAG},
+ {"v2v-preset",required_argument,NULL,'p'},
+ {"nice",required_argument,NULL,'N'},
+ {"croptop",required_argument,&flag,CROPTOP_FLAG},
+ {"cropbottom",required_argument,&flag,CROPBOTTOM_FLAG},
+ {"cropright",required_argument,&flag,CROPRIGHT_FLAG},
+ {"cropleft",required_argument,&flag,CROPLEFT_FLAG},
+ {"inputfps",required_argument,&flag,INPUTFPS_FLAG},
+ {"audiostream",required_argument,&flag,AUDIOSTREAM_FLAG},
+ {"subtitles",required_argument,&flag,SUBTITLES_FLAG},
+ {"subtitles-encoding",required_argument,&flag,SUBTITLES_ENCODING_FLAG},
+ {"subtitles-language",required_argument,&flag,SUBTITLES_LANGUAGE_FLAG},
+ {"subtitles-category",required_argument,&flag,SUBTITLES_CATEGORY_FLAG},
+ {"starttime",required_argument,NULL,'s'},
+ {"endtime",required_argument,NULL,'e'},
+ {"sync",0,&flag,SYNC_FLAG},
+ {"optimize",0,&flag,OPTIMIZE_FLAG},
+ {"speedlevel",required_argument,&flag,SPEEDLEVEL_FLAG},
+ {"frontend",0,&flag,FRONTEND_FLAG},
+
+ {"artist",required_argument,&metadata_flag,10},
+ {"title",required_argument,&metadata_flag,11},
+ {"date",required_argument,&metadata_flag,12},
+ {"location",required_argument,&metadata_flag,13},
+ {"organization",required_argument,&metadata_flag,14},
+ {"copyright",required_argument,&metadata_flag,15},
+ {"license",required_argument,&metadata_flag,16},
+ {"contact",required_argument,&metadata_flag,17},
+ {"source-hash",required_argument,&metadata_flag,18},
+
+ {"help",0,NULL,'h'},
+ {NULL,0,NULL,0}
+ };
+
+ char pidfile_name[255] = { '\0' };
+ FILE *fpid = NULL;
+
+ ff2theora convert = ff2theora_init ();
+ avcodec_register_all();
+ avdevice_register_all();
+ av_register_all();
+
+ if (argc == 1){
+ print_usage ();
+ }
+ // set some variables;
+ init_info(&info);
+ theora_comment_init (&info.tc);
+
+ while((c=getopt_long(argc,argv,optstring,options,&long_option_index))!=EOF){
+ switch(c)
+ {
+ case 0:
+ if (flag) {
+ switch (flag)
+ {
+ case DEINTERLACE_FLAG:
+ convert->deinterlace = 1;
+ flag = -1;
+ break;
+ case PP_FLAG:
+ if(!strcmp(optarg, "help")) {
+ fprintf(stdout, pp_help);
+ exit(1);
+ }
+ snprintf(convert->pp_mode,sizeof(convert->pp_mode),"%s",optarg);
+ flag = -1;
+ break;
+ case VHOOK_FLAG:
+ convert->vhook = 1;
+ add_frame_hooker(optarg);
+ flag = -1;
+ break;
+
+ case SYNC_FLAG:
+ convert->sync = 1;
+ flag = -1;
+ break;
+ case NOSOUND_FLAG:
+ convert->disable_audio = 1;
+ flag = -1;
+ break;
+ case OPTIMIZE_FLAG:
+ info.speed_level = 0;
+ flag = -1;
+ break;
+ case SPEEDLEVEL_FLAG:
+ info.speed_level = atoi(optarg);
+ flag = -1;
+ break;
+ case FRONTEND_FLAG:
+ info.frontend = 1;
+ flag = -1;
+ break;
+ /* crop */
+ case CROPTOP_FLAG:
+ convert->frame_topBand = crop_check(convert,"top",optarg);
+ flag = -1;
+ break;
+ case CROPBOTTOM_FLAG:
+ convert->frame_bottomBand = crop_check(convert,"bottom",optarg);
+ flag = -1;
+ break;
+ case CROPRIGHT_FLAG:
+ convert->frame_rightBand = crop_check(convert,"right",optarg);
+ flag = -1;
+ break;
+ case CROPLEFT_FLAG:
+ convert->frame_leftBand = crop_check(convert,"left",optarg);
+ flag = -1;
+ break;
+ case ASPECT_FLAG:
+ convert->frame_aspect = aspect_check(optarg);
+ flag = -1;
+ break;
+ case INPUTFPS_FLAG:
+ convert->force_input_fps = atof(optarg);
+ flag = -1;
+ break;
+ case AUDIOSTREAM_FLAG:
+ convert->audiostream = atoi(optarg);
+ flag = -1;
+ break;
+ case NOSKELETON:
+ info.with_skeleton=0;
+ break;
+#ifdef HAVE_KATE
+ case SUBTITLES_FLAG:
+ set_subtitles_file(convert,optarg);
+ flag = -1;
+ info.with_kate=1;
+ break;
+ case SUBTITLES_ENCODING_FLAG:
+ if (!strcmp(optarg,"utf-8")) set_subtitles_encoding(convert,ENC_UTF8);
+ if (!strcmp(optarg,"utf8")) set_subtitles_encoding(convert,ENC_UTF8);
+ else if (!strcmp(optarg,"iso-8859-1")) set_subtitles_encoding(convert,ENC_ISO_8859_1);
+ else if (!strcmp(optarg,"latin1")) set_subtitles_encoding(convert,ENC_ISO_8859_1);
+ else report_unknown_subtitle_encoding(optarg);
+ flag = -1;
+ break;
+ case SUBTITLES_LANGUAGE_FLAG:
+ if (strlen(optarg)>15) {
+ fprintf(stderr, "WARNING - language is limited to 15 characters, and will be truncated\n");
+ }
+ set_subtitles_language(convert,optarg);
+ flag = -1;
+ break;
+ case SUBTITLES_CATEGORY_FLAG:
+ if (strlen(optarg)>15) {
+ fprintf(stderr, "WARNING - category is limited to 15 characters, and will be truncated\n");
+ }
+ set_subtitles_category(convert,optarg);
+ flag = -1;
+ break;
+#else
+ case SUBTITLES_FLAG:
+ case SUBTITLES_ENCODING_FLAG:
+ case SUBTITLES_LANGUAGE_FLAG:
+ case SUBTITLES_CATEGORY_FLAG:
+ fprintf(stderr, "WARNING - Kate support not compiled in, subtitles will not be output\n"
+ " - install libkate and rebuild ffmpeg2theora for subtitle support\n");
+ break;
+#endif
+ }
+ }
+
+ /* metadata */
+ if (metadata_flag){
+ switch(metadata_flag) {
+ case 10:
+ theora_comment_add_tag(&info.tc, "ARTIST", optarg);
+ break;
+ case 11:
+ theora_comment_add_tag(&info.tc, "TITLE", optarg);
+ break;
+ case 12:
+ theora_comment_add_tag(&info.tc, "DATE", optarg);
+ break;
+ case 13:
+ theora_comment_add_tag(&info.tc, "LOCATION", optarg);
+ break;
+ case 14:
+ theora_comment_add_tag(&info.tc, "ORGANIZATION", optarg);
+ break;
+ case 15:
+ theora_comment_add_tag(&info.tc, "COPYRIGHT", optarg);
+ break;
+ case 16:
+ theora_comment_add_tag(&info.tc, "LICENSE", optarg);
+ break;
+ case 17:
+ theora_comment_add_tag(&info.tc, "CONTACT", optarg);
+ break;
+ case 18:
+ theora_comment_add_tag(&info.tc, "SOURCE HASH", optarg);
+ break;
+ }
+ metadata_flag=0;
+ }
+ break;
+ case 'e':
+ convert->end_time = atoi(optarg);
+ break;
+ case 's':
+ convert->start_time = atoi(optarg);
+ break;
+ case 'o':
+ snprintf(outputfile_name,sizeof(outputfile_name),"%s",optarg);
+ outputfile_set=1;
+ break;
+ case 'k':
+ info.with_skeleton=1;
+ break;
+ case 'P':
+ sprintf(pidfile_name,optarg);
+ break;
+ case 'f':
+ input_fmt=av_find_input_format(optarg);
+ break;
+ case 'x':
+ convert->picture_width=atoi(optarg);
+ break;
+ case 'y':
+ convert->picture_height=atoi(optarg);
+ break;
+ case 'v':
+ convert->video_quality = rint(atof(optarg)*6.3);
+ if(convert->video_quality <0 || convert->video_quality >63){
+ fprintf(stderr,"Only values from 0 to 10 are valid for video quality.\n");
+ exit(1);
+ }
+ convert->video_bitrate=0;
+ break;
+ case 'V':
+ convert->video_bitrate=rint(atof(optarg)*1000);
+ if (convert->video_bitrate < 1) {
+ fprintf(stderr, "Only values from 1 to 16000 are valid for video bitrate (in kb/s).\n");
+ exit(1);
+ }
+ convert->video_quality=0;
+ break;
+ case 'a':
+ convert->audio_quality=atof(optarg);
+ if(convert->audio_quality<-2 || convert->audio_quality>10){
+ fprintf(stderr,"Only values from -2 to 10 are valid for audio quality.\n");
+ exit(1);
+ }
+ convert->audio_bitrate=0;
+ break;
+ case 'A':
+ convert->audio_bitrate=atof(optarg)*1000;
+ if(convert->audio_bitrate<0){
+ fprintf(stderr,"Only values >0 are valid for audio bitrate.\n");
+ exit(1);
+ }
+ convert->audio_quality = -990;
+ break;
+ case 'G':
+ convert->video_gamma = atof(optarg);
+ break;
+ case 'C':
+ convert->video_contr = atof(optarg);
+ break;
+ case 'Z':
+ convert->video_satur = atof(optarg);
+ break;
+ case 'B':
+ convert->video_bright = atof(optarg);
+ break;
+ case 'S':
+ convert->sharpness = atoi(optarg);
+ if (convert->sharpness < 0 || convert->sharpness > 2) {
+ fprintf (stderr, "Only values from 0 to 2 are valid for sharpness.\n");
+ exit(1);
+ }
+ break;
+ case 'K':
+ convert->keyint = atoi(optarg);
+ if (convert->keyint < 1 || convert->keyint > 65536) {
+ fprintf (stderr, "Only values from 1 to 65536 are valid for keyframe interval.\n");
+ exit(1);
+ }
+ break;
+ case 'H':
+ convert->sample_rate=atoi(optarg);
+ break;
+ case 'F':
+ convert->framerate_new = get_framerate(optarg);
+ break;
+ case 'c':
+ convert->channels=atoi(optarg);
+ if(convert->channels <= 0) {
+ fprintf (stderr, "You can not have less than one audio channel.\n");
+ exit(1);
+ }
+ break;
+ case 'p':
+ //v2v presets
+ if(!strcmp(optarg, "info")){
+ print_presets_info();
+ exit(1);
+ }
+ else if(!strcmp(optarg, "pro")){
+ //need a way to set resize here. and not later
+ convert->preset=V2V_PRESET_PRO;
+ convert->video_quality = rint(7*6.3);
+ convert->audio_quality = 3.00;
+ convert->sharpness = 0;
+ info.speed_level = 0;
+ }
+ else if(!strcmp(optarg,"preview")){
+ //need a way to set resize here. and not later
+ convert->preset=V2V_PRESET_PREVIEW;
+ convert->video_quality = rint(5*6.3);
+ convert->audio_quality = 1.00;
+ convert->sharpness = 2;
+ info.speed_level = 0;
+ }
+ else if(!strcmp(optarg,"videobin")){
+ convert->preset=V2V_PRESET_VIDEOBIN;
+ convert->video_bitrate=rint(600*1000);
+ convert->video_quality = 0;
+ convert->audio_quality = 3.00;
+ convert->sharpness = 2;
+ info.speed_level = 0;
+ }
+ else if(!strcmp(optarg,"padma")){
+ convert->preset=V2V_PRESET_PADMA;
+ convert->video_quality = rint(5*6.3);
+ convert->audio_quality = 3.00;
+ convert->sharpness = 0;
+ info.speed_level = 0;
+ }
+ else if(!strcmp(optarg,"padma-stream")){
+ convert->preset=V2V_PRESET_PADMASTREAM;
+ convert->video_bitrate=rint(180*1000);
+ convert->video_quality = 0;
+ convert->audio_quality = -1.00;
+ convert->sample_rate=44100;
+ convert->sharpness = 2;
+ convert->keyint = 16;
+ info.speed_level = 0;
+ }
+ else{
+ fprintf(stderr,"\nUnknown preset.\n\n");
+ print_presets_info();
+ exit(1);
+ }
+ break;
+ case 'N':
+ n = atoi(optarg);
+ if (n) {
+#ifndef _WIN32
+ if (nice(n)<0) {
+ fprintf(stderr,"Error setting `%d' for niceness.", n);
+ }
+#endif
+ }
+ break;
+ case 'h':
+ print_usage ();
+ exit(1);
+ }
+ }
+
+ while(optind<argc){
+ /* assume that anything following the options must be a filename */
+ snprintf(inputfile_name,sizeof(inputfile_name),"%s",argv[optind]);
+ if(!strcmp(inputfile_name,"-")){
+ snprintf(inputfile_name,sizeof(inputfile_name),"pipe:");
+ }
+ if(outputfile_set!=1){
+ /* reserve 4 bytes in the buffer for the `.ogv' extension */
+ snprintf(outputfile_name, sizeof(outputfile_name) - 4, "%s", argv[optind]);
+ if((str_ptr = strrchr(outputfile_name, '.'))) {
+ sprintf(str_ptr, ".ogv");
+ if(!strcmp(inputfile_name, outputfile_name)){
+ snprintf(outputfile_name, sizeof(outputfile_name), "%s.ogv", inputfile_name);
+ }
+ }
+ else {
+ snprintf(outputfile_name, sizeof(outputfile_name), "%s.ogv", outputfile_name);
+ }
+ outputfile_set=1;
+ }
+ optind++;
+ }
+
+#ifdef VIDEO4LINUX_ENABLED
+ if(formatParams != NULL) {
+ formatParams->channel = 0;
+ formatParams->width = PAL_HALF_WIDTH;
+ formatParams->height = PAL_HALF_HEIGHT;
+ if(convert->picture_width)
+ formatParams->width = convert->picture_width;
+ if(convert->picture_height)
+ formatParams->height = convert->picture_height;
+
+ formatParams->time_base.den = 25;
+ formatParams->time_base.num = 1;
+ if(convert->force_input_fps) {
+
+ formatParams->time_base.den = convert->force_input_fps * 1000;
+ formatParams->time_base.num = 1000;
+
+ }
+ formatParams->standard = "pal";
+ input_fmt = av_find_input_format("video4linux");
+ sprintf(inputfile_name,"");
+ }
+#endif
+
+ //FIXME: is using_stdin still neded? is it needed as global variable?
+ using_stdin |= !strcmp(inputfile_name, "pipe:" ) ||
+ !strcmp( inputfile_name, "/dev/stdin" );
+
+ if(outputfile_set!=1){
+ fprintf(stderr,"You have to specify an output file with -o output.ogv.\n");
+ exit(1);
+ }
+
+ /* could go, but so far no player supports offset_x/y */
+ if(convert->picture_width % 8 || convert->picture_height % 8){
+ fprintf(stderr,"Output size must be a multiple of 8 for now.\n");
+ exit(1);
+ }
+ /*
+ if(convert->picture_width % 4 || convert->picture_height % 4){
+ fprintf(stderr,"Output width and height size must be a multiple of 2.\n");
+ exit(1);
+ }
+ */
+ if(convert->end_time>0 && convert->end_time <= convert->start_time){
+ fprintf(stderr,"End time has to be bigger than start time.\n");
+ exit(1);
+ }
+
+ if (*pidfile_name)
+ {
+ fpid = fopen(pidfile_name, "w");
+ if (fpid != NULL)
+ {
+ fprintf(fpid, "%i", getpid());
+ fclose(fpid);
+ }
+ }
+
+ oggmux_setup_kate_streams(&info, convert->n_kate_streams);
+
+ for (n=0; n<convert->n_kate_streams; ++n) {
+ ff2theora_kate_stream *ks=convert->kate_streams+n;
+ if (load_subtitles(ks)>=0) {
+ printf("Muxing Kate stream %d from %s as %s %s\n",
+ n,ks->filename,
+ ks->subtitles_language[0]?ks->subtitles_language:"<unknown language>",
+ ks->subtitles_category[0]?ks->subtitles_category:"subtitles");
+ }
+ }
+
+ if (av_open_input_file(&convert->context, inputfile_name, input_fmt, 0, formatParams) >= 0){
+ if (av_find_stream_info (convert->context) >= 0){
+#ifdef WIN32
+ if(!strcmp(outputfile_name,"-") || !strcmp(outputfile_name,"/dev/stdout")){
+ _setmode(_fileno(stdout), _O_BINARY);
+ info.outfile = stdout;
+ }
+ else {
+ info.outfile = fopen(outputfile_name,"wb");
+ }
+#else
+ if(!strcmp(outputfile_name,"-")){
+ snprintf(outputfile_name,sizeof(outputfile_name),"/dev/stdout");
+ }
+ info.outfile = fopen(outputfile_name,"wb");
+#endif
+ if(info.frontend) {
+ fprintf(stderr, "\nf2t ;duration: %d;\n", convert->context->duration / AV_TIME_BASE);
+ }
+ else {
+ dump_format (convert->context, 0,inputfile_name, 0);
+ }
+ if(convert->disable_audio){
+ fprintf(stderr," [audio disabled].\n");
+ }
+ if(convert->sync){
+ fprintf(stderr," Use A/V Sync from input container.\n");
+ }
+
+ convert->pts_offset =
+ (double) convert->context->start_time / AV_TIME_BASE;
+ if(!info.outfile) {
+ if(info.frontend)
+ fprintf(stderr, "\nf2t ;result: Unable to open output file.;\n");
+ else
+ fprintf (stderr,"\nUnable to open output file `%s'.\n", outputfile_name);
+ return(1);
+ }
+ if (convert->context->duration != AV_NOPTS_VALUE) {
+ info.duration = convert->context->duration / AV_TIME_BASE;
+ }
+ ff2theora_output (convert);
+ convert->audio_index =convert->video_index = -1;
+ }
+ else{
+ if(info.frontend)
+ fprintf(stderr, "\nf2t ;result: input format not suported.;\n");
+ else
+ fprintf (stderr,"\nUnable to decode input.\n");
+ return(1);
+ }
+ av_close_input_file (convert->context);
+ }
+ else{
+ fprintf (stderr, "\nFile `%s' does not exist or has an unknown data format.\n", inputfile_name);
+ return(1);
+ }
+ ff2theora_close (convert);
+ fprintf(stderr,"\n");
+
+ if (*pidfile_name)
+ unlink(pidfile_name);
+
+ if(info.frontend)
+ fprintf(stderr, "\nf2t ;result: ok;\n");
+
+ return(0);
+}
Added: trunk/ffmpeg2theora/src/ffmpeg2theora.h
===================================================================
--- trunk/ffmpeg2theora/src/ffmpeg2theora.h (rev 0)
+++ trunk/ffmpeg2theora/src/ffmpeg2theora.h 2008-05-23 17:56:21 UTC (rev 14950)
@@ -0,0 +1,101 @@
+#ifndef _F2T_FFMPEG2THEORA_H_
+#define _F2T_FFMPEG2THEORA_H_
+
+#include "subtitles.h"
+
+typedef enum {
+ ENC_UNSET,
+ ENC_UTF8,
+ ENC_ISO_8859_1,
+} F2T_ENCODING;
+
+
+typedef struct ff2theora_subtitle{
+ char *text;
+ size_t len;
+ double t0;
+ double t1;
+} ff2theora_subtitle;
+
+typedef struct ff2theora_kate_stream{
+ const char *filename;
+ size_t num_subtitles;
+ ff2theora_subtitle *subtitles;
+ size_t subtitles_count; /* total subtitles output so far */
+ F2T_ENCODING subtitles_encoding;
+ char subtitles_language[16];
+ char subtitles_category[16];
+} ff2theora_kate_stream;
+
+typedef struct ff2theora{
+ AVFormatContext *context;
+ int video_index;
+ int audio_index;
+
+ int deinterlace;
+ int vhook;
+ int audiostream;
+ int sample_rate;
+ int channels;
+ int disable_audio;
+ float audio_quality;
+ int audio_bitrate;
+ int preset;
+
+ int picture_width;
+ int picture_height;
+ double fps;
+ struct SwsContext *sws_colorspace_ctx; /* for image resampling/resizing */
+ struct SwsContext *sws_scale_ctx; /* for image resampling/resizing */
+ ReSampleContext *audio_resample_ctx;
+ ogg_int32_t aspect_numerator;
+ ogg_int32_t aspect_denominator;
+ double frame_aspect;
+
+ int pix_fmt;
+ int video_quality;
+ int video_bitrate;
+ int sharpness;
+ int keyint;
+ char pp_mode[255];
+
+ double force_input_fps;
+ int sync;
+
+ /* cropping */
+ int frame_topBand;
+ int frame_bottomBand;
+ int frame_leftBand;
+ int frame_rightBand;
+
+ int frame_width;
+ int frame_height;
+ int frame_x_offset;
+ int frame_y_offset;
+
+ /* In seconds */
+ int start_time;
+ int end_time;
+
+ AVRational framerate_new;
+
+ double pts_offset; /* between given input pts and calculated output pts */
+ int64_t frame_count; /* total video frames output so far */
+ int64_t sample_count; /* total audio samples output so far */
+
+ size_t n_kate_streams;
+ ff2theora_kate_stream *kate_streams;
+
+ // ffmpeg2theora --nosound -f dv -H 32000 -S 0 -v 8 -x 384 -y 288 -G 1.5 input.dv
+ double video_gamma;
+ double video_bright;
+ double video_contr;
+ double video_satur;
+ int y_lut_used;
+ int uv_lut_used;
+ unsigned char y_lut[256];
+ unsigned char uv_lut[256];
+}
+*ff2theora;
+
+#endif
Copied: trunk/ffmpeg2theora/src/subtitles.c (from rev 14949, trunk/ffmpeg2theora/subtitles.c)
===================================================================
--- trunk/ffmpeg2theora/src/subtitles.c (rev 0)
+++ trunk/ffmpeg2theora/src/subtitles.c 2008-05-23 17:56:21 UTC (rev 14950)
@@ -0,0 +1,293 @@
+/* -*- tab-width:4;c-file-style:"cc-mode"; -*- */
+/*
+ * subtitles.c -- Kate Subtitles
+ * Copyright (C) 2007-2008 <j at v2v.cc>
+ *
+ * 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-1307, USA.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <getopt.h>
+#include <math.h>
+#include <errno.h>
+
+#include "libavformat/avformat.h"
+
+#ifdef WIN32
+#include "fcntl.h"
+#endif
+
+#include "theorautils.h"
+#include "subtitles.h"
+
+
+/**
+ * adds a new kate stream structure
+ */
+static void add_kate_stream(ff2theora this){
+ ff2theora_kate_stream *ks;
+ this->kate_streams=(ff2theora_kate_stream*)realloc(this->kate_streams,(this->n_kate_streams+1)*sizeof(ff2theora_kate_stream));
+ ks=&this->kate_streams[this->n_kate_streams++];
+ ks->filename = NULL;
+ ks->num_subtitles = 0;
+ ks->subtitles = 0;
+ ks->subtitles_count = 0; /* denotes not set yet */
+ ks->subtitles_encoding = ENC_UNSET;
+ strcpy(ks->subtitles_language, "");
+ strcpy(ks->subtitles_category, "");
+}
+
+/*
+ * sets the filename of the next subtitles file
+ */
+void set_subtitles_file(ff2theora this,const char *filename){
+ size_t n;
+ for (n=0; n<this->n_kate_streams;++n) {
+ if (!this->kate_streams[n].filename) break;
+ }
+ if (n==this->n_kate_streams) add_kate_stream(this);
+ this->kate_streams[n].filename = filename;
+}
+
+/*
+ * sets the language of the next subtitles file
+ */
+void set_subtitles_language(ff2theora this,const char *language){
+ size_t n;
+ for (n=0; n<this->n_kate_streams;++n) {
+ if (!this->kate_streams[n].subtitles_language[0]) break;
+ }
+ if (n==this->n_kate_streams) add_kate_stream(this);
+ strncpy(this->kate_streams[n].subtitles_language, language, 16);
+ this->kate_streams[n].subtitles_language[15] = 0;
+}
+
+/*
+ * sets the category of the next subtitles file
+ */
+void set_subtitles_category(ff2theora this,const char *category){
+ size_t n;
+ for (n=0; n<this->n_kate_streams;++n) {
+ if (!this->kate_streams[n].subtitles_category[0]) break;
+ }
+ if (n==this->n_kate_streams) add_kate_stream(this);
+ strncpy(this->kate_streams[n].subtitles_category, category, 16);
+ this->kate_streams[n].subtitles_category[15] = 0;
+}
+
+/**
+ * sets the encoding of the next subtitles file
+ */
+void set_subtitles_encoding(ff2theora this,F2T_ENCODING encoding){
+ size_t n;
+ for (n=0; n<this->n_kate_streams;++n) {
+ if (this->kate_streams[n].subtitles_encoding==ENC_UNSET) break;
+ }
+ if (n==this->n_kate_streams) add_kate_stream(this);
+ this->kate_streams[n].subtitles_encoding = encoding;
+}
+
+
+void report_unknown_subtitle_encoding(const char *name)
+{
+ fprintf(stderr, "Unknown character encoding: %s\n",name);
+ fprintf(stderr, "Valid character encodings are:\n");
+ fprintf(stderr, " " SUPPORTED_ENCODINGS "\n");
+}
+
+static char *fgets2(char *s,size_t sz,FILE *f)
+{
+ char *ret = fgets(s, sz, f);
+ /* fixup DOS newline character */
+ char *ptr=strchr(s, '\r');
+ if (ptr) *ptr='\n';
+ return ret;
+}
+
+static double hmsms2s(int h,int m,int s,int ms)
+{
+ return h*3600+m*60+s+ms/1000.0;
+}
+
+/* very simple implementation when no iconv */
+static void convert_subtitle_to_utf8(F2T_ENCODING encoding,unsigned char *text)
+{
+ size_t nbytes;
+ unsigned char *ptr,*newtext;
+
+ if (!text || !*text) return;
+
+ switch (encoding) {
+ case ENC_UNSET:
+ /* we don't know what encoding this is, assume utf-8 and we'll yell if it ain't */
+ break;
+ case ENC_UTF8:
+ /* nothing to do, already in utf-8 */
+ break;
+ case ENC_ISO_8859_1:
+ /* simple, characters above 0x7f are broken in two,
+ and code points map to the iso-8859-1 8 bit codes */
+ nbytes=0;
+ for (ptr=text;*ptr;++ptr) {
+ nbytes++;
+ if (0x80&*ptr) nbytes++;
+ }
+ newtext=(unsigned char*)malloc(1+nbytes);
+ if (!newtext) {
+ fprintf(stderr, "Memory allocation failed - cannot convert text\n");
+ return;
+ }
+ nbytes=0;
+ for (ptr=text;*ptr;++ptr) {
+ if (0x80&*ptr) {
+ newtext[nbytes++]=0xc0|((*ptr)>>6);
+ newtext[nbytes++]=0x80|((*ptr)&0x3f);
+ }
+ else {
+ newtext[nbytes++]=*ptr;
+ }
+ }
+ newtext[nbytes++]=0;
+ memcpy(text,newtext,nbytes);
+ free(newtext);
+ break;
+ default:
+ fprintf(stderr, "ERROR: encoding %d not handled in conversion!\n", encoding);
+ break;
+ }
+}
+
+int load_subtitles(ff2theora_kate_stream *this)
+{
+#ifdef HAVE_KATE
+ enum { need_id, need_timing, need_text };
+ int need = need_id;
+ int last_seen_id=0;
+ int ret;
+ int id;
+ static char text[4096];
+ int h0,m0,s0,ms0,h1,m1,s1,ms1;
+ double t0,t1;
+ static char str[4096];
+ int warned=0;
+
+ FILE *f = fopen(this->filename, "r");
+ if (!f) {
+ fprintf(stderr,"WARNING - Failed to open subtitles file %s (%s)\n", this->filename, strerror(errno));
+ return -1;
+ }
+
+ /* first, check for a BOM */
+ ret=fread(str,1,3,f);
+ if (ret<3 || memcmp(str,"\xef\xbb\xbf",3)) {
+ /* No BOM, rewind */
+ fseek(f,0,SEEK_SET);
+ }
+
+ fgets2(str,sizeof(str),f);
+ while (!feof(f)) {
+ switch (need) {
+ case need_id:
+ ret=sscanf(str,"%d\n",&id);
+ if (ret!=1) {
+ fprintf(stderr,"WARNING - Syntax error: %s\n",str);
+ fclose(f);
+ return -1;
+ }
+ if (id!=last_seen_id+1) {
+ fprintf(stderr,"WARNING - non consecutive ids: %s - pretending not to have noticed\n",str);
+ }
+ last_seen_id=id;
+ need=need_timing;
+ strcpy(text,"");
+ break;
+ case need_timing:
+ ret=sscanf(str,"%d:%d:%d%*[.,]%d --> %d:%d:%d%*[.,]%d\n",&h0,&m0,&s0,&ms0,&h1,&m1,&s1,&ms1);
+ if (ret!=8) {
+ fprintf(stderr,"WARNING - Syntax error: %s\n",str);
+ fclose(f);
+ return -1;
+ }
+ else {
+ t0=hmsms2s(h0,m0,s0,ms0);
+ t1=hmsms2s(h1,m1,s1,ms1);
+ }
+ need=need_text;
+ break;
+ case need_text:
+ if (*str=='\n') {
+ convert_subtitle_to_utf8(this->subtitles_encoding,(unsigned char*)text);
+ size_t len = strlen(text);
+ this->subtitles = (ff2theora_subtitle*)realloc(this->subtitles, (this->num_subtitles+1)*sizeof(ff2theora_subtitle));
+ if (!this->subtitles) {
+ fprintf(stderr, "Out of memory\n");
+ fclose(f);
+ return -1;
+ }
+ ret=kate_text_validate(kate_utf8,text,len+1);
+ if (ret<0) {
+ if (!warned) {
+ fprintf(stderr,"WARNING: subtitle %s is not valid utf-8\n",text);
+ fprintf(stderr," further invalid subtitles will NOT be flagged\n");
+ warned=1;
+ }
+ }
+ else {
+ /* kill off trailing \n characters */
+ while (len>0) {
+ if (text[len-1]=='\n') text[--len]=0; else break;
+ }
+ this->subtitles[this->num_subtitles].text = (char*)malloc(len+1);
+ memcpy(this->subtitles[this->num_subtitles].text, text, len+1);
+ this->subtitles[this->num_subtitles].len = len;
+ this->subtitles[this->num_subtitles].t0 = t0;
+ this->subtitles[this->num_subtitles].t1 = t1;
+ this->num_subtitles++;
+ }
+ need=need_id;
+ }
+ else {
+ strcat(text,str);
+ }
+ break;
+ }
+ fgets2(str,sizeof(str),f);
+ }
+
+ fclose(f);
+
+ /* fprintf(stderr," %u subtitles loaded.\n", this->num_subtitles); */
+
+ return this->num_subtitles;
+#else
+ return 0;
+#endif
+}
+
+void free_subtitles(ff2theora this)
+{
+ size_t i,n;
+ for (i=0; i<this->n_kate_streams; ++i) {
+ ff2theora_kate_stream *ks=this->kate_streams+i;
+ for (n=0; n<ks->num_subtitles; ++n) free(ks->subtitles[n].text);
+ free(ks->subtitles);
+ }
+ free(this->kate_streams);
+}
+
Copied: trunk/ffmpeg2theora/src/subtitles.h (from rev 14949, trunk/ffmpeg2theora/subtitles.h)
===================================================================
--- trunk/ffmpeg2theora/src/subtitles.h (rev 0)
+++ trunk/ffmpeg2theora/src/subtitles.h 2008-05-23 17:56:21 UTC (rev 14950)
@@ -0,0 +1,32 @@
+#ifndef _F2T_SUBTITLES_H_
+#define _F2T_SUBTITLES_H_
+
+#ifdef HAVE_KATE
+#include "kate/kate.h"
+#endif
+#include "ffmpeg2theora.h"
+
+#ifndef __GNUC__
+/* Windows doesn't have strcasecmp but stricmp (at least, DOS had)
+ (or was that strcmpi ? Might have been Borland C) */
+#define strcasecmp(s1, s2) stricmp(s1, s2)
+#endif
+
+
+#define SUPPORTED_ENCODINGS "utf-8, utf8, iso-8859-1, latin1"
+
+static void add_kate_stream(ff2theora this);
+extern int load_subtitles(ff2theora_kate_stream *this);
+extern void free_subtitles(ff2theora this);
+
+extern void set_subtitles_file(ff2theora this,const char *filename);
+extern void set_subtitles_language(ff2theora this,const char *language);
+extern void set_subtitles_category(ff2theora this,const char *category);
+extern void set_subtitles_encoding(ff2theora this,F2T_ENCODING encoding);
+extern void report_unknown_subtitle_encoding(const char *name);
+
+static char *fgets2(char *s,size_t sz,FILE *f);
+static double hmsms2s(int h,int m,int s,int ms);
+static void convert_subtitle_to_utf8(F2T_ENCODING encoding,unsigned char *text);
+#endif
+
Copied: trunk/ffmpeg2theora/src/theorautils.c (from rev 14949, trunk/ffmpeg2theora/theorautils.c)
===================================================================
--- trunk/ffmpeg2theora/src/theorautils.c (rev 0)
+++ trunk/ffmpeg2theora/src/theorautils.c 2008-05-23 17:56:21 UTC (rev 14950)
@@ -0,0 +1,924 @@
+/* -*- tab-width:4;c-file-style:"cc-mode"; -*- */
+/*
+ * theorautils.c - Ogg Theora/Ogg Vorbis Abstraction and Muxing
+ * Copyright (C) 2003-2008 <j at v2v.cc>
+ *
+ * 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-1307, USA.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <time.h>
+
+#include "theora/theora.h"
+#include "vorbis/codec.h"
+#include "vorbis/vorbisenc.h"
+#ifdef HAVE_OGGKATE
+#include "kate/oggkate.h"
+#endif
+
+#include "theorautils.h"
+
+
+
+static double rint(double x)
+{
+ if (x < 0.0)
+ return (double)(int)(x - 0.5);
+ else
+ return (double)(int)(x + 0.5);
+}
+
+void init_info(oggmux_info *info) {
+ info->with_skeleton = 1; /* skeleton is enabled by default */
+ info->frontend = 0; /*frontend mode*/
+ info->videotime = 0;
+ info->audiotime = 0;
+ info->audio_bytesout = 0;
+ info->video_bytesout = 0;
+ info->kate_bytesout = 0;
+
+ info->videopage_valid = 0;
+ info->audiopage_valid = 0;
+ info->audiopage_buffer_length = 0;
+ info->videopage_buffer_length = 0;
+ info->audiopage = NULL;
+ info->videopage = NULL;
+ info->start_time = time(NULL);
+ info->duration = -1;
+ info->speed_level = -1;
+
+ info->v_pkg=0;
+ info->a_pkg=0;
+ info->k_pkg=0;
+#ifdef OGGMUX_DEBUG
+ info->a_page=0;
+ info->v_page=0;
+ info->k_page=0;
+#endif
+
+ info->with_kate = 0;
+ info->n_kate_streams = 0;
+}
+
+void oggmux_setup_kate_streams(oggmux_info *info, int n_kate_streams)
+{
+ int n;
+
+ info->n_kate_streams = n_kate_streams;
+ if (n_kate_streams == 0) return;
+ info->kate_streams = (oggmux_kate_stream*)malloc(n_kate_streams*sizeof(oggmux_kate_stream));
+ for (n=0; n<n_kate_streams; ++n) {
+ oggmux_kate_stream *ks=info->kate_streams+n;
+ ks->katepage_valid = 0;
+ ks->katepage_buffer_length = 0;
+ ks->katepage = NULL;
+ ks->katetime = 0;
+ }
+}
+
+static void write16le(unsigned char *ptr,ogg_uint16_t v)
+{
+ ptr[0]=v&0xff;
+ ptr[1]=(v>>8)&0xff;
+}
+
+static void write32le(unsigned char *ptr,ogg_uint32_t v)
+{
+ ptr[0]=v&0xff;
+ ptr[1]=(v>>8)&0xff;
+ ptr[2]=(v>>16)&0xff;
+ ptr[3]=(v>>24)&0xff;
+}
+
+static void write64le(unsigned char *ptr,ogg_int64_t v)
+{
+ ogg_uint32_t hi=v>>32;
+ ptr[0]=v&0xff;
+ ptr[1]=(v>>8)&0xff;
+ ptr[2]=(v>>16)&0xff;
+ ptr[3]=(v>>24)&0xff;
+ ptr[4]=hi&0xff;
+ ptr[5]=(hi>>8)&0xff;
+ ptr[6]=(hi>>16)&0xff;
+ ptr[7]=(hi>>24)&0xff;
+}
+
+void add_fishead_packet (oggmux_info *info) {
+ ogg_packet op;
+
+ memset (&op, 0, sizeof (op));
+
+ op.packet = _ogg_calloc (64, sizeof(unsigned char));
+ if (op.packet == NULL) return;
+
+ memset (op.packet, 0, 64);
+ memcpy (op.packet, FISHEAD_IDENTIFIER, 8); /* identifier */
+ write16le(op.packet+8, SKELETON_VERSION_MAJOR); /* version major */
+ write16le(op.packet+10, SKELETON_VERSION_MINOR); /* version minor */
+ write64le(op.packet+12, (ogg_int64_t)0); /* presentationtime numerator */
+ write64le(op.packet+20, (ogg_int64_t)1000); /* presentationtime denominator */
+ write64le(op.packet+28, (ogg_int64_t)0); /* basetime numerator */
+ write64le(op.packet+36, (ogg_int64_t)1000); /* basetime denominator */
+ /* both the numerator are zero hence handled by the memset */
+ write32le(op.packet+44, 0); /* UTC time, set to zero for now */
+
+ op.b_o_s = 1; /* its the first packet of the stream */
+ op.e_o_s = 0; /* its not the last packet of the stream */
+ op.bytes = 64; /* length of the packet in bytes */
+
+ ogg_stream_packetin (&info->so, &op); /* adding the packet to the skeleton stream */
+ _ogg_free (op.packet);
+}
+
+/*
+ * Adds the fishead packets in the skeleton output stream along with the e_o_s packet
+ */
+void add_fisbone_packet (oggmux_info *info) {
+ ogg_packet op;
+ int n;
+
+ if (!info->audio_only) {
+ memset (&op, 0, sizeof (op));
+ op.packet = _ogg_calloc (80, sizeof(unsigned char));
+ if (op.packet == NULL) return;
+
+ memset (op.packet, 0, 80);
+ /* it will be the fisbone packet for the theora video */
+ memcpy (op.packet, FISBONE_IDENTIFIER, 8); /* identifier */
+ write32le(op.packet+8, FISBONE_MESSAGE_HEADER_OFFSET); /* offset of the message header fields */
+ write32le(op.packet+12, info->to.serialno); /* serialno of the theora stream */
+ write32le(op.packet+16, 3); /* number of header packets */
+ /* granulerate, temporal resolution of the bitstream in samples/microsecond */
+ write64le(op.packet+20, info->ti.fps_numerator); /* granulrate numerator */
+ write64le(op.packet+28, info->ti.fps_denominator); /* granulrate denominator */
+ write64le(op.packet+36, 0); /* start granule */
+ write32le(op.packet+44, 0); /* preroll, for theora its 0 */
+ *(op.packet+48) = theora_granule_shift (&info->ti); /* granule shift */
+ memcpy(op.packet+FISBONE_SIZE, "Content-Type: video/theora\r\n", 28); /* message header field, Content-Type */
+
+ op.b_o_s = 0;
+ op.e_o_s = 0;
+ op.bytes = 80; /* size of the packet in bytes */
+
+ ogg_stream_packetin (&info->so, &op);
+ _ogg_free (op.packet);
+ }
+
+ if (!info->video_only) {
+ memset (&op, 0, sizeof (op));
+ op.packet = _ogg_calloc (80, sizeof(unsigned char));
+ if (op.packet == NULL) return;
+
+ memset (op.packet, 0, 80);
+ /* it will be the fisbone packet for the vorbis audio */
+ memcpy (op.packet, FISBONE_IDENTIFIER, 8); /* identifier */
+ write32le(op.packet+8, FISBONE_MESSAGE_HEADER_OFFSET); /* offset of the message header fields */
+ write32le(op.packet+12, info->vo.serialno); /* serialno of the vorbis stream */
+ write32le(op.packet+16, 3); /* number of header packet */
+ /* granulerate, temporal resolution of the bitstream in Hz */
+ write64le(op.packet+20, info->sample_rate); /* granulerate numerator */
+ write64le(op.packet+28, (ogg_int64_t)1); /* granulerate denominator */
+ write64le(op.packet+36, 0); /* start granule */
+ write32le(op.packet+44, 2); /* preroll, for vorbis its 2 */
+ *(op.packet+48) = 0; /* granule shift, always 0 for vorbis */
+ memcpy (op.packet+FISBONE_SIZE, "Content-Type: audio/vorbis\r\n", 28);
+ /* Important: Check the case of Content-Type for correctness */
+
+ op.b_o_s = 0;
+ op.e_o_s = 0;
+ op.bytes = 80;
+
+ ogg_stream_packetin (&info->so, &op);
+ _ogg_free (op.packet);
+ }
+
+#ifdef HAVE_KATE
+ if (info->with_kate) {
+ for (n=0; n<info->n_kate_streams; ++n) {
+ oggmux_kate_stream *ks=info->kate_streams+n;
+ memset (&op, 0, sizeof (op));
+ op.packet = _ogg_calloc (86, sizeof(unsigned char));
+ memset (op.packet, 0, 86);
+ /* it will be the fisbone packet for the kate stream */
+ memcpy (op.packet, FISBONE_IDENTIFIER, 8); /* identifier */
+ write32le(op.packet+8, FISBONE_MESSAGE_HEADER_OFFSET); /* offset of the message header fields */
+ write32le(op.packet+12, ks->ko.serialno); /* serialno of the vorbis stream */
+ write32le(op.packet+16, ks->ki.num_headers); /* number of header packet */
+ /* granulerate, temporal resolution of the bitstream in Hz */
+ write64le(op.packet+20, ks->ki.gps_numerator); /* granulerate numerator */
+ write64le(op.packet+28, ks->ki.gps_denominator); /* granulerate denominator */
+ write64le(op.packet+36, 0); /* start granule */
+ write32le(op.packet+44, 0); /* preroll, for kate it's 0 */
+ *(op.packet+48) = ks->ki.granule_shift; /* granule shift */
+ memcpy (op.packet+FISBONE_SIZE, "Content-Type: application/x-kate\r\n", 34);
+ /* Important: Check the case of Content-Type for correctness */
+
+ op.b_o_s = 0;
+ op.e_o_s = 0;
+ op.bytes = 86;
+
+ ogg_stream_packetin (&info->so, &op);
+ _ogg_free (op.packet);
+ }
+ }
+#endif
+}
+
+void oggmux_init (oggmux_info *info){
+ ogg_page og;
+ ogg_packet op;
+
+ /* yayness. Set up Ogg output stream */
+ srand (time (NULL));
+ ogg_stream_init (&info->vo, rand ());
+
+ if(!info->audio_only){
+ ogg_stream_init (&info->to, rand ()); /* oops, add one ot the above */
+ theora_encode_init (&info->td, &info->ti);
+
+ if(info->speed_level >= 0) {
+ int max_speed_level;
+ theora_control(&info->td, TH_ENCCTL_GET_SPLEVEL_MAX, &max_speed_level, sizeof(int));
+ if(info->speed_level > max_speed_level)
+ info->speed_level = max_speed_level;
+ theora_control(&info->td, TH_ENCCTL_SET_SPLEVEL, &info->speed_level, sizeof(int));
+ }
+ }
+ /* init theora done */
+
+ /* initialize Vorbis too, if we have audio. */
+ if(!info->video_only){
+ int ret;
+ vorbis_info_init (&info->vi);
+ /* Encoding using a VBR quality mode. */
+ if(info->vorbis_quality>-99)
+ ret =vorbis_encode_init_vbr (&info->vi, info->channels,info->sample_rate,info->vorbis_quality);
+ else
+ ret=vorbis_encode_init(&info->vi,info->channels,info->sample_rate,-1,info->vorbis_bitrate,-1);
+
+ if (ret){
+ fprintf (stderr,
+ "The Vorbis encoder could not set up a mode according to\n"
+ "the requested quality or bitrate.\n\n");
+ exit (1);
+ }
+
+ vorbis_comment_init (&info->vc);
+ vorbis_comment_add_tag (&info->vc, "ENCODER",PACKAGE_STRING);
+ /* set up the analysis state and auxiliary encoding storage */
+ vorbis_analysis_init (&info->vd, &info->vi);
+ vorbis_block_init (&info->vd, &info->vb);
+
+ }
+ /* audio init done */
+
+ /* initialize kate if we have subtitles */
+ if (info->with_kate) {
+ int ret, n;
+#ifdef HAVE_KATE
+ for (n=0; n<info->n_kate_streams; ++n) {
+ oggmux_kate_stream *ks=info->kate_streams+n;
+ ogg_stream_init (&ks->ko, rand ()); /* oops, add one ot the above */
+ ret = kate_encode_init (&ks->k, &ks->ki);
+ if (ret<0) fprintf(stderr, "kate_encode_init: %d\n",ret);
+ ret = kate_comment_init(&ks->kc);
+ if (ret<0) fprintf(stderr, "kate_comment_init: %d\n",ret);
+ kate_comment_add_tag (&ks->kc, "ENCODER",PACKAGE_STRING);
+ }
+#endif
+ }
+ /* kate init done */
+
+ /* first packet should be skeleton fishead packet, if skeleton is used */
+
+ if (info->with_skeleton) {
+ ogg_stream_init (&info->so, rand());
+ add_fishead_packet (info);
+ if (ogg_stream_pageout (&info->so, &og) != 1){
+ fprintf (stderr, "Internal Ogg library error.\n");
+ exit (1);
+ }
+ fwrite (og.header, 1, og.header_len, info->outfile);
+ fwrite (og.body, 1, og.body_len, info->outfile);
+ }
+
+ /* write the bitstream header packets with proper page interleave */
+
+ /* first packet will get its own page automatically */
+ if(!info->audio_only){
+ theora_encode_header (&info->td, &op);
+ ogg_stream_packetin (&info->to, &op);
+ if (ogg_stream_pageout (&info->to, &og) != 1){
+ fprintf (stderr, "Internal Ogg library error.\n");
+ exit (1);
+ }
+ fwrite (og.header, 1, og.header_len, info->outfile);
+ fwrite (og.body, 1, og.body_len, info->outfile);
+
+ /* create the remaining theora headers */
+ /* theora_comment_init (&info->tc); is called in main() prior to parsing options */
+ theora_comment_add_tag (&info->tc, "ENCODER",PACKAGE_STRING);
+ theora_encode_comment (&info->tc, &op);
+ ogg_stream_packetin (&info->to, &op);
+ _ogg_free (op.packet);
+
+ theora_encode_tables (&info->td, &op);
+ ogg_stream_packetin (&info->to, &op);
+ }
+ if(!info->video_only){
+ ogg_packet header;
+ ogg_packet header_comm;
+ ogg_packet header_code;
+
+ vorbis_analysis_headerout (&info->vd, &info->vc, &header,
+ &header_comm, &header_code);
+ ogg_stream_packetin (&info->vo, &header); /* automatically placed in its own
+ * page */
+ if (ogg_stream_pageout (&info->vo, &og) != 1){
+ fprintf (stderr, "Internal Ogg library error.\n");
+ exit (1);
+ }
+ fwrite (og.header, 1, og.header_len, info->outfile);
+ fwrite (og.body, 1, og.body_len, info->outfile);
+
+ /* remaining vorbis header packets */
+ ogg_stream_packetin (&info->vo, &header_comm);
+ ogg_stream_packetin (&info->vo, &header_code);
+ }
+
+#ifdef HAVE_KATE
+ if (info->with_kate) {
+ int n;
+ for (n=0; n<info->n_kate_streams; ++n) {
+ oggmux_kate_stream *ks=info->kate_streams+n;
+ int ret;
+ while (1) {
+ ret=kate_ogg_encode_headers(&ks->k,&ks->kc,&op);
+ if (ret==0) {
+ ogg_stream_packetin(&ks->ko,&op);
+ ogg_packet_clear(&op);
+ }
+ if (ret<0) fprintf(stderr, "kate_encode_headers: %d\n",ret);
+ if (ret>0) break;
+ }
+
+ /* first header is on a separate page - libogg will do it automatically */
+ ret=ogg_stream_pageout (&ks->ko, &og);
+ if (ret!=1) {
+ fprintf (stderr, "Internal Ogg library error.\n");
+ exit (1);
+ }
+ fwrite (og.header, 1, og.header_len, info->outfile);
+ fwrite (og.body, 1, og.body_len, info->outfile);
+ }
+ }
+#endif
+
+ /* output the appropriate fisbone packets */
+ if (info->with_skeleton) {
+ add_fisbone_packet (info);
+ while (1) {
+ int result = ogg_stream_flush (&info->so, &og);
+ if (result < 0){
+ /* can't get here */
+ fprintf (stderr, "Internal Ogg library error.\n");
+ exit (1);
+ }
+ if (result == 0)
+ break;
+ fwrite (og.header, 1, og.header_len, info->outfile);
+ fwrite (og.body, 1, og.body_len, info->outfile);
+ }
+ }
+
+ if (!info->audio_only) {
+ theora_info_clear(&info->ti);
+ }
+
+ /* Flush the rest of our headers. This ensures
+ * the actual data in each stream will start
+ * on a new page, as per spec. */
+ while (1 && !info->audio_only){
+ int result = ogg_stream_flush (&info->to, &og);
+ if (result < 0){
+ /* can't get here */
+ fprintf (stderr, "Internal Ogg library error.\n");
+ exit (1);
+ }
+ if (result == 0)
+ break;
+ fwrite (og.header, 1, og.header_len, info->outfile);
+ fwrite (og.body, 1, og.body_len, info->outfile);
+ }
+ while (1 && !info->video_only){
+ int result = ogg_stream_flush (&info->vo, &og);
+ if (result < 0){
+ /* can't get here */
+ fprintf (stderr, "Internal Ogg library error.\n");
+ exit (1);
+ }
+ if (result == 0)
+ break;
+ fwrite (og.header, 1, og.header_len,info->outfile);
+ fwrite (og.body, 1, og.body_len, info->outfile);
+ }
+ if (info->with_kate) {
+ int n;
+ for (n=0; n<info->n_kate_streams; ++n) {
+ oggmux_kate_stream *ks=info->kate_streams+n;
+ while (1) {
+ int result = ogg_stream_flush (&ks->ko, &og);
+ if (result < 0){
+ /* can't get here */
+ fprintf (stderr, "Internal Ogg library error.\n");
+ exit (1);
+ }
+ if (result == 0)
+ break;
+ fwrite (og.header, 1, og.header_len,info->outfile);
+ fwrite (og.body, 1, og.body_len, info->outfile);
+ }
+ }
+ }
+
+ if (info->with_skeleton) {
+ int result;
+
+ /* build and add the e_o_s packet */
+ memset (&op, 0, sizeof (op));
+ op.b_o_s = 0;
+ op.e_o_s = 1; /* its the e_o_s packet */
+ op.granulepos = 0;
+ op.bytes = 0; /* e_o_s packet is an empty packet */
+ ogg_stream_packetin (&info->so, &op);
+
+ result = ogg_stream_flush (&info->so, &og);
+ if (result < 0){
+ /* can't get here */
+ fprintf (stderr, "Internal Ogg library error.\n");
+ exit (1);
+ }
+ fwrite (og.header, 1, og.header_len,info->outfile);
+ fwrite (og.body, 1, og.body_len, info->outfile);
+ }
+}
+
+/**
+ * adds a video frame to the encoding sink
+ * if e_o_s is 1 the end of the logical bitstream will be marked.
+ * @param this ff2theora struct
+ * @param info oggmux_info
+ * @param yuv_buffer
+ * @param e_o_s 1 indicates ond of stream
+ */
+void oggmux_add_video (oggmux_info *info, yuv_buffer *yuv, int e_o_s){
+ ogg_packet op;
+ theora_encode_YUVin (&info->td, yuv);
+ while(theora_encode_packetout (&info->td, e_o_s, &op)) {
+ ogg_stream_packetin (&info->to, &op);
+ info->v_pkg++;
+ }
+}
+
+/**
+ * adds audio samples to encoding sink
+ * @param buffer pointer to buffer
+ * @param bytes bytes in buffer
+ * @param samples samples in buffer
+ * @param e_o_s 1 indicates end of stream.
+ */
+void oggmux_add_audio (oggmux_info *info, int16_t * buffer, int bytes, int samples, int e_o_s){
+ ogg_packet op;
+
+ int i,j, count = 0;
+ float **vorbis_buffer;
+ if (bytes <= 0 && samples <= 0){
+ /* end of audio stream */
+ if(e_o_s)
+ vorbis_analysis_wrote (&info->vd, 0);
+ }
+ else{
+ vorbis_buffer = vorbis_analysis_buffer (&info->vd, samples);
+ /* uninterleave samples */
+ for (i = 0; i < samples; i++){
+ for(j=0;j<info->channels;j++){
+ vorbis_buffer[j][i] = buffer[count++] / 32768.f;
+ }
+ }
+ vorbis_analysis_wrote (&info->vd, samples);
+ }
+ while(vorbis_analysis_blockout (&info->vd, &info->vb) == 1){
+ /* analysis, assume we want to use bitrate management */
+ vorbis_analysis (&info->vb, NULL);
+ vorbis_bitrate_addblock (&info->vb);
+
+ /* weld packets into the bitstream */
+ while (vorbis_bitrate_flushpacket (&info->vd, &op)){
+ ogg_stream_packetin (&info->vo, &op);
+ info->a_pkg++;
+ }
+ }
+}
+
+/**
+ * adds a subtitles text to the encoding sink
+ * if e_o_s is 1 the end of the logical bitstream will be marked.
+ * @param info oggmux_info
+ * @param idx which kate stream to output to
+ * @param t0 the show time of the text
+ * @param t1 the hide time of the text
+ * @param text the utf-8 text
+ * @param len the number of bytes in the text
+ * @param e_o_s 1 indicates end of stream
+ */
+void oggmux_add_kate_text (oggmux_info *info, int idx, double t0, double t1, const char *text, size_t len, int e_o_s){
+#ifdef HAVE_KATE
+ ogg_packet op;
+ oggmux_kate_stream *ks=info->kate_streams+idx;
+ int ret;
+ ret = kate_ogg_encode_text(&ks->k, t0, t1, text, len, &op);
+ if (ret>=0) {
+ ogg_stream_packetin (&ks->ko, &op);
+ info->k_pkg++;
+ }
+ else {
+ fprintf(stderr, "Failed to encode kate data packet (%f --> %f, [%s]): %d",
+ t0, t1, text, ret);
+ }
+ if(e_o_s) {
+ ret = kate_ogg_encode_finish(&ks->k, -1, &op);
+ if (ret>=0) {
+ ogg_stream_packetin (&ks->ko, &op);
+ info->k_pkg++;
+ }
+ else {
+ fprintf(stderr, "Failed to encode kate end packet: %d", ret);
+ }
+ }
+#endif
+}
+
+/**
+ * adds a kate end packet to the encoding sink
+ * @param info oggmux_info
+ * @param idx which kate stream to output to
+ * @param t the time of the end packet
+ */
+void oggmux_add_kate_end_packet (oggmux_info *info, int idx, double t){
+#ifdef HAVE_KATE
+ ogg_packet op;
+ oggmux_kate_stream *ks=info->kate_streams+idx;
+ int ret;
+ ret = kate_ogg_encode_finish(&ks->k, t, &op);
+ if (ret>=0) {
+ ogg_stream_packetin (&ks->ko, &op);
+ info->k_pkg++;
+ }
+ else {
+ fprintf(stderr, "Failed to encode kate end packet: %d", ret);
+ }
+#endif
+}
+
+static double get_remaining(oggmux_info *info, double timebase) {
+ double remaining = 0;
+ double to_encode, time_so_far;
+
+ if(info->duration != -1 && timebase > 0) {
+ time_so_far = time(NULL) - info->start_time;
+ to_encode = info->duration - timebase;
+ if(to_encode > 0) {
+ remaining = (time_so_far / timebase) * to_encode;
+ }
+ }
+ return remaining;
+}
+
+static void print_stats(oggmux_info *info, double timebase){
+ int hundredths = timebase * 100 - (long) timebase * 100;
+ int seconds = (long) timebase % 60;
+ int minutes = ((long) timebase / 60) % 60;
+ int hours = (long) timebase / 3600;
+ double remaining = get_remaining(info, timebase);
+ int remaining_seconds = (long) remaining % 60;
+ int remaining_minutes = ((long) remaining / 60) % 60;
+ int remaining_hours = (long) remaining / 3600;
+ if(info->frontend) {
+ fprintf (stderr,"\nf2t ;position: %.02lf;audio_kbps: %d;video_kbps: %d;remaining: %.02lf\n",
+ timebase,
+ info->akbps, info->vkbps,
+ remaining
+ );
+
+ }
+ else {
+ if(!remaining) {
+ remaining = time(NULL) - info->start_time;
+ remaining_seconds = (long) remaining % 60;
+ remaining_minutes = ((long) remaining / 60) % 60;
+ remaining_hours = (long) remaining / 3600;
+ fprintf (stderr,"\r %d:%02d:%02d.%02d audio: %dkbps video: %dkbps, time elapsed: %02d:%02d:%02d ",
+ hours, minutes, seconds, hundredths,
+ info->akbps, info->vkbps,
+ remaining_hours, remaining_minutes, remaining_seconds
+ );
+ }
+ else {
+ fprintf (stderr,"\r %d:%02d:%02d.%02d audio: %dkbps video: %dkbps, time remaining: %02d:%02d:%02d ",
+ hours, minutes, seconds, hundredths,
+ info->akbps, info->vkbps,
+ remaining_hours, remaining_minutes, remaining_seconds
+ );
+ }
+ }
+}
+
+static void write_audio_page(oggmux_info *info)
+{
+ int ret;
+
+ ret = fwrite(info->audiopage, 1, info->audiopage_len, info->outfile);
+ if(ret < info->audiopage_len) {
+ fprintf(stderr,"error writing audio page\n");
+ }
+ else {
+ info->audio_bytesout += ret;
+ }
+ info->audiopage_valid = 0;
+ info->a_pkg -=ogg_page_packets((ogg_page *)&info->audiopage);
+#ifdef OGGMUX_DEBUG
+ info->a_page++;
+ info->v_page=0;
+ fprintf(stderr,"\naudio page %d (%d pkgs) | pkg remaining %d\n",info->a_page,ogg_page_packets((ogg_page *)&info->audiopage),info->a_pkg);
+#endif
+
+ info->akbps = rint (info->audio_bytesout * 8. / info->audiotime * .001);
+ if(info->akbps<0)
+ info->akbps=0;
+ print_stats(info, info->audiotime);
+}
+
+static void write_video_page(oggmux_info *info)
+{
+ int ret;
+
+ ret = fwrite(info->videopage, 1, info->videopage_len, info->outfile);
+ if(ret < info->videopage_len) {
+ fprintf(stderr,"error writing video page\n");
+ }
+ else {
+ info->video_bytesout += ret;
+ }
+ info->videopage_valid = 0;
+ info->v_pkg -= ogg_page_packets((ogg_page *)&info->videopage);
+#ifdef OGGMUX_DEBUG
+ info->v_page++;
+ info->a_page=0;
+ fprintf(stderr,"\nvideo page %d (%d pkgs) | pkg remaining %d\n",info->v_page,ogg_page_packets((ogg_page *)&info->videopage),info->v_pkg);
+#endif
+
+
+ info->vkbps = rint (info->video_bytesout * 8. / info->videotime * .001);
+ if(info->vkbps<0)
+ info->vkbps=0;
+ print_stats(info, info->videotime);
+}
+
+static void write_kate_page(oggmux_info *info, int idx)
+{
+ int ret;
+ oggmux_kate_stream *ks=info->kate_streams+idx;
+
+ ret = fwrite(ks->katepage, 1, ks->katepage_len, info->outfile);
+ if(ret < ks->katepage_len) {
+ fprintf(stderr,"error writing kate page\n");
+ }
+ else {
+ info->kate_bytesout += ret;
+ }
+ ks->katepage_valid = 0;
+ info->k_pkg -= ogg_page_packets((ogg_page *)&ks->katepage);
+#ifdef OGGMUX_DEBUG
+ ks->k_page++;
+ fprintf(stderr,"\nkate page %d (%d pkgs) | pkg remaining %d\n",ks->k_page,ogg_page_packets((ogg_page *)&info->katepage),info->k_pkg);
+#endif
+
+
+ /*
+ info->kkbps = rint (info->kate_bytesout * 8. / info->katetime * .001);
+ if(info->kkbps<0)
+ info->kkbps=0;
+ print_stats(info, info->katetime);
+ */
+}
+
+static int find_best_valid_kate_page(oggmux_info *info)
+{
+ int n;
+ double t=0.0;
+ int best=-1;
+ if (info->with_kate) for (n=0; n<info->n_kate_streams;++n) {
+ oggmux_kate_stream *ks=info->kate_streams+n;
+ if (ks->katepage_valid) {
+ if (best==-1 || ks->katetime<t) {
+ t=ks->katetime;
+ best=n;
+ }
+ }
+ }
+ return best;
+}
+
+void oggmux_flush (oggmux_info *info, int e_o_s)
+{
+ int n,len;
+ ogg_page og;
+ int best;
+
+ /* flush out the ogg pages to info->outfile */
+ while(1) {
+ /* Get pages for both streams, if not already present, and if available.*/
+ if(!info->audio_only && !info->videopage_valid) {
+ // this way seeking is much better,
+ // not sure if 23 packets is a good value. it works though
+ int v_next=0;
+ if(info->v_pkg>22 && ogg_stream_flush(&info->to, &og) > 0) {
+ v_next=1;
+ }
+ else if(ogg_stream_pageout(&info->to, &og) > 0) {
+ v_next=1;
+ }
+ if(v_next) {
+ len = og.header_len + og.body_len;
+ if(info->videopage_buffer_length < len) {
+ info->videopage = realloc(info->videopage, len);
+ info->videopage_buffer_length = len;
+ }
+ info->videopage_len = len;
+ memcpy(info->videopage, og.header, og.header_len);
+ memcpy(info->videopage+og.header_len , og.body, og.body_len);
+
+ info->videopage_valid = 1;
+ if(ogg_page_granulepos(&og)>0) {
+ info->videotime = theora_granule_time (&info->td,
+ ogg_page_granulepos(&og));
+ }
+ }
+ }
+ if(!info->video_only && !info->audiopage_valid) {
+ // this way seeking is much better,
+ // not sure if 23 packets is a good value. it works though
+ int a_next=0;
+ if(info->a_pkg>22 && ogg_stream_flush(&info->vo, &og) > 0) {
+ a_next=1;
+ }
+ else if(ogg_stream_pageout(&info->vo, &og) > 0) {
+ a_next=1;
+ }
+ if(a_next) {
+ len = og.header_len + og.body_len;
+ if(info->audiopage_buffer_length < len) {
+ info->audiopage = realloc(info->audiopage, len);
+ info->audiopage_buffer_length = len;
+ }
+ info->audiopage_len = len;
+ memcpy(info->audiopage, og.header, og.header_len);
+ memcpy(info->audiopage+og.header_len , og.body, og.body_len);
+
+ info->audiopage_valid = 1;
+ if(ogg_page_granulepos(&og)>0) {
+ info->audiotime= vorbis_granule_time (&info->vd,
+ ogg_page_granulepos(&og));
+ }
+ }
+ }
+
+#ifdef HAVE_KATE
+ if (info->with_kate) for (n=0; n<info->n_kate_streams; ++n) {
+ oggmux_kate_stream *ks=info->kate_streams+n;
+ if (!ks->katepage_valid) {
+ int k_next=0;
+ /* always flush kate stream */
+ if (ogg_stream_flush(&ks->ko, &og) > 0) {
+ k_next = 1;
+ }
+ if (k_next) {
+ len = og.header_len + og.body_len;
+ if(ks->katepage_buffer_length < len) {
+ ks->katepage = realloc(ks->katepage, len);
+ ks->katepage_buffer_length = len;
+ }
+ ks->katepage_len = len;
+ memcpy(ks->katepage, og.header, og.header_len);
+ memcpy(ks->katepage+og.header_len , og.body, og.body_len);
+
+ ks->katepage_valid = 1;
+ if(ogg_page_granulepos(&og)>0) {
+ ks->katetime= kate_granule_time (&ks->ki,
+ ogg_page_granulepos(&og));
+ }
+ }
+ }
+ }
+#endif
+
+#ifdef HAVE_KATE
+#define CHECK_KATE_OUTPUT(which) \
+ if (best>=0 && info->kate_streams[best].katetime/*-1.0*/<=info->which##time) { \
+ write_kate_page(info, best); \
+ continue; \
+ }
+#else
+#define CHECK_KATE_OUTPUT(which) ((void)0)
+#endif
+
+ best=find_best_valid_kate_page(info);
+
+ if(info->video_only && info->videopage_valid) {
+ CHECK_KATE_OUTPUT(video);
+ write_video_page(info);
+ }
+ else if(info->audio_only && info->audiopage_valid) {
+ CHECK_KATE_OUTPUT(audio);
+ write_audio_page(info);
+ }
+ /* We're using both. We can output only:
+ * a) If we have valid pages for both
+ * b) At EOS, for the remaining stream.
+ */
+ else if(info->videopage_valid && info->audiopage_valid) {
+ /* Make sure they're in the right order. */
+ if(info->videotime <= info->audiotime) {
+ CHECK_KATE_OUTPUT(video);
+ write_video_page(info);
+ }
+ else {
+ CHECK_KATE_OUTPUT(audio);
+ write_audio_page(info);
+ }
+ }
+ else if(e_o_s && best>=0) {
+ write_kate_page(info, best);
+ }
+ else if(e_o_s && info->videopage_valid) {
+ write_video_page(info);
+ }
+ else if(e_o_s && info->audiopage_valid) {
+ write_audio_page(info);
+ }
+ else {
+ break; /* Nothing more writable at the moment */
+ }
+ }
+}
+
+void oggmux_close (oggmux_info *info){
+ int n;
+
+ ogg_stream_clear (&info->vo);
+ vorbis_block_clear (&info->vb);
+ vorbis_dsp_clear (&info->vd);
+ vorbis_comment_clear (&info->vc);
+ vorbis_info_clear (&info->vi);
+
+ ogg_stream_clear (&info->to);
+ theora_clear (&info->td);
+
+#ifdef HAVE_KATE
+ for (n=0; n<info->n_kate_streams; ++n) {
+ ogg_stream_clear (&info->kate_streams[n].ko);
+ kate_comment_clear (&info->kate_streams[n].kc);
+ kate_info_clear (&info->kate_streams[n].ki);
+ kate_clear (&info->kate_streams[n].k);
+ }
+#endif
+
+ if (info->outfile && info->outfile != stdout)
+ fclose (info->outfile);
+
+ if(info->videopage)
+ free(info->videopage);
+ if(info->audiopage)
+ free(info->audiopage);
+
+ for (n=0; n<info->n_kate_streams; ++n) {
+ if(info->kate_streams[n].katepage)
+ free(info->kate_streams[n].katepage);
+ }
+}
Copied: trunk/ffmpeg2theora/src/theorautils.h (from rev 14949, trunk/ffmpeg2theora/theorautils.h)
===================================================================
--- trunk/ffmpeg2theora/src/theorautils.h (rev 0)
+++ trunk/ffmpeg2theora/src/theorautils.h 2008-05-23 17:56:21 UTC (rev 14950)
@@ -0,0 +1,143 @@
+/* -*- tab-width:4;c-file-style:"cc-mode"; -*- */
+/*
+ * theorautils.h -- Ogg Theora/Ogg Vorbis Abstraction and Muxing
+ * Copyright (C) 2003-2005 <j at v2v.cc>
+ *
+ * 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-1307, USA.
+ */
+#ifndef _F2T_THEORAUTILS_H_
+#define _F2T_THEORAUTILS_H_
+
+#include <stdint.h>
+#include "theora/theora.h"
+#include "vorbis/codec.h"
+#include "vorbis/vorbisenc.h"
+#ifdef HAVE_KATE
+#include "kate/kate.h"
+#endif
+#include "ogg/ogg.h"
+
+// #define OGGMUX_DEBUG
+
+#define SKELETON_VERSION_MAJOR 3
+#define SKELETON_VERSION_MINOR 0
+#define FISHEAD_IDENTIFIER "fishead\0"
+#define FISBONE_IDENTIFIER "fisbone\0"
+#define FISBONE_SIZE 52
+#define FISBONE_MESSAGE_HEADER_OFFSET 44
+
+typedef struct
+{
+#ifdef HAVE_KATE
+ kate_state k;
+ kate_info ki;
+ kate_comment kc;
+#endif
+ ogg_stream_state ko; /* take physical pages, weld into a logical
+ * stream of packets */
+ int katepage_valid;
+ unsigned char *katepage;
+ int katepage_len;
+ int katepage_buffer_length;
+ double katetime;
+}
+oggmux_kate_stream;
+
+typedef struct
+{
+ /* the file the mixed ogg stream is written to */
+ FILE *outfile;
+
+ int audio_only;
+ int video_only;
+ int with_skeleton;
+ int frontend;
+ /* vorbis settings */
+ int sample_rate;
+ int channels;
+ double vorbis_quality;
+ int vorbis_bitrate;
+
+ vorbis_info vi; /* struct that stores all the static vorbis bitstream settings */
+ vorbis_comment vc; /* struct that stores all the user comments */
+
+ /* theora settings */
+ theora_info ti;
+ theora_comment tc;
+ int speed_level;
+
+ /* state info */
+ theora_state td;
+ vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */
+ vorbis_block vb; /* local working space for packet->PCM decode */
+
+ int with_kate;
+
+ /* used for muxing */
+ ogg_stream_state to; /* take physical pages, weld into a logical
+ * stream of packets */
+ ogg_stream_state vo; /* take physical pages, weld into a logical
+ * stream of packets */
+ ogg_stream_state so; /* take physical pages, weld into a logical
+ * stream of packets, used for skeleton stream */
+
+ int audiopage_valid;
+ int videopage_valid;
+ unsigned char *audiopage;
+ unsigned char *videopage;
+ int videopage_len;
+ int audiopage_len;
+ int videopage_buffer_length;
+ int audiopage_buffer_length;
+
+ /* some stats */
+ double audiotime;
+ double videotime;
+ double duration;
+
+ int vkbps;
+ int akbps;
+ ogg_int64_t audio_bytesout;
+ ogg_int64_t video_bytesout;
+ ogg_int64_t kate_bytesout;
+ time_t start_time;
+
+ //to do some manual page flusing
+ int v_pkg;
+ int a_pkg;
+ int k_pkg;
+#ifdef OGGMUX_DEBUG
+ int a_page;
+ int v_page;
+ int k_page;
+#endif
+
+ int n_kate_streams;
+ oggmux_kate_stream *kate_streams;
+}
+oggmux_info;
+
+void init_info(oggmux_info *info);
+extern void oggmux_setup_kate_streams(oggmux_info *info, int n_kate_streams);
+extern void oggmux_init (oggmux_info *info);
+extern void oggmux_add_video (oggmux_info *info, yuv_buffer *yuv, int e_o_s);
+extern void oggmux_add_audio (oggmux_info *info, int16_t * readbuffer, int bytesread, int samplesread,int e_o_s);
+extern void oggmux_add_kate_text (oggmux_info *info, int idx, double t0, double t1, const char *text, size_t len,int e_o_s);
+extern void oggmux_add_kate_end_packet (oggmux_info *info, int idx, double t);
+extern void oggmux_flush (oggmux_info *info, int e_o_s);
+extern void oggmux_close (oggmux_info *info);
+
+
+#endif
Deleted: trunk/ffmpeg2theora/subtitles.c
===================================================================
--- trunk/ffmpeg2theora/subtitles.c 2008-05-23 17:55:53 UTC (rev 14949)
+++ trunk/ffmpeg2theora/subtitles.c 2008-05-23 17:56:21 UTC (rev 14950)
@@ -1,293 +0,0 @@
-/* -*- tab-width:4;c-file-style:"cc-mode"; -*- */
-/*
- * subtitles.c -- Kate Subtitles
- * Copyright (C) 2007-2008 <j at v2v.cc>
- *
- * 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-1307, USA.
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <getopt.h>
-#include <math.h>
-#include <errno.h>
-
-#include "libavformat/avformat.h"
-
-#ifdef WIN32
-#include "fcntl.h"
-#endif
-
-#include "theorautils.h"
-#include "subtitles.h"
-
-
-/**
- * adds a new kate stream structure
- */
-static void add_kate_stream(ff2theora this){
- ff2theora_kate_stream *ks;
- this->kate_streams=(ff2theora_kate_stream*)realloc(this->kate_streams,(this->n_kate_streams+1)*sizeof(ff2theora_kate_stream));
- ks=&this->kate_streams[this->n_kate_streams++];
- ks->filename = NULL;
- ks->num_subtitles = 0;
- ks->subtitles = 0;
- ks->subtitles_count = 0; /* denotes not set yet */
- ks->subtitles_encoding = ENC_UNSET;
- strcpy(ks->subtitles_language, "");
- strcpy(ks->subtitles_category, "");
-}
-
-/*
- * sets the filename of the next subtitles file
- */
-void set_subtitles_file(ff2theora this,const char *filename){
- size_t n;
- for (n=0; n<this->n_kate_streams;++n) {
- if (!this->kate_streams[n].filename) break;
- }
- if (n==this->n_kate_streams) add_kate_stream(this);
- this->kate_streams[n].filename = filename;
-}
-
-/*
- * sets the language of the next subtitles file
- */
-void set_subtitles_language(ff2theora this,const char *language){
- size_t n;
- for (n=0; n<this->n_kate_streams;++n) {
- if (!this->kate_streams[n].subtitles_language[0]) break;
- }
- if (n==this->n_kate_streams) add_kate_stream(this);
- strncpy(this->kate_streams[n].subtitles_language, language, 16);
- this->kate_streams[n].subtitles_language[15] = 0;
-}
-
-/*
- * sets the category of the next subtitles file
- */
-void set_subtitles_category(ff2theora this,const char *category){
- size_t n;
- for (n=0; n<this->n_kate_streams;++n) {
- if (!this->kate_streams[n].subtitles_category[0]) break;
- }
- if (n==this->n_kate_streams) add_kate_stream(this);
- strncpy(this->kate_streams[n].subtitles_category, category, 16);
- this->kate_streams[n].subtitles_category[15] = 0;
-}
-
-/**
- * sets the encoding of the next subtitles file
- */
-void set_subtitles_encoding(ff2theora this,F2T_ENCODING encoding){
- size_t n;
- for (n=0; n<this->n_kate_streams;++n) {
- if (this->kate_streams[n].subtitles_encoding==ENC_UNSET) break;
- }
- if (n==this->n_kate_streams) add_kate_stream(this);
- this->kate_streams[n].subtitles_encoding = encoding;
-}
-
-
-void report_unknown_subtitle_encoding(const char *name)
-{
- fprintf(stderr, "Unknown character encoding: %s\n",name);
- fprintf(stderr, "Valid character encodings are:\n");
- fprintf(stderr, " " SUPPORTED_ENCODINGS "\n");
-}
-
-static char *fgets2(char *s,size_t sz,FILE *f)
-{
- char *ret = fgets(s, sz, f);
- /* fixup DOS newline character */
- char *ptr=strchr(s, '\r');
- if (ptr) *ptr='\n';
- return ret;
-}
-
-static double hmsms2s(int h,int m,int s,int ms)
-{
- return h*3600+m*60+s+ms/1000.0;
-}
-
-/* very simple implementation when no iconv */
-static void convert_subtitle_to_utf8(F2T_ENCODING encoding,unsigned char *text)
-{
- size_t nbytes;
- unsigned char *ptr,*newtext;
-
- if (!text || !*text) return;
-
- switch (encoding) {
- case ENC_UNSET:
- /* we don't know what encoding this is, assume utf-8 and we'll yell if it ain't */
- break;
- case ENC_UTF8:
- /* nothing to do, already in utf-8 */
- break;
- case ENC_ISO_8859_1:
- /* simple, characters above 0x7f are broken in two,
- and code points map to the iso-8859-1 8 bit codes */
- nbytes=0;
- for (ptr=text;*ptr;++ptr) {
- nbytes++;
- if (0x80&*ptr) nbytes++;
- }
- newtext=(unsigned char*)malloc(1+nbytes);
- if (!newtext) {
- fprintf(stderr, "Memory allocation failed - cannot convert text\n");
- return;
- }
- nbytes=0;
- for (ptr=text;*ptr;++ptr) {
- if (0x80&*ptr) {
- newtext[nbytes++]=0xc0|((*ptr)>>6);
- newtext[nbytes++]=0x80|((*ptr)&0x3f);
- }
- else {
- newtext[nbytes++]=*ptr;
- }
- }
- newtext[nbytes++]=0;
- memcpy(text,newtext,nbytes);
- free(newtext);
- break;
- default:
- fprintf(stderr, "ERROR: encoding %d not handled in conversion!\n", encoding);
- break;
- }
-}
-
-int load_subtitles(ff2theora_kate_stream *this)
-{
-#ifdef HAVE_KATE
- enum { need_id, need_timing, need_text };
- int need = need_id;
- int last_seen_id=0;
- int ret;
- int id;
- static char text[4096];
- int h0,m0,s0,ms0,h1,m1,s1,ms1;
- double t0,t1;
- static char str[4096];
- int warned=0;
-
- FILE *f = fopen(this->filename, "r");
- if (!f) {
- fprintf(stderr,"WARNING - Failed to open subtitles file %s (%s)\n", this->filename, strerror(errno));
- return -1;
- }
-
- /* first, check for a BOM */
- ret=fread(str,1,3,f);
- if (ret<3 || memcmp(str,"\xef\xbb\xbf",3)) {
- /* No BOM, rewind */
- fseek(f,0,SEEK_SET);
- }
-
- fgets2(str,sizeof(str),f);
- while (!feof(f)) {
- switch (need) {
- case need_id:
- ret=sscanf(str,"%d\n",&id);
- if (ret!=1) {
- fprintf(stderr,"WARNING - Syntax error: %s\n",str);
- fclose(f);
- return -1;
- }
- if (id!=last_seen_id+1) {
- fprintf(stderr,"WARNING - non consecutive ids: %s - pretending not to have noticed\n",str);
- }
- last_seen_id=id;
- need=need_timing;
- strcpy(text,"");
- break;
- case need_timing:
- ret=sscanf(str,"%d:%d:%d%*[.,]%d --> %d:%d:%d%*[.,]%d\n",&h0,&m0,&s0,&ms0,&h1,&m1,&s1,&ms1);
- if (ret!=8) {
- fprintf(stderr,"WARNING - Syntax error: %s\n",str);
- fclose(f);
- return -1;
- }
- else {
- t0=hmsms2s(h0,m0,s0,ms0);
- t1=hmsms2s(h1,m1,s1,ms1);
- }
- need=need_text;
- break;
- case need_text:
- if (*str=='\n') {
- convert_subtitle_to_utf8(this->subtitles_encoding,(unsigned char*)text);
- size_t len = strlen(text);
- this->subtitles = (ff2theora_subtitle*)realloc(this->subtitles, (this->num_subtitles+1)*sizeof(ff2theora_subtitle));
- if (!this->subtitles) {
- fprintf(stderr, "Out of memory\n");
- fclose(f);
- return -1;
- }
- ret=kate_text_validate(kate_utf8,text,len+1);
- if (ret<0) {
- if (!warned) {
- fprintf(stderr,"WARNING: subtitle %s is not valid utf-8\n",text);
- fprintf(stderr," further invalid subtitles will NOT be flagged\n");
- warned=1;
- }
- }
- else {
- /* kill off trailing \n characters */
- while (len>0) {
- if (text[len-1]=='\n') text[--len]=0; else break;
- }
- this->subtitles[this->num_subtitles].text = (char*)malloc(len+1);
- memcpy(this->subtitles[this->num_subtitles].text, text, len+1);
- this->subtitles[this->num_subtitles].len = len;
- this->subtitles[this->num_subtitles].t0 = t0;
- this->subtitles[this->num_subtitles].t1 = t1;
- this->num_subtitles++;
- }
- need=need_id;
- }
- else {
- strcat(text,str);
- }
- break;
- }
- fgets2(str,sizeof(str),f);
- }
-
- fclose(f);
-
- /* fprintf(stderr," %u subtitles loaded.\n", this->num_subtitles); */
-
- return this->num_subtitles;
-#else
- return 0;
-#endif
-}
-
-void free_subtitles(ff2theora this)
-{
- size_t i,n;
- for (i=0; i<this->n_kate_streams; ++i) {
- ff2theora_kate_stream *ks=this->kate_streams+i;
- for (n=0; n<ks->num_subtitles; ++n) free(ks->subtitles[n].text);
- free(ks->subtitles);
- }
- free(this->kate_streams);
-}
-
Deleted: trunk/ffmpeg2theora/subtitles.h
===================================================================
--- trunk/ffmpeg2theora/subtitles.h 2008-05-23 17:55:53 UTC (rev 14949)
+++ trunk/ffmpeg2theora/subtitles.h 2008-05-23 17:56:21 UTC (rev 14950)
@@ -1,32 +0,0 @@
-#ifndef _F2T_SUBTITLES_H_
-#define _F2T_SUBTITLES_H_
-
-#ifdef HAVE_KATE
-#include "kate/kate.h"
-#endif
-#include "ffmpeg2theora.h"
-
-#ifndef __GNUC__
-/* Windows doesn't have strcasecmp but stricmp (at least, DOS had)
- (or was that strcmpi ? Might have been Borland C) */
-#define strcasecmp(s1, s2) stricmp(s1, s2)
-#endif
-
-
-#define SUPPORTED_ENCODINGS "utf-8, utf8, iso-8859-1, latin1"
-
-static void add_kate_stream(ff2theora this);
-extern int load_subtitles(ff2theora_kate_stream *this);
-extern void free_subtitles(ff2theora this);
-
-extern void set_subtitles_file(ff2theora this,const char *filename);
-extern void set_subtitles_language(ff2theora this,const char *language);
-extern void set_subtitles_category(ff2theora this,const char *category);
-extern void set_subtitles_encoding(ff2theora this,F2T_ENCODING encoding);
-extern void report_unknown_subtitle_encoding(const char *name);
-
-static char *fgets2(char *s,size_t sz,FILE *f);
-static double hmsms2s(int h,int m,int s,int ms);
-static void convert_subtitle_to_utf8(F2T_ENCODING encoding,unsigned char *text);
-#endif
-
Deleted: trunk/ffmpeg2theora/theorautils.c
===================================================================
--- trunk/ffmpeg2theora/theorautils.c 2008-05-23 17:55:53 UTC (rev 14949)
+++ trunk/ffmpeg2theora/theorautils.c 2008-05-23 17:56:21 UTC (rev 14950)
@@ -1,924 +0,0 @@
-/* -*- tab-width:4;c-file-style:"cc-mode"; -*- */
-/*
- * theorautils.c - Ogg Theora/Ogg Vorbis Abstraction and Muxing
- * Copyright (C) 2003-2008 <j at v2v.cc>
- *
- * 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-1307, USA.
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <time.h>
-
-#include "theora/theora.h"
-#include "vorbis/codec.h"
-#include "vorbis/vorbisenc.h"
-#ifdef HAVE_OGGKATE
-#include "kate/oggkate.h"
-#endif
-
-#include "theorautils.h"
-
-
-
-static double rint(double x)
-{
- if (x < 0.0)
- return (double)(int)(x - 0.5);
- else
- return (double)(int)(x + 0.5);
-}
-
-void init_info(oggmux_info *info) {
- info->with_skeleton = 1; /* skeleton is enabled by default */
- info->frontend = 0; /*frontend mode*/
- info->videotime = 0;
- info->audiotime = 0;
- info->audio_bytesout = 0;
- info->video_bytesout = 0;
- info->kate_bytesout = 0;
-
- info->videopage_valid = 0;
- info->audiopage_valid = 0;
- info->audiopage_buffer_length = 0;
- info->videopage_buffer_length = 0;
- info->audiopage = NULL;
- info->videopage = NULL;
- info->start_time = time(NULL);
- info->duration = -1;
- info->speed_level = -1;
-
- info->v_pkg=0;
- info->a_pkg=0;
- info->k_pkg=0;
-#ifdef OGGMUX_DEBUG
- info->a_page=0;
- info->v_page=0;
- info->k_page=0;
-#endif
-
- info->with_kate = 0;
- info->n_kate_streams = 0;
-}
-
-void oggmux_setup_kate_streams(oggmux_info *info, int n_kate_streams)
-{
- int n;
-
- info->n_kate_streams = n_kate_streams;
- if (n_kate_streams == 0) return;
- info->kate_streams = (oggmux_kate_stream*)malloc(n_kate_streams*sizeof(oggmux_kate_stream));
- for (n=0; n<n_kate_streams; ++n) {
- oggmux_kate_stream *ks=info->kate_streams+n;
- ks->katepage_valid = 0;
- ks->katepage_buffer_length = 0;
- ks->katepage = NULL;
- ks->katetime = 0;
- }
-}
-
-static void write16le(unsigned char *ptr,ogg_uint16_t v)
-{
- ptr[0]=v&0xff;
- ptr[1]=(v>>8)&0xff;
-}
-
-static void write32le(unsigned char *ptr,ogg_uint32_t v)
-{
- ptr[0]=v&0xff;
- ptr[1]=(v>>8)&0xff;
- ptr[2]=(v>>16)&0xff;
- ptr[3]=(v>>24)&0xff;
-}
-
-static void write64le(unsigned char *ptr,ogg_int64_t v)
-{
- ogg_uint32_t hi=v>>32;
- ptr[0]=v&0xff;
- ptr[1]=(v>>8)&0xff;
- ptr[2]=(v>>16)&0xff;
- ptr[3]=(v>>24)&0xff;
- ptr[4]=hi&0xff;
- ptr[5]=(hi>>8)&0xff;
- ptr[6]=(hi>>16)&0xff;
- ptr[7]=(hi>>24)&0xff;
-}
-
-void add_fishead_packet (oggmux_info *info) {
- ogg_packet op;
-
- memset (&op, 0, sizeof (op));
-
- op.packet = _ogg_calloc (64, sizeof(unsigned char));
- if (op.packet == NULL) return;
-
- memset (op.packet, 0, 64);
- memcpy (op.packet, FISHEAD_IDENTIFIER, 8); /* identifier */
- write16le(op.packet+8, SKELETON_VERSION_MAJOR); /* version major */
- write16le(op.packet+10, SKELETON_VERSION_MINOR); /* version minor */
- write64le(op.packet+12, (ogg_int64_t)0); /* presentationtime numerator */
- write64le(op.packet+20, (ogg_int64_t)1000); /* presentationtime denominator */
- write64le(op.packet+28, (ogg_int64_t)0); /* basetime numerator */
- write64le(op.packet+36, (ogg_int64_t)1000); /* basetime denominator */
- /* both the numerator are zero hence handled by the memset */
- write32le(op.packet+44, 0); /* UTC time, set to zero for now */
-
- op.b_o_s = 1; /* its the first packet of the stream */
- op.e_o_s = 0; /* its not the last packet of the stream */
- op.bytes = 64; /* length of the packet in bytes */
-
- ogg_stream_packetin (&info->so, &op); /* adding the packet to the skeleton stream */
- _ogg_free (op.packet);
-}
-
-/*
- * Adds the fishead packets in the skeleton output stream along with the e_o_s packet
- */
-void add_fisbone_packet (oggmux_info *info) {
- ogg_packet op;
- int n;
-
- if (!info->audio_only) {
- memset (&op, 0, sizeof (op));
- op.packet = _ogg_calloc (80, sizeof(unsigned char));
- if (op.packet == NULL) return;
-
- memset (op.packet, 0, 80);
- /* it will be the fisbone packet for the theora video */
- memcpy (op.packet, FISBONE_IDENTIFIER, 8); /* identifier */
- write32le(op.packet+8, FISBONE_MESSAGE_HEADER_OFFSET); /* offset of the message header fields */
- write32le(op.packet+12, info->to.serialno); /* serialno of the theora stream */
- write32le(op.packet+16, 3); /* number of header packets */
- /* granulerate, temporal resolution of the bitstream in samples/microsecond */
- write64le(op.packet+20, info->ti.fps_numerator); /* granulrate numerator */
- write64le(op.packet+28, info->ti.fps_denominator); /* granulrate denominator */
- write64le(op.packet+36, 0); /* start granule */
- write32le(op.packet+44, 0); /* preroll, for theora its 0 */
- *(op.packet+48) = theora_granule_shift (&info->ti); /* granule shift */
- memcpy(op.packet+FISBONE_SIZE, "Content-Type: video/theora\r\n", 28); /* message header field, Content-Type */
-
- op.b_o_s = 0;
- op.e_o_s = 0;
- op.bytes = 80; /* size of the packet in bytes */
-
- ogg_stream_packetin (&info->so, &op);
- _ogg_free (op.packet);
- }
-
- if (!info->video_only) {
- memset (&op, 0, sizeof (op));
- op.packet = _ogg_calloc (80, sizeof(unsigned char));
- if (op.packet == NULL) return;
-
- memset (op.packet, 0, 80);
- /* it will be the fisbone packet for the vorbis audio */
- memcpy (op.packet, FISBONE_IDENTIFIER, 8); /* identifier */
- write32le(op.packet+8, FISBONE_MESSAGE_HEADER_OFFSET); /* offset of the message header fields */
- write32le(op.packet+12, info->vo.serialno); /* serialno of the vorbis stream */
- write32le(op.packet+16, 3); /* number of header packet */
- /* granulerate, temporal resolution of the bitstream in Hz */
- write64le(op.packet+20, info->sample_rate); /* granulerate numerator */
- write64le(op.packet+28, (ogg_int64_t)1); /* granulerate denominator */
- write64le(op.packet+36, 0); /* start granule */
- write32le(op.packet+44, 2); /* preroll, for vorbis its 2 */
- *(op.packet+48) = 0; /* granule shift, always 0 for vorbis */
- memcpy (op.packet+FISBONE_SIZE, "Content-Type: audio/vorbis\r\n", 28);
- /* Important: Check the case of Content-Type for correctness */
-
- op.b_o_s = 0;
- op.e_o_s = 0;
- op.bytes = 80;
-
- ogg_stream_packetin (&info->so, &op);
- _ogg_free (op.packet);
- }
-
-#ifdef HAVE_KATE
- if (info->with_kate) {
- for (n=0; n<info->n_kate_streams; ++n) {
- oggmux_kate_stream *ks=info->kate_streams+n;
- memset (&op, 0, sizeof (op));
- op.packet = _ogg_calloc (86, sizeof(unsigned char));
- memset (op.packet, 0, 86);
- /* it will be the fisbone packet for the kate stream */
- memcpy (op.packet, FISBONE_IDENTIFIER, 8); /* identifier */
- write32le(op.packet+8, FISBONE_MESSAGE_HEADER_OFFSET); /* offset of the message header fields */
- write32le(op.packet+12, ks->ko.serialno); /* serialno of the vorbis stream */
- write32le(op.packet+16, ks->ki.num_headers); /* number of header packet */
- /* granulerate, temporal resolution of the bitstream in Hz */
- write64le(op.packet+20, ks->ki.gps_numerator); /* granulerate numerator */
- write64le(op.packet+28, ks->ki.gps_denominator); /* granulerate denominator */
- write64le(op.packet+36, 0); /* start granule */
- write32le(op.packet+44, 0); /* preroll, for kate it's 0 */
- *(op.packet+48) = ks->ki.granule_shift; /* granule shift */
- memcpy (op.packet+FISBONE_SIZE, "Content-Type: application/x-kate\r\n", 34);
- /* Important: Check the case of Content-Type for correctness */
-
- op.b_o_s = 0;
- op.e_o_s = 0;
- op.bytes = 86;
-
- ogg_stream_packetin (&info->so, &op);
- _ogg_free (op.packet);
- }
- }
-#endif
-}
-
-void oggmux_init (oggmux_info *info){
- ogg_page og;
- ogg_packet op;
-
- /* yayness. Set up Ogg output stream */
- srand (time (NULL));
- ogg_stream_init (&info->vo, rand ());
-
- if(!info->audio_only){
- ogg_stream_init (&info->to, rand ()); /* oops, add one ot the above */
- theora_encode_init (&info->td, &info->ti);
-
- if(info->speed_level >= 0) {
- int max_speed_level;
- theora_control(&info->td, TH_ENCCTL_GET_SPLEVEL_MAX, &max_speed_level, sizeof(int));
- if(info->speed_level > max_speed_level)
- info->speed_level = max_speed_level;
- theora_control(&info->td, TH_ENCCTL_SET_SPLEVEL, &info->speed_level, sizeof(int));
- }
- }
- /* init theora done */
-
- /* initialize Vorbis too, if we have audio. */
- if(!info->video_only){
- int ret;
- vorbis_info_init (&info->vi);
- /* Encoding using a VBR quality mode. */
- if(info->vorbis_quality>-99)
- ret =vorbis_encode_init_vbr (&info->vi, info->channels,info->sample_rate,info->vorbis_quality);
- else
- ret=vorbis_encode_init(&info->vi,info->channels,info->sample_rate,-1,info->vorbis_bitrate,-1);
-
- if (ret){
- fprintf (stderr,
- "The Vorbis encoder could not set up a mode according to\n"
- "the requested quality or bitrate.\n\n");
- exit (1);
- }
-
- vorbis_comment_init (&info->vc);
- vorbis_comment_add_tag (&info->vc, "ENCODER",PACKAGE_STRING);
- /* set up the analysis state and auxiliary encoding storage */
- vorbis_analysis_init (&info->vd, &info->vi);
- vorbis_block_init (&info->vd, &info->vb);
-
- }
- /* audio init done */
-
- /* initialize kate if we have subtitles */
- if (info->with_kate) {
- int ret, n;
-#ifdef HAVE_KATE
- for (n=0; n<info->n_kate_streams; ++n) {
- oggmux_kate_stream *ks=info->kate_streams+n;
- ogg_stream_init (&ks->ko, rand ()); /* oops, add one ot the above */
- ret = kate_encode_init (&ks->k, &ks->ki);
- if (ret<0) fprintf(stderr, "kate_encode_init: %d\n",ret);
- ret = kate_comment_init(&ks->kc);
- if (ret<0) fprintf(stderr, "kate_comment_init: %d\n",ret);
- kate_comment_add_tag (&ks->kc, "ENCODER",PACKAGE_STRING);
- }
-#endif
- }
- /* kate init done */
-
- /* first packet should be skeleton fishead packet, if skeleton is used */
-
- if (info->with_skeleton) {
- ogg_stream_init (&info->so, rand());
- add_fishead_packet (info);
- if (ogg_stream_pageout (&info->so, &og) != 1){
- fprintf (stderr, "Internal Ogg library error.\n");
- exit (1);
- }
- fwrite (og.header, 1, og.header_len, info->outfile);
- fwrite (og.body, 1, og.body_len, info->outfile);
- }
-
- /* write the bitstream header packets with proper page interleave */
-
- /* first packet will get its own page automatically */
- if(!info->audio_only){
- theora_encode_header (&info->td, &op);
- ogg_stream_packetin (&info->to, &op);
- if (ogg_stream_pageout (&info->to, &og) != 1){
- fprintf (stderr, "Internal Ogg library error.\n");
- exit (1);
- }
- fwrite (og.header, 1, og.header_len, info->outfile);
- fwrite (og.body, 1, og.body_len, info->outfile);
-
- /* create the remaining theora headers */
- /* theora_comment_init (&info->tc); is called in main() prior to parsing options */
- theora_comment_add_tag (&info->tc, "ENCODER",PACKAGE_STRING);
- theora_encode_comment (&info->tc, &op);
- ogg_stream_packetin (&info->to, &op);
- _ogg_free (op.packet);
-
- theora_encode_tables (&info->td, &op);
- ogg_stream_packetin (&info->to, &op);
- }
- if(!info->video_only){
- ogg_packet header;
- ogg_packet header_comm;
- ogg_packet header_code;
-
- vorbis_analysis_headerout (&info->vd, &info->vc, &header,
- &header_comm, &header_code);
- ogg_stream_packetin (&info->vo, &header); /* automatically placed in its own
- * page */
- if (ogg_stream_pageout (&info->vo, &og) != 1){
- fprintf (stderr, "Internal Ogg library error.\n");
- exit (1);
- }
- fwrite (og.header, 1, og.header_len, info->outfile);
- fwrite (og.body, 1, og.body_len, info->outfile);
-
- /* remaining vorbis header packets */
- ogg_stream_packetin (&info->vo, &header_comm);
- ogg_stream_packetin (&info->vo, &header_code);
- }
-
-#ifdef HAVE_KATE
- if (info->with_kate) {
- int n;
- for (n=0; n<info->n_kate_streams; ++n) {
- oggmux_kate_stream *ks=info->kate_streams+n;
- int ret;
- while (1) {
- ret=kate_ogg_encode_headers(&ks->k,&ks->kc,&op);
- if (ret==0) {
- ogg_stream_packetin(&ks->ko,&op);
- ogg_packet_clear(&op);
- }
- if (ret<0) fprintf(stderr, "kate_encode_headers: %d\n",ret);
- if (ret>0) break;
- }
-
- /* first header is on a separate page - libogg will do it automatically */
- ret=ogg_stream_pageout (&ks->ko, &og);
- if (ret!=1) {
- fprintf (stderr, "Internal Ogg library error.\n");
- exit (1);
- }
- fwrite (og.header, 1, og.header_len, info->outfile);
- fwrite (og.body, 1, og.body_len, info->outfile);
- }
- }
-#endif
-
- /* output the appropriate fisbone packets */
- if (info->with_skeleton) {
- add_fisbone_packet (info);
- while (1) {
- int result = ogg_stream_flush (&info->so, &og);
- if (result < 0){
- /* can't get here */
- fprintf (stderr, "Internal Ogg library error.\n");
- exit (1);
- }
- if (result == 0)
- break;
- fwrite (og.header, 1, og.header_len, info->outfile);
- fwrite (og.body, 1, og.body_len, info->outfile);
- }
- }
-
- if (!info->audio_only) {
- theora_info_clear(&info->ti);
- }
-
- /* Flush the rest of our headers. This ensures
- * the actual data in each stream will start
- * on a new page, as per spec. */
- while (1 && !info->audio_only){
- int result = ogg_stream_flush (&info->to, &og);
- if (result < 0){
- /* can't get here */
- fprintf (stderr, "Internal Ogg library error.\n");
- exit (1);
- }
- if (result == 0)
- break;
- fwrite (og.header, 1, og.header_len, info->outfile);
- fwrite (og.body, 1, og.body_len, info->outfile);
- }
- while (1 && !info->video_only){
- int result = ogg_stream_flush (&info->vo, &og);
- if (result < 0){
- /* can't get here */
- fprintf (stderr, "Internal Ogg library error.\n");
- exit (1);
- }
- if (result == 0)
- break;
- fwrite (og.header, 1, og.header_len,info->outfile);
- fwrite (og.body, 1, og.body_len, info->outfile);
- }
- if (info->with_kate) {
- int n;
- for (n=0; n<info->n_kate_streams; ++n) {
- oggmux_kate_stream *ks=info->kate_streams+n;
- while (1) {
- int result = ogg_stream_flush (&ks->ko, &og);
- if (result < 0){
- /* can't get here */
- fprintf (stderr, "Internal Ogg library error.\n");
- exit (1);
- }
- if (result == 0)
- break;
- fwrite (og.header, 1, og.header_len,info->outfile);
- fwrite (og.body, 1, og.body_len, info->outfile);
- }
- }
- }
-
- if (info->with_skeleton) {
- int result;
-
- /* build and add the e_o_s packet */
- memset (&op, 0, sizeof (op));
- op.b_o_s = 0;
- op.e_o_s = 1; /* its the e_o_s packet */
- op.granulepos = 0;
- op.bytes = 0; /* e_o_s packet is an empty packet */
- ogg_stream_packetin (&info->so, &op);
-
- result = ogg_stream_flush (&info->so, &og);
- if (result < 0){
- /* can't get here */
- fprintf (stderr, "Internal Ogg library error.\n");
- exit (1);
- }
- fwrite (og.header, 1, og.header_len,info->outfile);
- fwrite (og.body, 1, og.body_len, info->outfile);
- }
-}
-
-/**
- * adds a video frame to the encoding sink
- * if e_o_s is 1 the end of the logical bitstream will be marked.
- * @param this ff2theora struct
- * @param info oggmux_info
- * @param yuv_buffer
- * @param e_o_s 1 indicates ond of stream
- */
-void oggmux_add_video (oggmux_info *info, yuv_buffer *yuv, int e_o_s){
- ogg_packet op;
- theora_encode_YUVin (&info->td, yuv);
- while(theora_encode_packetout (&info->td, e_o_s, &op)) {
- ogg_stream_packetin (&info->to, &op);
- info->v_pkg++;
- }
-}
-
-/**
- * adds audio samples to encoding sink
- * @param buffer pointer to buffer
- * @param bytes bytes in buffer
- * @param samples samples in buffer
- * @param e_o_s 1 indicates end of stream.
- */
-void oggmux_add_audio (oggmux_info *info, int16_t * buffer, int bytes, int samples, int e_o_s){
- ogg_packet op;
-
- int i,j, count = 0;
- float **vorbis_buffer;
- if (bytes <= 0 && samples <= 0){
- /* end of audio stream */
- if(e_o_s)
- vorbis_analysis_wrote (&info->vd, 0);
- }
- else{
- vorbis_buffer = vorbis_analysis_buffer (&info->vd, samples);
- /* uninterleave samples */
- for (i = 0; i < samples; i++){
- for(j=0;j<info->channels;j++){
- vorbis_buffer[j][i] = buffer[count++] / 32768.f;
- }
- }
- vorbis_analysis_wrote (&info->vd, samples);
- }
- while(vorbis_analysis_blockout (&info->vd, &info->vb) == 1){
- /* analysis, assume we want to use bitrate management */
- vorbis_analysis (&info->vb, NULL);
- vorbis_bitrate_addblock (&info->vb);
-
- /* weld packets into the bitstream */
- while (vorbis_bitrate_flushpacket (&info->vd, &op)){
- ogg_stream_packetin (&info->vo, &op);
- info->a_pkg++;
- }
- }
-}
-
-/**
- * adds a subtitles text to the encoding sink
- * if e_o_s is 1 the end of the logical bitstream will be marked.
- * @param info oggmux_info
- * @param idx which kate stream to output to
- * @param t0 the show time of the text
- * @param t1 the hide time of the text
- * @param text the utf-8 text
- * @param len the number of bytes in the text
- * @param e_o_s 1 indicates end of stream
- */
-void oggmux_add_kate_text (oggmux_info *info, int idx, double t0, double t1, const char *text, size_t len, int e_o_s){
-#ifdef HAVE_KATE
- ogg_packet op;
- oggmux_kate_stream *ks=info->kate_streams+idx;
- int ret;
- ret = kate_ogg_encode_text(&ks->k, t0, t1, text, len, &op);
- if (ret>=0) {
- ogg_stream_packetin (&ks->ko, &op);
- info->k_pkg++;
- }
- else {
- fprintf(stderr, "Failed to encode kate data packet (%f --> %f, [%s]): %d",
- t0, t1, text, ret);
- }
- if(e_o_s) {
- ret = kate_ogg_encode_finish(&ks->k, -1, &op);
- if (ret>=0) {
- ogg_stream_packetin (&ks->ko, &op);
- info->k_pkg++;
- }
- else {
- fprintf(stderr, "Failed to encode kate end packet: %d", ret);
- }
- }
-#endif
-}
-
-/**
- * adds a kate end packet to the encoding sink
- * @param info oggmux_info
- * @param idx which kate stream to output to
- * @param t the time of the end packet
- */
-void oggmux_add_kate_end_packet (oggmux_info *info, int idx, double t){
-#ifdef HAVE_KATE
- ogg_packet op;
- oggmux_kate_stream *ks=info->kate_streams+idx;
- int ret;
- ret = kate_ogg_encode_finish(&ks->k, t, &op);
- if (ret>=0) {
- ogg_stream_packetin (&ks->ko, &op);
- info->k_pkg++;
- }
- else {
- fprintf(stderr, "Failed to encode kate end packet: %d", ret);
- }
-#endif
-}
-
-static double get_remaining(oggmux_info *info, double timebase) {
- double remaining = 0;
- double to_encode, time_so_far;
-
- if(info->duration != -1 && timebase > 0) {
- time_so_far = time(NULL) - info->start_time;
- to_encode = info->duration - timebase;
- if(to_encode > 0) {
- remaining = (time_so_far / timebase) * to_encode;
- }
- }
- return remaining;
-}
-
-static void print_stats(oggmux_info *info, double timebase){
- int hundredths = timebase * 100 - (long) timebase * 100;
- int seconds = (long) timebase % 60;
- int minutes = ((long) timebase / 60) % 60;
- int hours = (long) timebase / 3600;
- double remaining = get_remaining(info, timebase);
- int remaining_seconds = (long) remaining % 60;
- int remaining_minutes = ((long) remaining / 60) % 60;
- int remaining_hours = (long) remaining / 3600;
- if(info->frontend) {
- fprintf (stderr,"\nf2t ;position: %.02lf;audio_kbps: %d;video_kbps: %d;remaining: %.02lf\n",
- timebase,
- info->akbps, info->vkbps,
- remaining
- );
-
- }
- else {
- if(!remaining) {
- remaining = time(NULL) - info->start_time;
- remaining_seconds = (long) remaining % 60;
- remaining_minutes = ((long) remaining / 60) % 60;
- remaining_hours = (long) remaining / 3600;
- fprintf (stderr,"\r %d:%02d:%02d.%02d audio: %dkbps video: %dkbps, time elapsed: %02d:%02d:%02d ",
- hours, minutes, seconds, hundredths,
- info->akbps, info->vkbps,
- remaining_hours, remaining_minutes, remaining_seconds
- );
- }
- else {
- fprintf (stderr,"\r %d:%02d:%02d.%02d audio: %dkbps video: %dkbps, time remaining: %02d:%02d:%02d ",
- hours, minutes, seconds, hundredths,
- info->akbps, info->vkbps,
- remaining_hours, remaining_minutes, remaining_seconds
- );
- }
- }
-}
-
-static void write_audio_page(oggmux_info *info)
-{
- int ret;
-
- ret = fwrite(info->audiopage, 1, info->audiopage_len, info->outfile);
- if(ret < info->audiopage_len) {
- fprintf(stderr,"error writing audio page\n");
- }
- else {
- info->audio_bytesout += ret;
- }
- info->audiopage_valid = 0;
- info->a_pkg -=ogg_page_packets((ogg_page *)&info->audiopage);
-#ifdef OGGMUX_DEBUG
- info->a_page++;
- info->v_page=0;
- fprintf(stderr,"\naudio page %d (%d pkgs) | pkg remaining %d\n",info->a_page,ogg_page_packets((ogg_page *)&info->audiopage),info->a_pkg);
-#endif
-
- info->akbps = rint (info->audio_bytesout * 8. / info->audiotime * .001);
- if(info->akbps<0)
- info->akbps=0;
- print_stats(info, info->audiotime);
-}
-
-static void write_video_page(oggmux_info *info)
-{
- int ret;
-
- ret = fwrite(info->videopage, 1, info->videopage_len, info->outfile);
- if(ret < info->videopage_len) {
- fprintf(stderr,"error writing video page\n");
- }
- else {
- info->video_bytesout += ret;
- }
- info->videopage_valid = 0;
- info->v_pkg -= ogg_page_packets((ogg_page *)&info->videopage);
-#ifdef OGGMUX_DEBUG
- info->v_page++;
- info->a_page=0;
- fprintf(stderr,"\nvideo page %d (%d pkgs) | pkg remaining %d\n",info->v_page,ogg_page_packets((ogg_page *)&info->videopage),info->v_pkg);
-#endif
-
-
- info->vkbps = rint (info->video_bytesout * 8. / info->videotime * .001);
- if(info->vkbps<0)
- info->vkbps=0;
- print_stats(info, info->videotime);
-}
-
-static void write_kate_page(oggmux_info *info, int idx)
-{
- int ret;
- oggmux_kate_stream *ks=info->kate_streams+idx;
-
- ret = fwrite(ks->katepage, 1, ks->katepage_len, info->outfile);
- if(ret < ks->katepage_len) {
- fprintf(stderr,"error writing kate page\n");
- }
- else {
- info->kate_bytesout += ret;
- }
- ks->katepage_valid = 0;
- info->k_pkg -= ogg_page_packets((ogg_page *)&ks->katepage);
-#ifdef OGGMUX_DEBUG
- ks->k_page++;
- fprintf(stderr,"\nkate page %d (%d pkgs) | pkg remaining %d\n",ks->k_page,ogg_page_packets((ogg_page *)&info->katepage),info->k_pkg);
-#endif
-
-
- /*
- info->kkbps = rint (info->kate_bytesout * 8. / info->katetime * .001);
- if(info->kkbps<0)
- info->kkbps=0;
- print_stats(info, info->katetime);
- */
-}
-
-static int find_best_valid_kate_page(oggmux_info *info)
-{
- int n;
- double t=0.0;
- int best=-1;
- if (info->with_kate) for (n=0; n<info->n_kate_streams;++n) {
- oggmux_kate_stream *ks=info->kate_streams+n;
- if (ks->katepage_valid) {
- if (best==-1 || ks->katetime<t) {
- t=ks->katetime;
- best=n;
- }
- }
- }
- return best;
-}
-
-void oggmux_flush (oggmux_info *info, int e_o_s)
-{
- int n,len;
- ogg_page og;
- int best;
-
- /* flush out the ogg pages to info->outfile */
- while(1) {
- /* Get pages for both streams, if not already present, and if available.*/
- if(!info->audio_only && !info->videopage_valid) {
- // this way seeking is much better,
- // not sure if 23 packets is a good value. it works though
- int v_next=0;
- if(info->v_pkg>22 && ogg_stream_flush(&info->to, &og) > 0) {
- v_next=1;
- }
- else if(ogg_stream_pageout(&info->to, &og) > 0) {
- v_next=1;
- }
- if(v_next) {
- len = og.header_len + og.body_len;
- if(info->videopage_buffer_length < len) {
- info->videopage = realloc(info->videopage, len);
- info->videopage_buffer_length = len;
- }
- info->videopage_len = len;
- memcpy(info->videopage, og.header, og.header_len);
- memcpy(info->videopage+og.header_len , og.body, og.body_len);
-
- info->videopage_valid = 1;
- if(ogg_page_granulepos(&og)>0) {
- info->videotime = theora_granule_time (&info->td,
- ogg_page_granulepos(&og));
- }
- }
- }
- if(!info->video_only && !info->audiopage_valid) {
- // this way seeking is much better,
- // not sure if 23 packets is a good value. it works though
- int a_next=0;
- if(info->a_pkg>22 && ogg_stream_flush(&info->vo, &og) > 0) {
- a_next=1;
- }
- else if(ogg_stream_pageout(&info->vo, &og) > 0) {
- a_next=1;
- }
- if(a_next) {
- len = og.header_len + og.body_len;
- if(info->audiopage_buffer_length < len) {
- info->audiopage = realloc(info->audiopage, len);
- info->audiopage_buffer_length = len;
- }
- info->audiopage_len = len;
- memcpy(info->audiopage, og.header, og.header_len);
- memcpy(info->audiopage+og.header_len , og.body, og.body_len);
-
- info->audiopage_valid = 1;
- if(ogg_page_granulepos(&og)>0) {
- info->audiotime= vorbis_granule_time (&info->vd,
- ogg_page_granulepos(&og));
- }
- }
- }
-
-#ifdef HAVE_KATE
- if (info->with_kate) for (n=0; n<info->n_kate_streams; ++n) {
- oggmux_kate_stream *ks=info->kate_streams+n;
- if (!ks->katepage_valid) {
- int k_next=0;
- /* always flush kate stream */
- if (ogg_stream_flush(&ks->ko, &og) > 0) {
- k_next = 1;
- }
- if (k_next) {
- len = og.header_len + og.body_len;
- if(ks->katepage_buffer_length < len) {
- ks->katepage = realloc(ks->katepage, len);
- ks->katepage_buffer_length = len;
- }
- ks->katepage_len = len;
- memcpy(ks->katepage, og.header, og.header_len);
- memcpy(ks->katepage+og.header_len , og.body, og.body_len);
-
- ks->katepage_valid = 1;
- if(ogg_page_granulepos(&og)>0) {
- ks->katetime= kate_granule_time (&ks->ki,
- ogg_page_granulepos(&og));
- }
- }
- }
- }
-#endif
-
-#ifdef HAVE_KATE
-#define CHECK_KATE_OUTPUT(which) \
- if (best>=0 && info->kate_streams[best].katetime/*-1.0*/<=info->which##time) { \
- write_kate_page(info, best); \
- continue; \
- }
-#else
-#define CHECK_KATE_OUTPUT(which) ((void)0)
-#endif
-
- best=find_best_valid_kate_page(info);
-
- if(info->video_only && info->videopage_valid) {
- CHECK_KATE_OUTPUT(video);
- write_video_page(info);
- }
- else if(info->audio_only && info->audiopage_valid) {
- CHECK_KATE_OUTPUT(audio);
- write_audio_page(info);
- }
- /* We're using both. We can output only:
- * a) If we have valid pages for both
- * b) At EOS, for the remaining stream.
- */
- else if(info->videopage_valid && info->audiopage_valid) {
- /* Make sure they're in the right order. */
- if(info->videotime <= info->audiotime) {
- CHECK_KATE_OUTPUT(video);
- write_video_page(info);
- }
- else {
- CHECK_KATE_OUTPUT(audio);
- write_audio_page(info);
- }
- }
- else if(e_o_s && best>=0) {
- write_kate_page(info, best);
- }
- else if(e_o_s && info->videopage_valid) {
- write_video_page(info);
- }
- else if(e_o_s && info->audiopage_valid) {
- write_audio_page(info);
- }
- else {
- break; /* Nothing more writable at the moment */
- }
- }
-}
-
-void oggmux_close (oggmux_info *info){
- int n;
-
- ogg_stream_clear (&info->vo);
- vorbis_block_clear (&info->vb);
- vorbis_dsp_clear (&info->vd);
- vorbis_comment_clear (&info->vc);
- vorbis_info_clear (&info->vi);
-
- ogg_stream_clear (&info->to);
- theora_clear (&info->td);
-
-#ifdef HAVE_KATE
- for (n=0; n<info->n_kate_streams; ++n) {
- ogg_stream_clear (&info->kate_streams[n].ko);
- kate_comment_clear (&info->kate_streams[n].kc);
- kate_info_clear (&info->kate_streams[n].ki);
- kate_clear (&info->kate_streams[n].k);
- }
-#endif
-
- if (info->outfile && info->outfile != stdout)
- fclose (info->outfile);
-
- if(info->videopage)
- free(info->videopage);
- if(info->audiopage)
- free(info->audiopage);
-
- for (n=0; n<info->n_kate_streams; ++n) {
- if(info->kate_streams[n].katepage)
- free(info->kate_streams[n].katepage);
- }
-}
Deleted: trunk/ffmpeg2theora/theorautils.h
===================================================================
--- trunk/ffmpeg2theora/theorautils.h 2008-05-23 17:55:53 UTC (rev 14949)
+++ trunk/ffmpeg2theora/theorautils.h 2008-05-23 17:56:21 UTC (rev 14950)
@@ -1,143 +0,0 @@
-/* -*- tab-width:4;c-file-style:"cc-mode"; -*- */
-/*
- * theorautils.h -- Ogg Theora/Ogg Vorbis Abstraction and Muxing
- * Copyright (C) 2003-2005 <j at v2v.cc>
- *
- * 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-1307, USA.
- */
-#ifndef _F2T_THEORAUTILS_H_
-#define _F2T_THEORAUTILS_H_
-
-#include <stdint.h>
-#include "theora/theora.h"
-#include "vorbis/codec.h"
-#include "vorbis/vorbisenc.h"
-#ifdef HAVE_KATE
-#include "kate/kate.h"
-#endif
-#include "ogg/ogg.h"
-
-// #define OGGMUX_DEBUG
-
-#define SKELETON_VERSION_MAJOR 3
-#define SKELETON_VERSION_MINOR 0
-#define FISHEAD_IDENTIFIER "fishead\0"
-#define FISBONE_IDENTIFIER "fisbone\0"
-#define FISBONE_SIZE 52
-#define FISBONE_MESSAGE_HEADER_OFFSET 44
-
-typedef struct
-{
-#ifdef HAVE_KATE
- kate_state k;
- kate_info ki;
- kate_comment kc;
-#endif
- ogg_stream_state ko; /* take physical pages, weld into a logical
- * stream of packets */
- int katepage_valid;
- unsigned char *katepage;
- int katepage_len;
- int katepage_buffer_length;
- double katetime;
-}
-oggmux_kate_stream;
-
-typedef struct
-{
- /* the file the mixed ogg stream is written to */
- FILE *outfile;
-
- int audio_only;
- int video_only;
- int with_skeleton;
- int frontend;
- /* vorbis settings */
- int sample_rate;
- int channels;
- double vorbis_quality;
- int vorbis_bitrate;
-
- vorbis_info vi; /* struct that stores all the static vorbis bitstream settings */
- vorbis_comment vc; /* struct that stores all the user comments */
-
- /* theora settings */
- theora_info ti;
- theora_comment tc;
- int speed_level;
-
- /* state info */
- theora_state td;
- vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */
- vorbis_block vb; /* local working space for packet->PCM decode */
-
- int with_kate;
-
- /* used for muxing */
- ogg_stream_state to; /* take physical pages, weld into a logical
- * stream of packets */
- ogg_stream_state vo; /* take physical pages, weld into a logical
- * stream of packets */
- ogg_stream_state so; /* take physical pages, weld into a logical
- * stream of packets, used for skeleton stream */
-
- int audiopage_valid;
- int videopage_valid;
- unsigned char *audiopage;
- unsigned char *videopage;
- int videopage_len;
- int audiopage_len;
- int videopage_buffer_length;
- int audiopage_buffer_length;
-
- /* some stats */
- double audiotime;
- double videotime;
- double duration;
-
- int vkbps;
- int akbps;
- ogg_int64_t audio_bytesout;
- ogg_int64_t video_bytesout;
- ogg_int64_t kate_bytesout;
- time_t start_time;
-
- //to do some manual page flusing
- int v_pkg;
- int a_pkg;
- int k_pkg;
-#ifdef OGGMUX_DEBUG
- int a_page;
- int v_page;
- int k_page;
-#endif
-
- int n_kate_streams;
- oggmux_kate_stream *kate_streams;
-}
-oggmux_info;
-
-void init_info(oggmux_info *info);
-extern void oggmux_setup_kate_streams(oggmux_info *info, int n_kate_streams);
-extern void oggmux_init (oggmux_info *info);
-extern void oggmux_add_video (oggmux_info *info, yuv_buffer *yuv, int e_o_s);
-extern void oggmux_add_audio (oggmux_info *info, int16_t * readbuffer, int bytesread, int samplesread,int e_o_s);
-extern void oggmux_add_kate_text (oggmux_info *info, int idx, double t0, double t1, const char *text, size_t len,int e_o_s);
-extern void oggmux_add_kate_end_packet (oggmux_info *info, int idx, double t);
-extern void oggmux_flush (oggmux_info *info, int e_o_s);
-extern void oggmux_close (oggmux_info *info);
-
-
-#endif
More information about the commits
mailing list