]> git.sesse.net Git - ffmpeg/blobdiff - ffmpeg.c
Replace SYS_DARWIN by the more correct __APPLE_CC__, these preprocessor
[ffmpeg] / ffmpeg.c
index e1343edd681bbf41ef14b23ae76814db305d5b51..711a18f4f59aa9fb907ac777c2c26fdf6e62b4dc 100644 (file)
--- a/ffmpeg.c
+++ b/ffmpeg.c
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
+#include "config.h"
+#include <ctype.h>
+#include <string.h>
+#include <math.h>
+#include <stdlib.h>
+#include <errno.h>
 #include <signal.h>
 #include <limits.h>
 #include "avformat.h"
 #include "fifo.h"
 #include "avstring.h"
 
-#ifdef __MINGW32__
-#include <conio.h>
-#else
+#if !defined(HAVE_GETRUSAGE) && defined(HAVE_GETPROCESSTIMES)
+#include <windows.h>
+#endif
+
+#if defined(HAVE_TERMIOS_H)
 #include <unistd.h>
 #include <fcntl.h>
 #include <sys/ioctl.h>
 #include <sys/time.h>
 #include <termios.h>
 #include <sys/resource.h>
-#endif
-#ifdef CONFIG_OS2
-#include <sys/types.h>
-#include <sys/select.h>
-#include <stdlib.h>
+#elif defined(HAVE_CONIO_H)
+#include <conio.h>
 #endif
 #undef time //needed because HAVE_AV_CONFIG_H is defined on top
 #include <time.h>
