From 85a4302e7031b0285aeb9559aa6dbc531db6e443 Mon Sep 17 00:00:00 2001 From: Good Guy Date: Tue, 1 Dec 2020 16:00:34 -0700 Subject: [PATCH] Andrew improves asset of Interlace + some aspect ratio fixups --- cinelerra-5.1/cinelerra/ffmpeg.C | 130 ++++++++++++++++++++++++++- cinelerra-5.1/cinelerra/ffmpeg.h | 4 + cinelerra-5.1/cinelerra/fileffmpeg.C | 16 +++- cinelerra-5.1/cinelerra/mwindow.C | 21 ++++- 4 files changed, 168 insertions(+), 3 deletions(-) diff --git a/cinelerra-5.1/cinelerra/ffmpeg.C b/cinelerra-5.1/cinelerra/ffmpeg.C index 97b6698a..0f41bd23 100644 --- a/cinelerra-5.1/cinelerra/ffmpeg.C +++ b/cinelerra-5.1/cinelerra/ffmpeg.C @@ -1213,6 +1213,40 @@ int FFVideoStream::decode_frame(AVFrame *frame) return 1; } +int FFVideoStream::probe(int64_t pos) +{ + int ret = video_seek(pos); + if( ret < 0 ) return -1; + if( !frame && !(frame=av_frame_alloc()) ) { + fprintf(stderr, "FFVideoStream::probe: av_frame_alloc failed\n"); + return -1; + } + + if (ffmpeg->interlace_from_codec) + return 1; + + ret = read_frame(frame); + if( ret > 0 ) { + //printf("codec interlace: %i \n",frame->interlaced_frame); + //printf("codec tff: %i \n",frame->top_field_first); + + if (!frame->interlaced_frame) + ffmpeg->interlace_from_codec = AV_FIELD_PROGRESSIVE; + if ((frame->interlaced_frame) && (frame->top_field_first)) + ffmpeg->interlace_from_codec = AV_FIELD_TT; + if ((frame->interlaced_frame) && (!frame->top_field_first)) + ffmpeg->interlace_from_codec = AV_FIELD_BB; + //printf("Interlace mode from codec: %i\n", ffmpeg->interlace_from_codec); + + } + + if( frame->format == AV_PIX_FMT_NONE || frame->width <= 0 || frame->height <= 0 ) + ret = -1; + + ret = ret > 0 ? 1 : ret < 0 ? -1 : 0; + return ret; +} + int FFVideoStream::load(VFrame *vframe, int64_t pos) { int ret = video_seek(pos); @@ -1221,6 +1255,8 @@ int FFVideoStream::load(VFrame *vframe, int64_t pos) fprintf(stderr, "FFVideoStream::load: av_frame_alloc failed\n"); return -1; } + + int i = MAX_RETRY + pos - curr_pos; int64_t cache_start = 0; while( ret>=0 && !flushed && curr_pos<=pos && --i>=0 ) { @@ -1391,6 +1427,7 @@ int FFVideoStream::encode(VFrame *vframe) int FFVideoStream::drain() { + return 0; } @@ -1776,6 +1813,7 @@ FFMPEG::FFMPEG(FileBase *file_base) flow = 1; decoding = encoding = 0; has_audio = has_video = 0; + interlace_from_codec = 0; opts = 0; opt_duration = -1; opt_video_filter = 0; @@ -2411,6 +2449,10 @@ int FFMPEG::info(char *text, int len) AVPixelFormat pix_fmt = (AVPixelFormat)st->codecpar->format; const char *pfn = av_get_pix_fmt_name(pix_fmt); report(" pix %s\n", pfn ? pfn : unkn); + int interlace = st->codecpar->field_order; + report(" interlace (container level): %i\n", interlace ? interlace : -1); + int interlace_codec = interlace_from_codec; + report(" interlace (codec level): %i\n", interlace_codec ? interlace_codec : -1); enum AVColorSpace space = st->codecpar->color_space; const char *nm = av_color_space_name(space); report(" color space:%s", nm ? nm : unkn); @@ -2889,6 +2931,25 @@ int FFMPEG::open_encoder(const char *type, const char *spec) vid->interlaced = asset->interlace_mode == ILACE_MODE_TOP_FIRST || asset->interlace_mode == ILACE_MODE_BOTTOM_FIRST ? 1 : 0; vid->top_field_first = asset->interlace_mode == ILACE_MODE_TOP_FIRST ? 1 : 0; + switch (asset->interlace_mode) { + case ILACE_MODE_TOP_FIRST: + if (ctx->codec->id == AV_CODEC_ID_MJPEG) + av_dict_set(&sopts, "field_order", "tt", 0); + else + av_dict_set(&sopts, "field_order", "tb", 0); + if (ctx->codec_id != AV_CODEC_ID_MJPEG) + av_dict_set(&sopts, "flags", "+ilme+ildct", 0); + break; + case ILACE_MODE_BOTTOM_FIRST: + if (ctx->codec->id == AV_CODEC_ID_MJPEG) + av_dict_set(&sopts, "field_order", "bb", 0); + else + av_dict_set(&sopts, "field_order", "bt", 0); + if (ctx->codec_id != AV_CODEC_ID_MJPEG) + av_dict_set(&sopts, "flags", "+ilme+ildct", 0); + break; + case ILACE_MODE_NOTINTERLACED: av_dict_set(&sopts, "field_order", "progressive", 0); break; + } break; } default: eprintf(_("not audio/video, %s:%s\n"), codec_name, filename); @@ -3181,6 +3242,33 @@ int FFMPEG::audio_seek(int stream, int64_t pos) return 0; } +int FFMPEG::video_probe(int64_t pos) +{ + int vidx = vstrm_index[0].st_idx; + FFVideoStream *vid = ffvideo[vidx]; + vid->probe(pos); + + int interlace1 = interlace_from_codec; + //printf("interlace from codec: %i\n", interlace1); + + switch (interlace1) + { + case AV_FIELD_TT: + case AV_FIELD_TB: + return ILACE_MODE_TOP_FIRST; + case AV_FIELD_BB: + case AV_FIELD_BT: + return ILACE_MODE_BOTTOM_FIRST; + case AV_FIELD_PROGRESSIVE: + return ILACE_MODE_NOTINTERLACED; + default: + return ILACE_MODE_UNDETECTED; + } + +} + + + int FFMPEG::video_seek(int stream, int64_t pos) { int vidx = vstrm_index[stream].st_idx; @@ -3468,7 +3556,22 @@ int FFMPEG::ff_coded_height(int stream) float FFMPEG::ff_aspect_ratio(int stream) { - return ffvideo[stream]->aspect_ratio; + //return ffvideo[stream]->aspect_ratio; + AVFormatContext *fmt_ctx = ffvideo[stream]->fmt_ctx; + AVStream *strm = ffvideo[stream]->st; + AVCodecParameters *par = ffvideo[stream]->st->codecpar; + AVRational dar; + AVRational sar = av_guess_sample_aspect_ratio(fmt_ctx, strm, NULL); + if (sar.num) { + printf("sample_aspect_ratio, %f \n", av_q2d(sar)); + av_reduce(&dar.num, &dar.den, + par->width * sar.num, + par->height * sar.den, + 1024*1024); + printf("display_aspect_ratio, %f \n", av_q2d(dar)); + return av_q2d(dar); + } + return ffvideo[stream]->aspect_ratio; } const char* FFMPEG::ff_video_codec(int stream) @@ -3509,6 +3612,31 @@ int FFMPEG::ff_video_mpeg_color_range(int stream) return ffvideo[stream]->st->codecpar->color_range == AVCOL_RANGE_MPEG ? 1 : 0; } +int FFMPEG::ff_interlace(int stream) +{ +// https://ffmpeg.org/doxygen/trunk/structAVCodecParserContext.html +/* reads from demuxer because codec frame not ready */ + int interlace0 = ffvideo[stream]->st->codecpar->field_order; + printf("interlace from demux: %i\n", interlace0); + + switch (interlace0) + { + case AV_FIELD_TT: + case AV_FIELD_TB: + return ILACE_MODE_TOP_FIRST; + case AV_FIELD_BB: + case AV_FIELD_BT: + return ILACE_MODE_BOTTOM_FIRST; + case AV_FIELD_PROGRESSIVE: + return ILACE_MODE_NOTINTERLACED; + default: + return ILACE_MODE_UNDETECTED; + } + +} + + + int FFMPEG::ff_cpus() { return !file_base ? 1 : file_base->file->cpus; diff --git a/cinelerra-5.1/cinelerra/ffmpeg.h b/cinelerra-5.1/cinelerra/ffmpeg.h index 2e1f201f..4f1624ce 100644 --- a/cinelerra-5.1/cinelerra/ffmpeg.h +++ b/cinelerra-5.1/cinelerra/ffmpeg.h @@ -256,6 +256,7 @@ public: int init_frame(AVFrame *picture); int load(VFrame *vframe, int64_t pos); + int probe(int64_t pos); int video_seek(int64_t pos); int encode(VFrame *vframe); int drain(); @@ -383,6 +384,7 @@ public: double get_initial_timecode(int data_type, int channel, double frame_rate); int audio_seek(int ch, int64_t pos); + int video_probe(int64_t pos); int video_seek(int layer, int64_t pos); int decode(int chn, int64_t pos, double *samples, int len); @@ -434,6 +436,7 @@ public: int decoding, encoding; int has_audio, has_video; + int interlace_from_codec; FFMPEG(FileBase *file_base=0); ~FFMPEG(); @@ -463,6 +466,7 @@ public: float ff_aspect_ratio(int stream); int ff_color_range(int stream); int ff_color_space(int stream); + int ff_interlace(int stream); double ff_frame_rate(int stream); const char *ff_video_codec(int stream); int64_t ff_video_frames(int stream); diff --git a/cinelerra-5.1/cinelerra/fileffmpeg.C b/cinelerra-5.1/cinelerra/fileffmpeg.C index ff206b10..eed14f20 100644 --- a/cinelerra-5.1/cinelerra/fileffmpeg.C +++ b/cinelerra-5.1/cinelerra/fileffmpeg.C @@ -326,7 +326,7 @@ int FileFFMPEG::open_file(int rd, int wr) int result = 0; if( ff ) return 1; ff = new FFMPEG(this); - + if( rd ) { result = ff->init_decoder(asset->path); if( !result ) result = ff->open_decoder(); @@ -342,6 +342,11 @@ int FileFFMPEG::open_file(int rd, int wr) int video_layers = ff->ff_total_video_layers(); if( video_layers > 0 ) { asset->video_data = 1; + asset->aspect_ratio = ff->ff_aspect_ratio(0); + printf("ff_aspect_ratio, %f \n", asset->aspect_ratio); + if (!asset->interlace_mode) asset->interlace_mode = ff->ff_interlace(0); + ff->video_probe(1); + if (!asset->interlace_mode && (ff->interlace_from_codec) ) asset->interlace_mode = ff->video_probe(1); if( !asset->layers ) asset->layers = video_layers; asset->actual_width = ff->ff_video_width(0); asset->actual_height = ff->ff_video_height(0); @@ -1938,6 +1943,15 @@ int FFOptionsFormatView::handle_event() { Asset *asset = fmt_config->asset; char *format_name = asset->fformat; + char *replace_name0 = "mov"; + char *replace_name1 = "mpegts"; + char *replace_name2 = "matroska"; + if (!strcmp(format_name, "qt")) + format_name = replace_name0; // fixup + if (!strcmp(format_name, "m2ts")) + format_name = replace_name1; // fixup + if (!strcmp(format_name, "mkv")) + format_name = replace_name2; // fixup avformat_free_context(fmt_ctx); fmt_ctx = 0; int ret = avformat_alloc_output_context2(&fmt_ctx, 0, format_name, 0); if( ret || !fmt_ctx ) { diff --git a/cinelerra-5.1/cinelerra/mwindow.C b/cinelerra-5.1/cinelerra/mwindow.C index f245018a..6621d11a 100644 --- a/cinelerra-5.1/cinelerra/mwindow.C +++ b/cinelerra-5.1/cinelerra/mwindow.C @@ -4493,11 +4493,14 @@ static inline int gcd(int m, int n) int MWindow::create_aspect_ratio(float &w, float &h, int width, int height) { w = 1; h = 1; + double ar; + if(!width || !height) return 1; if( width == 720 && (height == 480 || height == 576) ) { w = 4; h = 3; return 0; // for NTSC and PAL } - double ar = (double)width / height; + + ar = (double)width / height; // square-ish pixels if( EQUIV(ar, 1.0000) ) return 0; if( EQUIV(ar, 1.3333) ) { w = 4; h = 3; return 0; } @@ -4505,6 +4508,8 @@ int MWindow::create_aspect_ratio(float &w, float &h, int width, int height) if( EQUIV(ar, 2.1111) ) { w = 19; h = 9; return 0; } if( EQUIV(ar, 2.2222) ) { w = 20; h = 9; return 0; } if( EQUIV(ar, 2.3333) ) { w = 21; h = 9; return 0; } + if( EQUIV(ar, 2.37037) ) { w = 64; h = 27; return 0; } + int ww = width, hh = height; // numerator, denominator must be under mx int mx = 255, n = gcd(ww, hh); @@ -5048,12 +5053,26 @@ int MWindow::select_asset(Asset *asset, int vstream, int astream, int delete_tra session->output_w = width; session->output_h = height; session->frame_rate = framerate; + session->interlace_mode = asset->interlace_mode; // not, asset->actual_width/actual_height asset->width = session->output_w; asset->height = session->output_h; asset->frame_rate = session->frame_rate; + create_aspect_ratio(session->aspect_w, session->aspect_h, session->output_w, session->output_h); + float ar = asset->aspect_ratio; + if (ar) { + //printf ("Aspect ratio from asset: %f \n", ar); + if( EQUIV(ar, 1.3333) ) { session->aspect_w = 4; session->aspect_h = 3; } + if( EQUIV(ar, 1.7777) ) { session->aspect_w = 16; session->aspect_h = 9; } + if( EQUIV(ar, 2.1111) ) { session->aspect_w = 19; session->aspect_h = 9; } + if( EQUIV(ar, 2.2222) ) { session->aspect_w = 20; session->aspect_h = 9; } + if( EQUIV(ar, 2.3333) ) { session->aspect_w = 21; session->aspect_h = 9; } + if( EQUIV(ar, 2.370370) ) { session->aspect_w = 64; session->aspect_h = 27; } + } + + Track *track = edl->tracks->first; for( Track *next_track=0; track; track=next_track ) { next_track = track->next; -- 2.26.2