diff mbox

[FFmpeg-devel] avformat/avienc: fix fields-per-frame value for interlaced video streams

Message ID 1511365263-17845-1-git-send-email-t.rapp@noa-archive.com
State New
Headers show

Commit Message

Tobias Rapp Nov. 22, 2017, 3:41 p.m. UTC
Writes one set of field framing information for progressive streams and
two sets for interlaced streams. Fixes ticket #6383.

Unfortunately the OpenDML v1.02 document is not very specific what value
to use for start_line when frame data is not coming from a capturing
device, so this is just using 0/1 depending on the field order as a
best-effort guess.

Signed-off-by: Tobias Rapp <t.rapp@noa-archive.com>
---
 libavformat/avienc.c             | 38 +++++++++++++++++++++++++++-----------
 libavformat/version.h            |  2 +-
 tests/ref/fate/copy-trac2211-avi |  4 ++--
 3 files changed, 30 insertions(+), 14 deletions(-)

Comments

Derek Buitenhuis Nov. 22, 2017, 3:58 p.m. UTC | #1
On 11/22/2017 3:41 PM, Tobias Rapp wrote:
> Writes one set of field framing information for progressive streams and
> two sets for interlaced streams. Fixes ticket #6383.
> 
> Unfortunately the OpenDML v1.02 document is not very specific what value
> to use for start_line when frame data is not coming from a capturing
> device, so this is just using 0/1 depending on the field order as a
> best-effort guess.

Looking at the OpenDML spec, I think this indeed is the best we can do without
deeper knowledge of where the source signal came from, or copying it from a
pre-existing file, within the existing avformat scaffolding.

Code itself seems OK.

- Derek
Carl Eugen Hoyos Nov. 22, 2017, 10:52 p.m. UTC | #2
2017-11-22 16:41 GMT+01:00 Tobias Rapp <t.rapp@noa-archive.com>:
> Writes one set of field framing information for progressive streams and
> two sets for interlaced streams. Fixes ticket #6383.
>
> Unfortunately the OpenDML v1.02 document is not very specific what value
> to use for start_line when frame data is not coming from a capturing
> device, so this is just using 0/1 depending on the field order as a
> best-effort guess.

