Skip to content
Snippets Groups Projects
ffmpeg.c 126 KiB
Newer Older
Fabrice Bellard's avatar
Fabrice Bellard committed
/*
 * FFmpeg main 
Fabrice Bellard's avatar
Fabrice Bellard committed
 * Copyright (c) 2000-2003 Fabrice Bellard
Fabrice Bellard's avatar
Fabrice Bellard committed
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
Fabrice Bellard's avatar
Fabrice Bellard committed
 *
 * This library is distributed in the hope that it will be useful,
Fabrice Bellard's avatar
Fabrice Bellard committed
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
Fabrice Bellard's avatar
Fabrice Bellard committed
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
Fabrice Bellard's avatar
Fabrice Bellard committed
 */
#define HAVE_AV_CONFIG_H
#include "avformat.h"
Fabrice Bellard's avatar
Fabrice Bellard committed
#ifndef CONFIG_WIN32
Fabrice Bellard's avatar
Fabrice Bellard committed
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <termios.h>
Fabrice Bellard's avatar
Fabrice Bellard committed
#include <sys/resource.h>
Fabrice Bellard's avatar
Fabrice Bellard committed
#endif
#ifdef CONFIG_OS2
#include <sys/types.h>
#include <sys/select.h>
#include <stdlib.h>
#endif
Michael Niedermayer's avatar
Michael Niedermayer committed
#undef time //needed because HAVE_AV_CONFIG_H is defined on top
#include <time.h>
Fabrice Bellard's avatar
Fabrice Bellard committed

Fabrice Bellard's avatar
Fabrice Bellard committed
#include "cmdutils.h"

#if !defined(INFINITY) && defined(HUGE_VAL)
#define INFINITY HUGE_VAL
#endif
Fabrice Bellard's avatar
Fabrice Bellard committed

/* select an input stream for an output stream */
typedef struct AVStreamMap {
    int file_index;
    int stream_index;
} AVStreamMap;

extern const OptionDef options[];

static void show_help(void);
static void show_license(void);
Fabrice Bellard's avatar
Fabrice Bellard committed

#define MAX_FILES 20

static AVFormatContext *input_files[MAX_FILES];
static int nb_input_files = 0;

static AVFormatContext *output_files[MAX_FILES];
static int nb_output_files = 0;

static AVStreamMap stream_maps[MAX_FILES];
static int nb_stream_maps;

static AVInputFormat *file_iformat;
static AVOutputFormat *file_oformat;
Fabrice Bellard's avatar
Fabrice Bellard committed
static int frame_width  = 160;
static int frame_height = 128;
static float frame_aspect_ratio = 0;
static enum PixelFormat frame_pix_fmt = PIX_FMT_YUV420P;
static int frame_padtop  = 0;
static int frame_padbottom = 0;
static int frame_padleft  = 0;
static int frame_padright = 0;
static int padcolor[3] = {16,128,128}; /* default to black */
static int frame_topBand  = 0;
static int frame_bottomBand = 0;
static int frame_leftBand  = 0;
static int frame_rightBand = 0;
static int frame_rate = 25;
static int frame_rate_base = 1;
static int video_bit_rate = 200*1000;
static int video_bit_rate_tolerance = 4000*1000;
static int video_qmin = 2;
static int video_qmax = 31;
Michael Niedermayer's avatar
Michael Niedermayer committed
static int video_lmin = 2*FF_QP2LAMBDA;
static int video_lmax = 31*FF_QP2LAMBDA;
Michael Niedermayer's avatar
Michael Niedermayer committed
static int video_mb_qmin = 2;
static int video_mb_qmax = 31;
static int video_qdiff = 3;
static float video_qblur = 0.5;
static float video_qcomp = 0.5;
static uint16_t *intra_matrix = NULL;
static uint16_t *inter_matrix = NULL;
#if 0 //experimental, (can be removed)
static float video_rc_qsquish=1.0;
static float video_rc_qmod_amp=0;
static int video_rc_qmod_freq=0;
static char *video_rc_override_string=NULL;
static char *video_rc_eq="tex^qComp";
static int video_rc_buffer_size=0;
static float video_rc_buffer_aggressivity=1.0;
static int video_rc_max_rate=0;
static int video_rc_min_rate=0;
static float video_rc_initial_cplx=0;
static float video_b_qfactor = 1.25;
static float video_b_qoffset = 1.25;
static float video_i_qoffset = 0.0;
static int video_intra_quant_bias= FF_DEFAULT_QUANT_BIAS;
static int video_inter_quant_bias= FF_DEFAULT_QUANT_BIAS;
Fabrice Bellard's avatar
Fabrice Bellard committed
static int video_disable = 0;
static int video_codec_id = CODEC_ID_NONE;
static int same_quality = 0;
static int b_frames = 0;
static int mb_decision = FF_MB_DECISION_SIMPLE;
static int ildct_cmp = FF_CMP_VSAD;
static int mb_cmp = FF_CMP_SAD;
static int sub_cmp = FF_CMP_SAD;
static int cmp = FF_CMP_SAD;
static int pre_cmp = FF_CMP_SAD;
static int pre_me = 0;
static float lumi_mask = 0;
static float dark_mask = 0;
static float scplx_mask = 0;
static float tcplx_mask = 0;
static float p_mask = 0;
static int use_4mv = 0;
static int use_obmc = 0;
static int use_loop = 0;
static int use_aiv = 0;
static int use_alt_scan = 0;
static int use_trell = 0;
static int use_scan_offset = 0;
Michael Niedermayer's avatar
Michael Niedermayer committed
static int use_qpel = 0;
static int qns = 0;
static int do_deinterlace = 0;
static int do_interlace_dct = 0;
static int do_interlace_me = 0;
static int workaround_bugs = FF_BUG_AUTODETECT;
static int error_resilience = 2;
static int error_concealment = 3;
static int dct_algo = 0;
static int use_part = 0;
static int packet_size = 0;
static int error_rate = 0;
static int strict = 0;
static int top_field_first = -1;
static int noise_reduction = 0;
Michael Niedermayer's avatar
Michael Niedermayer committed
static int debug = 0;
static int intra_dc_precision = 0;
static int coder = 0;
static int context = 0;
static int predictor = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
extern int loop_input; /* currently a hack */
Fabrice Bellard's avatar
Fabrice Bellard committed

