On Tue, Apr 28, 2020 at 3:18 AM Nicolas George <geo...@nsup.org> wrote:

> Andreas Rheinhardt (12020-04-28):
> > That's expected. The patch provided only provides the structure in which
> > the values are intended to be exported; it does not add any demuxing or
> > muxing capabilities for mov or mkv (as you can see from the fact that
> > none of these (de)muxers have been changed in the patch).
>
> Which is something I intended to comment on: adding code without users
> is rarely a good idea. I suggest we do not commit until at least one
> demuxer use it, preferably at least two. Otherwise, we may realize that
> “oh crap, it doesn't work” because of a tiny unforeseen detail.


Thanks for the feedback. I also have patches for the demux (MOV/MKV) and
mux (MOV/MKV).

As there is still the alternative of using the fields in the
AVCodecParameters/AVCodecContext, my intention was to keep the first patch
small to resolve discussion on that point.

I've included the patches, if you'd like to try test it, Kieren. I see on
your test file that there may be some slight rounding error making output
crop 704 not 703 (MKV file ends up with pixel_crop_{left,right} = 8).

/ffprobe ../testdata/clap.mov 2>&1 | grep -A1 "Side"
    Side data:
      Clean aperture:[width 41472/59 height:576/1 h_offset:0/1 v_offset:0/1]
./ffmpeg -i ../testdata/clap.mov  -vcodec copy -acodec copy /tmp/clap.mkv
./ffprobe /tmp/clap.mkv 2>&1 | grep -A1 "Side"
    Side data:
      Clean aperture:[width 704/1 height:576/1 h_offset:0/1 v_offset:0/1]
From d92371cc2de6a671b44d9f6dd9d28544d05b5287 Mon Sep 17 00:00:00 2001
From: Neil Birkbeck <neil.birkb...@gmail.com>
Date: Sun, 26 Apr 2020 20:42:59 -0700
Subject: [PATCH 3/3] libavformat: Adding MOV/MKV muxer support for CLAP side
 data.

Write out stream-level AVCleanAperture side data in the muxer.

Signed-off-by: Neil Birkbeck <neil.birkb...@gmail.com>
---
 libavformat/matroskaenc.c | 37 +++++++++++++++++++++++++++++++++++++
 libavformat/movenc.c      | 28 ++++++++++++++++++++--------
 2 files changed, 57 insertions(+), 8 deletions(-)

diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c
index 784973a951..19ff29853e 100644
--- a/libavformat/matroskaenc.c
+++ b/libavformat/matroskaenc.c
@@ -901,6 +901,38 @@ static int mkv_write_video_color(AVIOContext *pb, const AVCodecParameters *par,
     return 0;
 }
 
