X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=ffmpeg.c;h=22bfed8dc2ee479b75af795d690b0ca9373dbf5a;hb=4b2be143cd5ab216c6a7ebd8715b732169077e5d;hp=68f84fe57550020617035330f7d2a9a1f3255b42;hpb=ede0e475070298e2bc85870c08c74b33982110dd;p=ffmpeg diff --git a/ffmpeg.c b/ffmpeg.c index 68f84fe5755..22bfed8dc2e 100644 --- a/ffmpeg.c +++ b/ffmpeg.c @@ -36,6 +36,7 @@ #include "libswscale/swscale.h" #include "libavcodec/opt.h" #include "libavcodec/audioconvert.h" +#include "libavcodec/colorspace.h" #include "libavutil/fifo.h" #include "libavutil/avstring.h" #include "libavformat/os_support.h" @@ -222,6 +223,12 @@ static unsigned int sws_flags = SWS_BICUBIC; static int64_t timer_start; +static uint8_t *audio_buf; +static uint8_t *audio_out; +static uint8_t *audio_out2; + +static short *samples; + static AVBitStreamFilterContext *video_bitstream_filters=NULL; static AVBitStreamFilterContext *audio_bitstream_filters=NULL; static AVBitStreamFilterContext *subtitle_bitstream_filters=NULL; @@ -248,13 +255,29 @@ typedef struct AVOutputStream { AVFrame pict_tmp; /* temporary image for resampling */ struct SwsContext *img_resample_ctx; /* for image resampling */ int resample_height; + int resample_width; + int resample_pix_fmt; + + /* full frame size of first frame */ + int original_height; + int original_width; + /* cropping area sizes */ int video_crop; - int topBand; /* cropping area sizes */ + int topBand; + int bottomBand; int leftBand; + int rightBand; + /* cropping area of first frame */ + int original_topBand; + int original_bottomBand; + int original_leftBand; + int original_rightBand; + + /* padding area sizes */ int video_pad; - int padtop; /* padding area sizes */ + int padtop; int padbottom; int padleft; int padright; @@ -427,6 +450,15 @@ static int av_exit(int ret) powerpc_display_perf_report(); #endif /* CONFIG_POWERPC_PERF */ + for (i=0;ipix_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 */ - fprintf(stderr, "Deinterlacing failed\n"); - av_free(buf); - buf = NULL; - picture2 = picture; - } - } else { - av_picture_copy(picture2, picture, dec->pix_fmt, dec->width, dec->height); + if(avpicture_deinterlace(picture2, picture, + dec->pix_fmt, dec->width, dec->height) < 0) { + /* if error, do not deinterlace */ + fprintf(stderr, "Deinterlacing failed\n"); + av_free(buf); + buf = NULL; + picture2 = picture; } } else { picture2 = picture; @@ -805,6 +830,7 @@ static void do_subtitle_out(AVFormatContext *s, nb = 1; for(i = 0; i < nb; i++) { + sub->pts = av_rescale_q(pts, ist->st->time_base, AV_TIME_BASE_Q); subtitle_out_size = avcodec_encode_subtitle(enc, subtitle_out, subtitle_out_max_size, sub); @@ -835,6 +861,7 @@ static void do_video_out(AVFormatContext *s, int *frame_size) { int nb_frames, i, ret; + int64_t topBand, bottomBand, leftBand, rightBand; AVFrame *final_picture, *formatted_picture, *resampling_dst, *padding_src; AVFrame picture_crop_temp, picture_pad_temp; AVCodecContext *enc, *dec; @@ -911,6 +938,48 @@ static void do_video_out(AVFormatContext *s, if (ost->video_resample) { padding_src = NULL; final_picture = &ost->pict_tmp; + if( (ost->resample_height != (ist->st->codec->height - (ost->topBand + ost->bottomBand))) + || (ost->resample_width != (ist->st->codec->width - (ost->leftBand + ost->rightBand))) + || (ost->resample_pix_fmt!= ist->st->codec->pix_fmt) ) { + + fprintf(stderr,"Input Stream #%d.%d frame size changed to %dx%d, %s\n", ist->file_index, ist->index, ist->st->codec->width, ist->st->codec->height,avcodec_get_pix_fmt_name(ist->st->codec->pix_fmt)); + /* keep bands proportional to the frame size */ + topBand = ((int64_t)ist->st->codec->height * ost->original_topBand / ost->original_height) & ~1; + bottomBand = ((int64_t)ist->st->codec->height * ost->original_bottomBand / ost->original_height) & ~1; + leftBand = ((int64_t)ist->st->codec->width * ost->original_leftBand / ost->original_width) & ~1; + rightBand = ((int64_t)ist->st->codec->width * ost->original_rightBand / ost->original_width) & ~1; + + /* sanity check to ensure no bad band sizes sneak in */ + assert(topBand <= INT_MAX && topBand >= 0); + assert(bottomBand <= INT_MAX && bottomBand >= 0); + assert(leftBand <= INT_MAX && leftBand >= 0); + assert(rightBand <= INT_MAX && rightBand >= 0); + + ost->topBand = topBand; + ost->bottomBand = bottomBand; + ost->leftBand = leftBand; + ost->rightBand = rightBand; + + ost->resample_height = ist->st->codec->height - (ost->topBand + ost->bottomBand); + ost->resample_width = ist->st->codec->width - (ost->leftBand + ost->rightBand); + ost->resample_pix_fmt= ist->st->codec->pix_fmt; + + /* initialize a new scaler context */ + sws_freeContext(ost->img_resample_ctx); + sws_flags = av_get_int(sws_opts, "sws_flags", NULL); + ost->img_resample_ctx = sws_getContext( + ist->st->codec->width - (ost->leftBand + ost->rightBand), + ist->st->codec->height - (ost->topBand + ost->bottomBand), + ist->st->codec->pix_fmt, + ost->st->codec->width - (ost->padleft + ost->padright), + ost->st->codec->height - (ost->padtop + ost->padbottom), + ost->st->codec->pix_fmt, + sws_flags, NULL, NULL, NULL); + if (ost->img_resample_ctx == NULL) { + fprintf(stderr, "Cannot get resampling context\n"); + av_exit(1); + } + } sws_scale(ost->img_resample_ctx, formatted_picture->data, formatted_picture->linesize, 0, ost->resample_height, resampling_dst->data, resampling_dst->linesize); } @@ -973,7 +1042,7 @@ static void do_video_out(AVFormatContext *s, fprintf(stderr, "Video encoding failed\n"); av_exit(1); } - //enc->frame_number = enc->real_pict_num; + if(ret>0){ pkt.data= bit_buffer; pkt.size= ret; @@ -988,9 +1057,8 @@ static void do_video_out(AVFormatContext *s, write_frame(s, &pkt, ost->st->codec, bitstream_filters[ost->file_index][pkt.stream_index]); *frame_size = ret; video_size += ret; - //fprintf(stderr,"\nFrame: %3d %3d size: %5d type: %d", - // enc->frame_number-1, enc->real_pict_num, ret, - // enc->pict_type); + //fprintf(stderr,"\nFrame: %3d size: %5d type: %d", + // enc->frame_number-1, ret, enc->pict_type); /* if two pass, output log */ if (ost->logfile && enc->stats_out) { fprintf(ost->logfile, "%s", enc->stats_out); @@ -1049,7 +1117,7 @@ static void print_report(AVFormatContext **output_files, { char buf[1024]; AVOutputStream *ost; - AVFormatContext *oc, *os; + AVFormatContext *oc; int64_t total_size; AVCodecContext *enc; int frame_number, vid, i; @@ -1082,7 +1150,6 @@ static void print_report(AVFormatContext **output_files, vid = 0; for(i=0;ifile_index]; enc = ost->st->codec; if (vid && enc->codec_type == CODEC_TYPE_VIDEO) { snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "q=%2.1f ", @@ -1180,29 +1247,26 @@ static int output_packet(AVInputStream *ist, int ist_index, AVFrame picture; void *buffer_to_free; static unsigned int samples_size= 0; - static short *samples= NULL; AVSubtitle subtitle, *subtitle_to_free; int got_subtitle; AVPacket avpkt; - av_init_packet(&avpkt); - if(ist->next_pts == AV_NOPTS_VALUE) ist->next_pts= ist->pts; if (pkt == NULL) { /* EOF handling */ + av_init_packet(&avpkt); avpkt.data = NULL; avpkt.size = 0; goto handle_eof; + } else { + avpkt = *pkt; } if(pkt->dts != AV_NOPTS_VALUE) ist->next_pts = ist->pts = av_rescale_q(pkt->dts, ist->st->time_base, AV_TIME_BASE_Q); - avpkt.size = pkt->size; - avpkt.data = pkt->data; - //while we have more to decode or while the decoder did output something on EOF while (avpkt.size > 0 || (!pkt && ist->next_pts != ist->pts)) { handle_eof: @@ -1403,8 +1467,13 @@ static int output_packet(AVInputStream *ist, int ist_index, opkt.flags= pkt->flags; //FIXME remove the following 2 lines they shall be replaced by the bitstream filters + if(ost->st->codec->codec_id != CODEC_ID_H264) { if(av_parser_change(ist->st->parser, ost->st->codec, &opkt.data, &opkt.size, data_buf, data_size, pkt->flags & PKT_FLAG_KEY)) opkt.destruct= av_destruct_packet; + } else { + opkt.data = data_buf; + opkt.size = data_size; + } write_frame(os, &opkt, ost->st->codec, bitstream_filters[ost->file_index][opkt.stream_index]); ost->st->codec->frame_number++; @@ -1455,11 +1524,23 @@ static int output_packet(AVInputStream *ist, int ist_index, fifo_bytes = av_fifo_size(ost->fifo); ret = 0; /* encode any samples remaining in fifo */ - if(fifo_bytes > 0 && enc->codec->capabilities & CODEC_CAP_SMALL_LAST_FRAME) { + if (fifo_bytes > 0) { + int osize = av_get_bits_per_sample_format(enc->sample_fmt) >> 3; int fs_tmp = enc->frame_size; - enc->frame_size = fifo_bytes / (2 * enc->channels); + av_fifo_generic_read(ost->fifo, samples, fifo_bytes, NULL); - ret = avcodec_encode_audio(enc, bit_buffer, bit_buffer_size, samples); + if (enc->codec->capabilities & CODEC_CAP_SMALL_LAST_FRAME) { + enc->frame_size = fifo_bytes / (osize * enc->channels); + } else { /* pad */ + int frame_bytes = enc->frame_size*osize*enc->channels; + if (samples_size < frame_bytes) + av_exit(1); + memset((uint8_t*)samples+fifo_bytes, 0, frame_bytes - fifo_bytes); + } + + ret = avcodec_encode_audio(enc, bit_buffer, bit_buffer_size, samples); + pkt.duration = av_rescale((int64_t)enc->frame_size*ost->st->time_base.den, + ost->st->time_base.num, enc->sample_rate); enc->frame_size = fs_tmp; } if(ret <= 0) { @@ -1737,6 +1818,8 @@ static int av_encode(AVFormatContext **output_files, av_metadata_set(&ost->st->metadata, "language", lang->value); ost->st->disposition = ist->st->disposition; + codec->bits_per_raw_sample= icodec->bits_per_raw_sample; + codec->chroma_sample_location = icodec->chroma_sample_location; if (ost->st->stream_copy) { /* if stream_copy is selected, no need to decode or encode */ @@ -1800,6 +1883,10 @@ static int av_encode(AVFormatContext **output_files, ost->encoding_needed = 1; break; case CODEC_TYPE_VIDEO: + if (ost->st->codec->pix_fmt == PIX_FMT_NONE) { + fprintf(stderr, "Video pixel format is unknown, stream cannot be decoded\n"); + av_exit(1); + } ost->video_crop = ((frame_leftBand + frame_rightBand + frame_topBand + frame_bottomBand) != 0); ost->video_pad = ((frame_padleft + frame_padright + frame_padtop + frame_padbottom) != 0); ost->video_resample = ((codec->width != icodec->width - @@ -1810,8 +1897,10 @@ static int av_encode(AVFormatContext **output_files, (frame_padtop + frame_padbottom)) || (codec->pix_fmt != icodec->pix_fmt)); if (ost->video_crop) { - ost->topBand = frame_topBand; - ost->leftBand = frame_leftBand; + ost->topBand = ost->original_topBand = frame_topBand; + ost->bottomBand = ost->original_bottomBand = frame_bottomBand; + ost->leftBand = ost->original_leftBand = frame_leftBand; + ost->rightBand = ost->original_rightBand = frame_rightBand; } if (ost->video_pad) { ost->padtop = frame_padtop; @@ -1845,7 +1934,14 @@ static int av_encode(AVFormatContext **output_files, fprintf(stderr, "Cannot get resampling context\n"); av_exit(1); } - ost->resample_height = icodec->height - (frame_topBand + frame_bottomBand); + + ost->original_height = icodec->height; + ost->original_width = icodec->width; + + ost->resample_height = icodec->height - (frame_topBand + frame_bottomBand); + ost->resample_width = icodec->width - (frame_leftBand + frame_rightBand); + ost->resample_pix_fmt= icodec->pix_fmt; + codec->bits_per_raw_sample= 0; } ost->encoding_needed = 1; ist->decoding_needed = 1; @@ -1907,6 +2003,8 @@ static int av_encode(AVFormatContext **output_files, if (!bit_buffer) bit_buffer = av_malloc(bit_buffer_size); if (!bit_buffer) { + fprintf(stderr, "Cannot allocate %d bytes output buffer\n", + bit_buffer_size); ret = AVERROR(ENOMEM); goto fail; } @@ -1919,13 +2017,13 @@ static int av_encode(AVFormatContext **output_files, if (!codec) codec = avcodec_find_encoder(ost->st->codec->codec_id); if (!codec) { - snprintf(error, sizeof(error), "Unsupported codec for output stream #%d.%d", - ost->file_index, ost->index); + snprintf(error, sizeof(error), "Encoder (codec id %d) not found for output stream #%d.%d", + ost->st->codec->codec_id, ost->file_index, ost->index); ret = AVERROR(EINVAL); goto dump_format; } if (avcodec_open(ost->st->codec, codec) < 0) { - snprintf(error, sizeof(error), "Error while opening codec for output stream #%d.%d - maybe incorrect parameters such as bit_rate, rate, width or height", + snprintf(error, sizeof(error), "Error while opening encoder for output stream #%d.%d - maybe incorrect parameters such as bit_rate, rate, width or height", ost->file_index, ost->index); ret = AVERROR(EINVAL); goto dump_format; @@ -1942,13 +2040,13 @@ static int av_encode(AVFormatContext **output_files, if (!codec) codec = avcodec_find_decoder(ist->st->codec->codec_id); if (!codec) { - snprintf(error, sizeof(error), "Unsupported codec (id=%d) for input stream #%d.%d", + snprintf(error, sizeof(error), "Decoder (codec id %d) not found for input stream #%d.%d", ist->st->codec->codec_id, ist->file_index, ist->index); ret = AVERROR(EINVAL); goto dump_format; } if (avcodec_open(ist->st->codec, codec) < 0) { - snprintf(error, sizeof(error), "Error while opening codec for input stream #%d.%d", + snprintf(error, sizeof(error), "Error while opening decoder for input stream #%d.%d", ist->file_index, ist->index); ret = AVERROR(EINVAL); goto dump_format; @@ -1961,7 +2059,6 @@ static int av_encode(AVFormatContext **output_files, /* init pts */ for(i=0;ifile_index]; ist->pts = 0; ist->next_pts = AV_NOPTS_VALUE; ist->is_start = 1; @@ -2052,7 +2149,6 @@ static int av_encode(AVFormatContext **output_files, } term_init(); - key = -1; timer_start = av_gettime(); for(; received_sigterm == 0;) { @@ -2326,12 +2422,6 @@ static int opt_me_threshold(const char *opt, const char *arg) return 0; } -static void opt_loglevel(const char *opt, const char *arg) -{ - int level = parse_number_or_die(opt, arg, OPT_INT, INT_MIN, INT_MAX); - av_log_set_level(level); -} - static int opt_verbose(const char *opt, const char *arg) { verbose = parse_number_or_die(opt, arg, OPT_INT64, -10, 10); @@ -2366,10 +2456,6 @@ static void opt_frame_crop_top(const char *arg) fprintf(stderr, "Incorrect top crop size\n"); av_exit(1); } - if ((frame_topBand % 2) != 0) { - fprintf(stderr, "Top crop size must be a multiple of 2\n"); - av_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"); av_exit(1); @@ -2384,10 +2470,6 @@ static void opt_frame_crop_bottom(const char *arg) fprintf(stderr, "Incorrect bottom crop size\n"); av_exit(1); } - if ((frame_bottomBand % 2) != 0) { - fprintf(stderr, "Bottom crop size must be a multiple of 2\n"); - av_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"); av_exit(1); @@ -2402,10 +2484,6 @@ static void opt_frame_crop_left(const char *arg) fprintf(stderr, "Incorrect left crop size\n"); av_exit(1); } - if ((frame_leftBand % 2) != 0) { - fprintf(stderr, "Left crop size must be a multiple of 2\n"); - av_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"); av_exit(1); @@ -2420,10 +2498,6 @@ static void opt_frame_crop_right(const char *arg) fprintf(stderr, "Incorrect right crop size\n"); av_exit(1); } - if ((frame_rightBand % 2) != 0) { - fprintf(stderr, "Right crop size must be a multiple of 2\n"); - av_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"); av_exit(1); @@ -2443,23 +2517,6 @@ static void opt_frame_size(const char *arg) } } - -#define SCALEBITS 10 -#define ONE_HALF (1 << (SCALEBITS - 1)) -#define FIX(x) ((int) ((x) * (1<> SCALEBITS) - -#define RGB_TO_U(r1, g1, b1, shift)\ -(((- FIX(0.16874) * r1 - FIX(0.33126) * g1 + \ - FIX(0.50000) * b1 + (ONE_HALF << shift) - 1) >> (SCALEBITS + shift)) + 128) - -#define RGB_TO_V(r1, g1, b1, shift)\ -(((FIX(0.50000) * r1 - FIX(0.41869) * g1 - \ - FIX(0.08131) * b1 + (ONE_HALF << shift) - 1) >> (SCALEBITS + shift)) + 128) - static void opt_pad_color(const char *arg) { /* Input is expected to be six hex digits similar to how colors are expressed in html tags (but without the #) */ @@ -2482,10 +2539,6 @@ static void opt_frame_pad_top(const char *arg) fprintf(stderr, "Incorrect top pad size\n"); av_exit(1); } - if ((frame_padtop % 2) != 0) { - fprintf(stderr, "Top pad size must be a multiple of 2\n"); - av_exit(1); - } } static void opt_frame_pad_bottom(const char *arg) @@ -2495,10 +2548,6 @@ static void opt_frame_pad_bottom(const char *arg) fprintf(stderr, "Incorrect bottom pad size\n"); av_exit(1); } - if ((frame_padbottom % 2) != 0) { - fprintf(stderr, "Bottom pad size must be a multiple of 2\n"); - av_exit(1); - } } @@ -2509,10 +2558,6 @@ static void opt_frame_pad_left(const char *arg) fprintf(stderr, "Incorrect left pad size\n"); av_exit(1); } - if ((frame_padleft % 2) != 0) { - fprintf(stderr, "Left pad size must be a multiple of 2\n"); - av_exit(1); - } } @@ -2523,10 +2568,6 @@ static void opt_frame_pad_right(const char *arg) fprintf(stderr, "Incorrect right pad size\n"); av_exit(1); } - if ((frame_padright % 2) != 0) { - fprintf(stderr, "Right pad size must be a multiple of 2\n"); - av_exit(1); - } } static void list_fmts(void (*get_fmt_string)(char *buf, int buf_size, int fmt), int nb_fmts) @@ -3010,7 +3051,7 @@ static void new_video_stream(AVFormatContext *oc) { AVStream *st; AVCodecContext *video_enc; - int codec_id; + enum CodecID codec_id; st = av_new_stream(oc, oc->nb_streams); if (!st) { @@ -3152,7 +3193,7 @@ static void new_audio_stream(AVFormatContext *oc) { AVStream *st; AVCodecContext *audio_enc; - int codec_id; + enum CodecID codec_id; st = av_new_stream(oc, oc->nb_streams); if (!st) { @@ -3203,6 +3244,8 @@ static void new_audio_stream(AVFormatContext *oc) audio_enc->channels = audio_channels; audio_enc->sample_fmt = audio_sample_fmt; audio_enc->channel_layout = channel_layout; + if (avcodec_channel_layout_num_channels(channel_layout) != audio_channels) + audio_enc->channel_layout = 0; if(codec && codec->sample_fmts){ const enum SampleFormat *p= codec->sample_fmts; @@ -3805,8 +3848,8 @@ static const OptionDef options[] = { { "ss", OPT_FUNC2 | HAS_ARG, {(void*)opt_start_time}, "set the start time offset", "time_off" }, { "itsoffset", OPT_FUNC2 | HAS_ARG, {(void*)opt_input_ts_offset}, "set the input ts offset", "time_off" }, { "itsscale", HAS_ARG, {(void*)opt_input_ts_scale}, "set the input ts scale", "stream:scale" }, - { "timestamp", OPT_FUNC2 | HAS_ARG, {(void*)&opt_rec_timestamp}, "set the timestamp ('now' to set the current time)", "time" }, - { "metadata", OPT_FUNC2 | HAS_ARG, {(void*)&opt_metadata}, "add metadata", "string=string" }, + { "timestamp", OPT_FUNC2 | HAS_ARG, {(void*)opt_rec_timestamp}, "set the timestamp ('now' to set the current time)", "time" }, + { "metadata", OPT_FUNC2 | HAS_ARG, {(void*)opt_metadata}, "add metadata", "string=string" }, { "dframes", OPT_INT | HAS_ARG, {(void*)&max_frames[CODEC_TYPE_DATA]}, "set the number of data frames to record", "number" }, { "benchmark", OPT_BOOL | OPT_EXPERT, {(void*)&do_benchmark}, "add timings for benchmarking" }, @@ -3818,7 +3861,7 @@ static const OptionDef options[] = { { "loop_input", OPT_BOOL | OPT_EXPERT, {(void*)&loop_input}, "loop (current only works with images)" }, { "loop_output", HAS_ARG | OPT_INT | OPT_EXPERT, {(void*)&loop_output}, "number of times to loop output in formats that support looping (0 loops forever)", "" }, { "v", HAS_ARG | OPT_FUNC2, {(void*)opt_verbose}, "set ffmpeg verbosity level", "number" }, - { "loglevel", HAS_ARG | OPT_FUNC2, {(void*)opt_loglevel}, "set libav* logging level", "number" }, + { "loglevel", HAS_ARG | OPT_FUNC2, {(void*)opt_loglevel}, "set libav* logging level", "logging level number or string" }, { "target", HAS_ARG, {(void*)opt_target}, "specify target file type (\"vcd\", \"svcd\", \"dvd\", \"dv\", \"dv50\", \"pal-vcd\", \"ntsc-svcd\", ...)", "type" }, { "threads", OPT_FUNC2 | 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", "" },