static int gop_size = 12;
static int intra_only = 0;
static int audio_sample_rate = 44100;
static int audio_bit_rate = 64000;
static int audio_disable = 0;
static int audio_channels = 1;
static int audio_codec_id = CODEC_ID_NONE;

static int64_t recording_time = 0;
static int64_t start_time = 0;
Fabrice Bellard's avatar
Fabrice Bellard committed
static int file_overwrite = 0;
static char *str_title = NULL;
static char *str_author = NULL;
static char *str_copyright = NULL;
static char *str_comment = NULL;
Fabrice Bellard's avatar
Fabrice Bellard committed
static int do_benchmark = 0;
static int do_hex_dump = 0;
static int do_vstats = 0;
static int do_pass = 0;
static int bitexact = 0;
static char *pass_logfilename = NULL;
static int audio_stream_copy = 0;
static int video_stream_copy = 0;
static char *video_grab_format = "video4linux";
static char *video_standard = "ntsc";
static char *audio_grab_format = "audio_device";
static int thread_count= 1;
static int64_t video_size = 0;
static int64_t audio_size = 0;
static int64_t extra_size = 0;
#define DEFAULT_PASS_LOGFILENAME "ffmpeg2pass"
Fabrice Bellard's avatar
Fabrice Bellard committed

typedef struct AVOutputStream {
    int file_index;          /* file index */
    int index;               /* stream index in the output file */
    int source_index;        /* AVInputStream index */
    AVStream *st;            /* stream in the output file */
    int encoding_needed;     /* true if encoding needed for this stream */
    int frame_number;
    /* input pts and corresponding output pts
       for A/V sync */
    double sync_ipts;
    int64_t sync_opts;
Fabrice Bellard's avatar
Fabrice Bellard committed
    /* video only */
    int video_resample;      /* video_resample and video_crop are mutually exclusive */
    AVFrame pict_tmp;      /* temporary image for resampling */
Fabrice Bellard's avatar
Fabrice Bellard committed
    ImgReSampleContext *img_resample_ctx; /* for image resampling */

    int video_crop;          /* video_resample and video_crop are mutually exclusive */
    int topBand;             /* cropping area sizes */
    int leftBand;
Fabrice Bellard's avatar
Fabrice Bellard committed
    
    int video_pad;           /* video_resample and video_pad are mutually exclusive */
    int padtop;              /* padding area sizes */
    int padbottom;
    int padleft;
    int padright;
    
Fabrice Bellard's avatar
Fabrice Bellard committed
    /* audio only */
    int audio_resample;
    ReSampleContext *resample; /* for audio resampling */
    FifoBuffer fifo;     /* for compression: one audio fifo per codec */
Fabrice Bellard's avatar
Fabrice Bellard committed
} AVOutputStream;

