Newer
Older
* 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.
* This library is distributed in the hope that it will be useful,
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* 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
#define HAVE_AV_CONFIG_H
#include "avformat.h"
#include "framehook.h"
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <termios.h>
Roumen Petrov
committed
#include <signal.h>
#ifdef CONFIG_OS2
#include <sys/types.h>
#include <sys/select.h>
#include <stdlib.h>
#endif
#if !defined(INFINITY) && defined(HUGE_VAL)
#define INFINITY HUGE_VAL
#endif
/* 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);
#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
committed
static AVImageFormat *image_format;
static float frame_aspect_ratio = 0;
static enum PixelFormat frame_pix_fmt = PIX_FMT_YUV420P;
Michael Niedermayer
committed
static int frame_topBand = 0;
static int frame_bottomBand = 0;
static int frame_leftBand = 0;
static int frame_rightBand = 0;
Michael Niedermayer
committed
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;
Michael Niedermayer
committed
static float video_qscale = 0;
static int video_qmin = 2;
static int video_qmax = 31;
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;
Vidar Madsen
committed
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;
Michael Niedermayer
committed
static float video_i_qfactor = -0.8;
Michael Niedermayer
committed
static int me_method = ME_EPZS;
static int video_disable = 0;
static int video_codec_id = CODEC_ID_NONE;
static int same_quality = 0;
static int mb_decision = FF_MB_DECISION_SIMPLE;
static int mb_cmp = FF_CMP_SAD;
static int sub_cmp = FF_CMP_SAD;
static int cmp = FF_CMP_SAD;
Michael Niedermayer
committed
static int use_aic = 0;
Michael Niedermayer
committed
static int use_umv = 0;
static int do_deinterlace = 0;
static int do_interlace = 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 idct_algo = 0;
static int use_part = 0;
static int packet_size = 0;
Wolfgang Hesseler
committed
static int debug_mv = 0;
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 start_time = 0;
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;
static int do_hex_dump = 0;
static int do_pkt_dump = 0;
static int do_psnr = 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;
Max Krasnyansky
committed
static int rate_emu = 0;
static char *video_grab_format = "video4linux";
Fabrice Bellard
committed
static char *video_device = NULL;
Fabrice Bellard
committed
static int video_channel = 0;
static char *video_standard = "ntsc";
Fabrice Bellard
committed
static char *audio_grab_format = "audio_device";
Fabrice Bellard
committed
static char *audio_device = NULL;
static int using_stdin = 0;
static int using_vhook = 0;
static int verbose = 1;
#define DEFAULT_PASS_LOGFILENAME "ffmpeg2pass"
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 */
Fabrice Bellard
committed
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;
double sync_ipts_offset;
int video_resample; /* video_resample and video_crop are mutually exclusive */
AVPicture pict_tmp; /* temporary image for resampling */
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;
int audio_resample;
ReSampleContext *resample; /* for audio resampling */
FifoBuffer fifo; /* for compression: one audio fifo per codec */
} 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 */
Max Krasnyansky
committed
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 */
} 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 */
/* init terminal so that we can grab keys */
static struct termios oldtty;
static void term_exit(void)
{
tcsetattr (0, TCSANOW, &oldtty);
}
Roumen Petrov
committed
static volatile sig_atomic_t received_sigterm = 0;
static void
sigterm_handler(int sig)
{
received_sigterm = sig;
term_exit();
}
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);
Roumen Petrov
committed
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
*/
#ifdef CONFIG_BEOS_NETSERVER
fcntl(0, F_SETFL, fcntl(0, F_GETFL) | O_NONBLOCK);
#endif
}
/* read a key without blocking */
static int read_key(void)
{
int n = 1;
#ifndef CONFIG_BEOS_NETSERVER
struct timeval tv;
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);
#endif
n = read(0, &ch, 1);
if (n == 1)
return n;
#else
static volatile int received_sigterm = 0;
/* no interactive support */
static void term_exit(void)
}
static void term_init(void)
{
}
static int read_key(void)
{
return 0;
#endif
static int read_ffserver_streams(AVFormatContext *s, const char *filename)
int i, err;
err = av_open_input_file(&ic, filename, NULL, FFM_PACKET_SIZE, NULL);
if (err < 0)
return err;
/* copy stream format */
s->nb_streams = ic->nb_streams;
for(i=0;i<ic->nb_streams;i++) {
AVStream *st;
st = av_mallocz(sizeof(AVStream));
memcpy(st, ic->streams[i], sizeof(AVStream));
s->streams[i] = st;
}
av_close_input_file(ic);
return 0;
}
Fabrice Bellard
committed
#define MAX_AUDIO_PACKET_SIZE (128 * 1024)
static void do_audio_out(AVFormatContext *s,
AVOutputStream *ost,
AVInputStream *ist,
unsigned char *buf, int size)
{
Sylvain Corré
committed
static uint8_t *audio_buf = NULL;
static uint8_t *audio_out = NULL;
Sylvain Corré
committed
Sylvain Corré
committed
/* SC: dynamic allocation of buffers */
if (!audio_buf)
audio_buf = av_malloc(2*MAX_AUDIO_PACKET_SIZE);
if (!audio_out)
Sylvain Corré
committed
if (!audio_buf || !audio_out)
return; /* Should signal an error ! */
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) {
/* 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) {
(short *)audio_buf);
Fabrice Bellard
committed
av_write_frame(s, ost->index, audio_out, ret);
/* 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,
(short *)buftmp);
Fabrice Bellard
committed
av_write_frame(s, ost->index, audio_out, ret);
static void pre_process_video_frame(AVInputStream *ist, AVPicture *picture, void **bufp)
{
AVCodecContext *dec;
AVPicture *picture2;
AVPicture picture_tmp;
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);
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;
}
Fabrice Bellard
committed
/* we begin to correct av delay at this threshold */
#define AV_DELAY_MAX 0.100
static void do_video_out(AVFormatContext *s,
AVOutputStream *ost,
AVInputStream *ist,
Fabrice Bellard
committed
int *frame_size, AVOutputStream *audio_sync)
Fabrice Bellard
committed
int nb_frames, i, ret;
AVPicture *final_picture, *formatted_picture;
AVPicture picture_format_temp, picture_crop_temp;
static uint8_t *video_buffer;
uint8_t *buf = NULL, *buf1 = NULL;
AVCodecContext *enc, *dec;
enum PixelFormat target_pixfmt;
dec = &ist->st->codec;
Fabrice Bellard
committed
/* by default, we output a single frame */
nb_frames = 1;
Philip Gladstone
committed
*frame_size = 0;
Fabrice Bellard
committed
/* 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;
// printf("delay=%f\n", av_delay);
if (av_delay < -AV_DELAY_MAX)
nb_frames = 2;
else if (av_delay > AV_DELAY_MAX)
nb_frames = 0;
} else {
double vdelta;
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 */
}
Fabrice Bellard
committed
}
{
static char *action[] = { "drop frame", "copy frame", "dup frame" };
if (audio_sync)
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
committed
if (nb_frames <= 0)
if (!video_buffer)
Fabrice Bellard
committed
video_buffer = av_malloc(VIDEO_BUFFER_SIZE);
if (!video_buffer)
return;
/* convert pixel format if needed */
target_pixfmt = ost->video_resample ? 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);
if (!buf)
return;
formatted_picture = &picture_format_temp;
avpicture_fill(formatted_picture, buf, target_pixfmt, dec->width, dec->height);
if (img_convert(formatted_picture, target_pixfmt,
(AVPicture *)in_picture, dec->pix_fmt,
dec->width, dec->height) < 0) {
fprintf(stderr, "pixel format conversion not handled\n");
goto the_end;
}
} else {
formatted_picture = (AVPicture *)in_picture;
}
/* XXX: resampling could be done before raw format convertion in
some cases to go faster */
/* XXX: only works for YUV420P */
final_picture = &ost->pict_tmp;
img_resample(ost->img_resample_ctx, final_picture, formatted_picture);
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(final_picture, buf, enc->pix_fmt, enc->width, enc->height);
if (img_convert(final_picture, enc->pix_fmt,
&ost->pict_tmp, PIX_FMT_YUV420P,
enc->width, enc->height) < 0) {
fprintf(stderr, "pixel format conversion not handled\n");
goto the_end;
}
}
} 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;
final_picture = formatted_picture;
}
/* duplicates frame if needed */
/* XXX: pb because no interleaving */
Fabrice Bellard
committed
for(i=0;i<nb_frames;i++) {
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));
enc->coded_frame = old_frame;
} else {
*(AVPicture*)&big_picture= *final_picture;
/* better than nothing: use input picture interlaced
settings */
big_picture.interlaced_frame = in_picture->interlaced_frame;
big_picture.top_field_first = in_picture->top_field_first;
/* handles sameq here. This is not correct because it may
not be a global option */
if (same_quality) {
big_picture.quality = ist->st->quality;
}else
big_picture.quality = ost->st->quality;
ret = avcodec_encode_video(enc,
//enc->frame_number = enc->real_pict_num;
Fabrice Bellard
committed
av_write_frame(s, ost->index, video_buffer, ret);
*frame_size = ret;
//fprintf(stderr,"\nFrame: %3d %3d size: %5d type: %d",
// enc->frame_number-1, enc->real_pict_num, ret,
/* if two pass, output log */
if (ost->logfile && enc->stats_out) {
fprintf(ost->logfile, "%s", enc->stats_out);
}
Fabrice Bellard
committed
ost->frame_number++;
Fabrice Bellard
committed
the_end:
static double psnr(double d){
if(d==0) return INFINITY;
Fabrice Bellard
committed
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;
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;
total_size += frame_size;
if (enc->codec_type == CODEC_TYPE_VIDEO) {
Fabrice Bellard
committed
frame_number = ost->frame_number;
Michael Niedermayer
committed
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);
Fabrice Bellard
committed
/* compute pts value */
ti1 = (double)ost->st->pts.val * os->pts_num / os->pts_den;
if (ti1 < 0.01)
ti1 = 0.01;
Michael Niedermayer
committed
bitrate = (double)(frame_size * 8) * enc->frame_rate / enc->frame_rate_base / 1000.0;
avg_bitrate = (double)(total_size * 8) / ti1 / 1000.0;
fprintf(fvstats, "s_size= %8.0fkB time= %0.3f br= %7.1fkbits/s avg_br= %7.1fkbits/s ",
(double)total_size / 1024, ti1, bitrate, avg_bitrate);
fprintf(fvstats,"type= %c\n", av_get_pict_type_char(enc->coded_frame->pict_type));
Fabrice Bellard
committed
}
static void print_report(AVFormatContext **output_files,
AVOutputStream **ost_table, int nb_ostreams,
int is_last_report)
Fabrice Bellard
committed
{
char buf[1024];
AVOutputStream *ost;
AVFormatContext *oc, *os;
Fabrice Bellard
committed
AVCodecContext *enc;
int frame_number, vid, i;
double bitrate, ti1, pts;
Fabrice Bellard
committed
if (!is_last_report) {
Fabrice Bellard
committed
/* 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;
}
Fabrice Bellard
committed
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
committed
enc->coded_frame->quality/(float)FF_QP2LAMBDA);
}
Fabrice Bellard
committed
if (!vid && enc->codec_type == CODEC_TYPE_VIDEO) {
frame_number = ost->frame_number;
Michael Niedermayer
committed
frame_number, enc->coded_frame ? enc->coded_frame->quality/(float)FF_QP2LAMBDA : 0);
Michael Niedermayer
committed
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));
}
Fabrice Bellard
committed
vid = 1;
}
/* compute min output value */
pts = (double)ost->st->pts.val * os->pts_num / os->pts_den;
Kareila
committed
if ((pts < ti1) && (pts > 0))
Fabrice Bellard
committed
ti1 = pts;
}
if (ti1 < 0.01)
ti1 = 0.01;
if (verbose || is_last_report) {
bitrate = (double)(total_size * 8) / ti1 / 1000.0;
sprintf(buf + strlen(buf),
Fabrice Bellard
committed
"size=%8.0fkB time=%0.1f bitrate=%6.1fkbits/s",
(double)total_size / 1024, ti1, bitrate);
fprintf(stderr, "%s \r", buf);
Fabrice Bellard
committed
fflush(stderr);
}
if (is_last_report)
fprintf(stderr, "\n");
Fabrice Bellard
committed
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
/* pkt = NULL means EOF (needed to flush decoder buffers) */
static int output_packet(AVInputStream *ist, int ist_index,
AVOutputStream **ost_table, int nb_ostreams,
AVPacket *pkt)
{
AVFormatContext *os;
AVOutputStream *ost;
uint8_t *ptr;
int len, ret, i;
uint8_t *data_buf;
int data_size, got_picture;
AVFrame picture;
short samples[AVCODEC_MAX_AUDIO_FRAME_SIZE / 2];
void *buffer_to_free;
if (pkt && pkt->pts != AV_NOPTS_VALUE) {
ist->pts = pkt->pts;
} else {
ist->pts = ist->next_pts;
}
if (pkt == NULL) {
/* EOF handling */
ptr = NULL;
len = 0;
goto handle_eof;
}
len = pkt->size;
ptr = pkt->data;
while (len > 0) {
handle_eof:
/* decode the packet if needed */
data_buf = NULL; /* fail safe */
data_size = 0;
if (ist->decoding_needed) {
switch(ist->st->codec.codec_type) {
case CODEC_TYPE_AUDIO:
/* XXX: could avoid copy if PCM 16 bits with same
endianness as CPU */
ret = avcodec_decode_audio(&ist->st->codec, samples, &data_size,
ptr, len);
if (ret < 0)
goto fail_decode;
ptr += ret;
len -= ret;
/* Some bug in mpeg audio decoder gives */
/* data_size < 0, it seems they are overflows */
if (data_size <= 0) {
/* no audio frame */
continue;
}
data_buf = (uint8_t *)samples;
ist->next_pts += ((int64_t)AV_TIME_BASE * data_size) /
(2 * ist->st->codec.channels);
break;
case CODEC_TYPE_VIDEO:
data_size = (ist->st->codec.width * ist->st->codec.height * 3) / 2;
/* XXX: allocate picture correctly */
memset(&picture, 0, sizeof(picture));
ret = avcodec_decode_video(&ist->st->codec,
&picture, &got_picture, ptr, len);
ist->st->quality= picture.quality;
if (ret < 0)
goto fail_decode;
if (!got_picture) {
/* no picture yet */
goto discard_packet;
}
if (ist->st->codec.frame_rate_base != 0) {
ist->next_pts += ((int64_t)AV_TIME_BASE *
ist->st->codec.frame_rate_base) /
ist->st->codec.frame_rate;
}
len = 0;
break;
default:
goto fail_decode;
}
} else {
data_buf = ptr;
data_size = len;
ret = len;
len = 0;
}
buffer_to_free = NULL;
if (ist->st->codec.codec_type == CODEC_TYPE_VIDEO) {
pre_process_video_frame(ist, (AVPicture *)&picture,
&buffer_to_free);
}
/* frame rate emulation */
if (ist->st->codec.rate_emu) {
int64_t pts = av_rescale((int64_t) ist->frame * ist->st->codec.frame_rate_base, 1000000, ist->st->codec.frame_rate);
int64_t now = av_gettime() - ist->start;
if (pts > now)
usleep(pts - now);
ist->frame++;
}
#if 0
/* mpeg PTS deordering : if it is a P or I frame, the PTS
is the one of the next displayed one */
/* XXX: add mpeg4 too ? */
if (ist->st->codec.codec_id == CODEC_ID_MPEG1VIDEO) {
if (ist->st->codec.pict_type != B_TYPE) {
int64_t tmp;
tmp = ist->last_ip_pts;
ist->last_ip_pts = ist->frac_pts.val;
ist->frac_pts.val = tmp;
}
}
#endif
/* if output time reached then transcode raw format,
encode packets and output them */
if (start_time == 0 || ist->pts >= start_time)
for(i=0;i<nb_ostreams;i++) {
int frame_size;
ost = ost_table[i];
if (ost->source_index == ist_index) {
os = output_files[ost->file_index];
#if 0
printf("%d: got pts=%0.3f %0.3f\n", i,
(double)pkt->pts / AV_TIME_BASE,
((double)ist->pts / AV_TIME_BASE) -
((double)ost->st->pts.val * os->pts_num / os->pts_den));
#endif
/* set the input output pts pairs */
ost->sync_ipts = (double)ist->pts / AV_TIME_BASE;
/* XXX: take into account the various fifos,
in particular for audio */
ost->sync_opts = ost->st->pts.val;
//printf("ipts=%lld sync_ipts=%f sync_opts=%lld pts.val=%lld pkt->pts=%lld\n", ist->pts, ost->sync_ipts, ost->sync_opts, ost->st->pts.val, pkt->pts);
if (ost->encoding_needed) {
switch(ost->st->codec.codec_type) {
case CODEC_TYPE_AUDIO:
do_audio_out(os, ost, ist, data_buf, data_size);
break;
case CODEC_TYPE_VIDEO:
/* find an audio stream for synchro */
{
int i;
AVOutputStream *audio_sync, *ost1;
audio_sync = NULL;
for(i=0;i<nb_ostreams;i++) {
ost1 = ost_table[i];
if (ost1->file_index == ost->file_index &&
ost1->st->codec.codec_type == CODEC_TYPE_AUDIO) {
audio_sync = ost1;
break;
}
}
do_video_out(os, ost, ist, &picture, &frame_size, audio_sync);
if (do_vstats && frame_size)
do_video_stats(os, ost, frame_size);
}
break;
default:
av_abort();
}
} else {
AVFrame avframe;
/* no reencoding needed : output the packet directly */
/* force the input stream PTS */
memset(&avframe, 0, sizeof(AVFrame));
ost->st->codec.coded_frame= &avframe;
avframe.key_frame = pkt->flags & PKT_FLAG_KEY;
av_write_frame(os, ost->index, data_buf, data_size);
ost->st->codec.frame_number++;
ost->frame_number++;
}
}
}
av_free(buffer_to_free);
}
discard_packet:
return 0;
fail_decode:
return -1;
}
/*
* The following code is the main loop of the file converter
*/
static int av_encode(AVFormatContext **output_files,
int nb_output_files,
AVFormatContext **input_files,
int nb_input_files,
AVStreamMap *stream_maps, int nb_stream_maps)
{
int ret, i, j, k, n, nb_istreams = 0, nb_ostreams = 0;
AVFormatContext *is, *os;
AVCodecContext *codec, *icodec;
AVOutputStream *ost, **ost_table = NULL;
AVInputStream *ist, **ist_table = NULL;
AVFormatContext *stream_no_data;
int key;
file_table= (AVInputFile*) av_mallocz(nb_input_files * sizeof(AVInputFile));
/* input stream init */
j = 0;
for(i=0;i<nb_input_files;i++) {
is = input_files[i];
file_table[i].ist_index = j;
file_table[i].nb_streams = is->nb_streams;
j += is->nb_streams;
}
nb_istreams = j;
ist_table = av_mallocz(nb_istreams * sizeof(AVInputStream *));
if (!ist_table)
for(i=0;i<nb_istreams;i++) {
ist = av_mallocz(sizeof(AVInputStream));
if (!ist)
goto fail;
ist_table[i] = ist;
}
j = 0;
for(i=0;i<nb_input_files;i++) {
is = input_files[i];
for(k=0;k<is->nb_streams;k++) {
ist = ist_table[j++];
ist->st = is->streams[k];
ist->file_index = i;
ist->index = k;
ist->discard = 1; /* the stream is discarded by default
(changed later) */
Max Krasnyansky
committed
if (ist->st->codec.rate_emu) {
ist->start = av_gettime();
ist->frame = 0;
}
}
}
/* output stream init */
nb_ostreams = 0;
for(i=0;i<nb_output_files;i++) {
os = output_files[i];
nb_ostreams += os->nb_streams;
}
if (nb_stream_maps > 0 && nb_stream_maps != nb_ostreams) {
fprintf(stderr, "Number of stream maps must match number of output streams\n");
exit(1);
}
Brian Foley
committed
/* Sanity check the mapping args -- do the input files & streams exist? */
for(i=0;i<nb_stream_maps;i++) {
int fi = stream_maps[i].file_index;
int si = stream_maps[i].stream_index;
if (fi < 0 || fi > nb_input_files - 1 ||
si < 0 || si > file_table[fi].nb_streams - 1) {
fprintf(stderr,"Could not find input stream #%d.%d\n", fi, si);
exit(1);
}
}
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
ost_table = av_mallocz(sizeof(AVOutputStream *) * nb_ostreams);
if (!ost_table)
goto fail;
for(i=0;i<nb_ostreams;i++) {
ost = av_mallocz(sizeof(AVOutputStream));
if (!ost)
goto fail;
ost_table[i] = ost;
}
n = 0;
for(k=0;k<nb_output_files;k++) {
os = output_files[k];
for(i=0;i<os->nb_streams;i++) {
int found;
ost = ost_table[n++];
ost->file_index = k;
ost->index = i;
ost->st = os->streams[i];
if (nb_stream_maps > 0) {
ost->source_index = file_table[stream_maps[n-1].file_index].ist_index +
stream_maps[n-1].stream_index;
Brian Foley
committed
/* Sanity check that the stream types match */
if (ist_table[ost->source_index]->st->codec.codec_type != ost->st->codec.codec_type) {
fprintf(stderr, "Codec type mismatch for mapping #%d.%d -> #%d.%d\n",
stream_maps[n-1].file_index, stream_maps[n-1].stream_index,
ost->file_index, ost->index);
exit(1);
}
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
} else {
/* get corresponding input stream index : we select the first one with the right type */
found = 0;
for(j=0;j<nb_istreams;j++) {
ist = ist_table[j];
if (ist->discard &&
ist->st->codec.codec_type == ost->st->codec.codec_type) {
ost->source_index = j;
found = 1;
}
}
if (!found) {
/* try again and reuse existing stream */
for(j=0;j<nb_istreams;j++) {
ist = ist_table[j];
if (ist->st->codec.codec_type == ost->st->codec.codec_type) {
ost->source_index = j;
found = 1;
}
}
if (!found) {
fprintf(stderr, "Could not find input stream matching output stream #%d.%d\n",
ost->file_index, ost->index);
exit(1);
}
}
}
ist = ist_table[ost->source_index];
ist->discard = 0;
}
}
/* for each output stream, we compute the right encoding parameters */
for(i=0;i<nb_ostreams;i++) {
ost = ost_table[i];
ist = ist_table[ost->source_index];
codec = &ost->st->codec;
icodec = &ist->st->codec;
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;
codec->codec_tag = icodec->codec_tag;
codec->bit_rate = icodec->bit_rate;
switch(codec->codec_type) {
case CODEC_TYPE_AUDIO:
codec->sample_rate = icodec->sample_rate;
codec->channels = icodec->channels;
break;
case CODEC_TYPE_VIDEO:
codec->frame_rate = icodec->frame_rate;
Michael Niedermayer
committed
codec->frame_rate_base = icodec->frame_rate_base;
codec->width = icodec->width;
codec->height = icodec->height;
break;
default:
av_abort();
}
} else {
switch(codec->codec_type) {
case CODEC_TYPE_AUDIO:
if (fifo_init(&ost->fifo, 2 * MAX_AUDIO_PACKET_SIZE))
goto fail;
if (codec->channels == icodec->channels &&
codec->sample_rate == icodec->sample_rate) {
ost->audio_resample = 0;
} else {
if (codec->channels != icodec->channels &&
icodec->codec_id == CODEC_ID_AC3) {
/* Special case for 5:1 AC3 input */
/* and mono or stereo output */
/* Request specific number of channels */
icodec->channels = codec->channels;
if (codec->sample_rate == icodec->sample_rate)
ost->audio_resample = 0;
else {
ost->audio_resample = 1;
ost->resample = audio_resample_init(codec->channels, icodec->channels,
codec->sample_rate,
icodec->sample_rate);
Michael Niedermayer
committed
if(!ost->resample)
{
printf("Can't resample. Aborting.\n");
av_abort();
}
/* Request specific number of channels */
icodec->channels = codec->channels;
} else {
ost->audio_resample = 1;
ost->resample = audio_resample_init(codec->channels, icodec->channels,
Michael Niedermayer
committed
if(!ost->resample)
{
printf("Can't resample. Aborting.\n");
av_abort();
}
}
}
ist->decoding_needed = 1;
ost->encoding_needed = 1;
break;
case CODEC_TYPE_VIDEO:
codec->height == icodec->height &&
frame_topBand == 0 &&
frame_bottomBand == 0 &&
frame_leftBand == 0 &&
frame_rightBand == 0)
{
ost->video_resample = 0;
ost->video_crop = 0;
} else if ((codec->width == icodec->width -
(frame_leftBand + frame_rightBand)) &&
(codec->height == icodec->height -
(frame_topBand + frame_bottomBand)))
{
ost->video_crop = 1;
ost->topBand = frame_topBand;
ost->leftBand = frame_leftBand;
ost->video_crop = 0; // cropping is handled as part of resample
buf = av_malloc((codec->width * codec->height * 3) / 2);
if (!buf)
goto fail;
ost->pict_tmp.data[0] = buf;
ost->pict_tmp.data[1] = ost->pict_tmp.data[0] + (codec->width * codec->height);
ost->pict_tmp.data[2] = ost->pict_tmp.data[1] + (codec->width * codec->height) / 4;
ost->pict_tmp.linesize[0] = codec->width;
ost->pict_tmp.linesize[1] = codec->width / 2;
ost->pict_tmp.linesize[2] = codec->width / 2;
Michael Niedermayer
committed
ost->img_resample_ctx = img_resample_full_init(
Michael Niedermayer
committed
ist->st->codec.width, ist->st->codec.height,
frame_topBand, frame_bottomBand,
frame_leftBand, frame_rightBand);
}
ost->encoding_needed = 1;
ist->decoding_needed = 1;
break;
default:
av_abort();
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
/* two pass mode */
if (ost->encoding_needed &&
(codec->flags & (CODEC_FLAG_PASS1 | CODEC_FLAG_PASS2))) {
char logfilename[1024];
FILE *f;
int size;
char *logbuffer;
snprintf(logfilename, sizeof(logfilename), "%s-%d.log",
pass_logfilename ?
pass_logfilename : DEFAULT_PASS_LOGFILENAME, i);
if (codec->flags & CODEC_FLAG_PASS1) {
f = fopen(logfilename, "w");
if (!f) {
perror(logfilename);
exit(1);
}
ost->logfile = f;
} else {
/* read the log file */
f = fopen(logfilename, "r");
if (!f) {
perror(logfilename);
exit(1);
}
fseek(f, 0, SEEK_END);
size = ftell(f);
fseek(f, 0, SEEK_SET);
logbuffer = av_malloc(size + 1);
if (!logbuffer) {
fprintf(stderr, "Could not allocate log buffer\n");
exit(1);
}
fread(logbuffer, 1, size, f);
fclose(f);
logbuffer[size] = '\0';
codec->stats_in = logbuffer;
/* dump the file output parameters - cannot be done before in case
of stream copy */
for(i=0;i<nb_output_files;i++) {
dump_format(output_files[i], i, output_files[i]->filename, 1);
}
/* dump the stream mapping */
fprintf(stderr, "Stream mapping:\n");
for(i=0;i<nb_ostreams;i++) {
ost = ost_table[i];
fprintf(stderr, " Stream #%d.%d -> #%d.%d\n",
ist_table[ost->source_index]->file_index,
ist_table[ost->source_index]->index,
ost->file_index,
ost->index);
}
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
/* open each encoder */
for(i=0;i<nb_ostreams;i++) {
ost = ost_table[i];
if (ost->encoding_needed) {
AVCodec *codec;
codec = avcodec_find_encoder(ost->st->codec.codec_id);
if (!codec) {
fprintf(stderr, "Unsupported codec for output stream #%d.%d\n",
ost->file_index, ost->index);
exit(1);
}
if (avcodec_open(&ost->st->codec, codec) < 0) {
fprintf(stderr, "Error while opening codec for stream #%d.%d - maybe incorrect parameters such as bit_rate, rate, width or height\n",
ost->file_index, ost->index);
exit(1);
}
}
}
/* open each decoder */
for(i=0;i<nb_istreams;i++) {
ist = ist_table[i];
if (ist->decoding_needed) {
AVCodec *codec;
codec = avcodec_find_decoder(ist->st->codec.codec_id);
if (!codec) {
fprintf(stderr, "Unsupported codec (id=%d) for input stream #%d.%d\n",
ist->st->codec.codec_id, ist->file_index, ist->index);
exit(1);
}
if (avcodec_open(&ist->st->codec, codec) < 0) {
fprintf(stderr, "Error while opening codec for input stream #%d.%d\n",
ist->file_index, ist->index);
exit(1);
}
//if (ist->st->codec.codec_type == CODEC_TYPE_VIDEO)
// ist->st->codec.flags |= CODEC_FLAG_REPEAT_FIELD;
}
}
/* init pts */
for(i=0;i<nb_istreams;i++) {
ist = ist_table[i];
ist->next_pts = 0;
}
/* compute buffer size max (should use a complete heuristic) */
for(i=0;i<nb_input_files;i++) {
file_table[i].buffer_size_max = 2048;
}
/* open files and write file headers */
for(i=0;i<nb_output_files;i++) {
os = output_files[i];
if (av_write_header(os) < 0) {
fprintf(stderr, "Could not write header for output file #%d (incorrect codec paramters ?)\n", i);
ret = -EINVAL;
goto fail;
}
#ifndef CONFIG_WIN32
if ( !using_stdin )
fprintf(stderr, "Press [q] to stop encoding\n");
#endif
term_init();
stream_no_data = 0;
key = -1;
for(; received_sigterm == 0;) {
Fabrice Bellard
committed
double pts_min;
/* if 'q' pressed, exits */
if (!using_stdin) {
/* read_key() returns 0 on EOF */
key = read_key();
if (key == 'q')
break;
}
Fabrice Bellard
committed
/* select the stream that we must read now by looking at the
smallest output pts */
Fabrice Bellard
committed
pts_min = 1e10;
for(i=0;i<nb_ostreams;i++) {
double pts;
ost = ost_table[i];
os = output_files[ost->file_index];
ist = ist_table[ost->source_index];
pts = (double)ost->st->pts.val * os->pts_num / os->pts_den;
if (!file_table[ist->file_index].eof_reached &&
pts < pts_min) {
pts_min = pts;
file_index = ist->file_index;
}
}
/* if none, if is finished */
if (file_index < 0) {
Fabrice Bellard
committed
}
Fabrice Bellard
committed
if (recording_time > 0 && pts_min >= (recording_time / 1000000.0))
Fabrice Bellard
committed
/* read a frame from it and output it in the fifo */
if (av_read_frame(is, &pkt) < 0) {
if (!pkt.size) {
stream_no_data = is;
} else {
stream_no_data = 0;
}
if (do_pkt_dump) {
av_pkt_dump(stdout, &pkt, do_hex_dump);
Fabrice Bellard
committed
}
/* the following test is needed in case new streams appear
dynamically in stream : we ignore them */
if (pkt.stream_index >= file_table[file_index].nb_streams)
ist_index = file_table[file_index].ist_index + pkt.stream_index;
ist = ist_table[ist_index];
if (ist->discard)
goto discard_packet;
//fprintf(stderr,"read #%d.%d size=%d\n", ist->file_index, ist->index, pkt.size);
Fabrice Bellard
committed
if (output_packet(ist, ist_index, ost_table, nb_ostreams, &pkt) < 0) {
fprintf(stderr, "Error while decoding stream #%d.%d\n",
ist->file_index, ist->index);
av_free_packet(&pkt);
goto redo;
Fabrice Bellard
committed
Fabrice Bellard
committed
/* dump report by using the output first video and audio streams */
print_report(output_files, ost_table, nb_ostreams, 0);
Fabrice Bellard
committed
/* at the end of stream, we must flush the decoder buffers */
for(i=0;i<nb_istreams;i++) {
ist = ist_table[i];
if (ist->decoding_needed) {
output_packet(ist, i, ost_table, nb_ostreams, NULL);
}
}
term_exit();
/* dump report by using the first video and audio streams */
Fabrice Bellard
committed
print_report(output_files, ost_table, nb_ostreams, 1);
/* close each encoder */
for(i=0;i<nb_ostreams;i++) {
ost = ost_table[i];
if (ost->encoding_needed) {
av_freep(&ost->st->codec.stats_in);
avcodec_close(&ost->st->codec);
}
}
/* close each decoder */
for(i=0;i<nb_istreams;i++) {
ist = ist_table[i];
if (ist->decoding_needed) {
avcodec_close(&ist->st->codec);
}
}
/* write the trailer if needed and close file */
for(i=0;i<nb_output_files;i++) {
os = output_files[i];
av_write_trailer(os);
if (ist_table) {
for(i=0;i<nb_istreams;i++) {
ist = ist_table[i];
}
if (ost_table) {
for(i=0;i<nb_ostreams;i++) {
ost = ost_table[i];
if (ost) {
if (ost->logfile) {
fclose(ost->logfile);
ost->logfile = NULL;
}
fifo_free(&ost->fifo); /* works even if fifo is not
initialized but set to zero */
if (ost->video_resample)
img_resample_close(ost->img_resample_ctx);
if (ost->audio_resample)
audio_resample_close(ost->resample);
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
}
return ret;
fail:
ret = -ENOMEM;
goto fail1;
}
#if 0
int file_read(const char *filename)
{
URLContext *h;
unsigned char buffer[1024];
int len, i;
if (url_open(&h, filename, O_RDONLY) < 0) {
printf("could not open '%s'\n", filename);
return -1;
}
for(;;) {
len = url_read(h, buffer, sizeof(buffer));
if (len <= 0)
break;
for(i=0;i<len;i++) putchar(buffer[i]);
}
url_close(h);
return 0;
}
#endif
static void opt_image_format(const char *arg)
Fabrice Bellard
committed
{
AVImageFormat *f;
for(f = first_image_format; f != NULL; f = f->next) {
if (!strcmp(arg, f->name))
break;
}
if (!f) {
fprintf(stderr, "Unknown image format: '%s'\n", arg);
exit(1);
}
image_format = f;
}
static void opt_format(const char *arg)
Fabrice Bellard
committed
/* compatibility stuff for pgmyuv */
if (!strcmp(arg, "pgmyuv")) {
opt_image_format(arg);
arg = "image";
}
file_iformat = av_find_input_format(arg);
file_oformat = guess_format(arg, NULL, NULL);
if (!file_iformat && !file_oformat) {
fprintf(stderr, "Unknown input or output format: %s\n", arg);
static void opt_video_bitrate(const char *arg)
static void opt_video_bitrate_tolerance(const char *arg)
{
video_bit_rate_tolerance = atoi(arg) * 1000;
}
static void opt_video_bitrate_max(const char *arg)
{
video_rc_max_rate = atoi(arg) * 1000;
}
static void opt_video_bitrate_min(const char *arg)
{
video_rc_min_rate = atoi(arg) * 1000;
}
static void opt_video_buffer_size(const char *arg)
static void opt_video_rc_eq(char *arg)
static void opt_video_rc_override_string(char *arg)
{
video_rc_override_string = arg;
}
static void opt_workaround_bugs(const char *arg)
Michael Niedermayer
committed
{
workaround_bugs = atoi(arg);
}
static void opt_dct_algo(const char *arg)
{
dct_algo = atoi(arg);
}
static void opt_idct_algo(const char *arg)
{
idct_algo = atoi(arg);
}
static void opt_error_resilience(const char *arg)
{
error_resilience = atoi(arg);
}
static void opt_error_concealment(const char *arg)
{
error_concealment = atoi(arg);
}
static void opt_debug(const char *arg)
Wolfgang Hesseler
committed
static void opt_vismv(const char *arg)
{
debug_mv = atoi(arg);
}
static void opt_verbose(const char *arg)
{
verbose = atoi(arg);
}
static void opt_frame_rate(const char *arg)
if (parse_frame_rate(&frame_rate, &frame_rate_base, arg) < 0) {
fprintf(stderr, "Incorrect frame rate\n");
exit(1);
}
static void opt_frame_crop_top(const char *arg)
Michael Niedermayer
committed
{
frame_topBand = atoi(arg);
if (frame_topBand < 0) {
fprintf(stderr, "Incorrect top crop size\n");
exit(1);
}
if ((frame_topBand % 2) != 0) {
fprintf(stderr, "Top crop size must be a multiple of 2\n");
exit(1);
}
if ((frame_topBand) >= frame_height){
fprintf(stderr, "Vertical crop dimensions are outside the range of the original image.\nRemember to crop first and scale second.\n");
exit(1);
}
frame_height -= frame_topBand;
}
static void opt_frame_crop_bottom(const char *arg)
Michael Niedermayer
committed
{
frame_bottomBand = atoi(arg);
if (frame_bottomBand < 0) {
fprintf(stderr, "Incorrect bottom crop size\n");
exit(1);
}
if ((frame_bottomBand % 2) != 0) {
fprintf(stderr, "Bottom crop size must be a multiple of 2\n");
exit(1);
}
if ((frame_bottomBand) >= frame_height){
fprintf(stderr, "Vertical crop dimensions are outside the range of the original image.\nRemember to crop first and scale second.\n");
exit(1);
}
frame_height -= frame_bottomBand;
}
static void opt_frame_crop_left(const char *arg)
Michael Niedermayer
committed
{
frame_leftBand = atoi(arg);
if (frame_leftBand < 0) {
fprintf(stderr, "Incorrect left crop size\n");
exit(1);
}
if ((frame_leftBand % 2) != 0) {
fprintf(stderr, "Left crop size must be a multiple of 2\n");
exit(1);
}
if ((frame_leftBand) >= frame_width){
fprintf(stderr, "Horizontal crop dimensions are outside the range of the original image.\nRemember to crop first and scale second.\n");
exit(1);
}
frame_width -= frame_leftBand;
}
static void opt_frame_crop_right(const char *arg)
Michael Niedermayer
committed
{
frame_rightBand = atoi(arg);
if (frame_rightBand < 0) {
fprintf(stderr, "Incorrect right crop size\n");
exit(1);
}
if ((frame_rightBand % 2) != 0) {
fprintf(stderr, "Right crop size must be a multiple of 2\n");
exit(1);
}
if ((frame_rightBand) >= frame_width){
fprintf(stderr, "Horizontal crop dimensions are outside the range of the original image.\nRemember to crop first and scale second.\n");
exit(1);
}
frame_width -= frame_rightBand;
}
static void opt_frame_size(const char *arg)
if (parse_image_size(&frame_width, &frame_height, arg) < 0) {
fprintf(stderr, "Incorrect frame size\n");
exit(1);
}
if ((frame_width % 2) != 0 || (frame_height % 2) != 0) {
fprintf(stderr, "Frame size must be a multiple of 2\n");
exit(1);
}
}
static void opt_frame_pix_fmt(const char *arg)
{
frame_pix_fmt = avcodec_get_pix_fmt(arg);
}
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
static void opt_frame_aspect_ratio(const char *arg)
{
int x = 0, y = 0;
double ar = 0;
const char *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);
}
frame_aspect_ratio = ar;
}
static void opt_gop_size(const char *arg)
static void opt_b_frames(const char *arg)
{
b_frames = atoi(arg);
if (b_frames > FF_MAX_B_FRAMES) {
fprintf(stderr, "\nCannot have more than %d B frames, increase FF_MAX_B_FRAMES.\n", FF_MAX_B_FRAMES);
exit(1);
} else if (b_frames < 1) {
fprintf(stderr, "\nNumber of B frames must be higher than 0\n");
exit(1);
}
}
static void opt_mb_decision(const char *arg)
{
mb_decision = atoi(arg);
}
static void opt_mb_cmp(const char *arg)
{
mb_cmp = atoi(arg);
}
static void opt_sub_cmp(const char *arg)
{
sub_cmp = atoi(arg);
}
static void opt_cmp(const char *arg)
{
cmp = atoi(arg);
}
static void opt_qscale(const char *arg)
Michael Niedermayer
committed
video_qscale = atof(arg);
if (video_qscale < 0.01 ||
video_qscale > 255) {
fprintf(stderr, "qscale must be >= 0.01 and <= 255\n");
static void opt_qmin(const char *arg)
{
video_qmin = atoi(arg);
if (video_qmin < 0 ||
video_qmin > 31) {
fprintf(stderr, "qmin must be >= 1 and <= 31\n");
exit(1);
}
}
static void opt_qmax(const char *arg)
{
video_qmax = atoi(arg);
if (video_qmax < 0 ||
video_qmax > 31) {
fprintf(stderr, "qmax must be >= 1 and <= 31\n");
exit(1);
}
}
static void opt_mb_qmin(const char *arg)
{
video_mb_qmin = atoi(arg);
if (video_mb_qmin < 0 ||
video_mb_qmin > 31) {
fprintf(stderr, "qmin must be >= 1 and <= 31\n");
exit(1);
}
}
static void opt_mb_qmax(const char *arg)
{
video_mb_qmax = atoi(arg);
if (video_mb_qmax < 0 ||
video_mb_qmax > 31) {
fprintf(stderr, "qmax must be >= 1 and <= 31\n");
exit(1);
}
}
static void opt_qdiff(const char *arg)
{
video_qdiff = atoi(arg);
if (video_qdiff < 0 ||
video_qdiff > 31) {
fprintf(stderr, "qdiff must be >= 1 and <= 31\n");
exit(1);
}
}
static void opt_qblur(const char *arg)
{
video_qblur = atof(arg);
}
static void opt_qcomp(const char *arg)
{
video_qcomp = atof(arg);
}
static void opt_rc_initial_cplx(const char *arg)
{
video_rc_initial_cplx = atof(arg);
}
static void opt_b_qfactor(const char *arg)
{
video_b_qfactor = atof(arg);
}
static void opt_i_qfactor(const char *arg)
{
video_i_qfactor = atof(arg);
}
static void opt_b_qoffset(const char *arg)
{
video_b_qoffset = atof(arg);
}
static void opt_i_qoffset(const char *arg)
{
video_i_qoffset = atof(arg);
}
static void opt_packet_size(const char *arg)
{
packet_size= atoi(arg);
}
static void opt_error_rate(const char *arg)
{
error_rate= atoi(arg);
}
static void opt_strict(const char *arg)
static void opt_audio_bitrate(const char *arg)
static void opt_audio_rate(const char *arg)
static void opt_audio_channels(const char *arg)
static void opt_video_device(const char *arg)
static void opt_video_channel(const char *arg)
Fabrice Bellard
committed
{
video_channel = strtol(arg, NULL, 0);
}
static void opt_video_standard(const char *arg)
{
video_standard = av_strdup(arg);
}
static void opt_audio_device(const char *arg)
static void opt_dv1394(const char *arg)
{
video_grab_format = "dv1394";
audio_grab_format = NULL;
static void opt_audio_codec(const char *arg)
if (!strcmp(arg, "copy")) {
audio_stream_copy = 1;
p = first_avcodec;
while (p) {
if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_AUDIO)
break;
p = p->next;
}
if (p == NULL) {
fprintf(stderr, "Unknown audio codec '%s'\n", arg);
exit(1);
} else {
audio_codec_id = p->id;
}
static void add_frame_hooker(const char *arg)
{
int argc = 0;
char *argv[64];
int i;
using_vhook = 1;
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);
}
}
const char *motion_str[] = {
"zero",
"full",
"log",
"phods",
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++;
}
static void opt_video_codec(const char *arg)
if (!strcmp(arg, "copy")) {
video_stream_copy = 1;
p = first_avcodec;
while (p) {
if (!strcmp(p->name, arg) && p->type == CODEC_TYPE_VIDEO)
break;
p = p->next;
}
if (p == NULL) {
fprintf(stderr, "Unknown video codec '%s'\n", arg);
exit(1);
} else {
video_codec_id = p->id;
}
static void opt_map(const char *arg)
{
AVStreamMap *m;
const char *p;
p = arg;
m = &stream_maps[nb_stream_maps++];
m->file_index = strtol(arg, (char **)&p, 0);
if (*p)
p++;
m->stream_index = strtol(p, (char **)&p, 0);
static void opt_recording_time(const char *arg)
static void opt_start_time(const char *arg)
{
start_time = parse_date(arg, 1);
}
static void opt_input_file(const char *filename)
{
AVFormatContext *ic;
AVFormatParameters params, *ap = ¶ms;
Michael Niedermayer
committed
int err, i, ret, rfps, rfps_base;
if (!strcmp(filename, "-"))
filename = "pipe:";
using_stdin |= !strcmp(filename, "pipe:" ) ||
!strcmp( filename, "/dev/stdin" );
memset(ap, 0, sizeof(*ap));
ap->sample_rate = audio_sample_rate;
ap->channels = audio_channels;
ap->frame_rate = frame_rate;
Michael Niedermayer
committed
ap->frame_rate_base = frame_rate_base;
ap->width = frame_width;
ap->height = frame_height;
Fabrice Bellard
committed
ap->image_format = image_format;
ap->pix_fmt = frame_pix_fmt;
/* open the input file with generic libav function */
err = av_open_input_file(&ic, filename, file_iformat, 0, ap);
print_error(filename, err);
/* If not enough info to get the stream parameters, we decode the
first frames to get it. (used in mpeg case for example) */
ret = av_find_stream_info(ic);
if (ret < 0) {
fprintf(stderr, "%s: could not find codec parameters\n", filename);
exit(1);
}
/* if seeking requested, we execute it */
if (start_time != 0) {
int64_t timestamp;
timestamp = start_time;
/* add the stream start time */
if (ic->start_time != AV_NOPTS_VALUE)
timestamp += ic->start_time;
ret = av_seek_frame(ic, -1, timestamp);
if (ret < 0) {
fprintf(stderr, "%s: could not seek to position %0.3f\n",
filename, (double)timestamp / AV_TIME_BASE);
}
/* reset seek info */
start_time = 0;
}
/* update the current parameters so that they match the one of the input stream */
for(i=0;i<ic->nb_streams;i++) {
AVCodecContext *enc = &ic->streams[i]->codec;
switch(enc->codec_type) {
case CODEC_TYPE_AUDIO:
//fprintf(stderr, "\nInput Audio channels: %d", enc->channels);
audio_channels = enc->channels;
audio_sample_rate = enc->sample_rate;
break;
case CODEC_TYPE_VIDEO:
frame_height = enc->height;
frame_width = enc->width;
frame_aspect_ratio = av_q2d(enc->sample_aspect_ratio) * enc->width / enc->height;
frame_pix_fmt = enc->pix_fmt;
Michael Niedermayer
committed
rfps = ic->streams[i]->r_frame_rate;
rfps_base = ic->streams[i]->r_frame_rate_base;
Michael Niedermayer
committed
enc->workaround_bugs = workaround_bugs;
enc->error_resilience = error_resilience;
enc->error_concealment = error_concealment;
Wolfgang Hesseler
committed
enc->idct_algo = idct_algo;
enc->debug = debug;
enc->debug_mv = debug_mv;
if(bitexact)
enc->flags|= CODEC_FLAG_BITEXACT;
Michael Niedermayer
committed
assert(enc->frame_rate_base == rfps_base); // should be true for now
if (enc->frame_rate != rfps) {
fprintf(stderr,"\nSeems that stream %d comes from film source: %2.2f->%2.2f\n",
Michael Niedermayer
committed
i, (float)enc->frame_rate / enc->frame_rate_base,
(float)rfps / rfps_base);
/* update the current frame rate to match the stream frame rate */
Michael Niedermayer
committed
frame_rate = rfps;
frame_rate_base = rfps_base;
Max Krasnyansky
committed
enc->rate_emu = rate_emu;
case CODEC_TYPE_DATA:
break;
default:
av_abort();
}
}
input_files[nb_input_files] = ic;
/* dump the file content */
dump_format(ic, nb_input_files, filename, 0);
nb_input_files++;
file_iformat = NULL;
file_oformat = NULL;
Fabrice Bellard
committed
image_format = NULL;
Max Krasnyansky
committed
rate_emu = 0;
static void check_audio_video_inputs(int *has_video_ptr, int *has_audio_ptr)
Fabrice Bellard
committed
{
int has_video, has_audio, i, j;
AVFormatContext *ic;
has_video = 0;
has_audio = 0;
for(j=0;j<nb_input_files;j++) {
ic = input_files[j];
for(i=0;i<ic->nb_streams;i++) {
AVCodecContext *enc = &ic->streams[i]->codec;
switch(enc->codec_type) {
case CODEC_TYPE_AUDIO:
has_audio = 1;
break;
case CODEC_TYPE_VIDEO:
has_video = 1;
break;
default:
av_abort();
Fabrice Bellard
committed
}
}
}
*has_video_ptr = has_video;
*has_audio_ptr = has_audio;
}
static void opt_output_file(const char *filename)
Fabrice Bellard
committed
int use_video, use_audio, nb_streams, input_has_video, input_has_audio;
Fabrice Bellard
committed
AVFormatParameters params, *ap = ¶ms;
if (!strcmp(filename, "-"))
filename = "pipe:";
oc = av_mallocz(sizeof(AVFormatContext));
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",
filename);
exit(1);
}
oc->oformat = file_oformat;
if (!strcmp(file_oformat->name, "ffm") &&
strstart(filename, "http:", NULL)) {
/* special case for files sent to ffserver: we get the stream
parameters from ffserver */
if (read_ffserver_streams(oc, filename) < 0) {
fprintf(stderr, "Could not read stream parameters from '%s'\n", filename);
exit(1);
}
} else {
use_video = file_oformat->video_codec != CODEC_ID_NONE;
use_audio = file_oformat->audio_codec != CODEC_ID_NONE;
Fabrice Bellard
committed
/* 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);
if (!input_has_video)
use_video = 0;
if (!input_has_audio)
use_audio = 0;
}
Fabrice Bellard
committed
/* manual disable */
if (audio_disable) {
use_audio = 0;
}
if (video_disable) {
use_video = 0;
}
nb_streams = 0;
if (use_video) {
AVCodecContext *video_enc;
st = av_mallocz(sizeof(AVStream));
if (!st) {
fprintf(stderr, "Could not alloc stream\n");
exit(1);
}
video_enc = &st->codec;
Michael Niedermayer
committed
if(!strcmp(file_oformat->name, "mp4") || !strcmp(file_oformat->name, "mov") || !strcmp(file_oformat->name, "3gp"))
video_enc->flags |= CODEC_FLAG_GLOBAL_HEADER;
if (video_stream_copy) {
st->stream_copy = 1;
video_enc->codec_type = CODEC_TYPE_VIDEO;
} else {
char *p;
int i;
codec_id = file_oformat->video_codec;
if (video_codec_id != CODEC_ID_NONE)
codec_id = video_codec_id;
video_enc->codec_id = codec_id;
video_enc->bit_rate = video_bit_rate;
video_enc->bit_rate_tolerance = video_bit_rate_tolerance;
video_enc->frame_rate = frame_rate;
Michael Niedermayer
committed
video_enc->frame_rate_base = frame_rate_base;
video_enc->width = frame_width;
video_enc->height = frame_height;
video_enc->sample_aspect_ratio = av_d2q(frame_aspect_ratio*frame_height/frame_width, 255);
video_enc->pix_fmt = frame_pix_fmt;
if (!intra_only)
video_enc->gop_size = gop_size;
else
video_enc->gop_size = 0;
if (video_qscale || same_quality) {
video_enc->flags |= CODEC_FLAG_QSCALE;
Michael Niedermayer
committed
st->quality = FF_QP2LAMBDA * video_qscale;
}
Vidar Madsen
committed
if(intra_matrix)
video_enc->intra_matrix = intra_matrix;
if(inter_matrix)
video_enc->inter_matrix = inter_matrix;
if(bitexact)
video_enc->flags |= CODEC_FLAG_BITEXACT;
video_enc->mb_decision = mb_decision;
video_enc->mb_cmp = mb_cmp;
video_enc->me_sub_cmp = sub_cmp;
video_enc->me_cmp = cmp;
Michael Niedermayer
committed
if (use_umv) {
video_enc->flags |= CODEC_FLAG_H263P_UMV;
}
if (use_aic) {
video_enc->flags |= CODEC_FLAG_H263P_AIC;
}
if (use_aiv) {
video_enc->flags |= CODEC_FLAG_H263P_AIV;
}
if (use_4mv) {
video_enc->flags |= CODEC_FLAG_4MV;
}
if (use_obmc) {
video_enc->flags |= CODEC_FLAG_OBMC;
}
video_enc->flags |= CODEC_FLAG_PART;
if (b_frames) {
video_enc->max_b_frames = b_frames;
video_enc->b_frame_strategy = 0;
video_enc->b_quant_factor = 2.0;
if (do_interlace) {
video_enc->flags |= CODEC_FLAG_INTERLACED_DCT;
}
video_enc->qmin = video_qmin;
video_enc->qmax = video_qmax;
video_enc->mb_qmin = video_mb_qmin;
video_enc->mb_qmax = video_mb_qmax;
video_enc->max_qdiff = video_qdiff;
video_enc->qblur = video_qblur;
video_enc->qcompress = video_qcomp;
video_enc->rc_eq = video_rc_eq;
Wolfgang Hesseler
committed
video_enc->debug = debug;
video_enc->debug_mv = debug_mv;
Loading
Loading full blame...