@@ -75,7 +80,7 @@ typedef struct AVMetaDataMap {
 extern const OptionDef options[];
 
 static void show_help(void);
-static void show_license(void);
+static void opt_show_license(void);
 static int opt_default(const char *opt, const char *arg);
 
 #define MAX_FILES 20
@@ -121,10 +126,9 @@ static int video_rc_qmod_freq=0;
 #endif
 static char *video_rc_override_string=NULL;
 static char *video_rc_eq="tex^qComp";
-static int me_method = ME_EPZS;
 static int video_disable = 0;
 static int video_discard = 0;
-static int video_codec_id = CODEC_ID_NONE;
+static char *video_codec_name = NULL;
 static int video_codec_tag = 0;
 static int same_quality = 0;
 static int do_deinterlace = 0;
@@ -142,11 +146,12 @@ static int audio_sample_rate = 44100;
 static float audio_qscale = QSCALE_NONE;
 static int audio_disable = 0;
 static int audio_channels = 1;
-static int audio_codec_id = CODEC_ID_NONE;
+static char  *audio_codec_name = NULL;
 static int audio_codec_tag = 0;
 static char *audio_language = NULL;
 
-static int subtitle_codec_id = CODEC_ID_NONE;
+static int subtitle_disable = 0;
+static char *subtitle_codec_name = NULL;
 static char *subtitle_language = NULL;
 
 static float mux_preload= 0.5;
@@ -173,6 +178,7 @@ static int video_stream_copy = 0;
 static int subtitle_stream_copy = 0;
 static int video_sync_method= 1;
 static int audio_sync_method= 0;
+static float audio_drift_threshold= 0.1;
 static int copy_ts= 0;
 static int opt_shortest = 0; //
 static int video_global_header = 0;
@@ -200,16 +206,16 @@ static int input_sync;
 static uint64_t limit_filesize = 0; //
 
 static int pgmyuv_compatibility_hack=0;
-static int dts_delta_threshold = 10;
+static float dts_delta_threshold = 10;
 
 static int sws_flags = SWS_BICUBIC;
 
-const char **opt_names=NULL;
-int opt_name_count=0;
-AVCodecContext *avctx_opts[CODEC_TYPE_NB];
-AVFormatContext *avformat_opts;
-struct SwsContext *sws_opts;
-static int64_t timer_start = 0;
+static const char **opt_names;
+static int opt_name_count;
+static AVCodecContext *avctx_opts[CODEC_TYPE_NB];
+static AVFormatContext *avformat_opts;
+static struct SwsContext *sws_opts;
+static int64_t timer_start;
 
 static AVBitStreamFilterContext *video_bitstream_filters=NULL;
 static AVBitStreamFilterContext *audio_bitstream_filters=NULL;
@@ -277,7 +283,7 @@ typedef struct AVInputFile {
     int nb_streams;       /* nb streams we are aware of */
 } AVInputFile;
 
-#ifndef __MINGW32__
+#ifdef HAVE_TERMIOS_H
 
 /* init terminal so that we can grab keys */
 static struct termios oldtty;
@@ -285,7 +291,7 @@ static struct termios oldtty;
 
 static void term_exit(void)
 {
-#ifndef __MINGW32__
+#ifdef HAVE_TERMIOS_H
     tcsetattr (0, TCSANOW, &oldtty);
 #endif
 }
@@ -301,7 +307,7 @@ sigterm_handler(int sig)
 
 static void term_init(void)
 {
-#ifndef __MINGW32__
+#ifdef HAVE_TERMIOS_H
     struct termios tty;
 
     tcgetattr (0, &tty);
@@ -334,10 +340,7 @@ static void term_init(void)
 /* read a key without blocking */
 static int read_key(void)
 {
-#ifdef __MINGW32__
-    if(kbhit())
-        return(getch());
-#else
+#if defined(HAVE_TERMIOS_H)
     int n = 1;
     unsigned char ch;
 #ifndef CONFIG_BEOS_NETSERVER
@@ -357,6 +360,9 @@ static int read_key(void)
 
         return n;
     }
+#elif defined(HAVE_CONIO_H)
+    if(kbhit())
+        return(getch());
 #endif
     return -1;
 }
@@ -395,7 +401,7 @@ static double
 get_sync_ipts(const AVOutputStream *ost)
 {
     const AVInputStream *ist = ost->sync_ist;
-    return (double)(ist->pts + input_files_ts_offset[ist->file_index] - start_time)/AV_TIME_BASE;
+    return (double)(ist->pts - start_time)/AV_TIME_BASE;
 }
 
 static void write_frame(AVFormatContext *s, AVPacket *pkt, AVCodecContext *avctx, AVBitStreamFilterContext *bsfc){
@@ -448,7 +454,7 @@ static void do_audio_out(AVFormatContext *s,
 
         //FIXME resample delay
         if(fabs(delta) > 50){
-            if(ist->is_start){
+            if(ist->is_start || fabs(delta) > audio_drift_threshold*enc->sample_rate){
                 if(byte_delta < 0){
                     byte_delta= FFMAX(byte_delta, -size);
                     size += byte_delta;
@@ -603,8 +609,9 @@ static void pre_process_video_frame(AVInputStream *ist, AVPicture *picture, void
         picture2 = picture;
     }
 
-    frame_hook_process(picture2, dec->pix_fmt, dec->width, dec->height,
-                       1000000 * ist->pts / AV_TIME_BASE);
+    if (ENABLE_VHOOK)
+        frame_hook_process(picture2, dec->pix_fmt, dec->width, dec->height,
+                           1000000 * ist->pts / AV_TIME_BASE);
 
     if (picture != picture2)
         *picture = *picture2;
@@ -653,7 +660,7 @@ static void do_subtitle_out(AVFormatContext *s,
         pkt.stream_index = ost->index;
         pkt.data = subtitle_out;
         pkt.size = subtitle_out_size;
-        pkt.pts = av_rescale_q(av_rescale_q(pts, ist->st->time_base, AV_TIME_BASE_Q) + input_files_ts_offset[ist->file_index], AV_TIME_BASE_Q,  ost->st->time_base);
+        pkt.pts = av_rescale_q(pts, ist->st->time_base, ost->st->time_base);
         if (enc->codec_id == CODEC_ID_DVB_SUBTITLE) {
             /* XXX: the pts correction is handled here. Maybe handling
                it in the codec would be better */
@@ -845,7 +852,6 @@ static void do_video_stats(AVFormatContext *os, AVOutputStream *ost,
 {
     AVCodecContext *enc;
     int frame_number;
-    int64_t ti;
     double ti1, bitrate, avg_bitrate;
 
     /* this is executed just the first time do_video_stats is called */
@@ -857,7 +863,6 @@ static void do_video_stats(AVFormatContext *os, AVOutputStream *ost,
         }
     }
 
-    ti = INT64_MAX;
     enc = ost->st->codec;
     if (enc->codec_type == CODEC_TYPE_VIDEO) {
         frame_number = ost->frame_number;
@@ -965,7 +970,7 @@ static void print_report(AVFormatContext **output_files,
             vid = 1;
         }
         /* compute min output value */
-        pts = (double)ost->st->pts.val * ost->st->time_base.num / ost->st->time_base.den;
+        pts = (double)ost->st->pts.val * av_q2d(ost->st->time_base);
         if ((pts < ti1) && (pts > 0))
             ti1 = pts;
     }
@@ -1199,13 +1204,16 @@ static int output_packet(AVInputStream *ist, int ist_index,
                                             pkt->pts);
                             break;
                         default:
-                            av_abort();
+                            abort();
                         }
                     } else {
                         AVFrame avframe; //FIXME/XXX remove this
                         AVPacket opkt;
                         av_init_packet(&opkt);
 
+                        if (!ost->frame_number && !(pkt->flags & PKT_FLAG_KEY))
+                            continue;
+
                         /* no reencoding needed : output the packet directly */
                         /* force the input stream PTS */
 
@@ -1222,18 +1230,16 @@ static int output_packet(AVInputStream *ist, int ist_index,
 
                         opkt.stream_index= ost->index;
                         if(pkt->pts != AV_NOPTS_VALUE)
-                            opkt.pts= av_rescale_q(av_rescale_q(pkt->pts, ist->st->time_base, AV_TIME_BASE_Q) + input_files_ts_offset[ist->file_index], AV_TIME_BASE_Q,  ost->st->time_base);
+                            opkt.pts= av_rescale_q(pkt->pts, ist->st->time_base, ost->st->time_base);
                         else
                             opkt.pts= AV_NOPTS_VALUE;
 
-                        {
-                            int64_t dts;
                             if (pkt->dts == AV_NOPTS_VALUE)
-                                dts = ist->next_pts;
+                                opkt.dts = av_rescale_q(ist->next_pts, AV_TIME_BASE_Q, ost->st->time_base);
                             else
-                                dts= av_rescale_q(pkt->dts, ist->st->time_base, AV_TIME_BASE_Q);
-                            opkt.dts= av_rescale_q(dts + input_files_ts_offset[ist->file_index], AV_TIME_BASE_Q,  ost->st->time_base);
-                        }
+                                opkt.dts = av_rescale_q(pkt->dts, ist->st->time_base, ost->st->time_base);
+
+                        opkt.duration = av_rescale_q(pkt->duration, ist->st->time_base, ost->st->time_base);
                         opkt.flags= pkt->flags;
 
                         //FIXME remove the following 2 lines they shall be replaced by the bitstream filters
@@ -1333,6 +1339,13 @@ static int output_packet(AVInputStream *ist, int ist_index,
     return -1;
 }
 
+static void print_sdp(AVFormatContext **avc, int n)
+{
+    char sdp[2048];
+
+    avf_sdp_create(avc, n, sdp, sizeof(sdp));
+    printf("SDP:\n%s\n", sdp);
+}
 
 /*
  * The following code is the main loop of the file converter
@@ -1350,6 +1363,7 @@ static int av_encode(AVFormatContext **output_files,
     AVInputStream *ist, **ist_table = NULL;
     AVInputFile *file_table;
     int key;
+    int want_sdp = 1;
 
     file_table= (AVInputFile*) av_mallocz(nb_input_files * sizeof(AVInputFile));
     if (!file_table)
@@ -1498,16 +1512,28 @@ static int av_encode(AVFormatContext **output_files,
     /* for each output stream, we compute the right encoding parameters */
     for(i=0;i<nb_ostreams;i++) {
         ost = ost_table[i];
+        os = output_files[ost->file_index];
         ist = ist_table[ost->source_index];
 
         codec = ost->st->codec;
         icodec = ist->st->codec;
 
+        if (!ost->st->language[0])
+            av_strlcpy(ost->st->language, ist->st->language,
+                       sizeof(ost->st->language));
+
         if (ost->st->stream_copy) {
             /* if stream_copy is selected, no need to decode or encode */
             codec->codec_id = icodec->codec_id;
             codec->codec_type = icodec->codec_type;
-            if(!codec->codec_tag) codec->codec_tag = icodec->codec_tag;
+
+            if(!codec->codec_tag){
+                if(   !os->oformat->codec_tag
+                   || av_codec_get_id (os->oformat->codec_tag, icodec->codec_tag) > 0
+                   || av_codec_get_tag(os->oformat->codec_tag, icodec->codec_id) <= 0)
+                    codec->codec_tag = icodec->codec_tag;
+            }
+
             codec->bit_rate = icodec->bit_rate;
             codec->extradata= icodec->extradata;
             codec->extradata_size= icodec->extradata_size;
@@ -1521,6 +1547,8 @@ static int av_encode(AVFormatContext **output_files,
                 codec->channels = icodec->channels;
                 codec->frame_size = icodec->frame_size;
                 codec->block_align= icodec->block_align;
+                if(codec->block_align == 1 && codec->codec_id == CODEC_ID_MP3)
+                    codec->block_align= 0;
                 break;
             case CODEC_TYPE_VIDEO:
                 if(using_vhook) {
@@ -1535,7 +1563,7 @@ static int av_encode(AVFormatContext **output_files,
             case CODEC_TYPE_SUBTITLE:
                 break;
             default:
-                av_abort();
+                abort();
             }
         } else {
             switch(codec->codec_type) {
@@ -1571,7 +1599,7 @@ static int av_encode(AVFormatContext **output_files,
                                                     codec->sample_rate, icodec->sample_rate);
                     if(!ost->resample){
                         printf("Can't resample.  Aborting.\n");
-                        av_abort();
+                        abort();
                     }
                 }
                 ist->decoding_needed = 1;
@@ -1610,8 +1638,7 @@ static int av_encode(AVFormatContext **output_files,
                         fprintf(stderr, "Cannot allocate temp picture, check pix fmt\n");
                         exit(1);
                     }
-                    if (ENABLE_SWSCALER)
-                        sws_flags = av_get_int(sws_opts, "sws_flags", NULL);
+                    sws_flags = av_get_int(sws_opts, "sws_flags", NULL);
                     ost->img_resample_ctx = sws_getContext(
                             icodec->width - (frame_leftBand + frame_rightBand),
                             icodec->height - (frame_topBand + frame_bottomBand),
@@ -1634,7 +1661,7 @@ static int av_encode(AVFormatContext **output_files,
                 ist->decoding_needed = 1;
                 break;
             default:
-                av_abort();
+                abort();
                 break;
             }
             /* two pass mode */
@@ -1758,10 +1785,9 @@ static int av_encode(AVFormatContext **output_files,
         ist = ist_table[i];
         is = input_files[ist->file_index];
         ist->pts = 0;
-        ist->next_pts = av_rescale_q(ist->st->start_time, ist->st->time_base, AV_TIME_BASE_Q);
-        if(ist->st->start_time == AV_NOPTS_VALUE)
-            ist->next_pts=0;
-        if(input_files_ts_offset[ist->file_index])
+        ist->next_pts=0;
+        if(   input_files_ts_offset[ist->file_index] != -is->start_time
+           && !(is->start_time == AV_NOPTS_VALUE && input_files_ts_offset[ist->file_index]==0))
             ist->next_pts= AV_NOPTS_VALUE;
         ist->is_start = 1;
     }
@@ -1805,6 +1831,12 @@ static int av_encode(AVFormatContext **output_files,
             ret = AVERROR(EINVAL);
             goto fail;
         }
+        if (strcmp(output_files[i]->oformat->name, "rtp")) {
+            want_sdp = 0;
+        }
+    }
+    if (want_sdp) {
+        print_sdp(output_files, nb_output_files);
     }
 
     if ( !using_stdin && verbose >= 0) {
@@ -1880,7 +1912,10 @@ static int av_encode(AVFormatContext **output_files,
         is = input_files[file_index];
         if (av_read_frame(is, &pkt) < 0) {
             file_table[file_index].eof_reached = 1;
-            if (opt_shortest) break; else continue; //
+            if (opt_shortest)
+                break;
+            else
+                continue;
         }
 
         if (do_pkt_dump) {
@@ -1895,18 +1930,22 @@ static int av_encode(AVFormatContext **output_files,
         if (ist->discard)
             goto discard_packet;
 
+        if (pkt.dts != AV_NOPTS_VALUE)
+            pkt.dts += av_rescale_q(input_files_ts_offset[ist->file_index], AV_TIME_BASE_Q, ist->st->time_base);
+        if (pkt.pts != AV_NOPTS_VALUE)
+            pkt.pts += av_rescale_q(input_files_ts_offset[ist->file_index], AV_TIME_BASE_Q, ist->st->time_base);
+
 //        fprintf(stderr, "next:%"PRId64" dts:%"PRId64" off:%"PRId64" %d\n", ist->next_pts, pkt.dts, input_files_ts_offset[ist->file_index], ist->st->codec->codec_type);
         if (pkt.dts != AV_NOPTS_VALUE && ist->next_pts != AV_NOPTS_VALUE) {
-            int64_t delta= av_rescale_q(pkt.dts, ist->st->time_base, AV_TIME_BASE_Q) - ist->next_pts;
-            if(FFABS(delta) > 1LL*dts_delta_threshold*AV_TIME_BASE && !copy_ts){
+            int64_t pkt_dts= av_rescale_q(pkt.dts, ist->st->time_base, AV_TIME_BASE_Q);
+            int64_t delta= pkt_dts - ist->next_pts;
+            if((FFABS(delta) > 1LL*dts_delta_threshold*AV_TIME_BASE || pkt_dts+1<ist->pts)&& !copy_ts){
                 input_files_ts_offset[ist->file_index]-= delta;
                 if (verbose > 2)
                     fprintf(stderr, "timestamp discontinuity %"PRId64", new offset= %"PRId64"\n", delta, input_files_ts_offset[ist->file_index]);
-                for(i=0; i<file_table[file_index].nb_streams; i++){
-                    int index= file_table[file_index].ist_index + i;
-                    ist_table[index]->next_pts += delta;
-                    ist_table[index]->is_start=1;
-                }
+                pkt.dts-= av_rescale_q(delta, AV_TIME_BASE_Q, ist->st->time_base);
+                if(pkt.pts != AV_NOPTS_VALUE)
+                    pkt.pts-= av_rescale_q(delta, AV_TIME_BASE_Q, ist->st->time_base);
             }
         }
 
@@ -2345,32 +2384,20 @@ static void opt_video_standard(const char *arg)
     video_standard = av_strdup(arg);
 }
 
-static void opt_codec(int *pstream_copy, int *pcodec_id,
+static void opt_codec(int *pstream_copy, char **pcodec_name,
                       int codec_type, const char *arg)
 {
-    AVCodec *p;
-
+    av_freep(pcodec_name);
     if (!strcmp(arg, "copy")) {
         *pstream_copy = 1;
     } else {
-        p = first_avcodec;
-        while (p) {
-            if (!strcmp(p->name, arg) && p->type == codec_type)
-                break;
-            p = p->next;
-        }
-        if (p == NULL) {
-            fprintf(stderr, "Unknown codec '%s'\n", arg);
-            exit(1);
-        } else {
-            *pcodec_id = p->id;
-        }
+        *pcodec_name = av_strdup(arg);
     }
 }
 
 static void opt_audio_codec(const char *arg)
 {
-    opt_codec(&audio_stream_copy, &audio_codec_id, CODEC_TYPE_AUDIO, arg);
+    opt_codec(&audio_stream_copy, &audio_codec_name, CODEC_TYPE_AUDIO, arg);
 }
 
 static void opt_audio_tag(const char *arg)
@@ -2391,6 +2418,7 @@ static void opt_video_tag(const char *arg)
         video_codec_tag= arg[0] + (arg[1]<<8) + (arg[2]<<16) + (arg[3]<<24);
 }
 
+#ifdef CONFIG_VHOOK
 static void add_frame_hooker(const char *arg)
 {
     int argc = 0;
@@ -2411,44 +2439,16 @@ static void add_frame_hooker(const char *arg)
         exit(1);
     }
 }
-
-const char *motion_str[] = {
-    "zero",
-    "full",
-    "log",
-    "phods",
-    "epzs",
-    "x1",
-    "hex",
-    "umh",
-    "iter",
-    NULL,
-};
-
-static void opt_motion_estimation(const char *arg)
-{
-    const char **p;
-    p = motion_str;
-    for(;;) {
-        if (!*p) {
-            fprintf(stderr, "Unknown motion estimation method '%s'\n", arg);
-            exit(1);
-        }
-        if (!strcmp(*p, arg))
-            break;
-        p++;
-    }
-    me_method = (p - motion_str) + 1;
-}
+#endif
 
 static void opt_video_codec(const char *arg)
 {
-    opt_codec(&video_stream_copy, &video_codec_id, CODEC_TYPE_VIDEO, arg);
+    opt_codec(&video_stream_copy, &video_codec_name, CODEC_TYPE_VIDEO, arg);
 }
 
 static void opt_subtitle_codec(const char *arg)
 {
-    opt_codec(&subtitle_stream_copy, &subtitle_codec_id, CODEC_TYPE_SUBTITLE, arg);
+    opt_codec(&subtitle_stream_copy, &subtitle_codec_name, CODEC_TYPE_SUBTITLE, arg);
 }
 
 static void opt_map(const char *arg)
@@ -2511,6 +2511,27 @@ static void opt_input_ts_offset(const char *arg)
     input_ts_offset = parse_date(arg, 1);
 }
 
+static enum CodecID find_codec_or_die(const char *name, int type, int encoder)
+{
+    char *codec_string = encoder ? "encoder" : "decoder";
+    AVCodec *codec;
+
+    if(!name)
+        return CODEC_ID_NONE;
+    codec = encoder ?
+        avcodec_find_encoder_by_name(name) :
+        avcodec_find_decoder_by_name(name);
+    if(!codec) {
+        av_log(NULL, AV_LOG_ERROR, "Unknown %s '%s'\n", codec_string, name);
+        exit(1);
+    }
+    if(codec->type != type) {
+        av_log(NULL, AV_LOG_ERROR, "Invalid %s type '%s'\n", codec_string, name);
+        exit(1);
+    }
+    return codec->id;
+}
+
 static void opt_input_file(const char *filename)
 {
     AVFormatContext *ic;
@@ -2538,8 +2559,8 @@ static void opt_input_file(const char *filename)
     ap->pix_fmt = frame_pix_fmt;
     ap->channel = video_channel;
     ap->standard = video_standard;
-    ap->video_codec_id = video_codec_id;
-    ap->audio_codec_id = audio_codec_id;
+    ap->video_codec_id = find_codec_or_die(video_codec_name, CODEC_TYPE_VIDEO, 0);
+    ap->audio_codec_id = find_codec_or_die(audio_codec_name, CODEC_TYPE_AUDIO, 0);
     if(pgmyuv_compatibility_hack)
         ap->video_codec_id= CODEC_ID_PGMYUV;
 
@@ -2641,11 +2662,13 @@ static void opt_input_file(const char *filename)
         case CODEC_TYPE_DATA:
             break;
         case CODEC_TYPE_SUBTITLE:
+            if(subtitle_disable)
+                ic->streams[i]->discard = AVDISCARD_ALL;
             break;
         case CODEC_TYPE_UNKNOWN:
             break;
         default:
-            av_abort();
+            abort();
         }
     }
 
@@ -2664,13 +2687,15 @@ static void opt_input_file(const char *filename)
     rate_emu = 0;
 }
 
-static void check_audio_video_inputs(int *has_video_ptr, int *has_audio_ptr)
+static void check_audio_video_sub_inputs(int *has_video_ptr, int *has_audio_ptr,
+                                         int *has_subtitle_ptr)
 {
-    int has_video, has_audio, i, j;
+    int has_video, has_audio, has_subtitle, i, j;
     AVFormatContext *ic;
 
     has_video = 0;
     has_audio = 0;
+    has_subtitle = 0;
     for(j=0;j<nb_input_files;j++) {
         ic = input_files[j];
         for(i=0;i<ic->nb_streams;i++) {
@@ -2682,17 +2707,20 @@ static void check_audio_video_inputs(int *has_video_ptr, int *has_audio_ptr)
             case CODEC_TYPE_VIDEO:
                 has_video = 1;
                 break;
+            case CODEC_TYPE_SUBTITLE:
+                has_subtitle = 1;
+                break;
             case CODEC_TYPE_DATA:
             case CODEC_TYPE_UNKNOWN:
-            case CODEC_TYPE_SUBTITLE:
                 break;
             default:
-                av_abort();
+                abort();
             }
         }
     }
     *has_video_ptr = has_video;
     *has_audio_ptr = has_audio;
+    *has_subtitle_ptr = has_subtitle;
 }
 
 static void new_video_stream(AVFormatContext *oc)
@@ -2737,8 +2765,8 @@ static void new_video_stream(AVFormatContext *oc)
         AVCodec *codec;
 
         codec_id = av_guess_codec(oc->oformat, NULL, oc->filename, NULL, CODEC_TYPE_VIDEO);
-        if (video_codec_id != CODEC_ID_NONE)
-            codec_id = video_codec_id;
+        if (video_codec_name)
+            codec_id = find_codec_or_die(video_codec_name, CODEC_TYPE_VIDEO, 1);
 
         video_enc->codec_id = codec_id;
         codec = avcodec_find_encoder(codec_id);
@@ -2834,8 +2862,6 @@ static void new_video_stream(AVFormatContext *oc)
         if (do_psnr)
             video_enc->flags|= CODEC_FLAG_PSNR;
 
-        video_enc->me_method = me_method;
-
         /* two pass mode */
         if (do_pass) {
             if (do_pass == 1) {
@@ -2848,7 +2874,7 @@ static void new_video_stream(AVFormatContext *oc)
 
     /* reset some key parameters */
     video_disable = 0;
-    video_codec_id = CODEC_ID_NONE;
+    av_freep(&video_codec_name);
     video_stream_copy = 0;
 }
 
@@ -2895,8 +2921,8 @@ static void new_audio_stream(AVFormatContext *oc)
                 av_set_double(audio_enc, opt_names[i], d);
         }
 
-        if (audio_codec_id != CODEC_ID_NONE)
-            codec_id = audio_codec_id;
+        if (audio_codec_name)
+            codec_id = find_codec_or_die(audio_codec_name, CODEC_TYPE_AUDIO, 1);
         audio_enc->codec_id = codec_id;
 
         if (audio_qscale > QSCALE_NONE) {
@@ -2916,23 +2942,16 @@ static void new_audio_stream(AVFormatContext *oc)
 
     /* reset some key parameters */
     audio_disable = 0;
-    audio_codec_id = CODEC_ID_NONE;
+    av_freep(&audio_codec_name);
     audio_stream_copy = 0;
 }
 
-static void opt_new_subtitle_stream(void)
+static void new_subtitle_stream(AVFormatContext *oc)
 {
-    AVFormatContext *oc;
     AVStream *st;
     AVCodecContext *subtitle_enc;
     int i;
 
-    if (nb_output_files <= 0) {
-        fprintf(stderr, "At least one output file must be specified\n");
-        exit(1);
-    }
-    oc = output_files[nb_output_files - 1];
-
     st = av_new_stream(oc, oc->nb_streams);
     if (!st) {
         fprintf(stderr, "Could not alloc stream\n");
@@ -2951,7 +2970,7 @@ static void opt_new_subtitle_stream(void)
              if(d==d && (opt->flags&AV_OPT_FLAG_SUBTITLE_PARAM) && (opt->flags&AV_OPT_FLAG_ENCODING_PARAM))
                  av_set_double(subtitle_enc, opt_names[i], d);
         }
-        subtitle_enc->codec_id = subtitle_codec_id;
+        subtitle_enc->codec_id = find_codec_or_die(subtitle_codec_name, CODEC_TYPE_SUBTITLE, 1);
     }
 
     if (subtitle_language) {
@@ -2960,7 +2979,8 @@ static void opt_new_subtitle_stream(void)
         subtitle_language = NULL;
     }
 
-    subtitle_codec_id = CODEC_ID_NONE;
+    subtitle_disable = 0;
+    av_freep(&subtitle_codec_name);
     subtitle_stream_copy = 0;
 }
 
@@ -2986,10 +3006,22 @@ static void opt_new_video_stream(void)
     new_video_stream(oc);
 }
 
+static void opt_new_subtitle_stream(void)
+{
+    AVFormatContext *oc;
+    if (nb_output_files <= 0) {
+        fprintf(stderr, "At least one output file must be specified\n");
+        exit(1);
+    }
+    oc = output_files[nb_output_files - 1];
+    new_subtitle_stream(oc);
+}
+
 static void opt_output_file(const char *filename)
 {
     AVFormatContext *oc;
-    int use_video, use_audio, input_has_video, input_has_audio, i;
+    int use_video, use_audio, use_subtitle;
+    int input_has_video, input_has_audio, input_has_subtitle, i;
     AVFormatParameters params, *ap = &params;
 
     if (!strcmp(filename, "-"))
@@ -3000,7 +3032,7 @@ static void opt_output_file(const char *filename)
     if (!file_oformat) {
         file_oformat = guess_format(NULL, filename, NULL);
         if (!file_oformat) {
-            fprintf(stderr, "Unable for find a suitable output format for '%s'\n",
+            fprintf(stderr, "Unable to find a suitable output format for '%s'\n",
                     filename);
             exit(1);
         }
@@ -3018,17 +3050,21 @@ static void opt_output_file(const char *filename)
             exit(1);
         }
     } else {
-        use_video = file_oformat->video_codec != CODEC_ID_NONE || video_stream_copy || video_codec_id != CODEC_ID_NONE;
-        use_audio = file_oformat->audio_codec != CODEC_ID_NONE || audio_stream_copy || audio_codec_id != CODEC_ID_NONE;
+        use_video = file_oformat->video_codec != CODEC_ID_NONE || video_stream_copy || video_codec_name;
+        use_audio = file_oformat->audio_codec != CODEC_ID_NONE || audio_stream_copy || audio_codec_name;
+        use_subtitle = file_oformat->subtitle_codec != CODEC_ID_NONE || subtitle_stream_copy || subtitle_codec_name;
 
         /* disable if no corresponding type found and at least one
            input file */
         if (nb_input_files > 0) {
-            check_audio_video_inputs(&input_has_video, &input_has_audio);
+            check_audio_video_sub_inputs(&input_has_video, &input_has_audio,
+                                         &input_has_subtitle);
             if (!input_has_video)
                 use_video = 0;
             if (!input_has_audio)
                 use_audio = 0;
+            if (!input_has_subtitle)
+                use_subtitle = 0;
         }
 
         /* manual disable */
@@ -3038,6 +3074,9 @@ static void opt_output_file(const char *filename)
         if (video_disable) {
             use_video = 0;
         }
+        if (subtitle_disable) {
+            use_subtitle = 0;
+        }
 
         if (use_video) {
             new_video_stream(oc);
@@ -3047,6 +3086,10 @@ static void opt_output_file(const char *filename)
             new_audio_stream(oc);
         }
 
+        if (use_subtitle) {
+            new_subtitle_stream(oc);
+        }
+
         oc->timestamp = rec_timestamp;
 
         if (str_title)
@@ -3137,32 +3180,35 @@ static void opt_pass(const char *pass_str)
     do_pass = pass;
 }
 
-#if defined(__MINGW32__) || defined(CONFIG_OS2)
-static int64_t getutime(void)
-{
-  return av_gettime();
-}
-#else
 static int64_t getutime(void)
 {
+#ifdef HAVE_GETRUSAGE
     struct rusage rusage;
 
     getrusage(RUSAGE_SELF, &rusage);
     return (rusage.ru_utime.tv_sec * 1000000LL) + rusage.ru_utime.tv_usec;
-}
+#elif defined(HAVE_GETPROCESSTIMES)
+    HANDLE proc;
+    FILETIME c, e, k, u;
+    proc = GetCurrentProcess();
+    GetProcessTimes(proc, &c, &e, &k, &u);
+    return ((int64_t) u.dwHighDateTime << 32 | u.dwLowDateTime) / 10;
+#else
+    return av_gettime();
 #endif
+}
 
 #if defined(CONFIG_FFM_DEMUXER) || defined(CONFIG_FFM_MUXER)
 extern int ffm_nopts;
 #endif
 
-static void show_formats(void)
+static void opt_show_formats(void)
 {
     AVInputFormat *ifmt;
     AVOutputFormat *ofmt;
     URLProtocol *up;
     AVCodec *p, *p2;
-    const char **pp, *last_name;
+    const char *last_name;
 
     printf("File formats:\n");
     last_name= "000";
@@ -3263,26 +3309,14 @@ static void show_formats(void)
     printf("\n");
 
     printf("Frame size, frame rate abbreviations:\n ntsc pal qntsc qpal sntsc spal film ntsc-film sqcif qcif cif 4cif\n");
-    printf("Motion estimation methods:\n");
-    pp = motion_str;
-    while (*pp) {
-        printf(" %s", *pp);
-        if ((pp - motion_str + 1) == ME_ZERO)
-            printf("(fastest)");
-        else if ((pp - motion_str + 1) == ME_FULL)
-            printf("(slowest)");
-        else if ((pp - motion_str + 1) == ME_EPZS)
-            printf("(default)");
-        pp++;
-    }
-    printf("\n\n");
+    printf("\n");
     printf(
 "Note, the names of encoders and decoders do not always match, so there are\n"
 "several cases where the above table shows encoder only or decoder only entries\n"
 "even though both encoding and decoding are supported. For example, the h263\n"
 "decoder corresponds to the h263 and h263p encoders, for file formats it is even\n"
 "worse.\n");
-    exit(1);
+    exit(0);
 }
 
 static void parse_matrix_coeffs(uint16_t *dest, const char *str)
@@ -3314,6 +3348,12 @@ static void opt_intra_matrix(const char *arg)
     parse_matrix_coeffs(intra_matrix, arg);
 }
 
+static void opt_show_help(void)
+{
+    show_help();
+    exit(0);
+}
+
 static void opt_target(const char *arg)
 {
     int norm = -1;
@@ -3511,7 +3551,7 @@ static void opt_audio_bsf(const char *arg)
     *bsfp= bsfc;
 }
 
-static void show_version(void)
+static void opt_show_version(void)
 {
     /* TODO: add function interface to avutil and avformat */
     fprintf(stderr, "ffmpeg      " FFMPEG_VERSION "\n"
@@ -3519,7 +3559,7 @@ static void show_version(void)
            "libavcodec  %d\n"
            "libavformat %d\n",
            LIBAVUTIL_BUILD, avcodec_build(), LIBAVFORMAT_BUILD);
-    exit(1);
+    exit(0);
 }
 
 static int opt_default(const char *opt, const char *arg){
@@ -3534,7 +3574,7 @@ static int opt_default(const char *opt, const char *arg){
     }
     if(!o)
         o = av_set_string(avformat_opts, opt, arg);
-    if(ENABLE_SWSCALER && !o)
+    if(!o)
         o = av_set_string(sws_opts, opt, arg);
     if(!o){
         if(opt[0] == 'a')
@@ -3566,16 +3606,16 @@ static int opt_default(const char *opt, const char *arg){
 
 const OptionDef options[] = {
     /* main options */
-    { "L", 0, {(void*)show_license}, "show license" },
-    { "h", 0, {(void*)show_help}, "show help" },
-    { "version", 0, {(void*)show_version}, "show version" },
-    { "formats", 0, {(void*)show_formats}, "show available formats, codecs, protocols, ..." },
+    { "L", 0, {(void*)opt_show_license}, "show license" },
+    { "h", 0, {(void*)opt_show_help}, "show help" },
+    { "version", 0, {(void*)opt_show_version}, "show version" },
+    { "formats", 0, {(void*)opt_show_formats}, "show available formats, codecs, protocols, ..." },
     { "f", HAS_ARG, {(void*)opt_format}, "force format", "fmt" },
     { "i", HAS_ARG, {(void*)opt_input_file}, "input file name", "filename" },
     { "y", OPT_BOOL, {(void*)&file_overwrite}, "overwrite output files" },
     { "map", HAS_ARG | OPT_EXPERT, {(void*)opt_map}, "set input stream mapping", "file:stream[:syncfile:syncstream]" },
     { "map_meta_data", HAS_ARG | OPT_EXPERT, {(void*)opt_map_meta_data}, "set meta data information of outfile from infile", "outfile:infile" },
-    { "t", HAS_ARG, {(void*)opt_recording_time}, "set the recording time", "duration" },
+    { "t", HAS_ARG, {(void*)opt_recording_time}, "record or transcode \"duration\" seconds of audio/video", "duration" },
     { "fs", HAS_ARG | OPT_INT64, {(void*)&limit_filesize}, "set the limit file size in bytes", "limit_size" }, //
     { "ss", HAS_ARG, {(void*)opt_start_time}, "set the start time offset", "time_off" },
     { "itsoffset", HAS_ARG, {(void*)opt_input_ts_offset}, "set the input ts offset", "time_off" },
@@ -3599,10 +3639,11 @@ const OptionDef options[] = {
     { "threads", HAS_ARG | OPT_EXPERT, {(void*)opt_thread_count}, "thread count", "count" },
     { "vsync", HAS_ARG | OPT_INT | OPT_EXPERT, {(void*)&video_sync_method}, "video sync method", "" },
     { "async", HAS_ARG | OPT_INT | OPT_EXPERT, {(void*)&audio_sync_method}, "audio sync method", "" },
+    { "adrift_threshold", HAS_ARG | OPT_FLOAT | OPT_EXPERT, {(void*)&audio_drift_threshold}, "audio drift threshold", "" },
     { "vglobal", HAS_ARG | OPT_INT | OPT_EXPERT, {(void*)&video_global_header}, "video global header storage type", "" },
     { "copyts", OPT_BOOL | OPT_EXPERT, {(void*)&copy_ts}, "copy timestamps" },
     { "shortest", OPT_BOOL | OPT_EXPERT, {(void*)&opt_shortest}, "finish encoding within shortest input" }, //
-    { "dts_delta_threshold", HAS_ARG | OPT_INT | OPT_EXPERT, {(void*)&dts_delta_threshold}, "timestamp discontinuity delta threshold", "" },
+    { "dts_delta_threshold", HAS_ARG | OPT_FLOAT | OPT_EXPERT, {(void*)&dts_delta_threshold}, "timestamp discontinuity delta threshold", "" },
 
     /* video options */
     { "vframes", OPT_INT | HAS_ARG | OPT_VIDEO, {(void*)&max_frames[CODEC_TYPE_VIDEO]}, "set the number of video frames to record", "number" },
@@ -3628,8 +3669,6 @@ const OptionDef options[] = {
     { "rc_eq", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_video_rc_eq}, "set rate control equation", "equation" },
     { "rc_override", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_video_rc_override_string}, "rate control override for specific intervals", "override" },
     { "vcodec", HAS_ARG | OPT_VIDEO, {(void*)opt_video_codec}, "force video codec ('copy' to copy stream)", "codec" },
-    { "me", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_motion_estimation}, "set motion estimation method",
-      "method" },
     { "me_threshold", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_me_threshold}, "motion estimaton threshold",  "" },
     { "strict", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_strict}, "how strictly to follow the standards", "strictness" },
     { "sameq", OPT_BOOL | OPT_VIDEO, {(void*)&same_quality},
@@ -3641,7 +3680,9 @@ const OptionDef options[] = {
     { "psnr", OPT_BOOL | OPT_EXPERT | OPT_VIDEO, {(void*)&do_psnr}, "calculate PSNR of compressed frames" },
     { "vstats", OPT_EXPERT | OPT_VIDEO, {(void*)&opt_vstats}, "dump video coding statistics to file" },
     { "vstats_file", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_vstats_file}, "dump video coding statistics to file", "file" },
+#ifdef CONFIG_VHOOK
     { "vhook", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)add_frame_hooker}, "insert video processing module", "module" },
+#endif
     { "intra_matrix", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_intra_matrix}, "specify intra matrix coeffs", "matrix" },
     { "inter_matrix", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_inter_matrix}, "specify inter matrix coeffs", "matrix" },
     { "top", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_top_field_first}, "top=1/bottom=0/auto=-1 field first", "" },
@@ -3663,6 +3704,7 @@ const OptionDef options[] = {
     { "alang", HAS_ARG | OPT_STRING | OPT_AUDIO, {(void *)&audio_language}, "set the ISO 639 language code (3 letters) of the current audio stream" , "code" },
 
     /* subtitle options */
+    { "sn", OPT_BOOL | OPT_SUBTITLE, {(void*)&subtitle_disable}, "disable subtitle" },
     { "scodec", HAS_ARG | OPT_SUBTITLE, {(void*)opt_subtitle_codec}, "force subtitle codec ('copy' to copy stream)", "codec" },
     { "newsubtitle", OPT_SUBTITLE, {(void*)opt_new_subtitle_stream}, "add a new subtitle stream to the current output stream" },
     { "slang", HAS_ARG | OPT_STRING | OPT_SUBTITLE, {(void *)&subtitle_language}, "set the ISO 639 language code (3 letters) of the current subtitle stream" , "code" },
@@ -3698,43 +3740,10 @@ static void show_banner(void)
 #endif
 }
 
-static void show_license(void)
+static void opt_show_license(void)
 {
-    show_banner();
-#ifdef CONFIG_GPL
-    printf(
-    "FFmpeg is free software; you can redistribute it and/or modify\n"
-    "it under the terms of the GNU General Public License as published by\n"
-    "the Free Software Foundation; either version 2 of the License, or\n"
-    "(at your option) any later version.\n"
-    "\n"
-    "FFmpeg is distributed in the hope that it will be useful,\n"
-    "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
-    "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
-    "GNU General Public License for more details.\n"
-    "\n"
-    "You should have received a copy of the GNU General Public License\n"
-    "along with FFmpeg; if not, write to the Free Software\n"
-    "Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n"
-    );
-#else
-    printf(
-    "FFmpeg is free software; you can redistribute it and/or\n"
-    "modify it under the terms of the GNU Lesser General Public\n"
-    "License as published by the Free Software Foundation; either\n"
-    "version 2.1 of the License, or (at your option) any later version.\n"
-    "\n"
-    "FFmpeg is distributed in the hope that it will be useful,\n"
-    "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
-    "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n"
-    "Lesser General Public License for more details.\n"
-    "\n"
-    "You should have received a copy of the GNU Lesser General Public\n"
-    "License along with FFmpeg; if not, write to the Free Software\n"
-    "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n"
-    );
-#endif
-    exit(1);
+    show_license();
+    exit(0);
 }
 
 /**
@@ -3749,7 +3758,6 @@ static void log_callback_help(void* ptr, int level, const char* fmt, va_list vl)
 static void show_help(void)
 {
     av_log_set_callback(log_callback_help);
-    show_banner();
     printf("usage: ffmpeg [[infile options] -i infile]... {[outfile options] outfile}...\n"
            "Hyper fast Audio and Video encoder\n");
     printf("\n");
@@ -3778,15 +3786,7 @@ static void show_help(void)
                       OPT_EXPERT);
     av_opt_show(avctx_opts[0], NULL);
     av_opt_show(avformat_opts, NULL);
-    if (ENABLE_SWSCALER)
-        av_opt_show(sws_opts, NULL);
-
-    exit(1);
-}
-
-void parse_arg_file(const char *filename)
-{
-    opt_output_file(filename);
+    av_opt_show(sws_opts, NULL);
 }
 
 int main(int argc, char **argv)
@@ -3800,16 +3800,16 @@ int main(int argc, char **argv)
         avctx_opts[i]= avcodec_alloc_context2(i);
     }
     avformat_opts = av_alloc_format_context();
-    if (ENABLE_SWSCALER)
-        sws_opts = sws_getContext(16,16,0, 16,16,0, sws_flags, NULL,NULL,NULL);
+    sws_opts = sws_getContext(16,16,0, 16,16,0, sws_flags, NULL,NULL,NULL);
 
-    if (argc <= 1)
+    show_banner();
+    if (argc <= 1) {
         show_help();
-    else
-        show_banner();
+        exit(1);
+    }
 
     /* parse options */
-    parse_options(argc, argv, options);
+    parse_options(argc, argv, options, opt_output_file);
 
     /* file converter / grab */
     if (nb_output_files <= 0) {
@@ -3857,6 +3857,10 @@ int main(int argc, char **argv)
 
     av_free(opt_names);
 
+    av_free(video_codec_name);
+    av_free(audio_codec_name);
+    av_free(subtitle_codec_name);
+
     av_free(video_standard);
 
 #ifdef CONFIG_POWERPC_PERF