typedef struct AVInputStream {
    int file_index;
    int index;
    AVStream *st;
    int discard;             /* true if stream data should be discarded */
    int decoding_needed;     /* true if the packets must be decoded in 'raw_fifo' */
    int64_t sample_index;      /* current sample */

    int64_t       start;     /* time when read started */
    unsigned long frame;     /* current frame */
    int64_t       next_pts;  /* synthetic pts for cases where pkt.pts
                                is not defined */
    int64_t       pts;       /* current pts */
Fabrice Bellard's avatar
Fabrice Bellard committed
} AVInputStream;

typedef struct AVInputFile {
    int eof_reached;      /* true if eof reached */
    int ist_index;        /* index of first stream in ist_table */
    int buffer_size;      /* current total buffer size */
    int buffer_size_max;  /* buffer size at which we consider we can stop
                             buffering */
    int nb_streams;       /* nb streams we are aware of */
Fabrice Bellard's avatar
Fabrice Bellard committed
} AVInputFile;

Fabrice Bellard's avatar
Fabrice Bellard committed
#ifndef CONFIG_WIN32

Fabrice Bellard's avatar
Fabrice Bellard committed
/* init terminal so that we can grab keys */
static struct termios oldtty;

static void term_exit(void)
{
    tcsetattr (0, TCSANOW, &oldtty);
}

static volatile sig_atomic_t received_sigterm = 0;

static void
sigterm_handler(int sig)
{
    received_sigterm = sig;
    term_exit();
}

Fabrice Bellard's avatar
Fabrice Bellard committed
static void term_init(void)
{
    struct termios tty;

    tcgetattr (0, &tty);
    oldtty = tty;

    tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
                          |INLCR|IGNCR|ICRNL|IXON);
    tty.c_oflag |= OPOST;
    tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN);
    tty.c_cflag &= ~(CSIZE|PARENB);
    tty.c_cflag |= CS8;
    tty.c_cc[VMIN] = 1;
    tty.c_cc[VTIME] = 0;
    
    tcsetattr (0, TCSANOW, &tty);

    signal(SIGINT , sigterm_handler); /* Interrupt (ANSI).  */
    signal(SIGQUIT, sigterm_handler); /* Quit (POSIX).  */
    signal(SIGTERM, sigterm_handler); /* Termination (ANSI).  */
    /*
    register a function to be called at normal program termination
    */
Fabrice Bellard's avatar
Fabrice Bellard committed
    atexit(term_exit);
#ifdef CONFIG_BEOS_NETSERVER
    fcntl(0, F_SETFL, fcntl(0, F_GETFL) | O_NONBLOCK);
#endif
Fabrice Bellard's avatar
Fabrice Bellard committed
}

/* read a key without blocking */
static int read_key(void)
{
Fabrice Bellard's avatar
Fabrice Bellard committed
    unsigned char ch;
#ifndef CONFIG_BEOS_NETSERVER
    struct timeval tv;
Fabrice Bellard's avatar
Fabrice Bellard committed
    fd_set rfds;

    FD_ZERO(&rfds);
    FD_SET(0, &rfds);
    tv.tv_sec = 0;
    tv.tv_usec = 0;
    n = select(1, &rfds, NULL, NULL, &tv);
Fabrice Bellard's avatar
Fabrice Bellard committed
    if (n > 0) {
Fabrice Bellard's avatar
Fabrice Bellard committed
            return ch;
Fabrice Bellard's avatar
Fabrice Bellard committed
    }
    return -1;
}

static int decode_interrupt_cb(void)
{
    return q_pressed || (q_pressed = read_key() == 'q');
}

Fabrice Bellard's avatar
Fabrice Bellard committed

static volatile int received_sigterm = 0;

/* no interactive support */
static void term_exit(void)
Fabrice Bellard's avatar
Fabrice Bellard committed
{
Fabrice Bellard's avatar
Fabrice Bellard committed

Fabrice Bellard's avatar
Fabrice Bellard committed

Fabrice Bellard's avatar
Fabrice Bellard committed
}

Fabrice Bellard's avatar
Fabrice Bellard committed

static int read_ffserver_streams(AVFormatContext *s, const char *filename)
Fabrice Bellard's avatar
Fabrice Bellard committed
{
Fabrice Bellard's avatar
Fabrice Bellard committed
    AVFormatContext *ic;

    err = av_open_input_file(&ic, filename, NULL, FFM_PACKET_SIZE, NULL);
    if (err < 0)
        return err;
Fabrice Bellard's avatar
Fabrice Bellard committed
    /* copy stream format */
    s->nb_streams = ic->nb_streams;
    for(i=0;i<ic->nb_streams;i++) {
        AVStream *st;
Michael Niedermayer's avatar
Michael Niedermayer committed

        st = av_mallocz(sizeof(AVStream));
Fabrice Bellard's avatar
Fabrice Bellard committed
        memcpy(st, ic->streams[i], sizeof(AVStream));
        s->streams[i] = st;
    }

    av_close_input_file(ic);
    return 0;
}

