diff mbox

[FFmpeg-devel] avformat/mxfdec: Detect field_order based on video_line_map

Message ID 1476175249-605-1-git-send-email-t.rapp@noa-archive.com
State Accepted
Commit e3196b686233bed3009248cb1ab7f0628ede6a2f
Headers show

Commit Message

Tobias Rapp Oct. 11, 2016, 8:40 a.m. UTC
Read video_line_map from MXF generic picture essence descriptor and use
it to derive the coded field order. Use field_dominance to derive the
display field order from coded field order. If field_dominance is not
available the default value "1" is used as defined in SMPTE S377-1.

Fixes field_order detection for a bunch of DV/DVCPRO files. The heuristic
for deriving coded field order from video_line_map is inspired by
MediaInfo.

Signed-off-by: Tobias Rapp <t.rapp@noa-archive.com>
---
 libavformat/mxfdec.c | 75 +++++++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 60 insertions(+), 15 deletions(-)

Comments

Tobias Rapp Oct. 18, 2016, 10:23 a.m. UTC | #1
On 11.10.2016 10:40, Tobias Rapp wrote:
> Read video_line_map from MXF generic picture essence descriptor and use
> it to derive the coded field order. Use field_dominance to derive the
> display field order from coded field order. If field_dominance is not
> available the default value "1" is used as defined in SMPTE S377-1.
>
> Fixes field_order detection for a bunch of DV/DVCPRO files. The heuristic
> for deriving coded field order from video_line_map is inspired by
> MediaInfo.
>
> Signed-off-by: Tobias Rapp <t.rapp@noa-archive.com>
> ---
>  libavformat/mxfdec.c | 75 +++++++++++++++++++++++++++++++++++++++++-----------
>  1 file changed, 60 insertions(+), 15 deletions(-)
>

Ping. Example files can be found at [1]. To debug the detected field 
order I used ffprobe plus the patch in [2]:

./ffprobe -show_streams -select_streams v -i $INPUT_FILE 2>/dev/null | 
grep field_order

For file "Avid-00005.mxf" [3] the result is:
field_order=tt (without patch)
field_order=bb (with patch)

For file "OpenCube-00003.mxf" [4] the result is:
field_order=unknown (without patch)
field_order=bb (with patch)

Regards,
Tobias

Links:
[1] http://mxf.irt.de/files/filter.php?action=query&filter=manufacturers
[2] https://ffmpeg.org/pipermail/ffmpeg-devel/2016-October/200607.html
[3] 
http://mxf.irt.de/files/download.php?action=getFile&repository=manufacturers&id=85
[4] 
http://mxf.irt.de/files/download.php?action=getFile&repository=manufacturers&id=114
Michael Niedermayer Oct. 18, 2016, 2:51 p.m. UTC | #2
On Tue, Oct 18, 2016 at 12:23:14PM +0200, Tobias Rapp wrote:
> On 11.10.2016 10:40, Tobias Rapp wrote:
> >Read video_line_map from MXF generic picture essence descriptor and use
> >it to derive the coded field order. Use field_dominance to derive the
> >display field order from coded field order. If field_dominance is not
> >available the default value "1" is used as defined in SMPTE S377-1.
> >
> >Fixes field_order detection for a bunch of DV/DVCPRO files. The heuristic
> >for deriving coded field order from video_line_map is inspired by
> >MediaInfo.
> >
> >Signed-off-by: Tobias Rapp <t.rapp@noa-archive.com>
> >---
> > libavformat/mxfdec.c | 75 +++++++++++++++++++++++++++++++++++++++++-----------
> > 1 file changed, 60 insertions(+), 15 deletions(-)
> >
> 
> Ping. Example files can be found at [1]. To debug the detected field
> order I used ffprobe plus the patch in [2]:
> 
> ./ffprobe -show_streams -select_streams v -i $INPUT_FILE 2>/dev/null
> | grep field_order
> 
> For file "Avid-00005.mxf" [3] the result is:
> field_order=tt (without patch)
> field_order=bb (with patch)
> 
> For file "OpenCube-00003.mxf" [4] the result is:
> field_order=unknown (without patch)
> field_order=bb (with patch)

can you make some fate test out of a small mxf file ?

[...]
diff mbox

Patch