+static int mkv_write_video_crop(AVIOContext *pb, AVCodecParameters *par, AVStream *st)
+{
+    int cropb = 0, cropt = 0, cropl = 0, cropr = 0;
+    double width, height, h_offset, v_offset;
+    int side_data_size = 0;
+    const AVCleanAperture *clap =
+        (const AVCleanAperture *)av_stream_get_side_data(
+            st, AV_PKT_DATA_CLEAN_APERTURE, &side_data_size);
+    if (!clap)
+        return 0;
+
+    width = av_q2d(clap->width);
+    height = av_q2d(clap->height);
+    h_offset = av_q2d(clap->horizontal_offset);
+    v_offset = av_q2d(clap->vertical_offset);
+    cropb = (int)(par->height - (par->height / 2. + v_offset + height / 2));
+    cropt = (int)(par->height / 2. + v_offset - height / 2);
+    cropr = (int)(par->width - (par->width / 2. + h_offset + width / 2));
+    cropl = (int)(par->width / 2. + h_offset - width / 2);
+    cropb = FFMAX(cropb, 0);
+    cropt = FFMAX(cropt, 0);
+    cropr = FFMAX(cropr, 0);
+    cropl = FFMAX(cropl, 0);
+    if (!cropr && !cropl && !cropt && !cropb)
+        return 0;
+    put_ebml_uint(pb, MATROSKA_ID_VIDEOPIXELCROPL, cropl);
+    put_ebml_uint(pb, MATROSKA_ID_VIDEOPIXELCROPR, cropr);
+    put_ebml_uint(pb, MATROSKA_ID_VIDEOPIXELCROPB, cropb);
+    put_ebml_uint(pb, MATROSKA_ID_VIDEOPIXELCROPT, cropt);
+    return 0;
+}
+
 static int mkv_write_video_projection(AVFormatContext *s, AVIOContext *pb,
                                       const AVStream *st)
 {
@@ -1287,6 +1319,11 @@ static int mkv_write_track(AVFormatContext *s, MatroskaMuxContext *mkv,
         } else if (mkv->mode != MODE_WEBM)
             put_ebml_uint(pb, MATROSKA_ID_VIDEODISPLAYUNIT, MATROSKA_VIDEO_DISPLAYUNIT_UNKNOWN);
 
+        // Write out pixel crop
+        ret = mkv_write_video_crop(pb, par, st);
+        if (ret < 0)
+            return ret;
+
         if (par->codec_id == AV_CODEC_ID_RAWVIDEO) {
             uint32_t color_space = av_le2ne32(par->codec_tag);
             put_ebml_binary(pb, MATROSKA_ID_VIDEOCOLORSPACE, &color_space, sizeof(color_space));
diff --git a/libavformat/movenc.c b/libavformat/movenc.c
index 32e8109268..ab2b53cab6 100644
--- a/libavformat/movenc.c
+++ b/libavformat/movenc.c
@@ -1847,16 +1847,28 @@ static int mov_write_dvcc_dvvc_tag(AVFormatContext *s, AVIOContext *pb, AVDOVIDe
 
 static int mov_write_clap_tag(AVIOContext *pb, MOVTrack *track)
 {
+    const AVCleanAperture* clap =
+        (const AVCleanAperture*) av_stream_get_side_data(
+            track->st, AV_PKT_DATA_CLEAN_APERTURE, NULL);
+    AVRational width = {.num = clap ? clap->width.num : track->par->width,
+                        .den = clap ? clap->width.den : 1};
+    AVRational height = {.num = clap ? clap->height.num : track->par->height,
+                         .den = clap ? clap->height.den : 1};
+    AVRational h_offs = {.num = clap ? clap->horizontal_offset.num : 0,
+                         .den = clap ? clap->horizontal_offset.den : 1};
+    AVRational v_offs = {.num = clap ? clap->vertical_offset.num : 0,
+                         .den = clap ? clap->vertical_offset.den : 1};
+
     avio_wb32(pb, 40);
     ffio_wfourcc(pb, "clap");
-    avio_wb32(pb, track->par->width); /* apertureWidth_N */
-    avio_wb32(pb, 1); /* apertureWidth_D (= 1) */
-    avio_wb32(pb, track->height); /* apertureHeight_N */
-    avio_wb32(pb, 1); /* apertureHeight_D (= 1) */
-    avio_wb32(pb, 0); /* horizOff_N (= 0) */
-    avio_wb32(pb, 1); /* horizOff_D (= 1) */
-    avio_wb32(pb, 0); /* vertOff_N (= 0) */
-    avio_wb32(pb, 1); /* vertOff_D (= 1) */
+    avio_wb32(pb, width.num); /* apertureWidth_N */
+    avio_wb32(pb, width.den); /* apertureWidth_D */
+    avio_wb32(pb, height.num); /* apertureHeight_N */
+    avio_wb32(pb, height.den); /* apertureHeight_D */
+    avio_wb32(pb, h_offs.num); /* horizOff_N (= 0) */
+    avio_wb32(pb, h_offs.den); /* horizOff_D (= 1) */
+    avio_wb32(pb, v_offs.num); /* vertOff_N (= 0) */
+    avio_wb32(pb, v_offs.den); /* vertOff_D (= 1) */
     return 40;
 }
 
-- 
2.26.2.303.gf8c07b1a785-goog

From 02a0c4caa1cd0be1913aad25d47e351c3166ee35 Mon Sep 17 00:00:00 2001
From: Neil Birkbeck <neil.birkb...@gmail.com>
Date: Sun, 26 Apr 2020 20:28:43 -0700
Subject: [PATCH 2/3] libavformat: demuxer support (MKV/MOV) for clean
 aperture.

Exports the container-level cropping as stream-level AVCleanAperture
side data.

Signed-off-by: Neil Birkbeck <neil.birkb...@gmail.com>
---
 libavformat/isom.h        |  3 +++
 libavformat/matroskadec.c | 42 ++++++++++++++++++++++++++++++++-------
 libavformat/mov.c         | 41 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 79 insertions(+), 7 deletions(-)

diff --git a/libavformat/isom.h b/libavformat/isom.h
index 41a9c64c11..8a0775fd70 100644
--- a/libavformat/isom.h
+++ b/libavformat/isom.h
@@ -27,6 +27,7 @@
 #include <stddef.h>
 #include <stdint.h>
 
+#include "libavutil/clean_aperture.h"
 #include "libavutil/encryption_info.h"
 #include "libavutil/mastering_display_metadata.h"
 #include "libavutil/spherical.h"
@@ -241,6 +242,8 @@ typedef struct MOVStreamContext {
         AVEncryptionInfo *default_encrypted_sample;
         MOVEncryptionIndex *encryption_index;
     } cenc;
+
+    AVCleanAperture *clap;
 } MOVStreamContext;
 
 typedef struct MOVContext {
diff --git a/libavformat/matroskadec.c b/libavformat/matroskadec.c
index 8e1326abf6..de520be247 100644
--- a/libavformat/matroskadec.c
+++ b/libavformat/matroskadec.c
@@ -190,6 +190,10 @@ typedef struct MatroskaTrackVideo {
     uint64_t display_height;
     uint64_t pixel_width;
     uint64_t pixel_height;
+    uint64_t pixel_cropb;
+    uint64_t pixel_cropt;
+    uint64_t pixel_cropl;
+    uint64_t pixel_cropr;
     EbmlBin  color_space;
     uint64_t display_unit;
     uint64_t interlaced;
@@ -480,10 +484,10 @@ static EbmlSyntax matroska_track_video[] = {
     { MATROSKA_ID_VIDEOALPHAMODE,      EBML_UINT,  0, offsetof(MatroskaTrackVideo, alpha_mode) },
     { MATROSKA_ID_VIDEOCOLOR,          EBML_NEST,  sizeof(MatroskaTrackVideoColor), offsetof(MatroskaTrackVideo, color), { .n = matroska_track_video_color } },
     { MATROSKA_ID_VIDEOPROJECTION,     EBML_NEST,  0, offsetof(MatroskaTrackVideo, projection), { .n = matroska_track_video_projection } },
-    { MATROSKA_ID_VIDEOPIXELCROPB,     EBML_NONE },
-    { MATROSKA_ID_VIDEOPIXELCROPT,     EBML_NONE },
-    { MATROSKA_ID_VIDEOPIXELCROPL,     EBML_NONE },
-    { MATROSKA_ID_VIDEOPIXELCROPR,     EBML_NONE },
+    { MATROSKA_ID_VIDEOPIXELCROPB,     EBML_UINT,  0, offsetof(MatroskaTrackVideo, pixel_cropb) },
+    { MATROSKA_ID_VIDEOPIXELCROPT,     EBML_UINT,  0, offsetof(MatroskaTrackVideo, pixel_cropt) },
+    { MATROSKA_ID_VIDEOPIXELCROPL,     EBML_UINT,  0, offsetof(MatroskaTrackVideo, pixel_cropl) },
+    { MATROSKA_ID_VIDEOPIXELCROPR,     EBML_UINT,  0, offsetof(MatroskaTrackVideo, pixel_cropr) },
     { MATROSKA_ID_VIDEODISPLAYUNIT,    EBML_UINT,  0, offsetof(MatroskaTrackVideo, display_unit), { .u= MATROSKA_VIDEO_DISPLAYUNIT_PIXELS } },
     { MATROSKA_ID_VIDEOFLAGINTERLACED, EBML_UINT,  0, offsetof(MatroskaTrackVideo, interlaced),  { .u = MATROSKA_VIDEO_INTERLACE_FLAG_UNDETERMINED } },
     { MATROSKA_ID_VIDEOFIELDORDER,     EBML_UINT,  0, offsetof(MatroskaTrackVideo, field_order), { .u = MATROSKA_VIDEO_FIELDORDER_UNDETERMINED } },
@@ -2695,7 +2699,8 @@ static int matroska_parse_tracks(AVFormatContext *s)
             MatroskaTrackPlane *planes = track->operation.combine_planes.elem;
             int display_width_mul  = 1;
             int display_height_mul = 1;
-
+            const int cropped_width = track->video.pixel_width - track->video.pixel_cropl - track->video.pixel_cropr;
+            const int cropped_height = track->video.pixel_height - track->video.pixel_cropt - track->video.pixel_cropb;
             st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
             st->codecpar->codec_tag  = fourcc;
             if (bit_depth >= 0)
@@ -2703,6 +2708,29 @@ static int matroska_parse_tracks(AVFormatContext *s)
             st->codecpar->width      = track->video.pixel_width;
             st->codecpar->height     = track->video.pixel_height;
 
+            if (track->video.pixel_cropt || track->video.pixel_cropb ||
+                track->video.pixel_cropl || track->video.pixel_cropr) {
+                AVCleanAperture *metadata = av_clean_aperture_alloc();
+                if (!metadata)
+                    return AVERROR(ENOMEM);
+                metadata->width.num = cropped_width;
+                metadata->height.num = cropped_height;
+                metadata->width.den = 1;
+                metadata->height.den = 1;
+                av_reduce(&metadata->horizontal_offset.num,
+                          &metadata->horizontal_offset.den,
+                          (int)track->video.pixel_cropl - (int)track->video.pixel_cropr, 2, INT_MAX);
+                av_reduce(&metadata->vertical_offset.num,
+                          &metadata->vertical_offset.den,
+                          (int)track->video.pixel_cropt - (int)track->video.pixel_cropb, 2, INT_MAX);
+                ret = av_stream_add_side_data(st, AV_PKT_DATA_CLEAN_APERTURE,
+                                              (uint8_t *)metadata, sizeof(*metadata));
+                if (ret < 0) {
+                    av_freep(&metadata);
+                    return ret;
+                }
+            }
+
             if (track->video.interlaced == MATROSKA_VIDEO_INTERLACE_FLAG_INTERLACED)
                 st->codecpar->field_order = mkv_field_order(matroska, track->video.field_order);
             else if (track->video.interlaced == MATROSKA_VIDEO_INTERLACE_FLAG_PROGRESSIVE)
@@ -2714,8 +2742,8 @@ static int matroska_parse_tracks(AVFormatContext *s)
             if (track->video.display_unit < MATROSKA_VIDEO_DISPLAYUNIT_UNKNOWN) {
                 av_reduce(&st->sample_aspect_ratio.num,
                           &st->sample_aspect_ratio.den,
-                          st->codecpar->height * track->video.display_width  * display_width_mul,
-                          st->codecpar->width  * track->video.display_height * display_height_mul,
+                          cropped_height * track->video.display_width  * display_width_mul,
+                          cropped_width  * track->video.display_height * display_height_mul,
                           255);
             }
             if (st->codecpar->codec_id != AV_CODEC_ID_HEVC)
diff --git a/libavformat/mov.c b/libavformat/mov.c
index 3d6fef685d..27f75020b4 100644
--- a/libavformat/mov.c
+++ b/libavformat/mov.c
@@ -5495,6 +5495,36 @@ static int mov_read_clli(MOVContext *c, AVIOContext *pb, MOVAtom atom)
     return 0;
 }
 
+static int mov_read_clap(MOVContext *c, AVIOContext *pb, MOVAtom atom)
+{
+    MOVStreamContext *sc;
+
+    if (c->fc->nb_streams < 1)
+        return AVERROR_INVALIDDATA;
+
+    sc = c->fc->streams[c->fc->nb_streams - 1]->priv_data;
+
+    if (atom.size < 32) {
+        av_log(c->fc, AV_LOG_ERROR, "Clean Aperture box is wrong size\n");
+        return AVERROR_INVALIDDATA;
+    }
+
+    sc->clap = av_clean_aperture_alloc();
+    if (!sc->clap)
+        return AVERROR(ENOMEM);
+
+    sc->clap->width.num  = avio_rb32(pb);
+    sc->clap->width.den  = avio_rb32(pb);
+    sc->clap->height.num  = avio_rb32(pb);
+    sc->clap->height.den  = avio_rb32(pb);
+    sc->clap->horizontal_offset.num  = avio_rb32(pb);
+    sc->clap->horizontal_offset.den  = avio_rb32(pb);
+    sc->clap->vertical_offset.num  = avio_rb32(pb);
+    sc->clap->vertical_offset.den  = avio_rb32(pb);
+
+    return 0;
+}
+
 static int mov_read_st3d(MOVContext *c, AVIOContext *pb, MOVAtom atom)
 {
     AVStream *st;
@@ -6941,6 +6971,7 @@ static const MOVParseTableEntry mov_default_parse_table[] = {
 { MKTAG('c','l','l','i'), mov_read_clli },
 { MKTAG('d','v','c','C'), mov_read_dvcc_dvvc },
 { MKTAG('d','v','v','C'), mov_read_dvcc_dvvc },
+{ MKTAG('c','l','a','p'), mov_read_clap },
 { 0, NULL }
 };
 
@@ -7380,6 +7411,7 @@ static int mov_read_close(AVFormatContext *s)
         av_freep(&sc->spherical);
         av_freep(&sc->mastering);
         av_freep(&sc->coll);
+        av_freep(&sc->clap);
     }
 
     if (mov->dv_demux) {
@@ -7744,6 +7776,15 @@ static int mov_read_header(AVFormatContext *s)
 
                 sc->coll = NULL;
             }
+            if (sc->clap) {
+                err = av_stream_add_side_data(st, AV_PKT_DATA_CLEAN_APERTURE,
+                                              (uint8_t *)sc->clap,
+                                              sizeof(*sc->clap));
+                if (err < 0)
+                    return err;
+
+                sc->clap = NULL;
+            }
             break;
         }
     }
-- 
2.26.2.303.gf8c07b1a785-goog

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".

Reply via email to