Fabrice Bellard's avatar
Fabrice Bellard committed

static void do_audio_out(AVFormatContext *s, 
                         AVOutputStream *ost, 
                         AVInputStream *ist,
                         unsigned char *buf, int size)
{
    uint8_t *buftmp;
    static uint8_t *audio_buf = NULL;
    static uint8_t *audio_out = NULL;
Michael Niedermayer's avatar
Michael Niedermayer committed
    const int audio_out_size= 4*MAX_AUDIO_PACKET_SIZE;
Fabrice Bellard's avatar
Fabrice Bellard committed
    int size_out, frame_bytes, ret;
    AVCodecContext *enc;

    /* SC: dynamic allocation of buffers */
    if (!audio_buf)
        audio_buf = av_malloc(2*MAX_AUDIO_PACKET_SIZE);
    if (!audio_out)
Michael Niedermayer's avatar
Michael Niedermayer committed
        audio_out = av_malloc(audio_out_size);
    if (!audio_buf || !audio_out)
        return;               /* Should signal an error ! */

    
Fabrice Bellard's avatar
Fabrice Bellard committed
    enc = &ost->st->codec;

    if (ost->audio_resample) {
        buftmp = audio_buf;
        size_out = audio_resample(ost->resample, 
                                  (short *)buftmp, (short *)buf,
                                  size / (ist->st->codec.channels * 2));
        size_out = size_out * enc->channels * 2;
    } else {
        buftmp = buf;
        size_out = size;
    }

    /* now encode as many frames as possible */
    if (enc->frame_size > 1) {
Fabrice Bellard's avatar
Fabrice Bellard committed
        /* output resampled raw samples */
        fifo_write(&ost->fifo, buftmp, size_out, 
                   &ost->fifo.wptr);

        frame_bytes = enc->frame_size * 2 * enc->channels;
        
        while (fifo_read(&ost->fifo, audio_buf, frame_bytes, 
                     &ost->fifo.rptr) == 0) {
Michael Niedermayer's avatar
Michael Niedermayer committed
            ret = avcodec_encode_audio(enc, audio_out, audio_out_size, 
            av_write_frame(s, ost->index, audio_out, ret);
Fabrice Bellard's avatar
Fabrice Bellard committed
        }
    } else {
        /* output a pcm frame */
        /* XXX: change encoding codec API to avoid this ? */
        switch(enc->codec->id) {
        case CODEC_ID_PCM_S16LE:
        case CODEC_ID_PCM_S16BE:
        case CODEC_ID_PCM_U16LE:
        case CODEC_ID_PCM_U16BE:
            break;
        default:
            size_out = size_out >> 1;
            break;
        }
        ret = avcodec_encode_audio(enc, audio_out, size_out, 
        av_write_frame(s, ost->index, audio_out, ret);
Fabrice Bellard's avatar
Fabrice Bellard committed
    }
}

static void pre_process_video_frame(AVInputStream *ist, AVPicture *picture, void **bufp)
{
    AVCodecContext *dec;
    AVPicture *picture2;
    AVPicture picture_tmp;
    uint8_t *buf = 0;

    dec = &ist->st->codec;

    /* deinterlace : must be done before any resize */
    if (do_deinterlace || using_vhook) {
        int size;

        /* create temporary picture */
        size = avpicture_get_size(dec->pix_fmt, dec->width, dec->height);
        buf = av_malloc(size);
        if (!buf)
            return;
        
        picture2 = &picture_tmp;
        avpicture_fill(picture2, buf, dec->pix_fmt, dec->width, dec->height);

Michael Niedermayer's avatar
Michael Niedermayer committed
        if (do_deinterlace){
            if(avpicture_deinterlace(picture2, picture, 
                                     dec->pix_fmt, dec->width, dec->height) < 0) {
                /* if error, do not deinterlace */
                av_free(buf);
                buf = NULL;
                picture2 = picture;
            }
        } else {
            if (img_convert(picture2, dec->pix_fmt, picture, 
                            dec->pix_fmt, dec->width, dec->height) < 0) {
                /* if error, do not copy */
                av_free(buf);
                buf = NULL;
                picture2 = picture;
            }
        }
    } else {
        picture2 = picture;
    }

    frame_hook_process(picture2, dec->pix_fmt, dec->width, dec->height);

    if (picture != picture2)
        *picture = *picture2;
    *bufp = buf;
}

/* we begin to correct av delay at this threshold */
#define AV_DELAY_MAX 0.100
Fabrice Bellard's avatar
Fabrice Bellard committed


/* Expects img to be yuv420 */
static void fill_pad_region(AVPicture* img, int height, int width,
        int padtop, int padbottom, int padleft, int padright, int *color) {
  
    int i, y, shift;
    uint8_t *optr;
    
    for (i = 0; i < 3; i++) {
        shift = (i == 0) ? 0 : 1;
        
        if (padtop || padleft) {
            memset(img->data[i], color[i], (((img->linesize[i] * padtop) + 
                            padleft) >> shift));
        }

        if (padleft || padright) {
            optr = img->data[i] + (img->linesize[i] * (padtop >> shift)) +
                (img->linesize[i] - (padright >> shift));

            for (y = 0; y < ((height - (padtop + padbottom)) >> shift); y++) {
                memset(optr, color[i], (padleft + padright) >> shift);
                optr += img->linesize[i];
            }
        }
      
        if (padbottom) {
            optr = img->data[i] + (img->linesize[i] * ((height - padbottom) >> shift));
            memset(optr, color[i], ((img->linesize[i] * padbottom) >> shift));
        }
    }
}


Fabrice Bellard's avatar
Fabrice Bellard committed
static void do_video_out(AVFormatContext *s, 
                         AVOutputStream *ost, 
                         AVInputStream *ist,
                         AVFrame *in_picture,
                         int *frame_size, AVOutputStream *audio_sync)
Fabrice Bellard's avatar
Fabrice Bellard committed
{
    AVFrame *final_picture, *formatted_picture;
    AVFrame picture_format_temp, picture_crop_temp;
    uint8_t *buf = NULL, *buf1 = NULL;
    enum PixelFormat target_pixfmt;
#define VIDEO_BUFFER_SIZE (1024*1024)

    avcodec_get_frame_defaults(&picture_format_temp);
    avcodec_get_frame_defaults(&picture_crop_temp);

Fabrice Bellard's avatar
Fabrice Bellard committed
    enc = &ost->st->codec;
Fabrice Bellard's avatar
Fabrice Bellard committed

    /* by default, we output a single frame */
    nb_frames = 1;

    /* NOTE: the A/V sync is always done by considering the audio is
       the master clock. It is suffisant for transcoding or playing,
       but not for the general case */
    if (audio_sync) {
        /* compute the A-V delay and duplicate/remove frames if needed */
        double adelta, vdelta, av_delay;

        adelta = audio_sync->sync_ipts - ((double)audio_sync->sync_opts * 
            s->pts_num / s->pts_den);

        vdelta = ost->sync_ipts - ((double)ost->sync_opts *
            s->pts_num / s->pts_den);

        av_delay = adelta - vdelta;
        if (av_delay < -AV_DELAY_MAX)
            nb_frames = 2;
        else if (av_delay > AV_DELAY_MAX)
            nb_frames = 0;
//        printf("adelta=%f vdelta=%f delay=%f nb=%d (A)\n", adelta, vdelta, av_delay, nb_frames);
        vdelta = (double)(ost->st->pts.val) * s->pts_num / s->pts_den - (ost->sync_ipts - ost->sync_ipts_offset);
        if (vdelta < 100 && vdelta > -100 && ost->sync_ipts_offset) {
            if (vdelta < -AV_DELAY_MAX)
                nb_frames = 2;
            else if (vdelta > AV_DELAY_MAX)
                nb_frames = 0;
        } else {
            ost->sync_ipts_offset -= vdelta;
            if (!ost->sync_ipts_offset)
                ost->sync_ipts_offset = 0.000001; /* one microsecond */
//        printf("delay=%f nb=%d (V)\n",vdelta, nb_frames);
    
#if defined(AVSYNC_DEBUG)
    {
        static char *action[] = { "drop frame", "copy frame", "dup frame" };
        if (audio_sync && verbose >=0) {
            fprintf(stderr, "Input APTS %12.6f, output APTS %12.6f, ",
                    (double) audio_sync->sync_ipts, 
                    (double) audio_sync->st->pts.val * s->pts_num / s->pts_den);
            fprintf(stderr, "Input VPTS %12.6f, output VPTS %12.6f: %s\n",
                    (double) ost->sync_ipts, 
                    (double) ost->st->pts.val * s->pts_num / s->pts_den,
                    action[nb_frames]);
        }
Fabrice Bellard's avatar
Fabrice Bellard committed
        return;
        video_buffer = av_malloc(VIDEO_BUFFER_SIZE);
    if (!video_buffer)
        return;
    /* convert pixel format if needed */
    target_pixfmt = ost->video_resample || ost->video_pad
        ? PIX_FMT_YUV420P : enc->pix_fmt;
    if (dec->pix_fmt != target_pixfmt) {
        int size;

        /* create temporary picture */
        size = avpicture_get_size(target_pixfmt, dec->width, dec->height);
Fabrice Bellard's avatar
Fabrice Bellard committed
        buf = av_malloc(size);
        formatted_picture = &picture_format_temp;
        avpicture_fill((AVPicture*)formatted_picture, buf, target_pixfmt, dec->width, dec->height);
        if (img_convert((AVPicture*)formatted_picture, target_pixfmt, 
                        (AVPicture *)in_picture, dec->pix_fmt, 
                        dec->width, dec->height) < 0) {

            if (verbose >= 0)
                fprintf(stderr, "pixel format conversion not handled\n");

    /* XXX: resampling could be done before raw format conversion in
       some cases to go faster */
    /* XXX: only works for YUV420P */
Fabrice Bellard's avatar
Fabrice Bellard committed
    if (ost->video_resample) {
        final_picture = &ost->pict_tmp;
        img_resample(ost->img_resample_ctx, (AVPicture*)final_picture, (AVPicture*)formatted_picture);
       
        if (ost->padtop || ost->padbottom || ost->padleft || ost->padright) {
            fill_pad_region((AVPicture*)final_picture, enc->height, enc->width,
                    ost->padtop, ost->padbottom, ost->padleft, ost->padright,
                    padcolor);
        }
        
	if (enc->pix_fmt != PIX_FMT_YUV420P) {
            int size;
	    
	    av_free(buf);
            /* create temporary picture */
            size = avpicture_get_size(enc->pix_fmt, enc->width, enc->height);
            buf = av_malloc(size);
            if (!buf)
                return;
            final_picture = &picture_format_temp;
            avpicture_fill((AVPicture*)final_picture, buf, enc->pix_fmt, enc->width, enc->height);
            if (img_convert((AVPicture*)final_picture, enc->pix_fmt, 
                            (AVPicture*)&ost->pict_tmp, PIX_FMT_YUV420P, 
                            enc->width, enc->height) < 0) {

                if (verbose >= 0)
                    fprintf(stderr, "pixel format conversion not handled\n");

    } else if (ost->video_crop) {
        picture_crop_temp.data[0] = formatted_picture->data[0] +
                (ost->topBand * formatted_picture->linesize[0]) + ost->leftBand;

        picture_crop_temp.data[1] = formatted_picture->data[1] +
                ((ost->topBand >> 1) * formatted_picture->linesize[1]) +
                (ost->leftBand >> 1);

        picture_crop_temp.data[2] = formatted_picture->data[2] +
                ((ost->topBand >> 1) * formatted_picture->linesize[2]) +
                (ost->leftBand >> 1);

        picture_crop_temp.linesize[0] = formatted_picture->linesize[0];
        picture_crop_temp.linesize[1] = formatted_picture->linesize[1];
        picture_crop_temp.linesize[2] = formatted_picture->linesize[2];
        final_picture = &picture_crop_temp;
    } else if (ost->video_pad) {
        final_picture = &ost->pict_tmp;

        for (i = 0; i < 3; i++) {
            uint8_t *optr, *iptr;
            int shift = (i == 0) ? 0 : 1;
            int y, yheight;
            
            /* set offset to start writing image into */
            optr = final_picture->data[i] + (((final_picture->linesize[i] * 
                            ost->padtop) + ost->padleft) >> shift);
            iptr = formatted_picture->data[i];

            yheight = (enc->height - ost->padtop - ost->padbottom) >> shift;
            for (y = 0; y < yheight; y++) {
                /* copy unpadded image row into padded image row */
                memcpy(optr, iptr, formatted_picture->linesize[i]);
                optr += final_picture->linesize[i];
                iptr += formatted_picture->linesize[i];
            }
        }

        fill_pad_region((AVPicture*)final_picture, enc->height, enc->width,
                ost->padtop, ost->padbottom, ost->padleft, ost->padright,
                padcolor);
        
        if (enc->pix_fmt != PIX_FMT_YUV420P) {
            int size;

            av_free(buf);
            /* create temporary picture */
            size = avpicture_get_size(enc->pix_fmt, enc->width, enc->height);
            buf = av_malloc(size);
            if (!buf)
                return;
            final_picture = &picture_format_temp;
            avpicture_fill((AVPicture*)final_picture, buf, enc->pix_fmt, enc->width, enc->height);
            if (img_convert((AVPicture*)final_picture, enc->pix_fmt, 
                        (AVPicture*)&ost->pict_tmp, PIX_FMT_YUV420P, 

                if (verbose >= 0)
                    fprintf(stderr, "pixel format conversion not handled\n");

Fabrice Bellard's avatar
Fabrice Bellard committed
    } else {
        final_picture = formatted_picture;
Fabrice Bellard's avatar
Fabrice Bellard committed
    }
    /* duplicates frame if needed */
    /* XXX: pb because no interleaving */
        if (s->oformat->flags & AVFMT_RAWPICTURE) {
            /* raw pictures are written as AVPicture structure to
               avoid any copies. We support temorarily the older
               method. */
            AVFrame* old_frame = enc->coded_frame;
	    enc->coded_frame = dec->coded_frame;
            av_write_frame(s, ost->index, 
                           (uint8_t *)final_picture, sizeof(AVPicture));
            AVFrame big_picture;
            /* better than nothing: use input picture interlaced
               settings */
            big_picture.interlaced_frame = in_picture->interlaced_frame;
            if(do_interlace_me || do_interlace_dct){
                if(top_field_first == -1)
                    big_picture.top_field_first = in_picture->top_field_first;
                else
                    big_picture.top_field_first = 1;
            }
Fabrice Bellard's avatar
Fabrice Bellard committed
            /* handles sameq here. This is not correct because it may
               not be a global option */
            if (same_quality) {
Michael Niedermayer's avatar
Michael Niedermayer committed
                big_picture.quality = ist->st->quality;
            }else
                big_picture.quality = ost->st->quality;
            big_picture.pts = AV_NOPTS_VALUE; //FIXME
            ret = avcodec_encode_video(enc, 
                                       video_buffer, VIDEO_BUFFER_SIZE,
Michael Niedermayer's avatar
Michael Niedermayer committed
                                       &big_picture);
            //enc->frame_number = enc->real_pict_num;
            av_write_frame(s, ost->index, video_buffer, ret);
Juanjo's avatar
Juanjo committed
            //fprintf(stderr,"\nFrame: %3d %3d size: %5d type: %d",
            //        enc->frame_number-1, enc->real_pict_num, ret,
Juanjo's avatar
Juanjo committed
            //        enc->pict_type);
            /* if two pass, output log */
            if (ost->logfile && enc->stats_out) {
                fprintf(ost->logfile, "%s", enc->stats_out);
            }
Fabrice Bellard's avatar
Fabrice Bellard committed
        }
Fabrice Bellard's avatar
Fabrice Bellard committed
    }
Fabrice Bellard's avatar
Fabrice Bellard committed
    av_free(buf);
    av_free(buf1);
Fabrice Bellard's avatar
Fabrice Bellard committed
}

static double psnr(double d){
    if(d==0) return INFINITY;
    return -10.0*log(d)/log(10.0);
static void do_video_stats(AVFormatContext *os, AVOutputStream *ost, 
                           int frame_size)
{
    static FILE *fvstats=NULL;
    char filename[40];
    time_t today2;
    struct tm *today;
    AVCodecContext *enc;
    int frame_number;
    int64_t ti;
    double ti1, bitrate, avg_bitrate;
    
    if (!fvstats) {
        today2 = time(NULL);
        today = localtime(&today2);
        sprintf(filename, "vstats_%02d%02d%02d.log", today->tm_hour,
                                               today->tm_min,
                                               today->tm_sec);
        fvstats = fopen(filename,"w");
        if (!fvstats) {
            perror("fopen");
            exit(1);
        }
    }
    
    ti = MAXINT64;
    enc = &ost->st->codec;
    if (enc->codec_type == CODEC_TYPE_VIDEO) {
        fprintf(fvstats, "frame= %5d q= %2.1f ", frame_number, enc->coded_frame->quality/(float)FF_QP2LAMBDA);
        if (enc->flags&CODEC_FLAG_PSNR)
            fprintf(fvstats, "PSNR= %6.2f ", psnr(enc->coded_frame->error[0]/(enc->width*enc->height*255.0*255.0)));
        
        fprintf(fvstats,"f_size= %6d ", frame_size);
        /* compute pts value */
        ti1 = (double)ost->st->pts.val * os->pts_num / os->pts_den;
        bitrate = (double)(frame_size * 8) * enc->frame_rate / enc->frame_rate_base / 1000.0;
        avg_bitrate = (double)(video_size * 8) / ti1 / 1000.0;
        fprintf(fvstats, "s_size= %8.0fkB time= %0.3f br= %7.1fkbits/s avg_br= %7.1fkbits/s ",
            (double)video_size / 1024, ti1, bitrate, avg_bitrate);
Falk Hüffner's avatar
Falk Hüffner committed
        fprintf(fvstats,"type= %c\n", av_get_pict_type_char(enc->coded_frame->pict_type));        
static void print_report(AVFormatContext **output_files,
			 AVOutputStream **ost_table, int nb_ostreams,
			 int is_last_report)
{
    char buf[1024];
    AVOutputStream *ost;
    AVFormatContext *oc, *os;
    int64_t total_size;
    AVCodecContext *enc;
    int frame_number, vid, i;
    double bitrate, ti1, pts;
    static int64_t last_time = -1;
        int64_t cur_time;
        /* display the report every 0.5 seconds */
        cur_time = av_gettime();
        if (last_time == -1) {
            last_time = cur_time;
            return;
        } 
        if ((cur_time - last_time) < 500000)
            return;
        last_time = cur_time;
    }

    oc = output_files[0];

    total_size = url_ftell(&oc->pb);
    
    buf[0] = '\0';
    ti1 = 1e10;
    vid = 0;
    for(i=0;i<nb_ostreams;i++) {
        ost = ost_table[i];
        os = output_files[ost->file_index];
        enc = &ost->st->codec;
        if (vid && enc->codec_type == CODEC_TYPE_VIDEO) {
Michael Niedermayer's avatar
Michael Niedermayer committed
            sprintf(buf + strlen(buf), "q=%2.1f ",
                    enc->coded_frame->quality/(float)FF_QP2LAMBDA);
        if (!vid && enc->codec_type == CODEC_TYPE_VIDEO) {
            frame_number = ost->frame_number;
Michael Niedermayer's avatar
Michael Niedermayer committed
            sprintf(buf + strlen(buf), "frame=%5d q=%2.1f ",
                    frame_number, enc->coded_frame ? enc->coded_frame->quality/(float)FF_QP2LAMBDA : 0);
            if(is_last_report)
                sprintf(buf + strlen(buf), "L");
            if (enc->flags&CODEC_FLAG_PSNR){
                int j;
                double error, error_sum=0;
                double scale, scale_sum=0;
                char type[3]= {'Y','U','V'};
                sprintf(buf + strlen(buf), "PSNR=");
                for(j=0; j<3; j++){
                    if(is_last_report){
                        error= enc->error[j];
                        scale= enc->width*enc->height*255.0*255.0*frame_number;
                    }else{
                        error= enc->coded_frame->error[j];
                        scale= enc->width*enc->height*255.0*255.0;
                    }
                    if(j) scale/=4;
                    error_sum += error;
                    scale_sum += scale;
                    sprintf(buf + strlen(buf), "%c:%2.2f ", type[j], psnr(error/scale));
                }
                sprintf(buf + strlen(buf), "*:%2.2f ", psnr(error_sum/scale_sum));
            }
            vid = 1;
        }
        /* compute min output value */
        pts = (double)ost->st->pts.val * os->pts_num / os->pts_den;
    if (verbose || is_last_report) {
        bitrate = (double)(total_size * 8) / ti1 / 1000.0;
        
        sprintf(buf + strlen(buf), 
            "size=%8.0fkB time=%0.1f bitrate=%6.1fkbits/s",
            (double)total_size / 1024, ti1, bitrate);
        if (verbose >= 0)
            fprintf(stderr, "%s    \r", buf);

    if (is_last_report && verbose >= 0){
        int64_t raw= audio_size + video_size + extra_size;
        fprintf(stderr, "video:%1.0fkB audio:%1.0fkB global headers:%1.0fkB muxing overhead %f%%\n",
                video_size/1024.0,
                audio_size/1024.0,
                extra_size/1024.0,
                100.0*(total_size - raw)/raw
        );
    }
/* pkt = NULL means EOF (needed to flush decoder buffers) */
static int output_packet(AVInputStream *ist, int ist_index,
                         AVOutputStream **ost_table, int nb_ostreams,
{
    AVFormatContext *os;
    AVOutputStream *ost;
    uint8_t *ptr;
    int len, ret, i;
    uint8_t *data_buf;
    int data_size, got_picture;