X-Git-Url: http://git.cinelerra-gg.org/git/?p=goodguy%2Fhistory.git;a=blobdiff_plain;f=cinelerra-5.1%2Fcinelerra%2Fffmpeg.C;h=2845788dc626178e0663e6dc7ddeb36625af0c9e;hp=3d51c70f28e5a8315adc4b871af940bdb59d5c14;hb=d60a59baa6cfe24c0fb153ed9e150a834ba29feb;hpb=89205d2d9298c3e37b4dd60a9dab1e3a1bdafae7 diff --git a/cinelerra-5.1/cinelerra/ffmpeg.C b/cinelerra-5.1/cinelerra/ffmpeg.C index 3d51c70f..2845788d 100644 --- a/cinelerra-5.1/cinelerra/ffmpeg.C +++ b/cinelerra-5.1/cinelerra/ffmpeg.C @@ -7,6 +7,8 @@ #include #include #include +#include + // work arounds (centos) #include #ifndef INT64_MAX @@ -17,8 +19,11 @@ #include "asset.h" #include "bccmodels.h" #include "bchash.h" -#include "fileffmpeg.h" +#include "edl.h" +#include "edlsession.h" #include "file.h" +#include "fileffmpeg.h" +#include "filesystem.h" #include "ffmpeg.h" #include "indexfile.h" #include "interlacemodes.h" @@ -28,6 +33,12 @@ #include "mwindow.h" #include "vframe.h" +#ifdef FFMPEG3 +#define url filename +#else +#define av_register_all(s) +#define avfilter_register_all(s) +#endif #define VIDEO_INBUF_SIZE 0x10000 #define AUDIO_INBUF_SIZE 0x10000 @@ -251,6 +262,10 @@ FFStream::FFStream(FFMPEG *ffmpeg, AVStream *st, int fidx) need_packet = 1; frame = fframe = 0; bsfc = 0; + stats_fp = 0; + stats_filename = 0; + stats_in = 0; + pass = 0; } FFStream::~FFStream() @@ -264,6 +279,9 @@ FFStream::~FFStream() if( frame ) av_frame_free(&frame); if( fframe ) av_frame_free(&fframe); delete frm_lock; + if( stats_fp ) fclose(stats_fp); + if( stats_in ) av_freep(&stats_in); + delete [] stats_filename; } void FFStream::ff_lock(const char *cp) @@ -309,7 +327,8 @@ int FFStream::decode_activate() av_dict_copy(&copts, ffmpeg->opts, 0); int ret = 0; // this should be avformat_copy_context(), but no copy avail - ret = avformat_open_input(&fmt_ctx, ffmpeg->fmt_ctx->filename, NULL, &copts); + ret = avformat_open_input(&fmt_ctx, + ffmpeg->fmt_ctx->url, ffmpeg->fmt_ctx->iformat, &copts); if( ret >= 0 ) { ret = avformat_find_stream_info(fmt_ctx, 0); st = fmt_ctx->streams[fidx]; @@ -324,9 +343,6 @@ int FFStream::decode_activate() ret = AVERROR(ENOMEM); } if( ret >= 0 ) { - av_codec_set_pkt_timebase(avctx, st->time_base); - if( decoder->capabilities & AV_CODEC_CAP_DR1 ) - avctx->flags |= CODEC_FLAG_EMU_EDGE; avcodec_parameters_to_context(avctx, st->codecpar); if( !av_dict_get(copts, "threads", NULL, 0) ) avctx->thread_count = ffmpeg->ff_cpus(); @@ -475,6 +491,10 @@ int FFStream::encode_frame(AVFrame *frame) ret = write_packet(opkt); if( ret < 0 ) break; ++pkts; + if( frame && stats_fp ) { + ret = write_stats_file(); + if( ret < 0 ) break; + } } ff_err(ret, "FFStream::encode_frame: encode failed\n"); return -1; @@ -485,11 +505,75 @@ int FFStream::flush() if( writing < 0 ) return -1; int ret = encode_frame(0); + if( ret >= 0 && stats_fp ) { + ret = write_stats_file(); + close_stats_file(); + } if( ret < 0 ) ff_err(ret, "FFStream::flush"); return ret >= 0 ? 0 : 1; } + +int FFStream::open_stats_file() +{ + stats_fp = fopen(stats_filename,"w"); + return stats_fp ? 0 : AVERROR(errno); +} + +int FFStream::close_stats_file() +{ + if( stats_fp ) { + fclose(stats_fp); stats_fp = 0; + } + return 0; +} + +int FFStream::read_stats_file() +{ + int64_t len = 0; struct stat stats_st; + int fd = open(stats_filename, O_RDONLY); + int ret = fd >= 0 ? 0: ENOENT; + if( !ret && fstat(fd, &stats_st) ) + ret = EINVAL; + if( !ret ) { + len = stats_st.st_size; + stats_in = (char *)av_malloc(len+1); + if( !stats_in ) + ret = ENOMEM; + } + if( !ret && read(fd, stats_in, len+1) != len ) + ret = EIO; + if( !ret ) { + stats_in[len] = 0; + avctx->stats_in = stats_in; + } + if( fd >= 0 ) + close(fd); + return !ret ? 0 : AVERROR(ret); +} + +int FFStream::write_stats_file() +{ + int ret = 0; + if( avctx->stats_out && (ret=strlen(avctx->stats_out)) > 0 ) { + int len = fwrite(avctx->stats_out, 1, ret, stats_fp); + if( ret != len ) + ff_err(ret = AVERROR(errno), "FFStream::write_stats_file"); + } + return ret; +} + +int FFStream::init_stats_file() +{ + int ret = 0; + if( (pass & 2) && (ret = read_stats_file()) < 0 ) + ff_err(ret, "stat file read: %s", stats_filename); + if( (pass & 1) && (ret=open_stats_file()) < 0 ) + ff_err(ret, "stat file open: %s", stats_filename); + return ret >= 0 ? 0 : ret; +} + int FFStream::seek(int64_t no, double rate) { // default ffmpeg native seek @@ -681,7 +765,7 @@ int FFAudioStream::decode_frame(AVFrame *frame) ff_err(ret, "FFAudioStream::decode_frame: Could not read audio frame\n"); return -1; } - int64_t pkt_ts = av_frame_get_best_effort_timestamp(frame); + int64_t pkt_ts = frame->best_effort_timestamp; if( pkt_ts != AV_NOPTS_VALUE ) curr_pos = ffmpeg->to_secs(pkt_ts - nudge, st->time_base) * sample_rate + 0.5; return 1; @@ -691,7 +775,7 @@ int FFAudioStream::encode_activate() { if( writing >= 0 ) return writing; if( !avctx->codec ) return writing = 0; - frame_sz = avctx->codec->capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE ? + frame_sz = avctx->codec->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE ? 10000 : avctx->frame_size; return FFStream::encode_activate(); } @@ -855,7 +939,7 @@ int FFVideoStream::decode_frame(AVFrame *frame) ff_err(ret, "FFVideoStream::decode_frame: Could not read video frame\n"); return -1; } - int64_t pkt_ts = av_frame_get_best_effort_timestamp(frame); + int64_t pkt_ts = frame->best_effort_timestamp; if( pkt_ts != AV_NOPTS_VALUE ) curr_pos = ffmpeg->to_secs(pkt_ts - nudge, st->time_base) * frame_rate + 0.5; return 1; @@ -970,6 +1054,7 @@ AVPixelFormat FFVideoConvert::color_model_to_pix_fmt(int color_model) case BC_RGB161616: return AV_PIX_FMT_RGB48LE; case BC_RGBA16161616: return AV_PIX_FMT_RGBA64LE; case BC_AYUV16161616: return AV_PIX_FMT_AYUV64LE; + case BC_GBRP: return AV_PIX_FMT_GBRP; default: break; } @@ -995,6 +1080,7 @@ int FFVideoConvert::pix_fmt_to_color_model(AVPixelFormat pix_fmt) case AV_PIX_FMT_RGB48LE: return BC_RGB161616; case AV_PIX_FMT_RGBA64LE: return BC_RGBA16161616; case AV_PIX_FMT_AYUV64LE: return BC_AYUV16161616; + case AV_PIX_FMT_GBRP: return BC_GBRP; default: break; } @@ -1091,7 +1177,7 @@ int FFVideoConvert::transfer_cmodel(VFrame *frame, AVFrame *ifp) { int ret = convert_cmodel(frame, ifp); if( ret > 0 ) { - const AVDictionary *src = av_frame_get_metadata(ifp); + const AVDictionary *src = ifp->metadata; AVDictionaryEntry *t = NULL; BC_Hash *hp = frame->get_params(); //hp->clear(); @@ -1188,7 +1274,7 @@ int FFVideoConvert::transfer_pixfmt(VFrame *frame, AVFrame *ofp) int ret = convert_pixfmt(frame, ofp); if( ret > 0 ) { BC_Hash *hp = frame->get_params(); - AVDictionary **dict = avpriv_frame_get_metadatap(ofp); + AVDictionary **dict = &ofp->metadata; //av_dict_free(dict); for( int i=0; isize(); ++i ) { char *key = hp->get_key(i), *val = hp->get_value(i); @@ -1305,6 +1391,37 @@ AVRational FFMPEG::to_time_base(int sample_rate) return (AVRational){1, sample_rate}; } +int FFMPEG::get_fmt_score(AVSampleFormat dst_fmt, AVSampleFormat src_fmt) +{ + int score = 0; + int dst_planar = av_sample_fmt_is_planar(dst_fmt); + int src_planar = av_sample_fmt_is_planar(src_fmt); + if( dst_planar != src_planar ) ++score; + int dst_bytes = av_get_bytes_per_sample(dst_fmt); + int src_bytes = av_get_bytes_per_sample(src_fmt); + score += (src_bytes > dst_bytes ? 100 : -10) * (src_bytes - dst_bytes); + int src_packed = av_get_packed_sample_fmt(src_fmt); + int dst_packed = av_get_packed_sample_fmt(dst_fmt); + if( dst_packed == AV_SAMPLE_FMT_S32 && src_packed == AV_SAMPLE_FMT_FLT ) score += 20; + if( dst_packed == AV_SAMPLE_FMT_FLT && src_packed == AV_SAMPLE_FMT_S32 ) score += 2; + return score; +} + +AVSampleFormat FFMPEG::find_best_sample_fmt_of_list( + const AVSampleFormat *sample_fmts, AVSampleFormat src_fmt) +{ + AVSampleFormat best = AV_SAMPLE_FMT_NONE; + int best_score = get_fmt_score(best, src_fmt); + for( int i=0; sample_fmts[i] >= 0; ++i ) { + AVSampleFormat sample_fmt = sample_fmts[i]; + int score = get_fmt_score(sample_fmt, src_fmt); + if( score >= best_score ) continue; + best = sample_fmt; best_score = score; + } + return best; +} + + void FFMPEG::set_option_path(char *path, const char *fmt, ...) { char *ep = path + BCTEXTLEN-1; @@ -1401,10 +1518,10 @@ int FFMPEG::get_file_format() return ret; } -int FFMPEG::scan_option_line(char *cp, char *tag, char *val) +int FFMPEG::scan_option_line(const char *cp, char *tag, char *val) { while( *cp == ' ' || *cp == '\t' ) ++cp; - char *bp = cp; + const char *bp = cp; while( *cp && *cp != ' ' && *cp != '\t' && *cp != '=' && *cp != '\n' ) ++cp; int len = cp - bp; if( !len || len > BCSTRLEN-1 ) return 1; @@ -1422,6 +1539,123 @@ int FFMPEG::scan_option_line(char *cp, char *tag, char *val) return 0; } +int FFMPEG::can_render(const char *fformat, const char *type) +{ + FileSystem fs; + char option_path[BCTEXTLEN]; + FFMPEG::set_option_path(option_path, type); + fs.update(option_path); + int total_files = fs.total_files(); + for( int i=0; iget_name(); + const char *ext = strrchr(name,'.'); + if( !ext ) continue; + if( !strcmp(fformat, ++ext) ) return 1; + } + return 0; +} + +int FFMPEG::get_ff_option(const char *nm, const char *options, char *value) +{ + for( const char *cp=options; *cp!=0; ) { + char line[BCTEXTLEN], *bp = line, *ep = bp+sizeof(line)-1; + while( bp < ep && *cp && *cp!='\n' ) *bp++ = *cp++; + if( *cp ) ++cp; + *bp = 0; + if( !line[0] || line[0] == '#' || line[0] == ';' ) continue; + char key[BCSTRLEN], val[BCTEXTLEN]; + if( FFMPEG::scan_option_line(line, key, val) ) continue; + if( !strcmp(key, nm) ) { + strncpy(value, val, BCSTRLEN); + return 0; + } + } + return 1; +} + +void FFMPEG::scan_audio_options(Asset *asset, EDL *edl) +{ + char cin_sample_fmt[BCSTRLEN]; + int cin_fmt = AV_SAMPLE_FMT_NONE; + const char *options = asset->ff_audio_options; + if( !get_ff_option("cin_sample_fmt", options, cin_sample_fmt) ) + cin_fmt = (int)av_get_sample_fmt(cin_sample_fmt); + if( cin_fmt < 0 ) { + char audio_codec[BCSTRLEN]; audio_codec[0] = 0; + AVCodec *av_codec = !FFMPEG::get_codec(audio_codec, "audio", asset->acodec) ? + avcodec_find_encoder_by_name(audio_codec) : 0; + if( av_codec && av_codec->sample_fmts ) + cin_fmt = find_best_sample_fmt_of_list(av_codec->sample_fmts, AV_SAMPLE_FMT_FLT); + } + if( cin_fmt < 0 ) cin_fmt = AV_SAMPLE_FMT_S16; + const char *name = av_get_sample_fmt_name((AVSampleFormat)cin_fmt); + if( !name ) name = _("None"); + strcpy(asset->ff_sample_format, name); + + char value[BCSTRLEN]; + if( !get_ff_option("cin_bitrate", options, value) ) + asset->ff_audio_bitrate = atoi(value); + if( !get_ff_option("cin_quality", options, value) ) + asset->ff_audio_quality = atoi(value); +} + +void FFMPEG::load_audio_options(Asset *asset, EDL *edl) +{ + char options_path[BCTEXTLEN]; + set_option_path(options_path, "audio/%s", asset->acodec); + if( !load_options(options_path, + asset->ff_audio_options, + sizeof(asset->ff_audio_options)) ) + scan_audio_options(asset, edl); +} + +void FFMPEG::scan_video_options(Asset *asset, EDL *edl) +{ + char cin_pix_fmt[BCSTRLEN]; + int cin_fmt = AV_PIX_FMT_NONE; + const char *options = asset->ff_video_options; + if( !get_ff_option("cin_pix_fmt", options, cin_pix_fmt) ) + cin_fmt = (int)av_get_pix_fmt(cin_pix_fmt); + if( cin_fmt < 0 ) { + char video_codec[BCSTRLEN]; video_codec[0] = 0; + AVCodec *av_codec = !get_codec(video_codec, "video", asset->vcodec) ? + avcodec_find_encoder_by_name(video_codec) : 0; + if( av_codec && av_codec->pix_fmts ) { + if( 0 && edl ) { // frequently picks a bad answer + int color_model = edl->session->color_model; + int max_bits = BC_CModels::calculate_pixelsize(color_model) * 8; + max_bits /= BC_CModels::components(color_model); + cin_fmt = avcodec_find_best_pix_fmt_of_list(av_codec->pix_fmts, + (BC_CModels::is_yuv(color_model) ? + (max_bits > 8 ? AV_PIX_FMT_AYUV64LE : AV_PIX_FMT_YUV444P) : + (max_bits > 8 ? AV_PIX_FMT_RGB48LE : AV_PIX_FMT_RGB24)), 0, 0); + } + else + cin_fmt = av_codec->pix_fmts[0]; + } + } + if( cin_fmt < 0 ) cin_fmt = AV_PIX_FMT_YUV420P; + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get((AVPixelFormat)cin_fmt); + const char *name = desc ? desc->name : _("None"); + strcpy(asset->ff_pixel_format, name); + + char value[BCSTRLEN]; + if( !get_ff_option("cin_bitrate", options, value) ) + asset->ff_video_bitrate = atoi(value); + if( !get_ff_option("cin_quality", options, value) ) + asset->ff_video_quality = atoi(value); +} + +void FFMPEG::load_video_options(Asset *asset, EDL *edl) +{ + char options_path[BCTEXTLEN]; + set_option_path(options_path, "video/%s", asset->vcodec); + if( !load_options(options_path, + asset->ff_video_options, + sizeof(asset->ff_video_options)) ) + scan_video_options(asset, edl); +} + int FFMPEG::load_defaults(const char *path, const char *type, char *codec, char *codec_options, int len) { @@ -1442,18 +1676,24 @@ int FFMPEG::load_defaults(const char *path, const char *type, return load_options(default_file, codec_options, len); } -void FFMPEG::set_asset_format(Asset *asset, const char *text) +void FFMPEG::set_asset_format(Asset *asset, EDL *edl, const char *text) { if( asset->format != FILE_FFMPEG ) return; if( text != asset->fformat ) strcpy(asset->fformat, text); - if( !asset->ff_audio_options[0] ) { - asset->audio_data = !load_defaults("audio", text, asset->acodec, - asset->ff_audio_options, sizeof(asset->ff_audio_options)); + if( asset->audio_data && !asset->ff_audio_options[0] ) { + if( !load_defaults("audio", text, asset->acodec, + asset->ff_audio_options, sizeof(asset->ff_audio_options)) ) + scan_audio_options(asset, edl); + else + asset->audio_data = 0; } - if( !asset->ff_video_options[0] ) { - asset->video_data = !load_defaults("video", text, asset->vcodec, - asset->ff_video_options, sizeof(asset->ff_video_options)); + if( asset->video_data && !asset->ff_video_options[0] ) { + if( !load_defaults("video", text, asset->vcodec, + asset->ff_video_options, sizeof(asset->ff_video_options)) ) + scan_video_options(asset, edl); + else + asset->video_data = 0; } } @@ -1465,19 +1705,18 @@ int FFMPEG::get_encoder(const char *options, eprintf(_("options open failed %s\n"),options); return 1; } - if( get_encoder(fp, format, codec, bsfilter) ) + char line[BCTEXTLEN]; + if( !fgets(line, sizeof(line), fp) || + scan_encoder(line, format, codec, bsfilter) ) eprintf(_("format/codec not found %s\n"), options); fclose(fp); return 0; } -int FFMPEG::get_encoder(FILE *fp, +int FFMPEG::scan_encoder(const char *line, char *format, char *codec, char *bsfilter) { format[0] = codec[0] = bsfilter[0] = 0; - char line[BCTEXTLEN]; - if( !fgets(line, sizeof(line), fp) ) return 1; - line[sizeof(line)-1] = 0; if( scan_option_line(line, format, codec) ) return 1; char *cp = codec; while( *cp && *cp != '|' ) ++cp; @@ -1696,7 +1935,9 @@ int FFMPEG::init_decoder(const char *filename) char file_opts[BCTEXTLEN]; char *bp = strrchr(strcpy(file_opts, filename), '/'); char *sp = strrchr(!bp ? file_opts : bp, '.'); + if( !sp ) sp = bp + strlen(bp); FILE *fp = 0; + AVInputFormat *ifmt = 0; if( sp ) { strcpy(sp, ".opts"); fp = fopen(file_opts, "r"); @@ -1704,12 +1945,16 @@ int FFMPEG::init_decoder(const char *filename) if( fp ) { read_options(fp, file_opts, opts); fclose(fp); + AVDictionaryEntry *tag; + if( (tag=av_dict_get(opts, "format", NULL, 0)) != 0 ) { + ifmt = av_find_input_format(tag->value); + } } else load_options("decode.opts", opts); AVDictionary *fopts = 0; av_dict_copy(&fopts, opts, 0); - int ret = avformat_open_input(&fmt_ctx, filename, NULL, &fopts); + int ret = avformat_open_input(&fmt_ctx, filename, ifmt, &fopts); av_dict_free(&fopts); if( ret >= 0 ) ret = avformat_find_stream_info(fmt_ctx, NULL); @@ -1723,8 +1968,8 @@ int FFMPEG::init_decoder(const char *filename) int FFMPEG::open_decoder() { struct stat st; - if( stat(fmt_ctx->filename, &st) < 0 ) { - eprintf(_("can't stat file: %s\n"), fmt_ctx->filename); + if( stat(fmt_ctx->url, &st) < 0 ) { + eprintf(_("can't stat file: %s\n"), fmt_ctx->url); return 1; } @@ -1811,14 +2056,18 @@ int FFMPEG::open_decoder() int FFMPEG::init_encoder(const char *filename) { - int fd = ::open(filename,O_WRONLY); - if( fd < 0 ) fd = open(filename,O_WRONLY+O_CREAT,0666); - if( fd < 0 ) { +// try access first for named pipes + int ret = access(filename, W_OK); + if( ret ) { + int fd = ::open(filename,O_WRONLY); + if( fd < 0 ) fd = open(filename,O_WRONLY+O_CREAT,0666); + if( fd >= 0 ) { close(fd); ret = 0; } + } + if( ret ) { eprintf(_("bad file path: %s\n"), filename); return 1; } - ::close(fd); - int ret = get_file_format(); + ret = get_file_format(); if( ret > 0 ) { eprintf(_("bad file format: %s\n"), filename); return 1; @@ -1862,7 +2111,9 @@ int FFMPEG::open_encoder(const char *type, const char *spec) return 1; } +#ifdef HAVE_DV if( !strcmp(codec_name, CODEC_TAG_DVSD) ) strcpy(codec_name, "dv"); +#endif else if( !strcmp(codec_name, CODEC_TAG_MJPEG) ) strcpy(codec_name, "mjpeg"); else if( !strcmp(codec_name, CODEC_TAG_JPEG) ) strcpy(codec_name, "jpeg"); @@ -1913,6 +2164,19 @@ int FFMPEG::open_encoder(const char *type, const char *spec) sprintf(arg, "%d", asset->ff_audio_bitrate); av_dict_set(&sopts, "b", arg, 0); } + else if( asset->ff_audio_quality >= 0 ) { + ctx->global_quality = asset->ff_audio_quality * FF_QP2LAMBDA; + ctx->qmin = ctx->qmax = asset->ff_audio_quality; + ctx->mb_lmin = ctx->qmin * FF_QP2LAMBDA; + ctx->mb_lmax = ctx->qmax * FF_QP2LAMBDA; + ctx->flags |= AV_CODEC_FLAG_QSCALE; + char arg[BCSTRLEN]; + av_dict_set(&sopts, "flags", "+qscale", 0); + sprintf(arg, "%d", asset->ff_audio_quality); + av_dict_set(&sopts, "qscale", arg, 0); + sprintf(arg, "%d", ctx->global_quality); + av_dict_set(&sopts, "global_quality", arg, 0); + } int aidx = ffaudio.size(); int fidx = aidx + ffvideo.size(); FFAudioStream *aud = new FFAudioStream(this, st, aidx, fidx); @@ -1929,7 +2193,10 @@ int FFMPEG::open_encoder(const char *type, const char *spec) break; } ctx->time_base = st->time_base = (AVRational){1, aud->sample_rate}; - ctx->sample_fmt = codec->sample_fmts[0]; + AVSampleFormat sample_fmt = av_get_sample_fmt(asset->ff_sample_format); + if( sample_fmt == AV_SAMPLE_FMT_NONE ) + sample_fmt = codec->sample_fmts ? codec->sample_fmts[0] : AV_SAMPLE_FMT_S16; + ctx->sample_fmt = sample_fmt; uint64_t layout = av_get_default_channel_layout(ctx->channels); aud->resample_context = swr_alloc_set_opts(NULL, layout, ctx->sample_fmt, aud->sample_rate, @@ -1962,7 +2229,7 @@ int FFMPEG::open_encoder(const char *type, const char *spec) ctx->qmin = ctx->qmax = asset->ff_video_quality; ctx->mb_lmin = ctx->qmin * FF_QP2LAMBDA; ctx->mb_lmax = ctx->qmax * FF_QP2LAMBDA; - ctx->flags |= CODEC_FLAG_QSCALE; + ctx->flags |= AV_CODEC_FLAG_QSCALE; char arg[BCSTRLEN]; av_dict_set(&sopts, "flags", "+qscale", 0); sprintf(arg, "%d", asset->ff_video_quality); @@ -1976,18 +2243,28 @@ int FFMPEG::open_encoder(const char *type, const char *spec) vstrm_index.append(ffidx(vidx, 0)); vid->avctx = ctx; ffvideo.append(vid); fst = vid; vid->width = asset->width; - ctx->width = (vid->width+3) & ~3; vid->height = asset->height; - ctx->height = (vid->height+3) & ~3; vid->frame_rate = asset->frame_rate; + + AVPixelFormat pix_fmt = av_get_pix_fmt(asset->ff_pixel_format); + if( pix_fmt == AV_PIX_FMT_NONE ) + pix_fmt = codec->pix_fmts ? codec->pix_fmts[0] : AV_PIX_FMT_YUV420P; + ctx->pix_fmt = pix_fmt; + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + int mask_w = (1<log2_chroma_w)-1; + ctx->width = (vid->width+mask_w) & ~mask_w; + int mask_h = (1<log2_chroma_h)-1; + ctx->height = (vid->height+mask_h) & ~mask_h; ctx->sample_aspect_ratio = to_sample_aspect_ratio(asset); - ctx->pix_fmt = codec->pix_fmts ? codec->pix_fmts[0] : AV_PIX_FMT_YUV420P; AVRational frame_rate = check_frame_rate(codec, vid->frame_rate); if( !frame_rate.num || !frame_rate.den ) { eprintf(_("check_frame_rate failed %s\n"), filename); ret = 1; break; } + av_reduce(&frame_rate.num, &frame_rate.den, + frame_rate.num, frame_rate.den, INT_MAX); + ctx->framerate = (AVRational) { frame_rate.num, frame_rate.den }; ctx->time_base = (AVRational) { frame_rate.den, frame_rate.num }; st->avg_frame_rate = frame_rate; st->time_base = ctx->time_base; @@ -2000,11 +2277,44 @@ int FFMPEG::open_encoder(const char *type, const char *spec) eprintf(_("not audio/video, %s:%s\n"), codec_name, filename); ret = 1; } + + if( ctx ) { + AVDictionaryEntry *tag; + if( (tag=av_dict_get(sopts, "cin_stats_filename", NULL, 0)) != 0 ) { + char suffix[BCSTRLEN]; sprintf(suffix,"-%d.log",fst->fidx); + fst->stats_filename = cstrcat(2, tag->value, suffix); + } + if( (tag=av_dict_get(sopts, "flags", NULL, 0)) != 0 ) { + int pass = fst->pass; + char *cp = tag->value; + while( *cp ) { + int ch = *cp++, pfx = ch=='-' ? -1 : ch=='+' ? 1 : 0; + if( !isalnum(!pfx ? ch : (ch=*cp++)) ) continue; + char id[BCSTRLEN], *bp = id, *ep = bp+sizeof(id)-1; + for( *bp++=ch; isalnum(ch=*cp); ++cp ) + if( bp < ep ) *bp++ = ch; + *bp = 0; + if( !strcmp(id, "pass1") ) { + pass = pfx<0 ? (pass&~1) : pfx>0 ? (pass|1) : 1; + } + else if( !strcmp(id, "pass2") ) { + pass = pfx<0 ? (pass&~2) : pfx>0 ? (pass|2) : 2; + } + } + if( (fst->pass=pass) ) { + if( pass & 1 ) ctx->flags |= AV_CODEC_FLAG_PASS1; + if( pass & 2 ) ctx->flags |= AV_CODEC_FLAG_PASS2; + } + } + } } if( !ret ) { if( fmt_ctx->oformat->flags & AVFMT_GLOBALHEADER ) - ctx->flags |= CODEC_FLAG_GLOBAL_HEADER; - + ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; + if( fst->stats_filename && (ret=fst->init_stats_file()) ) + eprintf(_("error: stats file = %s\n"), fst->stats_filename); + } + if( !ret ) { av_dict_set(&sopts, "cin_bitrate", 0, 0); av_dict_set(&sopts, "cin_quality", 0, 0); @@ -2016,6 +2326,13 @@ int FFMPEG::open_encoder(const char *type, const char *spec) if( ret < 0 ) fprintf(stderr, "Could not copy the stream parameters\n"); } + if( ret >= 0 ) { +_Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") + ret = avcodec_copy_context(st->codec, ctx); +_Pragma("GCC diagnostic warning \"-Wdeprecated-declarations\"") + if( ret < 0 ) + fprintf(stderr, "Could not copy the stream context\n"); + } if( ret < 0 ) { ff_err(ret,"FFMPEG::open_encoder"); eprintf(_("open failed %s:%s\n"), codec_name, filename); @@ -2162,9 +2479,9 @@ int FFMPEG::encode_activate() if( encoding < 0 ) { encoding = 0; if( !(fmt_ctx->flags & AVFMT_NOFILE) && - (ret=avio_open(&fmt_ctx->pb, fmt_ctx->filename, AVIO_FLAG_WRITE)) < 0 ) { + (ret=avio_open(&fmt_ctx->pb, fmt_ctx->url, AVIO_FLAG_WRITE)) < 0 ) { ff_err(ret, "FFMPEG::encode_activate: err opening : %s\n", - fmt_ctx->filename); + fmt_ctx->url); return -1; } @@ -2178,7 +2495,7 @@ int FFMPEG::encode_activate() while( --pi >= 0 && fmt_ctx->programs[pi]->id != prog_id ); AVDictionary **meta = &prog->metadata; av_dict_set(meta, "service_provider", "cin5", 0); - const char *path = fmt_ctx->filename, *bp = strrchr(path,'/'); + const char *path = fmt_ctx->url, *bp = strrchr(path,'/'); if( bp ) path = bp + 1; av_dict_set(meta, "title", path, 0); @@ -2210,7 +2527,7 @@ int FFMPEG::encode_activate() ret = avformat_write_header(fmt_ctx, &fopts); if( ret < 0 ) { ff_err(ret, "FFMPEG::encode_activate: write header failed %s\n", - fmt_ctx->filename); + fmt_ctx->url); return -1; } av_dict_free(&fopts); @@ -2555,14 +2872,14 @@ int FFVideoStream::create_filter(const char *filter_spec, AVCodecParameters *avp int i = sizeof(filter_name); while( --i>=0 && *sp!=0 && !strchr(" \t:=,",*sp) ) *np++ = *sp++; *np = 0; - AVFilter *filter = !filter_name[0] ? 0 : avfilter_get_by_name(filter_name); + const AVFilter *filter = !filter_name[0] ? 0 : avfilter_get_by_name(filter_name); if( !filter || avfilter_pad_get_type(filter->inputs,0) != AVMEDIA_TYPE_VIDEO ) { ff_err(AVERROR(EINVAL), "FFVideoStream::create_filter: %s\n", filter_spec); return -1; } filter_graph = avfilter_graph_alloc(); - AVFilter *buffersrc = avfilter_get_by_name("buffer"); - AVFilter *buffersink = avfilter_get_by_name("buffersink"); + const AVFilter *buffersrc = avfilter_get_by_name("buffer"); + const AVFilter *buffersink = avfilter_get_by_name("buffersink"); int ret = 0; char args[BCTEXTLEN]; AVPixelFormat pix_fmt = (AVPixelFormat)avpar->format; @@ -2596,14 +2913,14 @@ int FFAudioStream::create_filter(const char *filter_spec, AVCodecParameters *avp int i = sizeof(filter_name); while( --i>=0 && *sp!=0 && !strchr(" \t:=,",*sp) ) *np++ = *sp++; *np = 0; - AVFilter *filter = !filter_name[0] ? 0 : avfilter_get_by_name(filter_name); + const AVFilter *filter = !filter_name[0] ? 0 : avfilter_get_by_name(filter_name); if( !filter || avfilter_pad_get_type(filter->inputs,0) != AVMEDIA_TYPE_AUDIO ) { ff_err(AVERROR(EINVAL), "FFAudioStream::create_filter: %s\n", filter_spec); return -1; } filter_graph = avfilter_graph_alloc(); - AVFilter *buffersrc = avfilter_get_by_name("abuffer"); - AVFilter *buffersink = avfilter_get_by_name("abuffersink"); + const AVFilter *buffersrc = avfilter_get_by_name("abuffer"); + const AVFilter *buffersink = avfilter_get_by_name("abuffersink"); int ret = 0; char args[BCTEXTLEN]; AVSampleFormat sample_fmt = (AVSampleFormat)avpar->format; snprintf(args, sizeof(args), @@ -2675,6 +2992,7 @@ int FFMPEG::scan(IndexState *index_state, int64_t *scan_position, int *canceled) if( !frame ) { fprintf(stderr,"FFMPEG::scan: "); fprintf(stderr,_("av_frame_alloc failed\n")); + fprintf(stderr,"FFMPEG::scan:file=%s\n", file_base->asset->path); return -1; } @@ -2720,6 +3038,7 @@ int FFMPEG::scan(IndexState *index_state, int64_t *scan_position, int *canceled) } fprintf(stderr,"FFMPEG::scan: "); fprintf(stderr,_("codec open failed\n")); + fprintf(stderr,"FFMPEG::scan:file=%s\n", file_base->asset->path); avcodec_free_context(&avctx); }