diff --git a/libavformat/mxfdec.c b/libavformat/mxfdec.c
index 1939761..8332362 100644
--- a/libavformat/mxfdec.c
+++ b/libavformat/mxfdec.c
@@ -173,8 +173,10 @@  typedef struct MXFDescriptor {
     int width;
     int height; /* Field height, not frame height */
     int frame_layout; /* See MXFFrameLayout enum */
-#define MXF_TFF 1
-#define MXF_BFF 2
+    int video_line_map[2];
+#define MXF_FIELD_DOMINANCE_DEFAULT 0
+#define MXF_FIELD_DOMINANCE_FF 1 /* coded first, displayed first */
+#define MXF_FIELD_DOMINANCE_FL 2 /* coded first, displayed last */
     int field_dominance;
     int channels;
     int bits_per_sample;
@@ -968,6 +970,8 @@  static void mxf_read_pixel_layout(AVIOContext *pb, MXFDescriptor *descriptor)
 static int mxf_read_generic_descriptor(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset)
 {
     MXFDescriptor *descriptor = arg;
+    int entry_count, entry_size;
+
     switch(tag) {
     case 0x3F01:
         return mxf_read_strong_ref_array(pb, &descriptor->sub_descriptors_refs,
@@ -996,6 +1000,21 @@  static int mxf_read_generic_descriptor(void *arg, AVIOContext *pb, int tag, int
     case 0x320C:
         descriptor->frame_layout = avio_r8(pb);
         break;
+    case 0x320D:
+        entry_count = avio_rb32(pb);
+        entry_size = avio_rb32(pb);
+        if (entry_size == 4) {
+            if (entry_count > 0)
+                descriptor->video_line_map[0] = avio_rb32(pb);
+            else
+                descriptor->video_line_map[0] = 0;
+            if (entry_count > 1)
+                descriptor->video_line_map[1] = avio_rb32(pb);
+            else
+                descriptor->video_line_map[1] = 0;
+        } else
+            av_log(NULL, AV_LOG_WARNING, "VideoLineMap element size %d currently not supported\n", entry_size);
+        break;
     case 0x320E:
         descriptor->aspect_ratio.num = avio_rb32(pb);
         descriptor->aspect_ratio.den = avio_rb32(pb);
@@ -2044,19 +2063,45 @@  static int mxf_parse_structural_metadata(MXFContext *mxf)
                 case SegmentedFrame:
                     st->codecpar->field_order = AV_FIELD_PROGRESSIVE;
                 case SeparateFields:
-                    switch (descriptor->field_dominance) {
-                    case MXF_TFF:
-                        st->codecpar->field_order = AV_FIELD_TT;
-                        break;
-                    case MXF_BFF:
-                        st->codecpar->field_order = AV_FIELD_BB;
-                        break;
-                    default:
-                        avpriv_request_sample(mxf->fc,
-                                              "Field dominance %d support",
-                                              descriptor->field_dominance);
-                    case 0: // we already have many samples with field_dominance == unknown
-                        break;
+                    av_log(mxf->fc, AV_LOG_DEBUG, "video_line_map: (%d, %d), field_dominance: %d\n",
+                           descriptor->video_line_map[0], descriptor->video_line_map[1],
+                           descriptor->field_dominance);
+                    if ((descriptor->video_line_map[0] > 0) && (descriptor->video_line_map[1] > 0)) {
+                        /* Detect coded field order from VideoLineMap:
+                         *  (even, even) => bottom field coded first
+                         *  (even, odd)  => top field coded first
+                         *  (odd, even)  => top field coded first
+                         *  (odd, odd)   => bottom field coded first
+                         */
+                        if ((descriptor->video_line_map[0] + descriptor->video_line_map[1]) % 2) {
+                            switch (descriptor->field_dominance) {
+                                case MXF_FIELD_DOMINANCE_DEFAULT:
+                                case MXF_FIELD_DOMINANCE_FF:
+                                    st->codecpar->field_order = AV_FIELD_TT;
+                                    break;
+                                case MXF_FIELD_DOMINANCE_FL:
+                                    st->codecpar->field_order = AV_FIELD_TB;
+                                    break;
+                                default:
+                                    avpriv_request_sample(mxf->fc,
+                                                          "Field dominance %d support",
+                                                          descriptor->field_dominance);
+                            }
+                        } else {
+                            switch (descriptor->field_dominance) {
+                                case MXF_FIELD_DOMINANCE_DEFAULT:
+                                case MXF_FIELD_DOMINANCE_FF:
+                                    st->codecpar->field_order = AV_FIELD_BB;
+                                    break;
+                                case MXF_FIELD_DOMINANCE_FL:
+                                    st->codecpar->field_order = AV_FIELD_BT;
+                                    break;
+                                default:
+                                    avpriv_request_sample(mxf->fc,
+                                                          "Field dominance %d support",
+                                                          descriptor->field_dominance);
+                            }
+                        }
                     }
                     /* Turn field height into frame height. */
                     st->codecpar->height *= 2;