Basically I tried to set field_order depending on project's interlace settings. It seems to work ..in mov container for huffyuv/utvideo/magicuyv/mjpeg/dv It doesn't work for mpeg2 container/codec :( ===== diff --git a/cinelerra-5.1/cinelerra/ffmpeg.C b/cinelerra-5.1/cinelerra/ffmpeg.C index 97b6698a..b5c3aee5 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,11 @@ 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: av_dict_set(&sopts, "field_order", "tt", 0); break; + case ILACE_MODE_BOTTOM_FIRST: av_dict_set(&sopts, "field_order", "bb", 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 +3228,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 +3542,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 +3598,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; ===== cloud: https://cloud.mail.ru/public/EK7w/2PWd8i4AS I was unable to get dxnhd codec running, it always complained about something :/ DNxHR still doesn't show up as interlaced ......
I was unable to get dxnhd codec running, it always complained about something :/ DNxHR still doesn't show up as interlaced ......
What a lot of work you do, thank you very much! Of the DNxHD codec there are many specifications for each combination of resolution, bit rate and depth color. It is an unmanageable codec because it always finds compatibility problems. Basically only Avid used it. This is why DNxHR was created, which imitates the formats and flexibility of ProRes. The only rigidity of DNxHR are 4:2:2 or 4:4:4 (like ProRes) and the lack of interlacing, it can only be progressive. PS: There is also another famous high quality format: Cineform (GoPro property, but open). I've seen that it has big problems of slowness and compatibility with ffmpeg, so I didn't try to create presets.
В сообщении от Wednesday 18 November 2020 01:47:58 Andrea paz via Cin написал(а):
I was unable to get dxnhd codec running, it always complained about something :/ DNxHR still doesn't show up as interlaced ......
What a lot of work you do, thank you very much! Of the DNxHD codec there are many specifications for each combination of resolution, bit rate and depth color. It is an unmanageable codec because it always finds compatibility problems. Basically only Avid used it. This is why DNxHR was created, which imitates the formats and flexibility of ProRes. The only rigidity of DNxHR are 4:2:2 or 4:4:4 (like ProRes) and the lack of interlacing, it can only be progressive.
I think I fixed my patch for mpeg2/mpeg4 interlace (so, DVD master should work for creating interlaced DVD with option Use FFMPEG) I forgot those two flags: +ilme+ildct because they were hidden in flags section https://cloud.mail.ru/public/3JGM/BQTr2wHJ9
PS: There is also another famous high quality format: Cineform (GoPro property, but open). I've seen that it has big problems of slowness and compatibility with ffmpeg, so I didn't try to create presets.
participants (2)
-
Andrea paz -
Andrew Randrianasulu