I believe your approach is sane but the only available examples
may indicate that it should be set to something like height / 2 ;-(

> +            int num, den, fields, i;
>              av_reduce(&num, &den, dar.num, dar.den, 0xFFFF);
> +            if (par->field_order == AV_FIELD_TT || par->field_order == AV_FIELD_BB ||
> +                par->field_order == AV_FIELD_TB || par->field_order == AV_FIELD_BT) {
> +                fields = 2; // interlaced
> +            } else {
> +                fields = 1; // progressive

fields = 1 + field_order == TT || field_order == BB etc.;

> +            for (i = 0; i < fields; i++) {
> +                int start_line;
> +                if (par->field_order == AV_FIELD_TT || par->field_order == AV_FIELD_TB) {
> +                    start_line = (i == 0) ? 0 : 1;
> +                } else if (par->field_order == AV_FIELD_BB || par->field_order == AV_FIELD_BT) {
> +                    start_line = (i == 0) ? 1 : 0;

start_line = fields * (i ^ (par->field_order == AV_FIELD_BB ||
par->field_order == AV_FIELD_BT));

Which are imo less ugly.

Carl Eugen
Derek Buitenhuis Nov. 22, 2017, 11:10 p.m. UTC | #3
On 11/22/2017 10:52 PM, Carl Eugen Hoyos wrote:
> start_line = fields * (i ^ (par->field_order == AV_FIELD_BB ||
> par->field_order == AV_FIELD_BT));
> 
> Which are imo less ugly.

Can't agree.

It's needlessly less readable bit fiddling.

- Derek
Tobias Rapp Nov. 23, 2017, 8:40 a.m. UTC | #4
On 22.11.2017 23:52, Carl Eugen Hoyos wrote:
> 2017-11-22 16:41 GMT+01:00 Tobias Rapp <t.rapp@noa-archive.com>:
>> Writes one set of field framing information for progressive streams and
>> two sets for interlaced streams. Fixes ticket #6383.
>>
>> Unfortunately the OpenDML v1.02 document is not very specific what value
>> to use for start_line when frame data is not coming from a capturing
>> device, so this is just using 0/1 depending on the field order as a
>> best-effort guess.
> 
> I believe your approach is sane but the only available examples
> may indicate that it should be set to something like height / 2 ;-(

Indeed my main problem is that I have not found some real-world example 
file with two sets of field framing information. I scanned the files at 
http://streams.videolan.org/samples/ but out of >900 AVI files only 
about 40 files contain a vprp chunk but none contains two fields.

I have found two files that have FieldPerFrame=2 (indicating an 
interlaced video stream) but they contain a truncated vprp chunk (no 
field framing information):
http://streams.videolan.org/samples/V-codecs/MJPEGs/matrox-capture.avi
http://streams.videolan.org/samples/avi/TRA3106.avi

As this clearly doesn't match the specs I didn't want to follow these 
two examples.

I can use height/2 for start_line offset instead of 1 if that sounds 
better, to me it would look like an indication that the fields are 
stored separated, but no strong opinion from my side.

Regards,
Tobias
Carl Eugen Hoyos Nov. 23, 2017, 10:33 a.m. UTC | #5
2017-11-23 9:40 GMT+01:00 Tobias Rapp <t.rapp@noa-archive.com>:
> On 22.11.2017 23:52, Carl Eugen Hoyos wrote:
>>
>> 2017-11-22 16:41 GMT+01:00 Tobias Rapp <t.rapp@noa-archive.com>:
>>>
>>> Writes one set of field framing information for progressive streams and
>>> two sets for interlaced streams. Fixes ticket #6383.
>>>
>>> Unfortunately the OpenDML v1.02 document is not very specific what value
>>> to use for start_line when frame data is not coming from a capturing
>>> device, so this is just using 0/1 depending on the field order as a
>>> best-effort guess.
>>
>>
>> I believe your approach is sane but the only available examples
>> may indicate that it should be set to something like height / 2 ;-(

> I can use height/2 for start_line offset instead of 1

I tried hard not to imply that I would prefer this.

Carl Eugen
Tobias Rapp Nov. 24, 2017, 7:51 a.m. UTC | #6
On 23.11.2017 00:10, Derek Buitenhuis wrote:
> On 11/22/2017 10:52 PM, Carl Eugen Hoyos wrote:
>> start_line = fields * (i ^ (par->field_order == AV_FIELD_BB ||
>> par->field_order == AV_FIELD_BT));
>>
>> Which are imo less ugly.
> 
> Can't agree.
> 
> It's needlessly less readable bit fiddling.

+1

It may save some lines by in my opinion the current code is more 
readable and maintainable in case there are changes to AVFieldOrder (see 
discussion at 
https://ffmpeg.org/pipermail/ffmpeg-devel/2017-September/215698.html).

Regards,
Tobias
Tobias Rapp Nov. 27, 2017, 8:20 a.m. UTC | #7
On 22.11.2017 16:58, Derek Buitenhuis wrote:
> On 11/22/2017 3:41 PM, Tobias Rapp wrote:
>> Writes one set of field framing information for progressive streams and
>> two sets for interlaced streams. Fixes ticket #6383.
>>
>> Unfortunately the OpenDML v1.02 document is not very specific what value
>> to use for start_line when frame data is not coming from a capturing
>> device, so this is just using 0/1 depending on the field order as a
>> best-effort guess.
> 
> Looking at the OpenDML spec, I think this indeed is the best we can do without
> deeper knowledge of where the source signal came from, or copying it from a
> pre-existing file, within the existing avformat scaffolding.
> 
> Code itself seems OK.

Copied part of the commit message as a comment to the code and pushed. 
Thanks Carl and Derek for the review.

Regards,
Tobias
diff mbox

Patch

diff --git a/libavformat/avienc.c b/libavformat/avienc.c
index 483f5b5..efe67ce 100644
--- a/libavformat/avienc.c
+++ b/libavformat/avienc.c
@@ -501,8 +501,14 @@  static int avi_write_header(AVFormatContext *s)
             AVRational dar = av_mul_q(st->sample_aspect_ratio,
                                       (AVRational) { par->width,
                                                      par->height });
-            int num, den;
+            int num, den, fields, i;
             av_reduce(&num, &den, dar.num, dar.den, 0xFFFF);
+            if (par->field_order == AV_FIELD_TT || par->field_order == AV_FIELD_BB ||
+                par->field_order == AV_FIELD_TB || par->field_order == AV_FIELD_BT) {
+                fields = 2; // interlaced
+            } else {
+                fields = 1; // progressive
+            }
 
             avio_wl32(pb, 0); // video format   = unknown
             avio_wl32(pb, 0); // video standard = unknown
@@ -514,17 +520,27 @@  static int avi_write_header(AVFormatContext *s)
             avio_wl16(pb, num);
             avio_wl32(pb, par->width);
             avio_wl32(pb, par->height);
-            avio_wl32(pb, 1); // progressive FIXME
-
-            avio_wl32(pb, par->height);
-            avio_wl32(pb, par->width);
-            avio_wl32(pb, par->height);
-            avio_wl32(pb, par->width);
-            avio_wl32(pb, 0);
-            avio_wl32(pb, 0);
+            avio_wl32(pb, fields); // fields per frame
+
+            for (i = 0; i < fields; i++) {
+                int start_line;
+                if (par->field_order == AV_FIELD_TT || par->field_order == AV_FIELD_TB) {
+                    start_line = (i == 0) ? 0 : 1;
+                } else if (par->field_order == AV_FIELD_BB || par->field_order == AV_FIELD_BT) {
+                    start_line = (i == 0) ? 1 : 0;
+                } else {
+                    start_line = 0;
+                }
 
-            avio_wl32(pb, 0);
-            avio_wl32(pb, 0);
+                avio_wl32(pb, par->height / fields); // compressed bitmap height
+                avio_wl32(pb, par->width);           // compressed bitmap width
+                avio_wl32(pb, par->height / fields); // valid bitmap height
+                avio_wl32(pb, par->width);           // valid bitmap width
+                avio_wl32(pb, 0);                    // valid bitmap X offset
+                avio_wl32(pb, 0);                    // valid bitmap Y offset
+                avio_wl32(pb, 0);                    // valid X offset in T
+                avio_wl32(pb, start_line);           // valid Y start line
+            }
             ff_end_tag(pb, vprp);
         }
 
diff --git a/libavformat/version.h b/libavformat/version.h
index feb1461..7fe3710 100644
--- a/libavformat/version.h
+++ b/libavformat/version.h
@@ -33,7 +33,7 @@ 
 // Also please add any ticket numbers that you believe might be affected here
 #define LIBAVFORMAT_VERSION_MAJOR  58
 #define LIBAVFORMAT_VERSION_MINOR   2
-#define LIBAVFORMAT_VERSION_MICRO 102
+#define LIBAVFORMAT_VERSION_MICRO 103
 
 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
                                                LIBAVFORMAT_VERSION_MINOR, \
diff --git a/tests/ref/fate/copy-trac2211-avi b/tests/ref/fate/copy-trac2211-avi
index 007349e..06d81e5 100644
--- a/tests/ref/fate/copy-trac2211-avi
+++ b/tests/ref/fate/copy-trac2211-avi
@@ -1,5 +1,5 @@ 
-6f6b211cbc8de9871e8e09e64048e2f9 *tests/data/fate/copy-trac2211-avi.avi
-1777924 tests/data/fate/copy-trac2211-avi.avi
+0920978f3f8196413c43f0033b55a5b6 *tests/data/fate/copy-trac2211-avi.avi
+1777956 tests/data/fate/copy-trac2211-avi.avi
 #tb 0: 1/14
 #media_type 0: video
 #codec_id 0: rawvideo